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:
Fischlurch 2016-09-04 23:21:15 +02:00
parent 5c0baba2eb
commit ebb3ccb589
3 changed files with 72 additions and 58 deletions

View file

@ -48,7 +48,9 @@
namespace lib {
namespace diff{
ScopeManager::~ScopeManager() { }; ///< emit VTable here...
TreeMutator::~TreeMutator() { } ///< emit VTables here...
ScopeManager::~ScopeManager() { };

View file

@ -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;

View file

@ -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