// 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 struct strip { typedef T type; }; template struct strip { 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 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::type* arg1; typename strip::type* arg2; typename strip::type* arg3; typename strip::type* arg4; member_function_pointer mfp; }; // ---------------- template class bound_function_helper : public bound_function_helper_base { public: void call() const { (*fp)(*this->arg1, *this->arg2, *this->arg3, *this->arg4); } typename strip::type* fp; }; template class bound_function_helper : public bound_function_helper_base { 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 class bound_function_helper : public bound_function_helper_base { public: void call() const { (*fp)(); } typename strip::type* fp; }; template <> class bound_function_helper : public bound_function_helper_base { public: void call() const { if (this->mfp) this->mfp(); else if (fp) fp(); } void (*fp)(); }; // ---------------- template class bound_function_helper : public bound_function_helper_base { public: void call() const { (*fp)(*this->arg1); } typename strip::type* fp; }; template class bound_function_helper : public bound_function_helper_base { public: void call() const { if (this->mfp) this->mfp(*this->arg1); else if (fp) fp(*this->arg1); } void (*fp)(T1); }; // ---------------- template class bound_function_helper : public bound_function_helper_base { public: void call() const { (*fp)(*this->arg1, *this->arg2); } typename strip::type* fp; }; template class bound_function_helper : public bound_function_helper_base { 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 class bound_function_helper : public bound_function_helper_base { public: void call() const { (*fp)(*this->arg1, *this->arg2, *this->arg3); } typename strip::type* fp; }; template class bound_function_helper : public bound_function_helper_base { 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 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 void safe_clone(stack_based_memory_block& 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 > 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 void set ( F& function_object ) { COMPILE_TIME_ASSERT(is_function::value == false); COMPILE_TIME_ASSERT(is_pointer_type::value == false); using namespace bfp1_helpers; destroy_bf_memory(); typedef bound_function_helper_T > bf_helper_type; bf_helper_type temp; temp.fp = &function_object; temp.safe_clone(bf_memory); } template void set ( F& function_object, A1& arg1 ) { COMPILE_TIME_ASSERT(is_function::value == false); COMPILE_TIME_ASSERT(is_pointer_type::value == false); using namespace bfp1_helpers; destroy_bf_memory(); typedef bound_function_helper_T > bf_helper_type; bf_helper_type temp; temp.arg1 = &arg1; temp.fp = &function_object; temp.safe_clone(bf_memory); } template void set ( F& function_object, A1& arg1, A2& arg2 ) { COMPILE_TIME_ASSERT(is_function::value == false); COMPILE_TIME_ASSERT(is_pointer_type::value == false); using namespace bfp1_helpers; destroy_bf_memory(); typedef bound_function_helper_T > bf_helper_type; bf_helper_type temp; temp.arg1 = &arg1; temp.arg2 = &arg2; temp.fp = &function_object; temp.safe_clone(bf_memory); } template void set ( F& function_object, A1& arg1, A2& arg2, A3& arg3 ) { COMPILE_TIME_ASSERT(is_function::value == false); COMPILE_TIME_ASSERT(is_pointer_type::value == false); using namespace bfp1_helpers; destroy_bf_memory(); typedef bound_function_helper_T > 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 void set ( F& function_object, A1& arg1, A2& arg2, A3& arg3, A4& arg4 ) { COMPILE_TIME_ASSERT(is_function::value == false); COMPILE_TIME_ASSERT(is_pointer_type::value == false); using namespace bfp1_helpers; destroy_bf_memory(); typedef bound_function_helper_T > 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 void set ( T& object, void (T::*funct)() ) { using namespace bfp1_helpers; destroy_bf_memory(); typedef bound_function_helper_T > bf_helper_type; bf_helper_type temp; temp.mfp.set(object,funct); temp.safe_clone(bf_memory); } template void set ( const T& object, void (T::*funct)()const ) { using namespace bfp1_helpers; destroy_bf_memory(); typedef bound_function_helper_T > bf_helper_type; bf_helper_type temp; temp.mfp.set(object,funct); temp.safe_clone(bf_memory); } // ------------------------------------------- template void set ( T& object, void (T::*funct)(T1), A1& arg1 ) { using namespace bfp1_helpers; destroy_bf_memory(); typedef bound_function_helper_T > bf_helper_type; bf_helper_type temp; temp.arg1 = &arg1; temp.mfp.set(object,funct); temp.safe_clone(bf_memory); } template void set ( const T& object, void (T::*funct)(T1)const, A1& arg1 ) { using namespace bfp1_helpers; destroy_bf_memory(); typedef bound_function_helper_T > bf_helper_type; bf_helper_type temp; temp.arg1 = &arg1; temp.mfp.set(object,funct); temp.safe_clone(bf_memory); } // ---------------- template 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 > bf_helper_type; bf_helper_type temp; temp.arg1 = &arg1; temp.arg2 = &arg2; temp.mfp.set(object,funct); temp.safe_clone(bf_memory); } template 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 > bf_helper_type; bf_helper_type temp; temp.arg1 = &arg1; temp.arg2 = &arg2; temp.mfp.set(object,funct); temp.safe_clone(bf_memory); } // ---------------- template 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 > 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 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 > 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 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 > 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 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 > 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 > bf_helper_type; bf_helper_type temp; temp.fp = funct; temp.safe_clone(bf_memory); } template void set ( void (*funct)(T1), A1& arg1 ) { using namespace bfp1_helpers; destroy_bf_memory(); typedef bound_function_helper_T > bf_helper_type; bf_helper_type temp; temp.arg1 = &arg1; temp.fp = funct; temp.safe_clone(bf_memory); } template void set ( void (*funct)(T1, T2), A1& arg1, A2& arg2 ) { using namespace bfp1_helpers; destroy_bf_memory(); typedef bound_function_helper_T > bf_helper_type; bf_helper_type temp; temp.arg1 = &arg1; temp.arg2 = &arg2; temp.fp = funct; temp.safe_clone(bf_memory); } template 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 > 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 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 > 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 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(bf_memory.get()); } const bfp1_helpers::bound_function_helper_base_base* bf () const { return static_cast(bf_memory.get()); } }; // ---------------------------------------------------------------------------------------- inline void swap ( bound_function_pointer& a, bound_function_pointer& b ) { a.swap(b); } // ---------------------------------------------------------------------------------------- } #endif // DLIB_BOUND_FUNCTION_POINTER_KERNEl_1_