diff --git a/include/boost/unordered/detail/foa/concurrent_table.hpp b/include/boost/unordered/detail/foa/concurrent_table.hpp index 9dbef35c..07771ca5 100644 --- a/include/boost/unordered/detail/foa/concurrent_table.hpp +++ b/include/boost/unordered/detail/foa/concurrent_table.hpp @@ -691,6 +691,18 @@ public: return emplace_impl(std::forward(x)); } + /* Optimizations for maps for (k,v) to avoid eagerly constructing value */ + template + BOOST_FORCEINLINE auto emplace(K&& k, V&& v) -> + typename std::enable_if::value, + bool>::type + { + alloc_cted_or_fwded_key_type x( + this->al(), std::forward(k)); + return emplace_impl( + try_emplace_args_t{}, x.move_or_fwd(), std::forward(v)); + } + BOOST_FORCEINLINE bool insert(const init_type& x){return emplace_impl(x);} diff --git a/include/boost/unordered/detail/foa/core.hpp b/include/boost/unordered/detail/foa/core.hpp index 64894a04..5da7acb9 100644 --- a/include/boost/unordered/detail/foa/core.hpp +++ b/include/boost/unordered/detail/foa/core.hpp @@ -1232,6 +1232,58 @@ public: insert_type& value(){return val.value();} }; +template +alloc_cted_insert_type +alloc_make_insert_type(const Allocator& al,Args&&... args) +{ + return {al,std::forward(args)...}; +} + +template +class alloc_cted_or_fwded_key_type +{ + using key_type = typename TypePolicy::key_type; + allocator_constructed val; + +public: + alloc_cted_or_fwded_key_type(const Allocator& al_, KFwdRef k) + : val(al_, std::forward(k)) + { + } + + key_type&& move_or_fwd() { return std::move(val.value()); } +}; + +template +class alloc_cted_or_fwded_key_type::value>::type> +{ + // This specialization acts as a forwarding-reference wrapper + BOOST_UNORDERED_STATIC_ASSERT(std::is_reference::value); + KFwdRef ref; + +public: + alloc_cted_or_fwded_key_type(const Allocator&, KFwdRef k) + : ref(std::forward(k)) + { + } + + KFwdRef move_or_fwd() { return std::forward(ref); } +}; + +template +using is_map = + std::integral_constant::value>; + +template +using is_emplace_kv_able = std::integral_constant::value && + (is_similar::value || + is_complete_and_move_constructible::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 diff --git a/include/boost/unordered/detail/foa/flat_map_types.hpp b/include/boost/unordered/detail/foa/flat_map_types.hpp index 712df5fb..a97daba1 100644 --- a/include/boost/unordered/detail/foa/flat_map_types.hpp +++ b/include/boost/unordered/detail/foa/flat_map_types.hpp @@ -56,6 +56,12 @@ namespace boost { boost::allocator_construct(al, p, std::forward(args)...); } + template + static void construct(A& al, key_type* p, Args&&... args) + { + boost::allocator_construct(al, p, std::forward(args)...); + } + template 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 static void destroy(A& al, key_type* p) noexcept + { + boost::allocator_destroy(al, p); + } }; } // namespace foa } // namespace detail diff --git a/include/boost/unordered/detail/foa/node_map_types.hpp b/include/boost/unordered/detail/foa/node_map_types.hpp index ccb378ef..e4308a11 100644 --- a/include/boost/unordered/detail/foa/node_map_types.hpp +++ b/include/boost/unordered/detail/foa/node_map_types.hpp @@ -82,6 +82,12 @@ namespace boost { boost::allocator_construct(al, p, std::forward(args)...); } + template + static void construct(A& al, key_type* p, Args&&... args) + { + boost::allocator_construct(al, p, std::forward(args)...); + } + template static void construct(A& al, element_type* p, Args&&... args) { @@ -109,6 +115,11 @@ namespace boost { boost::allocator_destroy(al, p); } + template static void destroy(A& al, key_type* p) noexcept + { + boost::allocator_destroy(al, p); + } + template static void destroy(A& al, element_type* p) noexcept { diff --git a/include/boost/unordered/detail/foa/table.hpp b/include/boost/unordered/detail/foa/table.hpp index 0cd56de2..2ec49595 100644 --- a/include/boost/unordered/detail/foa/table.hpp +++ b/include/boost/unordered/detail/foa/table.hpp @@ -416,6 +416,19 @@ public: return emplace_impl(std::forward(x)); } + /* Optimizations for maps for (k,v) to avoid eagerly constructing value */ + template + BOOST_FORCEINLINE + typename std::enable_if::value, + std::pair >::type + emplace(K&& k, V&& v) + { + alloc_cted_or_fwded_key_type x( + this->al(), std::forward(k)); + return emplace_impl( + try_emplace_args_t{}, x.move_or_fwd(), std::forward(v)); + } + template BOOST_FORCEINLINE std::pair try_emplace( Key&& x,Args&&... args) diff --git a/include/boost/unordered/detail/type_traits.hpp b/include/boost/unordered/detail/type_traits.hpp index 0ae5656f..18f90a3c 100644 --- a/include/boost/unordered/detail/type_traits.hpp +++ b/include/boost/unordered/detail/type_traits.hpp @@ -48,6 +48,20 @@ namespace boost { template using void_t = typename make_void::type; + template struct is_complete : std::false_type + { + }; + + template + struct is_complete > : std::true_type + { + }; + + template + using is_complete_and_move_constructible = + typename std::conditional::value, + std::is_move_constructible, std::false_type>::type; + #if BOOST_WORKAROUND(BOOST_LIBSTDCXX_VERSION, < 50000) /* std::is_trivially_default_constructible not provided */ template