1 | ////////////////////////////////////////////////////////////////////////////// |
2 | // |
3 | // (C) Copyright Ion Gaztanaga 2008. Distributed under the Boost |
4 | // Software License, Version 1.0. (See accompanying file |
5 | // LICENSE_1_0.txt or copy at http://www.boost.org/LICENSE_1_0.txt) |
6 | // |
7 | // See http://www.boost.org/libs/container for documentation. |
8 | // |
9 | ////////////////////////////////////////////////////////////////////////////// |
10 | #ifndef BOOST_CONTAINER_PROPAGATE_ALLOCATOR_TEST_HPP |
11 | #define BOOST_CONTAINER_PROPAGATE_ALLOCATOR_TEST_HPP |
12 | |
13 | #include <boost/container/detail/config_begin.hpp> |
14 | #include <boost/core/lightweight_test.hpp> |
15 | #include "dummy_test_allocator.hpp" |
16 | |
17 | #include <iostream> |
18 | |
19 | namespace boost{ |
20 | namespace container { |
21 | namespace test{ |
22 | |
23 | template<class Selector> |
24 | struct alloc_propagate_base; |
25 | |
26 | template<class T, class Allocator, class Selector> |
27 | class alloc_propagate_wrapper |
28 | : public alloc_propagate_base<Selector>::template apply<T, Allocator>::type |
29 | { |
30 | BOOST_COPYABLE_AND_MOVABLE(alloc_propagate_wrapper) |
31 | |
32 | public: |
33 | typedef typename alloc_propagate_base |
34 | <Selector>::template apply<T, Allocator>::type Base; |
35 | |
36 | typedef typename Base::allocator_type allocator_type; |
37 | typedef typename Base::value_type value_type; |
38 | typedef typename Base::size_type size_type; |
39 | |
40 | alloc_propagate_wrapper() |
41 | : Base() |
42 | {} |
43 | |
44 | explicit alloc_propagate_wrapper(const allocator_type &a) |
45 | : Base(a) |
46 | {} |
47 | /* |
48 | //sequence containers only |
49 | explicit alloc_propagate_wrapper(size_type n, const value_type &v, const allocator_type &a) |
50 | : Base(n, v, a) |
51 | {} |
52 | |
53 | alloc_propagate_wrapper(size_type n, const allocator_type &a) |
54 | : Base(n, a) |
55 | {}*/ |
56 | |
57 | template<class Iterator> |
58 | alloc_propagate_wrapper(Iterator b, Iterator e, const allocator_type &a) |
59 | : Base(b, e, a) |
60 | {} |
61 | |
62 | #if !defined(BOOST_NO_CXX11_HDR_INITIALIZER_LIST) |
63 | alloc_propagate_wrapper(std::initializer_list<value_type> il, const allocator_type& a) |
64 | : Base(il, a) |
65 | {} |
66 | /* |
67 | //associative containers only |
68 | alloc_propagate_wrapper(std::initializer_list<value_type> il, const Compare& comp, const allocator_type& a) |
69 | : Base(il, comp, a) |
70 | {}*/ |
71 | |
72 | #endif |
73 | |
74 | alloc_propagate_wrapper(const alloc_propagate_wrapper &x) |
75 | : Base(x) |
76 | {} |
77 | |
78 | alloc_propagate_wrapper(const alloc_propagate_wrapper &x, const allocator_type &a) |
79 | : Base(x, a) |
80 | {} |
81 | |
82 | alloc_propagate_wrapper(BOOST_RV_REF(alloc_propagate_wrapper) x) |
83 | : Base(boost::move(static_cast<Base&>(x))) |
84 | {} |
85 | |
86 | alloc_propagate_wrapper(BOOST_RV_REF(alloc_propagate_wrapper) x, const allocator_type &a) |
87 | : Base(boost::move(static_cast<Base&>(x)), a) |
88 | {} |
89 | |
90 | alloc_propagate_wrapper &operator=(BOOST_COPY_ASSIGN_REF(alloc_propagate_wrapper) x) |
91 | { this->Base::operator=((const Base &)x); return *this; } |
92 | |
93 | alloc_propagate_wrapper &operator=(BOOST_RV_REF(alloc_propagate_wrapper) x) |
94 | { this->Base::operator=(boost::move(static_cast<Base&>(x))); return *this; } |
95 | |
96 | void swap(alloc_propagate_wrapper &x) |
97 | { this->Base::swap(x); } |
98 | }; |
99 | |
100 | template<class T> |
101 | struct get_real_stored_allocator |
102 | { |
103 | typedef typename T::stored_allocator_type type; |
104 | }; |
105 | |
106 | template<class Container> |
107 | void test_propagate_allocator_allocator_arg(); |
108 | |
109 | template<class Selector> |
110 | bool test_propagate_allocator() |
111 | { |
112 | { |
113 | typedef propagation_test_allocator<char, true, true, true, true, true> AlwaysPropagate; |
114 | typedef alloc_propagate_wrapper<char, AlwaysPropagate, Selector> PropagateCont; |
115 | typedef typename get_real_stored_allocator<typename PropagateCont::Base>::type StoredAllocator; |
116 | { |
117 | ////////////////////////////////////////// |
118 | //Test AlwaysPropagate allocator propagation |
119 | ////////////////////////////////////////// |
120 | |
121 | //default constructor |
122 | StoredAllocator::reset_unique_id(111); |
123 | PropagateCont c; //stored 112 |
124 | BOOST_TEST (c.get_stored_allocator().id_ == 112); |
125 | BOOST_TEST (c.get_stored_allocator().ctr_copies_ == 0); |
126 | BOOST_TEST (c.get_stored_allocator().ctr_moves_ == 0); |
127 | BOOST_TEST (c.get_stored_allocator().assign_copies_ == 0); |
128 | BOOST_TEST (c.get_stored_allocator().assign_moves_ == 0); |
129 | BOOST_TEST (c.get_stored_allocator().swaps_ == 0); |
130 | } |
131 | { |
132 | //copy constructor |
133 | StoredAllocator::reset_unique_id(222); |
134 | PropagateCont c; //stored 223 |
135 | BOOST_TEST (c.get_stored_allocator().id_ == 223); |
136 | //propagate_on_copy_constructor produces copies, moves or RVO (depending on the compiler). |
137 | //For allocators that copy in select_on_container_copy_construction, at least we must have a copy |
138 | PropagateCont c2(c); //should propagate 223 |
139 | BOOST_TEST (c2.get_stored_allocator().id_ == 223); |
140 | BOOST_TEST (c2.get_stored_allocator().ctr_copies_ >= 1); |
141 | BOOST_TEST (c2.get_stored_allocator().ctr_moves_ >= 0); |
142 | BOOST_TEST (c2.get_stored_allocator().assign_copies_ == 0); |
143 | BOOST_TEST (c2.get_stored_allocator().assign_moves_ == 0); |
144 | BOOST_TEST (c2.get_stored_allocator().swaps_ == 0); |
145 | } |
146 | { |
147 | //move constructor |
148 | StoredAllocator::reset_unique_id(333); |
149 | PropagateCont c; //stored 334 |
150 | BOOST_TEST (c.get_stored_allocator().id_ == 334); |
151 | PropagateCont c2(boost::move(c)); //should propagate 334 |
152 | BOOST_TEST (c2.get_stored_allocator().id_ == 334); |
153 | BOOST_TEST (c2.get_stored_allocator().ctr_copies_ == 0); |
154 | BOOST_TEST (c2.get_stored_allocator().ctr_moves_ > 0); |
155 | BOOST_TEST (c2.get_stored_allocator().assign_copies_ == 0); |
156 | BOOST_TEST (c2.get_stored_allocator().assign_moves_ == 0); |
157 | BOOST_TEST (c2.get_stored_allocator().swaps_ == 0); |
158 | } |
159 | { |
160 | //copy assign |
161 | StoredAllocator::reset_unique_id(444); |
162 | PropagateCont c; //stored 445 |
163 | BOOST_TEST (c.get_stored_allocator().id_ == 445); |
164 | PropagateCont c2; //stored 446 |
165 | BOOST_TEST (c2.get_stored_allocator().id_ == 446); |
166 | c2 = c; //should propagate 445 |
167 | BOOST_TEST (c2.get_stored_allocator().id_ == 445); |
168 | BOOST_TEST (c2.get_stored_allocator().ctr_copies_ == 0); |
169 | BOOST_TEST (c2.get_stored_allocator().ctr_moves_ == 0); |
170 | BOOST_TEST (c2.get_stored_allocator().assign_copies_ == 1); |
171 | BOOST_TEST (c2.get_stored_allocator().assign_moves_ == 0); |
172 | BOOST_TEST (c2.get_stored_allocator().swaps_ == 0); |
173 | } |
174 | { |
175 | //move assign |
176 | StoredAllocator::reset_unique_id(555); |
177 | PropagateCont c; //stored 556 |
178 | BOOST_TEST (c.get_stored_allocator().id_ == 556); |
179 | PropagateCont c2; //stored 557 |
180 | BOOST_TEST (c2.get_stored_allocator().id_ == 557); |
181 | c = boost::move(c2); //should propagate 557 |
182 | BOOST_TEST (c.get_stored_allocator().id_ == 557); |
183 | BOOST_TEST (c.get_stored_allocator().ctr_copies_ == 0); |
184 | BOOST_TEST (c.get_stored_allocator().ctr_moves_ == 0); |
185 | BOOST_TEST (c.get_stored_allocator().assign_copies_ == 0); |
186 | BOOST_TEST (c.get_stored_allocator().assign_moves_ == 1); |
187 | BOOST_TEST (c.get_stored_allocator().swaps_ == 0); |
188 | } |
189 | { |
190 | //swap |
191 | StoredAllocator::reset_unique_id(666); |
192 | PropagateCont c; //stored 667 |
193 | BOOST_TEST (c.get_stored_allocator().id_ == 667); |
194 | PropagateCont c2; //stored 668 |
195 | BOOST_TEST (c2.get_stored_allocator().id_ == 668); |
196 | c.swap(c2); |
197 | BOOST_TEST (c2.get_stored_allocator().ctr_copies_ == 0); |
198 | BOOST_TEST (c.get_stored_allocator().ctr_copies_ == 0); |
199 | BOOST_TEST (c2.get_stored_allocator().ctr_moves_ == 0); |
200 | BOOST_TEST (c.get_stored_allocator().ctr_moves_ == 0); |
201 | BOOST_TEST (c2.get_stored_allocator().assign_copies_ == 0); |
202 | BOOST_TEST (c.get_stored_allocator().assign_copies_ == 0); |
203 | BOOST_TEST (c2.get_stored_allocator().assign_moves_ == 0); |
204 | BOOST_TEST (c.get_stored_allocator().assign_moves_ == 0); |
205 | BOOST_TEST (c2.get_stored_allocator().swaps_ == 1); |
206 | BOOST_TEST (c.get_stored_allocator().swaps_ == 1); |
207 | } |
208 | //And now allocator argument constructors |
209 | test_propagate_allocator_allocator_arg<PropagateCont>(); |
210 | } |
211 | |
212 | ////////////////////////////////////////// |
213 | //Test NeverPropagate allocator propagation |
214 | ////////////////////////////////////////// |
215 | { |
216 | typedef propagation_test_allocator<char, false, false, false, false, true> NeverPropagate; |
217 | typedef alloc_propagate_wrapper<char, NeverPropagate, Selector> NoPropagateCont; |
218 | typedef typename get_real_stored_allocator<typename NoPropagateCont::Base>::type StoredAllocator; |
219 | { |
220 | //default constructor |
221 | StoredAllocator::reset_unique_id(111); |
222 | NoPropagateCont c; //stored 112 |
223 | BOOST_TEST (c.get_stored_allocator().id_ == 112); |
224 | BOOST_TEST (c.get_stored_allocator().ctr_copies_ == 0); |
225 | BOOST_TEST (c.get_stored_allocator().ctr_moves_ == 0); |
226 | BOOST_TEST (c.get_stored_allocator().assign_copies_ == 0); |
227 | BOOST_TEST (c.get_stored_allocator().assign_moves_ == 0); |
228 | BOOST_TEST (c.get_stored_allocator().swaps_ == 0); |
229 | } |
230 | { |
231 | //copy constructor |
232 | //propagate_on_copy_constructor produces copies, moves or RVO (depending on the compiler) |
233 | //For allocators that don't copy in select_on_container_copy_construction we must have a default |
234 | //construction |
235 | StoredAllocator::reset_unique_id(222); |
236 | NoPropagateCont c; //stored 223 |
237 | BOOST_TEST (c.get_stored_allocator().id_ == 223); |
238 | NoPropagateCont c2(c); //should NOT propagate 223 |
239 | BOOST_TEST (c2.get_stored_allocator().id_ == 224); |
240 | BOOST_TEST (c2.get_stored_allocator().ctr_copies_ >= 0); |
241 | BOOST_TEST (c2.get_stored_allocator().ctr_moves_ >= 0); |
242 | BOOST_TEST (c2.get_stored_allocator().assign_copies_ == 0); |
243 | BOOST_TEST (c2.get_stored_allocator().assign_moves_ == 0); |
244 | BOOST_TEST (c2.get_stored_allocator().swaps_ == 0); |
245 | } |
246 | { |
247 | //move constructor |
248 | StoredAllocator::reset_unique_id(333); |
249 | NoPropagateCont c; //stored 334 |
250 | BOOST_TEST (c.get_stored_allocator().id_ == 334); |
251 | NoPropagateCont c2(boost::move(c)); // should NOT propagate 334 |
252 | BOOST_TEST (c2.get_stored_allocator().ctr_copies_ >= 0); |
253 | BOOST_TEST (c2.get_stored_allocator().ctr_moves_ >= 0); |
254 | BOOST_TEST (c2.get_stored_allocator().assign_copies_ == 0); |
255 | BOOST_TEST (c2.get_stored_allocator().assign_moves_ == 0); |
256 | BOOST_TEST (c2.get_stored_allocator().swaps_ == 0); |
257 | } |
258 | { |
259 | //copy assign |
260 | StoredAllocator::reset_unique_id(444); |
261 | NoPropagateCont c; //stored 445 |
262 | NoPropagateCont c2; //stored 446 |
263 | c2 = c; // should NOT propagate 445 |
264 | BOOST_TEST (c2.get_stored_allocator().id_ == 446); |
265 | BOOST_TEST (c2.get_stored_allocator().ctr_copies_ == 0); |
266 | BOOST_TEST (c2.get_stored_allocator().ctr_moves_ == 0); |
267 | BOOST_TEST (c2.get_stored_allocator().assign_copies_ == 0); |
268 | BOOST_TEST (c2.get_stored_allocator().assign_moves_ == 0); |
269 | BOOST_TEST (c2.get_stored_allocator().swaps_ == 0); |
270 | } |
271 | { |
272 | //move assign |
273 | StoredAllocator::reset_unique_id(555); |
274 | NoPropagateCont c; //stored 556 |
275 | NoPropagateCont c2; //stored 557 |
276 | c2 = c; // should NOT propagate 556 |
277 | BOOST_TEST (c2.get_stored_allocator().id_ == 557); |
278 | BOOST_TEST (c2.get_stored_allocator().ctr_copies_ == 0); |
279 | BOOST_TEST (c2.get_stored_allocator().ctr_moves_ == 0); |
280 | BOOST_TEST (c2.get_stored_allocator().assign_copies_ == 0); |
281 | BOOST_TEST (c2.get_stored_allocator().assign_moves_ == 0); |
282 | BOOST_TEST (c2.get_stored_allocator().swaps_ == 0); |
283 | } |
284 | //And now allocator argument constructors |
285 | test_propagate_allocator_allocator_arg<NoPropagateCont>(); |
286 | } |
287 | { |
288 | //Don't use unequal ids as unequal allocators -------------------------|, |
289 | //because swap requires equal allocators v |
290 | typedef propagation_test_allocator<char, false, false, false, false, false> NeverPropagate; |
291 | typedef alloc_propagate_wrapper<char, NeverPropagate, Selector> NoPropagateCont; |
292 | typedef typename get_real_stored_allocator<typename NoPropagateCont::Base>::type StoredAllocator; |
293 | { |
294 | //swap |
295 | StoredAllocator::reset_unique_id(666); |
296 | NoPropagateCont c; //stored 667 |
297 | BOOST_TEST (c.get_stored_allocator().id_ == 667); |
298 | NoPropagateCont c2; //stored 668 |
299 | BOOST_TEST (c2.get_stored_allocator().id_ == 668); |
300 | c2.swap(c); // should NOT swap 667 and 668 |
301 | BOOST_TEST (c2.get_stored_allocator().id_ == 668); |
302 | BOOST_TEST (c2.get_stored_allocator().ctr_copies_ == 0); |
303 | BOOST_TEST (c2.get_stored_allocator().ctr_moves_ == 0); |
304 | BOOST_TEST (c2.get_stored_allocator().assign_copies_ == 0); |
305 | BOOST_TEST (c2.get_stored_allocator().assign_moves_ == 0); |
306 | BOOST_TEST (c2.get_stored_allocator().swaps_ == 0); |
307 | BOOST_TEST (c.get_stored_allocator().id_ == 667); |
308 | BOOST_TEST (c.get_stored_allocator().ctr_copies_ == 0); |
309 | BOOST_TEST (c.get_stored_allocator().ctr_moves_ == 0); |
310 | BOOST_TEST (c.get_stored_allocator().assign_copies_ == 0); |
311 | BOOST_TEST (c.get_stored_allocator().assign_moves_ == 0); |
312 | BOOST_TEST (c.get_stored_allocator().swaps_ == 0); |
313 | } |
314 | } |
315 | |
316 | return report_errors() == 0; |
317 | } |
318 | |
319 | template<class Container> |
320 | void test_propagate_allocator_allocator_arg() |
321 | { |
322 | typedef typename Container::allocator_type allocator_type; |
323 | typedef typename get_real_stored_allocator<typename Container::Base>::type StoredAllocator; |
324 | |
325 | { //The allocator must be always propagated |
326 | //allocator constructor |
327 | allocator_type::reset_unique_id(111); |
328 | const allocator_type & a = allocator_type(); //stored 112 |
329 | Container c(a); //should propagate 112 |
330 | BOOST_TEST (c.get_stored_allocator().id_ == 112); |
331 | BOOST_TEST (c.get_stored_allocator().ctr_copies_ > 0); |
332 | BOOST_TEST (c.get_stored_allocator().ctr_moves_ == 0); |
333 | BOOST_TEST (c.get_stored_allocator().assign_copies_ == 0); |
334 | BOOST_TEST (c.get_stored_allocator().assign_moves_ == 0); |
335 | BOOST_TEST (c.get_stored_allocator().swaps_ == 0); |
336 | } |
337 | { |
338 | //copy allocator constructor |
339 | StoredAllocator::reset_unique_id(999); |
340 | Container c; |
341 | //stored_allocator_type could be the same type as allocator_type |
342 | //so reset it again to get a predictable result |
343 | allocator_type::reset_unique_id(222); |
344 | Container c2(c, allocator_type()); //should propagate 223 |
345 | BOOST_TEST (c2.get_stored_allocator().id_ == 223); |
346 | BOOST_TEST (c2.get_stored_allocator().ctr_copies_ > 0); |
347 | BOOST_TEST (c2.get_stored_allocator().ctr_moves_ == 0); |
348 | BOOST_TEST (c2.get_stored_allocator().assign_copies_ == 0); |
349 | BOOST_TEST (c2.get_stored_allocator().assign_moves_ == 0); |
350 | BOOST_TEST (c2.get_stored_allocator().swaps_ == 0); |
351 | } |
352 | { |
353 | //move allocator constructor |
354 | StoredAllocator::reset_unique_id(999); |
355 | Container c; |
356 | //stored_allocator_type could be the same type as allocator_type |
357 | //so reset it again to get a predictable result |
358 | allocator_type::reset_unique_id(333); |
359 | Container c2(boost::move(c), allocator_type()); //should propagate 334 |
360 | BOOST_TEST (c2.get_stored_allocator().id_ == 334); |
361 | BOOST_TEST (c2.get_stored_allocator().ctr_copies_ > 0); |
362 | BOOST_TEST (c2.get_stored_allocator().ctr_moves_ == 0); |
363 | BOOST_TEST (c2.get_stored_allocator().assign_copies_ == 0); |
364 | BOOST_TEST (c2.get_stored_allocator().assign_moves_ == 0); |
365 | BOOST_TEST (c2.get_stored_allocator().swaps_ == 0); |
366 | } |
367 | } |
368 | |
369 | } //namespace test{ |
370 | } //namespace container { |
371 | } //namespace boost{ |
372 | |
373 | #include <boost/container/detail/config_end.hpp> |
374 | |
375 | #endif //#ifndef BOOST_CONTAINER_PROPAGATE_ALLOCATOR_TEST_HPP |
376 | |