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)
328 self_type(f, static_cast<const Mixin&>(*this)).swap(*this);
331 // Assignment from another BOOST_FUNCTION_FUNCTION
332 BOOST_FUNCTION_FUNCTION& operator=(const BOOST_FUNCTION_FUNCTION& f)
337 self_type(f).swap(*this);
341 // Assignment from another BOOST_FUNCTION_FUNCTION
342 void set(const BOOST_FUNCTION_FUNCTION& f)
348 self_type(f).swap(*this);
351 void swap(BOOST_FUNCTION_FUNCTION& other)
356 std::swap(function_base::manager, other.manager);
357 std::swap(function_base::functor, other.functor);
358 std::swap(invoker, other.invoker);
359 std::swap(static_cast<Mixin&>(*this), static_cast<Mixin&>(other));
362 // Clear out a target, if there is one
365 if (function_base::manager) {
366 function_base::functor =
367 function_base::manager(function_base::functor,
368 detail::function::destroy_functor_tag);
371 function_base::manager = 0;
376 void assign_to_own(const BOOST_FUNCTION_FUNCTION& f)
380 function_base::manager = f.manager;
381 function_base::functor =
382 f.manager(f.functor, detail::function::clone_functor_tag);
386 template<typename Functor>
387 void assign_to(Functor f)
389 typedef typename detail::function::get_function_tag<Functor>::type tag;
390 this->assign_to(f, tag());
393 template<typename FunctionPtr>
394 void assign_to(FunctionPtr f, detail::function::function_ptr_tag)
399 typedef typename detail::function::BOOST_FUNCTION_GET_FUNCTION_INVOKER<
401 R BOOST_FUNCTION_COMMA
402 BOOST_FUNCTION_TEMPLATE_ARGS
406 invoker = &invoker_type::invoke;
407 function_base::manager =
408 &detail::function::functor_manager<FunctionPtr, Allocator>::manage;
409 function_base::functor =
410 function_base::manager(detail::function::any_pointer(
411 // should be a reinterpret cast, but some compilers
412 // insist on giving cv-qualifiers to free functions
415 detail::function::clone_functor_tag);
419 #if BOOST_FUNCTION_NUM_ARGS > 0
420 template<typename MemberPtr>
421 void assign_to(MemberPtr f, detail::function::member_ptr_tag)
423 this->assign_to(mem_fn(f));
425 #endif // BOOST_FUNCTION_NUM_ARGS > 0
427 template<typename FunctionObj>
428 void assign_to(FunctionObj f, detail::function::function_obj_tag)
430 if (!detail::function::has_empty_target(addressof(f))) {
432 typename detail::function::BOOST_FUNCTION_GET_FUNCTION_OBJ_INVOKER<
434 R BOOST_FUNCTION_COMMA
435 BOOST_FUNCTION_TEMPLATE_ARGS
439 invoker = &invoker_type::invoke;
440 function_base::manager = &detail::function::functor_manager<
441 FunctionObj, Allocator>::manage;
442 #ifndef BOOST_NO_STD_ALLOCATOR
443 typedef typename Allocator::template rebind<FunctionObj>::other
445 typedef typename allocator_type::pointer pointer_type;
446 allocator_type allocator;
447 pointer_type copy = allocator.allocate(1);
448 allocator.construct(copy, f);
450 // Get back to the original pointer type
451 FunctionObj* new_f = static_cast<FunctionObj*>(copy);
453 FunctionObj* new_f = new FunctionObj(f);
454 #endif // BOOST_NO_STD_ALLOCATOR
455 function_base::functor =
456 detail::function::any_pointer(static_cast<void*>(new_f));
460 template<typename FunctionObj>
461 void assign_to(const reference_wrapper<FunctionObj>& f,
462 detail::function::function_obj_ref_tag)
464 if (!detail::function::has_empty_target(f.get_pointer())) {
466 typename detail::function::BOOST_FUNCTION_GET_FUNCTION_OBJ_INVOKER<
468 R BOOST_FUNCTION_COMMA
469 BOOST_FUNCTION_TEMPLATE_ARGS
473 invoker = &invoker_type::invoke;
474 function_base::manager = &detail::function::trivial_manager;
475 function_base::functor =
476 function_base::manager(
477 detail::function::any_pointer(
478 const_cast<FunctionObj*>(f.get_pointer())),
479 detail::function::clone_functor_tag);
483 template<typename FunctionObj>
484 void assign_to(FunctionObj, detail::function::stateless_function_obj_tag)
487 typename detail::function::
488 BOOST_FUNCTION_GET_STATELESS_FUNCTION_OBJ_INVOKER<
490 R BOOST_FUNCTION_COMMA
491 BOOST_FUNCTION_TEMPLATE_ARGS
494 invoker = &invoker_type::invoke;
495 function_base::manager = &detail::function::trivial_manager;
496 function_base::functor = detail::function::any_pointer(this);
499 typedef internal_result_type (*invoker_type)(detail::function::any_pointer
501 BOOST_FUNCTION_TEMPLATE_ARGS);
503 invoker_type invoker;
506 template<typename R BOOST_FUNCTION_COMMA BOOST_FUNCTION_TEMPLATE_PARMS ,
507 typename Policy, typename Mixin, typename Allocator>
508 inline void swap(BOOST_FUNCTION_FUNCTION<
509 R BOOST_FUNCTION_COMMA
510 BOOST_FUNCTION_TEMPLATE_ARGS ,
515 BOOST_FUNCTION_FUNCTION<
516 R BOOST_FUNCTION_COMMA
517 BOOST_FUNCTION_TEMPLATE_ARGS,
527 // Cleanup after ourselves...
528 #undef BOOST_FUNCTION_DEFAULT_ALLOCATOR
529 #undef BOOST_FUNCTION_COMMA
530 #undef BOOST_FUNCTION_FUNCTION
531 #undef BOOST_FUNCTION_FUNCTION_INVOKER
532 #undef BOOST_FUNCTION_VOID_FUNCTION_INVOKER
533 #undef BOOST_FUNCTION_FUNCTION_OBJ_INVOKER
534 #undef BOOST_FUNCTION_VOID_FUNCTION_OBJ_INVOKER
535 #undef BOOST_FUNCTION_STATELESS_FUNCTION_OBJ_INVOKER
536 #undef BOOST_FUNCTION_STATELESS_VOID_FUNCTION_OBJ_INVOKER
537 #undef BOOST_FUNCTION_GET_FUNCTION_INVOKER
538 #undef BOOST_FUNCTION_GET_FUNCTION_OBJ_INVOKER
539 #undef BOOST_FUNCTION_GET_STATELESS_FUNCTION_OBJ_INVOKER
540 #undef BOOST_FUNCTION_GET_MEM_FUNCTION_INVOKER