Raw File
objfunctor.h
// -*- C++ -*-
// $Id: objfunctor.h,v 2.0 2005-09-25 21:04:25 edwards Exp $
/*! @file
 * @brief Generic functor class
 */

#ifndef __objfunctor_h__
#define __objfunctor_h__

#include "typelist.h"
#include "typetraits.h"
#include <typeinfo>
#include <memory>

namespace Chroma
{
////////////////////////////////////////////////////////////////////////////////
// class template FunctorImpl (internal)
////////////////////////////////////////////////////////////////////////////////

  namespace Private
  {
    template <typename R>
    struct FunctorImplBase 
    {
      typedef R ResultType;
            
      typedef EmptyType Parm1;
      typedef EmptyType Parm2;
      typedef EmptyType Parm3;
      typedef EmptyType Parm4;
      typedef EmptyType Parm5;

      virtual FunctorImplBase* DoClone() const = 0;
      template <class U>
      static U* Clone(U* pObj)
	{
	  if (!pObj) return 0;
	  U* pClone = static_cast<U*>(pObj->DoClone());
	  assert(typeid(*pClone) == typeid(*pObj));
	  return pClone;
	}
    };
  }
    
////////////////////////////////////////////////////////////////////////////////
// macro DEFINE_CLONE_FUNCTORIMPL
// Implements the DoClone function for a functor implementation
////////////////////////////////////////////////////////////////////////////////

#define DEFINE_CLONE_FUNCTORIMPL(Cls) \
    virtual Cls* DoClone() const { return new Cls(*this); }

////////////////////////////////////////////////////////////////////////////////
// class template FunctorImpl
// The base class for a hierarchy of functors. The FunctorImpl class is not used
//     directly; rather, the Functor class manages and forwards to a pointer to
//     FunctorImpl
// You may want to derive your own functors from FunctorImpl.
// Specializations of FunctorImpl for up to 5 parameters follow
////////////////////////////////////////////////////////////////////////////////

  template <typename R, class TList>
  class FunctorImpl;

////////////////////////////////////////////////////////////////////////////////
// class template FunctorImpl
// Specialization for 0 (zero) parameters
////////////////////////////////////////////////////////////////////////////////

  template <typename R>
  class FunctorImpl<R, NullType>
    : public Private::FunctorImplBase<R>
  {
  public:
    typedef R ResultType;
    virtual R operator()() = 0;
  };

////////////////////////////////////////////////////////////////////////////////
// class template FunctorImpl
// Specialization for 1 parameter
////////////////////////////////////////////////////////////////////////////////

  template <typename R, typename P1>
  class FunctorImpl<R, TYPELIST_1(P1)>
    : public Private::FunctorImplBase<R>
  {
  public:
    typedef R ResultType;
    typedef typename TypeTraits<P1>::ParameterType Parm1;
    virtual R operator()(Parm1) = 0;
  };

////////////////////////////////////////////////////////////////////////////////
// class template FunctorImpl
// Specialization for 2 parameters
////////////////////////////////////////////////////////////////////////////////

  template <typename R, typename P1, typename P2>
  class FunctorImpl<R, TYPELIST_2(P1, P2)>
    : public Private::FunctorImplBase<R>
  {
  public:
    typedef R ResultType;
    typedef typename TypeTraits<P1>::ParameterType Parm1;
    typedef typename TypeTraits<P2>::ParameterType Parm2;
    virtual R operator()(Parm1, Parm2) = 0;
  };

////////////////////////////////////////////////////////////////////////////////
// class template FunctorImpl
// Specialization for 3 parameters
////////////////////////////////////////////////////////////////////////////////

  template <typename R, typename P1, typename P2, typename P3>
  class FunctorImpl<R, TYPELIST_3(P1, P2, P3)>
    : public Private::FunctorImplBase<R>
  {
  public:
    typedef R ResultType;
    typedef typename TypeTraits<P1>::ParameterType Parm1;
    typedef typename TypeTraits<P2>::ParameterType Parm2;
    typedef typename TypeTraits<P3>::ParameterType Parm3;
    virtual R operator()(Parm1, Parm2, Parm3) = 0;
  };

////////////////////////////////////////////////////////////////////////////////
// class template FunctorImpl
// Specialization for 4 parameters
////////////////////////////////////////////////////////////////////////////////

