WIP implementation draft
This commit is contained in:
parent
ec2e4e36ea
commit
077d3d176e
2 changed files with 117 additions and 14 deletions
|
|
@ -26,18 +26,18 @@
|
||||||
** to a specific type, thus ruling out polymorphism. But sometimes, when
|
** 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
|
** 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
|
** 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 situation arises when dealing with functor objects.
|
||||||
**
|
**
|
||||||
** This template helps building custom objects and wrappers based on this
|
** This template helps building custom objects and wrappers based on this
|
||||||
** pattern: it provides an buffer for the target objects and controls access
|
** pattern: it provides an buffer for the target objects and controls access
|
||||||
** through a two-layer capsule; while the outer container provides a neutral
|
** through a two-layer capsule; while the outer container exposes a neutral
|
||||||
** interface, the inner container keeps track of the actual type using a
|
** interface, the inner container keeps track of the actual type by means
|
||||||
** vtable. OpaqueHolder can be empty; but re-accessing the concrete
|
** of a vtable. OpaqueHolder can be empty; but re-accessing the concrete
|
||||||
** object requires knowledge of the actual type, similar to boost::any
|
** object requires knowledge of the actual type, similar to boost::any
|
||||||
** (but the latter uses heap storage).
|
** (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.
|
** properties of the contained object and the kind of access needed.
|
||||||
** When, to the contrary, the contained types are \em not related
|
** When, to the contrary, the contained types are \em not related
|
||||||
** and you need to re-discover their concrete type, then maybe
|
** and you need to re-discover their concrete type, then maybe
|
||||||
|
|
@ -78,21 +78,106 @@ namespace lib {
|
||||||
class OpaqueHolder
|
class OpaqueHolder
|
||||||
: public BoolCheckable<OpaqueHolder<BA,siz> >
|
: 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:
|
public:
|
||||||
OpaqueHolder()
|
OpaqueHolder()
|
||||||
// : created_(0)
|
{
|
||||||
{ }
|
new(&storage_) Buffer();
|
||||||
|
}
|
||||||
|
|
||||||
template<class SUB>
|
template<class SUB>
|
||||||
OpaqueHolder(SUB const& obj)
|
OpaqueHolder(SUB const& obj)
|
||||||
// : created_(0)
|
{
|
||||||
{ }
|
new(&storage_) Buff<SUB> (obj);
|
||||||
|
}
|
||||||
|
|
||||||
~OpaqueHolder() { clear(); }
|
~OpaqueHolder() { clear(); }
|
||||||
|
|
||||||
|
|
@ -100,13 +185,15 @@ namespace lib {
|
||||||
void
|
void
|
||||||
clear ()
|
clear ()
|
||||||
{
|
{
|
||||||
UNIMPLEMENTED ("delete contained object, if any");
|
buff().~Holder();
|
||||||
|
//////////////////////TODO sufficient?
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
OpaqueHolder (OpaqueHolder const& ref)
|
OpaqueHolder (OpaqueHolder const& ref)
|
||||||
// : created_(must_be_empty (ref))
|
{
|
||||||
{ }
|
ref.clone (storage_);
|
||||||
|
}
|
||||||
|
|
||||||
OpaqueHolder&
|
OpaqueHolder&
|
||||||
operator= (OpaqueHolder const& ref)
|
operator= (OpaqueHolder const& ref)
|
||||||
|
|
|
||||||
|
|
@ -91,6 +91,8 @@ namespace test{
|
||||||
typedef OpaqueHolder<Base> Opaque;
|
typedef OpaqueHolder<Base> Opaque;
|
||||||
typedef vector<Opaque> TestList;
|
typedef vector<Opaque> TestList;
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
/**********************************************************************************
|
/**********************************************************************************
|
||||||
* @test use the OpaqueHolder inline buffer to handle a family of classes
|
* @test use the OpaqueHolder inline buffer to handle a family of classes
|
||||||
* through a common interface, without being forced to use heap storage
|
* through a common interface, without being forced to use heap storage
|
||||||
|
|
@ -155,6 +157,20 @@ namespace test{
|
||||||
ASSERT (5 == oo->getIt());
|
ASSERT (5 == oo->getIt());
|
||||||
VERIFY_ERROR (WRONG_TYPE, oo.get<D3>() );
|
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();
|
oo.clear();
|
||||||
ASSERT (!oo);
|
ASSERT (!oo);
|
||||||
ASSERT (isnil(oo));
|
ASSERT (isnil(oo));
|
||||||
|
|
|
||||||
Loading…
Reference in a new issue