diff --git a/src/lib/polymorphic-value.hpp b/src/lib/polymorphic-value.hpp
index bd343342f..70a8bd35a 100644
--- a/src/lib/polymorphic-value.hpp
+++ b/src/lib/polymorphic-value.hpp
@@ -23,7 +23,7 @@
/** @file polymorphic-value.hpp
** A mechanism to allow for opaque polymorphic value objects.
** This template helps to overcome a problem frequently encountered in
- ** C++ programming, based on the fundamental design of C++, favouring
+ ** C++ programming, based on the fundamental design of C++, which favours
** explicit low-level control, copying of values and strict ctor-dtor pairs.
** Many object oriented design patterns build on polymorphism, where the
** actual type of an object isn't disclosed and collaborations rely on
@@ -35,7 +35,7 @@
** so 'objects' need just to be mentioned by reference.
**
** In C++ to employ many of the well known techniques, you're more or less
- ** bound to explicitly put the objects somewhere in hash allocated memory
+ ** bound to explicitly put the objects somewhere in heap allocated memory
** and then pass an interface pointer or reference into the actual algorithm.
** Often, this hinders a design based on constant values and small descriptor
** objects used inline, thus forcing into unnecessarily complex and heavyweight
@@ -46,19 +46,54 @@
** as \c const& -- typically constructing an anonymous temporary object conveniently
** just for passing an abstraction barrier (while the optimiser can be expected to
** remove this barrier and the accompanying nominal copy operations altogether in
- ** the generated code). Thus, the ability to return a polymorphic object from a
- ** factory or configuration function by value would open a lot of
+ ** the generated code). Consequently the ability to return a polymorphic object
+ ** from a factory or configuration function by value would open a lot of
** straight forward design possibilities and concise formulations.
**
** \par how to build a copyable value without knowing it's layout in detail
**
** So the goal is to build a copyable and assignable type with value semantics,
** without disclosing the actual implementation and object layout at the usage site.
- ** This seemingly contradictory can be achieved, provided that
+ ** This seemingly contradictory goal can be achieved, provided that
** - the space occupied by the actual implementation object is limited,
** so it can be placed as binary data into an otherwise opaque holder buffer
** - and the actual implementation object assists with copying and cloning
- ** itself, observing the actual implementation type and layout
+ ** itself, observing the actual implementation data layout
+ **
+ ** The PolymorphicValue template implements this idea, by exposing an copyable
+ ** container with value semantics to the client code. On instantiation, a common
+ ** base interface for the actual value objects needs to be provided; the resulting
+ ** instance will be automatically convertible to this interface. Obviously this
+ ** common interface must be an ABC or at least contain some virtual functions.
+ ** Moreover, the PolymorphicValue container provides static builder functions,
+ ** allowing to place a concrete instance of a subclass into the content buffer.
+ ** After construction, the actual type of this instance will be forgotten
+ ** (``type erasure''), but because the embedded vtable, on access the
+ ** proper implementation functions will be invoked.
+ **
+ ** Expanding on that pattern, the copying and cloning operations of the whole
+ ** container can be implemented by forwarding to appropriate virtual functions
+ ** on the embedded payload (implementation) object -- the concrete implementation
+ ** of these virtual functions can be assumed to know the real type and thus be
+ ** able to invoke the correct copy ctor or assignment operator. For this to
+ ** work, the interface needs to expose those copy and clone operations somehow
+ ** as virtual functions. There are two alternatives to get at this point:
+ ** - in the general case, the common base interface doesn't expose such operations.
+ ** Thus we need to mix in an additional \em management interface; this
+ ** can be done by \em subclassing the desired implementation type, because
+ ** this concrete type is irrelevant after finishing the placement constructor.
+ ** In order to re-access this management interface, so to be able to invoke
+ ** the copy or clone operations, we need to do an elaborate re-cast operation,
+ ** first going down to the leaf type and then back up into the mixed in
+ ** management interface. Basically this operation is performed by using
+ ** an \c dynamic_cast(bufferContents)
+ ** - but when the used client types provide some collaboration and implement
+ ** this management interface either directly on the API or as an immediate
+ ** sub-interface, then this copy/management interface is located within the
+ ** direct inheritance chain and can be reached by a simple \c static_cast.
+ ** Indeed, as we're just using a different meaning of the VTable, only a
+ ** single indirection (virtual function call) is required at runtime in
+ ** this case to invoke the copy ctor or assignment operator.
**
** @see polymorphic-value-test.cpp
** @see opaque-holder.hpp other similar opaque inline buffer templates
@@ -71,11 +106,13 @@
#include "lib/error.hpp"
+#include "lib/meta/duck-detector.hpp"
//#include "lib/bool-checkable.hpp"
//#include "lib/access-casted.hpp"
//#include "lib/util.hpp"
//#include
+#include
namespace lib {
@@ -85,8 +122,74 @@ namespace lib {
// using util::unConst;
- namespace { // implementation helpers...
+ namespace polyvalue { // implementation helpers...
+ using boost::enable_if;
+ using lumiera::Yes_t;
+ using lumiera::No_t;
+
+ struct EmptyBase{ };
+
+ template
+ class CopySupport
+ : public BA
+ {
+ public:
+ virtual ~CopySupport() { };
+ virtual void cloneInto (void* targetBuffer) const =0;
+ virtual void copyInto (IFA& targetBase) const =0;
+ };
+
+
+
+
+ template
+ class exposes_copySupportFunctions
+ {
+
+ META_DETECT_FUNCTION(void, cloneInto, (void*) const);
+
+ public:
+ enum{ value = HasFunSig_cloneInto::value
+ };
+ };
+
+
+ template
+ struct Trait
+ {
+ typedef CopySupport CopyAPI;
+ enum{ ADMIN_OVERHEAD = 2 * sizeof(void*) };
+
+ static CopyAPI&
+ accessCopyHandlingInterface (TY& bufferContents)
+ {
+ REQUIRE (INSTANCEOF (CopyAPI, &bufferContents));
+ return dynamic_cast (bufferContents);
+ }
+
+ typedef CopyAPI AdapterAttachment;
+ };
+
+
+ template
+ struct Trait >::type>
+ {
+ typedef TY CopyAPI;
+ enum{ ADMIN_OVERHEAD = 1 * sizeof(void*) };
+
+ template
+ static CopyAPI&
+ accessCopyHandlingInterface (IFA& bufferContents)
+ {
+ REQUIRE (INSTANCEOF (CopyAPI, &bufferContents));
+ return static_cast (bufferContents);
+ }
+
+ typedef EmptyBase AdapterAttachment;
+ };
}
@@ -112,10 +215,18 @@ namespace lib {
*/
template
< class IFA ///< the nominal Base/Interface class for a family of types
- , size_t siz ///< maximum storage required for the targets to be held inline
+ , size_t storage ///< maximum storage required for the target data to be held inline
+ , class CPY = IFA ///< special sub-interface to support copy operations
>
class PolymorphicValue
{
+
+ typedef polyvalue::Trait _Traits;
+ typedef typename _Traits::CopyAPI _CopyHandlingAdapter;
+ enum{
+ siz = storage + _Traits::ADMIN_OVERHEAD
+ };
+
mutable char buf_[siz];
template
@@ -158,18 +269,10 @@ namespace lib {
}
- class HandlingAdapter
- {
- public:
- virtual ~HandlingAdapter() { };
- virtual void cloneInto (void* targetBuffer) const =0;
- virtual void copyInto (IFA& targetBase) const =0;
- };
-
template
class Adapter
: public IMP
- , public HandlingAdapter
+ , public _Traits::AdapterAttachment
{
virtual void
cloneInto (void* targetBuffer) const
@@ -200,15 +303,15 @@ namespace lib {
};
- HandlingAdapter&
+ _CopyHandlingAdapter&
accessHandlingInterface () const
{
IFA& bufferContents = access();
- REQUIRE (INSTANCEOF (HandlingAdapter, &bufferContents));
- HandlingAdapter& hap = dynamic_cast (bufferContents);
- return hap;
+ _CopyHandlingAdapter& hap = _Traits::accessCopyHandlingInterface (bufferContents);
+ return hap; ////TODO cleanup unnecessary temporary
}
+
public:
operator IFA& ()
{
diff --git a/tests/lib/polymorphic-value-test.cpp b/tests/lib/polymorphic-value-test.cpp
index 7674b677e..26570c8ff 100644
--- a/tests/lib/polymorphic-value-test.cpp
+++ b/tests/lib/polymorphic-value-test.cpp
@@ -216,7 +216,7 @@ namespace test{
CHECK (elm == myLocalVal);
CHECK (!isSameObject (elm, myLocalVal));
- CHECK (sizeof(myLocalVal) <= MAX_SIZ + _ALIGN_);
+ CHECK (sizeof(myLocalVal) <= MAX_SIZ + polyvalue::Trait::ADMIN_OVERHEAD + _ALIGN_);
}