00001
00002
00003
00004
00005
00006
00007
00008
00009
00010
00011
00012
00013
00014
00015
00016
00017
00018
00019
00020
00021
00022
00062 #ifndef LIB_OPAQUE_HOLDER_H
00063 #define LIB_OPAQUE_HOLDER_H
00064
00065
00066 #include "lib/error.hpp"
00067 #include "lib/bool-checkable.hpp"
00068 #include "lib/access-casted.hpp"
00069 #include "lib/util.hpp"
00070
00071 #include <boost/noncopyable.hpp>
00072
00073
00074 namespace lib {
00075
00076 using lumiera::error::LUMIERA_ERROR_WRONG_TYPE;
00077 using util::isSameObject;
00078 using util::unConst;
00079
00080
00081 namespace {
00082
00083 using boost::disable_if;
00084 using boost::is_convertible;
00085
00086 bool
00087 validitySelfCheck (bool boolConvertible)
00088 {
00089 return boolConvertible;
00090 }
00091
00092 template<typename X>
00093 typename disable_if< is_convertible<X,bool>,
00094 bool >::type
00095 validitySelfCheck (X const&)
00096 {
00097 return true;
00098 }
00099
00100 }
00101
00102
00103
00104
00105
00112 template<class BA>
00113 struct InPlaceAnyHolder_useCommonBase
00114 {
00115 typedef BA Base;
00116
00117 template<class SUB>
00118 static Base*
00119 convert2base (SUB& obj)
00120 {
00121 SUB* oPtr = &obj;
00122 BA* asBase = util::AccessCasted<BA*>::access (oPtr);
00123 if (asBase)
00124 return asBase;
00125
00126 throw lumiera::error::Logic ("Unable to convert concrete object to Base interface"
00127 , LUMIERA_ERROR_WRONG_TYPE
00128 );
00129 }
00130
00131 template<class SUB>
00132 static SUB*
00133 access (Base* asBase)
00134 {
00135
00136
00137
00138 if (!util::use_static_downcast<Base*,SUB*>::value)
00139 {
00140 SUB* content = util::AccessCasted<SUB*>::access (asBase);
00141 return content;
00142
00143 }
00144 else
00145 return 0;
00146 }
00147 };
00148
00160 struct InPlaceAnyHolder_unrelatedTypes
00161 {
00162 typedef void Base;
00163
00164 template<class SUB>
00165 static void*
00166 convert2base (SUB& obj)
00167 {
00168 return static_cast<void*> (&obj);
00169 }
00170
00171 template<class SUB>
00172 static SUB*
00173 access (Base*)
00174 {
00175 return 0;
00176 }
00177 };
00178
00179
00180
00181
00182
00183
00184
00202 template
00203 < size_t siz
00204 , class AccessPolicy = InPlaceAnyHolder_unrelatedTypes
00206 >
00207 class InPlaceAnyHolder
00208 : public BoolCheckable<InPlaceAnyHolder<siz, AccessPolicy> >
00209 {
00210 typedef typename AccessPolicy::Base * BaseP;
00211
00213 struct Buffer
00214 {
00215 char content_[siz];
00216 void* ptr() { return &content_; }
00217
00218 virtual ~Buffer() {}
00219 virtual bool isValid() const =0;
00220 virtual bool empty() const =0;
00221 virtual BaseP getBase() const =0;
00222
00223 virtual void clone (void* targetStorage) const =0;
00224 };
00225
00227 struct EmptyBuff : Buffer
00228 {
00229 virtual bool isValid() const { return false; }
00230 virtual bool empty() const { return true; }
00231
00232 BaseP
00233 getBase() const
00234 {
00235 throw lumiera::error::Invalid("accessing empty holder");
00236 }
00237
00238 virtual void
00239 clone (void* targetStorage) const
00240 {
00241 new(targetStorage) EmptyBuff();
00242 }
00243 };
00244
00245
00248 template<typename SUB>
00249 struct Buff : Buffer
00250 {
00251 SUB&
00252 get() const
00253 {
00254 return *reinterpret_cast<SUB*> (unConst(this)->ptr());
00255 }
00256
00257 ~Buff()
00258 {
00259 get().~SUB();
00260 }
00261
00262 explicit
00263 Buff (SUB const& obj)
00264 {
00265 REQUIRE (siz >= sizeof(SUB));
00266 new(Buffer::ptr()) SUB (obj);
00267 }
00268
00269 Buff (Buff const& oBuff)
00270 {
00271 new(Buffer::ptr()) SUB (oBuff.get());
00272 }
00273
00274 Buff&
00275 operator= (Buff const& ref)
00276 {
00277 if (&ref != this)
00278 get() = ref.get();
00279 return *this;
00280 }
00281
00282
00283
00284 virtual void
00285 clone (void* targetStorage) const
00286 {
00287 new(targetStorage) Buff(get());
00288 }
00289
00290 virtual BaseP
00291 getBase() const
00292 {
00293 return AccessPolicy::convert2base (get());
00294 }
00295
00296 virtual bool
00297 empty() const
00298 {
00299 return false;
00300 }
00301
00302 virtual bool
00303 isValid() const
00304 {
00305 return validitySelfCheck (this->get());
00306 }
00307 };
00308
00309
00310
00311 enum{ BUFFSIZE = sizeof(Buffer) };
00312
00316 char storage_[BUFFSIZE];
00317
00318
00319
00320
00321
00322
00323 protected:
00324
00325 Buffer&
00326 buff()
00327 {
00328 return *reinterpret_cast<Buffer*> (&storage_);
00329 }
00330 const Buffer&
00331 buff() const
00332 {
00333 return *reinterpret_cast<const Buffer *> (&storage_);
00334 }
00335
00336
00337 void
00338 killBuffer()
00339 {
00340 buff().~Buffer();
00341 }
00342
00343 void
00344 make_emptyBuff()
00345 {
00346 new(&storage_) EmptyBuff();
00347 }
00348
00349 template<class SUB>
00350 void
00351 place_inBuff (SUB const& obj)
00352 {
00353 new(&storage_) Buff<SUB> (obj);
00354 }
00355
00356 void
00357 clone_inBuff (InPlaceAnyHolder const& ref)
00358 {
00359 ref.buff().clone (storage_);
00360 }
00361
00362 BaseP
00363 asBase () const
00364 {
00365 BaseP asBase = buff().getBase();
00366 ASSERT (asBase);
00367 return asBase;
00368 }
00369
00370
00371
00372
00373 public:
00374
00375 ~InPlaceAnyHolder()
00376 {
00377 killBuffer();
00378 }
00379
00380 void
00381 clear ()
00382 {
00383 killBuffer();
00384 make_emptyBuff();
00385 }
00386
00387
00388 InPlaceAnyHolder()
00389 {
00390 make_emptyBuff();
00391 }
00392
00393 template<class SUB>
00394 InPlaceAnyHolder(SUB const& obj)
00395 {
00396 place_inBuff (obj);
00397 }
00398
00399 InPlaceAnyHolder (InPlaceAnyHolder const& ref)
00400 {
00401 clone_inBuff (ref);
00402 }
00403
00404 InPlaceAnyHolder&
00405 operator= (InPlaceAnyHolder const& ref)
00406 {
00407 if (!isSameObject (*this, ref))
00408 {
00409 killBuffer();
00410 try
00411 {
00412 clone_inBuff (ref);
00413 }
00414 catch (...)
00415 {
00416 make_emptyBuff();
00417 throw;
00418 }
00419 }
00420 return *this;
00421 }
00422
00423 template<class SUB>
00424 InPlaceAnyHolder&
00425 operator= (SUB const& newContent)
00426 {
00427 if ( empty()
00428 || !isSameObject (*buff().getBase(), newContent)
00429 )
00430 {
00431 killBuffer();
00432 try
00433 {
00434 place_inBuff (newContent);
00435 }
00436 catch (...)
00437 {
00438 make_emptyBuff();
00439 throw;
00440 }
00441 }
00442 return *this;
00443 }
00444
00445
00446
00462 template<class SUB>
00463 SUB& get() const
00464 {
00465 typedef const Buffer* Iface;
00466 typedef const Buff<SUB> * Actual;
00467 Iface interface = &buff();
00468 Actual actual = dynamic_cast<Actual> (interface);
00469 if (actual)
00470 return actual->get();
00471
00472
00473
00474 SUB* content = AccessPolicy::template access<SUB> (asBase());
00475 if (content)
00476 return *content;
00477
00478 throw lumiera::error::Logic ("Attempt to access OpaqueHolder's contents "
00479 "specifying incompatible target type"
00480 , LUMIERA_ERROR_WRONG_TYPE
00481 );
00482 }
00483
00484
00485
00486 bool
00487 empty() const
00488 {
00489 return buff().empty();
00490 }
00491
00492
00493 bool
00494 isValid() const
00495 {
00496 return buff().isValid();
00497 }
00498 };
00499
00500
00501
00502
00503
00504
00530 template
00531 < class BA
00532 , size_t siz = sizeof(BA)
00533 >
00534 class OpaqueHolder
00535 : public InPlaceAnyHolder<siz, InPlaceAnyHolder_useCommonBase<BA> >
00536 {
00537 typedef InPlaceAnyHolder<siz, InPlaceAnyHolder_useCommonBase<BA> > InPlaceHolder;
00538
00539 public:
00540 OpaqueHolder() : InPlaceHolder() {}
00541
00542 template<class SUB>
00543 OpaqueHolder(SUB const& obj) : InPlaceHolder(obj) {}
00544
00545 template<class SUB>
00546 OpaqueHolder&
00547 operator= (SUB const& newContent)
00548 {
00549 static_cast<InPlaceHolder&>(*this) = newContent;
00550 return *this;
00551 }
00552
00553
00554
00555
00556
00557
00558
00559 BA&
00560 operator* () const
00561 {
00562 ASSERT (!InPlaceHolder::empty());
00563 return *InPlaceHolder::buff().getBase();
00564 }
00565
00566 BA*
00567 operator-> () const
00568 {
00569 ASSERT (!InPlaceHolder::empty());
00570 return InPlaceHolder::buff().getBase();
00571 }
00572
00573 };
00574
00575
00576
00577
00578
00579
00591 template
00592 < class BA
00593 , size_t siz = sizeof(BA)
00594 , class DEFAULT = BA
00595 >
00596 class InPlaceBuffer
00597 : boost::noncopyable
00598 {
00599
00600 mutable char buf_[siz];
00601
00602
00603 BA&
00604 getObj() const
00605 {
00606 return reinterpret_cast<BA&> (buf_);
00607 }
00608
00609 void
00610 placeDefault()
00611 {
00612 new(&buf_) DEFAULT();
00613 }
00614
00615 void
00616 destroy()
00617 {
00618 getObj().~BA();
00619 }
00620
00621
00622 public:
00623 InPlaceBuffer ()
00624 {
00625 placeDefault();
00626 }
00627
00628 ~InPlaceBuffer ()
00629 {
00630 destroy();
00631 }
00632
00633
00635 #define LIB_InPlaceBuffer_CTOR(_CTOR_CALL_) \
00636 destroy(); \
00637 try \
00638 { \
00639 REQUIRE (siz >= sizeof(TY)); \
00640 return *new(&buf_) _CTOR_CALL_; \
00641 } \
00642 catch (...) \
00643 { \
00644 placeDefault(); \
00645 throw; \
00646 }
00647
00648
00649 template<class TY>
00650 TY&
00651 create ()
00652 {
00653 LIB_InPlaceBuffer_CTOR ( TY() )
00654 }
00655
00656
00657 template<class TY, typename A1>
00658 TY&
00659 create (A1& a1)
00660 {
00661 LIB_InPlaceBuffer_CTOR ( TY(a1) )
00662 }
00663
00664
00665 template< class TY
00666 , typename A1
00667 , typename A2
00668 >
00669 TY&
00670 create (A1& a1, A2& a2)
00671 {
00672 LIB_InPlaceBuffer_CTOR ( TY(a1,a2) )
00673 }
00674
00675
00676 template< class TY
00677 , typename A1
00678 , typename A2
00679 , typename A3
00680 >
00681 TY&
00682 create (A1& a1, A2& a2, A3& a3)
00683 {
00684 LIB_InPlaceBuffer_CTOR ( TY(a1,a2,a3) )
00685 }
00686
00687
00688 template< class TY
00689 , typename A1
00690 , typename A2
00691 , typename A3
00692 , typename A4
00693 >
00694 TY&
00695 create (A1& a1, A2& a2, A3& a3, A4& a4)
00696 {
00697 LIB_InPlaceBuffer_CTOR ( TY(a1,a2,a3,a4) )
00698 }
00699
00700
00701 template< class TY
00702 , typename A1
00703 , typename A2
00704 , typename A3
00705 , typename A4
00706 , typename A5
00707 >
00708 TY&
00709 create (A1& a1, A2& a2, A3& a3, A4& a4, A5& a5)
00710 {
00711 LIB_InPlaceBuffer_CTOR ( TY(a1,a2,a3,a4,a5) )
00712 }
00713
00714
00715
00716
00717
00718 BA&
00719 operator* () const
00720 {
00721 return getObj();
00722 }
00723
00724 BA*
00725 operator-> () const
00726 {
00727 return &getObj();
00728 }
00729
00730
00731 template<class SUB>
00732 static SUB*
00733 access ()
00734 {
00735 BA * asBase = &getObj();
00736 SUB* content = util::AccessCasted<SUB*>::access (asBase);
00737 return content;
00738 }
00739 };
00740
00741
00742
00743
00744 }
00745 #endif