libstdc++: Optimize std::any_cast by replacing indirect call

This significantly improves the performance of std::any_cast, by
avoiding an indirect call to the _S_manage function through a function
pointer. Before we make that indirect call we've already established
that the contained value has the expected type, which means we also know
the manager type, and so can call one of its members directly.

We also know the precise type in the any::emplace functions, because
we've just constructed that type, so we can use the new member there
too. That doesn't seem to affect performance, but we might as well use
the new _S_access function anyway.

Signed-off-by: Tim Adye <Tim.Adye@cern.ch>
Signed-off-by: Jonathan Wakely <jwakely@redhat.com>

libstdc++-v3/ChangeLog:

	* include/std/any (any::_Manager::_S_access): New static
	function to access the contained value.
	(any::emplace, __any_caster): Use _S_access member of the
	manager type.
This commit is contained in:
Tim Adye 2021-06-04 15:59:38 +01:00 committed by Jonathan Wakely
parent f78f25f438
commit f6bb145c0b
1 changed files with 17 additions and 9 deletions

View File

@ -263,9 +263,7 @@ _GLIBCXX_BEGIN_NAMESPACE_VERSION
{
using _VTp = decay_t<_Tp>;
__do_emplace<_VTp>(std::forward<_Args>(__args)...);
any::_Arg __arg;
this->_M_manager(any::_Op_access, this, &__arg);
return *static_cast<_VTp*>(__arg._M_obj);
return *any::_Manager<_VTp>::_S_access(_M_storage);
}
/// Emplace with an object created from @p __il and @p __args as
@ -276,9 +274,7 @@ _GLIBCXX_BEGIN_NAMESPACE_VERSION
{
using _VTp = decay_t<_Tp>;
__do_emplace<_VTp, _Up>(__il, std::forward<_Args>(__args)...);
any::_Arg __arg;
this->_M_manager(any::_Op_access, this, &__arg);
return *static_cast<_VTp*>(__arg._M_obj);
return *any::_Manager<_VTp>::_S_access(_M_storage);
}
// modifiers
@ -384,6 +380,14 @@ _GLIBCXX_BEGIN_NAMESPACE_VERSION
void* __addr = &__storage._M_buffer;
::new (__addr) _Tp(std::forward<_Args>(__args)...);
}
static _Tp*
_S_access(const _Storage& __storage)
{
// The contained object is in __storage._M_buffer
const void* __addr = &__storage._M_buffer;
return static_cast<_Tp*>(const_cast<void*>(__addr));
}
};
// Manage external contained object.
@ -405,6 +409,12 @@ _GLIBCXX_BEGIN_NAMESPACE_VERSION
{
__storage._M_ptr = new _Tp(std::forward<_Args>(__args)...);
}
static _Tp*
_S_access(const _Storage& __storage)
{
// The contained object is in *__storage._M_ptr
return static_cast<_Tp*>(__storage._M_ptr);
}
};
};
@ -511,9 +521,7 @@ _GLIBCXX_BEGIN_NAMESPACE_VERSION
#endif
)
{
any::_Arg __arg;
__any->_M_manager(any::_Op_access, __any, &__arg);
return __arg._M_obj;
return any::_Manager<_Up>::_S_access(__any->_M_storage);
}
return nullptr;
}