comment:Yet Another Generalized Functors Implementation in C++

source : http://www.codeproject.com/KB/cpp/genfunctors.aspx

 

source code here:

http://www.google.cn/codesearch/p?hl=zh-CN#Sm49eXhuoDE/trunk/delta3d/inc/dtUtil/functor.h&q=struct%20FunImplBase&d=4

 

personal comment:

 

functor template class hold returnType , paramsListType, storedType param,

storedType could be initialized to store diff func pointer (nonconst/const /volotile func pointer or class member func pointer) when using diff functor consturct

cause we typedef diff pointer type as storedType within diff functor constructor

functor operator transmit the func call returnType and paramList to funcImp class's static member func of Call() ,

the funcImp is constructed and stored in Typeless.buffer[] which is encapsulated in storedType

like bridge pattern , using macro def of DoCall(params) to bridge multi overloaded functor::operator() to single vptr_->call_(*this, parms); 

why we instantiate template class funcImpl or MemberFuncImpl which inherit from template class FunStorageImpl cause we want to initialize FunImplBase::VTable in an uniform way,

if not then assign FunImplBase::VTable will consume effort of instantiate instace of corresponding template FunStorageImpl

 

class diagram

code snippet

 

template <class R, class TList, unsigned int size=4*sizeof(void*)>

class functor

{

    typedef R ReturnType;

    typedef TList TypeListType;

    typedef typename CallParams<TList>::ParamsListType ParamsListType;

    //default constructor, destructor, assignment

   Functor() : vptr_(0) {}
   ~Functor()
   {
      if (vptr_) vptr_->destroy_(*this);
   }
   Functor(Functor const& src)
   {
      vptr_ = src.vptr_ ? src.vptr_->clone_(src, *this) : NULL;
   }
   Functor& operator=(Functor const& src)
   {
      if (this != &src) {
         if (vptr_) vptr_->destroy_(*this);
         vptr_ = src.vptr_ ? src.vptr_->clone_(src, *this) : NULL;
      }
      return *this;
   }
   // is-empty selector
   bool operator!() const { return vptr_ == NULL; }

   bool valid() const { return vptr_ != NULL; }

   // ctor for static fns and arbitrary functors
   template <typename F> explicit Functor(F const& fun)
   {
      typedef FunctorImpl<F> StoredType;
      vptr_ = _init<StoredType>(fun); //assign vptr_ using
   }
   // ctor for member fns (note: raw ptrs and smart ptrs are equally welcome in pobj)
   template <class P, typename MF> explicit Functor(P const& pobj, MF memfun)
   {
      typedef MemberFnImpl<P, MF> StoredType;
      vptr_ = _init<StoredType>(std::pair<P, MF>(pobj, memfun));
   }

private:

    // initialization helper
   template <class T, class V>
   typename FunImplBase::VTable* _init(V const& v) //T stands for FunctorImpl or MemberFnImpl, V stands for these contrcutor's argument
   {
      // gcc obviously complained about the below code due to unused variables
      // so I'm removing it for now. As long as the unit tests pass, we should
      // be good. -osb
      //FunImplBase* pimpl = val_.template init<T>(v);
      //pimpl;
      val_.template init<T>(v);

     // store functorImpl or MemberFnImpl in Stored.Typeless.buffer[]  

     // MemberFnImpl  ctor :T stands for  MemberFnImpl<P, MF>    V stands for std::pair<P, MF>

     // FunctorImpl ctor: T stands for FunctorImpl<F> V stands for F

      // throw away pimpl, we don't need it in this implementation
      static typename FunImplBase::VTable vtbl =
      {
         &T::Destroy,
         &T::Clone,
         &T::Call,
      }; // diff T cause diff code instantiation for func _init , diff local static variable vtbl
      return &vtbl;
   }

   Stored val_;  //for holding funcImp class instance
   typename FunImplBase::VTable* vptr_; // act as the same func as virtual table ptr

public:
   // calls
   typedef typename dtUtil::TypeAtNonStrict<TList, 0, dtUtil::NullType>::Result  Parm1;
   typedef typename dtUtil::TypeAtNonStrict<TList, 1, dtUtil::NullType>::Result  Parm2;
   typedef typename dtUtil::TypeAtNonStrict<TList, 2, dtUtil::NullType>::Result  Parm3;
   typedef typename dtUtil::TypeAtNonStrict<TList, 3, dtUtil::NullType>::Result  Parm4;
   typedef typename dtUtil::TypeAtNonStrict<TList, 4, dtUtil::NullType>::Result  Parm5;
   typedef typename dtUtil::TypeAtNonStrict<TList, 5, dtUtil::NullType>::Result  Parm6;
   typedef typename dtUtil::TypeAtNonStrict<TList, 6, dtUtil::NullType>::Result  Parm7;
#define DoCall(parms) return vptr_->call_(*this, parms);
    inline R operator()(ParmsListType const& parms) const { DoCall(parms) }
    inline R operator()() const { DoCall(CallParms<TList>::Make()) }

