Files
boost_function/include/boost/function/function_template.hpp

398 lines
12 KiB
C++
Raw Normal View History

// Boost.Function library
2001-06-21 16:19:33 +00:00
// Copyright (C) 2001 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.
2001-06-21 16:19:33 +00:00
#include <cassert>
#include <algorithm>
// Type of the default allocator
#ifndef BOOST_NO_STD_ALLOCATOR
# define BOOST_FUNCTION_DEFAULT_ALLOCATOR std::allocator<function_base>
#else
2001-10-08 13:49:02 +00:00
# define BOOST_FUNCTION_DEFAULT_ALLOCATOR int
#endif // BOOST_NO_STD_ALLOCATOR
2001-06-21 16:19:33 +00:00
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
2001-06-21 16:19:33 +00:00
BOOST_FUNCTION_PARMS)
{
FunctionPtr f = reinterpret_cast<FunctionPtr>(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
2001-06-21 16:19:33 +00:00
BOOST_FUNCTION_PARMS)
{
FunctionPtr f = reinterpret_cast<FunctionPtr>(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
2001-06-21 16:19:33 +00:00
BOOST_FUNCTION_PARMS)
{
FunctionObj* f = static_cast<FunctionObj*>(function_obj_ptr.obj_ptr);
return (*f)(BOOST_FUNCTION_ARGS);
2001-06-21 16:19:33 +00:00
}
};
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
2001-06-21 16:19:33 +00:00
BOOST_FUNCTION_PARMS)
{
FunctionObj* f = static_cast<FunctionObj*>(function_obj_ptr.obj_ptr);
(*f)(BOOST_FUNCTION_ARGS);
2001-06-21 16:19:33 +00:00
return unusable();
}
};
template<
typename FunctionPtr,
typename Allocator,
typename R BOOST_FUNCTION_COMMA
BOOST_FUNCTION_TEMPLATE_PARMS
>
struct BOOST_FUNCTION_GET_FUNCTION_INVOKER
{
typedef typename IF<(is_void<R>::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 Allocator,
typename R BOOST_FUNCTION_COMMA
BOOST_FUNCTION_TEMPLATE_PARMS
>
struct BOOST_FUNCTION_GET_FUNCTION_OBJ_INVOKER
{
typedef typename IF<(is_void<R>::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;
};
} // end namespace function
} // end namespace detail
template<
typename R BOOST_FUNCTION_COMMA
BOOST_FUNCTION_TEMPLATE_PARMS,
typename Policy = empty_function_policy,
typename Mixin = empty_function_mixin,
typename Allocator = BOOST_FUNCTION_DEFAULT_ALLOCATOR
>
class BOOST_FUNCTION_FUNCTION : public function_base, public Mixin
{
public:
BOOST_STATIC_CONSTANT(int, args = BOOST_FUNCTION_NUM_ARGS);
#if BOOST_FUNCTION_NUM_ARGS == 1
typedef T1 argument_type;
#elif BOOST_FUNCTION_NUM_ARGS == 2
typedef T1 first_argument_type;
typedef T2 second_argument_type;
#endif
typedef typename detail::function::function_return_type<R>::type
result_type;
typedef Policy policy_type;
typedef Mixin mixin_type;
typedef Allocator allocator_type;
typedef BOOST_FUNCTION_FUNCTION self_type;
BOOST_FUNCTION_FUNCTION() : function_base(), Mixin(), invoker(0) {}
explicit BOOST_FUNCTION_FUNCTION(const Mixin& m) :
function_base(), Mixin(m), invoker(0)
{
}
// MSVC chokes if the following two constructors are collapsed into
// one with a default parameter.
template<typename Functor>
BOOST_FUNCTION_FUNCTION(const Functor& f) :
function_base(), Mixin(), invoker(0)
{
this->assign_to(f);
}
template<typename Functor>
BOOST_FUNCTION_FUNCTION(const Functor& f, const Mixin& m) :
function_base(), Mixin(m), invoker(0)
2001-06-21 16:19:33 +00:00
{
this->assign_to(f);
2001-06-21 16:19:33 +00:00
}
#ifdef __BORLANDC__
template<typename Functor>
BOOST_FUNCTION_FUNCTION(Functor* f, const Mixin& m = Mixin()) :
function_base(), Mixin(m), invoker(0)
{
this->assign_to(f);
}
#endif // __BORLANDC__
2001-06-21 16:19:33 +00:00
BOOST_FUNCTION_FUNCTION(const BOOST_FUNCTION_FUNCTION& f) :
function_base(), Mixin(static_cast<const Mixin&>(f)), invoker(0)
2001-06-21 16:19:33 +00:00
{
this->assign_to_own(f);
2001-06-21 16:19:33 +00:00
}
~BOOST_FUNCTION_FUNCTION() { clear(); }
2001-06-21 16:19:33 +00:00
result_type operator()(BOOST_FUNCTION_PARMS) const
{
assert(!this->empty());
policy_type policy;
policy.precall(this);
result_type result = invoker(functor BOOST_FUNCTION_COMMA
BOOST_FUNCTION_ARGS);
2001-06-21 16:19:33 +00:00
policy.postcall(this);
return result;
}
// 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<typename Functor>
BOOST_FUNCTION_FUNCTION& operator=(const Functor& f)
2001-06-21 16:19:33 +00:00
{
self_type(f, static_cast<const Mixin&>(*this)).swap(*this);
return *this;
2001-06-21 16:19:33 +00:00
}
#ifdef __BORLANDC__
2001-06-21 16:19:33 +00:00
template<typename Functor>
BOOST_FUNCTION_FUNCTION& operator=(Functor* f)
2001-06-21 16:19:33 +00:00
{
self_type(f, static_cast<const Mixin&>(*this)).swap(*this);
2001-06-21 16:19:33 +00:00
return *this;
}
#endif // __BORLANDC__
2001-06-21 16:19:33 +00:00
template<typename Functor>
void set(const Functor& f)
2001-06-21 16:19:33 +00:00
{
self_type(f, static_cast<const Mixin&>(*this)).swap(*this);
2001-06-21 16:19:33 +00:00
}
#ifdef __BORLANDC__
template<typename Functor>
void set(Functor* f)
{
self_type(f, static_cast<const Mixin&>(*this)).swap(*this);
}
#endif // __BORLANDC__
2001-06-21 16:19:33 +00:00
// Assignment from another BOOST_FUNCTION_FUNCTION
BOOST_FUNCTION_FUNCTION& operator=(const BOOST_FUNCTION_FUNCTION& f)
{
if (&f == this)
return *this;
self_type(f).swap(*this);
2001-06-21 16:19:33 +00:00
return *this;
}
// Assignment from another BOOST_FUNCTION_FUNCTION
void set(const BOOST_FUNCTION_FUNCTION& f)
{
if (&f == this)
return;
self_type(f).swap(*this);
2001-06-21 16:19:33 +00:00
}
void swap(BOOST_FUNCTION_FUNCTION& other)
{
if (&other == this)
return;
std::swap(manager, other.manager);
std::swap(functor, other.functor);
std::swap(invoker, other.invoker);
std::swap(static_cast<Mixin&>(*this), static_cast<Mixin&>(other));
}
// Clear out a target, if there is one
void clear()
{
if (manager)
functor = manager(functor, detail::function::destroy_functor);
manager = 0;
invoker = 0;
}
private:
void assign_to_own(const BOOST_FUNCTION_FUNCTION& f)
{
if (!f.empty()) {
invoker = f.invoker;
manager = f.manager;
functor = f.manager(f.functor, detail::function::clone_functor);
}
}
template<typename Functor>
void assign_to(const Functor& f)
{
typedef typename detail::function::get_function_tag<Functor>::type tag;
this->assign_to(f, tag());
}
template<typename MemberPtr>
void assign_to(MemberPtr f, detail::function::member_ptr_tag)
{
this->assign_to(mem_fn(f));
}
template<typename FunctionPtr>
void assign_to(FunctionPtr f, detail::function::function_ptr_tag)
{
clear();
if (f) {
typedef typename detail::function::BOOST_FUNCTION_GET_FUNCTION_INVOKER<
FunctionPtr,
Allocator,
R BOOST_FUNCTION_COMMA
BOOST_FUNCTION_TEMPLATE_ARGS
>::type
invoker_type;
invoker = &invoker_type::invoke;
manager = &detail::function::functor_manager<FunctionPtr,
Allocator>::manage;
functor = manager(detail::function::any_pointer(
reinterpret_cast<void (*)()>(f)
),
detail::function::clone_functor);
}
}
template<typename FunctionObj>
void assign_to(const FunctionObj& f, detail::function::function_obj_tag)
{
if (!detail::function::has_empty_target(&f)) {
typedef
typename detail::function::BOOST_FUNCTION_GET_FUNCTION_OBJ_INVOKER<
FunctionObj,
Allocator,
R BOOST_FUNCTION_COMMA
BOOST_FUNCTION_TEMPLATE_ARGS
>::type
invoker_type;
invoker = &invoker_type::invoke;
manager = &detail::function::functor_manager<FunctionObj,
Allocator>::manage;
functor =
manager(detail::function::any_pointer(const_cast<FunctionObj*>(&f)),
detail::function::clone_functor);
}
}
typedef result_type (*invoker_type)(detail::function::any_pointer
BOOST_FUNCTION_COMMA
BOOST_FUNCTION_TEMPLATE_ARGS);
invoker_type invoker;
2001-06-21 16:19:33 +00:00
};
template<typename R BOOST_FUNCTION_COMMA BOOST_FUNCTION_TEMPLATE_PARMS ,
typename Policy, typename Mixin, typename Allocator>
inline void swap(BOOST_FUNCTION_FUNCTION<
R BOOST_FUNCTION_COMMA
BOOST_FUNCTION_TEMPLATE_ARGS ,
Policy,
Mixin,
Allocator
>& f1,
BOOST_FUNCTION_FUNCTION<
R BOOST_FUNCTION_COMMA
BOOST_FUNCTION_TEMPLATE_ARGS,
Policy,
Mixin,
Allocator
>& f2)
{
f1.swap(f2);
}
2001-06-21 16:19:33 +00:00
}
// Cleanup after ourselves...
#undef BOOST_FUNCTION_DEFAULT_ALLOCATOR