Optimize emplace(k,v) for foa and cfoa containers

This commit is contained in:
Braden Ganetsky
2024-02-10 11:27:43 -06:00
parent 4fbe450a65
commit 4e6d4ade6c
6 changed files with 114 additions and 1 deletions

View File

@ -691,6 +691,18 @@ public:
return emplace_impl(std::forward<Value>(x));
}
/* Optimizations for maps for (k,v) to avoid eagerly constructing value */
template <typename K, typename V>
BOOST_FORCEINLINE auto emplace(K&& k, V&& v) ->
typename std::enable_if<is_emplace_kv_able<concurrent_table, K>::value,
bool>::type
{
alloc_cted_or_fwded_key_type<type_policy, Allocator, K&&> x(
this->al(), std::forward<K>(k));
return emplace_impl(
try_emplace_args_t{}, x.move_or_fwd(), std::forward<V>(v));
}
BOOST_FORCEINLINE bool
insert(const init_type& x){return emplace_impl(x);}

View File

@ -1232,6 +1232,58 @@ public:
insert_type& value(){return val.value();}
};
template<typename TypePolicy,typename Allocator,typename... Args>
alloc_cted_insert_type<TypePolicy,Allocator,Args...>
alloc_make_insert_type(const Allocator& al,Args&&... args)
{
return {al,std::forward<Args>(args)...};
}
template <typename TypePolicy, typename Allocator, typename KFwdRef,
typename = void>
class alloc_cted_or_fwded_key_type
{
using key_type = typename TypePolicy::key_type;
allocator_constructed<Allocator, key_type, TypePolicy> val;
public:
alloc_cted_or_fwded_key_type(const Allocator& al_, KFwdRef k)
: val(al_, std::forward<KFwdRef>(k))
{
}
key_type&& move_or_fwd() { return std::move(val.value()); }
};
template <typename TypePolicy, typename Allocator, typename KFwdRef>
class alloc_cted_or_fwded_key_type<TypePolicy, Allocator, KFwdRef,
typename std::enable_if<
is_similar<KFwdRef, typename TypePolicy::key_type>::value>::type>
{
// This specialization acts as a forwarding-reference wrapper
BOOST_UNORDERED_STATIC_ASSERT(std::is_reference<KFwdRef>::value);
KFwdRef ref;
public:
alloc_cted_or_fwded_key_type(const Allocator&, KFwdRef k)
: ref(std::forward<KFwdRef>(k))
{
}
KFwdRef move_or_fwd() { return std::forward<KFwdRef>(ref); }
};
template <typename Container>
using is_map =
std::integral_constant<bool, !std::is_same<typename Container::key_type,
typename Container::value_type>::value>;
template <typename Container, typename K>
using is_emplace_kv_able = std::integral_constant<bool,
is_map<Container>::value &&
(is_similar<K, typename Container::key_type>::value ||
is_complete_and_move_constructible<typename Container::key_type>::value)>;
/* table_core. The TypePolicy template parameter is used to generate
* instantiations suitable for either maps or sets, and introduces non-standard
* init_type and element_type:
@ -1249,7 +1301,7 @@ public:
*
* - TypePolicy::construct and TypePolicy::destroy are used for the
* construction and destruction of the internal types: value_type,
* init_type and element_type.
* init_type, element_type, and key_type.
*
* - TypePolicy::move is used to provide move semantics for the internal
* types used by the container during rehashing and emplace. These types

View File

@ -56,6 +56,12 @@ namespace boost {
boost::allocator_construct(al, p, std::forward<Args>(args)...);
}
template <class A, class... Args>
static void construct(A& al, key_type* p, Args&&... args)
{
boost::allocator_construct(al, p, std::forward<Args>(args)...);
}
template <class A> static void destroy(A& al, init_type* p) noexcept
{
boost::allocator_destroy(al, p);
@ -65,6 +71,11 @@ namespace boost {
{
boost::allocator_destroy(al, p);
}
template <class A> static void destroy(A& al, key_type* p) noexcept
{
boost::allocator_destroy(al, p);
}
};
} // namespace foa
} // namespace detail

View File

@ -82,6 +82,12 @@ namespace boost {
boost::allocator_construct(al, p, std::forward<Args>(args)...);
}
template <class A, class... Args>
static void construct(A& al, key_type* p, Args&&... args)
{
boost::allocator_construct(al, p, std::forward<Args>(args)...);
}
template <class A, class... Args>
static void construct(A& al, element_type* p, Args&&... args)
{
@ -109,6 +115,11 @@ namespace boost {
boost::allocator_destroy(al, p);
}
template <class A> static void destroy(A& al, key_type* p) noexcept
{
boost::allocator_destroy(al, p);
}
template <class A>
static void destroy(A& al, element_type* p) noexcept
{

View File

@ -416,6 +416,19 @@ public:
return emplace_impl(std::forward<T>(x));
}
/* Optimizations for maps for (k,v) to avoid eagerly constructing value */
template <typename K, typename V>
BOOST_FORCEINLINE
typename std::enable_if<is_emplace_kv_able<table, K>::value,
std::pair<iterator, bool> >::type
emplace(K&& k, V&& v)
{
alloc_cted_or_fwded_key_type<type_policy, Allocator, K&&> x(
this->al(), std::forward<K>(k));
return emplace_impl(
try_emplace_args_t{}, x.move_or_fwd(), std::forward<V>(v));
}
template<typename Key,typename... Args>
BOOST_FORCEINLINE std::pair<iterator,bool> try_emplace(
Key&& x,Args&&... args)

View File

@ -48,6 +48,20 @@ namespace boost {
template <typename... Ts> using void_t = typename make_void<Ts...>::type;
template <class T, class = void> struct is_complete : std::false_type
{
};
template <class T>
struct is_complete<T, void_t<int[sizeof(T)]> > : std::true_type
{
};
template <class T>
using is_complete_and_move_constructible =
typename std::conditional<is_complete<T>::value,
std::is_move_constructible<T>, std::false_type>::type;
#if BOOST_WORKAROUND(BOOST_LIBSTDCXX_VERSION, < 50000)
/* std::is_trivially_default_constructible not provided */
template <class T>