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