diff --git a/include/boost/unordered/concurrent_flat_map.hpp b/include/boost/unordered/concurrent_flat_map.hpp index 0e9c0f96..92afca7e 100644 --- a/include/boost/unordered/concurrent_flat_map.hpp +++ b/include/boost/unordered/concurrent_flat_map.hpp @@ -18,6 +18,7 @@ #include #include +#include #include #include #include @@ -25,6 +26,15 @@ #include #include +#define BOOST_UNORDERED_STATIC_ASSERT_INVOCABLE(F) \ + static_assert(boost::callable_traits::is_invocable::value, \ + "The provided Callable must be invocable with `value_type&`"); + +#define BOOST_UNORDERED_STATIC_ASSERT_CONST_INVOCABLE(F) \ + static_assert( \ + boost::callable_traits::is_invocable::value, \ + "The provided Callable must be invocable with `value_type const&`"); + namespace boost { namespace unordered { namespace detail { @@ -182,27 +192,32 @@ namespace boost { template bool insert_or_visit(value_type const& obj, F f) { + BOOST_UNORDERED_STATIC_ASSERT_INVOCABLE(F) return table_.insert_or_visit(obj, f); } template bool insert_or_visit(value_type&& obj, F f) { + BOOST_UNORDERED_STATIC_ASSERT_INVOCABLE(F) return table_.insert_or_visit(std::move(obj), f); } template bool insert_or_visit(init_type const& obj, F f) { + BOOST_UNORDERED_STATIC_ASSERT_INVOCABLE(F) return table_.insert_or_visit(obj, f); } template bool insert_or_visit(init_type&& obj, F f) { + BOOST_UNORDERED_STATIC_ASSERT_INVOCABLE(F) return table_.insert_or_visit(std::move(obj), f); } template void insert_or_visit(InputIterator first, InputIterator last, F f) { + BOOST_UNORDERED_STATIC_ASSERT_INVOCABLE(F) for (; first != last; ++first) { table_.insert_or_visit(*first, f); } @@ -211,6 +226,47 @@ namespace boost { template void insert_or_visit(std::initializer_list ilist, F f) { + BOOST_UNORDERED_STATIC_ASSERT_INVOCABLE(F) + this->insert_or_visit(ilist.begin(), ilist.end(), f); + } + + template bool insert_or_cvisit(value_type const& obj, F f) + { + BOOST_UNORDERED_STATIC_ASSERT_CONST_INVOCABLE(F) + return table_.insert_or_cvisit(obj, f); + } + + template bool insert_or_cvisit(value_type&& obj, F f) + { + BOOST_UNORDERED_STATIC_ASSERT_CONST_INVOCABLE(F) + return table_.insert_or_cvisit(std::move(obj), f); + } + + template bool insert_or_cvisit(init_type const& obj, F f) + { + BOOST_UNORDERED_STATIC_ASSERT_CONST_INVOCABLE(F) + return table_.insert_or_cvisit(obj, f); + } + + template bool insert_or_cvisit(init_type&& obj, F f) + { + BOOST_UNORDERED_STATIC_ASSERT_CONST_INVOCABLE(F) + return table_.insert_or_cvisit(std::move(obj), f); + } + + template + void insert_or_cvisit(InputIterator first, InputIterator last, F f) + { + BOOST_UNORDERED_STATIC_ASSERT_CONST_INVOCABLE(F) + for (; first != last; ++first) { + table_.insert_or_cvisit(*first, f); + } + } + + template + void insert_or_cvisit(std::initializer_list ilist, F f) + { + BOOST_UNORDERED_STATIC_ASSERT_CONST_INVOCABLE(F) this->insert_or_visit(ilist.begin(), ilist.end(), f); } @@ -247,4 +303,7 @@ namespace boost { } // namespace unordered } // namespace boost +#undef BOOST_UNORDERED_STATIC_ASSERT_INVOCABLE +#undef BOOST_UNORDERED_STATIC_ASSERT_CONST_INVOCABLE + #endif // BOOST_UNORDERED_CONCURRENT_FLAT_MAP_HPP \ No newline at end of file diff --git a/test/cfoa/insert_tests.cpp b/test/cfoa/insert_tests.cpp index 8b26a51f..d4dacc11 100644 --- a/test/cfoa/insert_tests.cpp +++ b/test/cfoa/insert_tests.cpp @@ -225,7 +225,7 @@ namespace { } } trans_insert_or_assign_move_assign; - struct lvalue_insert_or_visit_const_visitor_type + struct lvalue_insert_or_cvisit_type { template void operator()(std::vector& values, X& x) { @@ -233,7 +233,7 @@ namespace { std::atomic num_invokes{0}; thread_runner(values, [&x, &num_inserts, &num_invokes](boost::span s) { for (auto& r : s) { - bool b = x.insert_or_visit( + bool b = x.insert_or_cvisit( r, [&num_invokes](typename X::value_type const& v) { (void)v; ++num_invokes; @@ -254,9 +254,9 @@ namespace { BOOST_TEST_GT(raii::move_constructor, 0u); BOOST_TEST_EQ(raii::move_assignment, 0u); } - } lvalue_insert_or_visit_const_visitor; + } lvalue_insert_or_cvisit; - struct lvalue_insert_or_visit_mut_visitor_type + struct lvalue_insert_or_visit_type { template void operator()(std::vector& values, X& x) { @@ -285,9 +285,9 @@ namespace { BOOST_TEST_GT(raii::move_constructor, 0u); BOOST_TEST_EQ(raii::move_assignment, 0u); } - } lvalue_insert_or_visit_mut_visitor; + } lvalue_insert_or_visit; - struct rvalue_insert_or_visit_const_visitor_type + struct rvalue_insert_or_cvisit_type { template void operator()(std::vector& values, X& x) { @@ -295,7 +295,7 @@ namespace { std::atomic num_invokes{0}; thread_runner(values, [&x, &num_inserts, &num_invokes](boost::span s) { for (auto& r : s) { - bool b = x.insert_or_visit( + bool b = x.insert_or_cvisit( std::move(r), [&num_invokes](typename X::value_type const& v) { (void)v; ++num_invokes; @@ -320,9 +320,9 @@ namespace { BOOST_TEST_GE(raii::move_constructor, 2 * x.size()); } } - } rvalue_insert_or_visit_const_visitor; + } rvalue_insert_or_cvisit; - struct rvalue_insert_or_visit_mut_visitor_type + struct rvalue_insert_or_visit_type { template void operator()(std::vector& values, X& x) { @@ -354,9 +354,30 @@ namespace { BOOST_TEST_GE(raii::move_constructor, 2 * x.size()); } } - } rvalue_insert_or_visit_mut_visitor; + } rvalue_insert_or_visit; - struct iterator_range_insert_or_visit_const_visitor_type + struct iterator_range_insert_or_cvisit_type + { + template void operator()(std::vector& values, X& x) + { + std::atomic num_invokes{0}; + thread_runner(values, [&x, &num_invokes](boost::span s) { + x.insert_or_cvisit( + s.begin(), s.end(), [&num_invokes](typename X::value_type const& v) { + (void)v; + ++num_invokes; + }); + }); + + BOOST_TEST_EQ(num_invokes, values.size() - x.size()); + + BOOST_TEST_EQ(raii::default_constructor, 0u); + BOOST_TEST_EQ(raii::copy_constructor, 2 * x.size()); + BOOST_TEST_GT(raii::move_constructor, 0u); + } + } iterator_range_insert_or_cvisit; + + struct iterator_range_insert_or_visit_type { template void operator()(std::vector& values, X& x) { @@ -375,28 +396,7 @@ namespace { BOOST_TEST_EQ(raii::copy_constructor, 2 * x.size()); BOOST_TEST_GT(raii::move_constructor, 0u); } - } iterator_range_insert_or_visit_const_visitor; - - struct iterator_range_insert_or_visit_mut_visitor_type - { - template void operator()(std::vector& values, X& x) - { - std::atomic num_invokes{0}; - thread_runner(values, [&x, &num_invokes](boost::span s) { - x.insert_or_visit( - s.begin(), s.end(), [&num_invokes](typename X::value_type const& v) { - (void)v; - ++num_invokes; - }); - }); - - BOOST_TEST_EQ(num_invokes, values.size() - x.size()); - - BOOST_TEST_EQ(raii::default_constructor, 0u); - BOOST_TEST_EQ(raii::copy_constructor, 2 * x.size()); - BOOST_TEST_GT(raii::move_constructor, 0u); - } - } iterator_range_insert_or_visit_mut_visitor; + } iterator_range_insert_or_visit; template void insert(X*, G gen, F inserter, test::random_generator rg) @@ -507,7 +507,7 @@ namespace { ++num_invokes; }); - x.insert_or_visit( + x.insert_or_cvisit( values, [&num_invokes](typename X::value_type const& v) { (void)v; ++num_invokes; @@ -560,9 +560,9 @@ UNORDERED_TEST( ((value_type_generator)(init_type_generator)) ((lvalue_inserter)(rvalue_inserter)(iterator_range_inserter) (norehash_lvalue_inserter)(norehash_rvalue_inserter) - (lvalue_insert_or_visit_const_visitor)(lvalue_insert_or_visit_mut_visitor) - (rvalue_insert_or_visit_const_visitor)(rvalue_insert_or_visit_mut_visitor) - (iterator_range_insert_or_visit_const_visitor)(iterator_range_insert_or_visit_mut_visitor)) + (lvalue_insert_or_cvisit)(lvalue_insert_or_visit) + (rvalue_insert_or_cvisit)(rvalue_insert_or_visit) + (iterator_range_insert_or_cvisit)(iterator_range_insert_or_visit)) ((default_generator)(sequential)(limited_range))) UNORDERED_TEST(