1 // Boost.Function library
3 // Copyright (C) 2001 Doug Gregor (gregod@cs.rpi.edu)
5 // Permission to copy, use, sell and distribute this software is granted
6 // provided this copyright notice appears in all copies.
7 // Permission to modify the code and to distribute modified code is granted
8 // provided this copyright notice appears in all copies, and a notice
9 // that the code was modified is included with the copyright notice.
11 // This software is provided "as is" without express or implied warranty,
12 // and with no claim as to its suitability for any purpose.
14 // For more information, see http://www.boost.org
16 // Note: this header is a header template and must NOT have multiple-inclusion
19 #ifndef BOOST_FUNCTION_FUNCTION_TEMPLATE_HPP
20 #define BOOST_FUNCTION_FUNCTION_TEMPLATE_HPP
23 # include <boost/config.hpp>
24 # include <boost/function/function_base.hpp>
25 # include <boost/mem_fn.hpp>
26 #endif // BOOST_FUNCTION_FUNCTION_TEMPLATE_HPP
28 // Type of the default allocator
29 #ifndef BOOST_NO_STD_ALLOCATOR
30 # define BOOST_FUNCTION_DEFAULT_ALLOCATOR std::allocator<function_base>
32 # define BOOST_FUNCTION_DEFAULT_ALLOCATOR int
33 #endif // BOOST_NO_STD_ALLOCATOR
35 // Comma if nonzero number of arguments
36 #if BOOST_FUNCTION_NUM_ARGS == 0
37 # define BOOST_FUNCTION_COMMA
39 # define BOOST_FUNCTION_COMMA ,
40 #endif // BOOST_FUNCTION_NUM_ARGS > 0
42 // Class names used in this version of the code
43 #define BOOST_FUNCTION_FUNCTION BOOST_JOIN(function,BOOST_FUNCTION_NUM_ARGS)
44 #define BOOST_FUNCTION_FUNCTION_INVOKER \
45 BOOST_JOIN(function_invoker,BOOST_FUNCTION_NUM_ARGS)
46 #define BOOST_FUNCTION_VOID_FUNCTION_INVOKER \
47 BOOST_JOIN(void_function_invoker,BOOST_FUNCTION_NUM_ARGS)
48 #define BOOST_FUNCTION_FUNCTION_OBJ_INVOKER \
49 BOOST_JOIN(function_obj_invoker,BOOST_FUNCTION_NUM_ARGS)
50 #define BOOST_FUNCTION_VOID_FUNCTION_OBJ_INVOKER \
51 BOOST_JOIN(void_function_obj_invoker,BOOST_FUNCTION_NUM_ARGS)
52 #define BOOST_FUNCTION_STATELESS_FUNCTION_OBJ_INVOKER \
53 BOOST_JOIN(stateless_function_obj_invoker,BOOST_FUNCTION_NUM_ARGS)
54 #define BOOST_FUNCTION_STATELESS_VOID_FUNCTION_OBJ_INVOKER \
55 BOOST_JOIN(stateless_void_function_obj_invoker,BOOST_FUNCTION_NUM_ARGS)
56 #define BOOST_FUNCTION_GET_FUNCTION_INVOKER \
57 BOOST_JOIN(get_function_invoker,BOOST_FUNCTION_NUM_ARGS)
58 #define BOOST_FUNCTION_GET_FUNCTION_OBJ_INVOKER \
59 BOOST_JOIN(get_function_obj_invoker,BOOST_FUNCTION_NUM_ARGS)
60 #define BOOST_FUNCTION_GET_STATELESS_FUNCTION_OBJ_INVOKER \
61 BOOST_JOIN(get_stateless_function_obj_invoker,BOOST_FUNCTION_NUM_ARGS)
68 typename R BOOST_FUNCTION_COMMA
69 BOOST_FUNCTION_TEMPLATE_PARMS
71 struct BOOST_FUNCTION_FUNCTION_INVOKER
73 static R invoke(any_pointer function_ptr BOOST_FUNCTION_COMMA
76 FunctionPtr f = reinterpret_cast<FunctionPtr>(function_ptr.func_ptr);
77 return f(BOOST_FUNCTION_ARGS);
83 typename R BOOST_FUNCTION_COMMA
84 BOOST_FUNCTION_TEMPLATE_PARMS
86 struct BOOST_FUNCTION_VOID_FUNCTION_INVOKER
88 static unusable invoke(any_pointer function_ptr BOOST_FUNCTION_COMMA
92 FunctionPtr f = reinterpret_cast<FunctionPtr>(function_ptr.func_ptr);
93 f(BOOST_FUNCTION_ARGS);
100 typename R BOOST_FUNCTION_COMMA
101 BOOST_FUNCTION_TEMPLATE_PARMS
103 struct BOOST_FUNCTION_FUNCTION_OBJ_INVOKER
105 static R invoke(any_pointer function_obj_ptr BOOST_FUNCTION_COMMA
106 BOOST_FUNCTION_PARMS)
109 FunctionObj* f = (FunctionObj*)(function_obj_ptr.obj_ptr);
110 return (*f)(BOOST_FUNCTION_ARGS);
115 typename FunctionObj,
116 typename R BOOST_FUNCTION_COMMA
117 BOOST_FUNCTION_TEMPLATE_PARMS
119 struct BOOST_FUNCTION_VOID_FUNCTION_OBJ_INVOKER
121 static unusable invoke(any_pointer function_obj_ptr
123 BOOST_FUNCTION_PARMS)
126 FunctionObj* f = (FunctionObj*)(function_obj_ptr.obj_ptr);
127 (*f)(BOOST_FUNCTION_ARGS);
133 typename FunctionObj,
134 typename R BOOST_FUNCTION_COMMA
135 BOOST_FUNCTION_TEMPLATE_PARMS
137 struct BOOST_FUNCTION_STATELESS_FUNCTION_OBJ_INVOKER
139 static R invoke(any_pointer BOOST_FUNCTION_COMMA BOOST_FUNCTION_PARMS)
141 FunctionObj f = FunctionObj();
142 return f(BOOST_FUNCTION_ARGS);
147 typename FunctionObj,
148 typename R BOOST_FUNCTION_COMMA
149 BOOST_FUNCTION_TEMPLATE_PARMS
151 struct BOOST_FUNCTION_STATELESS_VOID_FUNCTION_OBJ_INVOKER
153 static unusable invoke(any_pointer BOOST_FUNCTION_COMMA
154 BOOST_FUNCTION_PARMS)
157 FunctionObj f = FunctionObj();
158 f(BOOST_FUNCTION_ARGS);
164 typename FunctionPtr,
165 typename R BOOST_FUNCTION_COMMA
166 BOOST_FUNCTION_TEMPLATE_PARMS
168 struct BOOST_FUNCTION_GET_FUNCTION_INVOKER
170 typedef typename ct_if<(is_void<R>::value),
171 BOOST_FUNCTION_VOID_FUNCTION_INVOKER<
173 R BOOST_FUNCTION_COMMA
174 BOOST_FUNCTION_TEMPLATE_ARGS
176 BOOST_FUNCTION_FUNCTION_INVOKER<
178 R BOOST_FUNCTION_COMMA
179 BOOST_FUNCTION_TEMPLATE_ARGS
185 typename FunctionObj,
186 typename R BOOST_FUNCTION_COMMA
187 BOOST_FUNCTION_TEMPLATE_PARMS
189 struct BOOST_FUNCTION_GET_FUNCTION_OBJ_INVOKER
191 typedef typename ct_if<(is_void<R>::value),
192 BOOST_FUNCTION_VOID_FUNCTION_OBJ_INVOKER<
194 R BOOST_FUNCTION_COMMA
195 BOOST_FUNCTION_TEMPLATE_ARGS
197 BOOST_FUNCTION_FUNCTION_OBJ_INVOKER<
199 R BOOST_FUNCTION_COMMA
200 BOOST_FUNCTION_TEMPLATE_ARGS
206 typename FunctionObj,
207 typename R BOOST_FUNCTION_COMMA
208 BOOST_FUNCTION_TEMPLATE_PARMS
210 struct BOOST_FUNCTION_GET_STATELESS_FUNCTION_OBJ_INVOKER
212 typedef typename ct_if<(is_void<R>::value),
213 BOOST_FUNCTION_STATELESS_VOID_FUNCTION_OBJ_INVOKER<
215 R BOOST_FUNCTION_COMMA
216 BOOST_FUNCTION_TEMPLATE_ARGS
218 BOOST_FUNCTION_STATELESS_FUNCTION_OBJ_INVOKER<
220 R BOOST_FUNCTION_COMMA
221 BOOST_FUNCTION_TEMPLATE_ARGS
226 } // end namespace function
227 } // end namespace detail
230 typename R BOOST_FUNCTION_COMMA
231 BOOST_FUNCTION_TEMPLATE_PARMS,
232 typename Policy = empty_function_policy,
233 typename Mixin = empty_function_mixin,
234 typename Allocator = BOOST_FUNCTION_DEFAULT_ALLOCATOR
236 class BOOST_FUNCTION_FUNCTION : public function_base, public Mixin
238 typedef typename detail::function::function_return_type<R>::type
239 internal_result_type;
242 BOOST_STATIC_CONSTANT(int, args = BOOST_FUNCTION_NUM_ARGS);
244 #if BOOST_FUNCTION_NUM_ARGS == 1
245 typedef T0 argument_type;
246 #elif BOOST_FUNCTION_NUM_ARGS == 2
247 typedef T0 first_argument_type;
248 typedef T1 second_argument_type;
251 #ifndef BOOST_NO_VOID_RETURNS
252 typedef R result_type;
254 typedef internal_result_type result_type;
255 #endif // BOOST_NO_VOID_RETURNS
256 typedef Policy policy_type;
257 typedef Mixin mixin_type;
258 typedef Allocator allocator_type;
259 typedef BOOST_FUNCTION_FUNCTION self_type;
261 BOOST_FUNCTION_FUNCTION() : function_base(), Mixin(), invoker(0) {}
263 explicit BOOST_FUNCTION_FUNCTION(const Mixin& m) :
264 function_base(), Mixin(m), invoker(0)
268 // MSVC chokes if the following two constructors are collapsed into
269 // one with a default parameter.
270 template<typename Functor>
271 BOOST_FUNCTION_FUNCTION(Functor BOOST_FUNCTION_TARGET_FIX(const &) f) :
272 function_base(), Mixin(), invoker(0)
277 template<typename Functor>
278 BOOST_FUNCTION_FUNCTION(Functor f, const Mixin& m) :
279 function_base(), Mixin(m), invoker(0)
284 BOOST_FUNCTION_FUNCTION(const BOOST_FUNCTION_FUNCTION& f) :
285 function_base(), Mixin(static_cast<const Mixin&>(f)), invoker(0)
287 this->assign_to_own(f);
290 ~BOOST_FUNCTION_FUNCTION() { clear(); }
292 result_type operator()(BOOST_FUNCTION_PARMS) const
294 assert(!this->empty());
297 policy.precall(this);
299 internal_result_type result = invoker(function_base::functor
301 BOOST_FUNCTION_ARGS);
303 policy.postcall(this);
304 #ifndef BOOST_NO_VOID_RETURNS
305 return static_cast<result_type>(result);
308 #endif // BOOST_NO_VOID_RETURNS
311 // The distinction between when to use BOOST_FUNCTION_FUNCTION and
312 // when to use self_type is obnoxious. MSVC cannot handle self_type as
313 // the return type of these assignment operators, but Borland C++ cannot
314 // handle BOOST_FUNCTION_FUNCTION as the type of the temporary to
316 template<typename Functor>
317 BOOST_FUNCTION_FUNCTION&
318 operator=(Functor BOOST_FUNCTION_TARGET_FIX(const &) f)
320 self_type(f, static_cast<const Mixin&>(*this)).swap(*this);
324 template<typename Functor>
325 void set(Functor BOOST_FUNCTION_TARGET_FIX(const &) f)
327 self_type(f, static_cast<const Mixin&>(*this)).swap(*this);
330 // Assignment from another BOOST_FUNCTION_FUNCTION
331 BOOST_FUNCTION_FUNCTION& operator=(const BOOST_FUNCTION_FUNCTION& f)
336 self_type(f).swap(*this);
340 // Assignment from another BOOST_FUNCTION_FUNCTION
341 void set(const BOOST_FUNCTION_FUNCTION& f)
346 self_type(f).swap(*this);
349 void swap(BOOST_FUNCTION_FUNCTION& other)
354 std::swap(function_base::manager, other.manager);
355 std::swap(function_base::functor, other.functor);
356 std::swap(invoker, other.invoker);
357 std::swap(static_cast<Mixin&>(*this), static_cast<Mixin&>(other));
360 // Clear out a target, if there is one
363 if (function_base::manager) {
364 function_base::functor =
365 function_base::manager(function_base::functor,
366 detail::function::destroy_functor_tag);
369 function_base::manager = 0;
374 void assign_to_own(const BOOST_FUNCTION_FUNCTION& f)
378 function_base::manager = f.manager;
379 function_base::functor =
380 f.manager(f.functor, detail::function::clone_functor_tag);
384 template<typename Functor>
385 void assign_to(Functor f)
387 typedef typename detail::function::get_function_tag<Functor>::type tag;
388 this->assign_to(f, tag());
391 template<typename FunctionPtr>
392 void assign_to(FunctionPtr f, detail::function::function_ptr_tag)
397 typedef typename detail::function::BOOST_FUNCTION_GET_FUNCTION_INVOKER<
399 R BOOST_FUNCTION_COMMA
400 BOOST_FUNCTION_TEMPLATE_ARGS
404 invoker = &invoker_type::invoke;
405 function_base::manager =
406 &detail::function::functor_manager<FunctionPtr, Allocator>::manage;
407 function_base::functor =
408 function_base::manager(detail::function::any_pointer(
409 // should be a reinterpret cast, but some compilers
410 // insist on giving cv-qualifiers to free functions
413 detail::function::clone_functor_tag);
417 #if BOOST_FUNCTION_NUM_ARGS > 0
418 template<typename MemberPtr>
419 void assign_to(MemberPtr f, detail::function::member_ptr_tag)
421 this->assign_to(mem_fn(f));
423 #endif // BOOST_FUNCTION_NUM_ARGS > 0
425 template<typename FunctionObj>
426 void assign_to(FunctionObj f, detail::function::function_obj_tag)
428 if (!detail::function::has_empty_target(addressof(f))) {
430 typename detail::function::BOOST_FUNCTION_GET_FUNCTION_OBJ_INVOKER<
432 R BOOST_FUNCTION_COMMA
433 BOOST_FUNCTION_TEMPLATE_ARGS
437 invoker = &invoker_type::invoke;
438 function_base::manager = &detail::function::functor_manager<
439 FunctionObj, Allocator>::manage;
440 #ifndef BOOST_NO_STD_ALLOCATOR
441 typedef typename Allocator::template rebind<FunctionObj>::other
443 typedef typename allocator_type::pointer pointer_type;
444 allocator_type allocator;
445 pointer_type copy = allocator.allocate(1);
446 allocator.construct(copy, f);
448 // Get back to the original pointer type
449 FunctionObj* new_f = static_cast<FunctionObj*>(copy);
451 FunctionObj* new_f = new FunctionObj(f);
452 #endif // BOOST_NO_STD_ALLOCATOR
453 function_base::functor =
454 detail::function::any_pointer(static_cast<void*>(new_f));
458 template<typename FunctionObj>
459 void assign_to(const reference_wrapper<FunctionObj>& f,
460 detail::function::function_obj_ref_tag)
462 if (!detail::function::has_empty_target(f.get_pointer())) {
464 typename detail::function::BOOST_FUNCTION_GET_FUNCTION_OBJ_INVOKER<
466 R BOOST_FUNCTION_COMMA
467 BOOST_FUNCTION_TEMPLATE_ARGS
471 invoker = &invoker_type::invoke;
472 function_base::manager = &detail::function::trivial_manager;
473 function_base::functor =
474 function_base::manager(
475 detail::function::any_pointer(
476 const_cast<FunctionObj*>(f.get_pointer())),
477 detail::function::clone_functor_tag);
481 template<typename FunctionObj>
482 void assign_to(FunctionObj, detail::function::stateless_function_obj_tag)
485 typename detail::function::
486 BOOST_FUNCTION_GET_STATELESS_FUNCTION_OBJ_INVOKER<
488 R BOOST_FUNCTION_COMMA
489 BOOST_FUNCTION_TEMPLATE_ARGS
492 invoker = &invoker_type::invoke;
493 function_base::manager = &detail::function::trivial_manager;
494 function_base::functor = detail::function::any_pointer(this);
497 typedef internal_result_type (*invoker_type)(detail::function::any_pointer
499 BOOST_FUNCTION_TEMPLATE_ARGS);
501 invoker_type invoker;
504 template<typename R BOOST_FUNCTION_COMMA BOOST_FUNCTION_TEMPLATE_PARMS ,
505 typename Policy, typename Mixin, typename Allocator>
506 inline void swap(BOOST_FUNCTION_FUNCTION<
507 R BOOST_FUNCTION_COMMA
508 BOOST_FUNCTION_TEMPLATE_ARGS ,
513 BOOST_FUNCTION_FUNCTION<
514 R BOOST_FUNCTION_COMMA
515 BOOST_FUNCTION_TEMPLATE_ARGS,
525 // Cleanup after ourselves...
526 #undef BOOST_FUNCTION_DEFAULT_ALLOCATOR
527 #undef BOOST_FUNCTION_COMMA
528 #undef BOOST_FUNCTION_FUNCTION
529 #undef BOOST_FUNCTION_FUNCTION_INVOKER
530 #undef BOOST_FUNCTION_VOID_FUNCTION_INVOKER
531 #undef BOOST_FUNCTION_FUNCTION_OBJ_INVOKER
532 #undef BOOST_FUNCTION_VOID_FUNCTION_OBJ_INVOKER
533 #undef BOOST_FUNCTION_STATELESS_FUNCTION_OBJ_INVOKER
534 #undef BOOST_FUNCTION_STATELESS_VOID_FUNCTION_OBJ_INVOKER
535 #undef BOOST_FUNCTION_GET_FUNCTION_INVOKER
536 #undef BOOST_FUNCTION_GET_FUNCTION_OBJ_INVOKER
537 #undef BOOST_FUNCTION_GET_STATELESS_FUNCTION_OBJ_INVOKER
538 #undef BOOST_FUNCTION_GET_MEM_FUNCTION_INVOKER