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