From c52ad849eacd7c3e087065839f314d8e6cdfc9cd Mon Sep 17 00:00:00 2001 From: Christian Mazakas Date: Mon, 1 May 2023 11:04:50 -0700 Subject: [PATCH] Add policy check that excludes unsequenced policies It's technically UB for the callable in an unsequenced policy to acquire a lock so we add static_assert()s to catch potential user error. --- include/boost/unordered/concurrent_flat_map.hpp | 13 +++++++++++++ test/cfoa/erase_tests.cpp | 2 +- test/cfoa/visit_tests.cpp | 6 +++--- 3 files changed, 17 insertions(+), 4 deletions(-) diff --git a/include/boost/unordered/concurrent_flat_map.hpp b/include/boost/unordered/concurrent_flat_map.hpp index 12778f64..c3cf5aeb 100644 --- a/include/boost/unordered/concurrent_flat_map.hpp +++ b/include/boost/unordered/concurrent_flat_map.hpp @@ -37,6 +37,14 @@ boost::unordered::detail::is_invocable::value, \ "The provided Callable must be invocable with `value_type const&`"); +#define BOOST_UNORDERED_STATIC_ASSERT_EXEC_POLICY(P) \ + static_assert(!std::is_base_of::value, \ + "ExecPolicy must be sequenced."); \ + static_assert( \ + !std::is_base_of::value, \ + "ExecPolicy must be sequenced."); + #define BOOST_UNORDERED_COMMA , #define BOOST_UNORDERED_LAST_ARG(Arg, Args) \ @@ -357,6 +365,7 @@ namespace boost { visit_all(ExecPolicy p, F f) { BOOST_UNORDERED_STATIC_ASSERT_INVOCABLE(F) + BOOST_UNORDERED_STATIC_ASSERT_EXEC_POLICY(ExecPolicy) table_.visit_all(p, f); } @@ -367,6 +376,7 @@ namespace boost { visit_all(ExecPolicy p, F f) const { BOOST_UNORDERED_STATIC_ASSERT_CONST_INVOCABLE(F) + BOOST_UNORDERED_STATIC_ASSERT_EXEC_POLICY(ExecPolicy) table_.visit_all(p, f); } @@ -377,6 +387,7 @@ namespace boost { cvisit_all(ExecPolicy p, F f) const { BOOST_UNORDERED_STATIC_ASSERT_CONST_INVOCABLE(F) + BOOST_UNORDERED_STATIC_ASSERT_EXEC_POLICY(ExecPolicy) table_.cvisit_all(p, f); } #endif @@ -663,6 +674,8 @@ namespace boost { void>::type erase_if(ExecPolicy p, F f) { + BOOST_UNORDERED_STATIC_ASSERT_EXEC_POLICY(ExecPolicy) + BOOST_UNORDERED_STATIC_ASSERT_EXEC_POLICY(ExecPolicy) table_.erase_if(p, f); } #endif diff --git a/test/cfoa/erase_tests.cpp b/test/cfoa/erase_tests.cpp index 2066e07e..3bffb8a2 100644 --- a/test/cfoa/erase_tests.cpp +++ b/test/cfoa/erase_tests.cpp @@ -281,7 +281,7 @@ namespace { thread_runner(values, [&num_invokes, &x, threshold](boost::span s) { (void)s; x.erase_if( - std::execution::par_unseq, [&num_invokes, threshold](value_type& v) { + std::execution::par, [&num_invokes, threshold](value_type& v) { ++num_invokes; return v.second.x_ > threshold; }); diff --git a/test/cfoa/visit_tests.cpp b/test/cfoa/visit_tests.cpp index 4c22782c..d49be2df 100644 --- a/test/cfoa/visit_tests.cpp +++ b/test/cfoa/visit_tests.cpp @@ -299,7 +299,7 @@ namespace { thread_runner(values, [&x, &mut_visitor](boost::span) { std::atomic num_visits{0}; - x.visit_all(std::execution::par_unseq, mut_visitor(num_visits)); + x.visit_all(std::execution::par, mut_visitor(num_visits)); BOOST_TEST_EQ(x.size(), num_visits); }); } @@ -309,7 +309,7 @@ namespace { std::atomic num_visits{0}; auto const& y = x; - y.visit_all(std::execution::par_unseq, const_visitor(num_visits)); + y.visit_all(std::execution::par, const_visitor(num_visits)); BOOST_TEST_EQ(x.size(), num_visits); }); } @@ -317,7 +317,7 @@ namespace { { thread_runner(values, [&x, &const_visitor](boost::span) { std::atomic num_visits{0}; - x.cvisit_all(std::execution::par_unseq, const_visitor(num_visits)); + x.cvisit_all(std::execution::par, const_visitor(num_visits)); BOOST_TEST_EQ(x.size(), num_visits); }); }