    inline R operator()(Parm1 p1) const { DoCall(CallParms<TList>::Make(p1)) }
    inline R operator()(Parm1 p1, Parm2 p2) const { DoCall(CallParms<TList>::Make(p1, p2)) }
    inline R operator()(Parm1 p1, Parm2 p2, Parm3 p3) const { DoCall(CallParms<TList>::Make(p1, p2, p3)) }
    inline R operator()(Parm1 p1, Parm2 p2, Parm3 p3, Parm4 p4) const { DoCall(CallParms<TList>::Make(p1, p2, p3, p4)) }
    inline R operator()(Parm1 p1, Parm2 p2, Parm3 p3, Parm4 p4, Parm5 p5) const { DoCall(CallParms<TList>::Make(p1, p2, p3, p4, p5)) }
    inline R operator()(Parm1 p1, Parm2 p2, Parm3 p3, Parm4 p4, Parm5 p5, Parm6 p6) const { DoCall(CallParms<TList>::Make(p1, p2, p3, p4, p5, p6)) }
    inline R operator()(Parm1 p1, Parm2 p2, Parm3 p3, Parm4 p4, Parm5 p5, Parm6 p6, Parm7 p7) const { DoCall(CallParms<TList>::Make(p1, p2, p3, p4, p5, p6, p7)) }

/*CallParams using

//generic pattern

template <class TList, template <class, unsigned int > class Holder, unsigned int i=0> struct InstantiateH{};

//partial instantiation for param TList

template <class T, class U, template<class, unsigned int> class Holder, unsigned int i>

class InstantiateH <TypeList<T,U>, Holder, i>

:public Holder <typename TypeList<T,U>::Head, i>

,public InstantiateH<typename TypeList<T,U>::Tail, Holder, i+1>

{

    enum { ordern = i };

    typedef Holder <typename TypeList<T,U>::Head, i> LeftBase;

    typedef InstantiateH <typename TypeList<T,U>::Tail, Holder, i+1> RightBase;

    InstantiateH(typename TypeList<T,U>::Head h, RightBase const &t ):LeftBase(h),RightBase(t){}

    InstantiateH(typename Typelist<T,U>::Head h, NullType>:LeftBase(h){}

    InstantiateH(typename Typelist<T,U>::Head h>:LeftBase(h){}

    InstantiateH(){}

};

//inherited base class partial specializations for termination

template <class TList, template <class ,unsigned int >class Holder, unsigned int i>

class InstantiateH<NullType, Holder, i>

{

InstantiateH(){}

};

template <unsigned int j, typename InstH, unsigned int i = 0> struct InstantiateHAccessor;
template <typename T, typename U, template <class, unsigned int> class Holder, unsigned int i>
struct InstantiateHAccessor<0, InstantiateH<TypeList<T, U>, Holder, i>, i>
{
   typedef InstantiateH<TypeList<T, U>, Holder, i> Instance;
   typedef typename Instance::LeftBase TargetHolder;
   static inline TargetHolder& Get(Instance& h) { return static_cast<TargetHolder&>(h); }
   static inline TargetHolder const& Get(Instance const& h) { return static_cast<TargetHolder const&>(h); }
};
template <unsigned int j, typename T, typename U, template <class, unsigned int> class Holder, unsigned int i>
struct InstantiateHAccessor<j, InstantiateH<TypeList<T, U>, Holder, i>, i>
{
   typedef InstantiateH<TypeList<T, U>, Holder, i> Instance;
   typedef Holder<typename TypeAt<TypeList<T, U>, j>::Result, j+i> TargetHolder;
   typedef typename Instance::RightBase RightBase;
   static inline TargetHolder& Get(Instance& h) { return InstantiateHAccessor<j-1, RightBase, i+1>::Get(static_cast<RightBase&>(h)); }
   static inline TargetHolder const& Get(Instance const& h) { return InstantiateHAccessor<j-1, RightBase, i+1>::Get(static_cast<RightBase const&>(h)); }
};
template <unsigned int j, class Instantiated> inline
typename InstantiateHAccessor<j, Instantiated, Instantiated::ordern>::TargetHolder&
GetH(Instantiated& h)
{
   return InstantiateHAccessor<j, Instantiated, Instantiated::ordern>::Get(h);
}
template <unsigned int j, class Instantiated> inline
typename InstantiateHAccessor<j, Instantiated, Instantiated::ordern>::TargetHolder const&
GetH(Instantiated const& h)
{
   return InstantiateHAccessor<j, Instantiated, Instantiated::ordern>::Get(h);
}

//struct InstantiateHAccessor<j, InstantiateH<TypeList<T, U>, Holder, i>, i> for static func Get() to return holder

//holder storing the param value and param index of a param in paramList

template <class TList> struct CallParms;

 

 

template <>
struct CallParms<TYPELIST_0()>
{
   typedef dtUtil::InstantiateH<dtUtil::NullType, dtUtil::TupleHolder> ParmsListType;
   static inline ParmsListType Make() { return ParmsListType(); }
};


template <typename P1>
struct CallParms<TYPELIST_1(P1)>
{
   typedef dtUtil::InstantiateH<typename dtUtil::CreateTL<P1>::Type, dtUtil::TupleHolder> ParmsListType;
   static inline ParmsListType Make(P1 p1)
   {
      return ParmsListType(p1);
   }
};

 


template <typename P1, typename P2>
struct CallParms<TYPELIST_2(P1, P2)>
{
   typedef dtUtil::InstantiateH<typename dtUtil::CreateTL<P1, P2>::Type, dtUtil::TupleHolder> ParmsListType;
   static inline ParmsListType Make(P1 p1, P2 p2)
   {
      return ParmsListType(p1,
         typename dtUtil::TailAt<ParmsListType, 0>::Result(p2));
   }
};

//... until p7

 

//generic template

template <typename CallType, typename R, class TList> struct FunctorCall;

 

 

 //... partial specializations for different numbers
//    of arguments of the function types ...

template <typename CallType, typename R>
struct FunctorCall<CallType, R, TYPELIST_0()>
{
   typedef dtUtil::InstantiateH<dtUtil::NullType, dtUtil::TupleHolder> ParmsListType;
   template <class Fun> static inline R Call(Fun const& fun, ParmsListType& /*parms*/)
   {
      return fun();
   }
   template <class PObj> static inline R Call(PObj const& pobj, CallType memfun, ParmsListType& /*parms*/)
   {
      return ((*pobj).*memfun)();
   }
};

 

 