  template <typename R, typename P1, typename P2, typename P3, typename P4>
  class FunctorImpl<R, TYPELIST_4(P1, P2, P3, P4)>
    : public Private::FunctorImplBase<R>
  {
  public:
    typedef R ResultType;
    typedef typename TypeTraits<P1>::ParameterType Parm1;
    typedef typename TypeTraits<P2>::ParameterType Parm2;
    typedef typename TypeTraits<P3>::ParameterType Parm3;
    typedef typename TypeTraits<P4>::ParameterType Parm4;
    virtual R operator()(Parm1, Parm2, Parm3, Parm4) = 0;
  };

////////////////////////////////////////////////////////////////////////////////
// class template FunctorImpl
// Specialization for 5 parameters
////////////////////////////////////////////////////////////////////////////////

  template <typename R, typename P1, typename P2, typename P3, typename P4,
    typename P5>
  class FunctorImpl<R, TYPELIST_5(P1, P2, P3, P4, P5)>
    : public Private::FunctorImplBase<R>
  {
  public:
    typedef R ResultType;
    typedef typename TypeTraits<P1>::ParameterType Parm1;
    typedef typename TypeTraits<P2>::ParameterType Parm2;
    typedef typename TypeTraits<P3>::ParameterType Parm3;
    typedef typename TypeTraits<P4>::ParameterType Parm4;
    typedef typename TypeTraits<P5>::ParameterType Parm5;
    virtual R operator()(Parm1, Parm2, Parm3, Parm4, Parm5) = 0;
  };


////////////////////////////////////////////////////////////////////////////////
// class template FunctorHandler
// Wraps functors and pointers to functions
////////////////////////////////////////////////////////////////////////////////

  template <class ParentFunctor, typename Fun>
  class FunctorHandler
    : public ParentFunctor::Impl
  {
    typedef typename ParentFunctor::Impl Base;

  public:
    typedef typename Base::ResultType ResultType;
    typedef typename Base::Parm1 Parm1;
    typedef typename Base::Parm2 Parm2;
    typedef typename Base::Parm3 Parm3;
    typedef typename Base::Parm4 Parm4;
    typedef typename Base::Parm5 Parm5;
        
    FunctorHandler(const Fun& fun) : f_(fun) {}
        
    DEFINE_CLONE_FUNCTORIMPL(FunctorHandler)

      // operator() implementations for up to 5 arguments
                
      ResultType operator()()
      { return f_(); }

    ResultType operator()(Parm1 p1)
      { return f_(p1); }
        
    ResultType operator()(Parm1 p1, Parm2 p2)
      { return f_(p1, p2); }
        
    ResultType operator()(Parm1 p1, Parm2 p2, Parm3 p3)
      { return f_(p1, p2, p3); }
        
    ResultType operator()(Parm1 p1, Parm2 p2, Parm3 p3, Parm4 p4)
      { return f_(p1, p2, p3, p4); }
        
    ResultType operator()(Parm1 p1, Parm2 p2, Parm3 p3, Parm4 p4, Parm5 p5)
      { return f_(p1, p2, p3, p4, p5); }
        
  private:
    Fun f_;
  };
        
////////////////////////////////////////////////////////////////////////////////
// class template FunctorHandler
// Wraps pointers to member functions
////////////////////////////////////////////////////////////////////////////////

  template <class ParentFunctor, typename PointerToObj,
    typename PointerToMemFn>
  class MemFunHandler : public ParentFunctor::Impl
  {
    typedef typename ParentFunctor::Impl Base;

  public:
    typedef typename Base::ResultType ResultType;
    typedef typename Base::Parm1 Parm1;
    typedef typename Base::Parm2 Parm2;
    typedef typename Base::Parm3 Parm3;
    typedef typename Base::Parm4 Parm4;
    typedef typename Base::Parm5 Parm5;

    MemFunHandler(const PointerToObj& pObj, PointerToMemFn pMemFn) 
      : pObj_(pObj), pMemFn_(pMemFn)
      {}
        
    DEFINE_CLONE_FUNCTORIMPL(MemFunHandler)
        
      ResultType operator()()
      { return ((*pObj_).*pMemFn_)(); }

    ResultType operator()(Parm1 p1)
      { return ((*pObj_).*pMemFn_)(p1); }
        
