1 // Copyright (C) 2005 Davis E. King (davis@dlib.net) 2 // License: Boost Software License See LICENSE.txt for the full license. 3 #ifndef DLIB_MEMBER_FUNCTION_POINTER_KERNEl_1_ 4 #define DLIB_MEMBER_FUNCTION_POINTER_KERNEl_1_ 5 6 #include "../algs.h" 7 #include "member_function_pointer_kernel_abstract.h" 8 #include "../enable_if.h" 9 #include <new> 10 11 namespace dlib 12 { 13 14 // ---------------------------------------------------------------------------------------- 15 16 template < 17 typename PARAM1 = void, 18 typename PARAM2 = void, 19 typename PARAM3 = void, 20 typename PARAM4 = void 21 > 22 class member_function_pointer; 23 24 // ---------------------------------------------------------------------------------------- 25 26 #define DLIB_MFP_SC DLIB_ASSERT(cb != 0, \ 27 "\tvoid member_function_pointer::set" \ 28 << "\n\tthe member function pointer can't be null" \ 29 << "\n\tthis: " << this ); 30 31 32 #define DLIB_MFP_OC DLIB_ASSERT(this->is_set() == true , \ 33 "\tvoid member_function_pointer::operator()" \ 34 << "\n\tYou must call set() before you can use this function" \ 35 << "\n\tthis: " << this); 36 37 // ---------------------------------------------------------------------------------------- 38 39 template <unsigned long num_args> 40 class mfp_kernel_1_base_class 41 { 42 /* 43 All member function pointer classes inherit from this class. This 44 is where most of the things in a member function pointer are defined. 45 46 The reason for the num_args template argument to this class is to prevent 47 any sort of implicit casting between derived member function pointer classes 48 that take different numbers of arguments. 49 */ 50 protected: 51 enum mfp_type { mfp_nonconst, mfp_const, mfp_null}; 52 53 class mp_base_base 54 { 55 public: mp_base_base(void * ptr,mfp_type type_)56 mp_base_base(void* ptr, mfp_type type_) : o(ptr),type(type_) {} ~mp_base_base()57 virtual ~mp_base_base(){} 58 virtual void clone(void* ptr) const = 0; 59 virtual bool is_same (const mp_base_base* item) const = 0; is_set()60 bool is_set () const { return o!=0; } 61 62 void* const o; 63 const mfp_type type; 64 }; 65 66 template <typename T> 67 class mp_null : public mp_base_base 68 { 69 public: 70 typedef void (T::*mfp_pointer_type)() ; 71 mp_null(void *,mfp_pointer_type)72 mp_null (void* , mfp_pointer_type ) : mp_base_base(0,mfp_null), callback(0) {} mp_null()73 mp_null () : mp_base_base(0,mfp_null), callback(0) {} 74 75 const mfp_pointer_type callback; 76 }; 77 78 template <typename mp_impl> 79 class mp_impl_T : public mp_impl 80 { 81 /* 82 This class supplies the implementations clone() and is_same() for any 83 classes that inherit from mp_base_base. It does this in a very 84 roundabout way... 85 */ 86 87 public: 88 typedef typename mp_impl::mfp_pointer_type mfp_pointer_type; 89 mp_impl_T()90 mp_impl_T() : mp_impl(0,0) {} mp_impl_T(void * ptr,mfp_pointer_type cb)91 mp_impl_T(void* ptr, mfp_pointer_type cb) : mp_impl(ptr,cb) {} 92 93 template <unsigned long mem_size> safe_clone(stack_based_memory_block<mem_size> & buf)94 void safe_clone(stack_based_memory_block<mem_size>& buf) 95 { 96 // This is here just to validate the assumption that our block of memory we have made 97 // in mp_memory is the right size to store the data for this object. If you 98 // get a compiler error on this line then email me :) 99 COMPILE_TIME_ASSERT(sizeof(mp_impl_T) <= mem_size); 100 clone(buf.get()); 101 } 102 clone(void * ptr)103 void clone (void* ptr) const { new(ptr) mp_impl_T(this->o,this->callback); } is_same(const mp_base_base * item)104 bool is_same (const mp_base_base* item) const 105 { 106 if (item->o == 0 && this->o == 0) 107 { 108 return true; 109 } 110 else if (item->o == this->o && this->type == item->type) 111 { 112 const mp_impl* i = reinterpret_cast<const mp_impl*>(item); 113 return (i->callback == this->callback); 114 } 115 return false; 116 } 117 }; 118 119 // MSVC with the /vms option, we get C2287 since the dummy class requires virtual 120 // inheritance. Adding the __virtual_inheritance specifier explicitly fixes the issue, 121 // but then Clang-CL no longer accepts it. 122 #if defined(_MSC_VER) && !defined(__clang__) 123 #define DLIB_MSVC_INHERITANCE_VIRTUAL __virtual_inheritance 124 #else 125 #define DLIB_MSVC_INHERITANCE_VIRTUAL 126 #endif 127 ~dummy_basedummy_base128 struct dummy_base { virtual void nonnull() {}; virtual ~dummy_base(){}; int a; }; nonnulldummy129 struct DLIB_MSVC_INHERITANCE_VIRTUAL dummy : virtual public dummy_base{ void nonnull() {}; }; 130 131 #undef DLIB_MSVC_INHERITANCE_VIRTUAL 132 133 typedef mp_impl_T<mp_null<dummy> > mp_null_impl; 134 public: 135 mfp_kernel_1_base_class(const mfp_kernel_1_base_class & item)136 mfp_kernel_1_base_class ( 137 const mfp_kernel_1_base_class& item 138 ) { item.mp()->clone(mp_memory.get()); } 139 mfp_kernel_1_base_class()140 mfp_kernel_1_base_class ( 141 ) { mp_null_impl().safe_clone(mp_memory); } 142 143 bool operator == ( 144 const mfp_kernel_1_base_class& item 145 ) const { return mp()->is_same(item.mp()); } 146 147 bool operator != ( 148 const mfp_kernel_1_base_class& item 149 ) const { return !(*this == item); } 150 151 mfp_kernel_1_base_class& operator= ( 152 const mfp_kernel_1_base_class& item 153 ) { mfp_kernel_1_base_class(item).swap(*this); return *this; } 154 ~mfp_kernel_1_base_class()155 ~mfp_kernel_1_base_class ( 156 ) { destroy_mp_memory(); } 157 clear()158 void clear( 159 ) { mfp_kernel_1_base_class().swap(*this); } 160 is_set()161 bool is_set ( 162 ) const { return mp()->is_set(); } 163 164 private: 165 typedef void (dummy::*safe_bool)(); 166 167 public: safe_bool()168 operator safe_bool () const { return is_set() ? &dummy::nonnull : 0; } 169 bool operator!() const { return !is_set(); } 170 swap(mfp_kernel_1_base_class & item)171 void swap ( 172 mfp_kernel_1_base_class& item 173 ) 174 { 175 // make a temp copy of item 176 mfp_kernel_1_base_class temp(item); 177 178 // destory the stuff in item 179 item.destroy_mp_memory(); 180 // copy *this into item 181 mp()->clone(item.mp_memory.get()); 182 183 // destory the stuff in this 184 destroy_mp_memory(); 185 // copy temp into *this 186 temp.mp()->clone(mp_memory.get()); 187 } 188 189 protected: 190 191 // The reason for adding 1 here is because visual studio 2003 will sometimes 192 // try to compile this code with sizeof(mp_null_impl) == 0 (which is a bug in visual studio). 193 // Fortunately, no actual real instances of this template seem to end up with that screwed up 194 // value so everything works fine if we just add 1 so that this degenerate case doesn't cause 195 // trouble. Note that we know it all works fine because safe_clone() checks the size of this 196 // memory block whenever the member function pointer is used. 197 stack_based_memory_block<sizeof(mp_null_impl)+1> mp_memory; 198 destroy_mp_memory()199 void destroy_mp_memory ( 200 ) 201 { 202 // Honestly this probably doesn't even do anything but I'm putting 203 // it here just for good measure. 204 mp()->~mp_base_base(); 205 } 206 mp()207 mp_base_base* mp () { return static_cast<mp_base_base*>(mp_memory.get()); } mp()208 const mp_base_base* mp () const { return static_cast<const mp_base_base*>(mp_memory.get()); } 209 210 }; 211 212 // ---------------------------------------------------------------------------------------- 213 214 template <> 215 class member_function_pointer<void,void,void,void> : public mfp_kernel_1_base_class<0> 216 { 217 class mp_base : public mp_base_base { 218 public: mp_base(void * ptr,mfp_type type_)219 mp_base(void* ptr, mfp_type type_) : mp_base_base(ptr,type_) {} 220 virtual void call() const = 0; 221 }; 222 223 template <typename T> 224 class mp_impl : public mp_base { 225 public: 226 typedef void (T::*mfp_pointer_type)() ; call()227 void call () const { (static_cast<T*>(this->o)->*callback)(); } 228 mp_impl(void * object,mfp_pointer_type cb)229 mp_impl ( void* object, mfp_pointer_type cb) : mp_base(object, mfp_nonconst), callback(cb) {} 230 const mfp_pointer_type callback; 231 }; 232 233 template <typename T> 234 class mp_impl_const : public mp_base { 235 public: 236 typedef void ((T::*mfp_pointer_type)()const); call()237 void call () const { (static_cast<const T*>(this->o)->*callback)(); } 238 mp_impl_const(void * object,mfp_pointer_type cb)239 mp_impl_const ( void* object, mfp_pointer_type cb) : mp_base(object,mfp_const), callback(cb) {} 240 const mfp_pointer_type callback; 241 }; 242 243 public: 244 typedef void param1_type; 245 typedef void param2_type; 246 typedef void param3_type; 247 typedef void param4_type; 248 249 // These two typedefs are here for backwards compatibility with previous versions 250 // of dlib. 251 typedef member_function_pointer kernel_1a; 252 typedef member_function_pointer kernel_1a_c; 253 254 operator()255 void operator() () const { DLIB_MFP_OC; static_cast<const mp_base*>(mp_memory.get())->call(); } 256 257 // the reason for putting disable_if on this function is that it avoids an overload 258 // resolution bug in visual studio. 259 template <typename T> typename disable_if<is_const_type<T>,void>::type set(T & object,typename mp_impl<T>::mfp_pointer_type cb)260 set(T& object, typename mp_impl<T>::mfp_pointer_type cb) 261 { DLIB_MFP_SC; destroy_mp_memory(); mp_impl_T<mp_impl<T> >(&object,cb).safe_clone(mp_memory); } 262 set(const T & object,typename mp_impl_const<T>::mfp_pointer_type cb)263 template <typename T> void set(const T& object, typename mp_impl_const<T>::mfp_pointer_type cb) 264 { DLIB_MFP_SC; destroy_mp_memory(); mp_impl_T<mp_impl_const<T> >((void*)&object,cb).safe_clone(mp_memory); } 265 266 }; 267 268 // ---------------------------------------------------------------------------------------- 269 270 template < 271 typename PARAM1 272 > 273 class member_function_pointer<PARAM1,void,void,void> : public mfp_kernel_1_base_class<1> 274 { 275 class mp_base : public mp_base_base { 276 public: mp_base(void * ptr,mfp_type type_)277 mp_base(void* ptr, mfp_type type_) : mp_base_base(ptr,type_) {} 278 virtual void call(PARAM1) const = 0; 279 }; 280 281 template <typename T> 282 class mp_impl : public mp_base { 283 public: 284 typedef void (T::*mfp_pointer_type)(PARAM1) ; call(PARAM1 p1)285 void call (PARAM1 p1) const { (static_cast<T*>(this->o)->*callback)(p1); } 286 mp_impl(void * object,mfp_pointer_type cb)287 mp_impl ( void* object, mfp_pointer_type cb) : mp_base(object, mfp_nonconst), callback(cb) {} 288 const mfp_pointer_type callback; 289 }; 290 291 template <typename T> 292 class mp_impl_const : public mp_base { 293 public: 294 typedef void ((T::*mfp_pointer_type)(PARAM1)const); call(PARAM1 p1)295 void call (PARAM1 p1) const { (static_cast<const T*>(this->o)->*callback)(p1); } 296 mp_impl_const(void * object,mfp_pointer_type cb)297 mp_impl_const ( void* object, mfp_pointer_type cb) : mp_base(object,mfp_const), callback(cb) {} 298 const mfp_pointer_type callback; 299 }; 300 301 public: 302 typedef PARAM1 param1_type; 303 typedef void param2_type; 304 typedef void param3_type; 305 typedef void param4_type; 306 307 // These two typedefs are here for backwards compatibility with previous versions 308 // of dlib. 309 typedef member_function_pointer kernel_1a; 310 typedef member_function_pointer kernel_1a_c; 311 312 operator()313 void operator() (PARAM1 p1) const { DLIB_MFP_OC; static_cast<const mp_base*>(mp_memory.get())->call(p1); } 314 315 // the reason for putting disable_if on this function is that it avoids an overload 316 // resolution bug in visual studio. 317 template <typename T> typename disable_if<is_const_type<T>,void>::type set(T & object,typename mp_impl<T>::mfp_pointer_type cb)318 set(T& object, typename mp_impl<T>::mfp_pointer_type cb) 319 { DLIB_MFP_SC; destroy_mp_memory(); mp_impl_T<mp_impl<T> >(&object,cb).safe_clone(mp_memory); } 320 set(const T & object,typename mp_impl_const<T>::mfp_pointer_type cb)321 template <typename T> void set(const T& object, typename mp_impl_const<T>::mfp_pointer_type cb) 322 { DLIB_MFP_SC; destroy_mp_memory(); mp_impl_T<mp_impl_const<T> >((void*)&object,cb).safe_clone(mp_memory); } 323 324 }; 325 326 // ---------------------------------------------------------------------------------------- 327 328 template < 329 typename PARAM1, 330 typename PARAM2 331 > 332 class member_function_pointer<PARAM1,PARAM2,void,void> : public mfp_kernel_1_base_class<2> 333 { 334 class mp_base : public mp_base_base { 335 public: mp_base(void * ptr,mfp_type type_)336 mp_base(void* ptr, mfp_type type_) : mp_base_base(ptr,type_) {} 337 virtual void call(PARAM1,PARAM2) const = 0; 338 }; 339 340 template <typename T> 341 class mp_impl : public mp_base { 342 public: 343 typedef void (T::*mfp_pointer_type)(PARAM1,PARAM2) ; call(PARAM1 p1,PARAM2 p2)344 void call (PARAM1 p1, PARAM2 p2) const { (static_cast<T*>(this->o)->*callback)(p1,p2); } 345 mp_impl(void * object,mfp_pointer_type cb)346 mp_impl ( void* object, mfp_pointer_type cb) : mp_base(object, mfp_nonconst), callback(cb) {} 347 const mfp_pointer_type callback; 348 }; 349 350 template <typename T> 351 class mp_impl_const : public mp_base { 352 public: 353 typedef void ((T::*mfp_pointer_type)(PARAM1,PARAM2)const); call(PARAM1 p1,PARAM2 p2)354 void call (PARAM1 p1, PARAM2 p2) const { (static_cast<const T*>(this->o)->*callback)(p1,p2); } 355 mp_impl_const(void * object,mfp_pointer_type cb)356 mp_impl_const ( void* object, mfp_pointer_type cb) : mp_base(object,mfp_const), callback(cb) {} 357 const mfp_pointer_type callback; 358 }; 359 360 public: 361 typedef PARAM1 param1_type; 362 typedef PARAM2 param2_type; 363 typedef void param3_type; 364 typedef void param4_type; 365 366 // These two typedefs are here for backwards compatibility with previous versions 367 // of dlib. 368 typedef member_function_pointer kernel_1a; 369 typedef member_function_pointer kernel_1a_c; 370 operator()371 void operator() (PARAM1 p1, PARAM2 p2) const { DLIB_MFP_OC; static_cast<const mp_base*>(mp_memory.get())->call(p1,p2); } 372 373 // the reason for putting disable_if on this function is that it avoids an overload 374 // resolution bug in visual studio. 375 template <typename T> typename disable_if<is_const_type<T>,void>::type set(T & object,typename mp_impl<T>::mfp_pointer_type cb)376 set(T& object, typename mp_impl<T>::mfp_pointer_type cb) 377 { DLIB_MFP_SC; destroy_mp_memory(); mp_impl_T<mp_impl<T> >(&object,cb).safe_clone(mp_memory); } 378 set(const T & object,typename mp_impl_const<T>::mfp_pointer_type cb)379 template <typename T> void set(const T& object, typename mp_impl_const<T>::mfp_pointer_type cb) 380 { DLIB_MFP_SC; destroy_mp_memory(); mp_impl_T<mp_impl_const<T> >((void*)&object,cb).safe_clone(mp_memory); } 381 382 }; 383 384 // ---------------------------------------------------------------------------------------- 385 386 template < 387 typename PARAM1, 388 typename PARAM2, 389 typename PARAM3 390 > 391 class member_function_pointer<PARAM1,PARAM2,PARAM3,void> : public mfp_kernel_1_base_class<3> 392 { 393 class mp_base : public mp_base_base { 394 public: mp_base(void * ptr,mfp_type type_)395 mp_base(void* ptr, mfp_type type_) : mp_base_base(ptr,type_) {} 396 virtual void call(PARAM1,PARAM2,PARAM3) const = 0; 397 }; 398 399 template <typename T> 400 class mp_impl : public mp_base { 401 public: 402 typedef void (T::*mfp_pointer_type)(PARAM1,PARAM2,PARAM3) ; call(PARAM1 p1,PARAM2 p2,PARAM3 p3)403 void call (PARAM1 p1, PARAM2 p2, PARAM3 p3) const { (static_cast<T*>(this->o)->*callback)(p1,p2,p3); } 404 mp_impl(void * object,mfp_pointer_type cb)405 mp_impl ( void* object, mfp_pointer_type cb) : mp_base(object, mfp_nonconst), callback(cb) {} 406 const mfp_pointer_type callback; 407 }; 408 409 template <typename T> 410 class mp_impl_const : public mp_base { 411 public: 412 typedef void ((T::*mfp_pointer_type)(PARAM1,PARAM2,PARAM3)const); call(PARAM1 p1,PARAM2 p2,PARAM3 p3)413 void call (PARAM1 p1, PARAM2 p2, PARAM3 p3) const { (static_cast<const T*>(this->o)->*callback)(p1,p2,p3); } 414 mp_impl_const(void * object,mfp_pointer_type cb)415 mp_impl_const ( void* object, mfp_pointer_type cb) : mp_base(object,mfp_const), callback(cb) {} 416 const mfp_pointer_type callback; 417 }; 418 419 public: 420 typedef PARAM1 param1_type; 421 typedef PARAM2 param2_type; 422 typedef PARAM3 param3_type; 423 typedef void param4_type; 424 425 // These two typedefs are here for backwards compatibility with previous versions 426 // of dlib. 427 typedef member_function_pointer kernel_1a; 428 typedef member_function_pointer kernel_1a_c; 429 operator()430 void operator() (PARAM1 p1, PARAM2 p2, PARAM3 p3) const { DLIB_MFP_OC; static_cast<const mp_base*>(mp_memory.get())->call(p1,p2,p3); } 431 432 // the reason for putting disable_if on this function is that it avoids an overload 433 // resolution bug in visual studio. 434 template <typename T> typename disable_if<is_const_type<T>,void>::type set(T & object,typename mp_impl<T>::mfp_pointer_type cb)435 set(T& object, typename mp_impl<T>::mfp_pointer_type cb) 436 { DLIB_MFP_SC; destroy_mp_memory(); mp_impl_T<mp_impl<T> >(&object,cb).safe_clone(mp_memory); } 437 set(const T & object,typename mp_impl_const<T>::mfp_pointer_type cb)438 template <typename T> void set(const T& object, typename mp_impl_const<T>::mfp_pointer_type cb) 439 { DLIB_MFP_SC; destroy_mp_memory(); mp_impl_T<mp_impl_const<T> >((void*)&object,cb).safe_clone(mp_memory); } 440 441 }; 442 443 // ---------------------------------------------------------------------------------------- 444 445 template < 446 typename PARAM1, 447 typename PARAM2, 448 typename PARAM3, 449 typename PARAM4 450 > 451 class member_function_pointer : public mfp_kernel_1_base_class<4> 452 { 453 class mp_base : public mp_base_base { 454 public: mp_base(void * ptr,mfp_type type_)455 mp_base(void* ptr, mfp_type type_) : mp_base_base(ptr,type_) {} 456 virtual void call(PARAM1,PARAM2,PARAM3,PARAM4) const = 0; 457 }; 458 459 template <typename T> 460 class mp_impl : public mp_base { 461 public: 462 typedef void (T::*mfp_pointer_type)(PARAM1,PARAM2,PARAM3, PARAM4) ; call(PARAM1 p1,PARAM2 p2,PARAM3 p3,PARAM4 p4)463 void call (PARAM1 p1, PARAM2 p2, PARAM3 p3, PARAM4 p4) const { (static_cast<T*>(this->o)->*callback)(p1,p2,p3,p4); } 464 mp_impl(void * object,mfp_pointer_type cb)465 mp_impl ( void* object, mfp_pointer_type cb) : mp_base(object, mfp_nonconst), callback(cb) {} 466 const mfp_pointer_type callback; 467 }; 468 469 template <typename T> 470 class mp_impl_const : public mp_base { 471 public: 472 typedef void ((T::*mfp_pointer_type)(PARAM1,PARAM2,PARAM3,PARAM4)const); call(PARAM1 p1,PARAM2 p2,PARAM3 p3,PARAM4 p4)473 void call (PARAM1 p1, PARAM2 p2, PARAM3 p3, PARAM4 p4) const { (static_cast<const T*>(this->o)->*callback)(p1,p2,p3,p4); } 474 mp_impl_const(void * object,mfp_pointer_type cb)475 mp_impl_const ( void* object, mfp_pointer_type cb) : mp_base(object,mfp_const), callback(cb) {} 476 const mfp_pointer_type callback; 477 }; 478 479 public: 480 typedef PARAM1 param1_type; 481 typedef PARAM2 param2_type; 482 typedef PARAM3 param3_type; 483 typedef PARAM4 param4_type; 484 485 // These two typedefs are here for backwards compatibility with previous versions 486 // of dlib. 487 typedef member_function_pointer kernel_1a; 488 typedef member_function_pointer kernel_1a_c; 489 operator()490 void operator() (PARAM1 p1, PARAM2 p2, PARAM3 p3, PARAM4 p4) const 491 { DLIB_MFP_OC; static_cast<const mp_base*>(mp_memory.get())->call(p1,p2,p3,p4); } 492 493 // the reason for putting disable_if on this function is that it avoids an overload 494 // resolution bug in visual studio. 495 template <typename T> typename disable_if<is_const_type<T>,void>::type set(T & object,typename mp_impl<T>::mfp_pointer_type cb)496 set(T& object, typename mp_impl<T>::mfp_pointer_type cb) 497 { DLIB_MFP_SC; destroy_mp_memory(); mp_impl_T<mp_impl<T> >(&object,cb).safe_clone(mp_memory); } 498 set(const T & object,typename mp_impl_const<T>::mfp_pointer_type cb)499 template <typename T> void set(const T& object, typename mp_impl_const<T>::mfp_pointer_type cb) 500 { DLIB_MFP_SC; destroy_mp_memory(); mp_impl_T<mp_impl_const<T> >((void*)&object,cb).safe_clone(mp_memory); } 501 502 }; 503 504 // ---------------------------------------------------------------------------------------- 505 506 } 507 508 #endif // DLIB_MEMBER_FUNCTION_POINTER_KERNEl_1_ 509 510