diff --git a/doc/unordered/changes.adoc b/doc/unordered/changes.adoc index 284e4c81..a7034389 100644 --- a/doc/unordered/changes.adoc +++ b/doc/unordered/changes.adoc @@ -19,6 +19,7 @@ visits the element if insertion did _not_ take place). * Added GDB pretty-printers for all containers and iterators. For a container with an allocator that uses fancy pointers, these only work if the proper pretty-printer is written for the fancy pointer type itself. * Fixed `std::initializer_list` assignment issues for open-addressing containers ({github-pr-url}/277[PR#277^]). +* Allowed non-copyable callables to be passed to the `std::initializer_list` overloads of `insert_{and|or}_[c]visit` for concurrent containers, by internally passing a `std::reference_wrapper` of the callable to the iterator-pair overloads. == Release 1.86.0 diff --git a/doc/unordered/concurrent_flat_map.adoc b/doc/unordered/concurrent_flat_map.adoc index 82f76ff4..8abc740c 100644 --- a/doc/unordered/concurrent_flat_map.adoc +++ b/doc/unordered/concurrent_flat_map.adoc @@ -1148,7 +1148,7 @@ template size_type insert_or_cvisit(std::initializer_list i Equivalent to [listing,subs="+macros,+quotes"] ----- - this->xref:#concurrent_flat_map_insert_iterator_range_or_visit[insert_or_[c\]visit](il.begin(), il.end(), f); + this->xref:#concurrent_flat_map_insert_iterator_range_or_visit[insert_or_[c\]visit](il.begin(), il.end(), std::ref(f)); ----- [horizontal] @@ -1246,15 +1246,15 @@ Returns:;; The number of elements inserted. ==== Insert Initializer List and Visit ```c++ template - size_type insert_or_visit(std::initializer_list il, F1 f1, F2 f2); + size_type insert_and_visit(std::initializer_list il, F1 f1, F2 f2); template - size_type insert_or_cvisit(std::initializer_list il, F1 f1, F2 f2); + size_type insert_and_cvisit(std::initializer_list il, F1 f1, F2 f2); ``` Equivalent to [listing,subs="+macros,+quotes"] ----- - this->xref:#concurrent_flat_map_insert_iterator_range_and_visit[insert_and_[c\]visit](il.begin(), il.end(), f1, f2); + this->xref:#concurrent_flat_map_insert_iterator_range_and_visit[insert_and_[c\]visit](il.begin(), il.end(), std::ref(f1), std::ref(f2)); ----- [horizontal] diff --git a/doc/unordered/concurrent_flat_set.adoc b/doc/unordered/concurrent_flat_set.adoc index c519ec49..3a6ebe70 100644 --- a/doc/unordered/concurrent_flat_set.adoc +++ b/doc/unordered/concurrent_flat_set.adoc @@ -1106,7 +1106,7 @@ template size_type insert_or_cvisit(std::initializer_list i Equivalent to [listing,subs="+macros,+quotes"] ----- - this->xref:#concurrent_flat_set_insert_iterator_range_or_visit[insert_or_[c\]visit](il.begin(), il.end(), f); + this->xref:#concurrent_flat_set_insert_iterator_range_or_visit[insert_or_[c\]visit](il.begin(), il.end(), std::ref(f)); ----- [horizontal] @@ -1222,7 +1222,7 @@ template Equivalent to [listing,subs="+macros,+quotes"] ----- - this->xref:#concurrent_flat_set_insert_iterator_range_and_visit[insert_and_[c\]visit](il.begin(), il.end(), f1, f2); + this->xref:#concurrent_flat_set_insert_iterator_range_and_visit[insert_and_[c\]visit](il.begin(), il.end(), std::ref(f1), std::ref(f2)); ----- [horizontal] diff --git a/doc/unordered/concurrent_node_map.adoc b/doc/unordered/concurrent_node_map.adoc index 46e45864..f6e20dd8 100644 --- a/doc/unordered/concurrent_node_map.adoc +++ b/doc/unordered/concurrent_node_map.adoc @@ -1207,7 +1207,7 @@ template size_type insert_or_cvisit(std::initializer_list i Equivalent to [listing,subs="+macros,+quotes"] ----- - this->xref:#concurrent_node_map_insert_iterator_range_or_visit[insert_or_[c\]visit](il.begin(), il.end(), f); + this->xref:#concurrent_node_map_insert_iterator_range_or_visit[insert_or_[c\]visit](il.begin(), il.end(), std::ref(f)); ----- [horizontal] @@ -1320,15 +1320,15 @@ Returns:;; The number of elements inserted. ==== Insert Initializer List and Visit ```c++ template - size_type insert_or_visit(std::initializer_list il, F1 f1, F2 f2); + size_type insert_and_visit(std::initializer_list il, F1 f1, F2 f2); template - size_type insert_or_cvisit(std::initializer_list il, F1 f1, F2 f2); + size_type insert_and_cvisit(std::initializer_list il, F1 f1, F2 f2); ``` Equivalent to [listing,subs="+macros,+quotes"] ----- - this->xref:#concurrent_node_map_insert_iterator_range_and_visit[insert_and_[c\]visit](il.begin(), il.end(), f1, f2); + this->xref:#concurrent_node_map_insert_iterator_range_and_visit[insert_and_[c\]visit](il.begin(), il.end(), std::ref(f1), std::ref(f2)); ----- [horizontal] diff --git a/doc/unordered/concurrent_node_set.adoc b/doc/unordered/concurrent_node_set.adoc index 2371954a..9757a680 100644 --- a/doc/unordered/concurrent_node_set.adoc +++ b/doc/unordered/concurrent_node_set.adoc @@ -1164,7 +1164,7 @@ template size_type insert_or_cvisit(std::initializer_list i Equivalent to [listing,subs="+macros,+quotes"] ----- - this->xref:#concurrent_node_set_insert_iterator_range_or_visit[insert_or_[c\]visit](il.begin(), il.end(), f); + this->xref:#concurrent_node_set_insert_iterator_range_or_visit[insert_or_[c\]visit](il.begin(), il.end(), std::ref(f)); ----- [horizontal] @@ -1295,7 +1295,7 @@ template Equivalent to [listing,subs="+macros,+quotes"] ----- - this->xref:#concurrent_node_set_insert_iterator_range_and_visit[insert_and_[c\]visit](il.begin(), il.end(), f1, f2); + this->xref:#concurrent_node_set_insert_iterator_range_and_visit[insert_and_[c\]visit](il.begin(), il.end(), std::ref(f1), std::ref(f2)); ----- [horizontal] diff --git a/include/boost/unordered/concurrent_flat_map.hpp b/include/boost/unordered/concurrent_flat_map.hpp index f957b0a5..c0b5f4ff 100644 --- a/include/boost/unordered/concurrent_flat_map.hpp +++ b/include/boost/unordered/concurrent_flat_map.hpp @@ -487,7 +487,7 @@ namespace boost { size_type insert_or_visit(std::initializer_list ilist, F f) { BOOST_UNORDERED_STATIC_ASSERT_INVOCABLE(F) - return this->insert_or_visit(ilist.begin(), ilist.end(), f); + return this->insert_or_visit(ilist.begin(), ilist.end(), std::ref(f)); } template @@ -520,7 +520,7 @@ namespace boost { size_type insert_or_cvisit(std::initializer_list ilist, F f) { BOOST_UNORDERED_STATIC_ASSERT_CONST_INVOCABLE(F) - return this->insert_or_cvisit(ilist.begin(), ilist.end(), f); + return this->insert_or_cvisit(ilist.begin(), ilist.end(), std::ref(f)); } template @@ -559,7 +559,8 @@ namespace boost { { BOOST_UNORDERED_STATIC_ASSERT_INVOCABLE(F1) BOOST_UNORDERED_STATIC_ASSERT_INVOCABLE(F2) - return this->insert_and_visit(ilist.begin(), ilist.end(), f1, f2); + return this->insert_and_visit( + ilist.begin(), ilist.end(), std::ref(f1), std::ref(f2)); } template @@ -598,7 +599,8 @@ namespace boost { { BOOST_UNORDERED_STATIC_ASSERT_INVOCABLE(F1) BOOST_UNORDERED_STATIC_ASSERT_CONST_INVOCABLE(F2) - return this->insert_and_cvisit(ilist.begin(), ilist.end(), f1, f2); + return this->insert_and_cvisit( + ilist.begin(), ilist.end(), std::ref(f1), std::ref(f2)); } template BOOST_FORCEINLINE bool emplace(Args&&... args) diff --git a/include/boost/unordered/concurrent_flat_set.hpp b/include/boost/unordered/concurrent_flat_set.hpp index 9aa2c8cc..bf1fbfe4 100644 --- a/include/boost/unordered/concurrent_flat_set.hpp +++ b/include/boost/unordered/concurrent_flat_set.hpp @@ -478,7 +478,7 @@ namespace boost { size_type insert_or_visit(std::initializer_list ilist, F f) { BOOST_UNORDERED_STATIC_ASSERT_CONST_INVOCABLE(F) - return this->insert_or_visit(ilist.begin(), ilist.end(), f); + return this->insert_or_visit(ilist.begin(), ilist.end(), std::ref(f)); } template @@ -520,7 +520,7 @@ namespace boost { size_type insert_or_cvisit(std::initializer_list ilist, F f) { BOOST_UNORDERED_STATIC_ASSERT_CONST_INVOCABLE(F) - return this->insert_or_cvisit(ilist.begin(), ilist.end(), f); + return this->insert_or_cvisit(ilist.begin(), ilist.end(), std::ref(f)); } template @@ -569,7 +569,8 @@ namespace boost { { BOOST_UNORDERED_STATIC_ASSERT_CONST_INVOCABLE(F1) BOOST_UNORDERED_STATIC_ASSERT_CONST_INVOCABLE(F2) - return this->insert_and_visit(ilist.begin(), ilist.end(), f1, f2); + return this->insert_and_visit( + ilist.begin(), ilist.end(), std::ref(f1), std::ref(f2)); } template @@ -619,7 +620,8 @@ namespace boost { { BOOST_UNORDERED_STATIC_ASSERT_CONST_INVOCABLE(F1) BOOST_UNORDERED_STATIC_ASSERT_CONST_INVOCABLE(F2) - return this->insert_and_cvisit(ilist.begin(), ilist.end(), f1, f2); + return this->insert_and_cvisit( + ilist.begin(), ilist.end(), std::ref(f1), std::ref(f2)); } template BOOST_FORCEINLINE bool emplace(Args&&... args) diff --git a/include/boost/unordered/concurrent_node_map.hpp b/include/boost/unordered/concurrent_node_map.hpp index 0b3eb2d9..899b1d3a 100644 --- a/include/boost/unordered/concurrent_node_map.hpp +++ b/include/boost/unordered/concurrent_node_map.hpp @@ -513,7 +513,7 @@ namespace boost { size_type insert_or_visit(std::initializer_list ilist, F f) { BOOST_UNORDERED_STATIC_ASSERT_INVOCABLE(F) - return this->insert_or_visit(ilist.begin(), ilist.end(), f); + return this->insert_or_visit(ilist.begin(), ilist.end(), std::ref(f)); } template @@ -567,7 +567,7 @@ namespace boost { size_type insert_or_cvisit(std::initializer_list ilist, F f) { BOOST_UNORDERED_STATIC_ASSERT_CONST_INVOCABLE(F) - return this->insert_or_cvisit(ilist.begin(), ilist.end(), f); + return this->insert_or_cvisit(ilist.begin(), ilist.end(), std::ref(f)); } template @@ -627,7 +627,8 @@ namespace boost { { BOOST_UNORDERED_STATIC_ASSERT_INVOCABLE(F1) BOOST_UNORDERED_STATIC_ASSERT_INVOCABLE(F2) - return this->insert_and_visit(ilist.begin(), ilist.end(), f1, f2); + return this->insert_and_visit( + ilist.begin(), ilist.end(), std::ref(f1), std::ref(f2)); } template @@ -688,7 +689,8 @@ namespace boost { { BOOST_UNORDERED_STATIC_ASSERT_INVOCABLE(F1) BOOST_UNORDERED_STATIC_ASSERT_CONST_INVOCABLE(F2) - return this->insert_and_cvisit(ilist.begin(), ilist.end(), f1, f2); + return this->insert_and_cvisit( + ilist.begin(), ilist.end(), std::ref(f1), std::ref(f2)); } template diff --git a/include/boost/unordered/concurrent_node_set.hpp b/include/boost/unordered/concurrent_node_set.hpp index cea51919..249f7fcd 100644 --- a/include/boost/unordered/concurrent_node_set.hpp +++ b/include/boost/unordered/concurrent_node_set.hpp @@ -504,7 +504,7 @@ namespace boost { size_type insert_or_visit(std::initializer_list ilist, F f) { BOOST_UNORDERED_STATIC_ASSERT_CONST_INVOCABLE(F) - return this->insert_or_visit(ilist.begin(), ilist.end(), f); + return this->insert_or_visit(ilist.begin(), ilist.end(), std::ref(f)); } template @@ -567,7 +567,7 @@ namespace boost { size_type insert_or_cvisit(std::initializer_list ilist, F f) { BOOST_UNORDERED_STATIC_ASSERT_CONST_INVOCABLE(F) - return this->insert_or_cvisit(ilist.begin(), ilist.end(), f); + return this->insert_or_cvisit(ilist.begin(), ilist.end(), std::ref(f)); } template @@ -638,7 +638,8 @@ namespace boost { { BOOST_UNORDERED_STATIC_ASSERT_CONST_INVOCABLE(F1) BOOST_UNORDERED_STATIC_ASSERT_CONST_INVOCABLE(F2) - return this->insert_and_visit(ilist.begin(), ilist.end(), f1, f2); + return this->insert_and_visit( + ilist.begin(), ilist.end(), std::ref(f1), std::ref(f2)); } template @@ -710,7 +711,8 @@ namespace boost { { BOOST_UNORDERED_STATIC_ASSERT_CONST_INVOCABLE(F1) BOOST_UNORDERED_STATIC_ASSERT_CONST_INVOCABLE(F2) - return this->insert_and_cvisit(ilist.begin(), ilist.end(), f1, f2); + return this->insert_and_cvisit( + ilist.begin(), ilist.end(), std::ref(f1), std::ref(f2)); } template diff --git a/include/boost/unordered/detail/concurrent_static_asserts.hpp b/include/boost/unordered/detail/concurrent_static_asserts.hpp index bc76c5b0..09b050bf 100644 --- a/include/boost/unordered/detail/concurrent_static_asserts.hpp +++ b/include/boost/unordered/detail/concurrent_static_asserts.hpp @@ -13,10 +13,7 @@ #include #include #include - -#include -#include -#include +#include #define BOOST_UNORDERED_STATIC_ASSERT_INVOCABLE(F) \ static_assert(boost::unordered::detail::is_invocable::value, \ @@ -79,13 +76,20 @@ namespace boost { namespace unordered { namespace detail { - template - struct is_invocable - : std::is_constructible, - std::reference_wrapper::type> > + template struct is_invocable_helper : std::false_type { }; + template + struct is_invocable_helper< + void_t()(std::declval()...))>, F, + Args...> : std::true_type + { + }; + + template + using is_invocable = is_invocable_helper; + } // namespace detail } // namespace unordered diff --git a/test/cfoa/insert_tests.cpp b/test/cfoa/insert_tests.cpp index cc451a2d..114234af 100644 --- a/test/cfoa/insert_tests.cpp +++ b/test/cfoa/insert_tests.cpp @@ -947,6 +947,14 @@ namespace { } } iterator_range_insert_and_visit; + struct non_copyable_function + { + non_copyable_function() = default; + non_copyable_function(const non_copyable_function&) = delete; + non_copyable_function(non_copyable_function&&) = default; + template void operator()(Args&&...) const {} + }; + template void insert(X*, GF gen_factory, F inserter, test::random_generator rg) { @@ -1047,6 +1055,9 @@ namespace { ++num_invokes; }), init_list.size()); + + x.insert_or_visit(init_list, non_copyable_function{}); + x.insert_or_cvisit(init_list, non_copyable_function{}); }); BOOST_TEST_EQ(num_invokes, (init_list.size() - x.size()) + @@ -1105,6 +1116,11 @@ namespace { ++num_invokes; }), init_list.size()); + + x.insert_and_visit( + init_list, non_copyable_function{}, non_copyable_function{}); + x.insert_and_cvisit( + init_list, non_copyable_function{}, non_copyable_function{}); }); BOOST_TEST_EQ(num_inserts, x.size());