1 // Boost.Function library
2 
3 //  Copyright Douglas Gregor 2001-2006
4 //  Copyright Emil Dotchevski 2007
5 //  Use, modification and distribution is subject to the Boost Software License, Version 1.0.
6 //  (See accompanying file LICENSE_1_0.txt or copy at
7 //  http://www.boost.org/LICENSE_1_0.txt)
8 
9 // For more information, see http://www.boost.org
10 
11 #ifndef BOOST_FUNCTION_BASE_HEADER
12 #define BOOST_FUNCTION_BASE_HEADER
13 
14 #include <stdexcept>
15 #include <string>
16 #include <memory>
17 #include <new>
18 #include <boost/config.hpp>
19 #include <boost/assert.hpp>
20 #include <boost/integer.hpp>
21 #include <boost/type_index.hpp>
22 #include <boost/type_traits/has_trivial_copy.hpp>
23 #include <boost/type_traits/has_trivial_destructor.hpp>
24 #include <boost/type_traits/is_const.hpp>
25 #include <boost/type_traits/is_integral.hpp>
26 #include <boost/type_traits/is_volatile.hpp>
27 #include <boost/type_traits/composite_traits.hpp>
28 #include <boost/ref.hpp>
29 #include <boost/mpl/if.hpp>
30 #include <boost/detail/workaround.hpp>
31 #include <boost/type_traits/alignment_of.hpp>
32 #ifndef BOOST_NO_SFINAE
33 #  include "boost/utility/enable_if.hpp"
34 #else
35 #  include "boost/mpl/bool.hpp"
36 #endif
37 #include <boost/function_equal.hpp>
38 #include <boost/function/function_fwd.hpp>
39 
40 #if defined(BOOST_MSVC)
41 #   pragma warning( push )
42 #   pragma warning( disable : 4793 ) // complaint about native code generation
43 #   pragma warning( disable : 4127 ) // "conditional expression is constant"
44 #endif
45 
46 #if defined(__ICL) && __ICL <= 600 || defined(__MWERKS__) && __MWERKS__ < 0x2406 && !defined(BOOST_STRICT_CONFIG)
47 #  define BOOST_FUNCTION_TARGET_FIX(x) x
48 #else
49 #  define BOOST_FUNCTION_TARGET_FIX(x)
50 #endif // __ICL etc
51 
52 #  define BOOST_FUNCTION_ENABLE_IF_NOT_INTEGRAL(Functor,Type)              \
53       typename ::boost::enable_if_c<          \
54                            !(::boost::is_integral<Functor>::value), \
55                            Type>::type
56 
57 namespace boost {
58   namespace detail {
59     namespace function {
60       class X;
61 
62       /**
63        * A buffer used to store small function objects in
64        * boost::function. It is a union containing function pointers,
65        * object pointers, and a structure that resembles a bound
66        * member function pointer.
67        */
68       union function_buffer_members
69       {
70         // For pointers to function objects
71         typedef void* obj_ptr_t;
72         mutable obj_ptr_t obj_ptr;
73 
74         // For pointers to std::type_info objects
75         struct type_t {
76           // (get_functor_type_tag, check_functor_type_tag).
77           const boost::typeindex::type_info* type;
78 
79           // Whether the type is const-qualified.
80           bool const_qualified;
81           // Whether the type is volatile-qualified.
82           bool volatile_qualified;
83         } type;
84 
85         // For function pointers of all kinds
86         typedef void (*func_ptr_t)();
87         mutable func_ptr_t func_ptr;
88 
89         // For bound member pointers
90         struct bound_memfunc_ptr_t {
91           void (X::*memfunc_ptr)(int);
92           void* obj_ptr;
93         } bound_memfunc_ptr;
94 
95         // For references to function objects. We explicitly keep
96         // track of the cv-qualifiers on the object referenced.
97         struct obj_ref_t {
98           mutable void* obj_ptr;
99           bool is_const_qualified;
100           bool is_volatile_qualified;
101         } obj_ref;
102       };
103 
104       union function_buffer
105       {
106         // Type-specific union members
107         mutable function_buffer_members members;
108 
109         // To relax aliasing constraints
110         mutable char data[sizeof(function_buffer_members)];
111       };
112 
113       /**
114        * The unusable class is a placeholder for unused function arguments
115        * It is also completely unusable except that it constructable from
116        * anything. This helps compilers without partial specialization to
117        * handle Boost.Function objects returning void.
118        */
119       struct unusable
120       {
unusableboost::detail::function::unusable121         unusable() {}
unusableboost::detail::function::unusable122         template<typename T> unusable(const T&) {}
123       };
124 
125       /* Determine the return type. This supports compilers that do not support
126        * void returns or partial specialization by silently changing the return
127        * type to "unusable".
128        */
129       template<typename T> struct function_return_type { typedef T type; };
130 
131       template<>
132       struct function_return_type<void>
133       {
134         typedef unusable type;
135       };
136 
137       // The operation type to perform on the given functor/function pointer
138       enum functor_manager_operation_type {
139         clone_functor_tag,
140         move_functor_tag,
141         destroy_functor_tag,
142         check_functor_type_tag,
143         get_functor_type_tag
144       };
145 
146       // Tags used to decide between different types of functions
147       struct function_ptr_tag {};
148       struct function_obj_tag {};
149       struct member_ptr_tag {};
150       struct function_obj_ref_tag {};
151 
152       template<typename F>
153       class get_function_tag
154       {
155         typedef typename mpl::if_c<(is_pointer<F>::value),
156                                    function_ptr_tag,
157                                    function_obj_tag>::type ptr_or_obj_tag;
158 
159         typedef typename mpl::if_c<(is_member_pointer<F>::value),
160                                    member_ptr_tag,
161                                    ptr_or_obj_tag>::type ptr_or_obj_or_mem_tag;
162 
163         typedef typename mpl::if_c<(is_reference_wrapper<F>::value),
164                                    function_obj_ref_tag,
165                                    ptr_or_obj_or_mem_tag>::type or_ref_tag;
166 
167       public:
168         typedef or_ref_tag type;
169       };
170 
171       // The trivial manager does nothing but return the same pointer (if we
172       // are cloning) or return the null pointer (if we are deleting).
173       template<typename F>
174       struct reference_manager
175       {
176         static inline void
manageboost::detail::function::reference_manager177         manage(const function_buffer& in_buffer, function_buffer& out_buffer,
178                functor_manager_operation_type op)
179         {
180           switch (op) {
181           case clone_functor_tag:
182             out_buffer.members.obj_ref = in_buffer.members.obj_ref;
183             return;
184 
185           case move_functor_tag:
186             out_buffer.members.obj_ref = in_buffer.members.obj_ref;
187             in_buffer.members.obj_ref.obj_ptr = 0;
188             return;
189 
190           case destroy_functor_tag:
191             out_buffer.members.obj_ref.obj_ptr = 0;
192             return;
193 
194           case check_functor_type_tag:
195             {
196               // Check whether we have the same type. We can add
197               // cv-qualifiers, but we can't take them away.
198               if (*out_buffer.members.type.type == boost::typeindex::type_id<F>()
199                   && (!in_buffer.members.obj_ref.is_const_qualified
200                       || out_buffer.members.type.const_qualified)
201                   && (!in_buffer.members.obj_ref.is_volatile_qualified
202                       || out_buffer.members.type.volatile_qualified))
203                 out_buffer.members.obj_ptr = in_buffer.members.obj_ref.obj_ptr;
204               else
205                 out_buffer.members.obj_ptr = 0;
206             }
207             return;
208 
209           case get_functor_type_tag:
210             out_buffer.members.type.type = &boost::typeindex::type_id<F>().type_info();
211             out_buffer.members.type.const_qualified = in_buffer.members.obj_ref.is_const_qualified;
212             out_buffer.members.type.volatile_qualified = in_buffer.members.obj_ref.is_volatile_qualified;
213             return;
214           }
215         }
216       };
217 
218       /**
219        * Determine if boost::function can use the small-object
220        * optimization with the function object type F.
221        */
222       template<typename F>
223       struct function_allows_small_object_optimization
224       {
225         BOOST_STATIC_CONSTANT
226           (bool,
227            value = ((sizeof(F) <= sizeof(function_buffer) &&
228                      (alignment_of<function_buffer>::value
229                       % alignment_of<F>::value == 0))));
230       };
231 
232       template <typename F,typename A>
233       struct functor_wrapper: public F, public A
234       {
functor_wrapperboost::detail::function::functor_wrapper235         functor_wrapper( F f, A a ):
236           F(f),
237           A(a)
238         {
239         }
240 
functor_wrapperboost::detail::function::functor_wrapper241         functor_wrapper(const functor_wrapper& f) :
242           F(static_cast<const F&>(f)),
243           A(static_cast<const A&>(f))
244         {
245         }
246       };
247 
248       /**
249        * The functor_manager class contains a static function "manage" which
250        * can clone or destroy the given function/function object pointer.
251        */
252       template<typename Functor>
253       struct functor_manager_common
254       {
255         typedef Functor functor_type;
256 
257         // Function pointers
258         static inline void
manage_ptrboost::detail::function::functor_manager_common259         manage_ptr(const function_buffer& in_buffer, function_buffer& out_buffer,
260                 functor_manager_operation_type op)
261         {
262           if (op == clone_functor_tag)
263             out_buffer.members.func_ptr = in_buffer.members.func_ptr;
264           else if (op == move_functor_tag) {
265             out_buffer.members.func_ptr = in_buffer.members.func_ptr;
266             in_buffer.members.func_ptr = 0;
267           } else if (op == destroy_functor_tag)
268             out_buffer.members.func_ptr = 0;
269           else if (op == check_functor_type_tag) {
270             if (*out_buffer.members.type.type == boost::typeindex::type_id<Functor>())
271               out_buffer.members.obj_ptr = &in_buffer.members.func_ptr;
272             else
273               out_buffer.members.obj_ptr = 0;
274           } else /* op == get_functor_type_tag */ {
275             out_buffer.members.type.type = &boost::typeindex::type_id<Functor>().type_info();
276             out_buffer.members.type.const_qualified = false;
277             out_buffer.members.type.volatile_qualified = false;
278           }
279         }
280 
281         // Function objects that fit in the small-object buffer.
282         static inline void
manage_smallboost::detail::function::functor_manager_common283         manage_small(const function_buffer& in_buffer, function_buffer& out_buffer,
284                 functor_manager_operation_type op)
285         {
286           if (op == clone_functor_tag || op == move_functor_tag) {
287             const functor_type* in_functor =
288               reinterpret_cast<const functor_type*>(in_buffer.data);
289             new (reinterpret_cast<void*>(out_buffer.data)) functor_type(*in_functor);
290 
291             if (op == move_functor_tag) {
292               functor_type* f = reinterpret_cast<functor_type*>(in_buffer.data);
293               (void)f; // suppress warning about the value of f not being used (MSVC)
294               f->~Functor();
295             }
296           } else if (op == destroy_functor_tag) {
297             // Some compilers (Borland, vc6, ...) are unhappy with ~functor_type.
298              functor_type* f = reinterpret_cast<functor_type*>(out_buffer.data);
299              (void)f; // suppress warning about the value of f not being used (MSVC)
300              f->~Functor();
301           } else if (op == check_functor_type_tag) {
302              if (*out_buffer.members.type.type == boost::typeindex::type_id<Functor>())
303               out_buffer.members.obj_ptr = in_buffer.data;
304             else
305               out_buffer.members.obj_ptr = 0;
306           } else /* op == get_functor_type_tag */ {
307             out_buffer.members.type.type = &boost::typeindex::type_id<Functor>().type_info();
308             out_buffer.members.type.const_qualified = false;
309             out_buffer.members.type.volatile_qualified = false;
310           }
311         }
312       };
313 
314       template<typename Functor>
315       struct functor_manager
316       {
317       private:
318         typedef Functor functor_type;
319 
320         // Function pointers
321         static inline void
managerboost::detail::function::functor_manager322         manager(const function_buffer& in_buffer, function_buffer& out_buffer,
323                 functor_manager_operation_type op, function_ptr_tag)
324         {
325           functor_manager_common<Functor>::manage_ptr(in_buffer,out_buffer,op);
326         }
327 
328         // Function objects that fit in the small-object buffer.
329         static inline void
managerboost::detail::function::functor_manager330         manager(const function_buffer& in_buffer, function_buffer& out_buffer,
331                 functor_manager_operation_type op, mpl::true_)
332         {
333           functor_manager_common<Functor>::manage_small(in_buffer,out_buffer,op);
334         }
335 
336         // Function objects that require heap allocation
337         static inline void
managerboost::detail::function::functor_manager338         manager(const function_buffer& in_buffer, function_buffer& out_buffer,
339                 functor_manager_operation_type op, mpl::false_)
340         {
341           if (op == clone_functor_tag) {
342             // Clone the functor
343             // GCC 2.95.3 gets the CV qualifiers wrong here, so we
344             // can't do the static_cast that we should do.
345             // jewillco: Changing this to static_cast because GCC 2.95.3 is
346             // obsolete.
347             const functor_type* f =
348               static_cast<const functor_type*>(in_buffer.members.obj_ptr);
349             functor_type* new_f = new functor_type(*f);
350             out_buffer.members.obj_ptr = new_f;
351           } else if (op == move_functor_tag) {
352             out_buffer.members.obj_ptr = in_buffer.members.obj_ptr;
353             in_buffer.members.obj_ptr = 0;
354           } else if (op == destroy_functor_tag) {
355             /* Cast from the void pointer to the functor pointer type */
356             functor_type* f =
357               static_cast<functor_type*>(out_buffer.members.obj_ptr);
358             delete f;
359             out_buffer.members.obj_ptr = 0;
360           } else if (op == check_functor_type_tag) {
361             if (*out_buffer.members.type.type == boost::typeindex::type_id<Functor>())
362               out_buffer.members.obj_ptr = in_buffer.members.obj_ptr;
363             else
364               out_buffer.members.obj_ptr = 0;
365           } else /* op == get_functor_type_tag */ {
366             out_buffer.members.type.type = &boost::typeindex::type_id<Functor>().type_info();
367             out_buffer.members.type.const_qualified = false;
368             out_buffer.members.type.volatile_qualified = false;
369           }
370         }
371 
372         // For function objects, we determine whether the function
373         // object can use the small-object optimization buffer or
374         // whether we need to allocate it on the heap.
375         static inline void
managerboost::detail::function::functor_manager376         manager(const function_buffer& in_buffer, function_buffer& out_buffer,
377                 functor_manager_operation_type op, function_obj_tag)
378         {
379           manager(in_buffer, out_buffer, op,
380                   mpl::bool_<(function_allows_small_object_optimization<functor_type>::value)>());
381         }
382 
383         // For member pointers, we use the small-object optimization buffer.
384         static inline void
managerboost::detail::function::functor_manager385         manager(const function_buffer& in_buffer, function_buffer& out_buffer,
386                 functor_manager_operation_type op, member_ptr_tag)
387         {
388           manager(in_buffer, out_buffer, op, mpl::true_());
389         }
390 
391       public:
392         /* Dispatch to an appropriate manager based on whether we have a
393            function pointer or a function object pointer. */
394         static inline void
manageboost::detail::function::functor_manager395         manage(const function_buffer& in_buffer, function_buffer& out_buffer,
396                functor_manager_operation_type op)
397         {
398           typedef typename get_function_tag<functor_type>::type tag_type;
399           switch (op) {
400           case get_functor_type_tag:
401             out_buffer.members.type.type = &boost::typeindex::type_id<functor_type>().type_info();
402             out_buffer.members.type.const_qualified = false;
403             out_buffer.members.type.volatile_qualified = false;
404             return;
405 
406           default:
407             manager(in_buffer, out_buffer, op, tag_type());
408             return;
409           }
410         }
411       };
412 
413       template<typename Functor, typename Allocator>
414       struct functor_manager_a
415       {
416       private:
417         typedef Functor functor_type;
418 
419         // Function pointers
420         static inline void
managerboost::detail::function::functor_manager_a421         manager(const function_buffer& in_buffer, function_buffer& out_buffer,
422                 functor_manager_operation_type op, function_ptr_tag)
423         {
424           functor_manager_common<Functor>::manage_ptr(in_buffer,out_buffer,op);
425         }
426 
427         // Function objects that fit in the small-object buffer.
428         static inline void
managerboost::detail::function::functor_manager_a429         manager(const function_buffer& in_buffer, function_buffer& out_buffer,
430                 functor_manager_operation_type op, mpl::true_)
431         {
432           functor_manager_common<Functor>::manage_small(in_buffer,out_buffer,op);
433         }
434 
435         // Function objects that require heap allocation
436         static inline void
managerboost::detail::function::functor_manager_a437         manager(const function_buffer& in_buffer, function_buffer& out_buffer,
438                 functor_manager_operation_type op, mpl::false_)
439         {
440           typedef functor_wrapper<Functor,Allocator> functor_wrapper_type;
441           typedef typename Allocator::template rebind<functor_wrapper_type>::other
442             wrapper_allocator_type;
443           typedef typename wrapper_allocator_type::pointer wrapper_allocator_pointer_type;
444 
445           if (op == clone_functor_tag) {
446             // Clone the functor
447             // GCC 2.95.3 gets the CV qualifiers wrong here, so we
448             // can't do the static_cast that we should do.
449             const functor_wrapper_type* f =
450               static_cast<const functor_wrapper_type*>(in_buffer.members.obj_ptr);
451             wrapper_allocator_type wrapper_allocator(static_cast<Allocator const &>(*f));
452             wrapper_allocator_pointer_type copy = wrapper_allocator.allocate(1);
453             wrapper_allocator.construct(copy, *f);
454 
455             // Get back to the original pointer type
456             functor_wrapper_type* new_f = static_cast<functor_wrapper_type*>(copy);
457             out_buffer.members.obj_ptr = new_f;
458           } else if (op == move_functor_tag) {
459             out_buffer.members.obj_ptr = in_buffer.members.obj_ptr;
460             in_buffer.members.obj_ptr = 0;
461           } else if (op == destroy_functor_tag) {
462             /* Cast from the void pointer to the functor_wrapper_type */
463             functor_wrapper_type* victim =
464               static_cast<functor_wrapper_type*>(in_buffer.members.obj_ptr);
465             wrapper_allocator_type wrapper_allocator(static_cast<Allocator const &>(*victim));
466             wrapper_allocator.destroy(victim);
467             wrapper_allocator.deallocate(victim,1);
468             out_buffer.members.obj_ptr = 0;
469           } else if (op == check_functor_type_tag) {
470             if (*out_buffer.members.type.type == boost::typeindex::type_id<Functor>())
471               out_buffer.members.obj_ptr = in_buffer.members.obj_ptr;
472             else
473               out_buffer.members.obj_ptr = 0;
474           } else /* op == get_functor_type_tag */ {
475             out_buffer.members.type.type = &boost::typeindex::type_id<Functor>().type_info();
476             out_buffer.members.type.const_qualified = false;
477             out_buffer.members.type.volatile_qualified = false;
478           }
479         }
480 
481         // For function objects, we determine whether the function
482         // object can use the small-object optimization buffer or
483         // whether we need to allocate it on the heap.
484         static inline void
managerboost::detail::function::functor_manager_a485         manager(const function_buffer& in_buffer, function_buffer& out_buffer,
486                 functor_manager_operation_type op, function_obj_tag)
487         {
488           manager(in_buffer, out_buffer, op,
489                   mpl::bool_<(function_allows_small_object_optimization<functor_type>::value)>());
490         }
491 
492       public:
493         /* Dispatch to an appropriate manager based on whether we have a
494            function pointer or a function object pointer. */
495         static inline void
manageboost::detail::function::functor_manager_a496         manage(const function_buffer& in_buffer, function_buffer& out_buffer,
497                functor_manager_operation_type op)
498         {
499           typedef typename get_function_tag<functor_type>::type tag_type;
500           switch (op) {
501           case get_functor_type_tag:
502             out_buffer.members.type.type = &boost::typeindex::type_id<functor_type>().type_info();
503             out_buffer.members.type.const_qualified = false;
504             out_buffer.members.type.volatile_qualified = false;
505             return;
506 
507           default:
508             manager(in_buffer, out_buffer, op, tag_type());
509             return;
510           }
511         }
512       };
513 
514       // A type that is only used for comparisons against zero
515       struct useless_clear_type {};
516 
517 #ifdef BOOST_NO_SFINAE
518       // These routines perform comparisons between a Boost.Function
519       // object and an arbitrary function object (when the last
520       // parameter is mpl::bool_<false>) or against zero (when the
521       // last parameter is mpl::bool_<true>). They are only necessary
522       // for compilers that don't support SFINAE.
523       template<typename Function, typename Functor>
524         bool
compare_equal(const Function & f,const Functor &,int,mpl::bool_<true>)525         compare_equal(const Function& f, const Functor&, int, mpl::bool_<true>)
526         { return f.empty(); }
527 
528       template<typename Function, typename Functor>
529         bool
compare_not_equal(const Function & f,const Functor &,int,mpl::bool_<true>)530         compare_not_equal(const Function& f, const Functor&, int,
531                           mpl::bool_<true>)
532         { return !f.empty(); }
533 
534       template<typename Function, typename Functor>
535         bool
compare_equal(const Function & f,const Functor & g,long,mpl::bool_<false>)536         compare_equal(const Function& f, const Functor& g, long,
537                       mpl::bool_<false>)
538         {
539           if (const Functor* fp = f.template target<Functor>())
540             return function_equal(*fp, g);
541           else return false;
542         }
543 
544       template<typename Function, typename Functor>
545         bool
compare_equal(const Function & f,const reference_wrapper<Functor> & g,int,mpl::bool_<false>)546         compare_equal(const Function& f, const reference_wrapper<Functor>& g,
547                       int, mpl::bool_<false>)
548         {
549           if (const Functor* fp = f.template target<Functor>())
550             return fp == g.get_pointer();
551           else return false;
552         }
553 
554       template<typename Function, typename Functor>
555         bool
compare_not_equal(const Function & f,const Functor & g,long,mpl::bool_<false>)556         compare_not_equal(const Function& f, const Functor& g, long,
557                           mpl::bool_<false>)
558         {
559           if (const Functor* fp = f.template target<Functor>())
560             return !function_equal(*fp, g);
561           else return true;
562         }
563 
564       template<typename Function, typename Functor>
565         bool
compare_not_equal(const Function & f,const reference_wrapper<Functor> & g,int,mpl::bool_<false>)566         compare_not_equal(const Function& f,
567                           const reference_wrapper<Functor>& g, int,
568                           mpl::bool_<false>)
569         {
570           if (const Functor* fp = f.template target<Functor>())
571             return fp != g.get_pointer();
572           else return true;
573         }
574 #endif // BOOST_NO_SFINAE
575 
576       /**
577        * Stores the "manager" portion of the vtable for a
578        * boost::function object.
579        */
580       struct vtable_base
581       {
582         void (*manager)(const function_buffer& in_buffer,
583                         function_buffer& out_buffer,
584                         functor_manager_operation_type op);
585       };
586     } // end namespace function
587   } // end namespace detail
588 
589 /**
590  * The function_base class contains the basic elements needed for the
591  * function1, function2, function3, etc. classes. It is common to all
592  * functions (and as such can be used to tell if we have one of the
593  * functionN objects).
594  */
595 class function_base
596 {
597 public:
function_base()598   function_base() : vtable(0) { }
599 
600   /** Determine if the function is empty (i.e., has no target). */
empty() const601   bool empty() const { return !vtable; }
602 
603   /** Retrieve the type of the stored function object, or type_id<void>()
604       if this is empty. */
target_type() const605   const boost::typeindex::type_info& target_type() const
606   {
607     if (!vtable) return boost::typeindex::type_id<void>().type_info();
608 
609     detail::function::function_buffer type;
610     get_vtable()->manager(functor, type, detail::function::get_functor_type_tag);
611     return *type.members.type.type;
612   }
613 
614   template<typename Functor>
target()615     Functor* target()
616     {
617       if (!vtable) return 0;
618 
619       detail::function::function_buffer type_result;
620       type_result.members.type.type = &boost::typeindex::type_id<Functor>().type_info();
621       type_result.members.type.const_qualified = is_const<Functor>::value;
622       type_result.members.type.volatile_qualified = is_volatile<Functor>::value;
623       get_vtable()->manager(functor, type_result,
624                       detail::function::check_functor_type_tag);
625       return static_cast<Functor*>(type_result.members.obj_ptr);
626     }
627 
628   template<typename Functor>
target() const629     const Functor* target() const
630     {
631       if (!vtable) return 0;
632 
633       detail::function::function_buffer type_result;
634       type_result.members.type.type = &boost::typeindex::type_id<Functor>().type_info();
635       type_result.members.type.const_qualified = true;
636       type_result.members.type.volatile_qualified = is_volatile<Functor>::value;
637       get_vtable()->manager(functor, type_result,
638                       detail::function::check_functor_type_tag);
639       // GCC 2.95.3 gets the CV qualifiers wrong here, so we
640       // can't do the static_cast that we should do.
641       return static_cast<const Functor*>(type_result.members.obj_ptr);
642     }
643 
644   template<typename F>
contains(const F & f) const645     bool contains(const F& f) const
646     {
647       if (const F* fp = this->template target<F>())
648       {
649         return function_equal(*fp, f);
650       } else {
651         return false;
652       }
653     }
654 
655 #if defined(__GNUC__) && __GNUC__ == 3 && __GNUC_MINOR__ <= 3
656   // GCC 3.3 and newer cannot copy with the global operator==, due to
657   // problems with instantiation of function return types before it
658   // has been verified that the argument types match up.
659   template<typename Functor>
660     BOOST_FUNCTION_ENABLE_IF_NOT_INTEGRAL(Functor, bool)
661     operator==(Functor g) const
662     {
663       if (const Functor* fp = target<Functor>())
664         return function_equal(*fp, g);
665       else return false;
666     }
667 
668   template<typename Functor>
669     BOOST_FUNCTION_ENABLE_IF_NOT_INTEGRAL(Functor, bool)
670     operator!=(Functor g) const
671     {
672       if (const Functor* fp = target<Functor>())
673         return !function_equal(*fp, g);
674       else return true;
675     }
676 #endif
677 
678 public: // should be protected, but GCC 2.95.3 will fail to allow access
get_vtable() const679   detail::function::vtable_base* get_vtable() const {
680     return reinterpret_cast<detail::function::vtable_base*>(
681              reinterpret_cast<std::size_t>(vtable) & ~static_cast<std::size_t>(0x01));
682   }
683 
has_trivial_copy_and_destroy() const684   bool has_trivial_copy_and_destroy() const {
685     return reinterpret_cast<std::size_t>(vtable) & 0x01;
686   }
687 
688   detail::function::vtable_base* vtable;
689   mutable detail::function::function_buffer functor;
690 };
691 
692 /**
693  * The bad_function_call exception class is thrown when a boost::function
694  * object is invoked
695  */
696 class bad_function_call : public std::runtime_error
697 {
698 public:
bad_function_call()699   bad_function_call() : std::runtime_error("call to empty boost::function") {}
700 };
701 
702 #ifndef BOOST_NO_SFINAE
operator ==(const function_base & f,detail::function::useless_clear_type *)703 inline bool operator==(const function_base& f,
704                        detail::function::useless_clear_type*)
705 {
706   return f.empty();
707 }
708 
operator !=(const function_base & f,detail::function::useless_clear_type *)709 inline bool operator!=(const function_base& f,
710                        detail::function::useless_clear_type*)
711 {
712   return !f.empty();
713 }
714 
operator ==(detail::function::useless_clear_type *,const function_base & f)715 inline bool operator==(detail::function::useless_clear_type*,
716                        const function_base& f)
717 {
718   return f.empty();
719 }
720 
operator !=(detail::function::useless_clear_type *,const function_base & f)721 inline bool operator!=(detail::function::useless_clear_type*,
722                        const function_base& f)
723 {
724   return !f.empty();
725 }
726 #endif
727 
728 #ifdef BOOST_NO_SFINAE
729 // Comparisons between boost::function objects and arbitrary function objects
730 template<typename Functor>
operator ==(const function_base & f,Functor g)731   inline bool operator==(const function_base& f, Functor g)
732   {
733     typedef mpl::bool_<(is_integral<Functor>::value)> integral;
734     return detail::function::compare_equal(f, g, 0, integral());
735   }
736 
737 template<typename Functor>
operator ==(Functor g,const function_base & f)738   inline bool operator==(Functor g, const function_base& f)
739   {
740     typedef mpl::bool_<(is_integral<Functor>::value)> integral;
741     return detail::function::compare_equal(f, g, 0, integral());
742   }
743 
744 template<typename Functor>
operator !=(const function_base & f,Functor g)745   inline bool operator!=(const function_base& f, Functor g)
746   {
747     typedef mpl::bool_<(is_integral<Functor>::value)> integral;
748     return detail::function::compare_not_equal(f, g, 0, integral());
749   }
750 
751 template<typename Functor>
operator !=(Functor g,const function_base & f)752   inline bool operator!=(Functor g, const function_base& f)
753   {
754     typedef mpl::bool_<(is_integral<Functor>::value)> integral;
755     return detail::function::compare_not_equal(f, g, 0, integral());
756   }
757 #else
758 
759 #  if !(defined(__GNUC__) && __GNUC__ == 3 && __GNUC_MINOR__ <= 3)
760 // Comparisons between boost::function objects and arbitrary function
761 // objects. GCC 3.3 and before has an obnoxious bug that prevents this
762 // from working.
763 template<typename Functor>
764   BOOST_FUNCTION_ENABLE_IF_NOT_INTEGRAL(Functor, bool)
765   operator==(const function_base& f, Functor g)
766   {
767     if (const Functor* fp = f.template target<Functor>())
768       return function_equal(*fp, g);
769     else return false;
770   }
771 
772 template<typename Functor>
773   BOOST_FUNCTION_ENABLE_IF_NOT_INTEGRAL(Functor, bool)
774   operator==(Functor g, const function_base& f)
775   {
776     if (const Functor* fp = f.template target<Functor>())
777       return function_equal(g, *fp);
778     else return false;
779   }
780 
781 template<typename Functor>
782   BOOST_FUNCTION_ENABLE_IF_NOT_INTEGRAL(Functor, bool)
783   operator!=(const function_base& f, Functor g)
784   {
785     if (const Functor* fp = f.template target<Functor>())
786       return !function_equal(*fp, g);
787     else return true;
788   }
789 
790 template<typename Functor>
791   BOOST_FUNCTION_ENABLE_IF_NOT_INTEGRAL(Functor, bool)
792   operator!=(Functor g, const function_base& f)
793   {
794     if (const Functor* fp = f.template target<Functor>())
795       return !function_equal(g, *fp);
796     else return true;
797   }
798 #  endif
799 
800 template<typename Functor>
801   BOOST_FUNCTION_ENABLE_IF_NOT_INTEGRAL(Functor, bool)
802   operator==(const function_base& f, reference_wrapper<Functor> g)
803   {
804     if (const Functor* fp = f.template target<Functor>())
805       return fp == g.get_pointer();
806     else return false;
807   }
808 
809 template<typename Functor>
810   BOOST_FUNCTION_ENABLE_IF_NOT_INTEGRAL(Functor, bool)
811   operator==(reference_wrapper<Functor> g, const function_base& f)
812   {
813     if (const Functor* fp = f.template target<Functor>())
814       return g.get_pointer() == fp;
815     else return false;
816   }
817 
818 template<typename Functor>
819   BOOST_FUNCTION_ENABLE_IF_NOT_INTEGRAL(Functor, bool)
820   operator!=(const function_base& f, reference_wrapper<Functor> g)
821   {
822     if (const Functor* fp = f.template target<Functor>())
823       return fp != g.get_pointer();
824     else return true;
825   }
826 
827 template<typename Functor>
828   BOOST_FUNCTION_ENABLE_IF_NOT_INTEGRAL(Functor, bool)
829   operator!=(reference_wrapper<Functor> g, const function_base& f)
830   {
831     if (const Functor* fp = f.template target<Functor>())
832       return g.get_pointer() != fp;
833     else return true;
834   }
835 
836 #endif // Compiler supporting SFINAE
837 
838 namespace detail {
839   namespace function {
has_empty_target(const function_base * f)840     inline bool has_empty_target(const function_base* f)
841     {
842       return f->empty();
843     }
844 
845 #if BOOST_WORKAROUND(BOOST_MSVC, <= 1310)
has_empty_target(const void *)846     inline bool has_empty_target(const void*)
847     {
848       return false;
849     }
850 #else
has_empty_target(...)851     inline bool has_empty_target(...)
852     {
853       return false;
854     }
855 #endif
856   } // end namespace function
857 } // end namespace detail
858 } // end namespace boost
859 
860 #undef BOOST_FUNCTION_ENABLE_IF_NOT_INTEGRAL
861 
862 #if defined(BOOST_MSVC)
863 #   pragma warning( pop )
864 #endif
865 
866 #endif // BOOST_FUNCTION_BASE_HEADER
867