// Boost.Function library // Copyright (C) 2001-2002 Doug Gregor (gregod@cs.rpi.edu) // // Permission to copy, use, sell and distribute this software is granted // provided this copyright notice appears in all copies. // Permission to modify the code and to distribute modified code is granted // provided this copyright notice appears in all copies, and a notice // that the code was modified is included with the copyright notice. // // This software is provided "as is" without express or implied warranty, // and with no claim as to its suitability for any purpose. // For more information, see http://www.boost.org // Note: this header is a header template and must NOT have multiple-inclusion // protection. #ifndef BOOST_FUNCTION_FUNCTION_TEMPLATE_HPP #define BOOST_FUNCTION_FUNCTION_TEMPLATE_HPP # include # include # include # include # include #endif // BOOST_FUNCTION_FUNCTION_TEMPLATE_HPP // Comma if nonzero number of arguments #if BOOST_FUNCTION_NUM_ARGS == 0 # define BOOST_FUNCTION_COMMA #else # define BOOST_FUNCTION_COMMA , #endif // BOOST_FUNCTION_NUM_ARGS > 0 // Class names used in this version of the code #define BOOST_FUNCTION_FUNCTION BOOST_JOIN(function,BOOST_FUNCTION_NUM_ARGS) #define BOOST_FUNCTION_FUNCTION_INVOKER \ BOOST_JOIN(function_invoker,BOOST_FUNCTION_NUM_ARGS) #define BOOST_FUNCTION_VOID_FUNCTION_INVOKER \ BOOST_JOIN(void_function_invoker,BOOST_FUNCTION_NUM_ARGS) #define BOOST_FUNCTION_FUNCTION_OBJ_INVOKER \ BOOST_JOIN(function_obj_invoker,BOOST_FUNCTION_NUM_ARGS) #define BOOST_FUNCTION_VOID_FUNCTION_OBJ_INVOKER \ BOOST_JOIN(void_function_obj_invoker,BOOST_FUNCTION_NUM_ARGS) #define BOOST_FUNCTION_STATELESS_FUNCTION_OBJ_INVOKER \ BOOST_JOIN(stateless_function_obj_invoker,BOOST_FUNCTION_NUM_ARGS) #define BOOST_FUNCTION_STATELESS_VOID_FUNCTION_OBJ_INVOKER \ BOOST_JOIN(stateless_void_function_obj_invoker,BOOST_FUNCTION_NUM_ARGS) #define BOOST_FUNCTION_GET_FUNCTION_INVOKER \ BOOST_JOIN(get_function_invoker,BOOST_FUNCTION_NUM_ARGS) #define BOOST_FUNCTION_GET_FUNCTION_OBJ_INVOKER \ BOOST_JOIN(get_function_obj_invoker,BOOST_FUNCTION_NUM_ARGS) #define BOOST_FUNCTION_GET_STATELESS_FUNCTION_OBJ_INVOKER \ BOOST_JOIN(get_stateless_function_obj_invoker,BOOST_FUNCTION_NUM_ARGS) namespace boost { namespace detail { namespace function { template< typename FunctionPtr, typename R BOOST_FUNCTION_COMMA BOOST_FUNCTION_TEMPLATE_PARMS > struct BOOST_FUNCTION_FUNCTION_INVOKER { static R invoke(any_pointer function_ptr BOOST_FUNCTION_COMMA BOOST_FUNCTION_PARMS) { FunctionPtr f = reinterpret_cast(function_ptr.func_ptr); return f(BOOST_FUNCTION_ARGS); } }; template< typename FunctionPtr, typename R BOOST_FUNCTION_COMMA BOOST_FUNCTION_TEMPLATE_PARMS > struct BOOST_FUNCTION_VOID_FUNCTION_INVOKER { static unusable invoke(any_pointer function_ptr BOOST_FUNCTION_COMMA BOOST_FUNCTION_PARMS) { FunctionPtr f = reinterpret_cast(function_ptr.func_ptr); f(BOOST_FUNCTION_ARGS); return unusable(); } }; template< typename FunctionObj, typename R BOOST_FUNCTION_COMMA BOOST_FUNCTION_TEMPLATE_PARMS > struct BOOST_FUNCTION_FUNCTION_OBJ_INVOKER { static R invoke(any_pointer function_obj_ptr BOOST_FUNCTION_COMMA BOOST_FUNCTION_PARMS) { FunctionObj* f = (FunctionObj*)(function_obj_ptr.obj_ptr); return (*f)(BOOST_FUNCTION_ARGS); } }; template< typename FunctionObj, typename R BOOST_FUNCTION_COMMA BOOST_FUNCTION_TEMPLATE_PARMS > struct BOOST_FUNCTION_VOID_FUNCTION_OBJ_INVOKER { static unusable invoke(any_pointer function_obj_ptr BOOST_FUNCTION_COMMA BOOST_FUNCTION_PARMS) { FunctionObj* f = (FunctionObj*)(function_obj_ptr.obj_ptr); (*f)(BOOST_FUNCTION_ARGS); return unusable(); } }; template< typename FunctionObj, typename R BOOST_FUNCTION_COMMA BOOST_FUNCTION_TEMPLATE_PARMS > struct BOOST_FUNCTION_STATELESS_FUNCTION_OBJ_INVOKER { static R invoke(any_pointer BOOST_FUNCTION_COMMA BOOST_FUNCTION_PARMS) { FunctionObj f = FunctionObj(); return f(BOOST_FUNCTION_ARGS); } }; template< typename FunctionObj, typename R BOOST_FUNCTION_COMMA BOOST_FUNCTION_TEMPLATE_PARMS > struct BOOST_FUNCTION_STATELESS_VOID_FUNCTION_OBJ_INVOKER { static unusable invoke(any_pointer BOOST_FUNCTION_COMMA BOOST_FUNCTION_PARMS) { FunctionObj f = FunctionObj(); f(BOOST_FUNCTION_ARGS); return unusable(); } }; template< typename FunctionPtr, typename R BOOST_FUNCTION_COMMA BOOST_FUNCTION_TEMPLATE_PARMS > struct BOOST_FUNCTION_GET_FUNCTION_INVOKER { typedef typename ct_if<(is_void::value), BOOST_FUNCTION_VOID_FUNCTION_INVOKER< FunctionPtr, R BOOST_FUNCTION_COMMA BOOST_FUNCTION_TEMPLATE_ARGS >, BOOST_FUNCTION_FUNCTION_INVOKER< FunctionPtr, R BOOST_FUNCTION_COMMA BOOST_FUNCTION_TEMPLATE_ARGS > >::type type; }; template< typename FunctionObj, typename R BOOST_FUNCTION_COMMA BOOST_FUNCTION_TEMPLATE_PARMS > struct BOOST_FUNCTION_GET_FUNCTION_OBJ_INVOKER { typedef typename ct_if<(is_void::value), BOOST_FUNCTION_VOID_FUNCTION_OBJ_INVOKER< FunctionObj, R BOOST_FUNCTION_COMMA BOOST_FUNCTION_TEMPLATE_ARGS >, BOOST_FUNCTION_FUNCTION_OBJ_INVOKER< FunctionObj, R BOOST_FUNCTION_COMMA BOOST_FUNCTION_TEMPLATE_ARGS > >::type type; }; template< typename FunctionObj, typename R BOOST_FUNCTION_COMMA BOOST_FUNCTION_TEMPLATE_PARMS > struct BOOST_FUNCTION_GET_STATELESS_FUNCTION_OBJ_INVOKER { typedef typename ct_if<(is_void::value), BOOST_FUNCTION_STATELESS_VOID_FUNCTION_OBJ_INVOKER< FunctionObj, R BOOST_FUNCTION_COMMA BOOST_FUNCTION_TEMPLATE_ARGS >, BOOST_FUNCTION_STATELESS_FUNCTION_OBJ_INVOKER< FunctionObj, R BOOST_FUNCTION_COMMA BOOST_FUNCTION_TEMPLATE_ARGS > >::type type; }; } // end namespace function } // end namespace detail template< typename R BOOST_FUNCTION_COMMA BOOST_FUNCTION_TEMPLATE_PARMS, typename ThreadingPolicy = BOOST_FUNCTION_DEFAULT_THREADING_POLICY, typename Allocator = BOOST_FUNCTION_DEFAULT_ALLOCATOR > class BOOST_FUNCTION_FUNCTION : public function_base, public ThreadingPolicy::mixin { typedef typename detail::function::function_return_type::type internal_result_type; typedef typename ThreadingPolicy::mixin threading_mixin; typedef typename ThreadingPolicy::lock lock; public: BOOST_STATIC_CONSTANT(int, args = BOOST_FUNCTION_NUM_ARGS); #if BOOST_FUNCTION_NUM_ARGS == 1 typedef T0 argument_type; #elif BOOST_FUNCTION_NUM_ARGS == 2 typedef T0 first_argument_type; typedef T1 second_argument_type; #endif #ifndef BOOST_NO_VOID_RETURNS typedef R result_type; #else typedef internal_result_type result_type; #endif // BOOST_NO_VOID_RETURNS typedef Allocator allocator_type; typedef BOOST_FUNCTION_FUNCTION self_type; typedef ThreadingPolicy threading_policy_type; BOOST_FUNCTION_FUNCTION() : function_base(), invoker(0) {} // MSVC chokes if the following two constructors are collapsed into // one with a default parameter. template BOOST_FUNCTION_FUNCTION(Functor BOOST_FUNCTION_TARGET_FIX(const &) f) : function_base(), invoker(0) { this->assign_to(f); } BOOST_FUNCTION_FUNCTION(const BOOST_FUNCTION_FUNCTION& f) : function_base(), invoker(0) { // Lock the other function object so it can't change during assignment lock l(static_cast(f)); (void)l; this->assign_to_own(f); } ~BOOST_FUNCTION_FUNCTION() { lock l(static_cast(*this)); (void)l; clear(); } result_type operator()(BOOST_FUNCTION_PARMS) const { // Make sure this function can't change while it is being invoked lock l(static_cast(*this)); (void)l; assert(!this->empty()); internal_result_type result = invoker(function_base::functor BOOST_FUNCTION_COMMA BOOST_FUNCTION_ARGS); #ifndef BOOST_NO_VOID_RETURNS return static_cast(result); #else return result; #endif // BOOST_NO_VOID_RETURNS } // The distinction between when to use BOOST_FUNCTION_FUNCTION and // when to use self_type is obnoxious. MSVC cannot handle self_type as // the return type of these assignment operators, but Borland C++ cannot // handle BOOST_FUNCTION_FUNCTION as the type of the temporary to // construct. template BOOST_FUNCTION_FUNCTION& operator=(Functor BOOST_FUNCTION_TARGET_FIX(const &) f) { self_type other(f); lock l(static_cast(*this)); (void)l; other.unlocked_swap(*this); return *this; } // Assignment from another BOOST_FUNCTION_FUNCTION BOOST_FUNCTION_FUNCTION& operator=(const BOOST_FUNCTION_FUNCTION& f) { if (&f == this) return *this; self_type other(f); lock l(static_cast(*this)); (void)l; other.unlocked_swap(*this); return *this; } void swap(BOOST_FUNCTION_FUNCTION& other) { if (&other == this) return; detail::function::scoped_double_lock l(*this, other); (void)l; unlocked_swap(other); } // Clear out a target, if there is one void clear() { lock l(static_cast(*this)); (void)l; if (function_base::manager) { function_base::functor = function_base::manager(function_base::functor, detail::function::destroy_functor_tag); } function_base::manager = 0; invoker = 0; } private: void assign_to_own(const BOOST_FUNCTION_FUNCTION& f) { if (!f.empty()) { invoker = f.invoker; function_base::manager = f.manager; function_base::functor = f.manager(f.functor, detail::function::clone_functor_tag); } } template void assign_to(Functor f) { typedef typename detail::function::get_function_tag::type tag; this->assign_to(f, tag()); } template void assign_to(FunctionPtr f, detail::function::function_ptr_tag) { clear(); if (f) { typedef typename detail::function::BOOST_FUNCTION_GET_FUNCTION_INVOKER< FunctionPtr, R BOOST_FUNCTION_COMMA BOOST_FUNCTION_TEMPLATE_ARGS >::type invoker_type; invoker = &invoker_type::invoke; function_base::manager = &detail::function::functor_manager::manage; function_base::functor = function_base::manager(detail::function::any_pointer( // should be a reinterpret cast, but some compilers // insist on giving cv-qualifiers to free functions (void (*)())(f) ), detail::function::clone_functor_tag); } } #if BOOST_FUNCTION_NUM_ARGS > 0 template void assign_to(MemberPtr f, detail::function::member_ptr_tag) { this->assign_to(mem_fn(f)); } #endif // BOOST_FUNCTION_NUM_ARGS > 0 template void assign_to(FunctionObj f, detail::function::function_obj_tag) { typedef detail::function::truth< boost::is_base_and_derived::value> is_boost_function; if (!detail::function::has_empty_target(f, is_boost_function())) { typedef typename detail::function::BOOST_FUNCTION_GET_FUNCTION_OBJ_INVOKER< FunctionObj, R BOOST_FUNCTION_COMMA BOOST_FUNCTION_TEMPLATE_ARGS >::type invoker_type; invoker = &invoker_type::invoke; function_base::manager = &detail::function::functor_manager< FunctionObj, Allocator>::manage; #ifndef BOOST_NO_STD_ALLOCATOR typedef typename Allocator::template rebind::other allocator_type; typedef typename allocator_type::pointer pointer_type; allocator_type allocator; pointer_type copy = allocator.allocate(1); allocator.construct(copy, f); // Get back to the original pointer type FunctionObj* new_f = static_cast(copy); #else FunctionObj* new_f = new FunctionObj(f); #endif // BOOST_NO_STD_ALLOCATOR function_base::functor = detail::function::any_pointer(static_cast(new_f)); } } template void assign_to(const reference_wrapper& f, detail::function::function_obj_ref_tag) { typedef detail::function::truth< boost::is_base_and_derived::value> is_boost_function; if (!detail::function::has_empty_target(f.get(), is_boost_function())) { typedef typename detail::function::BOOST_FUNCTION_GET_FUNCTION_OBJ_INVOKER< FunctionObj, R BOOST_FUNCTION_COMMA BOOST_FUNCTION_TEMPLATE_ARGS >::type invoker_type; invoker = &invoker_type::invoke; function_base::manager = &detail::function::trivial_manager; function_base::functor = function_base::manager( detail::function::any_pointer( const_cast(f.get_pointer())), detail::function::clone_functor_tag); } } template void assign_to(FunctionObj, detail::function::stateless_function_obj_tag) { typedef typename detail::function:: BOOST_FUNCTION_GET_STATELESS_FUNCTION_OBJ_INVOKER< FunctionObj, R BOOST_FUNCTION_COMMA BOOST_FUNCTION_TEMPLATE_ARGS >::type invoker_type; invoker = &invoker_type::invoke; function_base::manager = &detail::function::trivial_manager; function_base::functor = detail::function::any_pointer(this); } void unlocked_swap(BOOST_FUNCTION_FUNCTION& other) { std::swap(function_base::manager, other.manager); std::swap(function_base::functor, other.functor); std::swap(invoker, other.invoker); } typedef internal_result_type (*invoker_type)(detail::function::any_pointer BOOST_FUNCTION_COMMA BOOST_FUNCTION_TEMPLATE_ARGS); invoker_type invoker; }; template inline void swap(BOOST_FUNCTION_FUNCTION< R BOOST_FUNCTION_COMMA BOOST_FUNCTION_TEMPLATE_ARGS , ThreadingPolicy, Allocator >& f1, BOOST_FUNCTION_FUNCTION< R BOOST_FUNCTION_COMMA BOOST_FUNCTION_TEMPLATE_ARGS, ThreadingPolicy, Allocator >& f2) { f1.swap(f2); } } // Cleanup after ourselves... #undef BOOST_FUNCTION_COMMA #undef BOOST_FUNCTION_FUNCTION #undef BOOST_FUNCTION_FUNCTION_INVOKER #undef BOOST_FUNCTION_VOID_FUNCTION_INVOKER #undef BOOST_FUNCTION_FUNCTION_OBJ_INVOKER #undef BOOST_FUNCTION_VOID_FUNCTION_OBJ_INVOKER #undef BOOST_FUNCTION_STATELESS_FUNCTION_OBJ_INVOKER #undef BOOST_FUNCTION_STATELESS_VOID_FUNCTION_OBJ_INVOKER #undef BOOST_FUNCTION_GET_FUNCTION_INVOKER #undef BOOST_FUNCTION_GET_FUNCTION_OBJ_INVOKER #undef BOOST_FUNCTION_GET_STATELESS_FUNCTION_OBJ_INVOKER #undef BOOST_FUNCTION_GET_MEM_FUNCTION_INVOKER