mirror of
https://github.com/boostorg/function.git
synced 2025-07-17 06:32:13 +02:00
boost/function/function_template.hpp, boost/function/function_base.hpp:
- Added "contains" member function to extract a pointer to the target function object if you know its type - Added operator== that can compare a Boost.Function object against a function object libs/function/test/Jamfile, libs/function/test/contains_test.cpp: - Test contains() and equality comparison operators [SVN r21844]
This commit is contained in:
@ -14,17 +14,31 @@
|
||||
#include <string>
|
||||
#include <memory>
|
||||
#include <new>
|
||||
#include <typeinfo>
|
||||
#include <boost/config.hpp>
|
||||
#include <boost/assert.hpp>
|
||||
#include <boost/type_traits/arithmetic_traits.hpp>
|
||||
#include <boost/type_traits/is_integral.hpp>
|
||||
#include <boost/type_traits/composite_traits.hpp>
|
||||
#include <boost/type_traits/is_stateless.hpp>
|
||||
#include <boost/ref.hpp>
|
||||
#include <boost/pending/ct_if.hpp>
|
||||
#include <boost/detail/workaround.hpp>
|
||||
|
||||
#ifndef BOOST_NO_SFINAE
|
||||
# include "boost/utility/enable_if.hpp"
|
||||
#else
|
||||
# include "boost/mpl/bool.hpp"
|
||||
#endif
|
||||
|
||||
// Borrowed from Boost.Python library: determines the cases where we
|
||||
// need to use std::type_info::name to compare instead of operator==.
|
||||
# if (defined(__GNUC__) && __GNUC__ >= 3) \
|
||||
|| defined(_AIX) \
|
||||
|| ( defined(__sgi) && defined(__host_mips))
|
||||
# include <cstring>
|
||||
# define BOOST_FUNCTION_COMPARE_TYPE_ID(X,Y) \
|
||||
(std::strcmp((X).name(),(Y).name()) == 0)
|
||||
# else
|
||||
# define BOOST_FUNCTION_COMPARE_TYPE_ID(X,Y) (X==Y)
|
||||
#endif
|
||||
|
||||
#if defined(BOOST_MSVC) && BOOST_MSVC <= 1300 || defined(__ICL) && __ICL <= 600 || defined(__MWERKS__) && __MWERKS__ < 0x2406 && !defined(BOOST_STRICT_CONFIG)
|
||||
@ -139,7 +153,8 @@ namespace boost {
|
||||
// The operation type to perform on the given functor/function pointer
|
||||
enum functor_manager_operation_type {
|
||||
clone_functor_tag,
|
||||
destroy_functor_tag
|
||||
destroy_functor_tag,
|
||||
check_functor_type_tag
|
||||
};
|
||||
|
||||
// Tags used to decide between different types of functions
|
||||
@ -172,14 +187,27 @@ namespace boost {
|
||||
|
||||
// The trivial manager does nothing but return the same pointer (if we
|
||||
// are cloning) or return the null pointer (if we are deleting).
|
||||
inline any_pointer trivial_manager(any_pointer f,
|
||||
functor_manager_operation_type op)
|
||||
{
|
||||
if (op == clone_functor_tag)
|
||||
return f;
|
||||
else
|
||||
template<typename F>
|
||||
inline any_pointer
|
||||
trivial_manager(any_pointer f, functor_manager_operation_type op)
|
||||
{
|
||||
switch (op) {
|
||||
case clone_functor_tag: return f;
|
||||
|
||||
case destroy_functor_tag:
|
||||
return make_any_pointer(reinterpret_cast<void*>(0));
|
||||
|
||||
case check_functor_type_tag:
|
||||
{
|
||||
std::type_info* t = static_cast<std::type_info*>(f.obj_ptr);
|
||||
bool equal = BOOST_FUNCTION_COMPARE_TYPE_ID(typeid(F), *t);
|
||||
return equal? f : make_any_pointer(reinterpret_cast<void*>(0));
|
||||
}
|
||||
}
|
||||
|
||||
// Clears up a warning with GCC 3.2.3
|
||||
return make_any_pointer(reinterpret_cast<void*>(0));
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* The functor_manager class contains a static function "manage" which
|
||||
@ -264,13 +292,59 @@ namespace boost {
|
||||
static any_pointer
|
||||
manage(any_pointer functor_ptr, functor_manager_operation_type op)
|
||||
{
|
||||
typedef typename get_function_tag<functor_type>::type tag_type;
|
||||
return manager(functor_ptr, op, tag_type());
|
||||
if (op == check_functor_type_tag) {
|
||||
std::type_info* type =
|
||||
static_cast<std::type_info*>(functor_ptr.obj_ptr);
|
||||
bool equal =
|
||||
BOOST_FUNCTION_COMPARE_TYPE_ID(typeid(Functor), *type);
|
||||
return (equal? functor_ptr
|
||||
: make_any_pointer(reinterpret_cast<void*>(0)));
|
||||
}
|
||||
else {
|
||||
typedef typename get_function_tag<functor_type>::type tag_type;
|
||||
return manager(functor_ptr, op, tag_type());
|
||||
}
|
||||
}
|
||||
};
|
||||
|
||||
// A type that is only used for comparisons against zero
|
||||
struct useless_clear_type {};
|
||||
|
||||
#ifdef BOOST_NO_SFINAE
|
||||
// These routines perform comparisons between a Boost.Function
|
||||
// object and an arbitrary function object (when the last
|
||||
// parameter is mpl::bool_<false>) or against zero (when the
|
||||
// last parameter is mpl::bool_<true>). They are only necessary
|
||||
// for compilers that don't support SFINAE.
|
||||
template<typename Function, typename Functor>
|
||||
bool
|
||||
compare_equal(const Function& f, const Functor&, mpl::bool_<true>)
|
||||
{ return f.empty(); }
|
||||
|
||||
template<typename Function, typename Functor>
|
||||
bool
|
||||
compare_not_equal(const Function& f, const Functor&, mpl::bool_<true>)
|
||||
{ return !f.empty(); }
|
||||
|
||||
template<typename Function, typename Functor>
|
||||
bool
|
||||
compare_equal(const Function& f, const Functor& g, mpl::bool_<false>)
|
||||
{
|
||||
if (const Functor* fp = f.template contains<Functor>())
|
||||
return *fp == g;
|
||||
else return false;
|
||||
}
|
||||
|
||||
template<typename Function, typename Functor>
|
||||
bool
|
||||
compare_not_equal(const Function& f, const Functor& g,
|
||||
mpl::bool_<false>)
|
||||
{
|
||||
if (const Functor* fp = f.template contains<Functor>())
|
||||
return *fp != g;
|
||||
else return true;
|
||||
}
|
||||
#endif // BOOST_NO_SFINAE
|
||||
} // end namespace function
|
||||
} // end namespace detail
|
||||
|
||||
@ -291,11 +365,59 @@ public:
|
||||
// Is this function empty?
|
||||
bool empty() const { return !manager; }
|
||||
|
||||
template<typename Functor>
|
||||
Functor* contains()
|
||||
{
|
||||
if (!manager) return 0;
|
||||
|
||||
detail::function::any_pointer result =
|
||||
manager(detail::function::make_any_pointer(&typeid(Functor)),
|
||||
detail::function::check_functor_type_tag);
|
||||
if (!result.obj_ptr) return false;
|
||||
else {
|
||||
typedef typename detail::function::get_function_tag<Functor>::type tag;
|
||||
return get_functor_pointer<Functor>(tag(), 0);
|
||||
}
|
||||
}
|
||||
|
||||
template<typename Functor>
|
||||
const Functor* contains() const
|
||||
{
|
||||
if (!manager) return 0;
|
||||
|
||||
detail::function::any_pointer result =
|
||||
manager(detail::function::make_any_pointer(&typeid(Functor)),
|
||||
detail::function::check_functor_type_tag);
|
||||
if (!result.obj_ptr) return false;
|
||||
else {
|
||||
typedef typename detail::function::get_function_tag<Functor>::type tag;
|
||||
return get_functor_pointer<Functor>(tag(), 0);
|
||||
}
|
||||
}
|
||||
|
||||
public: // should be protected, but GCC 2.95.3 will fail to allow access
|
||||
detail::function::any_pointer (*manager)(
|
||||
detail::function::any_pointer,
|
||||
detail::function::functor_manager_operation_type);
|
||||
detail::function::any_pointer functor;
|
||||
|
||||
private:
|
||||
template<typename Functor>
|
||||
Functor* get_functor_pointer(detail::function::function_ptr_tag, int)
|
||||
{ return &reinterpret_cast<Functor>(functor.func_ptr); }
|
||||
|
||||
template<typename Functor, typename Tag>
|
||||
Functor* get_functor_pointer(Tag, long)
|
||||
{ return static_cast<Functor*>(functor.obj_ptr); }
|
||||
|
||||
template<typename Functor>
|
||||
const Functor*
|
||||
get_functor_pointer(detail::function::function_ptr_tag, int) const
|
||||
{ return &reinterpret_cast<const Functor>(functor.func_ptr); }
|
||||
|
||||
template<typename Functor, typename Tag>
|
||||
const Functor* get_functor_pointer(Tag, long) const
|
||||
{ return static_cast<const Functor*>(functor.const_obj_ptr); }
|
||||
};
|
||||
|
||||
/**
|
||||
@ -308,16 +430,7 @@ public:
|
||||
bad_function_call() : std::runtime_error("call to empty boost::function") {}
|
||||
};
|
||||
|
||||
/* Poison comparison between Boost.Function objects (because it is
|
||||
* meaningless). The comparisons would otherwise be allowed because of the
|
||||
* conversion required to allow syntax such as:
|
||||
* boost::function<int, int> f;
|
||||
* if (f) { f(5); }
|
||||
*/
|
||||
void operator==(const function_base&, const function_base&);
|
||||
void operator!=(const function_base&, const function_base&);
|
||||
|
||||
#if BOOST_WORKAROUND(BOOST_MSVC, <= 1310)
|
||||
#ifndef BOOST_NO_SFINAE
|
||||
inline bool operator==(const function_base& f,
|
||||
detail::function::useless_clear_type*)
|
||||
{
|
||||
|
@ -508,7 +508,7 @@ namespace boost {
|
||||
invoker_type;
|
||||
|
||||
invoker = &invoker_type::invoke;
|
||||
this->manager = &detail::function::trivial_manager;
|
||||
this->manager = &detail::function::trivial_manager<FunctionObj>;
|
||||
this->functor =
|
||||
this->manager(
|
||||
detail::function::make_any_pointer(
|
||||
@ -529,7 +529,7 @@ namespace boost {
|
||||
>::type
|
||||
invoker_type;
|
||||
invoker = &invoker_type::invoke;
|
||||
this->manager = &detail::function::trivial_manager;
|
||||
this->manager = &detail::function::trivial_manager<FunctionObj>;
|
||||
this->functor = detail::function::make_any_pointer(this);
|
||||
}
|
||||
|
||||
@ -556,6 +556,143 @@ namespace boost {
|
||||
f1.swap(f2);
|
||||
}
|
||||
|
||||
// Poison comparisons between boost::function objects of the same type.
|
||||
template<typename R BOOST_FUNCTION_COMMA BOOST_FUNCTION_TEMPLATE_PARMS ,
|
||||
typename Allocator>
|
||||
void operator==(const BOOST_FUNCTION_FUNCTION<
|
||||
R BOOST_FUNCTION_COMMA
|
||||
BOOST_FUNCTION_TEMPLATE_ARGS ,
|
||||
Allocator>&,
|
||||
const BOOST_FUNCTION_FUNCTION<
|
||||
R BOOST_FUNCTION_COMMA
|
||||
BOOST_FUNCTION_TEMPLATE_ARGS ,
|
||||
Allocator>&);
|
||||
template<typename R BOOST_FUNCTION_COMMA BOOST_FUNCTION_TEMPLATE_PARMS ,
|
||||
typename Allocator>
|
||||
void operator!=(const BOOST_FUNCTION_FUNCTION<
|
||||
R BOOST_FUNCTION_COMMA
|
||||
BOOST_FUNCTION_TEMPLATE_ARGS ,
|
||||
Allocator>&,
|
||||
const BOOST_FUNCTION_FUNCTION<
|
||||
R BOOST_FUNCTION_COMMA
|
||||
BOOST_FUNCTION_TEMPLATE_ARGS ,
|
||||
Allocator>&);
|
||||
|
||||
#ifdef BOOST_NO_SFINAE
|
||||
// Comparisons between boost::function objects and arbitrary function objects
|
||||
template<typename R BOOST_FUNCTION_COMMA BOOST_FUNCTION_TEMPLATE_PARMS ,
|
||||
typename Allocator, typename Functor>
|
||||
inline bool
|
||||
operator==(const BOOST_FUNCTION_FUNCTION<
|
||||
R BOOST_FUNCTION_COMMA
|
||||
BOOST_FUNCTION_TEMPLATE_ARGS ,
|
||||
Allocator>& f,
|
||||
Functor g)
|
||||
{
|
||||
typedef mpl::bool_<(is_integral<Functor>::value)> integral;
|
||||
return detail::function::compare_equal(f, g, integral());
|
||||
}
|
||||
|
||||
template<typename R BOOST_FUNCTION_COMMA BOOST_FUNCTION_TEMPLATE_PARMS ,
|
||||
typename Allocator, typename Functor>
|
||||
inline bool
|
||||
operator==(Functor g,
|
||||
const BOOST_FUNCTION_FUNCTION<
|
||||
R BOOST_FUNCTION_COMMA
|
||||
BOOST_FUNCTION_TEMPLATE_ARGS ,
|
||||
Allocator>& f)
|
||||
{
|
||||
typedef mpl::bool_<(is_integral<Functor>::value)> integral;
|
||||
return detail::function::compare_equal(f, g, integral());
|
||||
}
|
||||
|
||||
template<typename R BOOST_FUNCTION_COMMA BOOST_FUNCTION_TEMPLATE_PARMS ,
|
||||
typename Allocator, typename Functor>
|
||||
inline bool
|
||||
operator!=(const BOOST_FUNCTION_FUNCTION<
|
||||
R BOOST_FUNCTION_COMMA
|
||||
BOOST_FUNCTION_TEMPLATE_ARGS ,
|
||||
Allocator>& f,
|
||||
Functor g)
|
||||
{
|
||||
typedef mpl::bool_<(is_integral<Functor>::value)> integral;
|
||||
return detail::function::compare_not_equal(f, g, integral());
|
||||
}
|
||||
|
||||
template<typename R BOOST_FUNCTION_COMMA BOOST_FUNCTION_TEMPLATE_PARMS ,
|
||||
typename Allocator, typename Functor>
|
||||
inline bool
|
||||
operator!=(Functor g,
|
||||
const BOOST_FUNCTION_FUNCTION<
|
||||
R BOOST_FUNCTION_COMMA
|
||||
BOOST_FUNCTION_TEMPLATE_ARGS ,
|
||||
Allocator>& f)
|
||||
{
|
||||
typedef mpl::bool_<(is_integral<Functor>::value)> integral;
|
||||
return detail::function::compare_not_equal(f, g, integral());
|
||||
}
|
||||
#else
|
||||
|
||||
#define BOOST_FUNCTION_ENABLE_IF_NOT_INTEGRAL(Functor,Type) \
|
||||
typename enable_if_c<(::boost::type_traits::ice_not< \
|
||||
(is_integral<Functor>::value)>::value), \
|
||||
Type>::type
|
||||
|
||||
// Comparisons between boost::function objects and arbitrary function objects
|
||||
template<typename R BOOST_FUNCTION_COMMA BOOST_FUNCTION_TEMPLATE_PARMS ,
|
||||
typename Allocator, typename Functor>
|
||||
BOOST_FUNCTION_ENABLE_IF_NOT_INTEGRAL(Functor, bool)
|
||||
operator==(const BOOST_FUNCTION_FUNCTION<
|
||||
R BOOST_FUNCTION_COMMA
|
||||
BOOST_FUNCTION_TEMPLATE_ARGS ,
|
||||
Allocator>& f,
|
||||
Functor g)
|
||||
{
|
||||
if (const Functor* fp = f.template contains<Functor>()) return *fp == g;
|
||||
else return false;
|
||||
}
|
||||
|
||||
template<typename R BOOST_FUNCTION_COMMA BOOST_FUNCTION_TEMPLATE_PARMS ,
|
||||
typename Allocator, typename Functor>
|
||||
BOOST_FUNCTION_ENABLE_IF_NOT_INTEGRAL(Functor, bool)
|
||||
operator==(Functor g,
|
||||
const BOOST_FUNCTION_FUNCTION<
|
||||
R BOOST_FUNCTION_COMMA
|
||||
BOOST_FUNCTION_TEMPLATE_ARGS ,
|
||||
Allocator>& f)
|
||||
{
|
||||
if (const Functor* fp = f.template contains<Functor>()) return g == *fp;
|
||||
else return false;
|
||||
}
|
||||
|
||||
template<typename R BOOST_FUNCTION_COMMA BOOST_FUNCTION_TEMPLATE_PARMS ,
|
||||
typename Allocator, typename Functor>
|
||||
BOOST_FUNCTION_ENABLE_IF_NOT_INTEGRAL(Functor, bool)
|
||||
operator!=(const BOOST_FUNCTION_FUNCTION<
|
||||
R BOOST_FUNCTION_COMMA
|
||||
BOOST_FUNCTION_TEMPLATE_ARGS ,
|
||||
Allocator>& f,
|
||||
Functor g)
|
||||
{
|
||||
if (const Functor* fp = f.template contains<Functor>()) return *fp != g;
|
||||
else return true;
|
||||
}
|
||||
|
||||
template<typename R BOOST_FUNCTION_COMMA BOOST_FUNCTION_TEMPLATE_PARMS ,
|
||||
typename Allocator, typename Functor>
|
||||
BOOST_FUNCTION_ENABLE_IF_NOT_INTEGRAL(Functor, bool)
|
||||
operator!=(Functor g,
|
||||
const BOOST_FUNCTION_FUNCTION<
|
||||
R BOOST_FUNCTION_COMMA
|
||||
BOOST_FUNCTION_TEMPLATE_ARGS ,
|
||||
Allocator>& f)
|
||||
{
|
||||
if (const Functor* fp = f.template contains<Functor>()) return g != *fp;
|
||||
else return true;
|
||||
}
|
||||
#undef BOOST_FUNCTION_ENABLE_IF_NOT_INTEGRAL
|
||||
#endif // Compiler supporting SFINAE
|
||||
|
||||
#if !defined(BOOST_FUNCTION_NO_FUNCTION_TYPE_SYNTAX)
|
||||
|
||||
#if BOOST_FUNCTION_NUM_ARGS == 0
|
||||
|
@ -60,6 +60,8 @@ DEPENDS all : test ;
|
||||
[ run libs/function/test/function_ref_cxx98.cpp : : : : ]
|
||||
|
||||
[ run libs/function/test/function_ref_portable.cpp : : : : ]
|
||||
|
||||
[ run libs/function/test/contains_test.cpp : : : : ]
|
||||
;
|
||||
}
|
||||
|
96
test/contains_test.cpp
Normal file
96
test/contains_test.cpp
Normal file
@ -0,0 +1,96 @@
|
||||
// Boost.Function library
|
||||
|
||||
// Copyright Doug Gregor 2004. Use, modification and
|
||||
// distribution is subject to the Boost Software License, Version
|
||||
// 1.0. (See accompanying file LICENSE_1_0.txt or copy at
|
||||
// http://www.boost.org/LICENSE_1_0.txt)
|
||||
|
||||
#include <boost/test/minimal.hpp>
|
||||
#include <boost/function.hpp>
|
||||
#include <boost/ref.hpp>
|
||||
|
||||
static int forty_two() { return 42; }
|
||||
|
||||
struct Seventeen
|
||||
{
|
||||
int operator()() const { return 17; }
|
||||
};
|
||||
|
||||
struct ReturnInt
|
||||
{
|
||||
explicit ReturnInt(int value) : value(value) {}
|
||||
|
||||
int operator()() const { return value; }
|
||||
|
||||
int value;
|
||||
};
|
||||
|
||||
bool operator==(const ReturnInt& x, const ReturnInt& y)
|
||||
{ return x.value == y.value; }
|
||||
|
||||
bool operator!=(const ReturnInt& x, const ReturnInt& y)
|
||||
{ return x.value != y.value; }
|
||||
|
||||
static void contains_test()
|
||||
{
|
||||
boost::function0<int> f;
|
||||
|
||||
f = &forty_two;
|
||||
BOOST_TEST(*f.contains<int (*)()>() == &forty_two);
|
||||
BOOST_TEST(!f.contains<Seventeen>());
|
||||
|
||||
f = Seventeen();
|
||||
BOOST_TEST(!f.contains<int (*)()>());
|
||||
BOOST_TEST(f.contains<Seventeen>());
|
||||
|
||||
Seventeen this_seventeen;
|
||||
f = boost::ref(this_seventeen);
|
||||
BOOST_TEST(!f.contains<int (*)()>());
|
||||
BOOST_TEST(f.contains<Seventeen>());
|
||||
BOOST_TEST(f.contains<Seventeen>() == &this_seventeen);
|
||||
}
|
||||
|
||||
static void equal_test()
|
||||
{
|
||||
boost::function0<int> f;
|
||||
|
||||
f = &forty_two;
|
||||
BOOST_TEST(f == &forty_two);
|
||||
BOOST_TEST(&forty_two == f);
|
||||
BOOST_TEST(f != ReturnInt(17));
|
||||
BOOST_TEST(ReturnInt(17) != f);
|
||||
|
||||
f = ReturnInt(17);
|
||||
BOOST_TEST(f != &forty_two);
|
||||
BOOST_TEST(&forty_two != f);
|
||||
BOOST_TEST(f == ReturnInt(17));
|
||||
BOOST_TEST(ReturnInt(17) == f);
|
||||
BOOST_TEST(f != ReturnInt(16));
|
||||
BOOST_TEST(ReturnInt(16) != f);
|
||||
|
||||
#if !defined(BOOST_FUNCTION_NO_FUNCTION_TYPE_SYNTAX)
|
||||
boost::function<int(void)> g;
|
||||
|
||||
g = &forty_two;
|
||||
BOOST_TEST(g == &forty_two);
|
||||
BOOST_TEST(&forty_two == g);
|
||||
BOOST_TEST(g != ReturnInt(17));
|
||||
BOOST_TEST(ReturnInt(17) != g);
|
||||
|
||||
g = ReturnInt(17);
|
||||
BOOST_TEST(g != &forty_two);
|
||||
BOOST_TEST(&forty_two != g);
|
||||
BOOST_TEST(g == ReturnInt(17));
|
||||
BOOST_TEST(ReturnInt(17) == g);
|
||||
BOOST_TEST(g != ReturnInt(16));
|
||||
BOOST_TEST(ReturnInt(16) != g);
|
||||
#endif
|
||||
}
|
||||
|
||||
int test_main(int, char*[])
|
||||
{
|
||||
contains_test();
|
||||
equal_test();
|
||||
|
||||
return 0;
|
||||
}
|
Reference in New Issue
Block a user