diff --git a/include/boost/unordered/detail/foa.hpp b/include/boost/unordered/detail/foa.hpp index 0f9f1b79..5c6ca111 100644 --- a/include/boost/unordered/detail/foa.hpp +++ b/include/boost/unordered/detail/foa.hpp @@ -1129,6 +1129,25 @@ _STL_RESTORE_DEPRECATED_WARNING */ constexpr static float const mlf = 0.875f; +template +union storage +{ + T t_; + storage(){} + ~storage(){} +}; + +template +struct drop_guard +{ + using type_policy=TypePolicy; + + A& a; + T* p; + ~drop_guard(){type_policy::destroy(a,p);}; +}; + + /* foa::table interface departs in a number of ways from that of C++ unordered * associative containers because it's not for end-user consumption * (boost::unordered_[flat|node]_[map|set]) wrappers complete it as @@ -1418,18 +1437,35 @@ public: template BOOST_FORCEINLINE std::pair emplace(Args&&... args) { - /* We dispatch based on whether or not the value_type is constructible from - * an rvalue reference of the deduced emplace_type. We do this specifically - * for the case of the node-based containers. To this end, we're able to - * avoid allocating a node when a duplicate element is attempted to be - * inserted. For immovable types, we instead dispatch to the routine that - * unconditionally allocates via `type_policy::construct()`. - */ - return emplace_value( + using emplace_type=typename std::conditional< + std::is_constructible::value, + init_type, + value_type + >::type; + + using insert_type=typename std::conditional< std::is_constructible< - value_type, - emplace_type&&>{}, - std::forward(args)...); + value_type,emplace_type>::value, + emplace_type,element_type + >::type; + + using alloc_insert_type=typename std::conditional< + std::is_constructible< + value_type,emplace_type>::value, + emplace_type,value_type + >::type; + + using alloc_type= + typename boost::allocator_rebind::type; + + storage s; + alloc_type alloc{al()}; + auto *p=std::addressof(s.t_); + + type_policy::construct(alloc,p,std::forward(args)...); + + drop_guard guard{alloc,p}; + return emplace_impl(type_policy::move(*p)); } template @@ -1614,15 +1650,6 @@ private: template friend class table; using arrays_type=table_arrays; - template - using emplace_type = typename std::conditional< - std::is_constructible< - init_type,Args... - >::value, - init_type, - value_type - >::type; - struct clear_on_exit { ~clear_on_exit(){x.clear();} @@ -1904,29 +1931,6 @@ private: #pragma warning(pop) /* C4800 */ #endif - template - BOOST_FORCEINLINE std::pair emplace_value( - std::true_type /* movable value_type */,Args&&... args - ) { - using emplace_type_t = emplace_type; - return emplace_impl(emplace_type_t(std::forward(args)...)); - } - - template - BOOST_FORCEINLINE std::pair emplace_value( - std::false_type /* immovable value_type */,Args&&... args - ) { - alignas(element_type) - unsigned char buf[sizeof(element_type)]; - element_type* p = reinterpret_cast(buf); - - type_policy::construct(al(),p,std::forward(args)...); - destroy_element_on_exit d{this,p}; - (void)d; - - return emplace_impl(type_policy::move(*p)); - } - template BOOST_FORCEINLINE std::pair emplace_impl(Args&&... args) { diff --git a/include/boost/unordered/detail/foa/node_handle.hpp b/include/boost/unordered/detail/foa/node_handle.hpp index 1f6319db..49edd4f4 100644 --- a/include/boost/unordered/detail/foa/node_handle.hpp +++ b/include/boost/unordered/detail/foa/node_handle.hpp @@ -105,6 +105,9 @@ struct node_handle_base node_handle_base& operator=(node_handle_base&& nh)noexcept { + element_type x; + x.p=p_; + if(this!=&nh){ if(empty()){ if(nh.empty()){ /* empty(), nh.empty() */ @@ -115,7 +118,7 @@ struct node_handle_base } }else{ if(nh.empty()){ /* !empty(), nh.empty() */ - type_policy::destroy(al(),p_); + type_policy::destroy(al(),&x); reset(); }else{ /* !empty(), !nh.empty() */ bool const pocma= @@ -124,7 +127,7 @@ struct node_handle_base BOOST_ASSERT(pocma||al()==nh.al()); - type_policy::destroy(al(),p_); + type_policy::destroy(al(),&x); if(pocma){ al()=std::move(nh.al()); } @@ -137,7 +140,7 @@ struct node_handle_base if(empty()){ /* empty(), nh.empty() */ /* nothing to do */ }else{ /* !empty(), !nh.empty() */ - type_policy::destroy(al(),p_); + type_policy::destroy(al(),&x); reset(); } } @@ -147,7 +150,9 @@ struct node_handle_base ~node_handle_base() { if(!empty()){ - type_policy::destroy(al(),p_); + element_type x; + x.p=p_; + type_policy::destroy(al(),&x); reset(); } } diff --git a/include/boost/unordered/unordered_flat_map.hpp b/include/boost/unordered/unordered_flat_map.hpp index d419739b..758694a1 100644 --- a/include/boost/unordered/unordered_flat_map.hpp +++ b/include/boost/unordered/unordered_flat_map.hpp @@ -53,6 +53,11 @@ namespace boost { return kv.first; } + static moved_type move(init_type& x) + { + return {std::get<0>(std::move(x)), std::get<1>(std::move(x))}; + } + static moved_type move(element_type& x) { // TODO: we probably need to launder here @@ -61,11 +66,26 @@ namespace boost { } template - static void construct(A& al, element_type* p, Args&&... args) + static void construct(A& al, init_type* p, Args&&... args) { boost::allocator_construct(al, p, std::forward(args)...); } + template + static void construct(A& al, element_type* p, Args&&... args) + { + using alloc_type = + typename boost::allocator_rebind::type; + alloc_type alloc(al); + std::allocator_traits::construct( + alloc, p, std::forward(args)...); + } + + template static void destroy(A& al, init_type* p) noexcept + { + boost::allocator_destroy(al, p); + } + template static void destroy(A& al, element_type* p) noexcept { boost::allocator_destroy(al, p); diff --git a/include/boost/unordered/unordered_node_map.hpp b/include/boost/unordered/unordered_node_map.hpp index 3802d494..60eb5cc0 100644 --- a/include/boost/unordered/unordered_node_map.hpp +++ b/include/boost/unordered/unordered_node_map.hpp @@ -77,6 +77,11 @@ namespace boost { } static element_type&& move(element_type& x) { return std::move(x); } + static moved_type move(init_type& x) + { + return {std::get<0>(std::move(x)), std::get<1>(std::move(x))}; + } + static moved_type move(value_type& x) { return {std::move(const_cast(x.first)), @@ -96,6 +101,18 @@ namespace boost { construct(al, p, *copy.p); } + template + static void construct(A& al, init_type* p, Args&&... args) + { + boost::allocator_construct(al, p, std::forward(args)...); + } + + template + static void construct(A& al, value_type* p, Args&&... args) + { + boost::allocator_construct(al, p, std::forward(args)...); + } + template static void construct(A& al, element_type* p, Args&&... args) { @@ -106,10 +123,11 @@ namespace boost { } BOOST_CATCH(...) { - boost::allocator_deallocate(al, - boost::pointer_traits< - typename boost::allocator_pointer::type>::pointer_to(*p->p), - 1); + using pointer_type=typename boost::allocator_pointer::type; + using pointer_traits=boost::pointer_traits; + + boost::allocator_deallocate( + al,pointer_traits::pointer_to(*(p->p)),1); BOOST_RETHROW } BOOST_CATCH_END @@ -118,16 +136,22 @@ namespace boost { template static void destroy(A& al, value_type* p) noexcept { boost::allocator_destroy(al, p); - boost::allocator_deallocate(al, - boost::pointer_traits< - typename boost::allocator_pointer::type>::pointer_to(*p), - 1); + } + + template static void destroy(A& al, init_type* p) noexcept + { + boost::allocator_destroy(al, p); } template static void destroy(A& al, element_type* p) noexcept { if (p->p) { - destroy(al,p->p); + using pointer_type=typename boost::allocator_pointer::type; + using pointer_traits=boost::pointer_traits; + + destroy(al, p->p); + boost::allocator_deallocate( + al,pointer_traits::pointer_to(*(p->p)), 1); } } }; @@ -137,8 +161,7 @@ namespace boost { : public detail::foa::node_handle_base { private: - using base_type = - detail::foa::node_handle_base; + using base_type = detail::foa::node_handle_base; using typename base_type::type_policy; diff --git a/include/boost/unordered/unordered_node_set.hpp b/include/boost/unordered/unordered_node_set.hpp index c6fc8617..0fbd715c 100644 --- a/include/boost/unordered/unordered_node_set.hpp +++ b/include/boost/unordered/unordered_node_set.hpp @@ -78,6 +78,12 @@ namespace boost { x.p = nullptr; } + template + static void construct(A& al, value_type* p, Args&&... args) + { + boost::allocator_construct(al, p, std::forward(args)...); + } + template static void construct(A& al, element_type* p, Args&&... args) { @@ -100,16 +106,16 @@ namespace boost { template static void destroy(A& al, value_type* p) noexcept { boost::allocator_destroy(al, p); - boost::allocator_deallocate(al, - boost::pointer_traits< - typename boost::allocator_pointer::type>::pointer_to(*p), - 1); } template static void destroy(A& al, element_type* p) noexcept { if (p->p) { destroy(al, p->p); + boost::allocator_deallocate(al, + boost::pointer_traits::type>::pointer_to(*(p->p)), + 1); } } }; @@ -119,8 +125,7 @@ namespace boost { : public detail::foa::node_handle_base { private: - using base_type = - detail::foa::node_handle_base; + using base_type = detail::foa::node_handle_base; using typename base_type::type_policy; @@ -391,7 +396,7 @@ namespace boost { BOOST_ASSERT(get_allocator() == nh.get_allocator()); typename set_types::element_type x; - x.p=std::addressof(nh.element()); + x.p = std::addressof(nh.element()); auto itp = table_.insert(std::move(x)); if (itp.second) { @@ -411,7 +416,7 @@ namespace boost { BOOST_ASSERT(get_allocator() == nh.get_allocator()); typename set_types::element_type x; - x.p=std::addressof(nh.element()); + x.p = std::addressof(nh.element()); auto itp = table_.insert(std::move(x)); if (itp.second) { @@ -478,7 +483,7 @@ namespace boost { node_type extract(key_type const& key) { auto pos = find(key); - return pos!=end()?extract(pos):node_type(); + return pos != end() ? extract(pos) : node_type(); } template @@ -489,7 +494,7 @@ namespace boost { extract(K const& key) { auto pos = find(key); - return pos!=end()?extract(pos):node_type(); + return pos != end() ? extract(pos) : node_type(); } template