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:
Douglas Gregor
2004-01-20 18:02:02 +00:00
parent 50ff886c81
commit 7d30d98efd
4 changed files with 372 additions and 24 deletions

View File

@ -14,17 +14,31 @@
#include <string> #include <string>
#include <memory> #include <memory>
#include <new> #include <new>
#include <typeinfo>
#include <boost/config.hpp> #include <boost/config.hpp>
#include <boost/assert.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/composite_traits.hpp>
#include <boost/type_traits/is_stateless.hpp> #include <boost/type_traits/is_stateless.hpp>
#include <boost/ref.hpp> #include <boost/ref.hpp>
#include <boost/pending/ct_if.hpp> #include <boost/pending/ct_if.hpp>
#include <boost/detail/workaround.hpp> #include <boost/detail/workaround.hpp>
#ifndef BOOST_NO_SFINAE #ifndef BOOST_NO_SFINAE
# include "boost/utility/enable_if.hpp" # 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 #endif
#if defined(BOOST_MSVC) && BOOST_MSVC <= 1300 || defined(__ICL) && __ICL <= 600 || defined(__MWERKS__) && __MWERKS__ < 0x2406 && !defined(BOOST_STRICT_CONFIG) #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 // The operation type to perform on the given functor/function pointer
enum functor_manager_operation_type { enum functor_manager_operation_type {
clone_functor_tag, clone_functor_tag,
destroy_functor_tag destroy_functor_tag,
check_functor_type_tag
}; };
// Tags used to decide between different types of functions // 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 // The trivial manager does nothing but return the same pointer (if we
// are cloning) or return the null pointer (if we are deleting). // are cloning) or return the null pointer (if we are deleting).
inline any_pointer trivial_manager(any_pointer f, template<typename F>
functor_manager_operation_type op) inline any_pointer
{ trivial_manager(any_pointer f, functor_manager_operation_type op)
if (op == clone_functor_tag) {
return f; switch (op) {
else 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)); return make_any_pointer(reinterpret_cast<void*>(0));
} }
/** /**
* The functor_manager class contains a static function "manage" which * The functor_manager class contains a static function "manage" which
@ -264,13 +292,59 @@ namespace boost {
static any_pointer static any_pointer
manage(any_pointer functor_ptr, functor_manager_operation_type op) manage(any_pointer functor_ptr, functor_manager_operation_type op)
{ {
typedef typename get_function_tag<functor_type>::type tag_type; if (op == check_functor_type_tag) {
return manager(functor_ptr, op, tag_type()); 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 // A type that is only used for comparisons against zero
struct useless_clear_type {}; 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 function
} // end namespace detail } // end namespace detail
@ -291,11 +365,59 @@ public:
// Is this function empty? // Is this function empty?
bool empty() const { return !manager; } 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 public: // should be protected, but GCC 2.95.3 will fail to allow access
detail::function::any_pointer (*manager)( detail::function::any_pointer (*manager)(
detail::function::any_pointer, detail::function::any_pointer,
detail::function::functor_manager_operation_type); detail::function::functor_manager_operation_type);
detail::function::any_pointer functor; 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") {} bad_function_call() : std::runtime_error("call to empty boost::function") {}
}; };
/* Poison comparison between Boost.Function objects (because it is #ifndef BOOST_NO_SFINAE
* 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)
inline bool operator==(const function_base& f, inline bool operator==(const function_base& f,
detail::function::useless_clear_type*) detail::function::useless_clear_type*)
{ {

View File

@ -508,7 +508,7 @@ namespace boost {
invoker_type; invoker_type;
invoker = &invoker_type::invoke; invoker = &invoker_type::invoke;
this->manager = &detail::function::trivial_manager; this->manager = &detail::function::trivial_manager<FunctionObj>;
this->functor = this->functor =
this->manager( this->manager(
detail::function::make_any_pointer( detail::function::make_any_pointer(
@ -529,7 +529,7 @@ namespace boost {
>::type >::type
invoker_type; invoker_type;
invoker = &invoker_type::invoke; 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); this->functor = detail::function::make_any_pointer(this);
} }
@ -556,6 +556,143 @@ namespace boost {
f1.swap(f2); 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 !defined(BOOST_FUNCTION_NO_FUNCTION_TYPE_SYNTAX)
#if BOOST_FUNCTION_NUM_ARGS == 0 #if BOOST_FUNCTION_NUM_ARGS == 0

View File

@ -60,6 +60,8 @@ DEPENDS all : test ;
[ run libs/function/test/function_ref_cxx98.cpp : : : : ] [ run libs/function/test/function_ref_cxx98.cpp : : : : ]
[ run libs/function/test/function_ref_portable.cpp : : : : ] [ run libs/function/test/function_ref_portable.cpp : : : : ]
[ run libs/function/test/contains_test.cpp : : : : ]
; ;
} }

96
test/contains_test.cpp Normal file
View 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;
}