Add visit_all()

This commit is contained in:
Christian Mazakas
2023-04-07 12:39:39 -07:00
parent 91eb2ddbd1
commit ed80cb14e2
2 changed files with 198 additions and 57 deletions

View File

@ -185,9 +185,51 @@ namespace boost {
template <class F> std::size_t visit_all(F f) template <class F> std::size_t visit_all(F f)
{ {
BOOST_UNORDERED_STATIC_ASSERT_INVOCABLE(F)
return table_.visit_all(f); return table_.visit_all(f);
} }
template <class F> std::size_t visit_all(F f) const
{
BOOST_UNORDERED_STATIC_ASSERT_CONST_INVOCABLE(F)
return table_.visit_all(f);
}
template <class F> std::size_t cvisit_all(F f) const
{
BOOST_UNORDERED_STATIC_ASSERT_CONST_INVOCABLE(F)
return table_.cvisit_all(f);
}
#if defined(BOOST_UNORDERED_PARALLEL_ALGORITHMS)
template <class ExecPolicy, class F>
typename std::enable_if<detail::is_execution_policy<ExecPolicy>::value,
void>::type
visit_all(ExecPolicy p, F f)
{
BOOST_UNORDERED_STATIC_ASSERT_INVOCABLE(F)
table_.visit_all(p, f);
}
template <class ExecPolicy, class F>
typename std::enable_if<detail::is_execution_policy<ExecPolicy>::value,
void>::type
visit_all(ExecPolicy p, F f) const
{
BOOST_UNORDERED_STATIC_ASSERT_CONST_INVOCABLE(F)
table_.visit_all(p, f);
}
template <class ExecPolicy, class F>
typename std::enable_if<detail::is_execution_policy<ExecPolicy>::value,
void>::type
cvisit_all(ExecPolicy p, F f) const
{
BOOST_UNORDERED_STATIC_ASSERT_CONST_INVOCABLE(F)
table_.cvisit_all(p, f);
}
#endif
/// Modifiers /// Modifiers
/// ///

View File

@ -16,32 +16,24 @@ namespace {
struct lvalue_visitor_type struct lvalue_visitor_type
{ {
template <class T, class X> template <class T, class X, class M>
void operator()(std::vector<T>& values, X& x, test::random_generator rg) void operator()(std::vector<T>& values, X& x, M const& reference_map)
{ {
using value_type = typename X::value_type; using value_type = typename X::value_type;
std::atomic<std::uint64_t> num_visits{0}; std::atomic<std::uint64_t> num_visits{0};
std::atomic<std::uint64_t> total_count{0}; std::atomic<std::uint64_t> total_count{0};
auto mut_visitor = [&num_visits, rg](int r, int r2) { auto mut_visitor = [&num_visits, &reference_map](value_type& v) {
return [&num_visits, r, r2, rg](value_type& v) { BOOST_TEST(reference_map.contains(v.first));
BOOST_TEST_EQ(v.first.x_, r); BOOST_TEST_EQ(v.second, reference_map.find(v.first)->second);
if (rg == test::sequential) { ++num_visits;
BOOST_TEST_EQ(v.second.x_, r2);
}
++num_visits;
};
}; };
auto const_visitor = [&num_visits, rg](int r, int r2) { auto const_visitor = [&num_visits, &reference_map](value_type const& v) {
return [&num_visits, r, r2, rg](value_type const& v) { BOOST_TEST(reference_map.contains(v.first));
BOOST_TEST_EQ(v.first.x_, r); BOOST_TEST_EQ(v.second, reference_map.find(v.first)->second);
if (rg == test::sequential) { ++num_visits;
BOOST_TEST_EQ(v.second.x_, r2);
}
++num_visits;
};
}; };
{ {
@ -50,14 +42,12 @@ namespace {
for (auto const& val : s) { for (auto const& val : s) {
auto r = val.first.x_; auto r = val.first.x_;
BOOST_ASSERT(r >= 0); BOOST_ASSERT(r >= 0);
auto r2 = val.second.x_;
auto count = x.visit(val.first, mut_visitor(r, r2));
auto count = x.visit(val.first, mut_visitor);
BOOST_TEST_EQ(count, 1u); BOOST_TEST_EQ(count, 1u);
total_count += count; total_count += count;
count = x.visit(val.second, mut_visitor(r, r2)); count = x.visit(val.second, mut_visitor);
BOOST_TEST_EQ(count, 0u); BOOST_TEST_EQ(count, 0u);
} }
}); });
@ -75,15 +65,14 @@ namespace {
for (auto const& val : s) { for (auto const& val : s) {
auto r = val.first.x_; auto r = val.first.x_;
BOOST_ASSERT(r >= 0); BOOST_ASSERT(r >= 0);
auto r2 = val.second.x_;
auto const& y = x; auto const& y = x;
auto count = y.visit(val.first, const_visitor(r, r2)); auto count = y.visit(val.first, const_visitor);
BOOST_TEST_EQ(count, 1u); BOOST_TEST_EQ(count, 1u);
total_count += count; total_count += count;
count = y.visit(val.second, const_visitor(r, r2)); count = y.visit(val.second, const_visitor);
BOOST_TEST_EQ(count, 0u); BOOST_TEST_EQ(count, 0u);
} }
}); });
@ -101,14 +90,13 @@ namespace {
for (auto const& val : s) { for (auto const& val : s) {
auto r = val.first.x_; auto r = val.first.x_;
BOOST_ASSERT(r >= 0); BOOST_ASSERT(r >= 0);
auto r2 = val.second.x_;
auto count = x.cvisit(val.first, const_visitor(r, r2)); auto count = x.cvisit(val.first, const_visitor);
BOOST_TEST_EQ(count, 1u); BOOST_TEST_EQ(count, 1u);
total_count += count; total_count += count;
count = x.cvisit(val.second, const_visitor(r, r2)); count = x.cvisit(val.second, const_visitor);
BOOST_TEST_EQ(count, 0u); BOOST_TEST_EQ(count, 0u);
} }
}); });
@ -124,32 +112,24 @@ namespace {
struct transp_visitor_type struct transp_visitor_type
{ {
template <class T, class X> template <class T, class X, class M>
void operator()(std::vector<T>& values, X& x, test::random_generator rg) void operator()(std::vector<T>& values, X& x, M const& reference_map)
{ {
using value_type = typename X::value_type; using value_type = typename X::value_type;
std::atomic<std::uint64_t> num_visits{0}; std::atomic<std::uint64_t> num_visits{0};
std::atomic<std::uint64_t> total_count{0}; std::atomic<std::uint64_t> total_count{0};
auto mut_visitor = [&num_visits, rg](int r, int r2) { auto mut_visitor = [&num_visits, &reference_map](value_type& v) {
return [&num_visits, r, r2, rg](value_type& v) { BOOST_TEST(reference_map.contains(v.first));
BOOST_TEST_EQ(v.first.x_, r); BOOST_TEST_EQ(v.second, reference_map.find(v.first)->second);
if (rg == test::sequential) { ++num_visits;
BOOST_TEST_EQ(v.second.x_, r2);
}
++num_visits;
};
}; };
auto const_visitor = [&num_visits, rg](int r, int r2) { auto const_visitor = [&num_visits, &reference_map](value_type const& v) {
return [&num_visits, r, r2, rg](value_type const& v) { BOOST_TEST(reference_map.contains(v.first));
BOOST_TEST_EQ(v.first.x_, r); BOOST_TEST_EQ(v.second, reference_map.find(v.first)->second);
if (rg == test::sequential) { ++num_visits;
BOOST_TEST_EQ(v.second.x_, r2);
}
++num_visits;
};
}; };
{ {
@ -158,14 +138,13 @@ namespace {
for (auto const& val : s) { for (auto const& val : s) {
auto r = val.first.x_; auto r = val.first.x_;
BOOST_ASSERT(r >= 0); BOOST_ASSERT(r >= 0);
auto r2 = val.second.x_;
auto count = x.visit(val.first.x_, mut_visitor(r, r2)); auto count = x.visit(val.first.x_, mut_visitor);
BOOST_TEST_EQ(count, 1u); BOOST_TEST_EQ(count, 1u);
total_count += count; total_count += count;
count = x.visit(val.second.x_, mut_visitor(r, r2)); count = x.visit(val.second.x_, mut_visitor);
BOOST_TEST_EQ(count, 0u); BOOST_TEST_EQ(count, 0u);
} }
}); });
@ -183,15 +162,14 @@ namespace {
for (auto const& val : s) { for (auto const& val : s) {
auto r = val.first.x_; auto r = val.first.x_;
BOOST_ASSERT(r >= 0); BOOST_ASSERT(r >= 0);
auto r2 = val.second.x_;
auto const& y = x; auto const& y = x;
auto count = y.visit(val.first.x_, const_visitor(r, r2)); auto count = y.visit(val.first.x_, const_visitor);
BOOST_TEST_EQ(count, 1u); BOOST_TEST_EQ(count, 1u);
total_count += count; total_count += count;
count = y.visit(val.second.x_, const_visitor(r, r2)); count = y.visit(val.second.x_, const_visitor);
BOOST_TEST_EQ(count, 0u); BOOST_TEST_EQ(count, 0u);
} }
}); });
@ -209,14 +187,13 @@ namespace {
for (auto const& val : s) { for (auto const& val : s) {
auto r = val.first.x_; auto r = val.first.x_;
BOOST_ASSERT(r >= 0); BOOST_ASSERT(r >= 0);
auto r2 = val.second.x_;
auto count = x.cvisit(val.first.x_, const_visitor(r, r2)); auto count = x.cvisit(val.first.x_, const_visitor);
BOOST_TEST_EQ(count, 1u); BOOST_TEST_EQ(count, 1u);
total_count += count; total_count += count;
count = x.cvisit(val.second.x_, const_visitor(r, r2)); count = x.cvisit(val.second.x_, const_visitor);
BOOST_TEST_EQ(count, 0u); BOOST_TEST_EQ(count, 0u);
} }
}); });
@ -230,6 +207,128 @@ namespace {
} }
} transp_visitor; } transp_visitor;
struct visit_all_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;
std::atomic<std::uint64_t> total_count{0};
auto mut_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;
};
};
auto const_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;
};
};
{
thread_runner(values, [&x, &total_count, &mut_visitor](boost::span<T>) {
std::atomic<std::uint64_t> num_visits{0};
total_count += x.visit_all(mut_visitor(num_visits));
BOOST_TEST_EQ(x.size(), num_visits);
});
BOOST_TEST_EQ(total_count, num_threads * x.size());
total_count = 0;
}
{
thread_runner(
values, [&x, &total_count, &const_visitor](boost::span<T>) {
std::atomic<std::uint64_t> num_visits{0};
auto const& y = x;
total_count += y.visit_all(const_visitor(num_visits));
BOOST_TEST_EQ(x.size(), num_visits);
});
BOOST_TEST_EQ(total_count, num_threads * x.size());
total_count = 0;
}
{
thread_runner(
values, [&x, &total_count, &const_visitor](boost::span<T>) {
std::atomic<std::uint64_t> num_visits{0};
total_count += x.cvisit_all(const_visitor(num_visits));
BOOST_TEST_EQ(x.size(), num_visits);
});
BOOST_TEST_EQ(total_count, num_threads * x.size());
total_count = 0;
}
}
} visit_all;
struct exec_policy_visit_all_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_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;
};
};
auto const_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;
};
};
{
thread_runner(values, [&x, &mut_visitor](boost::span<T>) {
std::atomic<std::uint64_t> num_visits{0};
x.visit_all(std::execution::par_unseq, mut_visitor(num_visits));
BOOST_TEST_EQ(x.size(), num_visits);
});
}
{
thread_runner(values, [&x, &const_visitor](boost::span<T>) {
std::atomic<std::uint64_t> num_visits{0};
auto const& y = x;
y.visit_all(std::execution::par_unseq, const_visitor(num_visits));
BOOST_TEST_EQ(x.size(), num_visits);
});
}
{
thread_runner(values, [&x, &const_visitor](boost::span<T>) {
std::atomic<std::uint64_t> num_visits{0};
x.cvisit_all(std::execution::par_unseq, const_visitor(num_visits));
BOOST_TEST_EQ(x.size(), num_visits);
});
}
#else
(void)values;
(void)x;
(void)reference_map;
#endif
}
} exec_policy_visit_all;
template <class X, class G, class F> template <class X, class G, class F>
void visit(X*, G gen, F visitor, test::random_generator rg) void visit(X*, G gen, F visitor, test::random_generator rg)
{ {
@ -258,7 +357,7 @@ namespace {
std::uint64_t old_copy_assignment = raii::copy_assignment; std::uint64_t old_copy_assignment = raii::copy_assignment;
std::uint64_t old_move_assignment = raii::move_assignment; std::uint64_t old_move_assignment = raii::move_assignment;
visitor(values, x, rg); visitor(values, x, reference_map);
BOOST_TEST_EQ(old_default_constructor, raii::default_constructor); BOOST_TEST_EQ(old_default_constructor, raii::default_constructor);
BOOST_TEST_EQ(old_copy_constructor, raii::copy_constructor); BOOST_TEST_EQ(old_copy_constructor, raii::copy_constructor);
@ -293,7 +392,7 @@ UNORDERED_TEST(
visit, visit,
((map)) ((map))
((value_type_generator)(init_type_generator)) ((value_type_generator)(init_type_generator))
((lvalue_visitor)) ((lvalue_visitor)(visit_all)(exec_policy_visit_all))
((default_generator)(sequential)(limited_range))) ((default_generator)(sequential)(limited_range)))
UNORDERED_TEST( UNORDERED_TEST(