clean-up: move PlantingHandle over to the OpaqueHolder facility
...where it belongs; it is entirely generic and we'd expect more usage on APIs for callbacks
This commit is contained in:
parent
5c0baba2eb
commit
ebb3ccb589
3 changed files with 72 additions and 58 deletions
|
|
@ -48,7 +48,9 @@
|
|||
namespace lib {
|
||||
namespace diff{
|
||||
|
||||
ScopeManager::~ScopeManager() { }; ///< emit VTable here...
|
||||
TreeMutator::~TreeMutator() { } ///< emit VTables here...
|
||||
|
||||
ScopeManager::~ScopeManager() { };
|
||||
|
||||
|
||||
|
||||
|
|
|
|||
|
|
@ -107,63 +107,6 @@
|
|||
|
||||
|
||||
namespace lib {
|
||||
/////////////////////////////TODO move over into opaque-holder.hpp
|
||||
/**
|
||||
* handle to allow for safe _»remote implantation«_
|
||||
* of an unknown subclass into a given opaque InPlaceBuffer,
|
||||
* without having to disclose the concrete buffer type or size.
|
||||
* @remarks this is especially geared towards use in APIs, allowing
|
||||
* a not yet known implementation to implant an agent or collaboration
|
||||
* partner into the likewise undisclosed innards of the exposed service.
|
||||
* @warning the type BA must expose a virtual dtor, since the targeted
|
||||
* InPlaceBuffer has to take ownership of the implanted object.
|
||||
*/
|
||||
template<class BA>
|
||||
class PlantingHandle
|
||||
{
|
||||
void* buffer_;
|
||||
size_t maxSiz_;
|
||||
|
||||
///////TODO static assert to virtual dtor??
|
||||
public:
|
||||
template<size_t maxSiz>
|
||||
PlantingHandle (InPlaceBuffer<BA, maxSiz>& targetBuffer)
|
||||
: buffer_(&targetBuffer)
|
||||
, maxSiz_(maxSiz)
|
||||
{ }
|
||||
|
||||
|
||||
template<class SUB>
|
||||
BA&
|
||||
create (SUB&& subMutator)
|
||||
{
|
||||
if (sizeof(SUB) > maxSiz_)
|
||||
throw error::Fatal("Unable to implant implementation object of size "
|
||||
"exceeding the pre-established storage buffer capacity."
|
||||
,error::LUMIERA_ERROR_CAPACITY);
|
||||
|
||||
using Holder = InPlaceBuffer<BA, sizeof(SUB)>;
|
||||
Holder& holder = *static_cast<Holder*> (buffer_);
|
||||
|
||||
return holder.create<SUB> (std::forward<SUB> (subMutator));
|
||||
}
|
||||
|
||||
template<class SUB>
|
||||
bool
|
||||
canCreate() const
|
||||
{
|
||||
return sizeof(SUB) <= maxSiz_;
|
||||
}
|
||||
|
||||
BA*
|
||||
get() const
|
||||
{
|
||||
ENSURE (buffer_);
|
||||
BA& bufferContent = **static_cast<InPlaceBuffer<BA>*> (buffer_);
|
||||
return &bufferContent;
|
||||
}
|
||||
};
|
||||
/////////////////////////////TODO move over into opaque-holder.hpp
|
||||
namespace diff{
|
||||
|
||||
namespace error = lumiera::error;
|
||||
|
|
@ -199,6 +142,8 @@ namespace diff{
|
|||
{
|
||||
|
||||
public:
|
||||
virtual ~TreeMutator(); ///< this is an interface
|
||||
|
||||
/** only allow default and move construction */
|
||||
TreeMutator () =default;
|
||||
TreeMutator (TreeMutator&&) =default;
|
||||
|
|
|
|||
|
|
@ -571,6 +571,12 @@ namespace lib {
|
|||
* and especially it is mandatory for the base class to provide a
|
||||
* virtual dtor. On the other hand, just the (alignment rounded)
|
||||
* storage for the object(s) placed into the buffer is required.
|
||||
* @remarks as a complement, PlantingHandle may be used on APIs to offer
|
||||
* a lightweight way for clients to provide a callback.
|
||||
* @warning InPlaceBuffer really takes ownership, and even creates a
|
||||
* default constructed instance of the base class right away.
|
||||
* Yet the requirement for a virtual dtor is deliberately not
|
||||
* enforced here, to allow use for types without VTable.
|
||||
*
|
||||
* @tparam BA the nominal Base/Interface class for a family of types
|
||||
* @tparam siz maximum storage required for the targets to be held inline
|
||||
|
|
@ -669,6 +675,67 @@ namespace lib {
|
|||
|
||||
|
||||
|
||||
/**
|
||||
* handle to allow for safe _»remote implantation«_
|
||||
* of an unknown subclass into a given opaque InPlaceBuffer,
|
||||
* without having to disclose the concrete buffer type or size.
|
||||
* @remarks this is especially geared towards use in APIs, allowing
|
||||
* a not yet known implementation to implant an agent or collaboration
|
||||
* partner into the likewise undisclosed innards of the exposed service.
|
||||
* @warning the type BA must expose a virtual dtor, since the targeted
|
||||
* InPlaceBuffer has to take ownership of the implanted object.
|
||||
*/
|
||||
template<class BA>
|
||||
class PlantingHandle
|
||||
{
|
||||
void* buffer_;
|
||||
size_t maxSiz_;
|
||||
|
||||
static_assert (std::has_virtual_destructor<BA>(),
|
||||
"target interface BA must provide virtual dtor, "
|
||||
"since InPlaceBuffer needs to take ownership.");
|
||||
|
||||
public:
|
||||
template<size_t maxSiz>
|
||||
PlantingHandle (InPlaceBuffer<BA, maxSiz>& targetBuffer)
|
||||
: buffer_(&targetBuffer)
|
||||
, maxSiz_(maxSiz)
|
||||
{ }
|
||||
|
||||
|
||||
template<class SUB>
|
||||
BA&
|
||||
create (SUB&& implementation)
|
||||
{
|
||||
if (sizeof(SUB) > maxSiz_)
|
||||
throw error::Fatal("Unable to implant implementation object of size "
|
||||
"exceeding the pre-established storage buffer capacity."
|
||||
,error::LUMIERA_ERROR_CAPACITY);
|
||||
|
||||
using Holder = InPlaceBuffer<BA, sizeof(SUB)>;
|
||||
Holder& holder = *static_cast<Holder*> (buffer_);
|
||||
|
||||
return holder.create<SUB> (std::forward<SUB> (implementation));
|
||||
}
|
||||
|
||||
template<class SUB>
|
||||
bool
|
||||
canCreate() const
|
||||
{
|
||||
return sizeof(SUB) <= maxSiz_;
|
||||
}
|
||||
|
||||
BA*
|
||||
get() const
|
||||
{
|
||||
ENSURE (buffer_);
|
||||
BA& bufferContent = **static_cast<InPlaceBuffer<BA>*> (buffer_);
|
||||
return &bufferContent;
|
||||
}
|
||||
};
|
||||
|
||||
|
||||
|
||||
|
||||
} // namespace lib
|
||||
#endif
|
||||
|
|
|
|||
Loading…
Reference in a new issue