From 577b3e47f2a912b1656d0faf66bac25a6c625dca Mon Sep 17 00:00:00 2001 From: jj683 Date: Tue, 23 Jul 2024 18:31:42 +0300 Subject: [PATCH] set/map nothrow move constructible/assignable --- immer/detail/hamts/champ.hpp | 18 +++++++++++------- immer/detail/hamts/node.hpp | 14 ++++++++++---- immer/map.hpp | 5 +++++ immer/set.hpp | 6 ++++++ 4 files changed, 32 insertions(+), 11 deletions(-) diff --git a/immer/detail/hamts/champ.hpp b/immer/detail/hamts/champ.hpp index 64a8cb82..0e04d57e 100644 --- a/immer/detail/hamts/champ.hpp +++ b/immer/detail/hamts/champ.hpp @@ -139,22 +139,26 @@ struct champ static node_t* empty() { - static const auto node = node_t::make_inner_n(0); - return node->inc(); + static const auto empty_ = []{ + constexpr auto size = node_t::sizeof_inner_n(0); + static std::aligned_storage_t storage; + return node_t::make_inner_n_into(&storage, size, 0u); + }(); + return empty_->inc(); } - champ(node_t* r, size_t sz = 0) + champ(node_t* r, size_t sz = 0) noexcept : root{r} , size{sz} {} - champ(const champ& other) + champ(const champ& other) noexcept : champ{other.root, other.size} { inc(); } - champ(champ&& other) + champ(champ&& other) noexcept : champ{empty()} { swap(*this, other); @@ -167,13 +171,13 @@ struct champ return *this; } - champ& operator=(champ&& other) + champ& operator=(champ&& other) noexcept { swap(*this, other); return *this; } - friend void swap(champ& x, champ& y) + friend void swap(champ& x, champ& y) noexcept { using std::swap; swap(x.root, y.root); diff --git a/immer/detail/hamts/node.hpp b/immer/detail/hamts/node.hpp index 7f7dc8b1..18019849 100644 --- a/immer/detail/hamts/node.hpp +++ b/immer/detail/hamts/node.hpp @@ -222,12 +222,11 @@ struct node return can_mutate(impl.d.data.inner.values, e); } - static node_t* make_inner_n(count_t n) + static node_t* make_inner_n_into(void* buffer, std::size_t size, count_t n) { assert(n <= branches); - auto m = heap::allocate(sizeof_inner_n(n)); - auto p = new (m) node_t; - assert(p == (node_t*) m); + assert(size >= sizeof_inner_n(n)); + auto p = new (buffer) node_t; #if IMMER_TAGGED_NODE p->impl.d.kind = node_t::kind_t::inner; #endif @@ -237,6 +236,13 @@ struct node return p; } + static node_t* make_inner_n(count_t n) + { + assert(n <= branches); + auto m = heap::allocate(sizeof_inner_n(n)); + return make_inner_n_into(m, sizeof_inner_n(n), n); + } + static node_t* make_inner_n(count_t n, values_t* values) { auto p = make_inner_n(n); diff --git a/immer/map.hpp b/immer/map.hpp index 7cefdce8..6ab13d64 100644 --- a/immer/map.hpp +++ b/immer/map.hpp @@ -547,4 +547,9 @@ class map impl_t impl_ = impl_t::empty(); }; +static_assert(std::is_nothrow_move_constructible>::value, + "map is not nothrow move constructible"); +static_assert(std::is_nothrow_move_assignable>::value, + "map is not nothrow move assignable"); + } // namespace immer diff --git a/immer/set.hpp b/immer/set.hpp index 2bddc043..3b815f4b 100644 --- a/immer/set.hpp +++ b/immer/set.hpp @@ -292,4 +292,10 @@ class set impl_t impl_ = impl_t::empty(); }; +static_assert(std::is_nothrow_move_constructible>::value, + "set is not nothrow move constructible"); +static_assert(std::is_nothrow_move_assignable>::value, + "set is not nothrow move assignable"); + + } // namespace immer