From f9c32e7f8c4d86710bc177985d8449a0d156776a Mon Sep 17 00:00:00 2001 From: Christian Mazakas Date: Fri, 10 Feb 2023 14:19:01 -0800 Subject: [PATCH] Clean up impl of node_handle --- include/boost/unordered/detail/foa.hpp | 169 +-------------- .../unordered/detail/foa/node_handle.hpp | 196 ++++++++++++++++++ .../boost/unordered/unordered_node_map.hpp | 31 +-- .../boost/unordered/unordered_node_set.hpp | 27 +-- 4 files changed, 222 insertions(+), 201 deletions(-) create mode 100644 include/boost/unordered/detail/foa/node_handle.hpp diff --git a/include/boost/unordered/detail/foa.hpp b/include/boost/unordered/detail/foa.hpp index 2f101c8b..8f344bea 100644 --- a/include/boost/unordered/detail/foa.hpp +++ b/include/boost/unordered/detail/foa.hpp @@ -84,163 +84,6 @@ namespace unordered{ namespace detail{ namespace foa{ -template -struct insert_return_type -{ - Iterator position; - bool inserted; - NodeType node; -}; - -template -struct node_handle_base -{ - protected: - using type_policy=TypePolicy; - using value_type=typename type_policy::value_type; - using element_type=typename type_policy::element_type; - - public: - using allocator_type = Allocator; - - private: - value_type* p_=nullptr; - alignas(Allocator) unsigned char a_[sizeof(Allocator)]={0}; - - protected: - value_type& element()noexcept - { - BOOST_ASSERT(!empty()); - return *p_; - } - - value_type const& element()const noexcept - { - BOOST_ASSERT(!empty()); - return *p_; - } - - Allocator& al()noexcept - { - BOOST_ASSERT(!empty()); - return *reinterpret_cast(a_); - } - - Allocator const& al()const noexcept - { - BOOST_ASSERT(!empty()); - return *reinterpret_cast(a_); - } - - void emplace(value_type* p,Allocator a) - { - BOOST_ASSERT(empty()); - p_=p; - new(a_)Allocator(a); - } - - void emplace(element_type&& x,Allocator a) - { - emplace(x.p,a); - x.p=nullptr; - } - - void clear() - { - al().~Allocator(); - p_=nullptr; - } - - public: - constexpr node_handle_base()noexcept=default; - - node_handle_base(node_handle_base&& nh) noexcept - { - if (!nh.empty()){ - emplace(nh.p_,nh.al()); - nh.clear(); - } - } - - node_handle_base& operator=(node_handle_base&& nh)noexcept - { - bool const pocma= - boost::allocator_propagate_on_container_move_assignment< - Allocator>::type::value; - - if(!empty()){ - type_policy::destroy(al(),p_); - if (pocma&&!nh.empty()){al()=std::move(nh.al());} - } - - if(!nh.empty()){ - if(empty()){new(a_)Allocator(std::move(nh.al()));} - p_=nh.p_; - - nh.p_=nullptr; - reinterpret_cast(nh.a_)->~Allocator(); - }else if (!empty()){ - reinterpret_cast(a_)->~Allocator(); - p_=nullptr; - } - - return *this; - } - - ~node_handle_base() - { - if(!empty()){ - type_policy::destroy(al(),p_); - reinterpret_cast(a_)->~Allocator(); - } - } - - allocator_type get_allocator()const noexcept{return al();} - explicit operator bool()const noexcept{ return !empty();} - BOOST_ATTRIBUTE_NODISCARD bool empty()const noexcept{return p_==nullptr;} - - void swap(node_handle_base& nh) noexcept( - boost::allocator_is_always_equal::type::value|| - boost::allocator_propagate_on_container_swap::type::value) - { - using std::swap; - - bool const pocs= - boost::allocator_propagate_on_container_swap::type::value; - - if (!empty()&&!nh.empty()){ - BOOST_ASSERT(pocs || al()==nh.al()); - - value_type *p=p_; - p_=nh.p_; - nh.p_=p; - - if(pocs){ - swap(al(),nh.al()); - } - - return; - } - - if (empty()&&nh.empty()){return;} - - if (empty()){ - emplace(nh.p_,nh.al()); - nh.clear(); - }else{ - nh.emplace(p_,al()); - clear(); - } - } - - friend - void swap(node_handle_base& lhs,node_handle_base& rhs) - noexcept(noexcept(lhs.swap(rhs))) - { - return lhs.swap(rhs); - } -}; - static const std::size_t default_bucket_count = 0; /* foa::table is an open-addressing hash table serving as the foundational core @@ -1583,6 +1426,14 @@ public: BOOST_FORCEINLINE std::pair insert(value_type&& x){return emplace_impl(std::move(x));} + template + BOOST_FORCEINLINE + typename std::enable_if< + !std::is_same::value, + std::pair + >::type + insert(element_type&& x){return emplace_impl(std::move(x));} + template< bool dependent_value=false, typename std::enable_if< @@ -2045,7 +1896,7 @@ private: return emplace_impl(type_policy::move(*p)); } -public: + template BOOST_FORCEINLINE std::pair emplace_impl(Args&&... args) { @@ -2070,7 +1921,7 @@ public: }; } } -private: + static std::size_t capacity_for(std::size_t n) { return size_policy::size(size_index_for(n))*N-1; diff --git a/include/boost/unordered/detail/foa/node_handle.hpp b/include/boost/unordered/detail/foa/node_handle.hpp new file mode 100644 index 00000000..0919c7db --- /dev/null +++ b/include/boost/unordered/detail/foa/node_handle.hpp @@ -0,0 +1,196 @@ +/* Copyright 2023 Christian Mazakas. + * Distributed under the Boost Software License, Version 1.0. + * (See accompanying file LICENSE_1_0.txt or copy at + * http://www.boost.org/LICENSE_1_0.txt) + * + * See https://www.boost.org/libs/unordered for library home page. + */ + +#ifndef BOOST_UNORDERED_DETAIL_FOA_NODE_HANDLE_HPP +#define BOOST_UNORDERED_DETAIL_FOA_NODE_HANDLE_HPP + +#include +#include + +namespace boost{ +namespace unordered{ +namespace detail{ +namespace foa{ + +template +struct insert_return_type +{ + Iterator position; + bool inserted; + NodeType node; +}; + +template +union opt_storage { + BOOST_ATTRIBUTE_NO_UNIQUE_ADDRESS T t_; + + opt_storage(){} + ~opt_storage(){} +}; + +template +struct node_handle_base +{ + protected: + using type_policy=TypePolicy; + using value_type=typename type_policy::value_type; + using element_type=typename type_policy::element_type; + + public: + using allocator_type = Allocator; + + private: + value_type* p_=nullptr; + BOOST_ATTRIBUTE_NO_UNIQUE_ADDRESS opt_storage a_; + + protected: + value_type& element()noexcept + { + BOOST_ASSERT(!empty()); + return *p_; + } + + value_type const& element()const noexcept + { + BOOST_ASSERT(!empty()); + return *p_; + } + + Allocator& al()noexcept + { + BOOST_ASSERT(!empty()); + return a_.t_; + } + + Allocator const& al()const noexcept + { + BOOST_ASSERT(!empty()); + return a_.t_; + } + + void emplace(value_type* p,Allocator a) + { + BOOST_ASSERT(empty()); + p_=p; + new(&a_.t_)Allocator(a); + } + + void emplace(element_type&& x,Allocator a) + { + emplace(x.p,a); + x.p=nullptr; + } + + void clear() + { + al().~Allocator(); + p_=nullptr; + } + + public: + constexpr node_handle_base()noexcept=default; + + node_handle_base(node_handle_base&& nh) noexcept + { + if (!nh.empty()){ + emplace(nh.p_,nh.al()); + nh.clear(); + } + } + + node_handle_base& operator=(node_handle_base&& nh)noexcept + { + bool const pocma= + boost::allocator_propagate_on_container_move_assignment< + Allocator>::type::value; + + BOOST_ASSERT( + pocma + ||empty() + ||nh.empty() + ||(al()==nh.al())); + + if(!empty()){ + type_policy::destroy(al(),p_); + if (pocma&&!nh.empty()){al()=std::move(nh.al());} + } + + if(!nh.empty()){ + if(empty()){new(&a_.t_)Allocator(std::move(nh.al()));} + p_=nh.p_; + + nh.p_=nullptr; + nh.a_.t_.~Allocator(); + }else if (!empty()){ + a_.t_.~Allocator(); + p_=nullptr; + } + + return *this; + } + + ~node_handle_base() + { + if(!empty()){ + type_policy::destroy(al(),p_); + a_.t_.~Allocator(); + } + } + + allocator_type get_allocator()const noexcept{return al();} + explicit operator bool()const noexcept{ return !empty();} + BOOST_ATTRIBUTE_NODISCARD bool empty()const noexcept{return p_==nullptr;} + + void swap(node_handle_base& nh) noexcept( + boost::allocator_is_always_equal::type::value|| + boost::allocator_propagate_on_container_swap::type::value) + { + using std::swap; + + bool const pocs= + boost::allocator_propagate_on_container_swap::type::value; + + if (!empty()&&!nh.empty()){ + BOOST_ASSERT(pocs || al()==nh.al()); + + value_type *p=p_; + p_=nh.p_; + nh.p_=p; + + if(pocs){ + swap(al(),nh.al()); + } + + return; + } + + if (empty()&&nh.empty()){return;} + + if (empty()){ + emplace(nh.p_,nh.al()); + nh.clear(); + }else{ + nh.emplace(p_,al()); + clear(); + } + } + + friend + void swap(node_handle_base& lhs,node_handle_base& rhs) + noexcept(noexcept(lhs.swap(rhs))) + { + return lhs.swap(rhs); + } +}; + +} +} +} +} + +#endif // BOOST_UNORDERED_DETAIL_FOA_NODE_HANDLE_HPP diff --git a/include/boost/unordered/unordered_node_map.hpp b/include/boost/unordered/unordered_node_map.hpp index 9a0f293e..48f79243 100644 --- a/include/boost/unordered/unordered_node_map.hpp +++ b/include/boost/unordered/unordered_node_map.hpp @@ -11,6 +11,7 @@ #endif #include +#include #include #include @@ -139,16 +140,12 @@ namespace boost { using base_type = detail::foa::node_handle_base; - using base_type::element; using typename base_type::type_policy; template friend class boost::unordered::unordered_node_map; public: - using base_type::empty; - using base_type::swap; - using key_type = typename NodeMapTypes::key_type; using mapped_type = typename NodeMapTypes::mapped_type; @@ -159,14 +156,14 @@ namespace boost { key_type& key() const { - BOOST_ASSERT(!empty()); - return const_cast(element().first); + BOOST_ASSERT(!this->empty()); + return const_cast(this->element().first); } mapped_type& mapped() const { - BOOST_ASSERT(!empty()); - return const_cast(element().second); + BOOST_ASSERT(!this->empty()); + return const_cast(this->element().second); } }; } // namespace detail @@ -408,7 +405,7 @@ namespace boost { typename map_types::element_type x; x.p=std::addressof(nh.element()); - auto itp = table_.emplace_impl(std::move(x)); + auto itp = table_.insert(std::move(x)); if (itp.second) { nh.clear(); return {itp.first, true, node_type{}}; @@ -425,7 +422,7 @@ namespace boost { BOOST_ASSERT(get_allocator() == nh.get_allocator()); - auto itp = table_.emplace_impl(map_types::move(nh.element())); + auto itp = table_.insert(map_types::move(nh.element())); return itp.first; } @@ -597,12 +594,7 @@ namespace boost { node_type extract(key_type const& key) { auto pos = find(key); - node_type nh; - if (pos != end()) { - auto elem = table_.extract(pos); - nh.emplace(std::move(elem), get_allocator()); - } - return nh; + return pos!=end()?extract(pos):node_type(); } template @@ -613,12 +605,7 @@ namespace boost { extract(K const& key) { auto pos = find(key); - node_type nh; - if (pos != end()) { - auto elem = table_.extract(pos); - nh.emplace(std::move(elem), get_allocator()); - } - return nh; + return pos!=end()?extract(pos):node_type(); } template diff --git a/include/boost/unordered/unordered_node_set.hpp b/include/boost/unordered/unordered_node_set.hpp index 5adf0f37..93f26773 100644 --- a/include/boost/unordered/unordered_node_set.hpp +++ b/include/boost/unordered/unordered_node_set.hpp @@ -11,6 +11,7 @@ #endif #include +#include #include #include @@ -121,16 +122,12 @@ namespace boost { using base_type = detail::foa::node_handle_base; - using base_type::element; using typename base_type::type_policy; template friend class boost::unordered::unordered_node_set; public: - using base_type::empty; - using base_type::swap; - using value_type = typename NodeSetTypes::value_type; constexpr node_set_handle() noexcept = default; @@ -139,8 +136,8 @@ namespace boost { value_type& value() const { - BOOST_ASSERT(!empty()); - return const_cast(element()); + BOOST_ASSERT(!this->empty()); + return const_cast(this->element()); } }; } // namespace detail @@ -396,7 +393,7 @@ namespace boost { typename set_types::element_type x; x.p=std::addressof(nh.element()); - auto itp = table_.emplace_impl(std::move(x)); + auto itp = table_.insert(std::move(x)); if (itp.second) { nh.clear(); return {itp.first, true, node_type{}}; @@ -413,7 +410,7 @@ namespace boost { BOOST_ASSERT(get_allocator() == nh.get_allocator()); - auto itp = table_.emplace_impl(set_types::move(nh.element())); + auto itp = table_.insert(set_types::move(nh.element())); return itp.first; } @@ -473,12 +470,7 @@ namespace boost { node_type extract(key_type const& key) { auto pos = find(key); - node_type nh; - if (pos != end()) { - auto elem = table_.extract(pos); - nh.emplace(std::move(elem), get_allocator()); - } - return nh; + return pos!=end()?extract(pos):node_type(); } template @@ -489,12 +481,7 @@ namespace boost { extract(K const& key) { auto pos = find(key); - node_type nh; - if (pos != end()) { - auto elem = table_.extract(pos); - nh.emplace(std::move(elem), get_allocator()); - } - return nh; + return pos!=end()?extract(pos):node_type(); } template