68 #ifndef LIB_OPAQUE_HOLDER_H 69 #define LIB_OPAQUE_HOLDER_H 78 #include <boost/lexical_cast.hpp> 80 #include <type_traits> 87 using LERR_(BOTTOM_VALUE);
88 using LERR_(WRONG_TYPE);
98 using lib::meta::disable_if;
99 using std::is_constructible;
102 enable_if< is_constructible<bool,X>,
104 validitySelfCheck (X
const& boolConvertible)
106 return bool(boolConvertible);
110 disable_if< is_constructible<bool,X>,
112 validitySelfCheck (X
const&)
136 convert2base (SUB& obj)
143 throw error::Logic (
"Unable to convert concrete object to Base interface" 166 convert2base (SUB& obj)
168 return static_cast<void*
> (&obj);
203 typedef typename AccessPolicy::Base * BaseP;
208 alignas(size_t) std::byte content_[siz];
210 void* ptr() {
return &content_; }
213 virtual bool isValid()
const =0;
214 virtual bool empty()
const =0;
215 virtual BaseP getBase()
const =0;
217 virtual void clone (
void* targetStorage)
const =0;
223 virtual bool isValid()
const {
return false; }
224 virtual bool empty()
const {
return true; }
230 , LERR_(BOTTOM_VALUE));
234 clone (
void* targetStorage)
const 243 template<
typename SUB>
246 static_assert (siz >=
sizeof(SUB),
"InPlaceAnyHolder: insufficient Buffer size");
251 return * std::launder (reinterpret_cast<SUB*> (unConst(
this)->ptr()));
260 Buff (SUB
const& obj)
262 new(Buffer::ptr()) SUB (obj);
267 new(Buffer::ptr()) SUB (oBuff.
get());
281 clone (
void* targetStorage)
const 283 new(targetStorage)
Buff(
get());
289 return AccessPolicy::convert2base (
get());
301 return validitySelfCheck (this->
get());
307 enum{ BUFFSIZE =
sizeof(
Buffer) };
312 char storage_[BUFFSIZE];
324 return * std::launder (reinterpret_cast<Buffer*> (&storage_));
329 return * std::launder (reinterpret_cast<const Buffer *> (&storage_));
342 new(&storage_) EmptyBuff();
347 place_inBuff (SUB
const& obj)
349 new(&storage_) Buff<SUB> (obj);
355 ref.buff().clone (storage_);
361 BaseP asBase = buff().getBase();
403 if (not isSameObject (*
this, ref))
421 operator= (SUB
const& newContent)
424 or not isSameAdr (buff().getBase(), &newContent)
430 place_inBuff (newContent);
454 typedef const Buffer* Iface;
455 typedef const Buff<SUB> * Actual;
456 Iface
interface = &buff();
457 Actual actual =
dynamic_cast<Actual
> (interface);
459 return actual->get();
463 ,LERR_(BOTTOM_VALUE));
465 throw error::Logic (
"Attempt to access OpaqueHolder's contents " 466 "specifying incompatible target type" 476 return buff().empty();
483 return buff().isValid();
487 operator bool()
const 528 ,
size_t siz =
sizeof(BA)
543 operator= (SUB
const& newContent)
545 static_cast<InPlaceHolder&
>(*this) = newContent;
558 ASSERT (!InPlaceHolder::empty());
559 return *InPlaceHolder::buff().getBase();
565 ASSERT (!InPlaceHolder::empty());
566 return InPlaceHolder::buff().getBase();
576 template<
class BA,
class DEFAULT>
603 ,
size_t siz =
sizeof(BA)
617 return * std::launder (reinterpret_cast<BA*> (&buf_));
623 static_assert (siz >=
sizeof(DEFAULT),
"InPlaceBuffer too small");
625 new(&buf_) DEFAULT();
650 static_assert (siz >=
sizeof(SUB),
"InPlaceBuffer too small");
652 new(&buf_) SUB (std::forward<SUB> (instance));
655 template<
typename TY>
661 template<
typename SUB>
665 template<
class TY,
typename...ARGS>
668 static_assert (siz >=
sizeof(TY),
"InPlaceBuffer too small");
670 new(&buf_) TY (std::forward<ARGS> (args)...);
680 template<
class TY,
typename...ARGS>
684 static_assert (siz >=
sizeof(TY),
"InPlaceBuffer too small");
688 return *
new(&buf_) TY {std::forward<ARGS> (args)...};
702 static_assert (siz >=
sizeof(SUB),
"InPlaceBuffer too small");
706 return *
new(&buf_) SUB {std::forward<SUB> (implementation)};
720 return static_cast<DEFAULT&
> (getObj());
745 BA * asBase = &getObj();
770 template<
class BA,
class DEFAULT = BA>
776 static_assert (std::has_virtual_destructor<BA>(),
777 "target interface BA must provide virtual dtor, " 778 "since InPlaceBuffer needs to take ownership.");
781 void __ensure_can_create();
785 template<
size_t maxSiz>
787 : buffer_(&targetBuffer)
798 static_assert(std::is_base_of<BA,SUB>(),
"concrete object implanted into the opaque " 799 "buffer must implement the defined interface");
800 return sizeof(SUB) <= maxSiz_;
808 __ensure_can_create<SUB>();
811 Holder& holder = *
static_cast<Holder*
> (buffer_);
813 return holder.template emplace (std::forward<SUB> (implementation));
817 template<
class SUB,
typename...ARGS>
821 __ensure_can_create<SUB>();
824 Holder& holder = *
static_cast<Holder*
> (buffer_);
826 return holder.template create<SUB> (std::forward<ARGS> (args)...);
835 return &bufferContent;
844 template<
class BA,
class B0>
849 if (not this->canCreate<SUB>())
850 throw error::Fatal(
"Unable to implant implementation object of size " 851 "exceeding the pre-established storage buffer capacity. " 852 +boost::lexical_cast<std::string>(
sizeof(SUB)) +
" > " 853 +boost::lexical_cast<std::string>(maxSiz_)
854 ,error::LUMIERA_ERROR_CAPACITY);
Helper template to access a given value, possibly converted or casted in a safe way.
TY & create(ARGS &&...args)
Abbreviation for placement new.
Any copy and copy construction prohibited.
virtual ~Buffer()
this is an ABC with VTable
SUB & create(ARGS &&...args)
Abbreviation for placement new of a subclass SUB into the opaque buffer.
InPlaceBuffer(SUB &&instance)
immediately move-emplace an embedded subclass type
SUB & get() const
< core operation: target is contained within the inline buffer
Implementation namespace for support and library code.
InPlaceBuffer(TypeTag< TY >, ARGS &&...args)
immediately emplace an embedded subclass type
Inline buffer to hold and own an object while concealing the concrete type.
Derived specific exceptions within Lumiera's exception hierarchy.
SUB & emplace(SUB &&implementation)
move-construct an instance of a subclass into the opaque buffer
Inline buffer to hold and own an object while concealing the concrete type.
SUB & emplace(SUB &&implementation)
move-construct an instance of subclass into the opaque buffer
Mix-Ins to allow or prohibit various degrees of copying and cloning.
A handle to allow for safe »remote implantation« of an unknown subclass into a given opaque InPlaceBu...
Tiny helper functions and shortcuts to be used everywhere Consider this header to be effectively incl...
Lumiera error handling (C++ interface).
Inner capsule managing the contained object (interface)
Standard policy for accessing the contents via a common base class interface.
void __ensure_can_create()
Buffer to place and maintain an object instance privately within another object.
bool isSameAdr(A const &a, B const &b)
compare plain object address identity, disregarding type.
special case: no stored object
static auto embedType()
helper to mark the subclass type to create.
concrete subclass to manage a specific kind of contained object.
Helper for accessing a value, employing either a conversion or downcast, depending on the relation of...
bool isSameObject(A const &a, B const &b)
compare plain object identity, based directly on the referee's memory identities. ...