template <typename CallType, typename R, typename P1>
struct FunctorCall<CallType, R, TYPELIST_1(P1)>
{
   typedef dtUtil::InstantiateH<typename dtUtil::CreateTL<P1>::Type, dtUtil::TupleHolder> ParmsListType;
   template <class Fun> static inline R Call(Fun const& fun, ParmsListType& parms)
   {
      return fun(dtUtil::GetH<0>(parms).value);
   }
   template <class PObj> static inline R Call(PObj const& pobj, CallType memfun, ParmsListType& parms)
   {
      return ((*pobj).*memfun)(dtUtil::GetH<0>(parms).value);
   }

 

template <typename CallType, typename R, typename P1, typename P2>
struct FunctorCall<CallType, R, TYPELIST_2(P1, P2)>
{
   typedef dtUtil::InstantiateH<typename dtUtil::CreateTL<P1, P2>::Type, dtUtil::TupleHolder> ParmsListType;
   template <class Fun> static inline R Call(Fun const& fun, ParmsListType& parms)
   {
      return fun(
         dtUtil::GetH<0>(parms).value,
         dtUtil::GetH<1>(parms).value);
   }
   template <class PObj> static inline R Call(PObj const& pobj, CallType memfun, ParmsListType& parms)
   {
      return ((*pobj).*memfun)(
         dtUtil::GetH<0>(parms).value,   //get holder.value for p1
         dtUtil::GetH<1>(parms).value); //get holder.value for p2
   }
};

//...until p7
};

