From 7dfcdc6da836bad57e9874728a43b2190f0333e6 Mon Sep 17 00:00:00 2001 From: Christian Mazakas Date: Tue, 4 Oct 2022 14:38:31 -0700 Subject: [PATCH] Split move_tests into post_move_tests so testing with the new FOA containers is feasible --- test/Jamfile.v2 | 1 + test/unordered/move_tests.cpp | 519 ------------------------ test/unordered/post_move_tests.cpp | 627 +++++++++++++++++++++++++++++ 3 files changed, 628 insertions(+), 519 deletions(-) create mode 100644 test/unordered/post_move_tests.cpp diff --git a/test/Jamfile.v2 b/test/Jamfile.v2 index c16d4b26..7e267e07 100644 --- a/test/Jamfile.v2 +++ b/test/Jamfile.v2 @@ -47,6 +47,7 @@ run unordered/equivalent_keys_tests.cpp ; run unordered/constructor_tests.cpp ; run unordered/copy_tests.cpp ; run unordered/move_tests.cpp ; +run unordered/post_move_tests.cpp ; run unordered/assign_tests.cpp ; run unordered/insert_tests.cpp ; run unordered/insert_stable_tests.cpp ; diff --git a/test/unordered/move_tests.cpp b/test/unordered/move_tests.cpp index 21b2e90c..66b8e264 100644 --- a/test/unordered/move_tests.cpp +++ b/test/unordered/move_tests.cpp @@ -344,519 +344,6 @@ namespace move_tests { } } - template T const& get_key(T const& t) { return t; } - - template K const& get_key(std::pair const& kv) - { - return kv.first; - } - - template T const& get_value(T const& t) { return t; } - - template K const& get_value(std::pair const& kv) - { - return kv.second; - } - - template - static void insert_range(T& y, test::random_values const& v) - { - y.insert(v.begin(), v.end()); - BOOST_TEST_EQ(y.size(), - static_cast(std::distance(y.begin(), y.end()))); - } - - template - static void insert_single(T& y, test::random_values const& v) - { - y.insert(*v.begin()); - BOOST_TEST_EQ(y.size(), - static_cast(std::distance(y.begin(), y.end()))); - } - - template - static void insert_single_hint(T& y, test::random_values const& v) - { - y.insert(y.end(), *v.begin()); - BOOST_TEST_EQ(y.size(), - static_cast(std::distance(y.begin(), y.end()))); - } - - template struct insert_or_assign_invoker - { - void operator()(T&, test::random_values const&) {} - }; - - template - struct insert_or_assign_invoker< - boost::unordered_map > - { - void operator()(boost::unordered_map& y, - test::random_values< - boost::unordered_map > const& v) - { - typedef typename boost::unordered_map::size_type size_type; - - y.insert_or_assign(get_key(*v.begin()), get_value(*v.begin())); - BOOST_TEST_EQ( - y.size(), static_cast(std::distance(y.begin(), y.end()))); - } - }; - - template - static void insert_or_assign(T& y, test::random_values const& v) - { - insert_or_assign_invoker()(y, v); - } - - template struct insert_or_assign_hint_invoker - { - void operator()(T&, test::random_values const&) {} - }; - - template - struct insert_or_assign_hint_invoker< - boost::unordered_map > - { - void operator()(boost::unordered_map& y, - test::random_values< - boost::unordered_map > const& v) - { - typedef typename boost::unordered_map::size_type size_type; - y.insert_or_assign(y.end(), get_key(*v.begin()), get_value(*v.begin())); - BOOST_TEST_EQ( - y.size(), static_cast(std::distance(y.begin(), y.end()))); - } - }; - - template - static void insert_or_assign_hint(T& y, test::random_values const& v) - { - insert_or_assign_hint_invoker()(y, v); - } - - template struct try_emplace_invoker - { - void operator()(T&, test::random_values const&) {} - }; - - template - struct try_emplace_invoker< - boost::unordered_map > - { - void operator()(boost::unordered_map& y, - test::random_values< - boost::unordered_map > const& v) - { - typedef typename boost::unordered_map::size_type size_type; - y.try_emplace(get_key(*v.begin()), get_value(*v.begin())); - BOOST_TEST_EQ( - y.size(), static_cast(std::distance(y.begin(), y.end()))); - } - }; - - template - static void try_emplace(T& y, test::random_values const& v) - { - try_emplace_invoker()(y, v); - } - - template struct try_emplace_hint_invoker - { - void operator()(T&, test::random_values const&) {} - }; - - template - struct try_emplace_hint_invoker< - boost::unordered_map > - { - void operator()(boost::unordered_map& y, - test::random_values< - boost::unordered_map > const& v) - { - typedef typename boost::unordered_map::size_type size_type; - y.try_emplace(y.end(), get_key(*v.begin()), get_value(*v.begin())); - BOOST_TEST_EQ( - y.size(), static_cast(std::distance(y.begin(), y.end()))); - } - }; - - template - static void try_emplace_hint(T& y, test::random_values const& v) - { - try_emplace_hint_invoker()(y, v); - } - - template struct at_invoker - { - void operator()(T&, test::random_values const&) {} - }; - - template - struct at_invoker > - { - void operator()(boost::unordered_map& y, - test::random_values< - boost::unordered_map > const& v) - { - BOOST_TRY { y.at(get_key(*v.begin())); } - BOOST_CATCH(...) {} - BOOST_CATCH_END - } - }; - - template static void at(T& y, test::random_values const& v) - { - at_invoker()(y, v); - } - - template struct index_operator_invoker - { - void operator()(T&, test::random_values const&) {} - }; - - template - struct index_operator_invoker< - boost::unordered_map > - { - void operator()(boost::unordered_map& y, - test::random_values< - boost::unordered_map > const& v) - { - typedef typename boost::unordered_map::size_type size_type; - y[get_key(*v.begin())] = get_value(*v.begin()); - BOOST_TEST_EQ( - y.size(), static_cast(std::distance(y.begin(), y.end()))); - } - }; - - template - static void index_operator(T& y, test::random_values const& v) - { - index_operator_invoker()(y, v); - } - - template static void clear(T& y, test::random_values const&) - { - y.clear(); - BOOST_TEST(y.empty()); - BOOST_TEST_EQ(y.size(), - static_cast(std::distance(y.begin(), y.end()))); - } - - template static void capacity(T& y, test::random_values const&) - { - (void)y.empty(); - (void)y.size(); - (void)y.max_size(); - (void)y.load_factor(); - (void)y.max_load_factor(); - (void)y.hash_function(); - (void)y.key_eq(); - (void)y.get_allocator(); - } - - template static void iterators(T& y, test::random_values const&) - { - BOOST_TEST_EQ(y.size(), - static_cast(std::distance(y.begin(), y.end()))); - } - - template - static void erase_range(T& y, test::random_values const&) - { - y.erase(y.begin(), y.end()); - BOOST_TEST(y.empty()); - BOOST_TEST_EQ(y.size(), - static_cast(std::distance(y.begin(), y.end()))); - } - - template - static void erase_key(T& y, test::random_values const& v) - { - y.erase(get_key(*v.begin())); - BOOST_TEST_EQ(y.size(), - static_cast(std::distance(y.begin(), y.end()))); - } - - template static void lookup(T& y, test::random_values const& v) - { - (void)y.count(get_key(*v.begin())); - (void)y.find(get_key(*v.begin())); - (void)y.contains(get_key(*v.begin())); - (void)y.equal_range(get_key(*v.begin())); - } - - template static void reserve(T& y, test::random_values const&) - { - y.reserve(1337); - BOOST_TEST_GT(y.bucket_count(), 1337u); - BOOST_TEST_EQ(y.size(), - static_cast(std::distance(y.begin(), y.end()))); - } - - template - static void copy_assignment(T& y, test::random_values const& v) - { - T x(v.begin(), v.end()); - y = x; - BOOST_TEST_EQ(y.size(), x.size()); - BOOST_TEST_EQ(y.size(), - static_cast(std::distance(y.begin(), y.end()))); - } - - template - static void move_assignment(T& y, test::random_values const& v) - { - T x(v.begin(), v.end()); - std::size_t const size = x.size(); - y = boost::move(x); - BOOST_TEST_GE(y.size(), size); - BOOST_TEST_EQ(y.size(), - static_cast(std::distance(y.begin(), y.end()))); - } - - template static void equal(T& y, test::random_values const& v) - { - T x(v.begin(), v.end()); - (void)(y == x); - BOOST_TEST_EQ(y.size(), - static_cast(std::distance(y.begin(), y.end()))); - } - - template static void extract(T& y, test::random_values const& v) - { - (void)y.extract(get_key(*v.begin())); - BOOST_TEST_EQ(y.size(), - static_cast(std::distance(y.begin(), y.end()))); - } - - template static void merge(T& y, test::random_values const& v) - { - T x(v.begin(), v.end()); - if (y.get_allocator() == x.get_allocator()) { - y.merge(x); - } - BOOST_TEST_EQ(y.size(), - static_cast(std::distance(y.begin(), y.end()))); - } - - template bool pred(X const&) { return true; } - - template - static void erase_with_pred(T& y, test::random_values const&) - { - erase_if(y, pred); - BOOST_TEST_EQ(y.size(), - static_cast(std::distance(y.begin(), y.end()))); - } - - template - static void container_swap(T& y, test::random_values const& v) - { - T x(v.begin(), v.end()); - if (boost::allocator_propagate_on_container_swap< - typename T::allocator_type>::type::value || - x.get_allocator() == y.get_allocator()) { - y.swap(x); - } - BOOST_TEST_EQ(y.size(), - static_cast(std::distance(y.begin(), y.end()))); - } - - template static void buckets(T& y, test::random_values const& v) - { - (void)y.begin(0); - (void)y.end(0); - (void)y.bucket_count(); - (void)y.max_bucket_count(); - (void)y.bucket_size(0); - (void)y.bucket(get_key(*v.begin())); - } - - template - static void double_move_construct(T& y, test::random_values const&) - { - T x = boost::move(y); - x.clear(); - BOOST_TEST_EQ(y.size(), - static_cast(std::distance(y.begin(), y.end()))); - BOOST_TEST_EQ(x.size(), - static_cast(std::distance(x.begin(), x.end()))); - } - - template - static void double_move_assign(T& y, test::random_values const&) - { - T x; - x = boost::move(y); - x.clear(); - BOOST_TEST_EQ(y.size(), - static_cast(std::distance(y.begin(), y.end()))); - BOOST_TEST_EQ(x.size(), - static_cast(std::distance(x.begin(), x.end()))); - } - - template - static void post_move_tests(T* ptr, test::random_generator const& generator) - { - // clang-format off - void (*fps[])(T&, test::random_values const&) = { - insert_range, - insert_single, - insert_single_hint, - insert_or_assign, - insert_or_assign_hint, - try_emplace, - try_emplace_hint, - at, - index_operator, - clear, - capacity, - iterators, - erase_range, - erase_key, - lookup, - reserve, - copy_assignment, - move_assignment, - equal, - extract, - merge, - erase_with_pred, - container_swap, - buckets, - double_move_construct, - double_move_assign - }; - // clang-format on - - std::size_t const len = (sizeof(fps) / sizeof(*(fps))); - - for (std::size_t i = 0; i < len; ++i) { - test::check_instances check_; - - test::random_values const v(1000, generator); - test::object_count count; - T y(create(v, count)); - - unsigned num_allocs = test::detail::tracker.count_allocations; - (void)num_allocs; - - T x(boost::move(y)); - -#if defined(BOOST_UNORDERED_USE_MOVE) || \ - !defined(BOOST_NO_CXX11_RVALUE_REFERENCES) - BOOST_TEST(y.empty()); - BOOST_TEST(y.begin() == y.end()); - BOOST_TEST_EQ(y.bucket_count(), 0u); - BOOST_TEST_EQ(test::detail::tracker.count_allocations, num_allocs); -#endif - - fps[i](y, v); - - test::check_container(x, v); - test::check_equivalent_keys(x); - } - - for (std::size_t i = 0; i < len; ++i) { - typename T::hasher hf(1); - typename T::key_equal eq(1); - typename T::allocator_type al1(1); - typename T::allocator_type al2(2); - - test::check_instances check_; - - test::random_values v(1000, generator); - test::object_count count; - T y(v.begin(), v.end(), 0, hf, eq, al1); - T x(boost::move(y), al2); - - BOOST_TEST_NOT(y.empty()); - BOOST_TEST(y.begin() != y.end()); - - fps[i](y, v); - - test::check_container(x, v); - test::check_equivalent_keys(x); - } - - for (std::size_t i = 0; i < len; ++i) { - test::check_instances check_; - - test::random_values v(1000, generator); - test::object_count count; - T y(create(v, count)); - - unsigned num_allocs = test::detail::tracker.count_allocations; - (void)num_allocs; - - T x(empty(ptr)); - x = boost::move(y); - -#if defined(BOOST_UNORDERED_USE_MOVE) || \ - !defined(BOOST_NO_CXX11_RVALUE_REFERENCES) - BOOST_TEST(y.empty()); - BOOST_TEST(y.begin() == y.end()); - BOOST_TEST_EQ(y.bucket_count(), 0u); - BOOST_TEST_EQ(test::detail::tracker.count_allocations, num_allocs); -#endif - - fps[i](y, v); - - test::check_container(x, v); - test::check_equivalent_keys(x); - } - - for (std::size_t i = 0; i < len; ++i) { - typename T::hasher hf(1); - typename T::key_equal eq(1); - typename T::allocator_type al1(1); - typename T::allocator_type al2(2); - - test::check_instances check_; - - test::random_values v(1000, generator); - test::object_count count; - T y(v.begin(), v.end(), 0, hf, eq, al1); - - unsigned num_allocs = test::detail::tracker.count_allocations; - (void)num_allocs; - - T x(al2); - x = boost::move(y); - - bool b = boost::allocator_propagate_on_container_move_assignment< - typename T::allocator_type>::type::value; - if (b) { -#if defined(BOOST_UNORDERED_USE_MOVE) || \ - !defined(BOOST_NO_CXX11_RVALUE_REFERENCES) - BOOST_TEST(y.empty()); - BOOST_TEST(y.begin() == y.end()); - BOOST_TEST_EQ(y.bucket_count(), 0u); - BOOST_TEST_EQ(test::detail::tracker.count_allocations, num_allocs); -#else - BOOST_TEST_NOT(y.empty()); - BOOST_TEST(y.begin() != y.end()); - -#endif - } else { - BOOST_TEST_NOT(y.empty()); - BOOST_TEST(y.begin() != y.end()); - } - - fps[i](y, v); - - test::check_container(x, v); - test::check_equivalent_keys(x); - } - } - boost::unordered_map > >* test_map_std_alloc; @@ -930,12 +417,6 @@ namespace move_tests { test_set_no_prop_move)(test_multiset_no_prop_move)(test_map_no_prop_move)( test_multimap_no_prop_move))( (default_generator)(generate_collisions)(limited_range))) - UNORDERED_TEST(post_move_tests, - ((test_set)(test_multiset)(test_map)(test_multimap)(test_set_prop_move)( - test_multiset_prop_move)(test_map_prop_move)(test_multimap_prop_move)( - test_set_no_prop_move)(test_multiset_no_prop_move)(test_map_no_prop_move)( - test_multimap_no_prop_move))( - (default_generator)(generate_collisions)(limited_range))) } RUN_TESTS() diff --git a/test/unordered/post_move_tests.cpp b/test/unordered/post_move_tests.cpp new file mode 100644 index 00000000..5184a3a0 --- /dev/null +++ b/test/unordered/post_move_tests.cpp @@ -0,0 +1,627 @@ + +// Copyright (C) 2022 Christian Mazakas +// 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) + +// clang-format off +#include "../helpers/prefix.hpp" +#include +#include +#include "../helpers/postfix.hpp" +// clang-format on + +#include "../helpers/test.hpp" +#include "../objects/test.hpp" +#include "../objects/cxx11_allocator.hpp" +#include "../helpers/random_values.hpp" +#include "../helpers/tracker.hpp" +#include "../helpers/equivalent.hpp" +#include "../helpers/invariants.hpp" + +#include +#include + +#if defined(BOOST_MSVC) +#pragma warning(disable : 4127) // conditional expression is constant +#endif + +namespace move_tests { + test::seed_t initialize_seed(98624); +#if defined(BOOST_UNORDERED_USE_MOVE) || \ + !defined(BOOST_NO_CXX11_RVALUE_REFERENCES) +#define BOOST_UNORDERED_TEST_MOVING 1 +#else +#define BOOST_UNORDERED_TEST_MOVING 0 +#endif + + template T empty(T*) { return T(); } + + template + T create(test::random_values const& v, test::object_count& count) + { + T x(v.begin(), v.end()); + count = test::global_object_count; + return x; + } + + template + T create(test::random_values const& v, test::object_count& count, + typename T::hasher hf, typename T::key_equal eq, + typename T::allocator_type al, float mlf) + { + T x(0, hf, eq, al); + x.max_load_factor(mlf); + x.insert(v.begin(), v.end()); + count = test::global_object_count; + return x; + } + + template T const& get_key(T const& t) { return t; } + + template K const& get_key(std::pair const& kv) + { + return kv.first; + } + + template T const& get_value(T const& t) { return t; } + + template K const& get_value(std::pair const& kv) + { + return kv.second; + } + + template + static void insert_range(T& y, test::random_values const& v) + { + y.insert(v.begin(), v.end()); + BOOST_TEST_EQ(y.size(), + static_cast(std::distance(y.begin(), y.end()))); + } + + template + static void insert_single(T& y, test::random_values const& v) + { + y.insert(*v.begin()); + BOOST_TEST_EQ(y.size(), + static_cast(std::distance(y.begin(), y.end()))); + } + + template + static void insert_single_hint(T& y, test::random_values const& v) + { + y.insert(y.end(), *v.begin()); + BOOST_TEST_EQ(y.size(), + static_cast(std::distance(y.begin(), y.end()))); + } + + template struct insert_or_assign_invoker + { + void operator()(T&, test::random_values const&) {} + }; + + template + struct insert_or_assign_invoker< + boost::unordered_map > + { + void operator()(boost::unordered_map& y, + test::random_values< + boost::unordered_map > const& v) + { + typedef typename boost::unordered_map::size_type size_type; + + y.insert_or_assign(get_key(*v.begin()), get_value(*v.begin())); + BOOST_TEST_EQ( + y.size(), static_cast(std::distance(y.begin(), y.end()))); + } + }; + + template + static void insert_or_assign(T& y, test::random_values const& v) + { + insert_or_assign_invoker()(y, v); + } + + template struct insert_or_assign_hint_invoker + { + void operator()(T&, test::random_values const&) {} + }; + + template + struct insert_or_assign_hint_invoker< + boost::unordered_map > + { + void operator()(boost::unordered_map& y, + test::random_values< + boost::unordered_map > const& v) + { + typedef typename boost::unordered_map::size_type size_type; + y.insert_or_assign(y.end(), get_key(*v.begin()), get_value(*v.begin())); + BOOST_TEST_EQ( + y.size(), static_cast(std::distance(y.begin(), y.end()))); + } + }; + + template + static void insert_or_assign_hint(T& y, test::random_values const& v) + { + insert_or_assign_hint_invoker()(y, v); + } + + template struct try_emplace_invoker + { + void operator()(T&, test::random_values const&) {} + }; + + template + struct try_emplace_invoker< + boost::unordered_map > + { + void operator()(boost::unordered_map& y, + test::random_values< + boost::unordered_map > const& v) + { + typedef typename boost::unordered_map::size_type size_type; + y.try_emplace(get_key(*v.begin()), get_value(*v.begin())); + BOOST_TEST_EQ( + y.size(), static_cast(std::distance(y.begin(), y.end()))); + } + }; + + template + static void try_emplace(T& y, test::random_values const& v) + { + try_emplace_invoker()(y, v); + } + + template struct try_emplace_hint_invoker + { + void operator()(T&, test::random_values const&) {} + }; + + template + struct try_emplace_hint_invoker< + boost::unordered_map > + { + void operator()(boost::unordered_map& y, + test::random_values< + boost::unordered_map > const& v) + { + typedef typename boost::unordered_map::size_type size_type; + y.try_emplace(y.end(), get_key(*v.begin()), get_value(*v.begin())); + BOOST_TEST_EQ( + y.size(), static_cast(std::distance(y.begin(), y.end()))); + } + }; + + template + static void try_emplace_hint(T& y, test::random_values const& v) + { + try_emplace_hint_invoker()(y, v); + } + + template struct at_invoker + { + void operator()(T&, test::random_values const&) {} + }; + + template + struct at_invoker > + { + void operator()(boost::unordered_map& y, + test::random_values< + boost::unordered_map > const& v) + { + BOOST_TRY { y.at(get_key(*v.begin())); } + BOOST_CATCH(...) {} + BOOST_CATCH_END + } + }; + + template static void at(T& y, test::random_values const& v) + { + at_invoker()(y, v); + } + + template struct index_operator_invoker + { + void operator()(T&, test::random_values const&) {} + }; + + template + struct index_operator_invoker< + boost::unordered_map > + { + void operator()(boost::unordered_map& y, + test::random_values< + boost::unordered_map > const& v) + { + typedef typename boost::unordered_map::size_type size_type; + y[get_key(*v.begin())] = get_value(*v.begin()); + BOOST_TEST_EQ( + y.size(), static_cast(std::distance(y.begin(), y.end()))); + } + }; + + template + static void index_operator(T& y, test::random_values const& v) + { + index_operator_invoker()(y, v); + } + + template static void clear(T& y, test::random_values const&) + { + y.clear(); + BOOST_TEST(y.empty()); + BOOST_TEST_EQ(y.size(), + static_cast(std::distance(y.begin(), y.end()))); + } + + template static void capacity(T& y, test::random_values const&) + { + (void)y.empty(); + (void)y.size(); + (void)y.max_size(); + (void)y.load_factor(); + (void)y.max_load_factor(); + (void)y.hash_function(); + (void)y.key_eq(); + (void)y.get_allocator(); + } + + template static void iterators(T& y, test::random_values const&) + { + BOOST_TEST_EQ(y.size(), + static_cast(std::distance(y.begin(), y.end()))); + } + + template + static void erase_range(T& y, test::random_values const&) + { + y.erase(y.begin(), y.end()); + BOOST_TEST(y.empty()); + BOOST_TEST_EQ(y.size(), + static_cast(std::distance(y.begin(), y.end()))); + } + + template + static void erase_key(T& y, test::random_values const& v) + { + y.erase(get_key(*v.begin())); + BOOST_TEST_EQ(y.size(), + static_cast(std::distance(y.begin(), y.end()))); + } + + template static void lookup(T& y, test::random_values const& v) + { + (void)y.count(get_key(*v.begin())); + (void)y.find(get_key(*v.begin())); + (void)y.contains(get_key(*v.begin())); + (void)y.equal_range(get_key(*v.begin())); + } + + template static void reserve(T& y, test::random_values const&) + { + y.reserve(1337); + BOOST_TEST_GT(y.bucket_count(), 1337u); + BOOST_TEST_EQ(y.size(), + static_cast(std::distance(y.begin(), y.end()))); + } + + template + static void copy_assignment(T& y, test::random_values const& v) + { + T x(v.begin(), v.end()); + y = x; + BOOST_TEST_EQ(y.size(), x.size()); + BOOST_TEST_EQ(y.size(), + static_cast(std::distance(y.begin(), y.end()))); + } + + template + static void move_assignment(T& y, test::random_values const& v) + { + T x(v.begin(), v.end()); + std::size_t const size = x.size(); + y = boost::move(x); + BOOST_TEST_GE(y.size(), size); + BOOST_TEST_EQ(y.size(), + static_cast(std::distance(y.begin(), y.end()))); + } + + template static void equal(T& y, test::random_values const& v) + { + T x(v.begin(), v.end()); + (void)(y == x); + BOOST_TEST_EQ(y.size(), + static_cast(std::distance(y.begin(), y.end()))); + } + + template static void extract(T& y, test::random_values const& v) + { + (void)y.extract(get_key(*v.begin())); + BOOST_TEST_EQ(y.size(), + static_cast(std::distance(y.begin(), y.end()))); + } + + template static void merge(T& y, test::random_values const& v) + { + T x(v.begin(), v.end()); + if (y.get_allocator() == x.get_allocator()) { + y.merge(x); + } + BOOST_TEST_EQ(y.size(), + static_cast(std::distance(y.begin(), y.end()))); + } + + template bool pred(X const&) { return true; } + + template + static void erase_with_pred(T& y, test::random_values const&) + { + erase_if(y, pred); + BOOST_TEST_EQ(y.size(), + static_cast(std::distance(y.begin(), y.end()))); + } + + template + static void container_swap(T& y, test::random_values const& v) + { + T x(v.begin(), v.end()); + if (boost::allocator_propagate_on_container_swap< + typename T::allocator_type>::type::value || + x.get_allocator() == y.get_allocator()) { + y.swap(x); + } + BOOST_TEST_EQ(y.size(), + static_cast(std::distance(y.begin(), y.end()))); + } + + template static void buckets(T& y, test::random_values const& v) + { + (void)y.begin(0); + (void)y.end(0); + (void)y.bucket_count(); + (void)y.max_bucket_count(); + (void)y.bucket_size(0); + (void)y.bucket(get_key(*v.begin())); + } + + template + static void double_move_construct(T& y, test::random_values const&) + { + T x = boost::move(y); + x.clear(); + BOOST_TEST_EQ(y.size(), + static_cast(std::distance(y.begin(), y.end()))); + BOOST_TEST_EQ(x.size(), + static_cast(std::distance(x.begin(), x.end()))); + } + + template + static void double_move_assign(T& y, test::random_values const&) + { + T x; + x = boost::move(y); + x.clear(); + BOOST_TEST_EQ(y.size(), + static_cast(std::distance(y.begin(), y.end()))); + BOOST_TEST_EQ(x.size(), + static_cast(std::distance(x.begin(), x.end()))); + } + + template + static void post_move_tests(T* ptr, test::random_generator const& generator) + { + // clang-format off + void (*fps[])(T&, test::random_values const&) = { + insert_range, + insert_single, + insert_single_hint, + insert_or_assign, + insert_or_assign_hint, + try_emplace, + try_emplace_hint, + at, + index_operator, + clear, + capacity, + iterators, + erase_range, + erase_key, + lookup, + reserve, + copy_assignment, + move_assignment, + equal, + extract, + merge, + erase_with_pred, + container_swap, + buckets, + double_move_construct, + double_move_assign + }; + // clang-format on + + std::size_t const len = (sizeof(fps) / sizeof(*(fps))); + + for (std::size_t i = 0; i < len; ++i) { + test::check_instances check_; + + test::random_values const v(1000, generator); + test::object_count count; + T y(create(v, count)); + + unsigned num_allocs = test::detail::tracker.count_allocations; + (void)num_allocs; + + T x(boost::move(y)); + +#if defined(BOOST_UNORDERED_USE_MOVE) || \ + !defined(BOOST_NO_CXX11_RVALUE_REFERENCES) + BOOST_TEST(y.empty()); + BOOST_TEST(y.begin() == y.end()); + BOOST_TEST_EQ(y.bucket_count(), 0u); + BOOST_TEST_EQ(test::detail::tracker.count_allocations, num_allocs); +#endif + + fps[i](y, v); + + test::check_container(x, v); + test::check_equivalent_keys(x); + } + + for (std::size_t i = 0; i < len; ++i) { + typename T::hasher hf(1); + typename T::key_equal eq(1); + typename T::allocator_type al1(1); + typename T::allocator_type al2(2); + + test::check_instances check_; + + test::random_values v(1000, generator); + test::object_count count; + T y(v.begin(), v.end(), 0, hf, eq, al1); + T x(boost::move(y), al2); + + BOOST_TEST_NOT(y.empty()); + BOOST_TEST(y.begin() != y.end()); + + fps[i](y, v); + + test::check_container(x, v); + test::check_equivalent_keys(x); + } + + for (std::size_t i = 0; i < len; ++i) { + test::check_instances check_; + + test::random_values v(1000, generator); + test::object_count count; + T y(create(v, count)); + + unsigned num_allocs = test::detail::tracker.count_allocations; + (void)num_allocs; + + T x(empty(ptr)); + x = boost::move(y); + +#if defined(BOOST_UNORDERED_USE_MOVE) || \ + !defined(BOOST_NO_CXX11_RVALUE_REFERENCES) + BOOST_TEST(y.empty()); + BOOST_TEST(y.begin() == y.end()); + BOOST_TEST_EQ(y.bucket_count(), 0u); + BOOST_TEST_EQ(test::detail::tracker.count_allocations, num_allocs); +#endif + + fps[i](y, v); + + test::check_container(x, v); + test::check_equivalent_keys(x); + } + + for (std::size_t i = 0; i < len; ++i) { + typename T::hasher hf(1); + typename T::key_equal eq(1); + typename T::allocator_type al1(1); + typename T::allocator_type al2(2); + + test::check_instances check_; + + test::random_values v(1000, generator); + test::object_count count; + T y(v.begin(), v.end(), 0, hf, eq, al1); + + unsigned num_allocs = test::detail::tracker.count_allocations; + (void)num_allocs; + + T x(al2); + x = boost::move(y); + + bool b = boost::allocator_propagate_on_container_move_assignment< + typename T::allocator_type>::type::value; + if (b) { +#if defined(BOOST_UNORDERED_USE_MOVE) || \ + !defined(BOOST_NO_CXX11_RVALUE_REFERENCES) + BOOST_TEST(y.empty()); + BOOST_TEST(y.begin() == y.end()); + BOOST_TEST_EQ(y.bucket_count(), 0u); + BOOST_TEST_EQ(test::detail::tracker.count_allocations, num_allocs); +#else + BOOST_TEST_NOT(y.empty()); + BOOST_TEST(y.begin() != y.end()); + +#endif + } else { + BOOST_TEST_NOT(y.empty()); + BOOST_TEST(y.begin() != y.end()); + } + + fps[i](y, v); + + test::check_container(x, v); + test::check_equivalent_keys(x); + } + } + + boost::unordered_map > >* + test_map_std_alloc; + + boost::unordered_set >* test_set; + boost::unordered_multiset >* test_multiset; + boost::unordered_map > >* test_map; + boost::unordered_multimap > >* + test_multimap; + + boost::unordered_set >* + test_set_prop_move; + boost::unordered_multiset >* + test_multiset_prop_move; + boost::unordered_map, + test::propagate_move> >* test_map_prop_move; + boost::unordered_multimap, + test::propagate_move> >* test_multimap_prop_move; + + boost::unordered_set >* + test_set_no_prop_move; + boost::unordered_multiset >* + test_multiset_no_prop_move; + boost::unordered_map, + test::no_propagate_move> >* test_map_no_prop_move; + boost::unordered_multimap, + test::no_propagate_move> >* test_multimap_no_prop_move; + + using test::default_generator; + using test::generate_collisions; + using test::limited_range; + + UNORDERED_TEST(post_move_tests, + ((test_set)(test_multiset)(test_map)(test_multimap)(test_set_prop_move)( + test_multiset_prop_move)(test_map_prop_move)(test_multimap_prop_move)( + test_set_no_prop_move)(test_multiset_no_prop_move)(test_map_no_prop_move)( + test_multimap_no_prop_move))( + (default_generator)(generate_collisions)(limited_range))) +} + +RUN_TESTS()