use OpaqueHolder to solve the problem with the function type erasure...

...tried to use 2 policies, but doesn't work correct (and is uggly)
This commit is contained in:
Fischlurch 2009-07-05 03:38:33 +02:00
parent 4d1f45fc43
commit e2bb2c440c
2 changed files with 80 additions and 70 deletions

View file

@ -56,6 +56,7 @@
#include "lib/util.hpp"
#include "lib/error.hpp"
#include "lib/bool-checkable.hpp"
#include "lib/opaque-holder.hpp"
#include <tr1/functional>
@ -96,80 +97,38 @@ namespace typelist{
/* ====== Policy classes ====== */
/**
typedef function<void(void)> 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<StoreFunction>
: public FunHolder
{
/** Helper: type erasure */
struct Holder
{
enum { SIZE = sizeof(function<void(void)>) };
char storage_[SIZE];
virtual ~Holder() {}
virtual bool isValid() const { return false; }
};
/** embedding the concrete functor object */
template<typename SIG>
struct FunctionHolder : Holder
{
typedef function<SIG> 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<Functor*> (&storage_);
}
};
/** embedded buffer actually holding
* the concrete Functor object */
Holder holder_;
public:
template<typename SIG>
StoreFunction (SIG& fun)
{
new(&holder_) FunctionHolder<SIG> (function<SIG>(fun));
}
: FunHolder(function<SIG>(fun))
{ }
template<typename SIG>
StoreFunction (function<SIG> const& fun)
{
new(&holder_) FunctionHolder<SIG> (fun);
}
: FunHolder(fun)
{ }
template<typename SIG>
function<SIG>&
getFun ()
{
REQUIRE (INSTANCEOF (FunctionHolder<SIG>, &holder_));
return static_cast<FunctionHolder<SIG>&> (holder_).get();
}
bool
isValid() const
{
return holder_.isValid();
return get<function<SIG> >();
}
};

View file

@ -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 STO>
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 STO>
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 STO> class AccessPolicy = OpaqueHolder_useCommonBase
///< how to access the contents via a common interface?
>
class OpaqueHolder
: public BoolCheckable<OpaqueHolder<BA,siz> >
{
/** 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<Storage>
{
BA&
get() const
{
return *reinterpret_cast<BA*> (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());
}
};