1 // Boost.Function library
\r
3 // Copyright Douglas Gregor 2001-2006
\r
4 // Copyright Emil Dotchevski 2007
\r
5 // Use, modification and distribution is subject to the Boost Software License, Version 1.0.
\r
6 // (See accompanying file LICENSE_1_0.txt or copy at
\r
7 // http://www.boost.org/LICENSE_1_0.txt)
\r
9 // For more information, see http://www.boost.org
\r
11 #ifndef BOOST_FUNCTION_BASE_HEADER
\r
12 #define BOOST_FUNCTION_BASE_HEADER
\r
14 #include <stdexcept>
\r
18 #include <boost/config.hpp>
\r
19 #include <boost/detail/sp_typeinfo.hpp>
\r
20 #include <boost/assert.hpp>
\r
21 #include <boost/integer.hpp>
\r
22 #include <boost/type_traits/has_trivial_copy.hpp>
\r
23 #include <boost/type_traits/has_trivial_destructor.hpp>
\r
24 #include <boost/type_traits/is_const.hpp>
\r
25 #include <boost/type_traits/is_integral.hpp>
\r
26 #include <boost/type_traits/is_volatile.hpp>
\r
27 #include <boost/type_traits/composite_traits.hpp>
\r
28 #include <boost/type_traits/ice.hpp>
\r
29 #include <boost/ref.hpp>
\r
30 #include <boost/mpl/if.hpp>
\r
31 #include <boost/detail/workaround.hpp>
\r
32 #include <boost/type_traits/alignment_of.hpp>
\r
33 #ifndef BOOST_NO_SFINAE
\r
34 # include "boost/utility/enable_if.hpp"
\r
36 # include "boost/mpl/bool.hpp"
\r
38 #include <boost/function_equal.hpp>
\r
39 #include <boost/function/function_fwd.hpp>
\r
41 #if defined(BOOST_MSVC)
\r
42 # pragma warning( push )
\r
43 # pragma warning( disable : 4793 ) // complaint about native code generation
\r
44 # pragma warning( disable : 4127 ) // "conditional expression is constant"
\r
47 // Define BOOST_FUNCTION_STD_NS to the namespace that contains type_info.
\r
48 #ifdef BOOST_NO_STD_TYPEINFO
\r
49 // Embedded VC++ does not have type_info in namespace std
\r
50 # define BOOST_FUNCTION_STD_NS
\r
52 # define BOOST_FUNCTION_STD_NS std
\r
55 // Borrowed from Boost.Python library: determines the cases where we
\r
56 // need to use std::type_info::name to compare instead of operator==.
\r
57 #if defined( BOOST_NO_TYPEID )
\r
58 # define BOOST_FUNCTION_COMPARE_TYPE_ID(X,Y) ((X)==(Y))
\r
59 #elif (defined(__GNUC__) && __GNUC__ >= 3) \
\r
61 || ( defined(__sgi) && defined(__host_mips))
\r
63 # define BOOST_FUNCTION_COMPARE_TYPE_ID(X,Y) \
\r
64 (std::strcmp((X).name(),(Y).name()) == 0)
\r
66 # define BOOST_FUNCTION_COMPARE_TYPE_ID(X,Y) ((X)==(Y))
\r
69 #if defined(BOOST_MSVC) && BOOST_MSVC <= 1300 || defined(__ICL) && __ICL <= 600 || defined(__MWERKS__) && __MWERKS__ < 0x2406 && !defined(BOOST_STRICT_CONFIG)
\r
70 # define BOOST_FUNCTION_TARGET_FIX(x) x
\r
72 # define BOOST_FUNCTION_TARGET_FIX(x)
\r
75 #if !BOOST_WORKAROUND(__BORLANDC__, < 0x5A0)
\r
76 # define BOOST_FUNCTION_ENABLE_IF_NOT_INTEGRAL(Functor,Type) \
\r
77 typename ::boost::enable_if_c<(::boost::type_traits::ice_not< \
\r
78 (::boost::is_integral<Functor>::value)>::value), \
\r
81 // BCC doesn't recognize this depends on a template argument and complains
\r
82 // about the use of 'typename'
\r
83 # define BOOST_FUNCTION_ENABLE_IF_NOT_INTEGRAL(Functor,Type) \
\r
84 ::boost::enable_if_c<(::boost::type_traits::ice_not< \
\r
85 (::boost::is_integral<Functor>::value)>::value), \
\r
91 namespace function {
\r
95 * A buffer used to store small function objects in
\r
96 * boost::function. It is a union containing function pointers,
\r
97 * object pointers, and a structure that resembles a bound
\r
98 * member function pointer.
\r
100 union function_buffer
\r
102 // For pointers to function objects
\r
103 mutable void* obj_ptr;
\r
105 // For pointers to std::type_info objects
\r
107 // (get_functor_type_tag, check_functor_type_tag).
\r
108 const detail::sp_typeinfo* type;
\r
110 // Whether the type is const-qualified.
\r
111 bool const_qualified;
\r
112 // Whether the type is volatile-qualified.
\r
113 bool volatile_qualified;
\r
116 // For function pointers of all kinds
\r
117 mutable void (*func_ptr)();
\r
119 // For bound member pointers
\r
120 struct bound_memfunc_ptr_t {
\r
121 void (X::*memfunc_ptr)(int);
\r
123 } bound_memfunc_ptr;
\r
125 // For references to function objects. We explicitly keep
\r
126 // track of the cv-qualifiers on the object referenced.
\r
128 mutable void* obj_ptr;
\r
129 bool is_const_qualified;
\r
130 bool is_volatile_qualified;
\r
133 // To relax aliasing constraints
\r
138 * The unusable class is a placeholder for unused function arguments
\r
139 * It is also completely unusable except that it constructable from
\r
140 * anything. This helps compilers without partial specialization to
\r
141 * handle Boost.Function objects returning void.
\r
146 template<typename T> unusable(const T&) {}
\r
149 /* Determine the return type. This supports compilers that do not support
\r
150 * void returns or partial specialization by silently changing the return
\r
151 * type to "unusable".
\r
153 template<typename T> struct function_return_type { typedef T type; };
\r
156 struct function_return_type<void>
\r
158 typedef unusable type;
\r
161 // The operation type to perform on the given functor/function pointer
\r
162 enum functor_manager_operation_type {
\r
165 destroy_functor_tag,
\r
166 check_functor_type_tag,
\r
167 get_functor_type_tag
\r
170 // Tags used to decide between different types of functions
\r
171 struct function_ptr_tag {};
\r
172 struct function_obj_tag {};
\r
173 struct member_ptr_tag {};
\r
174 struct function_obj_ref_tag {};
\r
176 template<typename F>
\r
177 class get_function_tag
\r
179 typedef typename mpl::if_c<(is_pointer<F>::value),
\r
181 function_obj_tag>::type ptr_or_obj_tag;
\r
183 typedef typename mpl::if_c<(is_member_pointer<F>::value),
\r
185 ptr_or_obj_tag>::type ptr_or_obj_or_mem_tag;
\r
187 typedef typename mpl::if_c<(is_reference_wrapper<F>::value),
\r
188 function_obj_ref_tag,
\r
189 ptr_or_obj_or_mem_tag>::type or_ref_tag;
\r
192 typedef or_ref_tag type;
\r
195 // The trivial manager does nothing but return the same pointer (if we
\r
196 // are cloning) or return the null pointer (if we are deleting).
\r
197 template<typename F>
\r
198 struct reference_manager
\r
201 manage(const function_buffer& in_buffer, function_buffer& out_buffer,
\r
202 functor_manager_operation_type op)
\r
205 case clone_functor_tag:
\r
206 out_buffer.obj_ref.obj_ptr = in_buffer.obj_ref.obj_ptr;
\r
209 case move_functor_tag:
\r
210 out_buffer.obj_ref.obj_ptr = in_buffer.obj_ref.obj_ptr;
\r
211 in_buffer.obj_ref.obj_ptr = 0;
\r
214 case destroy_functor_tag:
\r
215 out_buffer.obj_ref.obj_ptr = 0;
\r
218 case check_functor_type_tag:
\r
220 const detail::sp_typeinfo& check_type
\r
221 = *out_buffer.type.type;
\r
223 // Check whether we have the same type. We can add
\r
224 // cv-qualifiers, but we can't take them away.
\r
225 if (BOOST_FUNCTION_COMPARE_TYPE_ID(check_type, BOOST_SP_TYPEID(F))
\r
226 && (!in_buffer.obj_ref.is_const_qualified
\r
227 || out_buffer.type.const_qualified)
\r
228 && (!in_buffer.obj_ref.is_volatile_qualified
\r
229 || out_buffer.type.volatile_qualified))
\r
230 out_buffer.obj_ptr = in_buffer.obj_ref.obj_ptr;
\r
232 out_buffer.obj_ptr = 0;
\r
236 case get_functor_type_tag:
\r
237 out_buffer.type.type = &BOOST_SP_TYPEID(F);
\r
238 out_buffer.type.const_qualified = in_buffer.obj_ref.is_const_qualified;
\r
239 out_buffer.type.volatile_qualified = in_buffer.obj_ref.is_volatile_qualified;
\r
246 * Determine if boost::function can use the small-object
\r
247 * optimization with the function object type F.
\r
249 template<typename F>
\r
250 struct function_allows_small_object_optimization
\r
252 BOOST_STATIC_CONSTANT
\r
254 value = ((sizeof(F) <= sizeof(function_buffer) &&
\r
255 (alignment_of<function_buffer>::value
\r
256 % alignment_of<F>::value == 0))));
\r
259 template <typename F,typename A>
\r
260 struct functor_wrapper: public F, public A
\r
262 functor_wrapper( F f, A a ):
\r
268 functor_wrapper(const functor_wrapper& f) :
\r
269 F(static_cast<const F&>(f)),
\r
270 A(static_cast<const A&>(f))
\r
276 * The functor_manager class contains a static function "manage" which
\r
277 * can clone or destroy the given function/function object pointer.
\r
279 template<typename Functor>
\r
280 struct functor_manager_common
\r
282 typedef Functor functor_type;
\r
284 // Function pointers
\r
286 manage_ptr(const function_buffer& in_buffer, function_buffer& out_buffer,
\r
287 functor_manager_operation_type op)
\r
289 if (op == clone_functor_tag)
\r
290 out_buffer.func_ptr = in_buffer.func_ptr;
\r
291 else if (op == move_functor_tag) {
\r
292 out_buffer.func_ptr = in_buffer.func_ptr;
\r
293 in_buffer.func_ptr = 0;
\r
294 } else if (op == destroy_functor_tag)
\r
295 out_buffer.func_ptr = 0;
\r
296 else if (op == check_functor_type_tag) {
\r
297 const detail::sp_typeinfo& check_type
\r
298 = *out_buffer.type.type;
\r
299 if (BOOST_FUNCTION_COMPARE_TYPE_ID(check_type, BOOST_SP_TYPEID(Functor)))
\r
300 out_buffer.obj_ptr = &in_buffer.func_ptr;
\r
302 out_buffer.obj_ptr = 0;
\r
303 } else /* op == get_functor_type_tag */ {
\r
304 out_buffer.type.type = &BOOST_SP_TYPEID(Functor);
\r
305 out_buffer.type.const_qualified = false;
\r
306 out_buffer.type.volatile_qualified = false;
\r
310 // Function objects that fit in the small-object buffer.
\r
312 manage_small(const function_buffer& in_buffer, function_buffer& out_buffer,
\r
313 functor_manager_operation_type op)
\r
315 if (op == clone_functor_tag || op == move_functor_tag) {
\r
316 const functor_type* in_functor =
\r
317 reinterpret_cast<const functor_type*>(&in_buffer.data);
\r
318 new ((void*)&out_buffer.data) functor_type(*in_functor);
\r
320 if (op == move_functor_tag) {
\r
321 reinterpret_cast<functor_type*>(&in_buffer.data)->~Functor();
\r
323 } else if (op == destroy_functor_tag) {
\r
324 // Some compilers (Borland, vc6, ...) are unhappy with ~functor_type.
\r
325 reinterpret_cast<functor_type*>(&out_buffer.data)->~Functor();
\r
326 } else if (op == check_functor_type_tag) {
\r
327 const detail::sp_typeinfo& check_type
\r
328 = *out_buffer.type.type;
\r
329 if (BOOST_FUNCTION_COMPARE_TYPE_ID(check_type, BOOST_SP_TYPEID(Functor)))
\r
330 out_buffer.obj_ptr = &in_buffer.data;
\r
332 out_buffer.obj_ptr = 0;
\r
333 } else /* op == get_functor_type_tag */ {
\r
334 out_buffer.type.type = &BOOST_SP_TYPEID(Functor);
\r
335 out_buffer.type.const_qualified = false;
\r
336 out_buffer.type.volatile_qualified = false;
\r
341 template<typename Functor>
\r
342 struct functor_manager
\r
345 typedef Functor functor_type;
\r
347 // Function pointers
\r
349 manager(const function_buffer& in_buffer, function_buffer& out_buffer,
\r
350 functor_manager_operation_type op, function_ptr_tag)
\r
352 functor_manager_common<Functor>::manage_ptr(in_buffer,out_buffer,op);
\r
355 // Function objects that fit in the small-object buffer.
\r
357 manager(const function_buffer& in_buffer, function_buffer& out_buffer,
\r
358 functor_manager_operation_type op, mpl::true_)
\r
360 functor_manager_common<Functor>::manage_small(in_buffer,out_buffer,op);
\r
363 // Function objects that require heap allocation
\r
365 manager(const function_buffer& in_buffer, function_buffer& out_buffer,
\r
366 functor_manager_operation_type op, mpl::false_)
\r
368 if (op == clone_functor_tag) {
\r
369 // Clone the functor
\r
370 // GCC 2.95.3 gets the CV qualifiers wrong here, so we
\r
371 // can't do the static_cast that we should do.
\r
372 const functor_type* f =
\r
373 (const functor_type*)(in_buffer.obj_ptr);
\r
374 functor_type* new_f = new functor_type(*f);
\r
375 out_buffer.obj_ptr = new_f;
\r
376 } else if (op == move_functor_tag) {
\r
377 out_buffer.obj_ptr = in_buffer.obj_ptr;
\r
378 in_buffer.obj_ptr = 0;
\r
379 } else if (op == destroy_functor_tag) {
\r
380 /* Cast from the void pointer to the functor pointer type */
\r
382 static_cast<functor_type*>(out_buffer.obj_ptr);
\r
384 out_buffer.obj_ptr = 0;
\r
385 } else if (op == check_functor_type_tag) {
\r
386 const detail::sp_typeinfo& check_type
\r
387 = *out_buffer.type.type;
\r
388 if (BOOST_FUNCTION_COMPARE_TYPE_ID(check_type, BOOST_SP_TYPEID(Functor)))
\r
389 out_buffer.obj_ptr = in_buffer.obj_ptr;
\r
391 out_buffer.obj_ptr = 0;
\r
392 } else /* op == get_functor_type_tag */ {
\r
393 out_buffer.type.type = &BOOST_SP_TYPEID(Functor);
\r
394 out_buffer.type.const_qualified = false;
\r
395 out_buffer.type.volatile_qualified = false;
\r
399 // For function objects, we determine whether the function
\r
400 // object can use the small-object optimization buffer or
\r
401 // whether we need to allocate it on the heap.
\r
403 manager(const function_buffer& in_buffer, function_buffer& out_buffer,
\r
404 functor_manager_operation_type op, function_obj_tag)
\r
406 manager(in_buffer, out_buffer, op,
\r
407 mpl::bool_<(function_allows_small_object_optimization<functor_type>::value)>());
\r
410 // For member pointers, we use the small-object optimization buffer.
\r
412 manager(const function_buffer& in_buffer, function_buffer& out_buffer,
\r
413 functor_manager_operation_type op, member_ptr_tag)
\r
415 manager(in_buffer, out_buffer, op, mpl::true_());
\r
419 /* Dispatch to an appropriate manager based on whether we have a
\r
420 function pointer or a function object pointer. */
\r
422 manage(const function_buffer& in_buffer, function_buffer& out_buffer,
\r
423 functor_manager_operation_type op)
\r
425 typedef typename get_function_tag<functor_type>::type tag_type;
\r
427 case get_functor_type_tag:
\r
428 out_buffer.type.type = &BOOST_SP_TYPEID(functor_type);
\r
429 out_buffer.type.const_qualified = false;
\r
430 out_buffer.type.volatile_qualified = false;
\r
434 manager(in_buffer, out_buffer, op, tag_type());
\r
440 template<typename Functor, typename Allocator>
\r
441 struct functor_manager_a
\r
444 typedef Functor functor_type;
\r
446 // Function pointers
\r
448 manager(const function_buffer& in_buffer, function_buffer& out_buffer,
\r
449 functor_manager_operation_type op, function_ptr_tag)
\r
451 functor_manager_common<Functor>::manage_ptr(in_buffer,out_buffer,op);
\r
454 // Function objects that fit in the small-object buffer.
\r
456 manager(const function_buffer& in_buffer, function_buffer& out_buffer,
\r
457 functor_manager_operation_type op, mpl::true_)
\r
459 functor_manager_common<Functor>::manage_small(in_buffer,out_buffer,op);
\r
462 // Function objects that require heap allocation
\r
464 manager(const function_buffer& in_buffer, function_buffer& out_buffer,
\r
465 functor_manager_operation_type op, mpl::false_)
\r
467 typedef functor_wrapper<Functor,Allocator> functor_wrapper_type;
\r
468 typedef typename Allocator::template rebind<functor_wrapper_type>::other
\r
469 wrapper_allocator_type;
\r
470 typedef typename wrapper_allocator_type::pointer wrapper_allocator_pointer_type;
\r
472 if (op == clone_functor_tag) {
\r
473 // Clone the functor
\r
474 // GCC 2.95.3 gets the CV qualifiers wrong here, so we
\r
475 // can't do the static_cast that we should do.
\r
476 const functor_wrapper_type* f =
\r
477 (const functor_wrapper_type*)(in_buffer.obj_ptr);
\r
478 wrapper_allocator_type wrapper_allocator(static_cast<Allocator const &>(*f));
\r
479 wrapper_allocator_pointer_type copy = wrapper_allocator.allocate(1);
\r
480 wrapper_allocator.construct(copy, *f);
\r
482 // Get back to the original pointer type
\r
483 functor_wrapper_type* new_f = static_cast<functor_wrapper_type*>(copy);
\r
484 out_buffer.obj_ptr = new_f;
\r
485 } else if (op == move_functor_tag) {
\r
486 out_buffer.obj_ptr = in_buffer.obj_ptr;
\r
487 in_buffer.obj_ptr = 0;
\r
488 } else if (op == destroy_functor_tag) {
\r
489 /* Cast from the void pointer to the functor_wrapper_type */
\r
490 functor_wrapper_type* victim =
\r
491 static_cast<functor_wrapper_type*>(in_buffer.obj_ptr);
\r
492 wrapper_allocator_type wrapper_allocator(static_cast<Allocator const &>(*victim));
\r
493 wrapper_allocator.destroy(victim);
\r
494 wrapper_allocator.deallocate(victim,1);
\r
495 out_buffer.obj_ptr = 0;
\r
496 } else if (op == check_functor_type_tag) {
\r
497 const detail::sp_typeinfo& check_type
\r
498 = *out_buffer.type.type;
\r
499 if (BOOST_FUNCTION_COMPARE_TYPE_ID(check_type, BOOST_SP_TYPEID(Functor)))
\r
500 out_buffer.obj_ptr = in_buffer.obj_ptr;
\r
502 out_buffer.obj_ptr = 0;
\r
503 } else /* op == get_functor_type_tag */ {
\r
504 out_buffer.type.type = &BOOST_SP_TYPEID(Functor);
\r
505 out_buffer.type.const_qualified = false;
\r
506 out_buffer.type.volatile_qualified = false;
\r
510 // For function objects, we determine whether the function
\r
511 // object can use the small-object optimization buffer or
\r
512 // whether we need to allocate it on the heap.
\r
514 manager(const function_buffer& in_buffer, function_buffer& out_buffer,
\r
515 functor_manager_operation_type op, function_obj_tag)
\r
517 manager(in_buffer, out_buffer, op,
\r
518 mpl::bool_<(function_allows_small_object_optimization<functor_type>::value)>());
\r
522 /* Dispatch to an appropriate manager based on whether we have a
\r
523 function pointer or a function object pointer. */
\r
525 manage(const function_buffer& in_buffer, function_buffer& out_buffer,
\r
526 functor_manager_operation_type op)
\r
528 typedef typename get_function_tag<functor_type>::type tag_type;
\r
530 case get_functor_type_tag:
\r
531 out_buffer.type.type = &BOOST_SP_TYPEID(functor_type);
\r
532 out_buffer.type.const_qualified = false;
\r
533 out_buffer.type.volatile_qualified = false;
\r
537 manager(in_buffer, out_buffer, op, tag_type());
\r
543 // A type that is only used for comparisons against zero
\r
544 struct useless_clear_type {};
\r
546 #ifdef BOOST_NO_SFINAE
\r
547 // These routines perform comparisons between a Boost.Function
\r
548 // object and an arbitrary function object (when the last
\r
549 // parameter is mpl::bool_<false>) or against zero (when the
\r
550 // last parameter is mpl::bool_<true>). They are only necessary
\r
551 // for compilers that don't support SFINAE.
\r
552 template<typename Function, typename Functor>
\r
554 compare_equal(const Function& f, const Functor&, int, mpl::bool_<true>)
\r
555 { return f.empty(); }
\r
557 template<typename Function, typename Functor>
\r
559 compare_not_equal(const Function& f, const Functor&, int,
\r
561 { return !f.empty(); }
\r
563 template<typename Function, typename Functor>
\r
565 compare_equal(const Function& f, const Functor& g, long,
\r
568 if (const Functor* fp = f.template target<Functor>())
\r
569 return function_equal(*fp, g);
\r
573 template<typename Function, typename Functor>
\r
575 compare_equal(const Function& f, const reference_wrapper<Functor>& g,
\r
576 int, mpl::bool_<false>)
\r
578 if (const Functor* fp = f.template target<Functor>())
\r
579 return fp == g.get_pointer();
\r
583 template<typename Function, typename Functor>
\r
585 compare_not_equal(const Function& f, const Functor& g, long,
\r
588 if (const Functor* fp = f.template target<Functor>())
\r
589 return !function_equal(*fp, g);
\r
593 template<typename Function, typename Functor>
\r
595 compare_not_equal(const Function& f,
\r
596 const reference_wrapper<Functor>& g, int,
\r
599 if (const Functor* fp = f.template target<Functor>())
\r
600 return fp != g.get_pointer();
\r
603 #endif // BOOST_NO_SFINAE
\r
606 * Stores the "manager" portion of the vtable for a
\r
607 * boost::function object.
\r
611 void (*manager)(const function_buffer& in_buffer,
\r
612 function_buffer& out_buffer,
\r
613 functor_manager_operation_type op);
\r
615 } // end namespace function
\r
616 } // end namespace detail
\r
619 * The function_base class contains the basic elements needed for the
\r
620 * function1, function2, function3, etc. classes. It is common to all
\r
621 * functions (and as such can be used to tell if we have one of the
\r
622 * functionN objects).
\r
624 class function_base
\r
627 function_base() : vtable(0) { }
\r
629 /** Determine if the function is empty (i.e., has no target). */
\r
630 bool empty() const { return !vtable; }
\r
632 /** Retrieve the type of the stored function object, or BOOST_SP_TYPEID(void)
\r
633 if this is empty. */
\r
634 const detail::sp_typeinfo& target_type() const
\r
636 if (!vtable) return BOOST_SP_TYPEID(void);
\r
638 detail::function::function_buffer type;
\r
639 get_vtable()->manager(functor, type, detail::function::get_functor_type_tag);
\r
640 return *type.type.type;
\r
643 template<typename Functor>
\r
646 if (!vtable) return 0;
\r
648 detail::function::function_buffer type_result;
\r
649 type_result.type.type = &BOOST_SP_TYPEID(Functor);
\r
650 type_result.type.const_qualified = is_const<Functor>::value;
\r
651 type_result.type.volatile_qualified = is_volatile<Functor>::value;
\r
652 get_vtable()->manager(functor, type_result,
\r
653 detail::function::check_functor_type_tag);
\r
654 return static_cast<Functor*>(type_result.obj_ptr);
\r
657 template<typename Functor>
\r
658 #if defined(BOOST_MSVC) && BOOST_WORKAROUND(BOOST_MSVC, < 1300)
\r
659 const Functor* target( Functor * = 0 ) const
\r
661 const Functor* target() const
\r
664 if (!vtable) return 0;
\r
666 detail::function::function_buffer type_result;
\r
667 type_result.type.type = &BOOST_SP_TYPEID(Functor);
\r
668 type_result.type.const_qualified = true;
\r
669 type_result.type.volatile_qualified = is_volatile<Functor>::value;
\r
670 get_vtable()->manager(functor, type_result,
\r
671 detail::function::check_functor_type_tag);
\r
672 // GCC 2.95.3 gets the CV qualifiers wrong here, so we
\r
673 // can't do the static_cast that we should do.
\r
674 return (const Functor*)(type_result.obj_ptr);
\r
677 template<typename F>
\r
678 bool contains(const F& f) const
\r
680 #if defined(BOOST_MSVC) && BOOST_WORKAROUND(BOOST_MSVC, < 1300)
\r
681 if (const F* fp = this->target( (F*)0 ))
\r
683 if (const F* fp = this->template target<F>())
\r
686 return function_equal(*fp, f);
\r
692 #if defined(__GNUC__) && __GNUC__ == 3 && __GNUC_MINOR__ <= 3
\r
693 // GCC 3.3 and newer cannot copy with the global operator==, due to
\r
694 // problems with instantiation of function return types before it
\r
695 // has been verified that the argument types match up.
\r
696 template<typename Functor>
\r
697 BOOST_FUNCTION_ENABLE_IF_NOT_INTEGRAL(Functor, bool)
\r
698 operator==(Functor g) const
\r
700 if (const Functor* fp = target<Functor>())
\r
701 return function_equal(*fp, g);
\r
705 template<typename Functor>
\r
706 BOOST_FUNCTION_ENABLE_IF_NOT_INTEGRAL(Functor, bool)
\r
707 operator!=(Functor g) const
\r
709 if (const Functor* fp = target<Functor>())
\r
710 return !function_equal(*fp, g);
\r
715 public: // should be protected, but GCC 2.95.3 will fail to allow access
\r
716 detail::function::vtable_base* get_vtable() const {
\r
717 return reinterpret_cast<detail::function::vtable_base*>(
\r
718 reinterpret_cast<std::size_t>(vtable) & ~(std::size_t)0x01);
\r
721 bool has_trivial_copy_and_destroy() const {
\r
722 return reinterpret_cast<std::size_t>(vtable) & 0x01;
\r
725 detail::function::vtable_base* vtable;
\r
726 mutable detail::function::function_buffer functor;
\r
730 * The bad_function_call exception class is thrown when a boost::function
\r
731 * object is invoked
\r
733 class bad_function_call : public std::runtime_error
\r
736 bad_function_call() : std::runtime_error("call to empty boost::function") {}
\r
739 #ifndef BOOST_NO_SFINAE
\r
740 inline bool operator==(const function_base& f,
\r
741 detail::function::useless_clear_type*)
\r
746 inline bool operator!=(const function_base& f,
\r
747 detail::function::useless_clear_type*)
\r
752 inline bool operator==(detail::function::useless_clear_type*,
\r
753 const function_base& f)
\r
758 inline bool operator!=(detail::function::useless_clear_type*,
\r
759 const function_base& f)
\r
765 #ifdef BOOST_NO_SFINAE
\r
766 // Comparisons between boost::function objects and arbitrary function objects
\r
767 template<typename Functor>
\r
768 inline bool operator==(const function_base& f, Functor g)
\r
770 typedef mpl::bool_<(is_integral<Functor>::value)> integral;
\r
771 return detail::function::compare_equal(f, g, 0, integral());
\r
774 template<typename Functor>
\r
775 inline bool operator==(Functor g, const function_base& f)
\r
777 typedef mpl::bool_<(is_integral<Functor>::value)> integral;
\r
778 return detail::function::compare_equal(f, g, 0, integral());
\r
781 template<typename Functor>
\r
782 inline bool operator!=(const function_base& f, Functor g)
\r
784 typedef mpl::bool_<(is_integral<Functor>::value)> integral;
\r
785 return detail::function::compare_not_equal(f, g, 0, integral());
\r
788 template<typename Functor>
\r
789 inline bool operator!=(Functor g, const function_base& f)
\r
791 typedef mpl::bool_<(is_integral<Functor>::value)> integral;
\r
792 return detail::function::compare_not_equal(f, g, 0, integral());
\r
796 # if !(defined(__GNUC__) && __GNUC__ == 3 && __GNUC_MINOR__ <= 3)
\r
797 // Comparisons between boost::function objects and arbitrary function
\r
798 // objects. GCC 3.3 and before has an obnoxious bug that prevents this
\r
800 template<typename Functor>
\r
801 BOOST_FUNCTION_ENABLE_IF_NOT_INTEGRAL(Functor, bool)
\r
802 operator==(const function_base& f, Functor g)
\r
804 if (const Functor* fp = f.template target<Functor>())
\r
805 return function_equal(*fp, g);
\r
809 template<typename Functor>
\r
810 BOOST_FUNCTION_ENABLE_IF_NOT_INTEGRAL(Functor, bool)
\r
811 operator==(Functor g, const function_base& f)
\r
813 if (const Functor* fp = f.template target<Functor>())
\r
814 return function_equal(g, *fp);
\r
818 template<typename Functor>
\r
819 BOOST_FUNCTION_ENABLE_IF_NOT_INTEGRAL(Functor, bool)
\r
820 operator!=(const function_base& f, Functor g)
\r
822 if (const Functor* fp = f.template target<Functor>())
\r
823 return !function_equal(*fp, g);
\r
827 template<typename Functor>
\r
828 BOOST_FUNCTION_ENABLE_IF_NOT_INTEGRAL(Functor, bool)
\r
829 operator!=(Functor g, const function_base& f)
\r
831 if (const Functor* fp = f.template target<Functor>())
\r
832 return !function_equal(g, *fp);
\r
837 template<typename Functor>
\r
838 BOOST_FUNCTION_ENABLE_IF_NOT_INTEGRAL(Functor, bool)
\r
839 operator==(const function_base& f, reference_wrapper<Functor> g)
\r
841 if (const Functor* fp = f.template target<Functor>())
\r
842 return fp == g.get_pointer();
\r
846 template<typename Functor>
\r
847 BOOST_FUNCTION_ENABLE_IF_NOT_INTEGRAL(Functor, bool)
\r
848 operator==(reference_wrapper<Functor> g, const function_base& f)
\r
850 if (const Functor* fp = f.template target<Functor>())
\r
851 return g.get_pointer() == fp;
\r
855 template<typename Functor>
\r
856 BOOST_FUNCTION_ENABLE_IF_NOT_INTEGRAL(Functor, bool)
\r
857 operator!=(const function_base& f, reference_wrapper<Functor> g)
\r
859 if (const Functor* fp = f.template target<Functor>())
\r
860 return fp != g.get_pointer();
\r
864 template<typename Functor>
\r
865 BOOST_FUNCTION_ENABLE_IF_NOT_INTEGRAL(Functor, bool)
\r
866 operator!=(reference_wrapper<Functor> g, const function_base& f)
\r
868 if (const Functor* fp = f.template target<Functor>())
\r
869 return g.get_pointer() != fp;
\r
873 #endif // Compiler supporting SFINAE
\r
876 namespace function {
\r
877 inline bool has_empty_target(const function_base* f)
\r
882 #if BOOST_WORKAROUND(BOOST_MSVC, <= 1310)
\r
883 inline bool has_empty_target(const void*)
\r
888 inline bool has_empty_target(...)
\r
893 } // end namespace function
\r
894 } // end namespace detail
\r
895 } // end namespace boost
\r
897 #undef BOOST_FUNCTION_ENABLE_IF_NOT_INTEGRAL
\r
898 #undef BOOST_FUNCTION_COMPARE_TYPE_ID
\r
900 #if defined(BOOST_MSVC)
\r
901 # pragma warning( pop )
\r
904 #endif // BOOST_FUNCTION_BASE_HEADER
\r