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