Added support for target_type() member function (returns an std::type_info of

the underlying function object) and casting to retrieve the underyling target.


[SVN r11360]
This commit is contained in:
Douglas Gregor
2001-10-08 13:32:24 +00:00
parent 62d3c6d426
commit 1d4282c706
2 changed files with 156 additions and 6 deletions

View File

@ -19,6 +19,8 @@
#include <string> #include <string>
#include <stdexcept> #include <stdexcept>
#include <memory> #include <memory>
#include <new>
#include <typeinfo>
#include <boost/config.hpp> #include <boost/config.hpp>
#include <boost/type_traits.hpp> #include <boost/type_traits.hpp>
@ -78,9 +80,11 @@ namespace boost {
union any_pointer union any_pointer
{ {
void* obj_ptr; void* obj_ptr;
const void* const_obj_ptr;
void (*func_ptr)(); void (*func_ptr)();
explicit any_pointer(void* p) : obj_ptr(p) {} explicit any_pointer(void* p) : obj_ptr(p) {}
explicit any_pointer(const void* p) : const_obj_ptr(p) {}
explicit any_pointer(void (*p)()) : func_ptr(p) {} explicit any_pointer(void (*p)()) : func_ptr(p) {}
}; };
@ -109,7 +113,11 @@ 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 { clone_functor, destroy_functor }; enum functor_manager_operation_type {
clone_functor,
destroy_functor,
retrieve_type_info
};
// Tags used to decide between function and function object pointers. // Tags used to decide between function and function object pointers.
struct function_ptr_tag {}; struct function_ptr_tag {};
@ -140,8 +148,10 @@ namespace boost {
{ {
if (op == clone_functor) if (op == clone_functor)
return function_ptr; return function_ptr;
else else if (op == destroy_functor)
return any_pointer(static_cast<void (*)()>(0)); return any_pointer(static_cast<void (*)()>(0));
else
return any_pointer(&typeid(Functor));
} }
// For function object pointers, we clone the pointer to each // For function object pointers, we clone the pointer to each
@ -171,7 +181,7 @@ namespace boost {
# endif // BOOST_NO_STD_ALLOCATOR # endif // BOOST_NO_STD_ALLOCATOR
return any_pointer(static_cast<void*>(new_f)); return any_pointer(static_cast<void*>(new_f));
} }
else { else if (op == destroy_functor) {
/* Cast from the void pointer to the functor pointer type */ /* Cast from the void pointer to the functor pointer type */
functor_type* f = functor_type* f =
reinterpret_cast<functor_type*>(function_obj_ptr.obj_ptr); reinterpret_cast<functor_type*>(function_obj_ptr.obj_ptr);
@ -190,8 +200,10 @@ namespace boost {
return any_pointer(static_cast<void*>(0)); return any_pointer(static_cast<void*>(0));
} }
else {
return any_pointer(&typeid(Functor));
}
} }
public: public:
/* Dispatch to an appropriate manager based on whether we have a /* Dispatch to an appropriate manager based on whether we have a
function pointer or a function object pointer. */ function pointer or a function object pointer. */

View File

