diff --git a/doc/unordered/changes.adoc b/doc/unordered/changes.adoc index b0f03187..1bf30623 100644 --- a/doc/unordered/changes.adoc +++ b/doc/unordered/changes.adoc @@ -14,6 +14,9 @@ ({github-pr-url}/265[PR#265^]). * In Visual Studio Natvis, supported any container with an allocator that uses fancy pointers. This applies to any fancy pointer type, as long as the proper Natvis customization point "Intrinsic" functions are written for the fancy pointer type. * Added GDB pretty-printers for all containers and iterators. For a container with an allocator that uses fancy pointers, these only work if the proper pretty-printer is written for the fancy pointer type itself. +* Fixed `std::initializer_list` assignment issues for open-addressing containers +({github-pr-url}/277[PR#277^]). + == Release 1.86.0 diff --git a/include/boost/unordered/unordered_flat_map.hpp b/include/boost/unordered/unordered_flat_map.hpp index 55024102..a6551b3a 100644 --- a/include/boost/unordered/unordered_flat_map.hpp +++ b/include/boost/unordered/unordered_flat_map.hpp @@ -1,4 +1,5 @@ // Copyright (C) 2022-2023 Christian Mazakas +// Copyright (C) 2024 Joaquin M Lopez Munoz // 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) @@ -202,6 +203,13 @@ namespace boost { return *this; } + unordered_flat_map& operator=(std::initializer_list il) + { + this->clear(); + this->insert(il.begin(), il.end()); + return *this; + } + allocator_type get_allocator() const noexcept { return table_.get_allocator(); diff --git a/include/boost/unordered/unordered_flat_set.hpp b/include/boost/unordered/unordered_flat_set.hpp index a72d3567..3b6eb3c2 100644 --- a/include/boost/unordered/unordered_flat_set.hpp +++ b/include/boost/unordered/unordered_flat_set.hpp @@ -1,4 +1,5 @@ // Copyright (C) 2022-2023 Christian Mazakas +// Copyright (C) 2024 Joaquin M Lopez Munoz // 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) @@ -198,6 +199,13 @@ namespace boost { return *this; } + unordered_flat_set& operator=(std::initializer_list il) + { + this->clear(); + this->insert(il.begin(), il.end()); + return *this; + } + allocator_type get_allocator() const noexcept { return table_.get_allocator(); diff --git a/include/boost/unordered/unordered_node_map.hpp b/include/boost/unordered/unordered_node_map.hpp index 56be52bc..c60a94e6 100644 --- a/include/boost/unordered/unordered_node_map.hpp +++ b/include/boost/unordered/unordered_node_map.hpp @@ -210,6 +210,13 @@ namespace boost { return *this; } + unordered_node_map& operator=(std::initializer_list il) + { + this->clear(); + this->insert(il.begin(), il.end()); + return *this; + } + allocator_type get_allocator() const noexcept { return table_.get_allocator(); diff --git a/include/boost/unordered/unordered_node_set.hpp b/include/boost/unordered/unordered_node_set.hpp index bc14ffb0..e8fb8b65 100644 --- a/include/boost/unordered/unordered_node_set.hpp +++ b/include/boost/unordered/unordered_node_set.hpp @@ -208,6 +208,13 @@ namespace boost { return *this; } + unordered_node_set& operator=(std::initializer_list il) + { + this->clear(); + this->insert(il.begin(), il.end()); + return *this; + } + allocator_type get_allocator() const noexcept { return table_.get_allocator(); diff --git a/test/cfoa/assign_tests.cpp b/test/cfoa/assign_tests.cpp index ea9403c2..f1c7788d 100644 --- a/test/cfoa/assign_tests.cpp +++ b/test/cfoa/assign_tests.cpp @@ -5,11 +5,16 @@ #include "helpers.hpp" +#include "../helpers/replace_allocator.hpp" +#include "../objects/non_default_ctble_allocator.hpp" + #include #include #include #include +#include + #if defined(__clang__) && defined(__has_warning) #if __has_warning("-Wself-assign-overloaded") @@ -882,6 +887,28 @@ namespace { check_raii_counts(); } + template + void initializer_list_assign_gh276( + X*, GF gen_factory, test::random_generator rg) + { + // https://github.com/boostorg/unordered/issues/276 + + using replaced_allocator_container = test::replace_allocator< + X, test::non_default_ctble_allocator >; + using replaced_allocator_type = + typename replaced_allocator_container::allocator_type; + + auto gen = gen_factory.template get(); + auto values = make_random_values(4, [&] { return gen(rg); }); + + replaced_allocator_container + x(replaced_allocator_type(0)), + y(values.begin(), values.end(), replaced_allocator_type(0)); + + x = {values[0], values[1], values[2], values[3]}; + BOOST_TEST(x == y); + } + template void insert_and_assign(X*, GF gen_factory, test::random_generator rg) { @@ -1112,6 +1139,12 @@ UNORDERED_TEST( ((test_map_and_init_list)(test_node_map_and_init_list) (test_set_and_init_list)(test_node_set_and_init_list))) +UNORDERED_TEST( + initializer_list_assign_gh276, + ((test_map)(test_node_map)(test_set)(test_node_set)) + ((value_type_generator_factory)) + ((default_generator))) + UNORDERED_TEST( insert_and_assign, ((test_map)(test_node_map)(test_set)(test_node_set)) diff --git a/test/helpers/replace_allocator.hpp b/test/helpers/replace_allocator.hpp new file mode 100644 index 00000000..0e794940 --- /dev/null +++ b/test/helpers/replace_allocator.hpp @@ -0,0 +1,44 @@ + +// Copyright 2024 Joaquin M Lopez Munz. +// Distributed under the Boost Software License, Version 1.0. (See accompanying +// file LICENSE_1_0.txt or move at http://www.boost.org/LICENSE_1_0.txt) + +#ifndef BOOST_UNORDERED_TEST_REPLACE_ALLOCATOR +#define BOOST_UNORDERED_TEST_REPLACE_ALLOCATOR + +#include +#include + +namespace test { +template + struct replace_allocator_impl; + + template + using replace_allocator = + typename replace_allocator_impl::type; + + template < + typename K, typename H, typename P, typename A, + template class Set, + typename Allocator + > + struct replace_allocator_impl, Allocator> + { + using type = Set< + K, H, P, boost::allocator_rebind_t >; + }; + + template < + typename K, typename H, typename T, typename P, typename A, + template class Map, + typename Allocator + > + struct replace_allocator_impl, Allocator> + { + using type = Map< + K, T, H, P, + boost::allocator_rebind_t > >; + }; +} // namespace test + +#endif // !defined(BOOST_UNORDERED_TEST_REPLACE_ALLOCATOR) diff --git a/test/objects/non_default_ctble_allocator.hpp b/test/objects/non_default_ctble_allocator.hpp new file mode 100644 index 00000000..5b3360ce --- /dev/null +++ b/test/objects/non_default_ctble_allocator.hpp @@ -0,0 +1,46 @@ + +// Copyright 2024 Joaquin M Lopez Munoz +// 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) + +#if !defined(BOOST_UNORDERED_TEST_NON_DEFAULT_CTBLE_ALLOCATOR_HEADER) +#define BOOST_UNORDERED_TEST_NON_DEFAULT_CTBLE_ALLOCATOR_HEADER + +#include + +namespace test +{ + template struct non_default_ctble_allocator + { + typedef T value_type; + + non_default_ctble_allocator(int) {} + + template + non_default_ctble_allocator(const non_default_ctble_allocator&) {} + + template + bool operator==(non_default_ctble_allocator const &) const noexcept + { + return true; + } + + template + bool operator!=(non_default_ctble_allocator const &) const noexcept + { + return false; + } + + T* allocate(std::size_t n) + { + return std::allocator().allocate(n); + } + + void deallocate(T* p, std::size_t n) + { + std::allocator().deallocate(p, n); + } + }; +} + +#endif diff --git a/test/unordered/assign_tests.cpp b/test/unordered/assign_tests.cpp index 21f43a53..9f7661c9 100644 --- a/test/unordered/assign_tests.cpp +++ b/test/unordered/assign_tests.cpp @@ -7,12 +7,16 @@ #include "../helpers/unordered.hpp" #include "../helpers/test.hpp" +#include "../helpers/replace_allocator.hpp" #include "../objects/test.hpp" #include "../objects/cxx11_allocator.hpp" +#include "../objects/non_default_ctble_allocator.hpp" #include "../helpers/random_values.hpp" #include "../helpers/tracker.hpp" #include "../helpers/equivalent.hpp" +#include + #if defined(BOOST_MSVC) #pragma warning(disable : 4127) // conditional expression is constant #endif @@ -288,6 +292,27 @@ namespace assign_tests { } #endif } + + BOOST_LIGHTWEIGHT_TEST_OSTREAM << "gh276\n"; + { + // https://github.com/boostorg/unordered/issues/276 + + using value_type = typename T::value_type; + using replaced_allocator_container = test::replace_allocator< + T, test::non_default_ctble_allocator >; + using replaced_allocator_type = + typename replaced_allocator_container::allocator_type; + + test::random_values v(4, generator); + std::vector vv(v.begin(), v.end()); + + replaced_allocator_container + x(replaced_allocator_type(0)), + y(vv.begin(), vv.begin() + 4, replaced_allocator_type(0)); + + x = {vv[0], vv[1], vv[2], vv[3]}; + BOOST_TEST(x == y); + } } using test::default_generator; diff --git a/test/unordered/node_handle_allocator_tests.cpp b/test/unordered/node_handle_allocator_tests.cpp index d19a703e..87729809 100644 --- a/test/unordered/node_handle_allocator_tests.cpp +++ b/test/unordered/node_handle_allocator_tests.cpp @@ -20,7 +20,8 @@ #endif #include "../helpers/test.hpp" - +#include "../helpers/replace_allocator.hpp" + #include #include #include @@ -82,42 +83,12 @@ namespace { bool operator!=(pocx_allocator const& rhs) const { return x_ != rhs.x_; } }; - template - struct replace_allocator_impl; - - template - using replace_allocator = - typename replace_allocator_impl::type; - - template < - typename K, typename H, typename P, typename A, - template class Set, - typename Allocator - > - struct replace_allocator_impl, Allocator> - { - using type = Set< - K, H, P, boost::allocator_rebind_t >; - }; - - template < - typename K, typename H, typename T, typename P, typename A, - template class Map, - typename Allocator - > - struct replace_allocator_impl, Allocator> - { - using type = Map< - K, T, H, P, - boost::allocator_rebind_t > >; - }; - template void node_handle_allocator_tests( X*, std::pair allocators) { using value_type = typename X::value_type; - using replaced_allocator_container = replace_allocator; + using replaced_allocator_container = test::replace_allocator; using node_type = typename replaced_allocator_container::node_type; replaced_allocator_container x1(allocators.first); @@ -143,7 +114,7 @@ namespace { X*, std::pair allocators) { using value_type = typename X::value_type; - using replaced_allocator_container = replace_allocator; + using replaced_allocator_container = test::replace_allocator; using node_type = typename replaced_allocator_container::node_type; replaced_allocator_container x1(allocators.first), x2(allocators.second);