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