From e2bb2c440c7f20d25f723bb5023f160043125c70 Mon Sep 17 00:00:00 2001 From: Ichthyostega Date: Sun, 5 Jul 2009 03:38:33 +0200 Subject: [PATCH] use OpaqueHolder to solve the problem with the function type erasure... ...tried to use 2 policies, but doesn't work correct (and is uggly) --- src/lib/meta/function-erasure.hpp | 71 ++++++--------------------- src/lib/opaque-holder.hpp | 79 +++++++++++++++++++++++++------ 2 files changed, 80 insertions(+), 70 deletions(-) diff --git a/src/lib/meta/function-erasure.hpp b/src/lib/meta/function-erasure.hpp index 6d3729160..5690c745a 100644 --- a/src/lib/meta/function-erasure.hpp +++ b/src/lib/meta/function-erasure.hpp @@ -56,6 +56,7 @@ #include "lib/util.hpp" #include "lib/error.hpp" #include "lib/bool-checkable.hpp" +#include "lib/opaque-holder.hpp" #include @@ -96,80 +97,38 @@ namespace typelist{ /* ====== Policy classes ====== */ - /** + typedef function FunVoid; + typedef lib::OpaqueHolder< FunVoid + , sizeof(FunVoid) // same size for all function objects + , lib::OpaqueHolder_useBruteForceCast // no common base class! + > FunHolder; + + /** * Policy for FunErasure: store an embedded tr1::function * Using this policy allows to store arbitrary complex functor objects * embedded within a neutral container and retrieving them later type-safe. * The price to pay is vtable access and heap storage of function arguments. */ class StoreFunction - : public lib::BoolCheckable + : public FunHolder { - /** Helper: type erasure */ - struct Holder - { - enum { SIZE = sizeof(function) }; - char storage_[SIZE]; - virtual ~Holder() {} - virtual bool isValid() const { return false; } - }; - - /** embedding the concrete functor object */ - template - struct FunctionHolder : Holder - { - typedef function Functor; - - FunctionHolder (Functor const& fun) - { - REQUIRE (SIZE >= sizeof(Functor)); - new(&storage_) Functor (fun); - } - ~FunctionHolder() - { - get().~Functor(); - } - bool - isValid() const - { - const Functor& func (unConst(this)->get()); - return bool(func); - } - Functor& - get() - { - return *reinterpret_cast (&storage_); - } - }; - - /** embedded buffer actually holding - * the concrete Functor object */ - Holder holder_; public: template StoreFunction (SIG& fun) - { - new(&holder_) FunctionHolder (function(fun)); - } + : FunHolder(function(fun)) + { } + template StoreFunction (function const& fun) - { - new(&holder_) FunctionHolder (fun); - } + : FunHolder(fun) + { } template function& getFun () { - REQUIRE (INSTANCEOF (FunctionHolder, &holder_)); - return static_cast&> (holder_).get(); - } - - bool - isValid() const - { - return holder_.isValid(); + return get >(); } }; diff --git a/src/lib/opaque-holder.hpp b/src/lib/opaque-holder.hpp index ab637f082..67e4eb6fc 100644 --- a/src/lib/opaque-holder.hpp +++ b/src/lib/opaque-holder.hpp @@ -87,6 +87,47 @@ namespace lib { } + /* ==== Policy classes for OpaqueHolder ==== */ + + /** + * Standard policy for accessing the contents via + * a common base class interface. Using this policy + * causes a virtual get() function to be used, where + * the actual Buff-subclasses will define overrides + * with covariant return types. + */ + template + class OpaqueHolder_useCommonBase + : public STO + { + typedef typename STO::BaseType Base; + + public: + /** @note a virtual get() function to be overridden */ + virtual Base& get() const =0; + }; + + /** + * Alternative policy for accessing the contents via + * a common interface; use this policy if the intention is + * to use OpaqueHolder with a family of similar classes, + * \em without requiring all of them to be derived from + * a common base class. (E.g. tr1::function objects). + * In this case, the BA template parameter of OpaqueHolder + * can be considered just a nominal placeholder. + * @note using this policy renders the smart-ptr style + * access largely useless and might even cause + * segmentation errors, when trying to access + * the contents of the buffer this way through + * a brute force reinterpret_cast. + */ + template + class OpaqueHolder_useBruteForceCast + : public STO + { + + }; + @@ -105,20 +146,33 @@ namespace lib { template < class BA ///< the nominal Base/Interface class for a family of types , size_t siz = sizeof(BA) ///< maximum storage required for the targets to be held inline + , template class AccessPolicy = OpaqueHolder_useCommonBase + ///< how to access the contents via a common interface? > class OpaqueHolder : public BoolCheckable > { - /** Inner capsule managing the contained object (interface) */ - struct Buffer + /** Storage buffer holding the target object inline */ + struct Storage { char content_[siz]; void* ptr() { return &content_; } - virtual ~Buffer() {} - virtual bool isValid() const { return false; } - virtual bool empty() const { return true; } + typedef BA BaseType; + + virtual ~Storage() {} + }; + + /** Inner capsule managing the contained object (interface) */ + struct Buffer + : AccessPolicy + { + BA& + get() const + { + return *reinterpret_cast (unConst(this)->ptr()); + } virtual void clone (void* targetStorage) const @@ -126,11 +180,8 @@ namespace lib { new(targetStorage) Buffer(); } - virtual BA& - get() const - { - throw lumiera::error::Logic ("get() called on empty Buffer"); - } + virtual bool isValid() const { return false; } + virtual bool empty() const { return true; } }; @@ -171,22 +222,22 @@ namespace lib { } - void + virtual void clone (void* targetStorage) const { new(targetStorage) Buff(this->get()); } - bool + virtual bool empty() const { return false; } - bool + virtual bool isValid() const { - return validitySelfCheck (get()); + return validitySelfCheck (this->get()); } };