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