68#ifndef LIB_OPAQUE_HOLDER_H
69#define LIB_OPAQUE_HOLDER_H
78#include <boost/lexical_cast.hpp>
87 using LERR_(BOTTOM_VALUE);
88 using LERR_(WRONG_TYPE);
99 using std::is_constructible;
102 enable_if< is_constructible<bool,X>,
106 return bool(boolConvertible);
110 disable_if< is_constructible<bool,X>,
143 throw error::Logic (
"Unable to convert concrete object to Base interface"
168 return static_cast<void*
> (&obj);
198 ,
class AccessPolicy = InPlaceAnyHolder_unrelatedTypes
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));
243 template<
typename SUB>
246 static_assert (siz >=
sizeof(SUB),
"InPlaceAnyHolder: insufficient Buffer size");
251 return * std::launder (
reinterpret_cast<SUB*
> (unConst(
this)->
ptr()));
283 new(targetStorage)
Buff(
get());
289 return AccessPolicy::convert2base (
get());
301 return validitySelfCheck (this->
get());
329 return * std::launder (
reinterpret_cast<const Buffer *
> (&
storage_));
403 if (not isSameObject (*
this, ref))
424 or not isSameAdr (
buff().getBase(), &newContent)
454 using Iface =
const Buffer *;
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"
487 operator bool()
const
528 ,
size_t siz =
sizeof(BA)
543 operator= (SUB
const& 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>
577 class PlantingHandle;
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.");
785 template<
size_t maxSiz>
798 static_assert(std::is_base_of<BA,SUB>(),
"concrete object implanted into the opaque "
799 "buffer must implement the defined interface");
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 for accessing a value, employing either a conversion or downcast, depending on the relation of...
Inline buffer to hold and own an object while concealing the concrete type.
char storage_[BUFFSIZE]
embedded buffer actually holding the concrete Buff object, which in turn holds and manages the target...
void clone_inBuff(InPlaceAnyHolder const &ref)
void place_inBuff(SUB const &obj)
AccessPolicy::Base * BaseP
const Buffer & buff() const
InPlaceAnyHolder(SUB const &obj)
InPlaceAnyHolder(InPlaceAnyHolder const &ref)
InPlaceAnyHolder & operator=(InPlaceAnyHolder const &ref)
SUB & get() const
re-accessing the concrete contained object.
Buffer to place and maintain an object instance privately within another object.
PlantingHandle< BA, DEFAULT > Handle
a "planting handle" can be used to expose an opaque InPlaceBuffer through an API
static auto embedType()
helper to mark the subclass type to create.
InPlaceBuffer(TypeTag< TY >, ARGS &&...args)
immediately emplace an embedded subclass type
TY & create(ARGS &&...args)
Abbreviation for placement new.
SUB & emplace(SUB &&implementation)
move-construct an instance of subclass into the opaque buffer
InPlaceBuffer(SUB &&instance)
immediately move-emplace an embedded subclass type
Inline buffer to hold and own an object while concealing the concrete type.
InPlaceAnyHolder< siz, InPlaceAnyHolder_useCommonBase< BA > > InPlaceHolder
OpaqueHolder(SUB const &obj)
A handle to allow for safe »remote implantation« of an unknown subclass into a given opaque InPlaceBu...
void __ensure_can_create()
PlantingHandle(InPlaceBuffer< BA, maxSiz, DEFAULT > &targetBuffer)
SUB & emplace(SUB &&implementation)
move-construct an instance of a subclass into the opaque buffer
SUB & create(ARGS &&...args)
Abbreviation for placement new of a subclass SUB into the opaque buffer.
Derived specific exceptions within Lumiera's exception hierarchy.
Lumiera error handling (C++ interface).
enable_if< is_constructible< bool, X >, bool > validitySelfCheck(X const &boolConvertible)
Implementation namespace for support and library code.
LumieraError< LERR_(FATAL), Logic > Fatal
LumieraError< LERR_(LOGIC)> Logic
LumieraError< LERR_(INVALID)> Invalid
bool isSameObject(A const &a, B const &b)
compare plain object identity, based directly on the referee's memory identities.
bool isSameAdr(A const &a, B const &b)
compare plain object address identity, disregarding type.
OBJ * unConst(const OBJ *)
shortcut to save some typing when having to define const and non-const variants of member functions
Mix-Ins to allow or prohibit various degrees of copying and cloning.
concrete subclass to manage a specific kind of contained object.
Buff & operator=(Buff const &ref)
virtual bool isValid() const
virtual void clone(void *targetStorage) const
virtual bool empty() const
SUB & get() const
< core operation: target is contained within the inline buffer
virtual BaseP getBase() const
Inner capsule managing the contained object (interface)
virtual BaseP getBase() const =0
virtual bool isValid() const =0
virtual ~Buffer()
this is an ABC with VTable
virtual void clone(void *targetStorage) const =0
virtual bool empty() const =0
special case: no stored object
virtual bool isValid() const
virtual void clone(void *targetStorage) const
virtual bool empty() const
Standard policy for accessing the contents via a common base class interface.
static Base * convert2base(SUB &obj)
static if_can_use_dynamic_downcast< SRC &&, TAR >::type access(SRC &&elem)
Tiny helper functions and shortcuts to be used everywhere Consider this header to be effectively incl...