    ResultType operator()(Parm1 p1, Parm2 p2)
      { return ((*pObj_).*pMemFn_)(p1, p2); }
        
    ResultType operator()(Parm1 p1, Parm2 p2, Parm3 p3)
      { return ((*pObj_).*pMemFn_)(p1, p2, p3); }
        
    ResultType operator()(Parm1 p1, Parm2 p2, Parm3 p3, Parm4 p4)
      { return ((*pObj_).*pMemFn_)(p1, p2, p3, p4); }
        
    ResultType operator()(Parm1 p1, Parm2 p2, Parm3 p3, Parm4 p4, Parm5 p5)
      { return ((*pObj_).*pMemFn_)(p1, p2, p3, p4, p5); }
        
  private:
    PointerToObj pObj_;
    PointerToMemFn pMemFn_;
  };
        
////////////////////////////////////////////////////////////////////////////////
// class template Functor
// A generalized functor implementation with value semantics
////////////////////////////////////////////////////////////////////////////////
       
  template <typename R, class TList = NullType>
  class ObjectFunctor
  {
  public:
    // Handy type definitions for the body type
    typedef FunctorImpl<R, TList> Impl;
    typedef R ResultType;
    typedef TList ParmList;
    typedef typename Impl::Parm1 Parm1;
    typedef typename Impl::Parm2 Parm2;
    typedef typename Impl::Parm3 Parm3;
    typedef typename Impl::Parm4 Parm4;
    typedef typename Impl::Parm5 Parm5;

    // Member functions

    ObjectFunctor() : spImpl_(0)
      {}
        
    ObjectFunctor(const ObjectFunctor& rhs) : spImpl_(Impl::Clone(rhs.spImpl_.get()))
      {}
        
    ObjectFunctor(std::auto_ptr<Impl> spImpl) : spImpl_(spImpl)
      {}
        
    template <typename Fun>
    ObjectFunctor(Fun fun)
      : spImpl_(new FunctorHandler<ObjectFunctor, Fun>(fun))
      {}

    template <class PtrObj, typename MemFn>
    ObjectFunctor(const PtrObj& p, MemFn memFn)
      : spImpl_(new MemFunHandler<ObjectFunctor, PtrObj, MemFn>(p, memFn))
      {}

    ObjectFunctor& operator=(const ObjectFunctor& rhs)
      {
	ObjectFunctor copy(rhs);
	// swap auto_ptrs by hand
	Impl* p = spImpl_.release();
	spImpl_.reset(copy.spImpl_.release());
	copy.spImpl_.reset(p);
	return *this;
      }
        
    ResultType operator()()
      { return (*spImpl_)(); }

    ResultType operator()(Parm1 p1)
      { return (*spImpl_)(p1); }
        
    ResultType operator()(Parm1 p1, Parm2 p2)
      { return (*spImpl_)(p1, p2); }
        
    ResultType operator()(Parm1 p1, Parm2 p2, Parm3 p3)
      { return (*spImpl_)(p1, p2, p3); }
        
    ResultType operator()(Parm1 p1, Parm2 p2, Parm3 p3, Parm4 p4)
      { return (*spImpl_)(p1, p2, p3, p4); }
        
    ResultType operator()(Parm1 p1, Parm2 p2, Parm3 p3, Parm4 p4, Parm5 p5)
      { return (*spImpl_)(p1, p2, p3, p4, p5); }

  private:
    std::auto_ptr<Impl> spImpl_;
  };
    
  namespace Private
  {
    template <class Fctor> struct BinderFirstTraits;

    template <typename R, class TList>
    struct BinderFirstTraits< ObjectFunctor<R, TList> >
    {
      typedef typename TL::Erase<TList, 
	typename TL::TypeAt<TList, 0>::Result>::Result
      ParmList;
      typedef ObjectFunctor<R, ParmList> BoundFunctorType;
      typedef typename BoundFunctorType::Impl Impl;
    };        
  }

////////////////////////////////////////////////////////////////////////////////
// class template BinderFirst
// Binds the first parameter of a ObjectFunctor object to a specific value
////////////////////////////////////////////////////////////////////////////////

