Skip to content

Commit 6654807

Browse files
committed
Rewrite the CFOA containers' FOA constructors so that a class with a template conversion operator does not instantiate the FOA container
1 parent 033c866 commit 6654807

7 files changed

Lines changed: 165 additions & 16 deletions

File tree

include/boost/unordered/concurrent_flat_map.hpp

Lines changed: 24 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -2,6 +2,7 @@
22
*
33
* Copyright 2023 Christian Mazakas.
44
* Copyright 2023-2024 Joaquin M Lopez Munoz.
5+
* Copyright 2026 Braden Ganetsky
56
* Distributed under the Boost Software License, Version 1.0.
67
* (See accompanying file LICENSE_1_0.txt or copy at
78
* http://www.boost.org/LICENSE_1_0.txt)
@@ -189,11 +190,30 @@ namespace boost {
189190
{
190191
}
191192

193+
template <class U,
194+
typename std::enable_if<
195+
// Ensure we match exactly `unordered_flat_map&&`.
196+
// Any lvalue references to `unordered_flat_map` are not supported.
197+
std::is_same<U,
198+
unordered_flat_map<Key, T, Hash, KeyEqual, Allocator> >::value,
199+
int>::type = 0>
200+
concurrent_flat_map(U&& other) : table_(std::move(other.table_))
201+
{
202+
}
192203

193-
template <bool avoid_explicit_instantiation = true>
194-
concurrent_flat_map(
195-
unordered_flat_map<Key, T, Hash, Pred, Allocator>&& other)
196-
: table_(std::move(other.table_))
204+
template <class U,
205+
typename std::enable_if<
206+
// Ensure we don't match any cvref-qualified `unordered_flat_map&&`,
207+
!detail::is_similar<U,
208+
unordered_flat_map<Key, T, Hash, KeyEqual, Allocator> >::value
209+
// but we do match anything convertible to `unordered_flat_map`.
210+
&& std::is_convertible<U&&,
211+
unordered_flat_map<Key, T, Hash, KeyEqual, Allocator> >::value,
212+
int>::type = 0>
213+
concurrent_flat_map(U&& other)
214+
: concurrent_flat_map(
215+
unordered_flat_map<Key, T, Hash, KeyEqual, Allocator>(
216+
std::forward<U>(other)))
197217
{
198218
}
199219

include/boost/unordered/concurrent_flat_set.hpp

Lines changed: 24 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -2,6 +2,7 @@
22
*
33
* Copyright 2023 Christian Mazakas.
44
* Copyright 2023-2024 Joaquin M Lopez Munoz.
5+
* Copyright 2026 Braden Ganetsky
56
* Distributed under the Boost Software License, Version 1.0.
67
* (See accompanying file LICENSE_1_0.txt or copy at
78
* http://www.boost.org/LICENSE_1_0.txt)
@@ -186,11 +187,30 @@ namespace boost {
186187
{
187188
}
188189

190+
template <class U,
191+
typename std::enable_if<
192+
// Ensure we match exactly `unordered_flat_set&&`.
193+
// Any lvalue references to `unordered_flat_set` are not supported.
194+
std::is_same<U,
195+
unordered_flat_set<Key, Hash, KeyEqual, Allocator> >::value,
196+
int>::type = 0>
197+
concurrent_flat_set(U&& other) : table_(std::move(other.table_))
198+
{
199+
}
189200

190-
template <bool avoid_explicit_instantiation = true>
191-
concurrent_flat_set(
192-
unordered_flat_set<Key, Hash, Pred, Allocator>&& other)
193-
: table_(std::move(other.table_))
201+
template <class U,
202+
typename std::enable_if<
203+
// Ensure we don't match any cvref-qualified `unordered_flat_set&&`,
204+
!detail::is_similar<U,
205+
unordered_flat_set<Key, Hash, KeyEqual, Allocator> >::value
206+
// but we do match anything convertible to `unordered_flat_set`.
207+
&& std::is_convertible<U&&,
208+
unordered_flat_set<Key, Hash, KeyEqual, Allocator> >::value,
209+
int>::type = 0>
210+
concurrent_flat_set(U&& other)
211+
: concurrent_flat_set(
212+
unordered_flat_set<Key, Hash, KeyEqual, Allocator>(
213+
std::forward<U>(other)))
194214
{
195215
}
196216

include/boost/unordered/concurrent_node_map.hpp

Lines changed: 25 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -2,6 +2,7 @@
22
*
33
* Copyright 2023 Christian Mazakas.
44
* Copyright 2023-2024 Joaquin M Lopez Munoz.
5+
* Copyright 2026 Braden Ganetsky
56
* Distributed under the Boost Software License, Version 1.0.
67
* (See accompanying file LICENSE_1_0.txt or copy at
78
* http://www.boost.org/LICENSE_1_0.txt)
@@ -197,10 +198,30 @@ namespace boost {
197198
{
198199
}
199200

200-
template <bool avoid_explicit_instantiation = true>
201-
concurrent_node_map(
202-
unordered_node_map<Key, T, Hash, Pred, Allocator>&& other)
203-
: table_(std::move(other.table_))
201+
template <class U,
202+
typename std::enable_if<
203+
// Ensure we match exactly `unordered_node_map&&`.
204+
// Any lvalue references to `unordered_node_map` are not supported.
205+
std::is_same<U,
206+
unordered_node_map<Key, T, Hash, KeyEqual, Allocator> >::value,
207+
int>::type = 0>
208+
concurrent_node_map(U&& other) : table_(std::move(other.table_))
209+
{
210+
}
211+
212+
template <class U,
213+
typename std::enable_if<
214+
// Ensure we don't match any cvref-qualified `unordered_node_map&&`,
215+
!detail::is_similar<U,
216+
unordered_node_map<Key, T, Hash, KeyEqual, Allocator> >::value
217+
// but we do match anything convertible to `unordered_node_map`.
218+
&& std::is_convertible<U&&,
219+
unordered_node_map<Key, T, Hash, KeyEqual, Allocator> >::value,
220+
int>::type = 0>
221+
concurrent_node_map(U&& other)
222+
: concurrent_node_map(
223+
unordered_node_map<Key, T, Hash, KeyEqual, Allocator>(
224+
std::forward<U>(other)))
204225
{
205226
}
206227

include/boost/unordered/concurrent_node_set.hpp

Lines changed: 25 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -2,6 +2,7 @@
22
*
33
* Copyright 2023 Christian Mazakas.
44
* Copyright 2023-2024 Joaquin M Lopez Munoz.
5+
* Copyright 2026 Braden Ganetsky
56
* Distributed under the Boost Software License, Version 1.0.
67
* (See accompanying file LICENSE_1_0.txt or copy at
78
* http://www.boost.org/LICENSE_1_0.txt)
@@ -194,10 +195,30 @@ namespace boost {
194195
{
195196
}
196197

197-
template <bool avoid_explicit_instantiation = true>
198-
concurrent_node_set(
199-
unordered_node_set<Key, Hash, Pred, Allocator>&& other)
200-
: table_(std::move(other.table_))
198+
template <class U,
199+
typename std::enable_if<
200+
// Ensure we match exactly `unordered_node_set&&`.
201+
// Any lvalue references to `unordered_node_set` are not supported.
202+
std::is_same<U,
203+
unordered_node_set<Key, Hash, KeyEqual, Allocator> >::value,
204+
int>::type = 0>
205+
concurrent_node_set(U&& other) : table_(std::move(other.table_))
206+
{
207+
}
208+
209+
template <class U,
210+
typename std::enable_if<
211+
// Ensure we don't match any cvref-qualified `unordered_node_set&&`,
212+
!detail::is_similar<U,
213+
unordered_node_set<Key, Hash, KeyEqual, Allocator> >::value
214+
// but we do match anything convertible to `unordered_node_set`.
215+
&& std::is_convertible<U&&,
216+
unordered_node_set<Key, Hash, KeyEqual, Allocator> >::value,
217+
int>::type = 0>
218+
concurrent_node_set(U&& other)
219+
: concurrent_node_set(
220+
unordered_node_set<Key, Hash, KeyEqual, Allocator>(
221+
std::forward<U>(other)))
201222
{
202223
}
203224

test/CMakeLists.txt

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -89,6 +89,7 @@ fca_tests(TYPE compile NAME foa_explicit_instantiation_tests COMPILE_DEFINITIONS
8989
fca_tests(TYPE compile NAME cfoa_explicit_instantiation_tests SOURCES cfoa/explicit_instantiation_tests.cpp)
9090

9191
fca_tests(TYPE compile NAME foa_conversion_operator_tests COMPILE_DEFINITIONS BOOST_UNORDERED_FOA_TESTS SOURCES unordered/conversion_operator_tests.cpp)
92+
fca_tests(TYPE compile NAME cfoa_conversion_operator_tests SOURCES cfoa/conversion_operator_tests.cpp)
9293

9394
# FOA tests
9495

test/Jamfile.v2

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -170,6 +170,7 @@ compile unordered/explicit_instantiation_tests.cpp : <define>BOOST_UNORDERED_FOA
170170
compile cfoa/explicit_instantiation_tests.cpp : : cfoa_explicit_instantiation_tests ;
171171

172172
compile unordered/conversion_operator_tests.cpp : <define>BOOST_UNORDERED_FOA_TESTS : foa_conversion_operator_tests ;
173+
compile cfoa/conversion_operator_tests.cpp : : cfoa_conversion_operator_tests ;
173174

174175
local FCA_EXCEPTION_TESTS =
175176
constructor_exception_tests
Lines changed: 65 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,65 @@
1+
// Copyright 2026 Braden Ganetsky
2+
// Distributed under the Boost Software License, Version 1.0.
3+
// https://www.boost.org/LICENSE_1_0.txt
4+
5+
#include <boost/static_assert.hpp>
6+
#include <boost/unordered/concurrent_flat_map.hpp>
7+
#include <boost/unordered/concurrent_flat_set.hpp>
8+
#include <boost/unordered/concurrent_node_map.hpp>
9+
#include <boost/unordered/concurrent_node_set.hpp>
10+
11+
using c_flat_map = boost::unordered::concurrent_flat_map<int, int>;
12+
using c_flat_set = boost::unordered::concurrent_flat_set<int>;
13+
using c_node_map = boost::unordered::concurrent_node_map<int, int>;
14+
using c_node_set = boost::unordered::concurrent_node_set<int>;
15+
16+
struct constrained_template_converter
17+
{
18+
struct dummy
19+
{
20+
};
21+
template <class T, typename std::enable_if<
22+
std::is_constructible<T, dummy>::value, int>::type = 0>
23+
operator T() const
24+
{
25+
return T{};
26+
}
27+
};
28+
29+
// Check whether the corresponding FOA container gets instantiated
30+
BOOST_STATIC_ASSERT(
31+
(!std::is_constructible<c_flat_map, constrained_template_converter>::value));
32+
BOOST_STATIC_ASSERT(
33+
(!std::is_constructible<c_flat_set, constrained_template_converter>::value));
34+
BOOST_STATIC_ASSERT(
35+
(!std::is_constructible<c_node_map, constrained_template_converter>::value));
36+
BOOST_STATIC_ASSERT(
37+
(!std::is_constructible<c_node_set, constrained_template_converter>::value));
38+
39+
#include <boost/unordered/unordered_flat_map.hpp>
40+
#include <boost/unordered/unordered_flat_set.hpp>
41+
#include <boost/unordered/unordered_node_map.hpp>
42+
#include <boost/unordered/unordered_node_set.hpp>
43+
44+
using flat_map = boost::unordered::unordered_flat_map<int, int>;
45+
using flat_set = boost::unordered::unordered_flat_set<int>;
46+
using node_map = boost::unordered::unordered_node_map<int, int>;
47+
using node_set = boost::unordered::unordered_node_set<int>;
48+
49+
template <class C> struct container_converter
50+
{
51+
operator C() const { return {}; }
52+
};
53+
54+
// Check whether the container can be constructed with an
55+
// implicit conversion to the corresponding FOA container
56+
BOOST_STATIC_ASSERT(
57+
(std::is_constructible<c_flat_map, container_converter<flat_map> >::value));
58+
BOOST_STATIC_ASSERT(
59+
(std::is_constructible<c_flat_set, container_converter<flat_set> >::value));
60+
BOOST_STATIC_ASSERT(
61+
(std::is_constructible<c_node_map, container_converter<node_map> >::value));
62+
BOOST_STATIC_ASSERT(
63+
(std::is_constructible<c_node_set, container_converter<node_set> >::value));
64+
65+
int main() { return 0; }

0 commit comments

Comments
 (0)