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