1 /* Copyright 2016-2019 Joaquin M Lopez Munoz.
2 * Distributed under the Boost Software License, Version 1.0.
3 * (See accompanying file LICENSE_1_0.txt or copy at
4 * http://www.boost.org/LICENSE_1_0.txt)
6 * See http://www.boost.org/libs/poly_collection for library home page.
9 #include "test_construction.hpp"
12 #include <boost/config.hpp>
13 #include <boost/core/lightweight_test.hpp>
14 #include <boost/detail/workaround.hpp>
15 #include <boost/type_erasure/relaxed.hpp>
16 #include <scoped_allocator>
19 #include "any_types.hpp"
20 #include "base_types.hpp"
21 #include "function_types.hpp"
22 #include "test_utilities.hpp"
24 using namespace test_utilities
;
27 bool Propagate
,bool AlwaysEqual
,
28 typename PolyCollection
,typename ValueFactory
,typename
... Types
30 void test_allocator_aware_construction()
32 using rooted_poly_collection
=realloc_poly_collection
<
33 PolyCollection
,rooted_allocator
,
34 std::integral_constant
<bool,Propagate
>,
35 std::integral_constant
<bool,AlwaysEqual
>>;
36 using allocator_type
=typename
rooted_poly_collection::allocator_type
;
38 allocator_type root1
{0},root2
{0};
39 rooted_poly_collection p
{root1
};
40 const rooted_poly_collection
& cp
=p
;
44 constraints
<is_equality_comparable
,is_copy_constructible
>,
49 rooted_poly_collection p2
{cp
};
51 BOOST_TEST(p2
.get_allocator().comes_from(root1
));
54 rooted_poly_collection p2
{cp
};
55 auto d2
=get_layout_data
<Types
...>(p2
);
56 rooted_poly_collection p3
{std::move(p2
)};
57 auto d3
=get_layout_data
<Types
...>(p3
);
60 BOOST_TEST(p2
.empty());
61 do_((BOOST_TEST(!p2
.template is_registered
<Types
>()),0)...);
62 BOOST_TEST(p2
.get_allocator().comes_from(root1
));
65 rooted_poly_collection p2
{cp
,root2
};
67 BOOST_TEST(p2
.get_allocator().comes_from(root2
));
69 #if BOOST_WORKAROUND(BOOST_MSVC,<=1900)
70 /* std::unordered_map allocator move ctor does not work when source and
71 * and target allocators are not equal.
76 #if BOOST_WORKAROUND(_MSVC_STL_UPDATE,==201811L)
77 /* This particular version of VS2019 has a bug in std::unordered_map
78 * allocator move ctor when source and target allocators are not equal.
79 * After private communication from Billy O'Neal.
85 rooted_poly_collection p2
{cp
};
86 auto d2
=get_layout_data
<Types
...>(p2
);
87 rooted_poly_collection p3
{std::move(p2
),root2
};
88 auto d3
=get_layout_data
<Types
...>(p3
);
92 #if BOOST_WORKAROUND(BOOST_LIBSTDCXX_VERSION,<40900)
93 /* Limitations from libstdc++-v3 force move construction with allocator
94 * to decay to copy construction with allocator.
97 (void)(d2
==d3
); /* Wunused-variable */
99 if(AlwaysEqual
)BOOST_TEST(d2
==d3
);
102 BOOST_TEST(p2
.empty());
103 do_((BOOST_TEST(!p2
.template is_registered
<Types
>()),0)...);
105 #if !defined(BOOST_MSVC)&&\
106 BOOST_WORKAROUND(BOOST_DINKUMWARE_STDLIB,BOOST_TESTED_AT(804))
107 /* Very odd behavior probably due to std::unordered_map allocator move
108 * ctor being implemented with move assignment, as reported in
109 * https://github.com/boostorg/poly_collection/issues/16
112 if(!(Propagate
&&!AlwaysEqual
))
114 BOOST_TEST(p3
.get_allocator().comes_from(root2
));
117 rooted_poly_collection p2
{root2
};
121 #if BOOST_WORKAROUND(BOOST_MSVC,<=1900)
122 /* std::unordered_map copy assignment does not propagate allocators */
126 #if BOOST_WORKAROUND(BOOST_LIBSTDCXX_VERSION,<40900)
127 /* std::unordered_map copy assignment always and only propagates unequal
131 if(!((Propagate
&&AlwaysEqual
)||(!Propagate
&&!AlwaysEqual
)))
133 #if !defined(BOOST_MSVC)&&\
134 BOOST_WORKAROUND(BOOST_DINKUMWARE_STDLIB,BOOST_TESTED_AT(804))
135 /* std::unordered_map copy assignment does not propagate allocators, as
136 * reported in https://github.com/boostorg/poly_collection/issues/16
141 BOOST_TEST(p2
.get_allocator().comes_from(Propagate
?root1
:root2
));
143 #if BOOST_WORKAROUND(BOOST_MSVC,<=1900)
144 /* std::unordered_map move asignment does not propagate allocators */
146 if(!Propagate
&&AlwaysEqual
)
149 rooted_poly_collection p2
{cp
};
150 auto d2
=get_layout_data
<Types
...>(p2
);
151 rooted_poly_collection p3
{root2
};
153 auto d3
=get_layout_data
<Types
...>(p3
);
155 if(Propagate
||AlwaysEqual
){
157 BOOST_TEST(p2
.empty());
158 do_((BOOST_TEST(!p2
.template is_registered
<Types
>()),0)...);
161 #if BOOST_WORKAROUND(BOOST_LIBSTDCXX_VERSION,<40900)
162 /* std::unordered_map move assignment always and only propagates unequal
166 if(!((Propagate
&&AlwaysEqual
)||(!Propagate
&&!AlwaysEqual
)))
168 #if !defined(BOOST_MSVC)&&\
169 BOOST_WORKAROUND(BOOST_DINKUMWARE_STDLIB,BOOST_TESTED_AT(804))
170 /* std::unordered_map move assignment does not propagate equal allocators,
171 * as reported in https://github.com/boostorg/poly_collection/issues/16
174 if(!(Propagate
&&AlwaysEqual
))
176 BOOST_TEST(p3
.get_allocator().comes_from(Propagate
?root1
:root2
));
178 #if BOOST_WORKAROUND(BOOST_MSVC,<=1900)
179 /* std::unordered_map::swap does not correctly swap control information when
180 * swapping allocators, which causes crashes on "Checked Iterators" mode.
183 if(!(Propagate
&&!AlwaysEqual
))
186 constexpr bool use_same_allocator
=!Propagate
&&!AlwaysEqual
;
188 rooted_poly_collection p2
{cp
},
189 p3
{use_same_allocator
?root1
:root2
};
191 auto d2
=get_layout_data
<Types
...>(p2
),
192 d3
=get_layout_data
<Types
...>(p3
);
195 auto e2
=get_layout_data
<Types
...>(p2
),
196 e3
=get_layout_data
<Types
...>(p3
);
199 do_((BOOST_TEST(!p2
.template is_registered
<Types
>()),0)...);
200 if(!use_same_allocator
201 #if BOOST_WORKAROUND(BOOST_MSVC,<=1900)
202 /* std::unordered_map::swap does not swap equal allocators */
204 &&!(Propagate
&&AlwaysEqual
)
206 #if BOOST_WORKAROUND(BOOST_LIBSTDCXX_VERSION,<40900)
207 /* std::unordered_map::swap always and only swaps unequal allocators */
209 &&!((Propagate
&&AlwaysEqual
)||(!Propagate
&&!AlwaysEqual
))
211 #if !defined(BOOST_MSVC)&&\
212 BOOST_WORKAROUND(BOOST_DINKUMWARE_STDLIB,BOOST_TESTED_AT(804))
213 /* std::unordered_map::swap does not swap equal allocators, as reported
214 * in https://github.com/boostorg/poly_collection/issues/16
217 &&!(Propagate
&&AlwaysEqual
)
220 BOOST_TEST(p2
.get_allocator().comes_from(Propagate
?root2
:root1
));
221 BOOST_TEST(p3
.get_allocator().comes_from(Propagate
?root1
:root2
));
226 auto f2
=get_layout_data
<Types
...>(p2
),
227 f3
=get_layout_data
<Types
...>(p3
);
230 do_((BOOST_TEST(!p3
.template is_registered
<Types
>()),0)...);
231 if(!use_same_allocator
){
232 BOOST_TEST(p2
.get_allocator().comes_from(root1
));
233 BOOST_TEST(p3
.get_allocator().comes_from(root2
));
238 template<typename PolyCollection
,typename ValueFactory
,typename
... Types
>
239 void test_construction()
242 constexpr bool propagate
=true,always_equal
=true;
244 test_allocator_aware_construction
<
245 !propagate
,!always_equal
,PolyCollection
,ValueFactory
,Types
...>();
246 test_allocator_aware_construction
<
247 !propagate
, always_equal
,PolyCollection
,ValueFactory
,Types
...>();
248 test_allocator_aware_construction
<
249 propagate
,!always_equal
,PolyCollection
,ValueFactory
,Types
...>();
250 test_allocator_aware_construction
<
251 propagate
, always_equal
,PolyCollection
,ValueFactory
,Types
...>();
256 const PolyCollection
& cp
=p
;
260 constraints
<is_equality_comparable
,is_copy_constructible
>,
265 PolyCollection p2
{cp
.begin(),cp
.end()};
270 constraints
<is_equality_comparable
,is_copy_constructible
>,
273 PolyCollection p2
{cp
.template begin
<type
>(),cp
.template end
<type
>()};
275 p2
.size()==cp
.template size
<type
>()&&
277 p2
.template begin
<type
>(),p2
.template end
<type
>(),
278 cp
.template begin
<type
>()));
283 using not_copy_constructible
=
284 boost::poly_collection::not_copy_constructible
;
287 const PolyCollection
& cp
=p
;
291 constraints
<is_equality_comparable
,is_not_copy_constructible
>,
295 #if BOOST_WORKAROUND(BOOST_LIBSTDCXX_VERSION,<40900)
296 /* std::unordered_map copy construction and assigment crash when elements
297 * throw on copy construction.
301 sizeof(not_copy_constructible
)>0,""); /* Wunused-local-typedefs */
302 (void)cp
; /* Wunused-variable */
304 check_throw
<not_copy_constructible
>([&]{
305 PolyCollection p2
{cp
};
308 check_throw
<not_copy_constructible
>([&]{
315 PolyCollection p2
{std::move(p
)};
316 BOOST_TEST(!p2
.empty());
317 BOOST_TEST(p
.empty());
318 do_((BOOST_TEST(!p
.template is_registered
<Types
>()),0)...);
321 BOOST_TEST(!p
.empty());
322 BOOST_TEST(p2
.empty());
323 do_((BOOST_TEST(!p2
.template is_registered
<Types
>()),0)...);
328 void test_scoped_allocator()
330 #if BOOST_WORKAROUND(BOOST_LIBSTDCXX_VERSION,<50000)&&\
331 BOOST_WORKAROUND(BOOST_LIBSTDCXX_VERSION,>40704)
332 /* std::scoped_allocator_adaptor not assignable, see
333 * https://gcc.gnu.org/bugzilla/show_bug.cgi?id=65279 .
334 * The bug prevents poly_collection below from creating any segment.
337 using vector_allocator
=rooted_allocator
<char>;
338 using vector
=std::vector
<char,vector_allocator
>;
339 using concept_
=boost::type_erasure::relaxed
;
340 using element_allocator
=rooted_allocator
<
341 boost::poly_collection::any_collection_value_type
<concept_
>
343 using collection_allocator
=std::scoped_allocator_adaptor
<
347 using poly_collection
=
348 boost::any_collection
<concept_
,collection_allocator
>;
350 element_allocator roote
{0};
351 vector_allocator rootv
{0};
352 collection_allocator al
{roote
,rootv
};
353 poly_collection p
{al
};
356 auto& s
=*p
.begin
<vector
>();
357 BOOST_TEST(p
.get_allocator().comes_from(roote
));
359 #if BOOST_WORKAROUND(BOOST_MSVC,>=1910)&&BOOST_WORKAROUND(BOOST_MSVC,<1916)
360 /* https://developercommunity.visualstudio.com/content/problem/246251/
364 BOOST_TEST(s
.get_allocator().comes_from(rootv
));
369 void test_construction()
372 any_types::collection
,auto_increment
,
373 any_types::t1
,any_types::t2
,any_types::t3
,
374 any_types::t4
,any_types::t5
>();
376 base_types::collection
,auto_increment
,
377 base_types::t1
,base_types::t2
,base_types::t3
,
378 base_types::t4
,base_types::t5
>();
380 function_types::collection
,auto_increment
,
381 function_types::t1
,function_types::t2
,function_types::t3
,
382 function_types::t4
,function_types::t5
>();
383 test_scoped_allocator();