From 077d3d176eaf2fc1dba07b77d9d85a15ece079a3 Mon Sep 17 00:00:00 2001 From: Ichthyostega Date: Sat, 4 Jul 2009 04:35:17 +0200 Subject: [PATCH] WIP implementation draft --- src/lib/opaque-holder.hpp | 115 +++++++++++++++++++++++++++---- tests/lib/opaque-holder-test.cpp | 16 +++++ 2 files changed, 117 insertions(+), 14 deletions(-) diff --git a/src/lib/opaque-holder.hpp b/src/lib/opaque-holder.hpp index e64b81c41..c5e732d07 100644 --- a/src/lib/opaque-holder.hpp +++ b/src/lib/opaque-holder.hpp @@ -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 > { - char content_[siz]; - typedef OpaqueHolder _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 + 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 (&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 _ThisType; /////TODO needed? + + Buffer& + buff() + { + return *reinterpret_cast (&storage_); + } + public: OpaqueHolder() -// : created_(0) - { } + { + new(&storage_) Buffer(); + } template OpaqueHolder(SUB const& obj) -// : created_(0) - { } + { + new(&storage_) Buff (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) diff --git a/tests/lib/opaque-holder-test.cpp b/tests/lib/opaque-holder-test.cpp index 4c589ff7b..3b8e7f94d 100644 --- a/tests/lib/opaque-holder-test.cpp +++ b/tests/lib/opaque-holder-test.cpp @@ -91,6 +91,8 @@ namespace test{ typedef OpaqueHolder Opaque; typedef vector 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() ); + D5 &rd5 (oo.get()); + ASSERT (isSameObject (rd5, *oo)); + + // verify that self-assignment is properly detected... + oo = oo; + ASSERT (oo); + ASSERT (isSameObject (rd5, *oo)); + oo = oo.get(); + ASSERT (isSameObject (rd5, *oo)); + ASSERT (oo); + oo = *oo; + ASSERT (isSameObject (rd5, *oo)); + ASSERT (oo); + oo.clear(); ASSERT (!oo); ASSERT (isnil(oo));