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