mirror of
https://github.com/boostorg/unordered.git
synced 2025-07-30 03:17:15 +02:00
Begin work on constructors
This commit is contained in:
@ -39,26 +39,26 @@
|
|||||||
|
|
||||||
#define BOOST_UNORDERED_COMMA ,
|
#define BOOST_UNORDERED_COMMA ,
|
||||||
|
|
||||||
#define BOOST_UNORDERED_LAST_ARG(Arg, Args) \
|
#define BOOST_UNORDERED_LAST_ARG(Arg, Args) \
|
||||||
mp11::mp_back<mp11::mp_list<Arg BOOST_UNORDERED_COMMA Args>>
|
mp11::mp_back<mp11::mp_list<Arg BOOST_UNORDERED_COMMA Args> >
|
||||||
|
|
||||||
#define BOOST_UNORDERED_STATIC_ASSERT_LAST_ARG_INVOCABLE(Arg, Args) \
|
#define BOOST_UNORDERED_STATIC_ASSERT_LAST_ARG_INVOCABLE(Arg, Args) \
|
||||||
BOOST_UNORDERED_STATIC_ASSERT_INVOCABLE(BOOST_UNORDERED_LAST_ARG(Arg, Args))
|
BOOST_UNORDERED_STATIC_ASSERT_INVOCABLE(BOOST_UNORDERED_LAST_ARG(Arg, Args))
|
||||||
|
|
||||||
#define BOOST_UNORDERED_STATIC_ASSERT_LAST_ARG_CONST_INVOCABLE(Arg, Args) \
|
#define BOOST_UNORDERED_STATIC_ASSERT_LAST_ARG_CONST_INVOCABLE(Arg, Args) \
|
||||||
BOOST_UNORDERED_STATIC_ASSERT_CONST_INVOCABLE( \
|
BOOST_UNORDERED_STATIC_ASSERT_CONST_INVOCABLE( \
|
||||||
BOOST_UNORDERED_LAST_ARG(Arg, Args))
|
BOOST_UNORDERED_LAST_ARG(Arg, Args))
|
||||||
|
|
||||||
namespace boost {
|
namespace boost {
|
||||||
namespace unordered {
|
namespace unordered {
|
||||||
namespace detail {
|
namespace detail {
|
||||||
|
|
||||||
template <class F, class... Args>
|
template <class F, class... Args>
|
||||||
struct is_invocable:
|
struct is_invocable
|
||||||
std::is_constructible<
|
: std::is_constructible<std::function<void(Args...)>,
|
||||||
std::function<void(Args...)>,
|
std::reference_wrapper<typename std::remove_reference<F>::type> >
|
||||||
std::reference_wrapper<typename std::remove_reference<F>::type>
|
{
|
||||||
>
|
};
|
||||||
{};
|
|
||||||
|
|
||||||
template <class Key, class T> struct concurrent_map_types
|
template <class Key, class T> struct concurrent_map_types
|
||||||
{
|
{
|
||||||
@ -142,7 +142,11 @@ namespace boost {
|
|||||||
using const_pointer =
|
using const_pointer =
|
||||||
typename boost::allocator_const_pointer<allocator_type>::type;
|
typename boost::allocator_const_pointer<allocator_type>::type;
|
||||||
|
|
||||||
concurrent_flat_map() : concurrent_flat_map(0) {}
|
concurrent_flat_map()
|
||||||
|
: concurrent_flat_map(detail::foa::default_bucket_count)
|
||||||
|
{
|
||||||
|
}
|
||||||
|
|
||||||
explicit concurrent_flat_map(size_type n, const hasher& hf = hasher(),
|
explicit concurrent_flat_map(size_type n, const hasher& hf = hasher(),
|
||||||
const key_equal& eql = key_equal(),
|
const key_equal& eql = key_equal(),
|
||||||
const allocator_type& a = allocator_type())
|
const allocator_type& a = allocator_type())
|
||||||
@ -150,6 +154,23 @@ namespace boost {
|
|||||||
{
|
{
|
||||||
}
|
}
|
||||||
|
|
||||||
|
template <class InputIterator>
|
||||||
|
concurrent_flat_map(InputIterator f, InputIterator l,
|
||||||
|
size_type n = detail::foa::default_bucket_count,
|
||||||
|
const hasher& hf = hasher(), const key_equal& eql = key_equal(),
|
||||||
|
const allocator_type& a = allocator_type())
|
||||||
|
: table_(n, hf, eql, a)
|
||||||
|
{
|
||||||
|
this->insert(f, l);
|
||||||
|
}
|
||||||
|
|
||||||
|
concurrent_flat_map(concurrent_flat_map const& rhs)
|
||||||
|
: table_(rhs.table_,
|
||||||
|
boost::allocator_select_on_container_copy_construction(
|
||||||
|
rhs.get_allocator()))
|
||||||
|
{
|
||||||
|
}
|
||||||
|
|
||||||
/// Capacity
|
/// Capacity
|
||||||
///
|
///
|
||||||
|
|
||||||
@ -276,15 +297,13 @@ namespace boost {
|
|||||||
|
|
||||||
template <class M> bool insert_or_assign(key_type const& k, M&& obj)
|
template <class M> bool insert_or_assign(key_type const& k, M&& obj)
|
||||||
{
|
{
|
||||||
return table_.try_emplace_or_visit(
|
return table_.try_emplace_or_visit(k, std::forward<M>(obj),
|
||||||
k, std::forward<M>(obj),
|
|
||||||
[&](value_type& m) { m.second = std::forward<M>(obj); });
|
[&](value_type& m) { m.second = std::forward<M>(obj); });
|
||||||
}
|
}
|
||||||
|
|
||||||
template <class M> bool insert_or_assign(key_type&& k, M&& obj)
|
template <class M> bool insert_or_assign(key_type&& k, M&& obj)
|
||||||
{
|
{
|
||||||
return table_.try_emplace_or_visit(
|
return table_.try_emplace_or_visit(std::move(k), std::forward<M>(obj),
|
||||||
std::move(k), std::forward<M>(obj),
|
|
||||||
[&](value_type& m) { m.second = std::forward<M>(obj); });
|
[&](value_type& m) { m.second = std::forward<M>(obj); });
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -293,8 +312,8 @@ namespace boost {
|
|||||||
detail::are_transparent<K, hasher, key_equal>::value, bool>::type
|
detail::are_transparent<K, hasher, key_equal>::value, bool>::type
|
||||||
insert_or_assign(K&& k, M&& obj)
|
insert_or_assign(K&& k, M&& obj)
|
||||||
{
|
{
|
||||||
return table_.try_emplace_or_visit(
|
return table_.try_emplace_or_visit(std::forward<K>(k),
|
||||||
std::forward<K>(k), std::forward<M>(obj),
|
std::forward<M>(obj),
|
||||||
[&](value_type& m) { m.second = std::forward<M>(obj); });
|
[&](value_type& m) { m.second = std::forward<M>(obj); });
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -455,16 +474,16 @@ namespace boost {
|
|||||||
bool try_emplace_or_visit(K&& k, Arg&& arg, Args&&... args)
|
bool try_emplace_or_visit(K&& k, Arg&& arg, Args&&... args)
|
||||||
{
|
{
|
||||||
BOOST_UNORDERED_STATIC_ASSERT_LAST_ARG_INVOCABLE(Arg, Args...)
|
BOOST_UNORDERED_STATIC_ASSERT_LAST_ARG_INVOCABLE(Arg, Args...)
|
||||||
return table_.try_emplace_or_visit(
|
return table_.try_emplace_or_visit(std::forward<K>(k),
|
||||||
std::forward<K>(k), std::forward<Arg>(arg), std::forward<Args>(args)...);
|
std::forward<Arg>(arg), std::forward<Args>(args)...);
|
||||||
}
|
}
|
||||||
|
|
||||||
template <class K, class Arg, class... Args>
|
template <class K, class Arg, class... Args>
|
||||||
bool try_emplace_or_cvisit(K&& k, Arg&& arg, Args&&... args)
|
bool try_emplace_or_cvisit(K&& k, Arg&& arg, Args&&... args)
|
||||||
{
|
{
|
||||||
BOOST_UNORDERED_STATIC_ASSERT_LAST_ARG_CONST_INVOCABLE(Arg, Args...)
|
BOOST_UNORDERED_STATIC_ASSERT_LAST_ARG_CONST_INVOCABLE(Arg, Args...)
|
||||||
return table_.try_emplace_or_cvisit(
|
return table_.try_emplace_or_cvisit(std::forward<K>(k),
|
||||||
std::forward<K>(k), std::forward<Arg>(arg), std::forward<Args>(args)...);
|
std::forward<Arg>(arg), std::forward<Args>(args)...);
|
||||||
}
|
}
|
||||||
|
|
||||||
size_type erase(key_type const& k) { return table_.erase(k); }
|
size_type erase(key_type const& k) { return table_.erase(k); }
|
||||||
@ -508,6 +527,16 @@ namespace boost {
|
|||||||
///
|
///
|
||||||
void rehash(size_type n) { table_.rehash(n); }
|
void rehash(size_type n) { table_.rehash(n); }
|
||||||
void reserve(size_type n) { table_.reserve(n); }
|
void reserve(size_type n) { table_.reserve(n); }
|
||||||
|
|
||||||
|
/// Observers
|
||||||
|
///
|
||||||
|
allocator_type get_allocator() const noexcept
|
||||||
|
{
|
||||||
|
return table_.get_allocator();
|
||||||
|
}
|
||||||
|
|
||||||
|
hasher hash_function() const { return table_.hash_function(); }
|
||||||
|
key_equal key_eq() const { return table_.key_eq(); }
|
||||||
};
|
};
|
||||||
} // namespace unordered
|
} // namespace unordered
|
||||||
} // namespace boost
|
} // namespace boost
|
||||||
|
@ -175,7 +175,14 @@ alias foa_tests :
|
|||||||
foa_merge_exception_tests
|
foa_merge_exception_tests
|
||||||
;
|
;
|
||||||
|
|
||||||
local CFOA_TESTS = insert_tests erase_tests try_emplace_tests emplace_tests visit_tests ;
|
local CFOA_TESTS =
|
||||||
|
insert_tests
|
||||||
|
erase_tests
|
||||||
|
try_emplace_tests
|
||||||
|
emplace_tests
|
||||||
|
visit_tests
|
||||||
|
constructor_tests
|
||||||
|
;
|
||||||
|
|
||||||
for local test in $(CFOA_TESTS)
|
for local test in $(CFOA_TESTS)
|
||||||
{
|
{
|
||||||
|
256
test/cfoa/constructor_tests.cpp
Normal file
256
test/cfoa/constructor_tests.cpp
Normal file
@ -0,0 +1,256 @@
|
|||||||
|
// Copyright (C) 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)
|
||||||
|
|
||||||
|
#include "helpers.hpp"
|
||||||
|
|
||||||
|
#include <boost/unordered/concurrent_flat_map.hpp>
|
||||||
|
|
||||||
|
test::seed_t initialize_seed(4122023);
|
||||||
|
|
||||||
|
using test::default_generator;
|
||||||
|
using test::limited_range;
|
||||||
|
using test::sequential;
|
||||||
|
|
||||||
|
using hasher = stateful_hash;
|
||||||
|
using key_equal = stateful_key_equal;
|
||||||
|
using allocator_type = std::allocator<std::pair<raii const, raii> >;
|
||||||
|
|
||||||
|
using map_type = boost::unordered::concurrent_flat_map<raii, raii, hasher,
|
||||||
|
key_equal, allocator_type>;
|
||||||
|
|
||||||
|
UNORDERED_AUTO_TEST (default_constructor) {
|
||||||
|
boost::unordered::concurrent_flat_map<raii, raii> x;
|
||||||
|
BOOST_TEST(x.empty());
|
||||||
|
BOOST_TEST_EQ(x.size(), 0u);
|
||||||
|
}
|
||||||
|
|
||||||
|
UNORDERED_AUTO_TEST (bucket_count_with_hasher_key_equal_and_allocator) {
|
||||||
|
raii::reset_counts();
|
||||||
|
{
|
||||||
|
map_type x(0);
|
||||||
|
|
||||||
|
BOOST_TEST(x.empty());
|
||||||
|
BOOST_TEST_EQ(x.size(), 0u);
|
||||||
|
BOOST_TEST_EQ(x.hash_function(), hasher());
|
||||||
|
BOOST_TEST_EQ(x.key_eq(), key_equal());
|
||||||
|
}
|
||||||
|
|
||||||
|
{
|
||||||
|
map_type x(0, hasher(1));
|
||||||
|
|
||||||
|
BOOST_TEST(x.empty());
|
||||||
|
BOOST_TEST_EQ(x.size(), 0u);
|
||||||
|
BOOST_TEST_EQ(x.hash_function(), hasher(1));
|
||||||
|
BOOST_TEST_EQ(x.key_eq(), key_equal());
|
||||||
|
}
|
||||||
|
|
||||||
|
{
|
||||||
|
map_type x(0, hasher(1), key_equal(2));
|
||||||
|
|
||||||
|
BOOST_TEST(x.empty());
|
||||||
|
BOOST_TEST_EQ(x.size(), 0u);
|
||||||
|
BOOST_TEST_EQ(x.hash_function(), hasher(1));
|
||||||
|
BOOST_TEST_EQ(x.key_eq(), key_equal(2));
|
||||||
|
}
|
||||||
|
|
||||||
|
{
|
||||||
|
map_type x(0, hasher(1), key_equal(2), allocator_type{});
|
||||||
|
|
||||||
|
BOOST_TEST(x.empty());
|
||||||
|
BOOST_TEST_EQ(x.size(), 0u);
|
||||||
|
BOOST_TEST_EQ(x.hash_function(), hasher(1));
|
||||||
|
BOOST_TEST_EQ(x.key_eq(), key_equal(2));
|
||||||
|
BOOST_TEST(x.get_allocator() == allocator_type{});
|
||||||
|
}
|
||||||
|
raii::reset_counts();
|
||||||
|
}
|
||||||
|
|
||||||
|
namespace {
|
||||||
|
template <class G> void from_iterator_range(G gen, test::random_generator rg)
|
||||||
|
{
|
||||||
|
auto values = make_random_values(1024 * 16, [&] { return gen(rg); });
|
||||||
|
auto reference_map =
|
||||||
|
boost::unordered_flat_map<raii, raii>(values.begin(), values.end());
|
||||||
|
raii::reset_counts();
|
||||||
|
|
||||||
|
{
|
||||||
|
map_type x(values.begin(), values.end());
|
||||||
|
|
||||||
|
test_matches_reference(x, reference_map);
|
||||||
|
BOOST_TEST_GT(x.size(), 0u);
|
||||||
|
BOOST_TEST_LE(x.size(), values.size());
|
||||||
|
BOOST_TEST_EQ(x.hash_function(), hasher());
|
||||||
|
BOOST_TEST_EQ(x.key_eq(), key_equal());
|
||||||
|
BOOST_TEST(x.get_allocator() == allocator_type{});
|
||||||
|
if (rg == sequential) {
|
||||||
|
BOOST_TEST_EQ(x.size(), values.size());
|
||||||
|
}
|
||||||
|
raii::reset_counts();
|
||||||
|
}
|
||||||
|
|
||||||
|
{
|
||||||
|
map_type x(values.begin(), values.end(), 0);
|
||||||
|
|
||||||
|
test_matches_reference(x, reference_map);
|
||||||
|
BOOST_TEST_GT(x.size(), 0u);
|
||||||
|
BOOST_TEST_LE(x.size(), values.size());
|
||||||
|
BOOST_TEST_EQ(x.hash_function(), hasher());
|
||||||
|
BOOST_TEST_EQ(x.key_eq(), key_equal());
|
||||||
|
BOOST_TEST(x.get_allocator() == allocator_type{});
|
||||||
|
if (rg == sequential) {
|
||||||
|
BOOST_TEST_EQ(x.size(), values.size());
|
||||||
|
}
|
||||||
|
raii::reset_counts();
|
||||||
|
}
|
||||||
|
|
||||||
|
{
|
||||||
|
map_type x(values.begin(), values.end(), 0, hasher(1));
|
||||||
|
|
||||||
|
test_matches_reference(x, reference_map);
|
||||||
|
BOOST_TEST_GT(x.size(), 0u);
|
||||||
|
BOOST_TEST_LE(x.size(), values.size());
|
||||||
|
BOOST_TEST_EQ(x.hash_function(), hasher(1));
|
||||||
|
BOOST_TEST_EQ(x.key_eq(), key_equal());
|
||||||
|
BOOST_TEST(x.get_allocator() == allocator_type{});
|
||||||
|
if (rg == sequential) {
|
||||||
|
BOOST_TEST_EQ(x.size(), values.size());
|
||||||
|
}
|
||||||
|
raii::reset_counts();
|
||||||
|
}
|
||||||
|
|
||||||
|
{
|
||||||
|
map_type x(values.begin(), values.end(), 0, hasher(1), key_equal(2));
|
||||||
|
|
||||||
|
test_matches_reference(x, reference_map);
|
||||||
|
BOOST_TEST_GT(x.size(), 0u);
|
||||||
|
BOOST_TEST_LE(x.size(), values.size());
|
||||||
|
BOOST_TEST_EQ(x.hash_function(), hasher(1));
|
||||||
|
BOOST_TEST_EQ(x.key_eq(), key_equal(2));
|
||||||
|
BOOST_TEST(x.get_allocator() == allocator_type{});
|
||||||
|
if (rg == sequential) {
|
||||||
|
BOOST_TEST_EQ(x.size(), values.size());
|
||||||
|
}
|
||||||
|
raii::reset_counts();
|
||||||
|
}
|
||||||
|
|
||||||
|
{
|
||||||
|
map_type x(values.begin(), values.end(), 0, hasher(1), key_equal(2),
|
||||||
|
allocator_type{});
|
||||||
|
|
||||||
|
test_matches_reference(x, reference_map);
|
||||||
|
BOOST_TEST_GT(x.size(), 0u);
|
||||||
|
BOOST_TEST_LE(x.size(), values.size());
|
||||||
|
BOOST_TEST_EQ(x.hash_function(), hasher(1));
|
||||||
|
BOOST_TEST_EQ(x.key_eq(), key_equal(2));
|
||||||
|
BOOST_TEST(x.get_allocator() == allocator_type{});
|
||||||
|
if (rg == sequential) {
|
||||||
|
BOOST_TEST_EQ(x.size(), values.size());
|
||||||
|
}
|
||||||
|
raii::reset_counts();
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
template <class G> void copy_constructor(G gen, test::random_generator rg)
|
||||||
|
{
|
||||||
|
{
|
||||||
|
map_type x(0, hasher(1), key_equal(2), allocator_type{});
|
||||||
|
map_type y(x);
|
||||||
|
|
||||||
|
BOOST_TEST_EQ(y.size(), x.size());
|
||||||
|
BOOST_TEST_EQ(y.hash_function(), x.hash_function());
|
||||||
|
BOOST_TEST_EQ(y.key_eq(), x.key_eq());
|
||||||
|
BOOST_TEST(y.get_allocator() == x.get_allocator());
|
||||||
|
}
|
||||||
|
|
||||||
|
auto values = make_random_values(1024 * 16, [&] { return gen(rg); });
|
||||||
|
auto reference_map =
|
||||||
|
boost::unordered_flat_map<raii, raii>(values.begin(), values.end());
|
||||||
|
raii::reset_counts();
|
||||||
|
|
||||||
|
{
|
||||||
|
map_type x(values.begin(), values.end(), 0, hasher(1), key_equal(2),
|
||||||
|
allocator_type{});
|
||||||
|
|
||||||
|
thread_runner(
|
||||||
|
values, [&x, &reference_map](
|
||||||
|
boost::span<typename decltype(values)::value_type> s) {
|
||||||
|
(void)s;
|
||||||
|
map_type y(x);
|
||||||
|
|
||||||
|
test_matches_reference(x, reference_map);
|
||||||
|
test_matches_reference(y, reference_map);
|
||||||
|
BOOST_TEST_EQ(y.size(), x.size());
|
||||||
|
BOOST_TEST_EQ(y.hash_function(), x.hash_function());
|
||||||
|
BOOST_TEST_EQ(y.key_eq(), x.key_eq());
|
||||||
|
BOOST_TEST(y.get_allocator() == x.get_allocator());
|
||||||
|
});
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
template <class G>
|
||||||
|
void copy_constructor_with_insertion(G gen, test::random_generator rg)
|
||||||
|
{
|
||||||
|
auto values = make_random_values(1024 * 16, [&] { return gen(rg); });
|
||||||
|
auto reference_map =
|
||||||
|
boost::unordered_flat_map<raii, raii>(values.begin(), values.end());
|
||||||
|
raii::reset_counts();
|
||||||
|
|
||||||
|
{
|
||||||
|
map_type x(0, hasher(1), key_equal(2), allocator_type{});
|
||||||
|
|
||||||
|
auto f = [&x, &values] {
|
||||||
|
std::this_thread::sleep_for(std::chrono::milliseconds(75));
|
||||||
|
for (auto const& val : values) {
|
||||||
|
x.insert(val);
|
||||||
|
}
|
||||||
|
};
|
||||||
|
|
||||||
|
std::thread t1(f);
|
||||||
|
std::thread t2(f);
|
||||||
|
|
||||||
|
thread_runner(
|
||||||
|
values, [&x, &reference_map, &values, rg](
|
||||||
|
boost::span<typename decltype(values)::value_type> s) {
|
||||||
|
(void)s;
|
||||||
|
map_type y(x);
|
||||||
|
BOOST_TEST_GT(y.size(), 0u);
|
||||||
|
BOOST_TEST_LE(y.size(), values.size());
|
||||||
|
BOOST_TEST_EQ(y.hash_function(), x.hash_function());
|
||||||
|
BOOST_TEST_EQ(y.key_eq(), x.key_eq());
|
||||||
|
BOOST_TEST(y.get_allocator() == x.get_allocator());
|
||||||
|
|
||||||
|
x.visit_all([&reference_map, rg](
|
||||||
|
typename map_type::value_type const& val) {
|
||||||
|
BOOST_TEST(reference_map.contains(val.first));
|
||||||
|
if (rg == sequential) {
|
||||||
|
BOOST_TEST_EQ(val.second, reference_map.find(val.first)->second);
|
||||||
|
}
|
||||||
|
});
|
||||||
|
});
|
||||||
|
|
||||||
|
t1.join();
|
||||||
|
t2.join();
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
} // namespace
|
||||||
|
|
||||||
|
// clang-format off
|
||||||
|
UNORDERED_TEST(
|
||||||
|
from_iterator_range,
|
||||||
|
((value_type_generator))
|
||||||
|
((default_generator)(sequential)(limited_range)))
|
||||||
|
|
||||||
|
UNORDERED_TEST(
|
||||||
|
copy_constructor,
|
||||||
|
((value_type_generator))
|
||||||
|
((default_generator)(sequential)(limited_range)))
|
||||||
|
|
||||||
|
UNORDERED_TEST(
|
||||||
|
copy_constructor_with_insertion,
|
||||||
|
((value_type_generator))
|
||||||
|
((default_generator)(sequential)(limited_range)))
|
||||||
|
// clang-format on
|
||||||
|
|
||||||
|
RUN_TESTS()
|
@ -36,6 +36,67 @@ struct transp_key_equal
|
|||||||
}
|
}
|
||||||
};
|
};
|
||||||
|
|
||||||
|
struct stateful_hash
|
||||||
|
{
|
||||||
|
int x_ = -1;
|
||||||
|
|
||||||
|
stateful_hash() = default;
|
||||||
|
stateful_hash(stateful_hash const&) = default;
|
||||||
|
stateful_hash(stateful_hash&& rhs) noexcept
|
||||||
|
{
|
||||||
|
auto tmp = x_;
|
||||||
|
x_ = rhs.x_;
|
||||||
|
rhs.x_ = tmp;
|
||||||
|
}
|
||||||
|
|
||||||
|
stateful_hash(int const x) : x_{x} {}
|
||||||
|
|
||||||
|
template <class T> std::size_t operator()(T const& t) const noexcept
|
||||||
|
{
|
||||||
|
std::size_t h = static_cast<std::size_t>(x_);
|
||||||
|
boost::hash_combine(h, t);
|
||||||
|
return h;
|
||||||
|
}
|
||||||
|
|
||||||
|
bool operator==(stateful_hash const& rhs) const { return x_ == rhs.x_; }
|
||||||
|
|
||||||
|
friend std::ostream& operator<<(std::ostream& os, stateful_hash const& rhs)
|
||||||
|
{
|
||||||
|
os << "{ x_: " << rhs.x_ << " }";
|
||||||
|
return os;
|
||||||
|
}
|
||||||
|
};
|
||||||
|
|
||||||
|
struct stateful_key_equal
|
||||||
|
{
|
||||||
|
int x_ = -1;
|
||||||
|
|
||||||
|
stateful_key_equal() = default;
|
||||||
|
stateful_key_equal(stateful_key_equal const&) = default;
|
||||||
|
stateful_key_equal(stateful_key_equal&& rhs) noexcept
|
||||||
|
{
|
||||||
|
auto tmp = x_;
|
||||||
|
x_ = rhs.x_;
|
||||||
|
rhs.x_ = tmp;
|
||||||
|
}
|
||||||
|
|
||||||
|
stateful_key_equal(int const x) : x_{x} {}
|
||||||
|
|
||||||
|
template <class T, class U> bool operator()(T const& t, U const& u) const
|
||||||
|
{
|
||||||
|
return t == u;
|
||||||
|
}
|
||||||
|
|
||||||
|
bool operator==(stateful_key_equal const& rhs) const { return x_ == rhs.x_; }
|
||||||
|
|
||||||
|
friend std::ostream& operator<<(
|
||||||
|
std::ostream& os, stateful_key_equal const& rhs)
|
||||||
|
{
|
||||||
|
os << "{ x_: " << rhs.x_ << " }";
|
||||||
|
return os;
|
||||||
|
}
|
||||||
|
};
|
||||||
|
|
||||||
struct raii
|
struct raii
|
||||||
{
|
{
|
||||||
static std::atomic<std::uint32_t> default_constructor;
|
static std::atomic<std::uint32_t> default_constructor;
|
||||||
@ -226,4 +287,14 @@ template <class T, class F> void thread_runner(std::vector<T>& values, F f)
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
template <class X, class Y>
|
||||||
|
void test_matches_reference(X const& x, Y const& reference_map)
|
||||||
|
{
|
||||||
|
using value_type = typename X::value_type;
|
||||||
|
BOOST_TEST_EQ(x.size(), x.visit_all([&](value_type const& kv) {
|
||||||
|
BOOST_TEST(reference_map.contains(kv.first));
|
||||||
|
BOOST_TEST_EQ(kv.second, reference_map.find(kv.first)->second);
|
||||||
|
}));
|
||||||
|
}
|
||||||
|
|
||||||
#endif // BOOST_UNORDERED_TEST_CFOA_HELPERS_HPP
|
#endif // BOOST_UNORDERED_TEST_CFOA_HELPERS_HPP
|
Reference in New Issue
Block a user