// Modifications copyright Amazon.com, Inc. or its affiliates. // Original file Copyright Crytek GMBH or its affiliates, used under license. // Callbacks based on CALLBACKS IN C++ USING TEMPLATE FUNCTORS Copyright 1994 Rich Hickey http://www.tutok.sk/fastgl/callback.html //**************** callback.hpp ********************** // Copyright 1994 Rich Hickey /* Permission to use, copy, modify, distribute and sell this software * for any purpose is hereby granted without fee, * provided that the above copyright notice appear in all copies and * that both that copyright notice and this permission notice appear * in supporting documentation. Rich Hickey makes no * representations about the suitability of this software for any * purpose. It is provided "as is" without express or implied warranty. */ #ifndef CRYINCLUDE_functor_H #define CRYINCLUDE_functor_H #include /* To use: If you wish to build a component that provides/needs a callback, simply specify and hold a Functor of the type corresponding to the args you wish to pass and the return value you need. There are 10 Functors from which to choose: Functor0 Functor1 Functor2 Functor3 Functor4 Functor5 Functor0wRet Functor1wRet Functor2wRet Functor3wRet Functor4wRet These are parameterized by their args and return value if any. Each has a default ctor and an operator() with the corresponding signature. They can be treated and used just like ptr-to-functions. If you want to be a client of a component that uses callbacks, you create a Functor by calling functor(). There are three flavors of functor - you can create a functor from: a ptr-to-stand-alone function an object and a pointer-to-member function. a pointer-to-member function (which will be called on first arg of functor) Note: this last was not covered in the article - see CBEXAM3.CPP functor( ptr-to-function) functor( reference-to-object,ptr-to-member-function) functor( ptr-to-member-function) The functor system is 100% type safe. It is also type flexible. You can build a functor out of a function that is 'type compatible' with the target functor - it need not have an exactly matching signature. By type compatible I mean a function with the same number of arguments, of types reachable from the functor's argument types by implicit conversion. The return type of the function must be implicitly convertible to the return type of the functor. A functor with no return can be built from a function with a return - the return value is simply ignored. (See ethel example below) All the correct virtual function behavior is preserved. (see ricky example below). If you somehow try to create something in violation of the type system you will get a compile-time or template-instantiation- time error. The Functor base class and translator classes are artifacts of this implementation. You should not write code that relies upon their existence. Nor should you rely on the return value of functor being anything in particular. All that is guaranteed is that the Functor classes have a default ctor, a ctor that can accept 0 as an initializer, an operator() with the requested argument types and return type, an operator that will allow it to be evaluated in a conditional (with 'true' meaning the functor is set, 'false' meaning it is not), and that Functors can be constructed from the result of functor(), given you've passed something compatible to functor(). In addition you can compare 2 functors with ==, !=, and <. 2 functors with the same 'callee' (function, object and/or ptr-to-mem-func) shall compare equal. op < forms an ordering relation across all callee types -> the actual order is not meaningful or to be depended upon. /////////////////////// BEGIN Example 1 ////////////////////////// #include #include "callback.hpp" //do5Times() is a function that takes a functor and invokes it 5 times void do5Times(const Functor1 &doIt) { for(int i=0;i<5;i++) doIt(i); } //Here are some standalone functions void fred(int i){cout << "fred: " << i< *FtorType; Functor1 ftor; //a functor variable //make a functor from ptr-to-function ftor = functor( fred ); do5Times(ftor); //note ethel is not an exact match - ok, is compatible ftor = functor( ethel ); do5Times(ftor); //create a D object to be a callback target D myD; //make functor from object and ptr-to-member-func ftor = functor( myD,&B::ricky ); do5Times(ftor); } /////////////////////// END of example 1 ////////////////////////// /////////////////////// BEGIN Example 2 ////////////////////////// #include #include "callback.hpp" //Button is a component that provides a functor-based //callback mechanism, so you can wire it up to whatever you wish class Button{ public: //ctor takes a functor and stores it away in a member Button(const Functor0 &uponClickDoThis):notify(uponClickDoThis) {} void click() { //invoke the functor, thus calling back client notify(); } private: //note this is a data member with a verb for a name - matches its //function-like usage Functor0 notify; }; class CDPlayer{ public: void play() {cout << "Playing"< class Functor{ public: void operator()(T t)const{}; }; void foo(const Functor &f) { f(1); //error C2064: term does not evaluate to a function //works when f is passed by value } */ // Note: if you are porting to another compiler that is having trouble you // can try defining some of these flags as well: #if defined(_MSC_VER) #define RHCB_CANT_PASS_MEMFUNC_BY_REFERENCE //like it says //#define RHCB_CANT_OVERLOAD_ON_CONSTNESS //of mem funcs #define RHCB_CANT_INIT_REFERENCE_CTOR_STYLE //int i;int &ir(i); //MS falls down //#define RHCB_WONT_PERFORM_PTR_CONVERSION //of 0 to ptr-to-any-type #endif // Don't touch this stuff #if defined(RHCB_CANT_PASS_MEMFUNC_BY_REFERENCE) #define RHCB_CONST_REF #else #define RHCB_CONST_REF const & #endif #if defined(RHCB_CANT_INIT_REFERENCE_CTOR_STYLE) #define RHCB_CTOR_STYLE_INIT = #else #define RHCB_CTOR_STYLE_INIT #endif #if defined(RHCB_WONT_PERFORM_PTR_CONVERSION) #define RHCB_DUMMY_INIT int #else #define RHCB_DUMMY_INIT DummyInit * #endif ////////////////////////////// THE CODE ////////////////////////// //change these when your compiler gets bool typedef bool RHCB_BOOL; //#include //for memstuff //#include //for size_t //typeless representation of a function and optional object typedef void (*PtrToFunc)(); class FunctorBase { public: //Note: ctors are protected //for evaluation in conditionals - can the functor be called? operator RHCB_BOOL()const{return callee||func;} //Now you can put them in containers _and_ remove them! //Source for these 3 is in callback.cpp friend bool operator==(const FunctorBase &lhs,const FunctorBase &rhs); friend bool operator!=(const FunctorBase &lhs,const FunctorBase &rhs); friend bool operator<(const FunctorBase &lhs,const FunctorBase &rhs); //The rest below for implementation use only ! class DummyInit{ }; typedef void (FunctorBase::*PMemFunc)(); enum {MEM_FUNC_SIZE = sizeof(PMemFunc)}; PtrToFunc getFunc() const {return func;} void *getCallee() const {return callee;} const char *getMemFunc() const {return memFunc;} protected: //////////////////////////////////////////////////////////////// // Note: this code depends on all ptr-to-mem-funcs being same size // If that is not the case then make memFunc as large as largest //////////////////////////////////////////////////////////////// union{ PtrToFunc func; char memFunc[MEM_FUNC_SIZE*2]; // Make sure we support multiple inheritance. }; void *callee; FunctorBase() : callee(0),func(0) {} FunctorBase(const void *c,PtrToFunc f, const void *mf,size_t sz) : callee((void *)c) { if (c) //must be callee/memfunc { assert(sz <= MEM_FUNC_SIZE * 2); memcpy(memFunc,mf,sz); if(sz class CBMemberTranslator0:public Functor0{ public: CBMemberTranslator0(Callee &c,const MemFunc &m): Functor0(thunk,&c,0,&m,sizeof(MemFunc)){} static void thunk(const FunctorBase &ftor) { Callee *callee = (Callee *)ftor.getCallee(); MemFunc &memFunc RHCB_CTOR_STYLE_INIT (*(MemFunc*)(void *)(ftor.getMemFunc())); (callee->*memFunc)(); } }; template class CBFunctionTranslator0:public Functor0{ public: CBFunctionTranslator0(Func f):Functor0(thunk,0,(PtrToFunc)f,0,0){} static void thunk(const FunctorBase &ftor) { (Func(ftor.getFunc()))(); } }; #if !defined(RHCB_CANT_OVERLOAD_ON_CONSTNESS) template inline CBMemberTranslator0 functor( Callee &c,void (CallType::* RHCB_CONST_REF f)()) { typedef void (CallType::*MemFunc)(); return CBMemberTranslator0(c,f); } #endif template inline CBMemberTranslator0 functor(const Callee &c,void (CallType::* RHCB_CONST_REF f)()const) { typedef void (CallType::*MemFunc)()const; return CBMemberTranslator0(c,f); } inline CBFunctionTranslator0 functor(void (*f)()) { return CBFunctionTranslator0(f); } /************************* no arg - with return *******************/ template class Functor0wRet:public FunctorBase{ public: Functor0wRet(RHCB_DUMMY_INIT = 0){} RT operator()()const { return RHCB_BC4_RET_BUG(thunk(*this)); } protected: typedef RT (*Thunk)(const FunctorBase &); Functor0wRet(Thunk t,const void *c,PtrToFunc f,const void *mf,size_t sz): FunctorBase(c,f,mf,sz),thunk(t){} private: Thunk thunk; }; template class CBMemberTranslator0wRet:public Functor0wRet{ public: CBMemberTranslator0wRet(Callee &c,const MemFunc &m): Functor0wRet(thunk,&c,0,&m,sizeof(MemFunc)){} static RT thunk(const FunctorBase &ftor) { Callee *callee = (Callee *)ftor.getCallee(); MemFunc &memFunc RHCB_CTOR_STYLE_INIT (*(MemFunc*)(void *)(ftor.getMemFunc())); return RHCB_BC4_RET_BUG((callee->*memFunc)()); } }; template class CBFunctionTranslator0wRet:public Functor0wRet{ public: CBFunctionTranslator0wRet(Func f):Functor0wRet(thunk,0,(PtrToFunc)f,0,0){} static RT thunk(const FunctorBase &ftor) { return (Func(ftor.getFunc()))(); } }; #if !defined(RHCB_CANT_OVERLOAD_ON_CONSTNESS) template inline CBMemberTranslator0wRet functor( Callee &c,RT (CallType::* RHCB_CONST_REF f)()) { typedef RT (CallType::*MemFunc)(); return CBMemberTranslator0wRet(c,f); } #endif template inline CBMemberTranslator0wRet functor( const Callee &c,RT (CallType::* RHCB_CONST_REF f)()const) { typedef RT (CallType::*MemFunc)()const; return CBMemberTranslator0wRet(c,f); } template inline CBFunctionTranslator0wRet functor( RT (*f)() ) { return CBFunctionTranslator0wRet(f); } /************************* one arg - no return *******************/ template class Functor1:public FunctorBase { public: Functor1(RHCB_DUMMY_INIT = 0){} void operator()(P1 p1)const { thunk(*this,p1); } //for STL typedef P1 argument_type; typedef void result_type; protected: typedef void (*Thunk)(const FunctorBase &,P1); Functor1(Thunk t,const void *c,PtrToFunc f,const void *mf,size_t sz): FunctorBase(c,f,mf,sz),thunk(t){} private: Thunk thunk; }; template class CBMemberTranslator1:public Functor1{ public: CBMemberTranslator1(Callee &c,const MemFunc &m): Functor1(thunk,&c,0,&m,sizeof(MemFunc)){} static void thunk(const FunctorBase &ftor,P1 p1) { Callee *callee = (Callee *)ftor.getCallee(); MemFunc &memFunc RHCB_CTOR_STYLE_INIT (*(MemFunc*)(void *)(ftor.getMemFunc())); (callee->*memFunc)(p1); } }; template class CBFunctionTranslator1:public Functor1{ public: CBFunctionTranslator1(Func f):Functor1(thunk,0,(PtrToFunc)f,0,0){} static void thunk(const FunctorBase &ftor,P1 p1) { (Func(ftor.getFunc()))(p1); } }; #if !defined(RHCB_CANT_OVERLOAD_ON_CONSTNESS) template inline CBMemberTranslator1 functor(Callee &c,void (CallType::* RHCB_CONST_REF f)(P1)) { typedef void (CallType::*MemFunc)(P1); return CBMemberTranslator1(c,f); } #endif template inline CBMemberTranslator1 functor(const Callee &c,void (CallType::* RHCB_CONST_REF f)(P1)const) { typedef void (CallType::*MemFunc)(P1)const; return CBMemberTranslator1(c,f); } template inline CBFunctionTranslator1 functor( void (*f)(P1) ) { return CBFunctionTranslator1(f); } template class CBMemberOf1stArgTranslator1:public Functor1{ public: CBMemberOf1stArgTranslator1(const MemFunc &m): Functor1(thunk,(void *)1,0,&m,sizeof(MemFunc)){} static void thunk(const FunctorBase &ftor,P1 p1) { MemFunc &memFunc RHCB_CTOR_STYLE_INIT (*(MemFunc*)(void *)(ftor.getMemFunc())); (p1.*memFunc)(); } }; #if !defined(RHCB_CANT_OVERLOAD_ON_CONSTNESS) template inline CBMemberOf1stArgTranslator1 functor( void (CallType::* RHCB_CONST_REF f)()) { typedef void (CallType::*MemFunc)(); return CBMemberOf1stArgTranslator1(f); } #endif template inline CBMemberOf1stArgTranslator1 functor( void (CallType::* RHCB_CONST_REF f)()const) { typedef void (CallType::*MemFunc)()const; return CBMemberOf1stArgTranslator1(f); } /************************* one arg - with return *******************/ template class Functor1wRet:public FunctorBase{ public: Functor1wRet(RHCB_DUMMY_INIT = 0){} RT operator()(P1 p1)const { return RHCB_BC4_RET_BUG(thunk(*this,p1)); } //for STL typedef P1 argument_type; typedef RT result_type; protected: typedef RT (*Thunk)(const FunctorBase &,P1); Functor1wRet(Thunk t,const void *c,PtrToFunc f,const void *mf,size_t sz): FunctorBase(c,f,mf,sz),thunk(t){} private: Thunk thunk; }; template class CBMemberTranslator1wRet:public Functor1wRet{ public: CBMemberTranslator1wRet(Callee &c,const MemFunc &m): Functor1wRet(thunk,&c,0,&m,sizeof(MemFunc)){} static RT thunk(const FunctorBase &ftor,P1 p1) { Callee *callee = (Callee *)ftor.getCallee(); MemFunc &memFunc RHCB_CTOR_STYLE_INIT (*(MemFunc*)(void *)(ftor.getMemFunc())); return RHCB_BC4_RET_BUG((callee->*memFunc)(p1)); } }; template class CBFunctionTranslator1wRet:public Functor1wRet{ public: CBFunctionTranslator1wRet(Func f): Functor1wRet(thunk,0,(PtrToFunc)f,0,0){} static RT thunk(const FunctorBase &ftor,P1 p1) { return (Func(ftor.getFunc()))(p1); } }; #if !defined(RHCB_CANT_OVERLOAD_ON_CONSTNESS) template inline CBMemberTranslator1wRet functor( Callee &c,RT (CallType::* RHCB_CONST_REF f)(P1)) { typedef RT (CallType::*MemFunc)(P1); return CBMemberTranslator1wRet(c,f); } #endif template inline CBMemberTranslator1wRet functor( const Callee &c,RT (CallType::* RHCB_CONST_REF f)(P1)const ) { typedef RT (CallType::*MemFunc)(P1)const; return CBMemberTranslator1wRet(c,f); } template inline CBFunctionTranslator1wRet functor( RT (*f)(P1) ) { return CBFunctionTranslator1wRet(f); } template class CBMemberOf1stArgTranslator1wRet:public Functor1wRet{ public: CBMemberOf1stArgTranslator1wRet(const MemFunc &m): Functor1wRet(thunk,(void *)1,0,&m,sizeof(MemFunc)){} static RT thunk(const FunctorBase &ftor,P1 p1) { MemFunc &memFunc RHCB_CTOR_STYLE_INIT (*(MemFunc*)(void *)(ftor.getMemFunc())); return RHCB_BC4_RET_BUG((p1.*memFunc)()); } }; #if !defined(RHCB_CANT_OVERLOAD_ON_CONSTNESS) template inline CBMemberOf1stArgTranslator1wRet functor( RT (CallType::* RHCB_CONST_REF f )()) { typedef RT (CallType::*MemFunc)(); return CBMemberOf1stArgTranslator1wRet(f); } #endif template inline CBMemberOf1stArgTranslator1wRet functor( RT (CallType::* RHCB_CONST_REF f)()const ) { typedef RT (CallType::*MemFunc)()const; return CBMemberOf1stArgTranslator1wRet(f); } /************************* two args - no return *******************/ template class Functor2:public FunctorBase{ public: Functor2(RHCB_DUMMY_INIT = 0){} void operator()(P1 p1,P2 p2)const { thunk(*this,p1,p2); } //for STL typedef P1 first_argument_type; typedef P2 second_argument_type; typedef void result_type; protected: typedef void (*Thunk)(const FunctorBase &,P1,P2); Functor2(Thunk t,const void *c,PtrToFunc f,const void *mf,size_t sz): FunctorBase(c,f,mf,sz),thunk(t){} private: Thunk thunk; }; template class CBMemberTranslator2:public Functor2{ public: CBMemberTranslator2(Callee &c,const MemFunc &m): Functor2(thunk,&c,0,&m,sizeof(MemFunc)){} static void thunk(const FunctorBase &ftor,P1 p1,P2 p2) { Callee *callee = (Callee *)ftor.getCallee(); MemFunc &memFunc RHCB_CTOR_STYLE_INIT (*(MemFunc*)(void *)(ftor.getMemFunc())); (callee->*memFunc)(p1,p2); } }; template class CBFunctionTranslator2:public Functor2{ public: CBFunctionTranslator2(Func f):Functor2(thunk,0,(PtrToFunc)f,0,0){} static void thunk(const FunctorBase &ftor,P1 p1,P2 p2) { (Func(ftor.getFunc()))(p1,p2); } }; #if !defined(RHCB_CANT_OVERLOAD_ON_CONSTNESS) template inline CBMemberTranslator2 functor( Callee &c,void (CallType::* RHCB_CONST_REF f)(P1,P2) ) { typedef void (CallType::*MemFunc)(P1,P2); return CBMemberTranslator2(c,f); } #endif template inline CBMemberTranslator2 functor( const Callee &c,void (CallType::* RHCB_CONST_REF f)(P1,P2)const) { typedef void (CallType::*MemFunc)(P1,P2)const; return CBMemberTranslator2(c,f); } template inline CBFunctionTranslator2 functor( void (*f)(P1,P2)) { return CBFunctionTranslator2(f); } template class CBMemberOf1stArgTranslator2:public Functor2{ public: CBMemberOf1stArgTranslator2(const MemFunc &m): Functor2(thunk,(void *)1,0,&m,sizeof(MemFunc)){} static void thunk(const FunctorBase &ftor,P1 p1,P2 p2) { MemFunc &memFunc RHCB_CTOR_STYLE_INIT (*(MemFunc*)(void *)(ftor.getMemFunc())); (p1.*memFunc)(p2); } }; #if !defined(RHCB_CANT_OVERLOAD_ON_CONSTNESS) template inline CBMemberOf1stArgTranslator2 functor( void (CallType::* RHCB_CONST_REF f)(P1)) { typedef void (CallType::*MemFunc)(P1); return CBMemberOf1stArgTranslator2(f); } #endif template inline CBMemberOf1stArgTranslator2 functor( void (CallType::* RHCB_CONST_REF f)(P1)const) { typedef void (CallType::*MemFunc)(P1)const; return CBMemberOf1stArgTranslator2(f); } /************************* two args - with return *******************/ template class Functor2wRet:public FunctorBase{ public: Functor2wRet(RHCB_DUMMY_INIT = 0){} RT operator()(P1 p1,P2 p2)const { return RHCB_BC4_RET_BUG(thunk(*this,p1,p2)); } //for STL typedef P1 first_argument_type; typedef P2 second_argument_type; typedef RT result_type; protected: typedef RT (*Thunk)(const FunctorBase &,P1,P2); Functor2wRet(Thunk t,const void *c,PtrToFunc f,const void *mf,size_t sz): FunctorBase(c,f,mf,sz),thunk(t){} private: Thunk thunk; }; template class CBMemberTranslator2wRet:public Functor2wRet{ public: CBMemberTranslator2wRet(Callee &c,const MemFunc &m): Functor2wRet(thunk,&c,0,&m,sizeof(MemFunc)){} static RT thunk(const FunctorBase &ftor,P1 p1,P2 p2) { Callee *callee = (Callee *)ftor.getCallee(); MemFunc &memFunc RHCB_CTOR_STYLE_INIT (*(MemFunc*)(void *)(ftor.getMemFunc())); return RHCB_BC4_RET_BUG((callee->*memFunc)(p1,p2)); } }; template class CBFunctionTranslator2wRet:public Functor2wRet{ public: CBFunctionTranslator2wRet(Func f): Functor2wRet(thunk,0,(PtrToFunc)f,0,0){} static RT thunk(const FunctorBase &ftor,P1 p1,P2 p2) { return (Func(ftor.getFunc()))(p1,p2); } }; #if !defined(RHCB_CANT_OVERLOAD_ON_CONSTNESS) template inline CBMemberTranslator2wRet functor( Callee &c,RT (CallType::* RHCB_CONST_REF f)(P1,P2)) { typedef RT (CallType::*MemFunc)(P1,P2); return CBMemberTranslator2wRet(c,f); } #endif template inline CBMemberTranslator2wRet functor( const Callee &c,RT (CallType::* RHCB_CONST_REF f)(P1,P2)const) { typedef RT (CallType::*MemFunc)(P1,P2)const; return CBMemberTranslator2wRet(c,f); } template inline CBFunctionTranslator2wRet functor( RT (*f)(P1,P2)) { return CBFunctionTranslator2wRet(f); } template class CBMemberOf1stArgTranslator2wRet:public Functor2wRet{ public: CBMemberOf1stArgTranslator2wRet(const MemFunc &m): Functor2wRet(thunk,(void *)1,0,&m,sizeof(MemFunc)){} static RT thunk(const FunctorBase &ftor,P1 p1,P2 p2) { MemFunc &memFunc RHCB_CTOR_STYLE_INIT (*(MemFunc*)(void *)(ftor.getMemFunc())); return RHCB_BC4_RET_BUG((p1.*memFunc)(p2)); } }; #if !defined(RHCB_CANT_OVERLOAD_ON_CONSTNESS) template inline CBMemberOf1stArgTranslator2wRet functor( RT (CallType::* RHCB_CONST_REF f)(P1)) { typedef RT (CallType::*MemFunc)(P1); return CBMemberOf1stArgTranslator2wRet(f); } #endif template inline CBMemberOf1stArgTranslator2wRet functor( RT (CallType::* RHCB_CONST_REF f)(P1)const) { typedef RT (CallType::*MemFunc)(P1)const; return CBMemberOf1stArgTranslator2wRet(f); } /************************* three args - no return *******************/ template class Functor3:public FunctorBase{ public: Functor3(RHCB_DUMMY_INIT = 0){} void operator()(P1 p1,P2 p2,P3 p3)const { thunk(*this,p1,p2,p3); } protected: typedef void (*Thunk)(const FunctorBase &,P1,P2,P3); Functor3(Thunk t,const void *c,PtrToFunc f,const void *mf,size_t sz): FunctorBase(c,f,mf,sz),thunk(t){} private: Thunk thunk; }; template class CBMemberTranslator3:public Functor3{ public: CBMemberTranslator3(Callee &c,const MemFunc &m): Functor3(thunk,&c,0,&m,sizeof(MemFunc)){} static void thunk(const FunctorBase &ftor,P1 p1,P2 p2,P3 p3) { Callee *callee = (Callee *)ftor.getCallee(); MemFunc &memFunc RHCB_CTOR_STYLE_INIT (*(MemFunc*)(void *)(ftor.getMemFunc())); (callee->*memFunc)(p1,p2,p3); } }; template class CBFunctionTranslator3:public Functor3{ public: CBFunctionTranslator3(Func f):Functor3(thunk,0,(PtrToFunc)f,0,0){} static void thunk(const FunctorBase &ftor,P1 p1,P2 p2,P3 p3) { (Func(ftor.getFunc()))(p1,p2,p3); } }; #if !defined(RHCB_CANT_OVERLOAD_ON_CONSTNESS) template inline CBMemberTranslator3 functor( Callee &c,void (CallType::* RHCB_CONST_REF f)(P1,P2,P3)) { typedef void (CallType::*MemFunc)(P1,P2,P3); return CBMemberTranslator3(c,f); } #endif template inline CBMemberTranslator3 functor( const Callee &c,void (CallType::* RHCB_CONST_REF f)(P1,P2,P3)const) { typedef void (CallType::*MemFunc)(P1,P2,P3)const; return CBMemberTranslator3(c,f); } template inline CBFunctionTranslator3 functor( void (*f)(P1,P2,P3)) { return CBFunctionTranslator3(f); } template class CBMemberOf1stArgTranslator3:public Functor3{ public: CBMemberOf1stArgTranslator3(const MemFunc &m): Functor3(thunk,(void *)1,0,&m,sizeof(MemFunc)){} static void thunk(const FunctorBase &ftor,P1 p1,P2 p2,P3 p3) { MemFunc &memFunc RHCB_CTOR_STYLE_INIT (*(MemFunc*)(void *)(ftor.getMemFunc())); (p1.*memFunc)(p2,p3); } }; #if !defined(RHCB_CANT_OVERLOAD_ON_CONSTNESS) template inline CBMemberOf1stArgTranslator3 functor( void (CallType::* RHCB_CONST_REF f)(P1,P2)) { typedef void (CallType::*MemFunc)(P1,P2); return CBMemberOf1stArgTranslator3(f); } #endif template inline CBMemberOf1stArgTranslator3 functor( void (CallType::* RHCB_CONST_REF f)(P1,P2)const) { typedef void (CallType::*MemFunc)(P1,P2)const; return CBMemberOf1stArgTranslator3(f); } /************************* three args - with return *******************/ template class Functor3wRet:public FunctorBase{ public: Functor3wRet(RHCB_DUMMY_INIT = 0){} RT operator()(P1 p1,P2 p2,P3 p3)const { return RHCB_BC4_RET_BUG(thunk(*this,p1,p2,p3)); } protected: typedef RT (*Thunk)(const FunctorBase &,P1,P2,P3); Functor3wRet(Thunk t,const void *c,PtrToFunc f,const void *mf,size_t sz): FunctorBase(c,f,mf,sz),thunk(t){} private: Thunk thunk; }; template class CBMemberTranslator3wRet:public Functor3wRet{ public: CBMemberTranslator3wRet(Callee &c,const MemFunc &m): Functor3wRet(thunk,&c,0,&m,sizeof(MemFunc)){} static RT thunk(const FunctorBase &ftor,P1 p1,P2 p2,P3 p3) { Callee *callee = (Callee *)ftor.getCallee(); MemFunc &memFunc RHCB_CTOR_STYLE_INIT (*(MemFunc*)(void *)(ftor.getMemFunc())); return RHCB_BC4_RET_BUG((callee->*memFunc)(p1,p2,p3)); } }; template class CBFunctionTranslator3wRet:public Functor3wRet{ public: CBFunctionTranslator3wRet(Func f): Functor3wRet(thunk,0,(PtrToFunc)f,0,0){} static RT thunk(const FunctorBase &ftor,P1 p1,P2 p2,P3 p3) { return (Func(ftor.getFunc()))(p1,p2,p3); } }; #if !defined(RHCB_CANT_OVERLOAD_ON_CONSTNESS) template inline CBMemberTranslator3wRet functor( Callee &c,RT (CallType::* RHCB_CONST_REF f)(P1,P2,P3)) { typedef RT (CallType::*MemFunc)(P1,P2,P3); return CBMemberTranslator3wRet(c,f); } #endif template inline CBMemberTranslator3wRet functor( const Callee &c,RT (CallType::* RHCB_CONST_REF f)(P1,P2,P3)const) { typedef RT (CallType::*MemFunc)(P1,P2,P3)const; return CBMemberTranslator3wRet(c,f); } template inline CBFunctionTranslator3wRet functor( RT (*f)(P1,P2,P3) ) { return CBFunctionTranslator3wRet(f); } template class CBMemberOf1stArgTranslator3wRet:public Functor3wRet{ public: CBMemberOf1stArgTranslator3wRet(const MemFunc &m): Functor3wRet(thunk,(void *)1,0,&m,sizeof(MemFunc)){} static RT thunk(const FunctorBase &ftor,P1 p1,P2 p2,P3 p3) { MemFunc &memFunc RHCB_CTOR_STYLE_INIT (*(MemFunc*)(void *)(ftor.getMemFunc())); return RHCB_BC4_RET_BUG((p1.*memFunc)(p2,p3)); } }; #if !defined(RHCB_CANT_OVERLOAD_ON_CONSTNESS) template inline CBMemberOf1stArgTranslator3wRet functor( RT (CallType::* RHCB_CONST_REF f)(P1,P2)) { typedef RT (CallType::*MemFunc)(P1,P2); return CBMemberOf1stArgTranslator3wRet(f); } #endif template inline CBMemberOf1stArgTranslator3wRet functor( RT (CallType::* RHCB_CONST_REF f)(P1,P2)const) { typedef RT (CallType::*MemFunc)(P1,P2)const; return CBMemberOf1stArgTranslator3wRet(f); } /************************* four args - no return *******************/ template class Functor4:public FunctorBase{ public: Functor4(RHCB_DUMMY_INIT = 0){} void operator()(P1 p1,P2 p2,P3 p3,P4 p4)const { thunk(*this,p1,p2,p3,p4); } protected: typedef void (*Thunk)(const FunctorBase &,P1,P2,P3,P4); Functor4(Thunk t,const void *c,PtrToFunc f,const void *mf,size_t sz): FunctorBase(c,f,mf,sz),thunk(t){} private: Thunk thunk; }; template class CBMemberTranslator4:public Functor4{ public: CBMemberTranslator4(Callee &c,const MemFunc &m): Functor4(thunk,&c,0,&m,sizeof(MemFunc)){} static void thunk(const FunctorBase &ftor,P1 p1,P2 p2,P3 p3,P4 p4) { Callee *callee = (Callee *)ftor.getCallee(); MemFunc &memFunc RHCB_CTOR_STYLE_INIT (*(MemFunc*)(void *)(ftor.getMemFunc())); (callee->*memFunc)(p1,p2,p3,p4); } }; template class CBFunctionTranslator4:public Functor4{ public: CBFunctionTranslator4(Func f): Functor4(thunk,0,(PtrToFunc)f,0,0){} static void thunk(const FunctorBase &ftor,P1 p1,P2 p2,P3 p3,P4 p4) { (Func(ftor.getFunc()))(p1,p2,p3,p4); } }; #if !defined(RHCB_CANT_OVERLOAD_ON_CONSTNESS) template inline CBMemberTranslator4 functor( Callee &c,void (CallType::* RHCB_CONST_REF f)(P1,P2,P3,P4)) { typedef void (CallType::*MemFunc)(P1,P2,P3,P4); return CBMemberTranslator4(c,f); } #endif template inline CBMemberTranslator4 functor( const Callee &c,void (CallType::* RHCB_CONST_REF f)(P1,P2,P3,P4)const) { typedef void (CallType::*MemFunc)(P1,P2,P3,P4)const; return CBMemberTranslator4(c,f); } template inline CBFunctionTranslator4 functor( void (*f)(P1,P2,P3,P4)) { return CBFunctionTranslator4(f); } template class CBMemberOf1stArgTranslator4:public Functor4{ public: CBMemberOf1stArgTranslator4(const MemFunc &m): Functor4(thunk,(void *)1,0,&m,sizeof(MemFunc)){} static void thunk(const FunctorBase &ftor,P1 p1,P2 p2,P3 p3,P4 p4) { MemFunc &memFunc RHCB_CTOR_STYLE_INIT (*(MemFunc*)(void *)(ftor.getMemFunc())); (p1.*memFunc)(p2,p3,p4); } }; #if !defined(RHCB_CANT_OVERLOAD_ON_CONSTNESS) template inline CBMemberOf1stArgTranslator4 functor( RT (CallType::* RHCB_CONST_REF f)(P1,P2,P3)) { typedef RT (CallType::*MemFunc)(P1,P2,P3); return CBMemberOf1stArgTranslator4(f); } #endif template inline CBMemberOf1stArgTranslator4 functor( RT (CallType::* RHCB_CONST_REF f)(P1,P2,P3)const) { typedef RT (CallType::*MemFunc)(P1,P2,P3)const; return CBMemberOf1stArgTranslator4(f); } /************************* four args - with return *******************/ template class Functor4wRet:public FunctorBase{ public: Functor4wRet(RHCB_DUMMY_INIT = 0){} RT operator()(P1 p1,P2 p2,P3 p3,P4 p4)const { return RHCB_BC4_RET_BUG(thunk(*this,p1,p2,p3,p4)); } protected: typedef RT (*Thunk)(const FunctorBase &,P1,P2,P3,P4); Functor4wRet(Thunk t,const void *c,PtrToFunc f,const void *mf,size_t sz): FunctorBase(c,f,mf,sz),thunk(t){} private: Thunk thunk; }; template class CBMemberTranslator4wRet:public Functor4wRet{ public: CBMemberTranslator4wRet(Callee &c,const MemFunc &m): Functor4wRet(thunk,&c,0,&m,sizeof(MemFunc)){} static RT thunk(const FunctorBase &ftor,P1 p1,P2 p2,P3 p3,P4 p4) { Callee *callee = (Callee *)ftor.getCallee(); MemFunc &memFunc RHCB_CTOR_STYLE_INIT (*(MemFunc*)(void *)(ftor.getMemFunc())); return RHCB_BC4_RET_BUG((callee->*memFunc)(p1,p2,p3,p4)); } }; template class CBFunctionTranslator4wRet:public Functor4wRet{ public: CBFunctionTranslator4wRet(Func f): Functor4wRet(thunk,0,(PtrToFunc)f,0,0){} static RT thunk(const FunctorBase &ftor,P1 p1,P2 p2,P3 p3,P4 p4) { return (Func(ftor.getFunc()))(p1,p2,p3,p4); } }; #if !defined(RHCB_CANT_OVERLOAD_ON_CONSTNESS) template inline CBMemberTranslator4wRet functor( Callee &c,RT (CallType::* RHCB_CONST_REF f)(P1,P2,P3,P4)) { typedef RT (CallType::*MemFunc)(P1,P2,P3,P4); return CBMemberTranslator4wRet(c,f); } #endif template inline CBMemberTranslator4wRet functor( const Callee &c,RT (CallType::* RHCB_CONST_REF f)(P1,P2,P3,P4)const) { typedef RT (CallType::*MemFunc)(P1,P2,P3,P4)const; return CBMemberTranslator4wRet(c,f); } template inline CBFunctionTranslator4wRet functor( RT (*f)(P1,P2,P3,P4) ) { return CBFunctionTranslator4wRet (f); } template class CBMemberOf1stArgTranslator4wRet:public Functor4wRet{ public: CBMemberOf1stArgTranslator4wRet(const MemFunc &m): Functor4wRet(thunk,(void *)1,0,&m,sizeof(MemFunc)){} static RT thunk(const FunctorBase &ftor,P1 p1,P2 p2,P3 p3,P4 p4) { MemFunc &memFunc RHCB_CTOR_STYLE_INIT (*(MemFunc*)(void *)(ftor.getMemFunc())); return RHCB_BC4_RET_BUG((p1.*memFunc)(p2,p3,p4)); } }; #if !defined(RHCB_CANT_OVERLOAD_ON_CONSTNESS) template inline CBMemberOf1stArgTranslator4wRet functor( RT (CallType::* RHCB_CONST_REF f)(P1,P2,P3)) { typedef RT (CallType::*MemFunc)(P1,P2,P3); return CBMemberOf1stArgTranslator4wRet(f); } #endif template inline CBMemberOf1stArgTranslator4wRet functor( RT (CallType::* RHCB_CONST_REF f)(P1,P2,P3)const) { typedef RT (CallType::*MemFunc)(P1,P2,P3)const; return CBMemberOf1stArgTranslator4wRet(f); } /************************* five args - no return *******************/ template class Functor5:public FunctorBase{ public: Functor5(RHCB_DUMMY_INIT = 0){} void operator()(P1 p1,P2 p2,P3 p3,P4 p4,P5 p5)const { thunk(*this,p1,p2,p3,p4,p5); } protected: typedef void (*Thunk)(const FunctorBase &,P1,P2,P3,P4,P5); Functor5(Thunk t,const void *c,PtrToFunc f,const void *mf,size_t sz): FunctorBase(c,f,mf,sz),thunk(t){} private: Thunk thunk; }; template class CBMemberTranslator5:public Functor5{ public: CBMemberTranslator5(Callee &c,const MemFunc &m): Functor5(thunk,&c,0,&m,sizeof(MemFunc)){} static void thunk(const FunctorBase &ftor,P1 p1,P2 p2,P3 p3,P4 p4,P5 p5) { Callee *callee = (Callee *)ftor.getCallee(); MemFunc &memFunc RHCB_CTOR_STYLE_INIT (*(MemFunc*)(void *)(ftor.getMemFunc())); (callee->*memFunc)(p1,p2,p3,p4,p5); } }; template class CBFunctionTranslator5:public Functor5{ public: CBFunctionTranslator5(Func f): Functor5(thunk,0,(PtrToFunc)f,0,0){} static void thunk(const FunctorBase &ftor,P1 p1,P2 p2,P3 p3,P4 p4,P5 p5) { (Func(ftor.getFunc()))(p1,p2,p3,p4,p5); } }; #if !defined(RHCB_CANT_OVERLOAD_ON_CONSTNESS) template inline CBMemberTranslator5 functor( Callee &c,RT (CallType::* RHCB_CONST_REF f)(P1,P2,P3,P4,P5)) { typedef RT (CallType::*MemFunc)(P1,P2,P3,P4,P5); return CBMemberTranslator5(c,f); } #endif template inline CBMemberTranslator5 functor( const Callee &c,RT (CallType::* RHCB_CONST_REF f)(P1,P2,P3,P4,P5)const) { typedef RT (CallType::*MemFunc)(P1,P2,P3,P4,P5)const; return CBMemberTranslator5(c,f); } template inline CBFunctionTranslator5 functor( RT (*f)(P1,P2,P3,P4,P5)) { return CBFunctionTranslator5(f); } template class CBMemberOf1stArgTranslator5:public Functor5{ public: CBMemberOf1stArgTranslator5(const MemFunc &m): Functor5(thunk,(void *)1,0,&m,sizeof(MemFunc)){} static void thunk(const FunctorBase &ftor,P1 p1,P2 p2,P3 p3,P4 p4,P5 p5) { MemFunc &memFunc RHCB_CTOR_STYLE_INIT (*(MemFunc*)(void *)(ftor.getMemFunc())); (p1.*memFunc)(p2,p3,p4,p5); } }; #if !defined(RHCB_CANT_OVERLOAD_ON_CONSTNESS) template inline CBMemberOf1stArgTranslator5 functor( RT (CallType::* RHCB_CONST_REF f)(P1,P2,P3,P4)) { typedef RT (CallType::*MemFunc)(P1,P2,P3,P4); return CBMemberOf1stArgTranslator5(f); } #endif template inline CBMemberOf1stArgTranslator5 functor( RT (CallType::* RHCB_CONST_REF f)(P1,P2,P3,P4)const) { typedef RT (CallType::*MemFunc)(P1,P2,P3,P4)const; return CBMemberOf1stArgTranslator5(f); } /************************* six args - no return *******************/ template class Functor6 :public FunctorBase{ public: Functor6(RHCB_DUMMY_INIT = 0){} void operator()(P1 p1, P2 p2, P3 p3, P4 p4, P5 p5, P6 p6)const { thunk(*this, p1, p2, p3, p4, p5, p6); } protected: typedef void(*Thunk)(const FunctorBase &, P1, P2, P3, P4, P5, P6); Functor6(Thunk t, const void *c, PtrToFunc f, const void *mf, size_t sz) : FunctorBase(c, f, mf, sz), thunk(t){} private: Thunk thunk; }; template class CBMemberTranslator6 :public Functor6{ public: CBMemberTranslator6(Callee &c, const MemFunc &m) : Functor6(thunk, &c, 0, &m, sizeof(MemFunc)){} static void thunk(const FunctorBase &ftor, P1 p1, P2 p2, P3 p3, P4 p4, P5 p5, P6 p6) { Callee *callee = (Callee *)ftor.getCallee(); MemFunc &memFunc RHCB_CTOR_STYLE_INIT (*(MemFunc*)(void *)(ftor.getMemFunc())); (callee->*memFunc)(p1, p2, p3, p4, p5, p6); } }; template class CBFunctionTranslator6 :public Functor6{ public: CBFunctionTranslator6(Func f) : Functor6(thunk, 0, (PtrToFunc)f, 0, 0){} static void thunk(const FunctorBase &ftor, P1 p1, P2 p2, P3 p3, P4 p4, P5 p5, P6 p6) { (Func(ftor.getFunc()))(p1, p2, p3, p4, p5, p6); } }; #if !defined(RHCB_CANT_OVERLOAD_ON_CONSTNESS) template inline CBMemberTranslator6 functor(Callee &c, RT(CallType::* RHCB_CONST_REF f)(P1, P2, P3, P4, P5, P6)) { typedef RT(CallType::*MemFunc)(P1, P2, P3, P4, P5, P6); return CBMemberTranslator6(c, f); } #endif template inline CBMemberTranslator6 functor(const Callee &c, RT(CallType::* RHCB_CONST_REF f)(P1, P2, P3, P4, P5, P6)const) { typedef RT(CallType::*MemFunc)(P1, P2, P3, P4, P5, P6)const; return CBMemberTranslator6(c, f); } template inline CBFunctionTranslator6 functor(RT(*f)(P1, P2, P3, P4, P5, P6)) { return CBFunctionTranslator6(f); } template class CBMemberOf1stArgTranslator6 :public Functor6{ public: CBMemberOf1stArgTranslator6(const MemFunc &m) : Functor6(thunk, (void *)1, 0, &m, sizeof(MemFunc)){} static void thunk(const FunctorBase &ftor, P1 p1, P2 p2, P3 p3, P4 p4, P5 p5, P6 p6) { MemFunc &memFunc RHCB_CTOR_STYLE_INIT (*(MemFunc*)(void *)(ftor.getMemFunc())); (p1.*memFunc)(p2, p3, p4, p5, p6); } }; #if !defined(RHCB_CANT_OVERLOAD_ON_CONSTNESS) template inline CBMemberOf1stArgTranslator6 functor(RT(CallType::* RHCB_CONST_REF f)(P1, P2, P3, P4, P5)) { typedef RT(CallType::*MemFunc)(P1, P2, P3, P4, P5); return CBMemberOf1stArgTranslator6(f); } #endif template inline CBMemberOf1stArgTranslator6 functor(RT(CallType::* RHCB_CONST_REF f)(P1, P2, P3, P4, P5)const) { typedef RT(CallType::*MemFunc)(P1, P2, P3, P4, P5)const; return CBMemberOf1stArgTranslator6(f); } /////////////////////////////////////////////////////////////////////////////// // // Inlines. // /////////////////////////////////////////////////////////////////////////////// inline bool operator==(const FunctorBase &lhs,const FunctorBase &rhs) { if (!lhs.callee) { if (rhs.callee) return false; return lhs.func == rhs.func; } else { if (!rhs.callee) return false; return lhs.callee == rhs.callee && !memcmp(lhs.memFunc,rhs.memFunc,FunctorBase::MEM_FUNC_SIZE); } } inline bool operator!=(const FunctorBase &lhs,const FunctorBase &rhs) { return !(lhs == rhs); } inline bool operator<(const FunctorBase &lhs,const FunctorBase &rhs) { //must order across funcs and callee/memfuncs, funcs are first if(!lhs.callee) { if(rhs.callee) return true; else return lhs.func < rhs.func; } else { if(!rhs.callee) return false; if(lhs.callee != rhs.callee) return lhs.callee < rhs.callee; else return memcmp(lhs.memFunc,rhs.memFunc,FunctorBase::MEM_FUNC_SIZE)<0; } } ////////////////////////////////////////////////////////////////////////// template class CFunctorsList { public: // Add functor to list. void Add( const FUNCTOR &f ) { m_functors.push_back( f ); } // Remvoe functor from list. void Remove( const FUNCTOR &f ) { typename Container::iterator it = std::find( m_functors.begin(),m_functors.end(),f ); if (it != m_functors.end()) { #undef erase m_functors.erase( it ); } } ////////////////////////////////////////////////////////////////////////// // Call all functors in this list. // Also several template functions for multiple parameters. ////////////////////////////////////////////////////////////////////////// void Call() { for (typename Container::iterator it = m_functors.begin(); it != m_functors.end(); ++it) { (*it)(); } } template void Call( const T1 ¶m1 ) { for (typename Container::iterator it = m_functors.begin(); it != m_functors.end(); ++it) { (*it)( param1 ); } } template void Call( const T1 ¶m1,const T2 ¶m2 ) { for (typename Container::iterator it = m_functors.begin(); it != m_functors.end(); ++it) { (*it)( param1,param2 ); } } template void Call( const T1 ¶m1,const T2 ¶m2,const T3 ¶m3 ) { for (typename Container::iterator it = m_functors.begin(); it != m_functors.end(); ++it) { (*it)( param1,param2,param3 ); } } private: typedef std::list Container; Container m_functors; }; #endif // CRYINCLUDE_functor_H