// Copyright (C) 2008 Davis E. King (davis@dlib.net) // License: Boost Software License See LICENSE.txt for the full license. #ifndef DLIB_BOUND_FUNCTION_POINTER_KERNEl_1_ #define DLIB_BOUND_FUNCTION_POINTER_KERNEl_1_ #include "../algs.h" #include "../member_function_pointer.h" #include "bound_function_pointer_kernel_abstract.h" namespace dlib { // ---------------------------------------------------------------------------------------- namespace bfp1_helpers { template <typename T> struct strip { typedef T type; }; template <typename T> struct strip<T&> { typedef T type; }; // ------------------------------------------------------------------------------------ class bound_function_helper_base_base { public: virtual ~bound_function_helper_base_base(){} virtual void call() const = 0; virtual bool is_set() const = 0; virtual void clone(void* ptr) const = 0; }; // ------------------------------------------------------------------------------------ template <typename T1, typename T2, typename T3, typename T4> class bound_function_helper_base : public bound_function_helper_base_base { public: bound_function_helper_base():arg1(0), arg2(0), arg3(0), arg4(0) {} typename strip<T1>::type* arg1; typename strip<T2>::type* arg2; typename strip<T3>::type* arg3; typename strip<T4>::type* arg4; member_function_pointer<T1,T2,T3,T4> mfp; }; // ---------------- template <typename F, typename T1 = void, typename T2 = void, typename T3 = void, typename T4 = void> class bound_function_helper : public bound_function_helper_base<T1,T2,T3,T4> { public: void call() const { (*fp)(*this->arg1, *this->arg2, *this->arg3, *this->arg4); } typename strip<F>::type* fp; }; template <typename T1, typename T2, typename T3, typename T4> class bound_function_helper<void,T1,T2,T3,T4> : public bound_function_helper_base<T1,T2,T3,T4> { public: void call() const { if (this->mfp) this->mfp(*this->arg1, *this->arg2, *this->arg3, *this->arg4); else if (fp) fp(*this->arg1, *this->arg2, *this->arg3, *this->arg4); } void (*fp)(T1, T2, T3, T4); }; // ---------------- template <typename F> class bound_function_helper<F,void,void,void,void> : public bound_function_helper_base<void,void,void,void> { public: void call() const { (*fp)(); } typename strip<F>::type* fp; }; template <> class bound_function_helper<void,void,void,void,void> : public bound_function_helper_base<void,void,void,void> { public: void call() const { if (this->mfp) this->mfp(); else if (fp) fp(); } void (*fp)(); }; // ---------------- template <typename F, typename T1> class bound_function_helper<F,T1,void,void,void> : public bound_function_helper_base<T1,void,void,void> { public: void call() const { (*fp)(*this->arg1); } typename strip<F>::type* fp; }; template <typename T1> class bound_function_helper<void,T1,void,void,void> : public bound_function_helper_base<T1,void,void,void> { public: void call() const { if (this->mfp) this->mfp(*this->arg1); else if (fp) fp(*this->arg1); } void (*fp)(T1); }; // ---------------- template <typename F, typename T1, typename T2> class bound_function_helper<F,T1,T2,void,void> : public bound_function_helper_base<T1,T2,void,void> { public: void call() const { (*fp)(*this->arg1, *this->arg2); } typename strip<F>::type* fp; }; template <typename T1, typename T2> class bound_function_helper<void,T1,T2,void,void> : public bound_function_helper_base<T1,T2,void,void> { public: void call() const { if (this->mfp) this->mfp(*this->arg1, *this->arg2); else if (fp) fp(*this->arg1, *this->arg2); } void (*fp)(T1, T2); }; // ---------------- template <typename F, typename T1, typename T2, typename T3> class bound_function_helper<F,T1,T2,T3,void> : public bound_function_helper_base<T1,T2,T3,void> { public: void call() const { (*fp)(*this->arg1, *this->arg2, *this->arg3); } typename strip<F>::type* fp; }; template <typename T1, typename T2, typename T3> class bound_function_helper<void,T1,T2,T3,void> : public bound_function_helper_base<T1,T2,T3,void> { public: void call() const { if (this->mfp) this->mfp(*this->arg1, *this->arg2, *this->arg3); else if (fp) fp(*this->arg1, *this->arg2, *this->arg3); } void (*fp)(T1, T2, T3); }; // ------------------------------------------------------------------------------------ // ------------------------------------------------------------------------------------ template <typename T> class bound_function_helper_T : public T { public: bound_function_helper_T(){ this->fp = 0;} bool is_set() const { return this->fp != 0 || this->mfp.is_set(); } template <unsigned long mem_size> void safe_clone(stack_based_memory_block<mem_size>& buf) { // This is here just to validate the assumption that our block of memory we have made // in bf_memory is the right size to store the data for this object. If you // get a compiler error on this line then email me :) COMPILE_TIME_ASSERT(sizeof(bound_function_helper_T) <= mem_size); clone(buf.get()); } void clone (void* ptr) const { bound_function_helper_T* p = new(ptr) bound_function_helper_T(); p->arg1 = this->arg1; p->arg2 = this->arg2; p->arg3 = this->arg3; p->arg4 = this->arg4; p->fp = this->fp; p->mfp = this->mfp; } }; } // ---------------------------------------------------------------------------------------- class bound_function_pointer { typedef bfp1_helpers::bound_function_helper_T<bfp1_helpers::bound_function_helper<void,int> > bf_null_type; public: // These typedefs are here for backwards compatibility with previous versions of // dlib. typedef bound_function_pointer kernel_1a; typedef bound_function_pointer kernel_1a_c; bound_function_pointer ( ) { bf_null_type().safe_clone(bf_memory); } bound_function_pointer ( const bound_function_pointer& item ) { item.bf()->clone(bf_memory.get()); } ~bound_function_pointer() { destroy_bf_memory(); } bound_function_pointer& operator= ( const bound_function_pointer& item ) { bound_function_pointer(item).swap(*this); return *this; } void clear ( ) { bound_function_pointer().swap(*this); } bool is_set ( ) const { return bf()->is_set(); } void swap ( bound_function_pointer& item ) { // make a temp copy of item bound_function_pointer temp(item); // destory the stuff in item item.destroy_bf_memory(); // copy *this into item bf()->clone(item.bf_memory.get()); // destory the stuff in this destroy_bf_memory(); // copy temp into *this temp.bf()->clone(bf_memory.get()); } void operator() ( ) const { // make sure requires clause is not broken DLIB_ASSERT(is_set() == true , "\tvoid bound_function_pointer::operator()" << "\n\tYou must call set() before you can use this function" << "\n\tthis: " << this ); bf()->call(); } private: struct dummy{ void nonnull() {}}; typedef void (dummy::*safe_bool)(); public: operator safe_bool () const { return is_set() ? &dummy::nonnull : 0; } bool operator!() const { return !is_set(); } // ------------------------------------------- // set function object overloads // ------------------------------------------- template <typename F> void set ( F& function_object ) { COMPILE_TIME_ASSERT(is_function<F>::value == false); COMPILE_TIME_ASSERT(is_pointer_type<F>::value == false); using namespace bfp1_helpers; destroy_bf_memory(); typedef bound_function_helper_T<bound_function_helper<F> > bf_helper_type; bf_helper_type temp; temp.fp = &function_object; temp.safe_clone(bf_memory); } template <typename F, typename A1 > void set ( F& function_object, A1& arg1 ) { COMPILE_TIME_ASSERT(is_function<F>::value == false); COMPILE_TIME_ASSERT(is_pointer_type<F>::value == false); using namespace bfp1_helpers; destroy_bf_memory(); typedef bound_function_helper_T<bound_function_helper<F,A1> > bf_helper_type; bf_helper_type temp; temp.arg1 = &arg1; temp.fp = &function_object; temp.safe_clone(bf_memory); } template <typename F, typename A1, typename A2 > void set ( F& function_object, A1& arg1, A2& arg2 ) { COMPILE_TIME_ASSERT(is_function<F>::value == false); COMPILE_TIME_ASSERT(is_pointer_type<F>::value == false); using namespace bfp1_helpers; destroy_bf_memory(); typedef bound_function_helper_T<bound_function_helper<F,A1,A2> > bf_helper_type; bf_helper_type temp; temp.arg1 = &arg1; temp.arg2 = &arg2; temp.fp = &function_object; temp.safe_clone(bf_memory); } template <typename F, typename A1, typename A2, typename A3 > void set ( F& function_object, A1& arg1, A2& arg2, A3& arg3 ) { COMPILE_TIME_ASSERT(is_function<F>::value == false); COMPILE_TIME_ASSERT(is_pointer_type<F>::value == false); using namespace bfp1_helpers; destroy_bf_memory(); typedef bound_function_helper_T<bound_function_helper<F,A1,A2,A3> > bf_helper_type; bf_helper_type temp; temp.arg1 = &arg1; temp.arg2 = &arg2; temp.arg3 = &arg3; temp.fp = &function_object; temp.safe_clone(bf_memory); } template <typename F, typename A1, typename A2, typename A3, typename A4> void set ( F& function_object, A1& arg1, A2& arg2, A3& arg3, A4& arg4 ) { COMPILE_TIME_ASSERT(is_function<F>::value == false); COMPILE_TIME_ASSERT(is_pointer_type<F>::value == false); using namespace bfp1_helpers; destroy_bf_memory(); typedef bound_function_helper_T<bound_function_helper<F,A1,A2,A3,A4> > bf_helper_type; bf_helper_type temp; temp.arg1 = &arg1; temp.arg2 = &arg2; temp.arg3 = &arg3; temp.arg4 = &arg4; temp.fp = &function_object; temp.safe_clone(bf_memory); } // ------------------------------------------- // set mfp overloads // ------------------------------------------- template <typename T> void set ( T& object, void (T::*funct)() ) { using namespace bfp1_helpers; destroy_bf_memory(); typedef bound_function_helper_T<bound_function_helper<void> > bf_helper_type; bf_helper_type temp; temp.mfp.set(object,funct); temp.safe_clone(bf_memory); } template <typename T > void set ( const T& object, void (T::*funct)()const ) { using namespace bfp1_helpers; destroy_bf_memory(); typedef bound_function_helper_T<bound_function_helper<void> > bf_helper_type; bf_helper_type temp; temp.mfp.set(object,funct); temp.safe_clone(bf_memory); } // ------------------------------------------- template <typename T, typename T1, typename A1 > void set ( T& object, void (T::*funct)(T1), A1& arg1 ) { using namespace bfp1_helpers; destroy_bf_memory(); typedef bound_function_helper_T<bound_function_helper<void,T1> > bf_helper_type; bf_helper_type temp; temp.arg1 = &arg1; temp.mfp.set(object,funct); temp.safe_clone(bf_memory); } template <typename T, typename T1, typename A1 > void set ( const T& object, void (T::*funct)(T1)const, A1& arg1 ) { using namespace bfp1_helpers; destroy_bf_memory(); typedef bound_function_helper_T<bound_function_helper<void,T1> > bf_helper_type; bf_helper_type temp; temp.arg1 = &arg1; temp.mfp.set(object,funct); temp.safe_clone(bf_memory); } // ---------------- template <typename T, typename T1, typename A1, typename T2, typename A2> void set ( T& object, void (T::*funct)(T1, T2), A1& arg1, A2& arg2 ) { using namespace bfp1_helpers; destroy_bf_memory(); typedef bound_function_helper_T<bound_function_helper<void,T1,T2> > bf_helper_type; bf_helper_type temp; temp.arg1 = &arg1; temp.arg2 = &arg2; temp.mfp.set(object,funct); temp.safe_clone(bf_memory); } template <typename T, typename T1, typename A1, typename T2, typename A2> void set ( const T& object, void (T::*funct)(T1, T2)const, A1& arg1, A2& arg2 ) { using namespace bfp1_helpers; destroy_bf_memory(); typedef bound_function_helper_T<bound_function_helper<void,T1,T2> > bf_helper_type; bf_helper_type temp; temp.arg1 = &arg1; temp.arg2 = &arg2; temp.mfp.set(object,funct); temp.safe_clone(bf_memory); } // ---------------- template <typename T, typename T1, typename A1, typename T2, typename A2, typename T3, typename A3> void set ( T& object, void (T::*funct)(T1, T2, T3), A1& arg1, A2& arg2, A3& arg3 ) { using namespace bfp1_helpers; destroy_bf_memory(); typedef bound_function_helper_T<bound_function_helper<void,T1,T2,T3> > bf_helper_type; bf_helper_type temp; temp.arg1 = &arg1; temp.arg2 = &arg2; temp.arg3 = &arg3; temp.mfp.set(object,funct); temp.safe_clone(bf_memory); } template <typename T, typename T1, typename A1, typename T2, typename A2, typename T3, typename A3> void set ( const T& object, void (T::*funct)(T1, T2, T3)const, A1& arg1, A2& arg2, A3& arg3 ) { using namespace bfp1_helpers; destroy_bf_memory(); typedef bound_function_helper_T<bound_function_helper<void,T1,T2,T3> > bf_helper_type; bf_helper_type temp; temp.arg1 = &arg1; temp.arg2 = &arg2; temp.arg3 = &arg3; temp.mfp.set(object,funct); temp.safe_clone(bf_memory); } // ---------------- template <typename T, typename T1, typename A1, typename T2, typename A2, typename T3, typename A3, typename T4, typename A4> void set ( T& object, void (T::*funct)(T1, T2, T3, T4), A1& arg1, A2& arg2, A3& arg3, A4& arg4 ) { using namespace bfp1_helpers; destroy_bf_memory(); typedef bound_function_helper_T<bound_function_helper<void,T1,T2,T3,T4> > bf_helper_type; bf_helper_type temp; temp.arg1 = &arg1; temp.arg2 = &arg2; temp.arg3 = &arg3; temp.arg4 = &arg4; temp.mfp.set(object,funct); temp.safe_clone(bf_memory); } template <typename T, typename T1, typename A1, typename T2, typename A2, typename T3, typename A3, typename T4, typename A4> void set ( const T& object, void (T::*funct)(T1, T2, T3, T4)const, A1& arg1, A2& arg2, A3& arg3, A4& arg4 ) { using namespace bfp1_helpers; destroy_bf_memory(); typedef bound_function_helper_T<bound_function_helper<void,T1,T2,T3,T4> > bf_helper_type; bf_helper_type temp; temp.arg1 = &arg1; temp.arg2 = &arg2; temp.arg3 = &arg3; temp.arg4 = &arg4; temp.mfp.set(object,funct); temp.safe_clone(bf_memory); } // ------------------------------------------- // set fp overloads // ------------------------------------------- void set ( void (*funct)() ) { using namespace bfp1_helpers; destroy_bf_memory(); typedef bound_function_helper_T<bound_function_helper<void> > bf_helper_type; bf_helper_type temp; temp.fp = funct; temp.safe_clone(bf_memory); } template <typename T1, typename A1> void set ( void (*funct)(T1), A1& arg1 ) { using namespace bfp1_helpers; destroy_bf_memory(); typedef bound_function_helper_T<bound_function_helper<void,T1> > bf_helper_type; bf_helper_type temp; temp.arg1 = &arg1; temp.fp = funct; temp.safe_clone(bf_memory); } template <typename T1, typename A1, typename T2, typename A2> void set ( void (*funct)(T1, T2), A1& arg1, A2& arg2 ) { using namespace bfp1_helpers; destroy_bf_memory(); typedef bound_function_helper_T<bound_function_helper<void,T1,T2> > bf_helper_type; bf_helper_type temp; temp.arg1 = &arg1; temp.arg2 = &arg2; temp.fp = funct; temp.safe_clone(bf_memory); } template <typename T1, typename A1, typename T2, typename A2, typename T3, typename A3> void set ( void (*funct)(T1, T2, T3), A1& arg1, A2& arg2, A3& arg3 ) { using namespace bfp1_helpers; destroy_bf_memory(); typedef bound_function_helper_T<bound_function_helper<void,T1,T2,T3> > bf_helper_type; bf_helper_type temp; temp.arg1 = &arg1; temp.arg2 = &arg2; temp.arg3 = &arg3; temp.fp = funct; temp.safe_clone(bf_memory); } template <typename T1, typename A1, typename T2, typename A2, typename T3, typename A3, typename T4, typename A4> void set ( void (*funct)(T1, T2, T3, T4), A1& arg1, A2& arg2, A3& arg3, A4& arg4 ) { using namespace bfp1_helpers; destroy_bf_memory(); typedef bound_function_helper_T<bound_function_helper<void,T1,T2,T3,T4> > bf_helper_type; bf_helper_type temp; temp.arg1 = &arg1; temp.arg2 = &arg2; temp.arg3 = &arg3; temp.arg4 = &arg4; temp.fp = funct; temp.safe_clone(bf_memory); } // ------------------------------------------- private: stack_based_memory_block<sizeof(bf_null_type)> bf_memory; void destroy_bf_memory ( ) { // Honestly, this probably doesn't even do anything but I'm putting // it here just for good measure. bf()->~bound_function_helper_base_base(); } bfp1_helpers::bound_function_helper_base_base* bf () { return static_cast<bfp1_helpers::bound_function_helper_base_base*>(bf_memory.get()); } const bfp1_helpers::bound_function_helper_base_base* bf () const { return static_cast<const bfp1_helpers::bound_function_helper_base_base*>(bf_memory.get()); } }; // ---------------------------------------------------------------------------------------- inline void swap ( bound_function_pointer& a, bound_function_pointer& b ) { a.swap(b); } // ---------------------------------------------------------------------------------------- } #endif // DLIB_BOUND_FUNCTION_POINTER_KERNEl_1_