WIP implementation draft

This commit is contained in:
Fischlurch 2009-07-04 04:35:17 +02:00
parent ec2e4e36ea
commit 077d3d176e
2 changed files with 117 additions and 14 deletions

View file

@ -26,18 +26,18 @@
** to a specific type, thus ruling out polymorphism. But sometimes, when
** we are able to control the maximum storage for a family of classes, we
** can escape this dilemma by using the type erasure pattern combined with
** an inline buffer holding the object of the concrete subclass. Frequently
** an inline buffer holding an object of the concrete subclass. Typically,
** this situation arises when dealing with functor objects.
**
** This template helps building custom objects and wrappers based on this
** pattern: it provides an buffer for the target objects and controls access
** through a two-layer capsule; while the outer container provides a neutral
** interface, the inner container keeps track of the actual type using a
** vtable. OpaqueHolder can be empty; but re-accessing the concrete
** through a two-layer capsule; while the outer container exposes a neutral
** interface, the inner container keeps track of the actual type by means
** of a vtable. OpaqueHolder can be empty; but re-accessing the concrete
** object requires knowledge of the actual type, similar to boost::any
** (but the latter uses heap storage).
**
** Using this approach is bound by specific stipulations regarding the
** Using this approach is bound to specific stipulations regarding the
** properties of the contained object and the kind of access needed.
** When, to the contrary, the contained types are \em not related
** and you need to re-discover their concrete type, then maybe
@ -78,21 +78,106 @@ namespace lib {
class OpaqueHolder
: public BoolCheckable<OpaqueHolder<BA,siz> >
{
char content_[siz];
typedef OpaqueHolder<BA,siz> _ThisType;
/** Inner capsule managing the contained object (interface) */
struct Buffer
{
char content_[siz];
virtual ~Buffer() {}
virtual bool isValid() const { return false; }
virtual bool empty() const { return true; }
virtual void
clone (void* targetStorage) const
{
new(targetStorage) Buffer();
}
};
/** concrete subclass managing a specific kind of contained object */
template<typename SUB>
struct Buff : Buffer
{
~Buff()
{
get().~SUB();
}
explicit
Buff (SUB const& obj)
{
REQUIRE (siz >= sizeof(SUB));
new(&content_) SUB (obj);
}
Buff (Buff const& oBuff)
{
new(&content_) SUB (oBuff.get());
}
Buff&
operator= (Buff const& ref)
{
if (&ref != this)
get() = ref.get();
return *this;
}
void
clone (void* targetStorage) const
{
new(targetStorage) Buff(this->get());
}
bool
empty() const
{
return false;
}
bool
isValid() const
{
UNIMPLEMENTED ("maybe forward bool check to contained object...");
}
SUB&
get() const
{
return *reinterpret_cast<SUB*> (&content_);
}
};
enum{ BUFFSIZE = sizeof(Buffer) };
/** embedded buffer actually holding the concrete Buff object,
* which in turn holds and manages the target object */
char storage_[BUFFSIZE];
typedef OpaqueHolder<BA,siz> _ThisType; /////TODO needed?
Buffer&
buff()
{
return *reinterpret_cast<Buffer*> (&storage_);
}
public:
OpaqueHolder()
// : created_(0)
{ }
{
new(&storage_) Buffer();
}
template<class SUB>
OpaqueHolder(SUB const& obj)
// : created_(0)
{ }
{
new(&storage_) Buff<SUB> (obj);
}
~OpaqueHolder() { clear(); }
@ -100,13 +185,15 @@ namespace lib {
void
clear ()
{
UNIMPLEMENTED ("delete contained object, if any");
buff().~Holder();
//////////////////////TODO sufficient?
}
OpaqueHolder (OpaqueHolder const& ref)
// : created_(must_be_empty (ref))
{ }
{
ref.clone (storage_);
}
OpaqueHolder&
operator= (OpaqueHolder const& ref)

View file

@ -91,6 +91,8 @@ namespace test{
typedef OpaqueHolder<Base> Opaque;
typedef vector<Opaque> TestList;
/**********************************************************************************
* @test use the OpaqueHolder inline buffer to handle a family of classes
* through a common interface, without being forced to use heap storage
@ -155,6 +157,20 @@ namespace test{
ASSERT (5 == oo->getIt());
VERIFY_ERROR (WRONG_TYPE, oo.get<D3>() );
D5 &rd5 (oo.get<D5>());
ASSERT (isSameObject (rd5, *oo));
// verify that self-assignment is properly detected...
oo = oo;
ASSERT (oo);
ASSERT (isSameObject (rd5, *oo));
oo = oo.get<D5>();
ASSERT (isSameObject (rd5, *oo));
ASSERT (oo);
oo = *oo;
ASSERT (isSameObject (rd5, *oo));
ASSERT (oo);
oo.clear();
ASSERT (!oo);
ASSERT (isnil(oo));