1 //////////////////////////////////////////////////////////////////////////////
2 //
3 // (C) Copyright Ion Gaztanaga 2016-2016. 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 #include <boost/core/lightweight_test.hpp>
11 #include <boost/static_assert.hpp>
12 #include <boost/container/node_handle.hpp>
13 #include <boost/container/new_allocator.hpp>
14 #include <boost/move/utility_core.hpp>
15 #include <boost/move/adl_move_swap.hpp>
16 #include <boost/container/detail/pair_key_mapped_of_value.hpp>
17
18 using namespace ::boost::container;
19
20 enum EAllocState
21 {
22 DefaultConstructed,
23 MoveConstructed,
24 MoveAssigned,
25 CopyConstructed,
26 CopyAssigned,
27 Swapped,
28 Destructed
29 };
30
31 template<class Node>
32 class trace_allocator
33 : public new_allocator<Node>
34 {
35 BOOST_COPYABLE_AND_MOVABLE(trace_allocator)
36
37 typedef new_allocator<Node> base_t;
38
39 public:
40
41 struct propagate_on_container_move_assignment
42 {
43 static const bool value = true;
44 };
45
46 struct propagate_on_container_swap
47 {
48 static const bool value = true;
49 };
50
51 //!Obtains an new_allocator that allocates
52 //!objects of type T2
53 template<class T2>
54 struct rebind
55 {
56 typedef trace_allocator<T2> other;
57 };
58
trace_allocator(unsigned value=999)59 explicit trace_allocator(unsigned value = 999)
60 : m_state(DefaultConstructed), m_value(value)
61 {
62 ++count;
63 }
64
trace_allocator(BOOST_RV_REF (trace_allocator)other)65 trace_allocator(BOOST_RV_REF(trace_allocator) other)
66 : base_t(boost::move(BOOST_MOVE_BASE(base_t, other))), m_state(MoveConstructed), m_value(other.m_value)
67 {
68 ++count;
69 }
70
trace_allocator(const trace_allocator & other)71 trace_allocator(const trace_allocator &other)
72 : base_t(other), m_state(CopyConstructed), m_value(other.m_value)
73 {
74 ++count;
75 }
76
operator =(BOOST_RV_REF (trace_allocator)other)77 trace_allocator & operator=(BOOST_RV_REF(trace_allocator) other)
78 {
79 m_value = other.m_value;
80 m_state = MoveAssigned;
81 return *this;
82 }
83
84 template<class OtherNode>
trace_allocator(const trace_allocator<OtherNode> & other)85 trace_allocator(const trace_allocator<OtherNode> &other)
86 : m_state(CopyConstructed), m_value(other.m_value)
87 {
88 ++count;
89 }
90
91 template<class OtherNode>
operator =(BOOST_COPY_ASSIGN_REF (trace_allocator<OtherNode>)other)92 trace_allocator & operator=(BOOST_COPY_ASSIGN_REF(trace_allocator<OtherNode>) other)
93 {
94 m_value = other.m_value;
95 m_state = CopyAssigned;
96 return *this;
97 }
98
~trace_allocator()99 ~trace_allocator()
100 {
101 m_value = 0u-1u;
102 m_state = Destructed;
103 --count;
104 }
105
swap(trace_allocator & other)106 void swap(trace_allocator &other)
107 {
108 boost::adl_move_swap(m_value, other.m_value);
109 m_state = other.m_state = Swapped;
110 }
111
swap(trace_allocator & left,trace_allocator & right)112 friend void swap(trace_allocator &left, trace_allocator &right)
113 {
114 left.swap(right);
115 }
116
117 EAllocState m_state;
118 unsigned m_value;
119
120 static unsigned int count;
121
reset_count()122 static void reset_count()
123 { count = 0; }
124 };
125
126 template<class Node>
127 unsigned int trace_allocator<Node>::count = 0;
128
129 template<class T>
130 struct node
131 {
132 typedef T value_type;
133 value_type value;
134
get_datanode135 value_type &get_data() { return value; }
get_datanode136 const value_type &get_data() const { return value; }
137
nodenode138 node()
139 {
140 ++count;
141 }
142
~nodenode143 ~node()
144 {
145 --count;
146 }
147
148 static unsigned int count;
149
reset_countnode150 static void reset_count()
151 { count = 0; }
152 };
153
154 template<class T1, class T2>
155 struct value
156 {
157 T1 first;
158 T2 second;
159 };
160
161 template<class T>
162 unsigned int node<T>::count = 0;
163
164
165 //Common types
166 typedef value<int, unsigned> test_pair;
167 typedef pair_key_mapped_of_value<int, unsigned> key_mapped_t;
168 typedef node<test_pair> node_t;
169 typedef trace_allocator< node_t > node_alloc_t;
170 typedef node_handle<node_alloc_t, void> node_handle_set_t;
171 typedef node_handle<node_alloc_t, key_mapped_t> node_handle_map_t;
172 typedef allocator_traits<node_alloc_t>::portable_rebind_alloc<test_pair>::type value_allocator_type;
173
test_types()174 void test_types()
175 {
176 //set
177 BOOST_STATIC_ASSERT(( dtl::is_same<node_handle_set_t::value_type, test_pair>::value ));
178 BOOST_STATIC_ASSERT(( dtl::is_same<node_handle_set_t::key_type, test_pair>::value ));
179 BOOST_STATIC_ASSERT(( dtl::is_same<node_handle_set_t::mapped_type, test_pair>::value ));
180 BOOST_STATIC_ASSERT(( dtl::is_same<node_handle_set_t::allocator_type, value_allocator_type>::value ));
181
182 //map
183 BOOST_STATIC_ASSERT(( dtl::is_same<node_handle_map_t::value_type, test_pair>::value ));
184 BOOST_STATIC_ASSERT(( dtl::is_same<node_handle_map_t::key_type, int>::value ));
185 BOOST_STATIC_ASSERT(( dtl::is_same<node_handle_map_t::mapped_type, unsigned>::value ));
186 BOOST_STATIC_ASSERT(( dtl::is_same<node_handle_map_t::allocator_type, value_allocator_type>::value ));
187 }
188
test_default_constructor()189 void test_default_constructor()
190 {
191 node_alloc_t::reset_count();
192 {
193 node_handle_set_t nh;
194 BOOST_TEST(node_alloc_t::count == 0);
195 }
196 BOOST_TEST(node_alloc_t::count == 0);
197 }
198
test_arg_constructor()199 void test_arg_constructor()
200 {
201 //With non-null pointer
202 node_alloc_t::reset_count();
203 node_t::reset_count();
204 {
205 const node_alloc_t al;
206 BOOST_TEST(node_alloc_t::count == 1);
207 {
208 node_handle_set_t nh(new node_t, al);
209 BOOST_TEST(node_t::count == 1);
210 BOOST_TEST(node_alloc_t::count == 2);
211 }
212 BOOST_TEST(node_alloc_t::count == 1);
213 }
214 BOOST_TEST(node_t::count == 0);
215 BOOST_TEST(node_alloc_t::count == 0);
216
217 //With null pointer
218 node_alloc_t::reset_count();
219 node_t::reset_count();
220 {
221 const node_alloc_t al;
222 BOOST_TEST(node_alloc_t::count == 1);
223 {
224 node_handle_set_t nh(0, al);
225 BOOST_TEST(node_t::count == 0);
226 BOOST_TEST(node_alloc_t::count == 1);
227 }
228 BOOST_TEST(node_alloc_t::count == 1);
229 BOOST_TEST(node_t::count == 0);
230 }
231 BOOST_TEST(node_alloc_t::count == 0);
232 }
233
test_move_constructor()234 void test_move_constructor()
235 {
236 //With non-null pointer
237 node_alloc_t::reset_count();
238 node_t::reset_count();
239 {
240 const node_alloc_t al;
241 BOOST_TEST(node_alloc_t::count == 1);
242 {
243 node_t *const from_ptr = new node_t;
244 node_handle_set_t nh(from_ptr, al);
245 BOOST_TEST(node_t::count == 1);
246 BOOST_TEST(node_alloc_t::count == 2);
247 {
248 node_handle_set_t nh2(boost::move(nh));
249 BOOST_TEST(nh.empty());
250 BOOST_TEST(!nh2.empty());
251 BOOST_TEST(nh2.get() == from_ptr);
252 BOOST_TEST(nh2.node_alloc().m_state == MoveConstructed);
253 BOOST_TEST(node_t::count == 1);
254 BOOST_TEST(node_alloc_t::count == 2);
255 }
256 BOOST_TEST(node_t::count == 0);
257 BOOST_TEST(node_alloc_t::count == 1);
258 }
259 BOOST_TEST(node_alloc_t::count == 1);
260 }
261 BOOST_TEST(node_t::count == 0);
262 BOOST_TEST(node_alloc_t::count == 0);
263
264 //With null pointer
265 node_alloc_t::reset_count();
266 node_t::reset_count();
267 {
268 const node_alloc_t al;
269 BOOST_TEST(node_alloc_t::count == 1);
270 {
271 node_handle_set_t nh;
272 {
273 node_handle_set_t nh2(boost::move(nh));
274 BOOST_TEST(nh.empty());
275 BOOST_TEST(nh2.empty());
276 BOOST_TEST(node_alloc_t::count == 1);
277 }
278 BOOST_TEST(node_t::count == 0);
279 BOOST_TEST(node_alloc_t::count == 1);
280 }
281 BOOST_TEST(node_alloc_t::count == 1);
282 }
283 BOOST_TEST(node_t::count == 0);
284 BOOST_TEST(node_alloc_t::count == 0);
285 }
286
test_related_constructor()287 void test_related_constructor()
288 {
289 //With non-null pointer
290 node_alloc_t::reset_count();
291 node_t::reset_count();
292 {
293 const node_alloc_t al;
294 BOOST_TEST(node_alloc_t::count == 1);
295 {
296 node_t *const from_ptr = new node_t;
297 node_handle_map_t nh(from_ptr, al);
298 BOOST_TEST(node_t::count == 1);
299 BOOST_TEST(node_alloc_t::count == 2);
300 {
301 node_handle_set_t nh2(boost::move(nh));
302 BOOST_TEST(nh.empty());
303 BOOST_TEST(!nh2.empty());
304 BOOST_TEST(nh2.get() == from_ptr);
305 BOOST_TEST(nh2.node_alloc().m_state == MoveConstructed);
306 BOOST_TEST(node_t::count == 1);
307 BOOST_TEST(node_alloc_t::count == 2);
308 }
309 BOOST_TEST(node_t::count == 0);
310 BOOST_TEST(node_alloc_t::count == 1);
311 }
312 BOOST_TEST(node_alloc_t::count == 1);
313 }
314 BOOST_TEST(node_t::count == 0);
315 BOOST_TEST(node_alloc_t::count == 0);
316
317 //With null pointer
318 node_alloc_t::reset_count();
319 node_t::reset_count();
320 {
321 const node_alloc_t al;
322 BOOST_TEST(node_alloc_t::count == 1);
323 {
324 node_handle_set_t nh;
325 {
326 node_handle_map_t nh2(boost::move(nh));
327 BOOST_TEST(nh.empty());
328 BOOST_TEST(nh2.empty());
329 BOOST_TEST(node_alloc_t::count == 1);
330 }
331 BOOST_TEST(node_t::count == 0);
332 BOOST_TEST(node_alloc_t::count == 1);
333 }
334 BOOST_TEST(node_alloc_t::count == 1);
335 }
336 BOOST_TEST(node_t::count == 0);
337 BOOST_TEST(node_alloc_t::count == 0);
338 }
339
test_move_assignment()340 void test_move_assignment()
341 {
342 //empty = full
343 {
344 node_alloc_t::reset_count();
345 node_t::reset_count();
346 node_t *const from_ptr = new node_t;
347 node_handle_set_t nh_from(from_ptr, node_alloc_t());
348 BOOST_TEST(node_t::count == 1);
349 BOOST_TEST(node_alloc_t::count == 1);
350
351 node_handle_set_t nh_to;
352 BOOST_TEST(nh_to.empty());
353 BOOST_TEST(node_t::count == 1);
354 BOOST_TEST(node_alloc_t::count == 1);
355
356 nh_to = boost::move(nh_from);
357
358 BOOST_TEST(nh_from.empty());
359 BOOST_TEST(!nh_to.empty());
360 BOOST_TEST(nh_to.get() == from_ptr);
361 BOOST_TEST(nh_to.node_alloc().m_state == MoveConstructed);
362 BOOST_TEST(node_t::count == 1);
363 BOOST_TEST(node_alloc_t::count == 1);
364 }
365
366 //empty = empty
367 {
368 node_alloc_t::reset_count();
369 node_t::reset_count();
370
371 node_handle_set_t nh_from;
372 BOOST_TEST(nh_from.empty());
373 BOOST_TEST(node_t::count == 0);
374 BOOST_TEST(node_alloc_t::count == 0);
375
376 node_handle_set_t nh_to;
377 BOOST_TEST(nh_to.empty());
378 BOOST_TEST(node_t::count == 0);
379 BOOST_TEST(node_alloc_t::count == 0);
380
381 nh_to = boost::move(nh_from);
382
383 BOOST_TEST(nh_from.empty());
384 BOOST_TEST(nh_to.empty());
385 BOOST_TEST(node_t::count == 0);
386 BOOST_TEST(node_alloc_t::count == 0);
387 }
388
389 //full = empty
390 {
391 node_alloc_t::reset_count();
392 node_t::reset_count();
393
394 node_handle_set_t nh_from;
395 BOOST_TEST(nh_from.empty());
396 BOOST_TEST(node_t::count == 0);
397 BOOST_TEST(node_alloc_t::count == 0);
398
399 node_handle_set_t nh_to(new node_t, node_alloc_t());
400 BOOST_TEST(node_t::count == 1);
401 BOOST_TEST(node_alloc_t::count == 1);
402
403 nh_to = boost::move(nh_from);
404
405 BOOST_TEST(nh_from.empty());
406 BOOST_TEST(nh_to.empty());
407 BOOST_TEST(node_t::count == 0);
408 BOOST_TEST(node_alloc_t::count == 0);
409 }
410
411 //full = full
412 {
413 node_alloc_t::reset_count();
414 node_t::reset_count();
415
416 node_t *const from_ptr = new node_t;
417 node_handle_set_t nh_from(from_ptr, node_alloc_t());
418 BOOST_TEST(node_t::count == 1);
419 BOOST_TEST(node_alloc_t::count == 1);
420
421 node_handle_set_t nh_to(new node_t, node_alloc_t());
422 BOOST_TEST(node_t::count == 2);
423 BOOST_TEST(node_alloc_t::count == 2);
424
425 nh_to = boost::move(nh_from);
426
427 BOOST_TEST(nh_from.empty());
428 BOOST_TEST(!nh_to.empty());
429 BOOST_TEST(nh_to.get() == from_ptr);
430 BOOST_TEST(nh_to.node_alloc().m_state == MoveAssigned);
431 BOOST_TEST(node_t::count == 1);
432 BOOST_TEST(node_alloc_t::count == 1);
433 }
434 }
435
test_value_key_mapped()436 void test_value_key_mapped()
437 {
438 //value()
439 {
440 node_t *from_ptr = new node_t;
441 const node_handle_set_t nh_from(from_ptr, node_alloc_t());
442 from_ptr->value.first = -99;
443 from_ptr->value.second = 99;
444 BOOST_TEST(nh_from.value().first == -99);
445 BOOST_TEST(nh_from.value().second == 99);
446 }
447 //key()/mapped()
448 {
449 node_t *from_ptr = new node_t;
450 const node_handle_map_t nh_from(from_ptr, node_alloc_t());
451 from_ptr->value.first = -98;
452 from_ptr->value.second = 98;
453 BOOST_TEST(nh_from.key() == -98);
454 BOOST_TEST(nh_from.mapped() == 98);
455 }
456 }
457
test_get_allocator()458 void test_get_allocator()
459 {
460 const node_handle_set_t nh(new node_t, node_alloc_t(888));
461 allocator_traits<node_alloc_t>::portable_rebind_alloc<test_pair>::type a = nh.get_allocator();
462 BOOST_TEST(a.m_value == 888);
463 }
464
test_bool_conversion_empty()465 void test_bool_conversion_empty()
466 {
467 const node_handle_set_t nh(new node_t, node_alloc_t(777));
468 const node_handle_set_t nh_null;
469 BOOST_TEST(nh && !nh_null);
470 BOOST_TEST(!(!nh || nh_null));
471 BOOST_TEST(!nh.empty() && nh_null.empty());
472 BOOST_TEST(!(nh.empty() || !nh_null.empty()));
473 }
474
test_swap()475 void test_swap()
476 {
477 //empty.swap(full)
478 {
479 node_alloc_t::reset_count();
480 node_t::reset_count();
481 node_t *const from_ptr = new node_t;
482 node_handle_set_t nh_from(from_ptr, node_alloc_t());
483 BOOST_TEST(node_t::count == 1);
484 BOOST_TEST(node_alloc_t::count == 1);
485
486 node_handle_set_t nh_to;
487 BOOST_TEST(nh_to.empty());
488 BOOST_TEST(node_t::count == 1);
489 BOOST_TEST(node_alloc_t::count == 1);
490
491 nh_to.swap(nh_from);
492
493 BOOST_TEST(nh_from.empty());
494 BOOST_TEST(!nh_to.empty());
495 BOOST_TEST(nh_to.get() == from_ptr);
496 BOOST_TEST(nh_to.node_alloc().m_state == MoveConstructed);
497 BOOST_TEST(node_t::count == 1);
498 BOOST_TEST(node_alloc_t::count == 1);
499 }
500
501 //empty.swap(empty)
502 {
503 node_alloc_t::reset_count();
504 node_t::reset_count();
505
506 node_handle_set_t nh_from;
507 BOOST_TEST(nh_from.empty());
508 BOOST_TEST(node_t::count == 0);
509 BOOST_TEST(node_alloc_t::count == 0);
510
511 node_handle_set_t nh_to;
512 BOOST_TEST(nh_to.empty());
513 BOOST_TEST(node_t::count == 0);
514 BOOST_TEST(node_alloc_t::count == 0);
515
516 nh_to.swap(nh_from);
517
518 BOOST_TEST(nh_from.empty());
519 BOOST_TEST(nh_to.empty());
520 BOOST_TEST(node_t::count == 0);
521 BOOST_TEST(node_alloc_t::count == 0);
522 }
523
524 //full.swap(empty)
525 {
526 node_alloc_t::reset_count();
527 node_t::reset_count();
528
529 node_handle_set_t nh_from;
530 BOOST_TEST(nh_from.empty());
531 BOOST_TEST(node_t::count == 0);
532 BOOST_TEST(node_alloc_t::count == 0);
533
534 node_t *const to_ptr = new node_t;
535 node_handle_set_t nh_to(to_ptr, node_alloc_t());
536 BOOST_TEST(node_t::count == 1);
537 BOOST_TEST(node_alloc_t::count == 1);
538
539 nh_to.swap(nh_from);
540
541 BOOST_TEST(!nh_from.empty());
542 BOOST_TEST(nh_from.node_alloc().m_state == MoveConstructed);
543 BOOST_TEST(nh_from.get() == to_ptr);
544 BOOST_TEST(nh_to.empty());
545
546 BOOST_TEST(node_t::count == 1);
547 BOOST_TEST(node_alloc_t::count == 1);
548 }
549
550 //full.swap(full)
551 {
552 node_alloc_t::reset_count();
553 node_t::reset_count();
554
555 node_t *const from_ptr = new node_t;
556 node_handle_set_t nh_from(from_ptr, node_alloc_t());
557 BOOST_TEST(node_t::count == 1);
558 BOOST_TEST(node_alloc_t::count == 1);
559
560 node_t *const to_ptr = new node_t;
561 node_handle_set_t nh_to(to_ptr, node_alloc_t());
562 BOOST_TEST(node_t::count == 2);
563 BOOST_TEST(node_alloc_t::count == 2);
564
565 nh_to.swap(nh_from);
566
567 BOOST_TEST(!nh_from.empty());
568 BOOST_TEST(nh_from.get() == to_ptr);
569 BOOST_TEST(nh_from.node_alloc().m_state == Swapped);
570
571 BOOST_TEST(!nh_to.empty());
572 BOOST_TEST(nh_to.get() == from_ptr);
573 BOOST_TEST(nh_to.node_alloc().m_state == Swapped);
574
575 BOOST_TEST(node_t::count == 2);
576 BOOST_TEST(node_alloc_t::count == 2);
577 }
578 }
579
test_get_release()580 void test_get_release()
581 {
582 //get()
583 {
584 node_alloc_t::reset_count();
585 node_t::reset_count();
586
587 node_t *const ptr = new node_t;
588 const node_handle_set_t nh(ptr, node_alloc_t());
589 BOOST_TEST(node_t::count == 1);
590 BOOST_TEST(node_alloc_t::count == 1);
591
592 BOOST_TEST(nh.get() == ptr);
593 BOOST_TEST(!nh.empty());
594 BOOST_TEST(node_t::count == 1);
595 BOOST_TEST(node_alloc_t::count == 1);
596 }
597 BOOST_TEST(node_t::count == 0);
598 BOOST_TEST(node_alloc_t::count == 0);
599
600 //release()
601 {
602 node_alloc_t::reset_count();
603 node_t::reset_count();
604
605 node_t *const ptr = new node_t;
606 node_handle_set_t nh(ptr, node_alloc_t());
607 BOOST_TEST(node_t::count == 1);
608 BOOST_TEST(node_alloc_t::count == 1);
609
610 BOOST_TEST(nh.release() == ptr);
611 BOOST_TEST(nh.empty());
612 BOOST_TEST(node_t::count == 1);
613 BOOST_TEST(node_alloc_t::count == 0);
614 delete ptr;
615 }
616 BOOST_TEST(node_t::count == 0);
617 }
618
main()619 int main()
620 {
621 test_types();
622 test_default_constructor();
623 test_arg_constructor();
624 test_move_constructor();
625 test_related_constructor();
626 test_move_assignment();
627 test_value_key_mapped();
628 test_get_allocator();
629 test_bool_conversion_empty();
630 test_swap();
631 test_get_release();
632 return ::boost::report_errors();
633 }
634