77 #ifndef LIB_OPAQUE_HOLDER_H 78 #define LIB_OPAQUE_HOLDER_H 87 #include <boost/lexical_cast.hpp> 91 #include <type_traits> 97 using LERR_(BOTTOM_VALUE);
98 using LERR_(WRONG_TYPE);
107 using lib::meta::disable_if;
108 using std::is_constructible;
111 enable_if< is_constructible<bool,X>,
113 validitySelfCheck (X
const& boolConvertible)
115 return bool(boolConvertible);
119 disable_if< is_constructible<bool,X>,
121 validitySelfCheck (X
const&)
145 convert2base (SUB& obj)
152 throw error::Logic (
"Unable to convert concrete object to Base interface" 175 convert2base (SUB& obj)
177 return static_cast<void*
> (&obj);
212 typedef typename AccessPolicy::Base * BaseP;
217 alignas(size_t) std::byte content_[siz];
219 void* ptr() {
return &content_; }
222 virtual bool isValid()
const =0;
223 virtual bool empty()
const =0;
224 virtual BaseP getBase()
const =0;
226 virtual void clone (
void* targetStorage)
const =0;
232 virtual bool isValid()
const {
return false; }
233 virtual bool empty()
const {
return true; }
239 , LERR_(BOTTOM_VALUE));
243 clone (
void* targetStorage)
const 252 template<
typename SUB>
255 static_assert (siz >=
sizeof(SUB),
"InPlaceAnyHolder: insufficient Buffer size");
260 return * std::launder (reinterpret_cast<SUB*> (unConst(
this)->ptr()));
269 Buff (SUB
const& obj)
271 new(Buffer::ptr()) SUB (obj);
276 new(Buffer::ptr()) SUB (oBuff.
get());
290 clone (
void* targetStorage)
const 292 new(targetStorage)
Buff(
get());
298 return AccessPolicy::convert2base (
get());
310 return validitySelfCheck (this->
get());
316 enum{ BUFFSIZE =
sizeof(
Buffer) };
321 char storage_[BUFFSIZE];
333 return * std::launder (reinterpret_cast<Buffer*> (&storage_));
338 return * std::launder (reinterpret_cast<const Buffer *> (&storage_));
351 new(&storage_) EmptyBuff();
356 place_inBuff (SUB
const& obj)
358 new(&storage_) Buff<SUB> (obj);
364 ref.buff().clone (storage_);
370 BaseP asBase = buff().getBase();
412 if (not isSameObject (*
this, ref))
430 operator= (SUB
const& newContent)
433 or not isSameObject (*buff().getBase(), newContent)
439 place_inBuff (newContent);
463 typedef const Buffer* Iface;
464 typedef const Buff<SUB> * Actual;
465 Iface
interface = &buff();
466 Actual actual =
dynamic_cast<Actual
> (interface);
468 return actual->get();
472 ,LERR_(BOTTOM_VALUE));
474 throw error::Logic (
"Attempt to access OpaqueHolder's contents " 475 "specifying incompatible target type" 485 return buff().empty();
492 return buff().isValid();
496 operator bool()
const 537 ,
size_t siz =
sizeof(BA)
552 operator= (SUB
const& newContent)
554 static_cast<InPlaceHolder&
>(*this) = newContent;
567 ASSERT (!InPlaceHolder::empty());
568 return *InPlaceHolder::buff().getBase();
574 ASSERT (!InPlaceHolder::empty());
575 return InPlaceHolder::buff().getBase();
585 template<
class BA,
class DEFAULT>
612 ,
size_t siz =
sizeof(BA)
626 return * std::launder (reinterpret_cast<BA*> (&buf_));
632 static_assert (siz >=
sizeof(DEFAULT),
"InPlaceBuffer too small");
634 new(&buf_) DEFAULT();
659 static_assert (siz >=
sizeof(SUB),
"InPlaceBuffer too small");
661 new(&buf_) SUB (std::forward<SUB> (instance));
664 template<
typename TY>
670 template<
typename SUB>
674 template<
class TY,
typename...ARGS>
677 static_assert (siz >=
sizeof(TY),
"InPlaceBuffer too small");
679 new(&buf_) TY (std::forward<ARGS> (args)...);
689 template<
class TY,
typename...ARGS>
693 static_assert (siz >=
sizeof(TY),
"InPlaceBuffer too small");
697 return *
new(&buf_) TY {std::forward<ARGS> (args)...};
711 static_assert (siz >=
sizeof(SUB),
"InPlaceBuffer too small");
715 return *
new(&buf_) SUB {std::forward<SUB> (implementation)};
729 return static_cast<DEFAULT&
> (getObj());
754 BA * asBase = &getObj();
779 template<
class BA,
class DEFAULT = BA>
785 static_assert (std::has_virtual_destructor<BA>(),
786 "target interface BA must provide virtual dtor, " 787 "since InPlaceBuffer needs to take ownership.");
790 void __ensure_can_create();
794 template<
size_t maxSiz>
796 : buffer_(&targetBuffer)
807 static_assert(std::is_base_of<BA,SUB>(),
"concrete object implanted into the opaque " 808 "buffer must implement the defined interface");
809 return sizeof(SUB) <= maxSiz_;
817 __ensure_can_create<SUB>();
820 Holder& holder = *
static_cast<Holder*
> (buffer_);
822 return holder.template emplace (std::forward<SUB> (implementation));
826 template<
class SUB,
typename...ARGS>
830 __ensure_can_create<SUB>();
833 Holder& holder = *
static_cast<Holder*
> (buffer_);
835 return holder.template create<SUB> (std::forward<ARGS> (args)...);
844 return &bufferContent;
853 template<
class BA,
class B0>
858 if (not this->canCreate<SUB>())
859 throw error::Fatal(
"Unable to implant implementation object of size " 860 "exceeding the pre-established storage buffer capacity. " 861 +boost::lexical_cast<std::string>(
sizeof(SUB)) +
" > " 862 +boost::lexical_cast<std::string>(maxSiz_)
863 ,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.
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, bypassing any custom comparison operators.