From b96dd2184f793a3931edf733178ecf6f48ddfae4 Mon Sep 17 00:00:00 2001 From: Christian Mazakas Date: Wed, 8 Feb 2023 15:08:51 -0800 Subject: [PATCH] Add foa-based node containers to node_handle_tests --- include/boost/unordered/detail/foa.hpp | 89 ++++++++- .../boost/unordered/unordered_node_map.hpp | 14 +- .../boost/unordered/unordered_node_set.hpp | 13 +- test/unordered/node_handle_tests.cpp | 179 +++++++++++++++--- 4 files changed, 252 insertions(+), 43 deletions(-) diff --git a/include/boost/unordered/detail/foa.hpp b/include/boost/unordered/detail/foa.hpp index 0eca82b0..710d2324 100644 --- a/include/boost/unordered/detail/foa.hpp +++ b/include/boost/unordered/detail/foa.hpp @@ -142,27 +142,57 @@ struct node_handle_base } public: - constexpr node_handle_base() noexcept = default; + constexpr node_handle_base()noexcept=default; node_handle_base(node_handle_base&& nh) noexcept { - if (!nh.empty()) { + if (!nh.empty()){ // neither of these move constructors are allowed to throw exceptions // so we can get away with rote placement new // - new (a_) Allocator(std::move(nh.al())); - new (x_) element_type(std::move(nh.element())); - empty_ = false; + new(a_)Allocator(std::move(nh.al())); + new(x_)element_type(std::move(nh.element())); + empty_=false; + reinterpret_cast(nh.x_)->~element_type(); reinterpret_cast(nh.a_)->~Allocator(); nh.empty_ = true; } } + 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(),reinterpret_cast(x_)); + reinterpret_cast(x_)->~element_type(); + if (pocma&&!nh.empty()){al()=std::move(nh.al());} + } + + if(!nh.empty()){ + new(x_)element_type(std::move(nh.element())); + if(empty()){new(a_)Allocator(std::move(nh.al()));} + empty_=false; + + reinterpret_cast(nh.x_)->~element_type(); + reinterpret_cast(nh.a_)->~Allocator(); + nh.empty_=true; + }else if (!empty()){ + reinterpret_cast(a_)->~Allocator(); + empty_=true; + } + + return *this; + } + ~node_handle_base() { if(!empty()){ type_policy::destroy(al(),reinterpret_cast(x_)); + reinterpret_cast(x_)->~element_type(); reinterpret_cast(a_)->~Allocator(); empty_=true; } @@ -171,6 +201,55 @@ struct node_handle_base allocator_type get_allocator()const noexcept{return al();} explicit operator bool()const noexcept{ return !empty();} BOOST_ATTRIBUTE_NODISCARD bool empty()const noexcept{return empty_;} + + 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()); + + element().swap(nh.element()); + + if(pocs){ + swap(al(),nh.al()); + } + + return; + } + + if (empty()&&nh.empty()){return;} + + if (empty()){ + new(x_)element_type(std::move(nh.element())); + new(a_)Allocator(nh.al()); + empty_=false; + + reinterpret_cast(nh.x_)->~element_type(); + reinterpret_cast(nh.a_)->~Allocator(); + nh.empty_=true; + }else{ + new(nh.x_)element_type(std::move(element())); + new(nh.a_)Allocator(al()); + nh.empty_=false; + + reinterpret_cast(x_)->~element_type(); + reinterpret_cast(a_)->~Allocator(); + empty_=true; + } + } + + 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; diff --git a/include/boost/unordered/unordered_node_map.hpp b/include/boost/unordered/unordered_node_map.hpp index 27d709b3..271fbd2c 100644 --- a/include/boost/unordered/unordered_node_map.hpp +++ b/include/boost/unordered/unordered_node_map.hpp @@ -60,6 +60,10 @@ namespace boost { p = rhs.p; rhs.p = nullptr; } + + void swap(element_type& rhs) noexcept { + std::swap(p, rhs.p); + } }; static value_type& value_from(element_type const& x) { return *(x.p); } @@ -135,21 +139,23 @@ namespace boost { detail::foa::node_handle_base; using base_type::element; - using base_type::type_policy; + 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; - public: - using base_type::empty; - constexpr node_map_handle() noexcept = default; node_map_handle(node_map_handle&& nh) noexcept = default; + node_map_handle& operator=(node_map_handle&&) noexcept = default; + key_type& key() const { BOOST_ASSERT(!empty()); diff --git a/include/boost/unordered/unordered_node_set.hpp b/include/boost/unordered/unordered_node_set.hpp index dbf0a94a..bf97c85e 100644 --- a/include/boost/unordered/unordered_node_set.hpp +++ b/include/boost/unordered/unordered_node_set.hpp @@ -56,6 +56,10 @@ namespace boost { p = rhs.p; rhs.p = nullptr; } + + void swap(element_type& rhs) noexcept { + std::swap(p, rhs.p); + } }; static value_type& value_from(element_type const& x) { return *x.p; } @@ -117,19 +121,20 @@ namespace boost { detail::foa::node_handle_base; using base_type::element; - using base_type::type_policy; + using typename base_type::type_policy; template friend class boost::unordered::unordered_node_set; - public: - using value_type = typename NodeSetTypes::value_type; - public: using base_type::empty; + using base_type::swap; + + using value_type = typename NodeSetTypes::value_type; constexpr node_set_handle() noexcept = default; node_set_handle(node_set_handle&& nh) noexcept = default; + node_set_handle& operator=(node_set_handle&&) noexcept = default; value_type& value() const { diff --git a/test/unordered/node_handle_tests.cpp b/test/unordered/node_handle_tests.cpp index 3ecf0d04..ad0aa1e1 100644 --- a/test/unordered/node_handle_tests.cpp +++ b/test/unordered/node_handle_tests.cpp @@ -166,23 +166,6 @@ static void failed_insertion_with_hint() } } -#ifdef BOOST_UNORDERED_FOA_TESTS - -UNORDERED_AUTO_TEST (examples) { - example1(); - example2(); - example3(); - failed_insertion_with_hint(); -} -#else -UNORDERED_AUTO_TEST (examples) { - example1(); - example2(); - example3(); - failed_insertion_with_hint(); -} - template bool node_handle_compare( NodeHandle const& nh, typename NodeHandle::value_type const& x) @@ -269,20 +252,38 @@ template void node_handle_tests_impl(Container& c) BOOST_TEST(!n4); } -UNORDERED_AUTO_TEST (node_handle_tests) { - boost::unordered_set x1; +template