forked from boostorg/function
Implement an optimization that David Abrahams and myself came up with,
where Boost.Function uses a bit in the vtable pointer to indicate when the target function object has a trivial copy constructor, trivial destructor, and fits within the small object buffer. In this case, we just copy the bits of the function object rather than performing an indirect call to the manager. This results in a 60% speedup on a micro-benchmark that copies and calls such function objects repeatedly. [SVN r51743]
This commit is contained in:
@ -678,6 +678,11 @@ namespace boost {
|
||||
R BOOST_FUNCTION_COMMA BOOST_FUNCTION_TEMPLATE_ARGS>
|
||||
vtable_type;
|
||||
|
||||
vtable_type* get_vtable() const {
|
||||
return reinterpret_cast<vtable_type*>(
|
||||
reinterpret_cast<std::size_t>(vtable) & ~(std::size_t)0x01);
|
||||
}
|
||||
|
||||
struct clear_type {};
|
||||
|
||||
public:
|
||||
@ -757,7 +762,7 @@ namespace boost {
|
||||
if (this->empty())
|
||||
boost::throw_exception(bad_function_call());
|
||||
|
||||
return static_cast<vtable_type*>(vtable)->invoker
|
||||
return get_vtable()->invoker
|
||||
(this->functor BOOST_FUNCTION_COMMA BOOST_FUNCTION_ARGS);
|
||||
}
|
||||
#else
|
||||
@ -847,7 +852,8 @@ namespace boost {
|
||||
void clear()
|
||||
{
|
||||
if (vtable) {
|
||||
reinterpret_cast<vtable_type*>(vtable)->clear(this->functor);
|
||||
if (!this->has_trivial_copy_and_destroy())
|
||||
get_vtable()->clear(this->functor);
|
||||
vtable = 0;
|
||||
}
|
||||
}
|
||||
@ -876,8 +882,11 @@ namespace boost {
|
||||
{
|
||||
if (!f.empty()) {
|
||||
this->vtable = f.vtable;
|
||||
f.vtable->manager(f.functor, this->functor,
|
||||
boost::detail::function::clone_functor_tag);
|
||||
if (this->has_trivial_copy_and_destroy())
|
||||
this->functor = f.functor;
|
||||
else
|
||||
get_vtable()->base.manager(f.functor, this->functor,
|
||||
boost::detail::function::clone_functor_tag);
|
||||
}
|
||||
}
|
||||
|
||||
@ -903,8 +912,15 @@ namespace boost {
|
||||
static vtable_type stored_vtable =
|
||||
{ { &manager_type::manage }, &invoker_type::invoke };
|
||||
|
||||
if (stored_vtable.assign_to(f, functor)) vtable = &stored_vtable.base;
|
||||
else vtable = 0;
|
||||
if (stored_vtable.assign_to(f, functor)) {
|
||||
std::size_t value = reinterpret_cast<std::size_t>(&stored_vtable.base);
|
||||
if (boost::has_trivial_copy_constructor<Functor>::value &&
|
||||
boost::has_trivial_destructor<Functor>::value &&
|
||||
detail::function::function_allows_small_object_optimization<Functor>::value)
|
||||
value |= (std::size_t)0x01;
|
||||
vtable = reinterpret_cast<detail::function::vtable_base *>(value);
|
||||
} else
|
||||
vtable = 0;
|
||||
}
|
||||
|
||||
template<typename Functor,typename Allocator>
|
||||
@ -930,8 +946,15 @@ namespace boost {
|
||||
static vtable_type stored_vtable =
|
||||
{ { &manager_type::manage }, &invoker_type::invoke };
|
||||
|
||||
if (stored_vtable.assign_to_a(f, functor, a)) vtable = &stored_vtable.base;
|
||||
else vtable = 0;
|
||||
if (stored_vtable.assign_to_a(f, functor, a)) {
|
||||
std::size_t value = reinterpret_cast<std::size_t>(&stored_vtable.base);
|
||||
if (boost::has_trivial_copy_constructor<Functor>::value &&
|
||||
boost::has_trivial_destructor<Functor>::value &&
|
||||
detail::function::function_allows_small_object_optimization<Functor>::value)
|
||||
value |= (std::size_t)0x01;
|
||||
vtable = reinterpret_cast<detail::function::vtable_base *>(value);
|
||||
} else
|
||||
vtable = 0;
|
||||
}
|
||||
|
||||
// Moves the value from the specified argument to *this. If the argument
|
||||
@ -947,9 +970,12 @@ namespace boost {
|
||||
#endif
|
||||
if (!f.empty()) {
|
||||
this->vtable = f.vtable;
|
||||
f.vtable->manager(f.functor, this->functor,
|
||||
boost::detail::function::move_functor_tag);
|
||||
f.vtable = 0;
|
||||
if (this->has_trivial_copy_and_destroy())
|
||||
this->functor = f.functor;
|
||||
else
|
||||
get_vtable()->base.manager(f.functor, this->functor,
|
||||
boost::detail::function::move_functor_tag);
|
||||
f.vtable = 0;
|
||||
#if !defined(BOOST_NO_EXCEPTIONS)
|
||||
} else {
|
||||
clear();
|
||||
@ -979,13 +1005,14 @@ namespace boost {
|
||||
template<typename R BOOST_FUNCTION_COMMA BOOST_FUNCTION_TEMPLATE_PARMS>
|
||||
typename BOOST_FUNCTION_FUNCTION<
|
||||
R BOOST_FUNCTION_COMMA BOOST_FUNCTION_TEMPLATE_ARGS>::result_type
|
||||
BOOST_FUNCTION_FUNCTION<R BOOST_FUNCTION_COMMA BOOST_FUNCTION_TEMPLATE_ARGS>
|
||||
inline
|
||||
BOOST_FUNCTION_FUNCTION<R BOOST_FUNCTION_COMMA BOOST_FUNCTION_TEMPLATE_ARGS>
|
||||
::operator()(BOOST_FUNCTION_PARMS) const
|
||||
{
|
||||
if (this->empty())
|
||||
boost::throw_exception(bad_function_call());
|
||||
|
||||
return reinterpret_cast<const vtable_type*>(vtable)->invoker
|
||||
return get_vtable()->invoker
|
||||
(this->functor BOOST_FUNCTION_COMMA BOOST_FUNCTION_ARGS);
|
||||
}
|
||||
#endif
|
||||
|
Reference in New Issue
Block a user