// Copyright 2006-2010 Daniel James. // Copyright (C) 2022-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) #if !defined(PIECEWISE_TEST_NAME) #include "../helpers/unordered.hpp" #include "../helpers/test.hpp" #include "../objects/test.hpp" #include "../helpers/random_values.hpp" #include "../helpers/tracker.hpp" #include "../helpers/equivalent.hpp" #include "../helpers/invariants.hpp" #include "../helpers/input_iterator.hpp" #include "../helpers/helpers.hpp" #include #include namespace insert_tests { test::seed_t initialize_seed(243432); template void unique_insert_tests1(X*, test::random_generator generator) { test::check_instances check_; typedef typename X::iterator iterator; typedef test::ordered ordered; UNORDERED_SUB_TEST("insert(value) tests for containers with unique keys") { X x; test::ordered tracker = test::create_ordered(x); test::random_values v(1000, generator); for (typename test::random_values::iterator it = v.begin(); it != v.end(); ++it) { typename X::size_type old_bucket_count = x.bucket_count(); float b = x.max_load_factor(); std::pair r1 = x.insert(*it); std::pair r2 = tracker.insert(*it); BOOST_TEST(r1.second == r2.second); BOOST_TEST(*r1.first == *r2.first); tracker.compare_key(x, *it); if (static_cast(x.size()) <= b * static_cast(old_bucket_count)) BOOST_TEST(x.bucket_count() == old_bucket_count); } test::check_equivalent_keys(x); } UNORDERED_SUB_TEST("insert(rvalue) tests for containers with unique keys") { X x; test::ordered tracker = test::create_ordered(x); test::random_values v(1000, generator); for (typename test::random_values::iterator it = v.begin(); it != v.end(); ++it) { typename X::size_type old_bucket_count = x.bucket_count(); float b = x.max_load_factor(); typename X::value_type value = *it; std::pair r1 = x.insert(boost::move(value)); std::pair r2 = tracker.insert(*it); BOOST_TEST(r1.second == r2.second); BOOST_TEST(*r1.first == *r2.first); tracker.compare_key(x, *it); if (static_cast(x.size()) <= b * static_cast(old_bucket_count)) BOOST_TEST(x.bucket_count() == old_bucket_count); } test::check_equivalent_keys(x); } } template void equivalent_insert_tests1(X*, test::random_generator generator) { test::check_instances check_; UNORDERED_SUB_TEST( "insert(value) tests for containers with equivalent keys") { X x; test::ordered tracker = test::create_ordered(x); test::random_values v(1000, generator); for (typename test::random_values::iterator it = v.begin(); it != v.end(); ++it) { typename X::size_type old_bucket_count = x.bucket_count(); float b = x.max_load_factor(); typename X::iterator r1 = x.insert(*it); typename test::ordered::iterator r2 = tracker.insert(*it); BOOST_TEST(*r1 == *r2); tracker.compare_key(x, *it); if (static_cast(x.size()) <= b * static_cast(old_bucket_count)) BOOST_TEST(x.bucket_count() == old_bucket_count); } test::check_equivalent_keys(x); } UNORDERED_SUB_TEST( "insert(rvalue) tests for containers with equivalent keys") { X x; test::ordered tracker = test::create_ordered(x); test::random_values v(1000, generator); for (typename test::random_values::iterator it = v.begin(); it != v.end(); ++it) { typename X::size_type old_bucket_count = x.bucket_count(); float b = x.max_load_factor(); typename X::value_type value = *it; typename X::iterator r1 = x.insert(boost::move(value)); typename test::ordered::iterator r2 = tracker.insert(*it); BOOST_TEST(*r1 == *r2); tracker.compare_key(x, *it); if (static_cast(x.size()) <= b * static_cast(old_bucket_count)) BOOST_TEST(x.bucket_count() == old_bucket_count); } test::check_equivalent_keys(x); } } template void insert_tests2(X*, test::random_generator generator) { typedef typename test::ordered tracker_type; typedef typename X::iterator iterator; typedef typename X::const_iterator const_iterator; typedef typename tracker_type::iterator tracker_iterator; UNORDERED_SUB_TEST("insert(begin(), value) tests") { test::check_instances check_; X x; tracker_type tracker = test::create_ordered(x); test::random_values v(1000, generator); for (typename test::random_values::iterator it = v.begin(); it != v.end(); ++it) { typename X::size_type old_bucket_count = x.bucket_count(); float b = x.max_load_factor(); iterator r1 = x.insert(x.begin(), *it); tracker_iterator r2 = tracker.insert(tracker.begin(), *it); BOOST_TEST(*r1 == *r2); tracker.compare_key(x, *it); if (static_cast(x.size()) <= b * static_cast(old_bucket_count)) BOOST_TEST(x.bucket_count() == old_bucket_count); } tracker.compare(x); test::check_equivalent_keys(x); } UNORDERED_SUB_TEST("insert(end(), value) tests") { test::check_instances check_; X x; X const& x_const = x; tracker_type tracker = test::create_ordered(x); test::random_values v(100, generator); for (typename test::random_values::iterator it = v.begin(); it != v.end(); ++it) { typename X::size_type old_bucket_count = x.bucket_count(); float b = x.max_load_factor(); const_iterator r1 = x.insert(x_const.end(), *it); tracker_iterator r2 = tracker.insert(tracker.end(), *it); BOOST_TEST(*r1 == *r2); tracker.compare_key(x, *it); if (static_cast(x.size()) <= b * static_cast(old_bucket_count)) BOOST_TEST(x.bucket_count() == old_bucket_count); } tracker.compare(x); test::check_equivalent_keys(x); } UNORDERED_SUB_TEST("insert(pos, value) tests") { test::check_instances check_; X x; iterator pos = x.begin(); tracker_type tracker = test::create_ordered(x); test::random_values v(1000, generator); for (typename test::random_values::iterator it = v.begin(); it != v.end(); ++it) { typename X::size_type old_bucket_count = x.bucket_count(); float b = x.max_load_factor(); pos = x.insert(pos, *it); tracker_iterator r2 = tracker.insert(tracker.begin(), *it); BOOST_TEST(*pos == *r2); tracker.compare_key(x, *it); if (static_cast(x.size()) <= b * static_cast(old_bucket_count)) BOOST_TEST(x.bucket_count() == old_bucket_count); } tracker.compare(x); test::check_equivalent_keys(x); } UNORDERED_SUB_TEST("insert(pos, rvalue) tests") { test::check_instances check_; X x; iterator pos = x.begin(); tracker_type tracker = test::create_ordered(x); test::random_values v(1000, generator); for (typename test::random_values::iterator it = v.begin(); it != v.end(); ++it) { typename X::size_type old_bucket_count = x.bucket_count(); float b = x.max_load_factor(); typename X::value_type value = *it; pos = x.insert(pos, boost::move(value)); tracker_iterator r2 = tracker.insert(tracker.begin(), *it); BOOST_TEST(*pos == *r2); tracker.compare_key(x, *it); if (static_cast(x.size()) <= b * static_cast(old_bucket_count)) BOOST_TEST(x.bucket_count() == old_bucket_count); } tracker.compare(x); test::check_equivalent_keys(x); } UNORDERED_SUB_TEST("insert single item range tests") { test::check_instances check_; X x; tracker_type tracker = test::create_ordered(x); test::random_values v(1000, generator); for (typename test::random_values::iterator it = v.begin(); it != v.end(); ++it) { typename X::size_type old_bucket_count = x.bucket_count(); float b = x.max_load_factor(); x.insert(it, test::next(it)); tracker.insert(*it); tracker.compare_key(x, *it); if (static_cast(x.size()) <= b * static_cast(old_bucket_count)) BOOST_TEST(x.bucket_count() == old_bucket_count); } tracker.compare(x); test::check_equivalent_keys(x); } UNORDERED_SUB_TEST("insert range tests") { test::check_instances check_; X x; test::random_values v(1000, generator); x.insert(v.begin(), v.end()); test::check_container(x, v); test::check_equivalent_keys(x); } UNORDERED_SUB_TEST("insert range with rehash tests") { test::check_instances check_; X x; test::random_values v(1000, generator); x.insert(*v.begin()); x.clear(); x.insert(v.begin(), v.end()); test::check_container(x, v); test::check_equivalent_keys(x); } UNORDERED_SUB_TEST("insert input iterator range tests") { test::check_instances check_; X x; test::random_values v(1000, generator); typename test::random_values::const_iterator begin = v.begin(), end = v.end(); x.insert(test::input_iterator(begin), test::input_iterator(end)); test::check_container(x, v); test::check_equivalent_keys(x); } UNORDERED_SUB_TEST("insert copy iterator range tests") { test::check_instances check_; X x; test::random_values v(1000, generator); x.insert(test::copy_iterator(v.begin()), test::copy_iterator(v.end())); test::check_container(x, v); test::check_equivalent_keys(x); } UNORDERED_SUB_TEST("insert copy iterator range test 2") { test::check_instances check_; X x; test::random_values v1(500, generator); test::random_values v2(500, generator); x.insert(test::copy_iterator(v1.begin()), test::copy_iterator(v1.end())); x.insert(test::copy_iterator(v2.begin()), test::copy_iterator(v2.end())); test::check_equivalent_keys(x); } UNORDERED_SUB_TEST("insert various ranges") { for (int i = 0; i < 100; ++i) { X x; test::ordered tracker = test::create_ordered(x); test::random_values v(1000, generator); for (typename test::random_values::iterator it = v.begin(); it != v.end();) { typename X::size_type old_bucket_count = x.bucket_count(); float b = x.max_load_factor(); typename test::random_values::iterator next = it; for (std::size_t j = test::random_value(20); j > 0; ++j) { ++next; if (next == v.end()) { break; } } x.insert(it, next); tracker.insert(it, next); it = next; tracker.compare(x); // Slow, but I can't see any other way. if (static_cast(x.size()) <= b * static_cast(old_bucket_count)) BOOST_TEST(x.bucket_count() == old_bucket_count); } test::check_equivalent_keys(x); } } } template void unique_emplace_tests1(X*, test::random_generator generator) { typedef typename X::iterator iterator; typedef test::ordered ordered; X x; test::ordered tracker = test::create_ordered(x); test::random_values v(1000, generator); for (typename test::random_values::iterator it = v.begin(); it != v.end(); ++it) { typename X::size_type old_bucket_count = x.bucket_count(); float b = x.max_load_factor(); std::pair r1 = x.emplace(*it); std::pair r2 = tracker.insert(*it); BOOST_TEST(r1.second == r2.second); BOOST_TEST(*r1.first == *r2.first); tracker.compare_key(x, *it); if (static_cast(x.size()) <= b * static_cast(old_bucket_count)) BOOST_TEST(x.bucket_count() == old_bucket_count); } tracker.compare(x); test::check_equivalent_keys(x); } template void equivalent_emplace_tests1(X*, test::random_generator generator) { X x; test::ordered tracker = test::create_ordered(x); test::random_values v(1000, generator); for (typename test::random_values::iterator it = v.begin(); it != v.end(); ++it) { typename X::size_type old_bucket_count = x.bucket_count(); float b = x.max_load_factor(); typename X::iterator r1 = x.emplace(*it); typename test::ordered::iterator r2 = tracker.insert(*it); BOOST_TEST(*r1 == *r2); tracker.compare_key(x, *it); if (static_cast(x.size()) <= b * static_cast(old_bucket_count)) BOOST_TEST(x.bucket_count() == old_bucket_count); } tracker.compare(x); test::check_equivalent_keys(x); } template void move_emplace_tests(X*, test::random_generator generator) { X x; test::ordered tracker = test::create_ordered(x); test::random_values v(1000, generator); for (typename test::random_values::iterator it = v.begin(); it != v.end(); ++it) { typename X::size_type old_bucket_count = x.bucket_count(); float b = x.max_load_factor(); typename X::value_type value = *it; x.emplace(boost::move(value)); tracker.insert(*it); tracker.compare_key(x, *it); if (static_cast(x.size()) <= b * static_cast(old_bucket_count)) BOOST_TEST(x.bucket_count() == old_bucket_count); } tracker.compare(x); test::check_equivalent_keys(x); } template void default_emplace_tests(X*, test::random_generator) { #if !BOOST_UNORDERED_SUN_WORKAROUNDS1 bool is_unique = test::has_unique_keys::value; X x; x.emplace(); BOOST_TEST(x.size() == 1); x.emplace(); BOOST_TEST(x.size() == (is_unique ? 1u : 2u)); x.emplace(); BOOST_TEST(x.size() == (is_unique ? 1u : 3u)); typename X::value_type y; BOOST_TEST(x.count(test::get_key(y)) == (is_unique ? 1u : 3u)); BOOST_TEST(*x.equal_range(test::get_key(y)).first == y); x.emplace(y); BOOST_TEST(x.size() == (is_unique ? 1u : 4u)); BOOST_TEST(x.count(test::get_key(y)) == (is_unique ? 1u : 4u)); BOOST_TEST(*x.equal_range(test::get_key(y)).first == y); x.clear(); BOOST_TEST(x.empty()); x.emplace(y); BOOST_TEST(x.size() == 1); x.emplace(y); BOOST_TEST(x.size() == (is_unique ? 1u : 2u)); BOOST_TEST(x.count(test::get_key(y)) == (is_unique ? 1u : 2u)); BOOST_TEST(*x.equal_range(test::get_key(y)).first == y); #endif } template void map_tests(X*, test::random_generator generator) { X x; test::ordered tracker = test::create_ordered(x); test::random_values v(1000, generator); for (typename test::random_values::iterator it = v.begin(); it != v.end(); ++it) { typename X::size_type old_bucket_count = x.bucket_count(); float b = x.max_load_factor(); x[it->first] = it->second; tracker[it->first] = it->second; tracker.compare_key(x, *it); if (static_cast(x.size()) <= b * static_cast(old_bucket_count)) BOOST_TEST(x.bucket_count() == old_bucket_count); } tracker.compare(x); test::check_equivalent_keys(x); } template void map_tests2(X*, test::random_generator generator) { typedef typename X::iterator iterator; UNORDERED_SUB_TEST("insert_or_assign") { test::check_instances check_; X x; test::ordered tracker = test::create_ordered(x); test::random_values v(1000, generator); for (typename test::random_values::iterator it = v.begin(); it != v.end(); ++it) { typename X::size_type old_bucket_count = x.bucket_count(); float b = x.max_load_factor(); std::pair r = x.insert_or_assign(it->first, it->second); BOOST_TEST(*r.first == *it); tracker[it->first] = it->second; tracker.compare_key(x, *it); if (static_cast(x.size()) < b * static_cast(old_bucket_count)) BOOST_TEST(x.bucket_count() == old_bucket_count); } tracker.compare(x); test::check_equivalent_keys(x); } UNORDERED_SUB_TEST("insert_or_assign(begin)") { test::check_instances check_; X x; test::ordered tracker = test::create_ordered(x); test::random_values v(1000, generator); for (typename test::random_values::iterator it = v.begin(); it != v.end(); ++it) { typename X::size_type old_bucket_count = x.bucket_count(); float b = x.max_load_factor(); iterator r = x.insert_or_assign(x.begin(), it->first, it->second); BOOST_TEST(*r == *it); tracker[it->first] = it->second; tracker.compare_key(x, *it); if (static_cast(x.size()) < b * static_cast(old_bucket_count)) BOOST_TEST(x.bucket_count() == old_bucket_count); } tracker.compare(x); test::check_equivalent_keys(x); } UNORDERED_SUB_TEST("insert_or_assign(end)") { test::check_instances check_; X x; test::ordered tracker = test::create_ordered(x); test::random_values v(1000, generator); for (typename test::random_values::iterator it = v.begin(); it != v.end(); ++it) { typename X::size_type old_bucket_count = x.bucket_count(); float b = x.max_load_factor(); iterator r = x.insert_or_assign(x.end(), it->first, it->second); BOOST_TEST(*r == *it); tracker[it->first] = it->second; tracker.compare_key(x, *it); if (static_cast(x.size()) < b * static_cast(old_bucket_count)) BOOST_TEST(x.bucket_count() == old_bucket_count); } tracker.compare(x); test::check_equivalent_keys(x); } UNORDERED_SUB_TEST("insert_or_assign(last)") { test::check_instances check_; X x; test::ordered tracker = test::create_ordered(x); iterator last = x.begin(); test::random_values v(1000, generator); for (typename test::random_values::iterator it = v.begin(); it != v.end(); ++it) { typename X::size_type old_bucket_count = x.bucket_count(); float b = x.max_load_factor(); iterator r = x.insert_or_assign(last, it->first, it->second); BOOST_TEST(*r == *it); tracker[it->first] = it->second; tracker.compare_key(x, *it); if (static_cast(x.size()) < b * static_cast(old_bucket_count)) BOOST_TEST(x.bucket_count() == old_bucket_count); last = r; } tracker.compare(x); test::check_equivalent_keys(x); } } template void set_tests(X*, test::random_generator) { // prove that our insert(iterator, iterator) implementation honors // Cpp17EmplaceConstructible // X x; std::vector v; v.reserve(1000); for (unsigned i = 0; i < 1000; ++i) { v.push_back(static_cast(i)); } x.insert(v.begin(), v.end()); BOOST_TEST_EQ(x.size(), 1000u); } struct pointer_constructible { int x; pointer_constructible(int x_) : x(x_) {} pointer_constructible(pointer_constructible const& p) : x(p.x) {} pointer_constructible(pointer_constructible* const&) : x(-1) {} pointer_constructible(BOOST_RV_REF(pointer_constructible*)) : x(-2) {} }; struct pointer_constructible_hash { typedef void is_transparent; std::size_t operator()(pointer_constructible const& p) const { return boost::hash()(p.x); } }; struct pointer_constructible_equal_to { typedef void is_transparent; bool operator()( pointer_constructible const& lhs, pointer_constructible const& rhs) const { return lhs.x == rhs.x; } }; template