@ -46,6 +46,8 @@ namespace boost {
virtual R call(BOOST_FUNCTION_PARMS) const = 0; virtual R call(BOOST_FUNCTION_PARMS) const = 0;
virtual BOOST_FUNCTION_INVOKER_BASE* clone() const = 0; virtual BOOST_FUNCTION_INVOKER_BASE* clone() const = 0;
virtual void destroy(BOOST_FUNCTION_INVOKER_BASE*) = 0; virtual void destroy(BOOST_FUNCTION_INVOKER_BASE*) = 0;
virtual const std::type_info& type() const = 0;
virtual any_pointer pointer() const = 0;
}; };
#endif // BOOST_FUNCTION_USE_VIRTUAL_FUNCTIONS #endif // BOOST_FUNCTION_USE_VIRTUAL_FUNCTIONS
@ -113,8 +115,18 @@ namespace boost {
# endif // BOOST_NO_STD_ALLOCATOR # endif // BOOST_NO_STD_ALLOCATOR
} }
virtual const std::type_info& type() const
{
return typeid(FunctionPtr);
}
virtual any_pointer pointer() const
{
return any_pointer(reinterpret_cast<void (*)()>(function_ptr));
}
private: private:
FunctionPtr function_ptr; mutable FunctionPtr function_ptr;
#else #else
static R invoke(any_pointer function_ptr BOOST_FUNCTION_COMMA static R invoke(any_pointer function_ptr BOOST_FUNCTION_COMMA
BOOST_FUNCTION_PARMS) BOOST_FUNCTION_PARMS)
@ -190,8 +202,18 @@ namespace boost {
# endif // BOOST_NO_STD_ALLOCATOR # endif // BOOST_NO_STD_ALLOCATOR
} }
virtual const std::type_info& type() const
{
return typeid(FunctionPtr);
}
virtual any_pointer pointer() const
{
return any_pointer(reinterpret_cast<void (*)()>(function_ptr));
}
private: private:
FunctionPtr function_ptr; mutable FunctionPtr function_ptr;
# else # else
static unusable invoke(any_pointer function_ptr BOOST_FUNCTION_COMMA static unusable invoke(any_pointer function_ptr BOOST_FUNCTION_COMMA
BOOST_FUNCTION_PARMS) BOOST_FUNCTION_PARMS)
@ -268,6 +290,16 @@ namespace boost {
#endif // BOOST_NO_STD_ALLOCATOR #endif // BOOST_NO_STD_ALLOCATOR
} }
virtual const std::type_info& type() const
{
return typeid(FunctionObj);
}
virtual any_pointer pointer() const
{
return any_pointer(&function_obj);
}
private: private:
mutable FunctionObj function_obj; mutable FunctionObj function_obj;
#else #else
@ -346,6 +378,16 @@ namespace boost {
# endif // BOOST_NO_STD_ALLOCATOR # endif // BOOST_NO_STD_ALLOCATOR
} }
virtual const std::type_info& type() const
{
return typeid(FunctionObj);
}
virtual any_pointer pointer() const
{
return any_pointer(&function_obj);
}
private: private:
mutable FunctionObj function_obj; mutable FunctionObj function_obj;
# else # else
@ -601,7 +643,73 @@ namespace boost {
#endif // BOOST_FUNCTION_USE_VIRTUAL_FUNCTIONS #endif // BOOST_FUNCTION_USE_VIRTUAL_FUNCTIONS
} }
const std::type_info& target_type() const
{
if (this->empty())
return typeid(void);
else {
#ifdef BOOST_FUNCTION_USE_VIRTUAL_FUNCTIONS
impl_type* i = reinterpret_cast<impl_type*>(impl);
return i->type();
#else
detail::function::any_pointer p =
manager(functor, detail::function::retrieve_type_info);
return *static_cast<const std::type_info*>(p.const_obj_ptr);
#endif // BOOST_FUNCTION_USE_VIRTUAL_FUNCTIONS
}
}
template<typename To>
To& cast(To* = 0)
{
assert(typeid(To) != typeid(void));
assert(typeid(To) == this->target_type());
typedef typename detail::function::IF<(is_pointer<To>::value),
detail::function::function_ptr_tag,
detail::function::function_obj_tag>::type tag;
#ifdef BOOST_FUNCTION_USE_VIRTUAL_FUNCTIONS
impl_type* i = reinterpret_cast<impl_type*>(impl);
return cast_helper<To>(i->pointer(), tag());
#else
return cast_helper<To>(functor, tag());
#endif // BOOST_FUNCTION_USE_VIRTUAL_FUNCTIONS
}
template<typename To>
const To& cast(To* = 0) const
{
assert(typeid(To) != typeid(void));
assert(typeid(To) == this->target_type());
typedef typename detail::function::IF<(is_pointer<To>::value),
detail::function::function_ptr_tag,
detail::function::function_obj_tag>::type tag;
#ifdef BOOST_FUNCTION_USE_VIRTUAL_FUNCTIONS
impl_type* i = reinterpret_cast<impl_type*>(impl);
return cast_helper<To>(i->pointer(), tag());
#else
return cast_helper<To>(functor, tag());
#endif // BOOST_FUNCTION_USE_VIRTUAL_FUNCTIONS
}
private: private:
template<typename To>
To& cast_helper(detail::function::any_pointer p,
detail::function::function_ptr_tag,
To* = 0) const
{
return reinterpret_cast<To>(p.func_ptr);
}
template<typename To>
To& cast_helper(detail::function::any_pointer p,
detail::function::function_obj_tag,
To* = 0) const
{
return *static_cast<To*>(p.obj_ptr);
}
void assign_to_own(const BOOST_FUNCTION_FUNCTION& f) void assign_to_own(const BOOST_FUNCTION_FUNCTION& f)
{ {
if (!f.empty()) { if (!f.empty()) {
@ -731,6 +839,36 @@ namespace boost {
{ {
f1.swap(f2); f1.swap(f2);
} }
template<typename To, typename R
BOOST_FUNCTION_COMMA BOOST_FUNCTION_TEMPLATE_PARMS ,
typename Policy, typename Mixin, typename Allocator>
inline To& function_cast(BOOST_FUNCTION_FUNCTION<
R BOOST_FUNCTION_COMMA
BOOST_FUNCTION_TEMPLATE_ARGS ,
Policy,
Mixin,
Allocator
>& f,
To* = 0)
{
return f.template cast<To>();
}
template<typename To, typename R
BOOST_FUNCTION_COMMA BOOST_FUNCTION_TEMPLATE_PARMS ,
typename Policy, typename Mixin, typename Allocator>
inline const To& function_cast(const BOOST_FUNCTION_FUNCTION<
R BOOST_FUNCTION_COMMA
BOOST_FUNCTION_TEMPLATE_ARGS ,
Policy,
Mixin,
Allocator
>& f,
To* = 0)
{
return f.template cast<To>();
}
} }
// Cleanup after ourselves... // Cleanup after ourselves...