Merge branch 'develop' into feature/detect_reentrancy

This commit is contained in:
joaquintides
2023-08-12 09:54:22 +02:00
committed by GitHub
14 changed files with 897 additions and 45 deletions
+138
View File
@@ -33,6 +33,9 @@ using hasher = stateful_hash;
using key_equal = stateful_key_equal;
using allocator_type = stateful_allocator<std::pair<raii const, raii> >;
using flat_map_type = boost::unordered::unordered_flat_map<raii, raii, hasher,
key_equal, allocator_type>;
using map_type = boost::unordered::concurrent_flat_map<raii, raii, hasher,
key_equal, allocator_type>;
@@ -843,6 +846,136 @@ namespace {
}
check_raii_counts();
}
template <class G> void flat_map_move_assign(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());
/*
* basically test that a temporary container is materialized and we
* move-assign from that
*
* we don't need to be super rigorous here because we already have tests for
* container assignment, we're just testing that a temporary is materialized
*/
{
raii::reset_counts();
flat_map_type flat_map(values.begin(), values.end(), values.size(),
hasher(1), key_equal(2), allocator_type(3));
map_type map(0, hasher(2), key_equal(1), allocator_type(3));
BOOST_TEST(flat_map.get_allocator() == map.get_allocator());
map = std::move(flat_map);
BOOST_TEST(flat_map.empty());
BOOST_TEST_EQ(map.size(), reference_map.size());
test_fuzzy_matches_reference(map, reference_map, rg);
BOOST_TEST_EQ(map.hash_function(), hasher(1));
BOOST_TEST_EQ(map.key_eq(), key_equal(2));
BOOST_TEST_EQ(raii::copy_constructor, 2 * values.size());
BOOST_TEST_EQ(raii::destructor, 2 * values.size());
BOOST_TEST_EQ(raii::move_constructor, 2 * reference_map.size());
BOOST_TEST_EQ(raii::copy_assignment, 0u);
BOOST_TEST_EQ(raii::move_assignment, 0u);
}
check_raii_counts();
{
raii::reset_counts();
map_type map(values.begin(), values.end(), values.size(), hasher(1),
key_equal(2), allocator_type(3));
flat_map_type flat_map(0, hasher(2), key_equal(1), allocator_type(3));
BOOST_TEST(flat_map.get_allocator() == map.get_allocator());
flat_map = std::move(map);
BOOST_TEST(map.empty());
BOOST_TEST_EQ(flat_map.size(), reference_map.size());
BOOST_TEST_EQ(flat_map.hash_function(), hasher(1));
BOOST_TEST_EQ(flat_map.key_eq(), key_equal(2));
BOOST_TEST_EQ(raii::copy_constructor, 2 * values.size());
BOOST_TEST_EQ(raii::destructor, 2 * values.size());
BOOST_TEST_EQ(raii::move_constructor, 2 * reference_map.size());
BOOST_TEST_EQ(raii::copy_assignment, 0u);
BOOST_TEST_EQ(raii::move_assignment, 0u);
}
check_raii_counts();
{
raii::reset_counts();
flat_map_type flat_map(values.begin(), values.end(), values.size(),
hasher(1), key_equal(2), allocator_type(3));
map_type map(0, hasher(2), key_equal(1), allocator_type(4));
BOOST_TEST(flat_map.get_allocator() != map.get_allocator());
map = std::move(flat_map);
BOOST_TEST(flat_map.empty());
BOOST_TEST_EQ(map.size(), reference_map.size());
test_fuzzy_matches_reference(map, reference_map, rg);
BOOST_TEST_EQ(map.hash_function(), hasher(1));
BOOST_TEST_EQ(map.key_eq(), key_equal(2));
BOOST_TEST_EQ(raii::copy_constructor, 2 * values.size());
BOOST_TEST_EQ(
raii::destructor, 2 * values.size() + 2 * reference_map.size());
BOOST_TEST_EQ(raii::move_constructor, 4 * reference_map.size());
BOOST_TEST_EQ(raii::copy_assignment, 0u);
BOOST_TEST_EQ(raii::move_assignment, 0u);
}
check_raii_counts();
{
raii::reset_counts();
map_type map(values.begin(), values.end(), values.size(), hasher(1),
key_equal(2), allocator_type(3));
flat_map_type flat_map(0, hasher(2), key_equal(1), allocator_type(4));
BOOST_TEST(flat_map.get_allocator() != map.get_allocator());
flat_map = std::move(map);
BOOST_TEST(map.empty());
BOOST_TEST_EQ(flat_map.size(), reference_map.size());
BOOST_TEST_EQ(flat_map.hash_function(), hasher(1));
BOOST_TEST_EQ(flat_map.key_eq(), key_equal(2));
BOOST_TEST_EQ(raii::copy_constructor, 2 * values.size());
BOOST_TEST_EQ(
raii::destructor, 2 * values.size() + 2 * reference_map.size());
BOOST_TEST_EQ(raii::move_constructor, 4 * reference_map.size());
BOOST_TEST_EQ(raii::copy_assignment, 0u);
BOOST_TEST_EQ(raii::move_assignment, 0u);
}
check_raii_counts();
}
} // namespace
// clang-format off
@@ -860,6 +993,11 @@ UNORDERED_TEST(
insert_and_assign,
((init_type_generator))
((default_generator)(sequential)(limited_range)))
UNORDERED_TEST(
flat_map_move_assign,
((init_type_generator))
((default_generator)(sequential)(limited_range)))
// clang-format on
RUN_TESTS()
+108
View File
@@ -775,6 +775,109 @@ namespace {
check_raii_counts();
}
template <class G> void flat_map_constructor(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, hasher, key_equal, allocator_type>(
values.begin(), values.end(), values.size());
raii::reset_counts();
{
boost::unordered_flat_map<raii, raii, hasher, key_equal, allocator_type>
flat_map(values.begin(), values.end(), reference_map.size(), hasher(1),
key_equal(2), allocator_type(3));
auto const old_dc = +raii::default_constructor;
auto const old_mc = +raii::move_constructor;
auto const old_cc = +raii::copy_constructor;
BOOST_TEST_EQ(old_dc, 0u);
BOOST_TEST_GT(old_mc, 0u);
BOOST_TEST_GT(old_cc, 0u);
map_type x(std::move(flat_map));
test_fuzzy_matches_reference(x, reference_map, rg);
BOOST_TEST_EQ(+raii::default_constructor, old_dc);
BOOST_TEST_EQ(+raii::move_constructor, old_mc);
BOOST_TEST_EQ(+raii::copy_constructor, old_cc);
BOOST_TEST_EQ(x.hash_function(), hasher(1));
BOOST_TEST_EQ(x.key_eq(), key_equal(2));
BOOST_TEST(x.get_allocator() == allocator_type(3));
BOOST_TEST(flat_map.empty());
}
check_raii_counts();
{
boost::unordered_flat_map<raii, raii, hasher, key_equal, allocator_type>
flat_map(0, hasher(1), key_equal(2), allocator_type(3));
map_type x(std::move(flat_map));
BOOST_TEST(x.empty());
BOOST_TEST_EQ(x.hash_function(), hasher(1));
BOOST_TEST_EQ(x.key_eq(), key_equal(2));
BOOST_TEST(x.get_allocator() == allocator_type(3));
BOOST_TEST(flat_map.empty());
}
check_raii_counts();
{
map_type flat_map(values.begin(), values.end(), reference_map.size(),
hasher(1), key_equal(2), allocator_type(3));
auto const old_dc = +raii::default_constructor;
auto const old_mc = +raii::move_constructor;
auto const old_cc = +raii::copy_constructor;
BOOST_TEST_EQ(old_dc, 0u);
BOOST_TEST_GT(old_mc, 0u);
BOOST_TEST_GT(old_cc, 0u);
boost::unordered_flat_map<raii, raii, hasher, key_equal, allocator_type>
x(std::move(flat_map));
BOOST_TEST(x == reference_map);
BOOST_TEST_EQ(+raii::default_constructor, old_dc);
BOOST_TEST_EQ(+raii::move_constructor, old_mc);
BOOST_TEST_EQ(+raii::copy_constructor, old_cc);
BOOST_TEST_EQ(x.hash_function(), hasher(1));
BOOST_TEST_EQ(x.key_eq(), key_equal(2));
BOOST_TEST(x.get_allocator() == allocator_type(3));
BOOST_TEST(flat_map.empty());
}
check_raii_counts();
{
map_type flat_map(0, hasher(1), key_equal(2), allocator_type(3));
boost::unordered_flat_map<raii, raii, hasher, key_equal, allocator_type>
x(std::move(flat_map));
BOOST_TEST(x.empty());
BOOST_TEST_EQ(x.hash_function(), hasher(1));
BOOST_TEST_EQ(x.key_eq(), key_equal(2));
BOOST_TEST(x.get_allocator() == allocator_type(3));
BOOST_TEST(flat_map.empty());
}
check_raii_counts();
}
} // namespace
// clang-format off
@@ -818,6 +921,11 @@ UNORDERED_TEST(
((value_type_generator))
((default_generator)(sequential)(limited_range)))
UNORDERED_TEST(
flat_map_constructor,
((value_type_generator))
((default_generator)(sequential)(limited_range)))
// clang-format on
RUN_TESTS()
+215 -1
View File
@@ -349,6 +349,106 @@ namespace {
} visit_all;
struct visit_while_type
{
template <class T, class X, class M>
void operator()(std::vector<T>& values, X& x, M const& reference_map)
{
using value_type = typename X::value_type;
auto mut_truthy_visitor = [&reference_map](
std::atomic<uint64_t>& num_visits) {
return [&reference_map, &num_visits](value_type& kv) {
BOOST_TEST(reference_map.contains(kv.first));
BOOST_TEST_EQ(kv.second, reference_map.find(kv.first)->second);
++num_visits;
return true;
};
};
auto const_truthy_visitor = [&reference_map](
std::atomic<uint64_t>& num_visits) {
return [&reference_map, &num_visits](value_type const& kv) {
BOOST_TEST(reference_map.contains(kv.first));
BOOST_TEST_EQ(kv.second, reference_map.find(kv.first)->second);
++num_visits;
return true;
};
};
auto mut_falsey_visitor = [&reference_map](
std::atomic<uint64_t>& num_visits) {
return [&reference_map, &num_visits](value_type& kv) {
BOOST_TEST(reference_map.contains(kv.first));
++num_visits;
return (kv.second.x_ % 100) == 0;
};
};
auto const_falsey_visitor = [&reference_map](
std::atomic<uint64_t>& num_visits) {
return [&reference_map, &num_visits](value_type const& kv) {
BOOST_TEST(reference_map.contains(kv.first));
++num_visits;
return (kv.second.x_ % 100) == 0;
};
};
{
thread_runner(values, [&x, &mut_truthy_visitor](boost::span<T>) {
std::atomic<std::uint64_t> num_visits{0};
BOOST_TEST(x.visit_while(mut_truthy_visitor(num_visits)));
BOOST_TEST_EQ(x.size(), num_visits);
});
}
{
thread_runner(values, [&x, &const_truthy_visitor](boost::span<T>) {
std::atomic<std::uint64_t> num_visits{0};
auto const& y = x;
BOOST_TEST(y.visit_while(const_truthy_visitor(num_visits)));
BOOST_TEST_EQ(x.size(), num_visits);
});
}
{
thread_runner(values, [&x, &const_truthy_visitor](boost::span<T>) {
std::atomic<std::uint64_t> num_visits{0};
BOOST_TEST(x.cvisit_while(const_truthy_visitor(num_visits)));
BOOST_TEST_EQ(x.size(), num_visits);
});
}
{
thread_runner(values, [&x, &mut_falsey_visitor](boost::span<T>) {
std::atomic<std::uint64_t> num_visits{0};
BOOST_TEST_NOT(x.visit_while(mut_falsey_visitor(num_visits)));
BOOST_TEST_LT(num_visits, x.size());
BOOST_TEST_GT(num_visits, 0u);
});
}
{
thread_runner(values, [&x, &const_falsey_visitor](boost::span<T>) {
std::atomic<std::uint64_t> num_visits{0};
auto const& y = x;
BOOST_TEST_NOT(y.visit_while(const_falsey_visitor(num_visits)));
BOOST_TEST_LT(num_visits, x.size());
BOOST_TEST_GT(num_visits, 0u);
});
}
{
thread_runner(values, [&x, &const_falsey_visitor](boost::span<T>) {
std::atomic<std::uint64_t> num_visits{0};
BOOST_TEST_NOT(x.cvisit_while(const_falsey_visitor(num_visits)));
BOOST_TEST_LT(num_visits, x.size());
BOOST_TEST_GT(num_visits, 0u);
});
}
}
} visit_while;
struct exec_policy_visit_all_type
{
template <class T, class X, class M>
@@ -407,6 +507,120 @@ namespace {
}
} exec_policy_visit_all;
struct exec_policy_visit_while_type
{
template <class T, class X, class M>
void operator()(std::vector<T>& values, X& x, M const& reference_map)
{
#if defined(BOOST_UNORDERED_PARALLEL_ALGORITHMS)
using value_type = typename X::value_type;
auto mut_truthy_visitor = [&reference_map](
std::atomic<uint64_t>& num_visits) {
return [&reference_map, &num_visits](value_type& kv) {
BOOST_TEST(reference_map.contains(kv.first));
BOOST_TEST_EQ(kv.second, reference_map.find(kv.first)->second);
++num_visits;
return true;
};
};
auto const_truthy_visitor = [&reference_map](
std::atomic<uint64_t>& num_visits) {
return [&reference_map, &num_visits](value_type const& kv) {
BOOST_TEST(reference_map.contains(kv.first));
BOOST_TEST_EQ(kv.second, reference_map.find(kv.first)->second);
++num_visits;
return true;
};
};
auto mut_falsey_visitor = [&reference_map](
std::atomic<uint64_t>& num_visits) {
return [&reference_map, &num_visits](value_type& kv) {
BOOST_TEST(reference_map.contains(kv.first));
BOOST_TEST_EQ(kv.second, reference_map.find(kv.first)->second);
++num_visits;
return (kv.second.x_ % 100) == 0;
};
};
auto const_falsey_visitor = [&reference_map](
std::atomic<uint64_t>& num_visits) {
return [&reference_map, &num_visits](value_type const& kv) {
BOOST_TEST(reference_map.contains(kv.first));
BOOST_TEST_EQ(kv.second, reference_map.find(kv.first)->second);
++num_visits;
return (kv.second.x_ % 100) == 0;
};
};
{
thread_runner(values, [&x, &mut_truthy_visitor](boost::span<T>) {
std::atomic<std::uint64_t> num_visits{0};
BOOST_TEST(
x.visit_while(std::execution::par, mut_truthy_visitor(num_visits)));
BOOST_TEST_EQ(x.size(), num_visits);
});
}
{
thread_runner(values, [&x, &const_truthy_visitor](boost::span<T>) {
std::atomic<std::uint64_t> num_visits{0};
auto const& y = x;
BOOST_TEST(y.visit_while(
std::execution::par, const_truthy_visitor(num_visits)));
BOOST_TEST_EQ(x.size(), num_visits);
});
}
{
thread_runner(values, [&x, &const_truthy_visitor](boost::span<T>) {
std::atomic<std::uint64_t> num_visits{0};
BOOST_TEST(x.cvisit_while(
std::execution::par, const_truthy_visitor(num_visits)));
BOOST_TEST_EQ(x.size(), num_visits);
});
}
{
thread_runner(values, [&x, &mut_falsey_visitor](boost::span<T>) {
std::atomic<std::uint64_t> num_visits{0};
BOOST_TEST_NOT(
x.visit_while(std::execution::par, mut_falsey_visitor(num_visits)));
BOOST_TEST_LT(num_visits, x.size());
BOOST_TEST_GT(num_visits, 0u);
});
}
{
thread_runner(values, [&x, &const_falsey_visitor](boost::span<T>) {
std::atomic<std::uint64_t> num_visits{0};
auto const& y = x;
BOOST_TEST_NOT(y.visit_while(
std::execution::par, const_falsey_visitor(num_visits)));
BOOST_TEST_LT(num_visits, x.size());
BOOST_TEST_GT(num_visits, 0u);
});
}
{
thread_runner(values, [&x, &const_falsey_visitor](boost::span<T>) {
std::atomic<std::uint64_t> num_visits{0};
BOOST_TEST_NOT(x.cvisit_while(
std::execution::par, const_falsey_visitor(num_visits)));
BOOST_TEST_LT(num_visits, x.size());
BOOST_TEST_GT(num_visits, 0u);
});
}
#else
(void)values;
(void)x;
(void)reference_map;
#endif
}
} exec_policy_visit_while;
template <class X, class G, class F>
void visit(X*, G gen, F visitor, test::random_generator rg)
{
@@ -570,7 +784,7 @@ UNORDERED_TEST(
visit,
((map))
((value_type_generator)(init_type_generator))
((lvalue_visitor)(visit_all)(exec_policy_visit_all))
((lvalue_visitor)(visit_all)(visit_while)(exec_policy_visit_all)(exec_policy_visit_while))
((default_generator)(sequential)(limited_range)))
UNORDERED_TEST(