diff --git a/include/boost/unordered/concurrent_flat_map.hpp b/include/boost/unordered/concurrent_flat_map.hpp index b9547f8d..2bea917e 100644 --- a/include/boost/unordered/concurrent_flat_map.hpp +++ b/include/boost/unordered/concurrent_flat_map.hpp @@ -185,9 +185,51 @@ namespace boost { template std::size_t visit_all(F f) { + BOOST_UNORDERED_STATIC_ASSERT_INVOCABLE(F) return table_.visit_all(f); } + template std::size_t visit_all(F f) const + { + BOOST_UNORDERED_STATIC_ASSERT_CONST_INVOCABLE(F) + return table_.visit_all(f); + } + + template 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 + typename std::enable_if::value, + void>::type + visit_all(ExecPolicy p, F f) + { + BOOST_UNORDERED_STATIC_ASSERT_INVOCABLE(F) + table_.visit_all(p, f); + } + + template + typename std::enable_if::value, + void>::type + visit_all(ExecPolicy p, F f) const + { + BOOST_UNORDERED_STATIC_ASSERT_CONST_INVOCABLE(F) + table_.visit_all(p, f); + } + + template + typename std::enable_if::value, + void>::type + cvisit_all(ExecPolicy p, F f) const + { + BOOST_UNORDERED_STATIC_ASSERT_CONST_INVOCABLE(F) + table_.cvisit_all(p, f); + } +#endif + /// Modifiers /// diff --git a/test/cfoa/visit_tests.cpp b/test/cfoa/visit_tests.cpp index f02a3ff3..ef526546 100644 --- a/test/cfoa/visit_tests.cpp +++ b/test/cfoa/visit_tests.cpp @@ -16,32 +16,24 @@ namespace { struct lvalue_visitor_type { - template - void operator()(std::vector& values, X& x, test::random_generator rg) + template + void operator()(std::vector& values, X& x, M const& reference_map) { using value_type = typename X::value_type; std::atomic num_visits{0}; std::atomic 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 - void operator()(std::vector& values, X& x, test::random_generator rg) + template + void operator()(std::vector& values, X& x, M const& reference_map) { using value_type = typename X::value_type; std::atomic num_visits{0}; std::atomic 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 + void operator()(std::vector& values, X& x, M const& reference_map) + { + using value_type = typename X::value_type; + + std::atomic total_count{0}; + + auto mut_visitor = [&reference_map](std::atomic& 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& 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) { + std::atomic 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) { + std::atomic 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) { + std::atomic 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 + void operator()(std::vector& 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& 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& 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) { + std::atomic 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) { + std::atomic 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) { + std::atomic 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 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(