]>
Commit | Line | Data |
---|---|---|
92f5a8d4 | 1 | /* Copyright 2016-2019 Joaquin M Lopez Munoz. |
b32b8144 FG |
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) | |
5 | * | |
6 | * See http://www.boost.org/libs/poly_collection for library home page. | |
7 | */ | |
8 | ||
9 | #include "test_construction.hpp" | |
10 | ||
11 | #include <algorithm> | |
12 | #include <boost/config.hpp> | |
13 | #include <boost/core/lightweight_test.hpp> | |
14 | #include <boost/detail/workaround.hpp> | |
b32b8144 FG |
15 | #include <boost/type_erasure/relaxed.hpp> |
16 | #include <scoped_allocator> | |
17 | #include <utility> | |
18 | #include <vector> | |
19 | #include "any_types.hpp" | |
20 | #include "base_types.hpp" | |
21 | #include "function_types.hpp" | |
22 | #include "test_utilities.hpp" | |
23 | ||
24 | using namespace test_utilities; | |
25 | ||
92f5a8d4 TL |
26 | template< |
27 | bool Propagate,bool AlwaysEqual, | |
28 | typename PolyCollection,typename ValueFactory,typename... Types | |
29 | > | |
30 | void test_allocator_aware_construction() | |
31 | { | |
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; | |
37 | ||
38 | allocator_type root1{0},root2{0}; | |
39 | rooted_poly_collection p{root1}; | |
40 | const rooted_poly_collection& cp=p; | |
41 | ValueFactory v; | |
42 | ||
43 | fill< | |
44 | constraints<is_equality_comparable,is_copy_constructible>, | |
45 | Types... | |
46 | >(p,v,2); | |
47 | ||
48 | { | |
49 | rooted_poly_collection p2{cp}; | |
50 | BOOST_TEST(p2==p); | |
51 | BOOST_TEST(p2.get_allocator().comes_from(root1)); | |
52 | } | |
53 | { | |
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); | |
58 | BOOST_TEST(p3==p); | |
59 | BOOST_TEST(d2==d3); | |
60 | BOOST_TEST(p2.empty()); | |
61 | do_((BOOST_TEST(!p2.template is_registered<Types>()),0)...); | |
62 | BOOST_TEST(p2.get_allocator().comes_from(root1)); | |
63 | } | |
64 | { | |
65 | rooted_poly_collection p2{cp,root2}; | |
66 | BOOST_TEST(p2==p); | |
67 | BOOST_TEST(p2.get_allocator().comes_from(root2)); | |
68 | } | |
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. | |
72 | */ | |
73 | ||
74 | if(AlwaysEqual) | |
75 | #endif | |
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. | |
80 | */ | |
81 | ||
82 | if(AlwaysEqual) | |
83 | #endif | |
84 | { | |
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); | |
89 | ||
90 | BOOST_TEST(p3==p); | |
91 | ||
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. | |
95 | */ | |
96 | ||
97 | (void)(d2==d3); /* Wunused-variable */ | |
98 | #else | |
99 | if(AlwaysEqual)BOOST_TEST(d2==d3); | |
100 | #endif | |
101 | ||
102 | BOOST_TEST(p2.empty()); | |
103 | do_((BOOST_TEST(!p2.template is_registered<Types>()),0)...); | |
104 | ||
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 | |
110 | */ | |
111 | ||
112 | if(!(Propagate&&!AlwaysEqual)) | |
113 | #endif | |
114 | BOOST_TEST(p3.get_allocator().comes_from(root2)); | |
115 | } | |
116 | { | |
117 | rooted_poly_collection p2{root2}; | |
118 | p2=cp; | |
119 | BOOST_TEST(p2==p); | |
120 | ||
121 | #if BOOST_WORKAROUND(BOOST_MSVC,<=1900) | |
122 | /* std::unordered_map copy assignment does not propagate allocators */ | |
123 | ||
124 | if(!Propagate) | |
125 | #endif | |
126 | #if BOOST_WORKAROUND(BOOST_LIBSTDCXX_VERSION,<40900) | |
127 | /* std::unordered_map copy assignment always and only propagates unequal | |
128 | * allocators. | |
129 | */ | |
130 | ||
131 | if(!((Propagate&&AlwaysEqual)||(!Propagate&&!AlwaysEqual))) | |
132 | #endif | |
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 | |
137 | */ | |
138 | ||
139 | if(!Propagate) | |
140 | #endif | |
141 | BOOST_TEST(p2.get_allocator().comes_from(Propagate?root1:root2)); | |
142 | } | |
143 | #if BOOST_WORKAROUND(BOOST_MSVC,<=1900) | |
144 | /* std::unordered_map move asignment does not propagate allocators */ | |
145 | ||
146 | if(!Propagate&&AlwaysEqual) | |
147 | #endif | |
148 | { | |
149 | rooted_poly_collection p2{cp}; | |
150 | auto d2=get_layout_data<Types...>(p2); | |
151 | rooted_poly_collection p3{root2}; | |
152 | p3=std::move(p2); | |
153 | auto d3=get_layout_data<Types...>(p3); | |
154 | BOOST_TEST(p3==p); | |
155 | if(Propagate||AlwaysEqual){ | |
156 | BOOST_TEST(d2==d3); | |
157 | BOOST_TEST(p2.empty()); | |
158 | do_((BOOST_TEST(!p2.template is_registered<Types>()),0)...); | |
159 | } | |
160 | ||
161 | #if BOOST_WORKAROUND(BOOST_LIBSTDCXX_VERSION,<40900) | |
162 | /* std::unordered_map move assignment always and only propagates unequal | |
163 | * allocators. | |
164 | */ | |
165 | ||
166 | if(!((Propagate&&AlwaysEqual)||(!Propagate&&!AlwaysEqual))) | |
167 | #endif | |
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 | |
172 | */ | |
173 | ||
174 | if(!(Propagate&&AlwaysEqual)) | |
175 | #endif | |
176 | BOOST_TEST(p3.get_allocator().comes_from(Propagate?root1:root2)); | |
177 | } | |
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. | |
181 | */ | |
182 | ||
183 | if(!(Propagate&&!AlwaysEqual)) | |
184 | #endif | |
185 | { | |
186 | constexpr bool use_same_allocator=!Propagate&&!AlwaysEqual; | |
187 | ||
188 | rooted_poly_collection p2{cp}, | |
189 | p3{use_same_allocator?root1:root2}; | |
190 | ||
191 | auto d2=get_layout_data<Types...>(p2), | |
192 | d3=get_layout_data<Types...>(p3); | |
193 | ||
194 | p2.swap(p3); | |
195 | auto e2=get_layout_data<Types...>(p2), | |
196 | e3=get_layout_data<Types...>(p3); | |
197 | BOOST_TEST(d2==e3); | |
198 | BOOST_TEST(d3==e2); | |
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 */ | |
203 | ||
204 | &&!(Propagate&&AlwaysEqual) | |
205 | #endif | |
206 | #if BOOST_WORKAROUND(BOOST_LIBSTDCXX_VERSION,<40900) | |
207 | /* std::unordered_map::swap always and only swaps unequal allocators */ | |
208 | ||
209 | &&!((Propagate&&AlwaysEqual)||(!Propagate&&!AlwaysEqual)) | |
210 | #endif | |
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 | |
215 | */ | |
216 | ||
217 | &&!(Propagate&&AlwaysEqual) | |
218 | #endif | |
219 | ){ | |
220 | BOOST_TEST(p2.get_allocator().comes_from(Propagate?root2:root1)); | |
221 | BOOST_TEST(p3.get_allocator().comes_from(Propagate?root1:root2)); | |
222 | } | |
223 | ||
224 | using std::swap; | |
225 | swap(p2,p3); | |
226 | auto f2=get_layout_data<Types...>(p2), | |
227 | f3=get_layout_data<Types...>(p3); | |
228 | BOOST_TEST(e2==f3); | |
229 | BOOST_TEST(e3==f2); | |
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)); | |
234 | } | |
235 | } | |
236 | } | |
237 | ||
b32b8144 FG |
238 | template<typename PolyCollection,typename ValueFactory,typename... Types> |
239 | void test_construction() | |
240 | { | |
92f5a8d4 TL |
241 | { |
242 | constexpr bool propagate=true,always_equal=true; | |
243 | ||
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...>(); | |
252 | } | |
253 | ||
b32b8144 FG |
254 | { |
255 | PolyCollection p; | |
256 | const PolyCollection& cp=p; | |
257 | ValueFactory v; | |
258 | ||
259 | fill< | |
260 | constraints<is_equality_comparable,is_copy_constructible>, | |
261 | Types... | |
262 | >(p,v,2); | |
263 | ||
b32b8144 FG |
264 | { |
265 | PolyCollection p2{cp.begin(),cp.end()}; | |
266 | BOOST_TEST(p2==p); | |
267 | } | |
268 | { | |
269 | using type=first_of< | |
270 | constraints<is_equality_comparable,is_copy_constructible>, | |
271 | Types...>; | |
272 | ||
273 | PolyCollection p2{cp.template begin<type>(),cp.template end<type>()}; | |
274 | BOOST_TEST( | |
275 | p2.size()==cp.template size<type>()&& | |
276 | std::equal( | |
277 | p2.template begin<type>(),p2.template end<type>(), | |
278 | cp.template begin<type>())); | |
279 | } | |
280 | } | |
281 | ||
b32b8144 FG |
282 | { |
283 | using not_copy_constructible= | |
284 | boost::poly_collection::not_copy_constructible; | |
285 | ||
286 | PolyCollection p; | |
287 | const PolyCollection& cp=p; | |
288 | ValueFactory v; | |
289 | ||
290 | fill< | |
291 | constraints<is_equality_comparable,is_not_copy_constructible>, | |
292 | Types... | |
293 | >(p,v,2); | |
294 | ||
295 | #if BOOST_WORKAROUND(BOOST_LIBSTDCXX_VERSION,<40900) | |
296 | /* std::unordered_map copy construction and assigment crash when elements | |
297 | * throw on copy construction. | |
298 | */ | |
299 | ||
300 | static_assert( | |
301 | sizeof(not_copy_constructible)>0,""); /* Wunused-local-typedefs */ | |
302 | (void)cp; /* Wunused-variable */ | |
303 | #else | |
304 | check_throw<not_copy_constructible>([&]{ | |
305 | PolyCollection p2{cp}; | |
306 | (void)p2; | |
307 | }); | |
308 | check_throw<not_copy_constructible>([&]{ | |
309 | PolyCollection p2; | |
310 | p2=cp; | |
311 | }); | |
312 | #endif | |
313 | ||
314 | { | |
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)...); | |
319 | ||
320 | p={std::move(p2)}; | |
321 | BOOST_TEST(!p.empty()); | |
322 | BOOST_TEST(p2.empty()); | |
323 | do_((BOOST_TEST(!p2.template is_registered<Types>()),0)...); | |
324 | } | |
325 | } | |
b32b8144 FG |
326 | } |
327 | ||
328 | void test_scoped_allocator() | |
329 | { | |
92f5a8d4 TL |
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. | |
335 | */ | |
336 | #else | |
b32b8144 FG |
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_> | |
342 | >; | |
343 | using collection_allocator=std::scoped_allocator_adaptor< | |
344 | element_allocator, | |
345 | vector_allocator | |
346 | >; | |
347 | using poly_collection= | |
348 | boost::any_collection<concept_,collection_allocator>; | |
349 | ||
350 | element_allocator roote{0}; | |
351 | vector_allocator rootv{0}; | |
352 | collection_allocator al{roote,rootv}; | |
353 | poly_collection p{al}; | |
354 | ||
355 | p.emplace<vector>(); | |
92f5a8d4 TL |
356 | auto& s=*p.begin<vector>(); |
357 | BOOST_TEST(p.get_allocator().comes_from(roote)); | |
b32b8144 | 358 | |
92f5a8d4 TL |
359 | #if BOOST_WORKAROUND(BOOST_MSVC,>=1910)&&BOOST_WORKAROUND(BOOST_MSVC,<1916) |
360 | /* https://developercommunity.visualstudio.com/content/problem/246251/ | |
361 | * 3136309.html | |
362 | */ | |
b32b8144 | 363 | #else |
92f5a8d4 TL |
364 | BOOST_TEST(s.get_allocator().comes_from(rootv)); |
365 | #endif | |
b32b8144 FG |
366 | #endif |
367 | } | |
368 | ||
369 | void test_construction() | |
370 | { | |
371 | 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>(); | |
375 | test_construction< | |
376 | base_types::collection,auto_increment, | |
377 | base_types::t1,base_types::t2,base_types::t3, | |
378 | base_types::t4,base_types::t5>(); | |
379 | test_construction< | |
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(); | |
384 | } |