Line data Source code
1 : #ifndef BOOST_FUNCTION_FUNCTION_TEMPLATE_HPP_INCLUDED
2 : #define BOOST_FUNCTION_FUNCTION_TEMPLATE_HPP_INCLUDED
3 :
4 : // Boost.Function library
5 :
6 : // Copyright Douglas Gregor 2001-2006
7 : // Copyright Emil Dotchevski 2007
8 : // Use, modification and distribution is subject to the Boost Software License, Version 1.0.
9 : // (See accompanying file LICENSE_1_0.txt or copy at
10 : // http://www.boost.org/LICENSE_1_0.txt)
11 :
12 : // For more information, see http://www.boost.org
13 :
14 : #include <boost/function/function_base.hpp>
15 : #include <boost/core/no_exceptions_support.hpp>
16 : #include <boost/mem_fn.hpp>
17 : #include <boost/throw_exception.hpp>
18 : #include <boost/config.hpp>
19 : #include <algorithm>
20 : #include <cassert>
21 : #include <type_traits>
22 :
23 : #if defined(BOOST_MSVC)
24 : # pragma warning( push )
25 : # pragma warning( disable : 4127 ) // "conditional expression is constant"
26 : #endif
27 :
28 : namespace boost {
29 : namespace detail {
30 : namespace function {
31 : template<
32 : typename FunctionPtr,
33 : typename R,
34 : typename... T
35 : >
36 : struct function_invoker
37 : {
38 : static R invoke(function_buffer& function_ptr,
39 : T... a)
40 : {
41 : FunctionPtr f = reinterpret_cast<FunctionPtr>(function_ptr.members.func_ptr);
42 : return f(static_cast<T&&>(a)...);
43 : }
44 : };
45 :
46 : template<
47 : typename FunctionPtr,
48 : typename R,
49 : typename... T
50 : >
51 : struct void_function_invoker
52 : {
53 : static void
54 731 : invoke(function_buffer& function_ptr,
55 : T... a)
56 :
57 : {
58 731 : FunctionPtr f = reinterpret_cast<FunctionPtr>(function_ptr.members.func_ptr);
59 731 : f(static_cast<T&&>(a)...);
60 731 : }
61 : };
62 :
63 : template<
64 : typename FunctionObj,
65 : typename R,
66 : typename... T
67 : >
68 : struct function_obj_invoker
69 : {
70 1319 : static R invoke(function_buffer& function_obj_ptr,
71 : T... a)
72 :
73 : {
74 : FunctionObj* f;
75 : if (function_allows_small_object_optimization<FunctionObj>::value)
76 1315 : f = reinterpret_cast<FunctionObj*>(function_obj_ptr.data);
77 : else
78 4 : f = reinterpret_cast<FunctionObj*>(function_obj_ptr.members.obj_ptr);
79 1319 : return (*f)(static_cast<T&&>(a)...);
80 : }
81 : };
82 :
83 : template<
84 : typename FunctionObj,
85 : typename R,
86 : typename... T
87 : >
88 : struct void_function_obj_invoker
89 : {
90 : static void
91 815 : invoke(function_buffer& function_obj_ptr,
92 : T... a)
93 :
94 : {
95 : FunctionObj* f;
96 : if (function_allows_small_object_optimization<FunctionObj>::value)
97 372 : f = reinterpret_cast<FunctionObj*>(function_obj_ptr.data);
98 : else
99 443 : f = reinterpret_cast<FunctionObj*>(function_obj_ptr.members.obj_ptr);
100 815 : (*f)(static_cast<T&&>(a)...);
101 815 : }
102 : };
103 :
104 : template<
105 : typename FunctionObj,
106 : typename R,
107 : typename... T
108 : >
109 : struct function_ref_invoker
110 : {
111 : static R invoke(function_buffer& function_obj_ptr,
112 : T... a)
113 :
114 : {
115 : FunctionObj* f =
116 : reinterpret_cast<FunctionObj*>(function_obj_ptr.members.obj_ptr);
117 : return (*f)(static_cast<T&&>(a)...);
118 : }
119 : };
120 :
121 : template<
122 : typename FunctionObj,
123 : typename R,
124 : typename... T
125 : >
126 : struct void_function_ref_invoker
127 : {
128 : static void
129 : invoke(function_buffer& function_obj_ptr,
130 : T... a)
131 :
132 : {
133 : FunctionObj* f =
134 : reinterpret_cast<FunctionObj*>(function_obj_ptr.members.obj_ptr);
135 : (*f)(static_cast<T&&>(a)...);
136 : }
137 : };
138 :
139 : /* Handle invocation of member pointers. */
140 : template<
141 : typename MemberPtr,
142 : typename R,
143 : typename... T
144 : >
145 : struct member_invoker
146 : {
147 : static R invoke(function_buffer& function_obj_ptr,
148 : T... a)
149 :
150 : {
151 : MemberPtr* f =
152 : reinterpret_cast<MemberPtr*>(function_obj_ptr.data);
153 : return boost::mem_fn(*f)(static_cast<T&&>(a)...);
154 : }
155 : };
156 :
157 : template<
158 : typename MemberPtr,
159 : typename R,
160 : typename... T
161 : >
162 : struct void_member_invoker
163 : {
164 : static void
165 : invoke(function_buffer& function_obj_ptr,
166 : T... a)
167 :
168 : {
169 : MemberPtr* f =
170 : reinterpret_cast<MemberPtr*>(function_obj_ptr.data);
171 : boost::mem_fn(*f)(static_cast<T&&>(a)...);
172 : }
173 : };
174 :
175 : template<
176 : typename FunctionPtr,
177 : typename R,
178 : typename... T
179 : >
180 : struct get_function_invoker
181 : {
182 : typedef typename std::conditional<std::is_void<R>::value,
183 : void_function_invoker<
184 : FunctionPtr,
185 : R,
186 : T...
187 : >,
188 : function_invoker<
189 : FunctionPtr,
190 : R,
191 : T...
192 : >
193 : >::type type;
194 : };
195 :
196 : template<
197 : typename FunctionObj,
198 : typename R,
199 : typename... T
200 : >
201 : struct get_function_obj_invoker
202 : {
203 : typedef typename std::conditional<std::is_void<R>::value,
204 : void_function_obj_invoker<
205 : FunctionObj,
206 : R,
207 : T...
208 : >,
209 : function_obj_invoker<
210 : FunctionObj,
211 : R,
212 : T...
213 : >
214 : >::type type;
215 : };
216 :
217 : template<
218 : typename FunctionObj,
219 : typename R,
220 : typename... T
221 : >
222 : struct get_function_ref_invoker
223 : {
224 : typedef typename std::conditional<std::is_void<R>::value,
225 : void_function_ref_invoker<
226 : FunctionObj,
227 : R,
228 : T...
229 : >,
230 : function_ref_invoker<
231 : FunctionObj,
232 : R,
233 : T...
234 : >
235 : >::type type;
236 : };
237 :
238 : /* Retrieve the appropriate invoker for a member pointer. */
239 : template<
240 : typename MemberPtr,
241 : typename R,
242 : typename... T
243 : >
244 : struct get_member_invoker
245 : {
246 : typedef typename std::conditional<std::is_void<R>::value,
247 : void_member_invoker<
248 : MemberPtr,
249 : R,
250 : T...
251 : >,
252 : member_invoker<
253 : MemberPtr,
254 : R,
255 : T...
256 : >
257 : >::type type;
258 : };
259 :
260 : /* Given the tag returned by get_function_tag, retrieve the
261 : actual invoker that will be used for the given function
262 : object.
263 :
264 : Each specialization contains an "apply_" nested class template
265 : that accepts the function object, return type, function
266 : argument types, and allocator. The resulting "apply_" class
267 : contains two typedefs, "invoker_type" and "manager_type",
268 : which correspond to the invoker and manager types. */
269 : template<typename Tag>
270 : struct get_invoker { };
271 :
272 : /* Retrieve the invoker for a function pointer. */
273 : template<>
274 : struct get_invoker<function_ptr_tag>
275 : {
276 : template<typename FunctionPtr,
277 : typename R, typename... T>
278 : struct apply_
279 : {
280 : typedef typename get_function_invoker<
281 : FunctionPtr,
282 : R,
283 : T...
284 : >::type
285 : invoker_type;
286 :
287 : typedef functor_manager<FunctionPtr> manager_type;
288 : };
289 :
290 : template<typename FunctionPtr, typename Allocator,
291 : typename R, typename... T>
292 : struct apply_a
293 : {
294 : typedef typename get_function_invoker<
295 : FunctionPtr,
296 : R,
297 : T...
298 : >::type
299 : invoker_type;
300 :
301 : typedef functor_manager<FunctionPtr> manager_type;
302 : };
303 : };
304 :
305 : /* Retrieve the invoker for a member pointer. */
306 : template<>
307 : struct get_invoker<member_ptr_tag>
308 : {
309 : template<typename MemberPtr,
310 : typename R, typename... T>
311 : struct apply_
312 : {
313 : typedef typename get_member_invoker<
314 : MemberPtr,
315 : R,
316 : T...
317 : >::type
318 : invoker_type;
319 :
320 : typedef functor_manager<MemberPtr> manager_type;
321 : };
322 :
323 : template<typename MemberPtr, typename Allocator,
324 : typename R, typename... T>
325 : struct apply_a
326 : {
327 : typedef typename get_member_invoker<
328 : MemberPtr,
329 : R,
330 : T...
331 : >::type
332 : invoker_type;
333 :
334 : typedef functor_manager<MemberPtr> manager_type;
335 : };
336 : };
337 :
338 : /* Retrieve the invoker for a function object. */
339 : template<>
340 : struct get_invoker<function_obj_tag>
341 : {
342 : template<typename FunctionObj,
343 : typename R, typename... T>
344 : struct apply_
345 : {
346 : typedef typename get_function_obj_invoker<
347 : FunctionObj,
348 : R,
349 : T...
350 : >::type
351 : invoker_type;
352 :
353 : typedef functor_manager<FunctionObj> manager_type;
354 : };
355 :
356 : template<typename FunctionObj, typename Allocator,
357 : typename R, typename... T>
358 : struct apply_a
359 : {
360 : typedef typename get_function_obj_invoker<
361 : FunctionObj,
362 : R,
363 : T...
364 : >::type
365 : invoker_type;
366 :
367 : typedef functor_manager_a<FunctionObj, Allocator> manager_type;
368 : };
369 : };
370 :
371 : /* Retrieve the invoker for a reference to a function object. */
372 : template<>
373 : struct get_invoker<function_obj_ref_tag>
374 : {
375 : template<typename RefWrapper,
376 : typename R, typename... T>
377 : struct apply_
378 : {
379 : typedef typename get_function_ref_invoker<
380 : typename RefWrapper::type,
381 : R,
382 : T...
383 : >::type
384 : invoker_type;
385 :
386 : typedef reference_manager<typename RefWrapper::type> manager_type;
387 : };
388 :
389 : template<typename RefWrapper, typename Allocator,
390 : typename R, typename... T>
391 : struct apply_a
392 : {
393 : typedef typename get_function_ref_invoker<
394 : typename RefWrapper::type,
395 : R,
396 : T...
397 : >::type
398 : invoker_type;
399 :
400 : typedef reference_manager<typename RefWrapper::type> manager_type;
401 : };
402 : };
403 :
404 :
405 : /**
406 : * vtable for a specific boost::function instance. This
407 : * structure must be an aggregate so that we can use static
408 : * initialization in boost::function's assign_to and assign_to_a
409 : * members. It therefore cannot have any constructors,
410 : * destructors, base classes, etc.
411 : */
412 : template<typename R, typename... T>
413 : struct basic_vtable
414 : {
415 : typedef R result_type;
416 :
417 : typedef result_type (*invoker_type)(function_buffer&
418 : ,
419 : T...);
420 :
421 : template<typename F>
422 104519 : bool assign_to(F f, function_buffer& functor) const
423 : {
424 : typedef typename get_function_tag<F>::type tag;
425 104519 : return assign_to(std::move(f), functor, tag());
426 0 : }
427 : template<typename F,typename Allocator>
428 : bool assign_to_a(F f, function_buffer& functor, Allocator a) const
429 : {
430 : typedef typename get_function_tag<F>::type tag;
431 : return assign_to_a(std::move(f), functor, a, tag());
432 : }
433 :
434 103422 : void clear(function_buffer& functor) const
435 : {
436 : #if defined(BOOST_GCC) && (__GNUC__ >= 11)
437 : # pragma GCC diagnostic push
438 : // False positive in GCC 11/12 for empty function objects
439 : # pragma GCC diagnostic ignored "-Wmaybe-uninitialized"
440 : #endif
441 103422 : if (base.manager)
442 103422 : base.manager(functor, functor, destroy_functor_tag);
443 : #if defined(BOOST_GCC) && (__GNUC__ >= 11)
444 : # pragma GCC diagnostic pop
445 : #endif
446 103422 : }
447 :
448 : private:
449 : // Function pointers
450 : template<typename FunctionPtr>
451 : bool
452 101762 : assign_to(FunctionPtr f, function_buffer& functor, function_ptr_tag) const
453 : {
454 101762 : this->clear(functor);
455 101762 : if (f) {
456 101762 : functor.members.func_ptr = reinterpret_cast<void (*)()>(f);
457 101762 : return true;
458 : } else {
459 0 : return false;
460 : }
461 101762 : }
462 : template<typename FunctionPtr,typename Allocator>
463 : bool
464 : assign_to_a(FunctionPtr f, function_buffer& functor, Allocator, function_ptr_tag) const
465 : {
466 : return assign_to(std::move(f),functor,function_ptr_tag());
467 : }
468 :
469 : // Member pointers
470 : template<typename MemberPtr>
471 : bool assign_to(MemberPtr f, function_buffer& functor, member_ptr_tag) const
472 : {
473 : // DPG TBD: Add explicit support for member function
474 : // objects, so we invoke through mem_fn() but we retain the
475 : // right target_type() values.
476 : if (f) {
477 : this->assign_to(boost::mem_fn(f), functor);
478 : return true;
479 : } else {
480 : return false;
481 : }
482 : }
483 : template<typename MemberPtr,typename Allocator>
484 : bool assign_to_a(MemberPtr f, function_buffer& functor, Allocator a, member_ptr_tag) const
485 : {
486 : // DPG TBD: Add explicit support for member function
487 : // objects, so we invoke through mem_fn() but we retain the
488 : // right target_type() values.
489 : if (f) {
490 : this->assign_to_a(boost::mem_fn(f), functor, a);
491 : return true;
492 : } else {
493 : return false;
494 : }
495 : }
496 :
497 : // Function objects
498 : // Assign to a function object using the small object optimization
499 : template<typename FunctionObj>
500 : void
501 1635 : assign_functor(FunctionObj f, function_buffer& functor, std::true_type) const
502 : {
503 1635 : new (reinterpret_cast<void*>(functor.data)) FunctionObj(std::move(f));
504 1635 : }
505 : template<typename FunctionObj,typename Allocator>
506 : void
507 : assign_functor_a(FunctionObj f, function_buffer& functor, Allocator, std::true_type) const
508 : {
509 : assign_functor(std::move(f),functor,std::true_type());
510 : }
511 :
512 : // Assign to a function object allocated on the heap.
513 : template<typename FunctionObj>
514 : void
515 1122 : assign_functor(FunctionObj f, function_buffer& functor, std::false_type) const
516 : {
517 1122 : functor.members.obj_ptr = new FunctionObj(std::move(f));
518 1122 : }
519 : template<typename FunctionObj,typename Allocator>
520 : void
521 : assign_functor_a(FunctionObj f, function_buffer& functor, Allocator a, std::false_type) const
522 : {
523 : typedef functor_wrapper<FunctionObj,Allocator> functor_wrapper_type;
524 :
525 : using wrapper_allocator_type = typename std::allocator_traits<Allocator>::template rebind_alloc<functor_wrapper_type>;
526 : using wrapper_allocator_pointer_type = typename std::allocator_traits<wrapper_allocator_type>::pointer;
527 :
528 : wrapper_allocator_type wrapper_allocator(a);
529 : wrapper_allocator_pointer_type copy = wrapper_allocator.allocate(1);
530 : std::allocator_traits<wrapper_allocator_type>::construct(wrapper_allocator, copy, functor_wrapper_type(f,a));
531 :
532 : functor_wrapper_type* new_f = static_cast<functor_wrapper_type*>(copy);
533 : functor.members.obj_ptr = new_f;
534 : }
535 :
536 : template<typename FunctionObj>
537 : bool
538 2757 : assign_to(FunctionObj f, function_buffer& functor, function_obj_tag) const
539 : {
540 2757 : if (!boost::detail::function::has_empty_target(boost::addressof(f))) {
541 2757 : assign_functor(std::move(f), functor,
542 : std::integral_constant<bool, (function_allows_small_object_optimization<FunctionObj>::value)>());
543 2757 : return true;
544 : } else {
545 0 : return false;
546 : }
547 2757 : }
548 : template<typename FunctionObj,typename Allocator>
549 : bool
550 : assign_to_a(FunctionObj f, function_buffer& functor, Allocator a, function_obj_tag) const
551 : {
552 : if (!boost::detail::function::has_empty_target(boost::addressof(f))) {
553 : assign_functor_a(std::move(f), functor, a,
554 : std::integral_constant<bool, (function_allows_small_object_optimization<FunctionObj>::value)>());
555 : return true;
556 : } else {
557 : return false;
558 : }
559 : }
560 :
561 : // Reference to a function object
562 : template<typename FunctionObj>
563 : bool
564 : assign_to(const reference_wrapper<FunctionObj>& f,
565 : function_buffer& functor, function_obj_ref_tag) const
566 : {
567 : functor.members.obj_ref.obj_ptr = (void *)(f.get_pointer());
568 : functor.members.obj_ref.is_const_qualified = std::is_const<FunctionObj>::value;
569 : functor.members.obj_ref.is_volatile_qualified = std::is_volatile<FunctionObj>::value;
570 : return true;
571 : }
572 : template<typename FunctionObj,typename Allocator>
573 : bool
574 : assign_to_a(const reference_wrapper<FunctionObj>& f,
575 : function_buffer& functor, Allocator, function_obj_ref_tag) const
576 : {
577 : return assign_to(f,functor,function_obj_ref_tag());
578 : }
579 :
580 : public:
581 : vtable_base base;
582 : invoker_type invoker;
583 : };
584 :
585 : template <typename... T>
586 : struct variadic_function_base
587 : {};
588 :
589 : template <typename T1>
590 : struct variadic_function_base<T1>
591 : {
592 : typedef T1 argument_type;
593 : typedef T1 arg1_type;
594 : };
595 :
596 : template <typename T1, typename T2>
597 : struct variadic_function_base<T1, T2>
598 : {
599 : typedef T1 first_argument_type;
600 : typedef T2 second_argument_type;
601 : typedef T1 arg1_type;
602 : typedef T2 arg2_type;
603 : };
604 :
605 : template <typename T1, typename T2, typename T3>
606 : struct variadic_function_base<T1, T2, T3>
607 : {
608 : typedef T1 arg1_type;
609 : typedef T2 arg2_type;
610 : typedef T3 arg3_type;
611 : };
612 :
613 : template <typename T1, typename T2, typename T3, typename T4>
614 : struct variadic_function_base<T1, T2, T3, T4>
615 : {
616 : typedef T1 arg1_type;
617 : typedef T2 arg2_type;
618 : typedef T3 arg3_type;
619 : typedef T4 arg4_type;
620 : };
621 :
622 : template <typename T1, typename T2, typename T3, typename T4, typename T5>
623 : struct variadic_function_base<T1, T2, T3, T4, T5>
624 : {
625 : typedef T1 arg1_type;
626 : typedef T2 arg2_type;
627 : typedef T3 arg3_type;
628 : typedef T4 arg4_type;
629 : typedef T5 arg5_type;
630 : };
631 :
632 : template <typename T1, typename T2, typename T3, typename T4, typename T5, typename T6>
633 : struct variadic_function_base<T1, T2, T3, T4, T5, T6>
634 : {
635 : typedef T1 arg1_type;
636 : typedef T2 arg2_type;
637 : typedef T3 arg3_type;
638 : typedef T4 arg4_type;
639 : typedef T5 arg5_type;
640 : typedef T6 arg6_type;
641 : };
642 :
643 : template <typename T1, typename T2, typename T3, typename T4, typename T5, typename T6, typename T7>
644 : struct variadic_function_base<T1, T2, T3, T4, T5, T6, T7>
645 : {
646 : typedef T1 arg1_type;
647 : typedef T2 arg2_type;
648 : typedef T3 arg3_type;
649 : typedef T4 arg4_type;
650 : typedef T5 arg5_type;
651 : typedef T6 arg6_type;
652 : typedef T7 arg7_type;
653 : };
654 :
655 : template <typename T1, typename T2, typename T3, typename T4, typename T5, typename T6, typename T7, typename T8>
656 : struct variadic_function_base<T1, T2, T3, T4, T5, T6, T7, T8>
657 : {
658 : typedef T1 arg1_type;
659 : typedef T2 arg2_type;
660 : typedef T3 arg3_type;
661 : typedef T4 arg4_type;
662 : typedef T5 arg5_type;
663 : typedef T6 arg6_type;
664 : typedef T7 arg7_type;
665 : typedef T8 arg8_type;
666 : };
667 :
668 : template <typename T1, typename T2, typename T3, typename T4, typename T5, typename T6, typename T7, typename T8, typename T9>
669 : struct variadic_function_base<T1, T2, T3, T4, T5, T6, T7, T8, T9>
670 : {
671 : typedef T1 arg1_type;
672 : typedef T2 arg2_type;
673 : typedef T3 arg3_type;
674 : typedef T4 arg4_type;
675 : typedef T5 arg5_type;
676 : typedef T6 arg6_type;
677 : typedef T7 arg7_type;
678 : typedef T8 arg8_type;
679 : typedef T9 arg9_type;
680 : };
681 :
682 : template <typename T1, typename T2, typename T3, typename T4, typename T5, typename T6, typename T7, typename T8, typename T9, typename T10>
683 : struct variadic_function_base<T1, T2, T3, T4, T5, T6, T7, T8, T9, T10>
684 : {
685 : typedef T1 arg1_type;
686 : typedef T2 arg2_type;
687 : typedef T3 arg3_type;
688 : typedef T4 arg4_type;
689 : typedef T5 arg5_type;
690 : typedef T6 arg6_type;
691 : typedef T7 arg7_type;
692 : typedef T8 arg8_type;
693 : typedef T9 arg9_type;
694 : typedef T10 arg10_type;
695 : };
696 :
697 : #if defined( BOOST_LIBSTDCXX_VERSION ) && BOOST_LIBSTDCXX_VERSION < 50000
698 :
699 : template<class T> struct is_trivially_copyable: std::integral_constant<bool,
700 : __has_trivial_copy(T) && __has_trivial_assign(T) && __has_trivial_destructor(T)> {};
701 :
702 : #else
703 :
704 : using std::is_trivially_copyable;
705 :
706 : #endif
707 :
708 : } // end namespace function
709 : } // end namespace detail
710 :
711 : template<
712 : typename R,
713 : typename... T
714 : >
715 : class function_n : public function_base
716 : , public detail::function::variadic_function_base<T...>
717 : {
718 : public:
719 : typedef R result_type;
720 :
721 : private:
722 : typedef boost::detail::function::basic_vtable<
723 : R, T...>
724 : vtable_type;
725 :
726 6661 : vtable_type* get_vtable() const {
727 6661 : return reinterpret_cast<vtable_type*>(
728 6661 : reinterpret_cast<std::size_t>(vtable) & ~static_cast<std::size_t>(0x01));
729 : }
730 :
731 : struct clear_type {};
732 :
733 : public:
734 : // add signature for boost::lambda
735 : template<typename Args>
736 : struct sig
737 : {
738 : typedef result_type type;
739 : };
740 :
741 : BOOST_STATIC_CONSTANT(int, arity = sizeof...(T));
742 :
743 : typedef function_n self_type;
744 :
745 6661 : BOOST_DEFAULTED_FUNCTION(function_n(), : function_base() {})
746 :
747 : // MSVC chokes if the following two constructors are collapsed into
748 : // one with a default parameter.
749 : template<typename Functor>
750 104519 : function_n(Functor f
751 : ,typename std::enable_if<
752 : !std::is_integral<Functor>::value,
753 : int>::type = 0
754 : ) :
755 104519 : function_base()
756 : {
757 104519 : this->assign_to(std::move(f));
758 104519 : }
759 : template<typename Functor,typename Allocator>
760 : function_n(Functor f, Allocator a
761 : ,typename std::enable_if<
762 : !std::is_integral<Functor>::value,
763 : int>::type = 0
764 : ) :
765 : function_base()
766 : {
767 : this->assign_to_a(std::move(f),a);
768 : }
769 :
770 : function_n(clear_type*) : function_base() { }
771 :
772 106562 : function_n(const function_n& f) : function_base()
773 : {
774 106562 : this->assign_to_own(f);
775 106562 : }
776 :
777 4088 : function_n(function_n&& f) : function_base()
778 : {
779 4088 : this->move_assign(f);
780 4088 : }
781 :
782 115631 : ~function_n() { clear(); }
783 :
784 2865 : result_type operator()(T... a) const
785 : {
786 2865 : if (this->empty())
787 0 : boost::throw_exception(bad_function_call());
788 :
789 5730 : return get_vtable()->invoker
790 2865 : (this->functor, static_cast<T&&>(a)...);
791 0 : }
792 :
793 : // The distinction between when to use function_n and
794 : // when to use self_type is obnoxious. MSVC cannot handle self_type as
795 : // the return type of these assignment operators, but Borland C++ cannot
796 : // handle function_n as the type of the temporary to
797 : // construct.
798 : template<typename Functor>
799 : typename std::enable_if<
800 : !std::is_integral<Functor>::value,
801 : function_n&>::type
802 : operator=(Functor f)
803 : {
804 : this->clear();
805 : BOOST_TRY {
806 : this->assign_to(f);
807 : } BOOST_CATCH (...) {
808 : vtable = 0;
809 : BOOST_RETHROW;
810 : }
811 : BOOST_CATCH_END
812 : return *this;
813 : }
814 : template<typename Functor,typename Allocator>
815 : void assign(Functor f, Allocator a)
816 : {
817 : this->clear();
818 : BOOST_TRY{
819 : this->assign_to_a(f,a);
820 : } BOOST_CATCH (...) {
821 : vtable = 0;
822 : BOOST_RETHROW;
823 : }
824 : BOOST_CATCH_END
825 : }
826 :
827 : function_n& operator=(clear_type*)
828 : {
829 : this->clear();
830 : return *this;
831 : }
832 :
833 : // Assignment from another function_n
834 : function_n& operator=(const function_n& f)
835 : {
836 : if (&f == this)
837 : return *this;
838 :
839 : this->clear();
840 : BOOST_TRY {
841 : this->assign_to_own(f);
842 : } BOOST_CATCH (...) {
843 : vtable = 0;
844 : BOOST_RETHROW;
845 : }
846 : BOOST_CATCH_END
847 : return *this;
848 : }
849 :
850 : // Move assignment from another function_n
851 : function_n& operator=(function_n&& f)
852 : {
853 : if (&f == this)
854 : return *this;
855 :
856 : this->clear();
857 : BOOST_TRY {
858 : this->move_assign(f);
859 : } BOOST_CATCH (...) {
860 : vtable = 0;
861 : BOOST_RETHROW;
862 : }
863 : BOOST_CATCH_END
864 : return *this;
865 : }
866 :
867 858 : void swap(function_n& other)
868 : {
869 858 : if (&other == this)
870 0 : return;
871 :
872 858 : function_n tmp;
873 858 : tmp.move_assign(*this);
874 858 : this->move_assign(other);
875 858 : other.move_assign(tmp);
876 858 : }
877 :
878 : // Clear out a target, if there is one
879 119573 : void clear()
880 : {
881 119573 : if (vtable) {
882 104882 : if (!this->has_trivial_copy_and_destroy())
883 1660 : get_vtable()->clear(this->functor);
884 104882 : vtable = 0;
885 104882 : }
886 119573 : }
887 :
888 3503 : explicit operator bool () const { return !this->empty(); }
889 :
890 : private:
891 106562 : void assign_to_own(const function_n& f)
892 : {
893 106562 : if (!f.empty()) {
894 102620 : this->vtable = f.vtable;
895 102620 : if (this->has_trivial_copy_and_destroy()) {
896 : // Don't operate on storage directly since union type doesn't relax
897 : // strict aliasing rules, despite of having member char type.
898 : # if defined(BOOST_GCC) && (BOOST_GCC >= 40700)
899 : # pragma GCC diagnostic push
900 : // This warning is technically correct, but we don't want to pay the price for initializing
901 : // just to silence a warning: https://github.com/boostorg/function/issues/27
902 : # pragma GCC diagnostic ignored "-Wmaybe-uninitialized"
903 : # if (BOOST_GCC >= 110000)
904 : // GCC 11.3, 12 emit a different warning: https://github.com/boostorg/function/issues/42
905 : # pragma GCC diagnostic ignored "-Wuninitialized"
906 : # endif
907 : # endif
908 101908 : std::memcpy(this->functor.data, f.functor.data, sizeof(boost::detail::function::function_buffer));
909 : # if defined(BOOST_GCC) && (BOOST_GCC >= 40700)
910 : # pragma GCC diagnostic pop
911 : # endif
912 101908 : } else
913 712 : get_vtable()->base.manager(f.functor, this->functor,
914 : boost::detail::function::clone_functor_tag);
915 102620 : }
916 106562 : }
917 :
918 : template<typename Functor>
919 104519 : void assign_to(Functor f)
920 : {
921 : using boost::detail::function::vtable_base;
922 :
923 : typedef typename boost::detail::function::get_function_tag<Functor>::type tag;
924 : typedef boost::detail::function::get_invoker<tag> get_invoker;
925 : typedef typename get_invoker::
926 : template apply_<Functor, R,
927 : T...>
928 : handler_type;
929 :
930 : typedef typename handler_type::invoker_type invoker_type;
931 : typedef typename handler_type::manager_type manager_type;
932 :
933 : // Note: it is extremely important that this initialization use
934 : // static initialization. Otherwise, we will have a race
935 : // condition here in multi-threaded code. See
936 : // http://thread.gmane.org/gmane.comp.lib.boost.devel/164902/.
937 : static const vtable_type stored_vtable =
938 : { { &manager_type::manage }, &invoker_type::invoke };
939 :
940 104519 : if (stored_vtable.assign_to(std::move(f), functor)) {
941 104519 : std::size_t value = reinterpret_cast<std::size_t>(&stored_vtable.base);
942 : // coverity[pointless_expression]: suppress coverity warnings on apparant if(const).
943 : if (boost::detail::function::is_trivially_copyable<Functor>::value &&
944 : boost::detail::function::function_allows_small_object_optimization<Functor>::value)
945 103223 : value |= static_cast<std::size_t>(0x01);
946 104519 : vtable = reinterpret_cast<boost::detail::function::vtable_base *>(value);
947 104519 : } else
948 0 : vtable = 0;
949 104519 : }
950 :
951 : template<typename Functor,typename Allocator>
952 : void assign_to_a(Functor f,Allocator a)
953 : {
954 : using boost::detail::function::vtable_base;
955 :
956 : typedef typename boost::detail::function::get_function_tag<Functor>::type tag;
957 : typedef boost::detail::function::get_invoker<tag> get_invoker;
958 : typedef typename get_invoker::
959 : template apply_a<Functor, Allocator, R,
960 : T...>
961 : handler_type;
962 :
963 : typedef typename handler_type::invoker_type invoker_type;
964 : typedef typename handler_type::manager_type manager_type;
965 :
966 : // Note: it is extremely important that this initialization use
967 : // static initialization. Otherwise, we will have a race
968 : // condition here in multi-threaded code. See
969 : // http://thread.gmane.org/gmane.comp.lib.boost.devel/164902/.
970 : static const vtable_type stored_vtable =
971 : { { &manager_type::manage }, &invoker_type::invoke };
972 :
973 : if (stored_vtable.assign_to_a(std::move(f), functor, a)) {
974 : std::size_t value = reinterpret_cast<std::size_t>(&stored_vtable.base);
975 : // coverity[pointless_expression]: suppress coverity warnings on apparant if(const).
976 : if (boost::detail::function::is_trivially_copyable<Functor>::value &&
977 : boost::detail::function::function_allows_small_object_optimization<Functor>::value)
978 : value |= static_cast<std::size_t>(0x01);
979 : vtable = reinterpret_cast<boost::detail::function::vtable_base *>(value);
980 : } else
981 : vtable = 0;
982 : }
983 :
984 : // Moves the value from the specified argument to *this. If the argument
985 : // has its function object allocated on the heap, move_assign will pass
986 : // its buffer to *this, and set the argument's buffer pointer to NULL.
987 6662 : void move_assign(function_n& f)
988 : {
989 6662 : if (&f == this)
990 0 : return;
991 :
992 : BOOST_TRY {
993 6662 : if (!f.empty()) {
994 1862 : this->vtable = f.vtable;
995 1862 : if (this->has_trivial_copy_and_destroy()) {
996 : // Don't operate on storage directly since union type doesn't relax
997 : // strict aliasing rules, despite of having member char type.
998 : # if defined(BOOST_GCC) && (BOOST_GCC >= 40700)
999 : # pragma GCC diagnostic push
1000 : // This warning is technically correct, but we don't want to pay the price for initializing
1001 : // just to silence a warning: https://github.com/boostorg/function/issues/27
1002 : # pragma GCC diagnostic ignored "-Wmaybe-uninitialized"
1003 : # if (BOOST_GCC >= 120000)
1004 : // GCC 12 emits a different warning: https://github.com/boostorg/function/issues/42
1005 : # pragma GCC diagnostic ignored "-Wuninitialized"
1006 : # endif
1007 : # endif
1008 438 : std::memcpy(this->functor.data, f.functor.data, sizeof(this->functor.data));
1009 : # if defined(BOOST_GCC) && (BOOST_GCC >= 40700)
1010 : # pragma GCC diagnostic pop
1011 : # endif
1012 438 : } else
1013 : #if defined(BOOST_GCC) && (__GNUC__ >= 11)
1014 : # pragma GCC diagnostic push
1015 : // False positive in GCC 11/12 for empty function objects (function_n_test.cpp:673)
1016 : # pragma GCC diagnostic ignored "-Wmaybe-uninitialized"
1017 : #endif
1018 1424 : get_vtable()->base.manager(f.functor, this->functor,
1019 : boost::detail::function::move_functor_tag);
1020 : #if defined(BOOST_GCC) && (__GNUC__ >= 11)
1021 : # pragma GCC diagnostic pop
1022 : #endif
1023 1862 : f.vtable = 0;
1024 1862 : } else {
1025 4800 : clear();
1026 : }
1027 6662 : } BOOST_CATCH (...) {
1028 0 : vtable = 0;
1029 0 : BOOST_RETHROW;
1030 0 : }
1031 : BOOST_CATCH_END
1032 6662 : }
1033 : };
1034 :
1035 : template<typename R, typename... T>
1036 : inline void swap(function_n<
1037 : R,
1038 : T...
1039 : >& f1,
1040 : function_n<
1041 : R,
1042 : T...
1043 : >& f2)
1044 : {
1045 : f1.swap(f2);
1046 : }
1047 :
1048 : // Poison comparisons between boost::function objects of the same type.
1049 : template<typename R, typename... T>
1050 : void operator==(const function_n<
1051 : R,
1052 : T...>&,
1053 : const function_n<
1054 : R,
1055 : T...>&);
1056 : template<typename R, typename... T>
1057 : void operator!=(const function_n<
1058 : R,
1059 : T...>&,
1060 : const function_n<
1061 : R,
1062 : T...>& );
1063 :
1064 : template<typename R,
1065 : typename... T>
1066 : class function<R (T...)>
1067 : : public function_n<R, T...>
1068 : {
1069 : typedef function_n<R, T...> base_type;
1070 : typedef function self_type;
1071 :
1072 : struct clear_type {};
1073 :
1074 : public:
1075 :
1076 9890 : BOOST_DEFAULTED_FUNCTION(function(), : base_type() {})
1077 :
1078 : template<typename Functor>
1079 209038 : function(Functor f
1080 : ,typename std::enable_if<
1081 : !std::is_integral<Functor>::value,
1082 : int>::type = 0
1083 : ) :
1084 104519 : base_type(std::move(f))
1085 104519 : {
1086 209038 : }
1087 : template<typename Functor,typename Allocator>
1088 : function(Functor f, Allocator a
1089 : ,typename std::enable_if<
1090 : !std::is_integral<Functor>::value,
1091 : int>::type = 0
1092 : ) :
1093 : base_type(std::move(f),a)
1094 : {
1095 : }
1096 :
1097 : function(clear_type*) : base_type() {}
1098 :
1099 213124 : function(const self_type& f) : base_type(static_cast<const base_type&>(f)){}
1100 :
1101 : function(const base_type& f) : base_type(static_cast<const base_type&>(f)){}
1102 :
1103 : // Move constructors
1104 8176 : function(self_type&& f): base_type(static_cast<base_type&&>(f)){}
1105 : function(base_type&& f): base_type(static_cast<base_type&&>(f)){}
1106 :
1107 : self_type& operator=(const self_type& f)
1108 : {
1109 : self_type(f).swap(*this);
1110 : return *this;
1111 : }
1112 :
1113 : self_type& operator=(self_type&& f)
1114 : {
1115 : self_type(static_cast<self_type&&>(f)).swap(*this);
1116 : return *this;
1117 : }
1118 :
1119 : template<typename Functor>
1120 : typename std::enable_if<
1121 : !std::is_integral<Functor>::value,
1122 : self_type&>::type
1123 858 : operator=(Functor f)
1124 : {
1125 858 : self_type(f).swap(*this);
1126 858 : return *this;
1127 0 : }
1128 :
1129 : self_type& operator=(clear_type*)
1130 : {
1131 : this->clear();
1132 : return *this;
1133 : }
1134 :
1135 : self_type& operator=(const base_type& f)
1136 : {
1137 : self_type(f).swap(*this);
1138 : return *this;
1139 : }
1140 :
1141 : self_type& operator=(base_type&& f)
1142 : {
1143 : self_type(static_cast<base_type&&>(f)).swap(*this);
1144 : return *this;
1145 : }
1146 : };
1147 :
1148 : } // end namespace boost
1149 :
1150 : #if defined(BOOST_MSVC)
1151 : # pragma warning( pop )
1152 : #endif
1153 :
1154 : // Resolve C++20 issue with fn == bind(...)
1155 : // https://github.com/boostorg/function/issues/45
1156 :
1157 : namespace boost
1158 : {
1159 :
1160 : namespace _bi
1161 : {
1162 :
1163 : template<class R, class F, class L> class bind_t;
1164 :
1165 : } // namespace _bi
1166 :
1167 : template<class S, class R, class F, class L> bool operator==( function<S> const& f, _bi::bind_t<R, F, L> const& b )
1168 : {
1169 : return f.contains( b );
1170 : }
1171 :
1172 : template<class S, class R, class F, class L> bool operator!=( function<S> const& f, _bi::bind_t<R, F, L> const& b )
1173 : {
1174 : return !f.contains( b );
1175 : }
1176 :
1177 : } // namespace boost
1178 :
1179 : #endif // #ifndef BOOST_FUNCTION_FUNCTION_TEMPLATE_HPP_INCLUDED
|