diff --git a/include/boost/unordered/concurrent_flat_map.hpp b/include/boost/unordered/concurrent_flat_map.hpp index 77445d187..b46a75939 100644 --- a/include/boost/unordered/concurrent_flat_map.hpp +++ b/include/boost/unordered/concurrent_flat_map.hpp @@ -2,6 +2,7 @@ * * Copyright 2023 Christian Mazakas. * Copyright 2023-2024 Joaquin M Lopez Munoz. + * Copyright 2026 Braden Ganetsky * Distributed under the Boost Software License, Version 1.0. * (See accompanying file LICENSE_1_0.txt or copy at * http://www.boost.org/LICENSE_1_0.txt) @@ -189,11 +190,30 @@ namespace boost { { } + template >::value, + int>::type = 0> + concurrent_flat_map(U&& other) : table_(std::move(other.table_)) + { + } - template - concurrent_flat_map( - unordered_flat_map&& other) - : table_(std::move(other.table_)) + template >::value + // but we do match anything convertible to `unordered_flat_map`. + && std::is_convertible >::value, + int>::type = 0> + concurrent_flat_map(U&& other) + : concurrent_flat_map( + unordered_flat_map( + std::forward(other))) { } diff --git a/include/boost/unordered/concurrent_flat_set.hpp b/include/boost/unordered/concurrent_flat_set.hpp index f0f44308e..514b90e10 100644 --- a/include/boost/unordered/concurrent_flat_set.hpp +++ b/include/boost/unordered/concurrent_flat_set.hpp @@ -2,6 +2,7 @@ * * Copyright 2023 Christian Mazakas. * Copyright 2023-2024 Joaquin M Lopez Munoz. + * Copyright 2026 Braden Ganetsky * Distributed under the Boost Software License, Version 1.0. * (See accompanying file LICENSE_1_0.txt or copy at * http://www.boost.org/LICENSE_1_0.txt) @@ -186,11 +187,29 @@ namespace boost { { } + template >::value, + int>::type = 0> + concurrent_flat_set(U&& other) : table_(std::move(other.table_)) + { + } - template - concurrent_flat_set( - unordered_flat_set&& other) - : table_(std::move(other.table_)) + template >::value + // but we do match anything convertible to `unordered_flat_set`. + && std::is_convertible >::value, + int>::type = 0> + concurrent_flat_set(U&& other) + : concurrent_flat_set(unordered_flat_set( + std::forward(other))) { } diff --git a/include/boost/unordered/concurrent_node_map.hpp b/include/boost/unordered/concurrent_node_map.hpp index 1b6f1623a..5ea7f24a8 100644 --- a/include/boost/unordered/concurrent_node_map.hpp +++ b/include/boost/unordered/concurrent_node_map.hpp @@ -2,6 +2,7 @@ * * Copyright 2023 Christian Mazakas. * Copyright 2023-2024 Joaquin M Lopez Munoz. + * Copyright 2026 Braden Ganetsky * Distributed under the Boost Software License, Version 1.0. * (See accompanying file LICENSE_1_0.txt or copy at * http://www.boost.org/LICENSE_1_0.txt) @@ -197,10 +198,30 @@ namespace boost { { } - template - concurrent_node_map( - unordered_node_map&& other) - : table_(std::move(other.table_)) + template >::value, + int>::type = 0> + concurrent_node_map(U&& other) : table_(std::move(other.table_)) + { + } + + template >::value + // but we do match anything convertible to `unordered_node_map`. + && std::is_convertible >::value, + int>::type = 0> + concurrent_node_map(U&& other) + : concurrent_node_map( + unordered_node_map( + std::forward(other))) { } diff --git a/include/boost/unordered/concurrent_node_set.hpp b/include/boost/unordered/concurrent_node_set.hpp index 430bc0798..bb8865d0d 100644 --- a/include/boost/unordered/concurrent_node_set.hpp +++ b/include/boost/unordered/concurrent_node_set.hpp @@ -2,6 +2,7 @@ * * Copyright 2023 Christian Mazakas. * Copyright 2023-2024 Joaquin M Lopez Munoz. + * Copyright 2026 Braden Ganetsky * Distributed under the Boost Software License, Version 1.0. * (See accompanying file LICENSE_1_0.txt or copy at * http://www.boost.org/LICENSE_1_0.txt) @@ -194,10 +195,29 @@ namespace boost { { } - template - concurrent_node_set( - unordered_node_set&& other) - : table_(std::move(other.table_)) + template >::value, + int>::type = 0> + concurrent_node_set(U&& other) : table_(std::move(other.table_)) + { + } + + template >::value + // but we do match anything convertible to `unordered_node_set`. + && std::is_convertible >::value, + int>::type = 0> + concurrent_node_set(U&& other) + : concurrent_node_set(unordered_node_set( + std::forward(other))) { } diff --git a/include/boost/unordered/unordered_flat_map.hpp b/include/boost/unordered/unordered_flat_map.hpp index 56ec1261e..fcd33fe5e 100644 --- a/include/boost/unordered/unordered_flat_map.hpp +++ b/include/boost/unordered/unordered_flat_map.hpp @@ -1,5 +1,6 @@ // Copyright (C) 2022-2023 Christian Mazakas // Copyright (C) 2024-2025 Joaquin M Lopez Munoz +// Copyright (C) 2026 Braden Ganetsky // Distributed under the Boost Software License, Version 1.0. (See accompanying // file LICENSE_1_0.txt or copy at http://www.boost.org/LICENSE_1_0.txt) @@ -182,10 +183,30 @@ namespace boost { { } - template - unordered_flat_map( - concurrent_flat_map&& other) - : table_(std::move(other.table_)) + template >::value, + int>::type = 0> + unordered_flat_map(U&& other) : table_(std::move(other.table_)) + { + } + + template >::value + // but we do match anything convertible to `concurrent_flat_map`. + && std::is_convertible >::value, + int>::type = 0> + unordered_flat_map(U&& other) + : unordered_flat_map( + concurrent_flat_map( + std::forward(other))) { } diff --git a/include/boost/unordered/unordered_flat_set.hpp b/include/boost/unordered/unordered_flat_set.hpp index b06a0d773..024edf16a 100644 --- a/include/boost/unordered/unordered_flat_set.hpp +++ b/include/boost/unordered/unordered_flat_set.hpp @@ -1,5 +1,6 @@ // Copyright (C) 2022-2023 Christian Mazakas // Copyright (C) 2024-2025 Joaquin M Lopez Munoz +// Copyright (C) 2026 Braden Ganetsky // Distributed under the Boost Software License, Version 1.0. (See accompanying // file LICENSE_1_0.txt or copy at http://www.boost.org/LICENSE_1_0.txt) @@ -178,10 +179,30 @@ namespace boost { { } - template - unordered_flat_set( - concurrent_flat_set&& other) - : table_(std::move(other.table_)) + template >::value, + int>::type = 0> + unordered_flat_set(U&& other) : table_(std::move(other.table_)) + { + } + + template >::value + // but we do match anything convertible to `concurrent_flat_set`. + && std::is_convertible >::value, + int>::type = 0> + unordered_flat_set(U&& other) + : unordered_flat_set( + concurrent_flat_set( + std::forward(other))) { } diff --git a/include/boost/unordered/unordered_node_map.hpp b/include/boost/unordered/unordered_node_map.hpp index a9d7ef449..a02071795 100644 --- a/include/boost/unordered/unordered_node_map.hpp +++ b/include/boost/unordered/unordered_node_map.hpp @@ -1,5 +1,6 @@ // Copyright (C) 2022-2023 Christian Mazakas // Copyright (C) 2024-2025 Joaquin M Lopez Munoz +// Copyright (C) 2026 Braden Ganetsky // Distributed under the Boost Software License, Version 1.0. (See accompanying // file LICENSE_1_0.txt or copy at http://www.boost.org/LICENSE_1_0.txt) @@ -189,10 +190,30 @@ namespace boost { { } - template - unordered_node_map( - concurrent_node_map&& other) - : table_(std::move(other.table_)) + template >::value, + int>::type = 0> + unordered_node_map(U&& other) : table_(std::move(other.table_)) + { + } + + template >::value + // but we do match anything convertible to `concurrent_node_map`. + && std::is_convertible >::value, + int>::type = 0> + unordered_node_map(U&& other) + : unordered_node_map( + concurrent_node_map( + std::forward(other))) { } diff --git a/include/boost/unordered/unordered_node_set.hpp b/include/boost/unordered/unordered_node_set.hpp index 1ac71b414..0335d660b 100644 --- a/include/boost/unordered/unordered_node_set.hpp +++ b/include/boost/unordered/unordered_node_set.hpp @@ -1,5 +1,6 @@ // Copyright (C) 2022-2023 Christian Mazakas // Copyright (C) 2024-2025 Joaquin M Lopez Munoz +// Copyright (C) 2026 Braden Ganetsky // Distributed under the Boost Software License, Version 1.0. (See accompanying // file LICENSE_1_0.txt or copy at http://www.boost.org/LICENSE_1_0.txt) @@ -187,10 +188,30 @@ namespace boost { { } - template - unordered_node_set( - concurrent_node_set&& other) - : table_(std::move(other.table_)) + template >::value, + int>::type = 0> + unordered_node_set(U&& other) : table_(std::move(other.table_)) + { + } + + template >::value + // but we do match anything convertible to `concurrent_node_set`. + && std::is_convertible >::value, + int>::type = 0> + unordered_node_set(U&& other) + : unordered_node_set( + concurrent_node_set( + std::forward(other))) { } diff --git a/test/CMakeLists.txt b/test/CMakeLists.txt index 902faf6e2..81f1e8100 100644 --- a/test/CMakeLists.txt +++ b/test/CMakeLists.txt @@ -163,4 +163,13 @@ cfoa_tests(SOURCES cfoa/rw_spinlock_test6.cpp) cfoa_tests(SOURCES cfoa/rw_spinlock_test7.cpp) cfoa_tests(SOURCES cfoa/rw_spinlock_test8.cpp) +# Compile tests + +fca_tests(TYPE compile NAME explicit_instantiation_tests SOURCES unordered/explicit_instantiation_tests.cpp) +foa_tests(TYPE compile NAME explicit_instantiation_tests SOURCES unordered/explicit_instantiation_tests.cpp) +cfoa_tests(TYPE compile NAME explicit_instantiation_tests SOURCES cfoa/explicit_instantiation_tests.cpp) + +foa_tests(TYPE compile NAME conversion_operator_tests SOURCES unordered/conversion_operator_tests.cpp) +cfoa_tests(TYPE compile NAME conversion_operator_tests SOURCES cfoa/conversion_operator_tests.cpp) + endif() diff --git a/test/Jamfile.v2 b/test/Jamfile.v2 index 38ee478c3..8db539e63 100644 --- a/test/Jamfile.v2 +++ b/test/Jamfile.v2 @@ -169,6 +169,9 @@ compile unordered/explicit_instantiation_tests.cpp : compile unordered/explicit_instantiation_tests.cpp : BOOST_UNORDERED_FOA_TESTS : foa_explicit_instantiation_tests ; compile cfoa/explicit_instantiation_tests.cpp : : cfoa_explicit_instantiation_tests ; +compile unordered/conversion_operator_tests.cpp : BOOST_UNORDERED_FOA_TESTS : foa_conversion_operator_tests ; +compile cfoa/conversion_operator_tests.cpp : : cfoa_conversion_operator_tests ; + local FCA_EXCEPTION_TESTS = constructor_exception_tests copy_exception_tests diff --git a/test/cfoa/conversion_operator_tests.cpp b/test/cfoa/conversion_operator_tests.cpp new file mode 100644 index 000000000..b8a32b79e --- /dev/null +++ b/test/cfoa/conversion_operator_tests.cpp @@ -0,0 +1,65 @@ +// Copyright 2026 Braden Ganetsky +// Distributed under the Boost Software License, Version 1.0. +// https://www.boost.org/LICENSE_1_0.txt + +#include +#include +#include +#include +#include + +using c_flat_map = boost::unordered::concurrent_flat_map; +using c_flat_set = boost::unordered::concurrent_flat_set; +using c_node_map = boost::unordered::concurrent_node_map; +using c_node_set = boost::unordered::concurrent_node_set; + +struct constrained_template_converter +{ + struct dummy + { + }; + template ::value, int>::type = 0> + operator T() const + { + return T{}; + } +}; + +// Check whether the corresponding FOA container gets instantiated +BOOST_STATIC_ASSERT( + (!std::is_constructible::value)); +BOOST_STATIC_ASSERT( + (!std::is_constructible::value)); +BOOST_STATIC_ASSERT( + (!std::is_constructible::value)); +BOOST_STATIC_ASSERT( + (!std::is_constructible::value)); + +#include +#include +#include +#include + +using flat_map = boost::unordered::unordered_flat_map; +using flat_set = boost::unordered::unordered_flat_set; +using node_map = boost::unordered::unordered_node_map; +using node_set = boost::unordered::unordered_node_set; + +template struct container_converter +{ + operator C() const { return {}; } +}; + +// Check whether the container can be constructed with an +// implicit conversion to the corresponding FOA container +BOOST_STATIC_ASSERT( + (std::is_constructible >::value)); +BOOST_STATIC_ASSERT( + (std::is_constructible >::value)); +BOOST_STATIC_ASSERT( + (std::is_constructible >::value)); +BOOST_STATIC_ASSERT( + (std::is_constructible >::value)); + +int main() { return 0; } diff --git a/test/unordered/conversion_operator_tests.cpp b/test/unordered/conversion_operator_tests.cpp new file mode 100644 index 000000000..fa2a56e26 --- /dev/null +++ b/test/unordered/conversion_operator_tests.cpp @@ -0,0 +1,69 @@ +// Copyright 2026 Braden Ganetsky +// Distributed under the Boost Software License, Version 1.0. +// https://www.boost.org/LICENSE_1_0.txt + +#if !defined(BOOST_UNORDERED_FOA_TESTS) +#error "This test is only for the FOA-style conatiners" +#endif + +#include +#include +#include +#include +#include + +using flat_map = boost::unordered::unordered_flat_map; +using flat_set = boost::unordered::unordered_flat_set; +using node_map = boost::unordered::unordered_node_map; +using node_set = boost::unordered::unordered_node_set; + +struct constrained_template_converter +{ + struct dummy + { + }; + template ::value, int>::type = 0> + operator T() const + { + return T{}; + } +}; + +// Check whether the corresponding CFOA container gets instantiated +BOOST_STATIC_ASSERT( + (!std::is_constructible::value)); +BOOST_STATIC_ASSERT( + (!std::is_constructible::value)); +BOOST_STATIC_ASSERT( + (!std::is_constructible::value)); +BOOST_STATIC_ASSERT( + (!std::is_constructible::value)); + +#include +#include +#include +#include + +using c_flat_map = boost::unordered::concurrent_flat_map; +using c_flat_set = boost::unordered::concurrent_flat_set; +using c_node_map = boost::unordered::concurrent_node_map; +using c_node_set = boost::unordered::concurrent_node_set; + +template struct container_converter +{ + operator C() const { return {}; } +}; + +// Check whether the container can be constructed with an +// implicit conversion to the corresponding CFOA container +BOOST_STATIC_ASSERT( + (std::is_constructible >::value)); +BOOST_STATIC_ASSERT( + (std::is_constructible >::value)); +BOOST_STATIC_ASSERT( + (std::is_constructible >::value)); +BOOST_STATIC_ASSERT( + (std::is_constructible >::value)); + +int main() { return 0; }