*/
private:

    //copying/destruction and calls implementation

    struct FunImpBase //hold three member variable of func pointer , design these to substitute vptr for virtual member func call

    {

      struct VTable;
      struct VTable
      {
         void (*destroy_)(Functor const&);
         VTable* (*clone_)(Functor const&, Functor&);
         R (*call_)(Functor const&, ParmsListType);
      };
      // VTable vtbl_;   // not needed here and actually wastes space!

    } 

   template <typename V, class Derived>

 // as FunctorImpl base class:     V stands for functor,             Derived stands for FunctorImpl<functor>

 // as MemberFnImpl base class: V stands for std::pair<P,T>,  Derived stands for MemberFnImpl<P,T>

   struct FunStorageImpl : public FunImplBase //implement Destory, Clone two func 
   {
      V val_;
      FunStorageImpl(V const& val) : val_(val) {}
      static void Destroy(Functor const& src) { src.val_.template destroy<Derived>(); }
      static typename FunImplBase::VTable* Clone(Functor const& src, Functor& dest)
      {
         Derived const& this_ = src.val_.template get<Derived const>();
         return dest._init<Derived>(this_.val_);
      }
   };

   template <typename T>
   struct FunctorImpl : public FunStorageImpl<T, FunctorImpl<T> > //implement Call func
   {
      FunctorImpl(T const& val) : FunStorageImpl<T, FunctorImpl>(val) {}
      static R Call(Functor const& src, ParmsListType parms)
      {
         FunctorImpl const& this_ = src.val_.template get<FunctorImpl const>();
         return FunctorCall<T, R, TList>::Call(this_.val_, parms); 

         //route call to template <class Fun> FunctorCall<T,R,TList>::Call(const Fun&, ParmsListType& params)
      }
   };
   template <class P, typename T>
   struct MemberFnImpl : public FunStorageImpl<std::pair<P, T>, MemberFnImpl<P, T> > //implement Call func
   {
      MemberFnImpl(std::pair<P, T> const& val) : FunStorageImpl<std::pair<P, T>, MemberFnImpl>(val) {}
      static R Call(Functor const& src, ParmsListType parms)
      {
         MemberFnImpl const& this_ = src.val_.template get<MemberFnImpl const>();
         return FunctorCall<T, R, TList>::Call(this_.val_.first, this_.val_.second, parms);

         //route call to template <class PObj> FunctorCall<T,R,TList>::Call(PObj const& pobj, T memfun, ParmsListType& parms)
      }
   };
 
   // typeless storage support
   struct Typeless //functional class
   {
      template <typename T> inline T* init1(T* v) { return new(getbuf()) T(v); }
      template <typename T, typename V> inline T* init(V const& v) { return new(getbuf()) T(v); }
       template <typename T> inline void destroy() const { (*reinterpret_cast<T const*>(getbuf())).~T(); }
      template <typename T> inline T const& get() const { return *reinterpret_cast<T const*>(getbuf()); }
      template <typename T> inline T& get() { return *reinterpret_cast<T*>(getbuf()); }
      void* getbuf() { return &buffer_[0]; }
      void const* getbuf() const { return &buffer_[0]; }
      unsigned char buffer_[size];
   };
   template <typename T>
   struct ByValue  //behaviour class
   {
      template <typename V> inline static T* init(Typeless& val, V const& v) { return val.template init<T>(v); } // construct T instance from address buffer[0]
      inline static void destroy(Typeless const& val) { val.template destroy<T>(); }
      inline static T const& get(Typeless const& val) { return val.template get<T>(); }
      inline static T& get(Typeless& val) { return val.template get<T>(); }
   };
   template <typename T>
   struct NewAlloc //behaviour class
   {
      template <typename V> inline static T* init(Typeless& val, V const& v) { return *val.template init<T*>(new T(v)); }

       //new T(v) in heap and construct T* from address buffer[0]
      inline static void destroy(Typeless const& val) { delete val.template get<T*>(); }
      inline static T const& get(Typeless const& val) { return *val.template get<T const*>(); }
      inline static T& get(Typeless& val) { return *val.template get<T*>(); }
   };
   template <typename T>
   struct SelectStored  //behaviour class
   {
      // TODO: it seems this is a good place to add alignment calculations
      typedef typename dtUtil::Select<
         sizeof(T)<=sizeof(Typeless),
         ByValue<T>,
         NewAlloc<T>
      >::Result Type;
   };
   struct Stored //behaviour class to delegate template func call to template param T class
   {
      template <typename T, typename V> inline T* init(V const& v) { return SelectStored<T>::Type::init(val_, v); }
      template <typename T> inline void destroy() const { SelectStored<T>::Type::destroy(val_); }
      template <typename T> inline T const& get() const { return SelectStored<T>::Type::get(val_); }
      template <typename T> inline T& get() { return SelectStored<T>::Type::get(val_); }
      Typeless val_;
   };
};

 

 

 

發表評論
所有評論
還沒有人評論,想成為第一個評論的人麼? 請在上方評論欄輸入並且點擊發布.
相關文章