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