  template <class OriginalFunctor>
  class BinderFirst 
    : public Private::BinderFirstTraits<OriginalFunctor>::Impl
  {
    typedef typename Private::BinderFirstTraits<OriginalFunctor>::Impl Base;
    typedef typename OriginalFunctor::ResultType ResultType;

    typedef typename OriginalFunctor::Parm1 BoundType;

    typedef typename OriginalFunctor::Parm2 Parm1;
    typedef typename OriginalFunctor::Parm3 Parm2;
    typedef typename OriginalFunctor::Parm4 Parm3;
    typedef typename OriginalFunctor::Parm5 Parm4;
    typedef EmptyType Parm5;

  public:
    BinderFirst(const OriginalFunctor& fun, BoundType bound)
      : f_(fun), b_(bound)
      {}
        
    DEFINE_CLONE_FUNCTORIMPL(BinderFirst)
        
      // operator() implementations for up to 5 arguments
                
      ResultType operator()()
      { return f_(b_); }

    ResultType operator()(Parm1 p1)
      { return f_(b_, p1); }
        
    ResultType operator()(Parm1 p1, Parm2 p2)
      { return f_(b_, p1, p2); }
        
    ResultType operator()(Parm1 p1, Parm2 p2, Parm3 p3)
      { return f_(b_, p1, p2, p3); }
        
    ResultType operator()(Parm1 p1, Parm2 p2, Parm3 p3, Parm4 p4)
      { return f_(b_, p1, p2, p3, p4); }
       
  private:
    OriginalFunctor f_;
    BoundType b_;
  };
    
////////////////////////////////////////////////////////////////////////////////
// function template BindFirst
// Binds the first parameter of a Functor object to a specific value
////////////////////////////////////////////////////////////////////////////////

  template <class Fctor>
  typename Private::BinderFirstTraits<Fctor>::BoundFunctorType
  BindFirst(
    const Fctor& fun,
    typename Fctor::Parm1 bound)
  {
    typedef typename Private::BinderFirstTraits<Fctor>::BoundFunctorType
      Outgoing;
        
    return Outgoing(std::auto_ptr<typename Outgoing::Impl>(
      new BinderFirst<Fctor>(fun, bound)));
  }

////////////////////////////////////////////////////////////////////////////////
// class template Chainer
// Chains two functor calls one after another
////////////////////////////////////////////////////////////////////////////////

  template <typename Fun1, typename Fun2>
  class Chainer : public Fun2::Impl
  {
    typedef Fun2 Base;

  public:
    typedef typename Base::ResultType ResultType;
    typedef typename Base::Parm1 Parm1;
    typedef typename Base::Parm2 Parm2;
    typedef typename Base::Parm3 Parm3;
    typedef typename Base::Parm4 Parm4;
    typedef typename Base::Parm5 Parm5;
        
    Chainer(const Fun1& fun1, const Fun2& fun2) : f1_(fun1), f2_(fun2) {}

    DEFINE_CLONE_FUNCTORIMPL(Chainer)

      // operator() implementations for up to 5 arguments

      ResultType operator()()
      { return f1_(), f2_(); }

    ResultType operator()(Parm1 p1)
      { return f1_(p1), f2_(p1); }
        
    ResultType operator()(Parm1 p1, Parm2 p2)
      { return f1_(p1, p2), f2_(p1, p2); }
        
    ResultType operator()(Parm1 p1, Parm2 p2, Parm3 p3)
      { return f1_(p1, p2, p3), f2_(p1, p2, p3); }
        
    ResultType operator()(Parm1 p1, Parm2 p2, Parm3 p3, Parm4 p4)
      { return f1_(p1, p2, p3, p4), f2_(p1, p2, p3, p4); }
        
    ResultType operator()(Parm1 p1, Parm2 p2, Parm3 p3, Parm4 p4, Parm5 p5)
      { return f1_(p1, p2, p3, p4, p5), f2_(p1, p2, p3, p4, p5); }
        
  private:
    Fun1 f1_;
    Fun2 f2_;
  };
    
////////////////////////////////////////////////////////////////////////////////
// function template Chain
// Chains two functor calls one after another
////////////////////////////////////////////////////////////////////////////////


  template <class Fun1, class Fun2>
  Fun2 Chain(
    const Fun1& fun1,
    const Fun2& fun2)
  {
    return Fun2(std::auto_ptr<typename Fun2::Impl>(
      new Chainer<Fun1, Fun2>(fun1, fun2)));
  }

}  // namespace Chroma

#endif
back to top