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)
{
BOOST_UNORDERED_STATIC_ASSERT_INVOCABLE(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
///

View File

@ -16,32 +16,24 @@ namespace {
struct lvalue_visitor_type
{
template <class T, class X>
void operator()(std::vector<T>& values, X& x, test::random_generator rg)
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> num_visits{0};
std::atomic<std::uint64_t> total_count{0};
auto mut_visitor = [&num_visits, rg](int r, int r2) {
return [&num_visits, r, r2, rg](value_type& v) {
BOOST_TEST_EQ(v.first.x_, r);
if (rg == test::sequential) {
BOOST_TEST_EQ(v.second.x_, r2);
}
++num_visits;
};
auto mut_visitor = [&num_visits, &reference_map](value_type& v) {
BOOST_TEST(reference_map.contains(v.first));
BOOST_TEST_EQ(v.second, reference_map.find(v.first)->second);
++num_visits;
};
auto const_visitor = [&num_visits, rg](int r, int r2) {
return [&num_visits, r, r2, rg](value_type const& v) {
BOOST_TEST_EQ(v.first.x_, r);
if (rg == test::sequential) {
BOOST_TEST_EQ(v.second.x_, r2);
}
++num_visits;
};
auto const_visitor = [&num_visits, &reference_map](value_type const& v) {
BOOST_TEST(reference_map.contains(v.first));
BOOST_TEST_EQ(v.second, reference_map.find(v.first)->second);
++num_visits;
};
{
@ -50,14 +42,12 @@ namespace {
for (auto const& val : s) {
auto r = val.first.x_;
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);
total_count += count;
count = x.visit(val.second, mut_visitor(r, r2));
count = x.visit(val.second, mut_visitor);
BOOST_TEST_EQ(count, 0u);
}
});
@ -75,15 +65,14 @@ namespace {
for (auto const& val : s) {
auto r = val.first.x_;
BOOST_ASSERT(r >= 0);
auto r2 = val.second.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);
total_count += count;
count = y.visit(val.second, const_visitor(r, r2));
count = y.visit(val.second, const_visitor);
BOOST_TEST_EQ(count, 0u);
}
});
@ -101,14 +90,13 @@ namespace {
for (auto const& val : s) {
auto r = val.first.x_;
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);
total_count += count;
count = x.cvisit(val.second, const_visitor(r, r2));
count = x.cvisit(val.second, const_visitor);
BOOST_TEST_EQ(count, 0u);
}
});
@ -124,32 +112,24 @@ namespace {
struct transp_visitor_type
{
template <class T, class X>
void operator()(std::vector<T>& values, X& x, test::random_generator rg)
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> num_visits{0};
std::atomic<std::uint64_t> total_count{0};
auto mut_visitor = [&num_visits, rg](int r, int r2) {
return [&num_visits, r, r2, rg](value_type& v) {
BOOST_TEST_EQ(v.first.x_, r);
if (rg == test::sequential) {
BOOST_TEST_EQ(v.second.x_, r2);
}
++num_visits;
};
auto mut_visitor = [&num_visits, &reference_map](value_type& v) {
BOOST_TEST(reference_map.contains(v.first));
BOOST_TEST_EQ(v.second, reference_map.find(v.first)->second);
++num_visits;
};
auto const_visitor = [&num_visits, rg](int r, int r2) {
return [&num_visits, r, r2, rg](value_type const& v) {
BOOST_TEST_EQ(v.first.x_, r);
if (rg == test::sequential) {
BOOST_TEST_EQ(v.second.x_, r2);
}
++num_visits;
};
auto const_visitor = [&num_visits, &reference_map](value_type const& v) {
BOOST_TEST(reference_map.contains(v.first));
BOOST_TEST_EQ(v.second, reference_map.find(v.first)->second);
++num_visits;
};
{
@ -158,14 +138,13 @@ namespace {
for (auto const& val : s) {
auto r = val.first.x_;
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);
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);
}
});
@ -183,15 +162,14 @@ namespace {
for (auto const& val : s) {
auto r = val.first.x_;
BOOST_ASSERT(r >= 0);
auto r2 = val.second.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);
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);
}
});
@ -209,14 +187,13 @@ namespace {
for (auto const& val : s) {
auto r = val.first.x_;
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);
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);
}
});
@ -230,6 +207,128 @@ namespace {
}
} 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>
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_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_copy_constructor, raii::copy_constructor);
@ -293,7 +392,7 @@ UNORDERED_TEST(
visit,
((map))
((value_type_generator)(init_type_generator))
((lvalue_visitor))
((lvalue_visitor)(visit_all)(exec_policy_visit_all))
((default_generator)(sequential)(limited_range)))
UNORDERED_TEST(