• Home
  • Line#
  • Scopes#
  • Navigate#
  • Raw
  • Download
1 //////////////////////////////////////////////////////////////////////////////
2 //
3 // (C) Copyright Ion Gaztanaga 2004-2013. 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 <set>
11 #include <boost/container/set.hpp>
12 #include <boost/container/adaptive_pool.hpp>
13 
14 #include "print_container.hpp"
15 #include "movable_int.hpp"
16 #include "dummy_test_allocator.hpp"
17 #include "set_test.hpp"
18 #include "propagate_allocator_test.hpp"
19 #include "emplace_test.hpp"
20 #include "../../intrusive/test/iterator_test.hpp"
21 
22 using namespace boost::container;
23 
24 //Test recursive structures
25 class recursive_set
26 {
27 public:
operator =(const recursive_set & x)28    recursive_set & operator=(const recursive_set &x)
29    {  id_ = x.id_;  set_ = x.set_; return *this; }
30 
31    int id_;
32    set<recursive_set> set_;
33    set<recursive_set>::iterator it_;
34    set<recursive_set>::const_iterator cit_;
35    set<recursive_set>::reverse_iterator rit_;
36    set<recursive_set>::const_reverse_iterator crit_;
37 
operator <(const recursive_set & a,const recursive_set & b)38    friend bool operator< (const recursive_set &a, const recursive_set &b)
39    {  return a.id_ < b.id_;   }
40 };
41 
42 //Test recursive structures
43 class recursive_multiset
44 {
45    public:
operator =(const recursive_multiset & x)46    recursive_multiset & operator=(const recursive_multiset &x)
47    {  id_ = x.id_;  multiset_ = x.multiset_; return *this;  }
48 
49    int id_;
50    multiset<recursive_multiset> multiset_;
51    multiset<recursive_multiset>::iterator it_;
52    multiset<recursive_multiset>::const_iterator cit_;
53    multiset<recursive_multiset>::reverse_iterator rit_;
54    multiset<recursive_multiset>::const_reverse_iterator crit_;
55 
operator <(const recursive_multiset & a,const recursive_multiset & b)56    friend bool operator< (const recursive_multiset &a, const recursive_multiset &b)
57    {  return a.id_ < b.id_;   }
58 };
59 
60 template<class C>
test_move()61 void test_move()
62 {
63    //Now test move semantics
64    C original;
65    original.emplace();
66    C move_ctor(boost::move(original));
67    C move_assign;
68    move_assign.emplace();
69    move_assign = boost::move(move_ctor);
70    move_assign.swap(original);
71 }
72 
node_type_test()73 bool node_type_test()
74 {
75    using namespace boost::container;
76    {
77       typedef set<test::movable_int> set_type;
78       set_type src;
79       {
80          test::movable_int mv_1(1), mv_2(2), mv_3(3);
81          src.emplace(boost::move(mv_1));
82          src.emplace(boost::move(mv_2));
83          src.emplace(boost::move(mv_3));
84       }
85       if(src.size() != 3)
86          return false;
87 
88       set_type dst;
89       {
90          test::movable_int mv_3(3);
91          dst.emplace(boost::move(mv_3));
92       }
93 
94       if(dst.size() != 1)
95          return false;
96 
97       const test::movable_int mv_1(1);
98       const test::movable_int mv_2(2);
99       const test::movable_int mv_3(3);
100       const test::movable_int mv_33(33);
101       set_type::insert_return_type r;
102 
103       r = dst.insert(src.extract(mv_33)); // Key version, try to insert empty node
104       if(! (r.position == dst.end() && r.inserted == false && r.node.empty()) )
105          return false;
106       r = dst.insert(src.extract(src.find(mv_1))); // Iterator version, successful
107       if(! (r.position == dst.find(mv_1) && r.inserted == true && r.node.empty()) )
108          return false;
109       r = dst.insert(dst.begin(), src.extract(mv_2)); // Key type version, successful
110       if(! (r.position == dst.find(mv_2) && r.inserted == true && r.node.empty()) )
111          return false;
112       r = dst.insert(src.extract(mv_3)); // Key type version, unsuccessful
113 
114       if(!src.empty())
115          return false;
116       if(dst.size() != 3)
117          return false;
118       if(! (r.position == dst.find(mv_3) && r.inserted == false && r.node.value() == mv_3) )
119          return false;
120    }
121 
122    {
123       typedef multiset<test::movable_int> multiset_type;
124       multiset_type src;
125       {
126          test::movable_int mv_1(1), mv_2(2), mv_3(3), mv_3bis(3);
127          src.emplace(boost::move(mv_1));
128          src.emplace(boost::move(mv_2));
129          src.emplace(boost::move(mv_3));
130          src.emplace_hint(src.begin(), boost::move(mv_3bis));
131       }
132       if(src.size() != 4)
133          return false;
134 
135       multiset_type dst;
136       {
137          test::movable_int mv_3(3);
138          dst.emplace(boost::move(mv_3));
139       }
140 
141       if(dst.size() != 1)
142          return false;
143 
144       const test::movable_int mv_1(1);
145       const test::movable_int mv_2(2);
146       const test::movable_int mv_3(3);
147       const test::movable_int mv_4(4);
148       multiset_type::iterator r;
149 
150       multiset_type::node_type nt(src.extract(mv_3));
151       r = dst.insert(dst.begin(), boost::move(nt));
152       if(! (*r == mv_3 && dst.find(mv_3) == r && nt.empty()) )
153          return false;
154 
155       nt = src.extract(src.find(mv_1));
156       r = dst.insert(boost::move(nt)); // Iterator version, successful
157       if(! (*r == mv_1 && nt.empty()) )
158          return false;
159 
160       nt = src.extract(mv_2);
161       r = dst.insert(boost::move(nt)); // Key type version, successful
162       if(! (*r == mv_2 && nt.empty()) )
163          return false;
164 
165       r = dst.insert(src.extract(mv_3)); // Key type version, successful
166       if(! (*r == mv_3 && r == --multiset_type::iterator(dst.upper_bound(mv_3)) && nt.empty()) )
167          return false;
168 
169       r = dst.insert(src.extract(mv_4)); // Key type version, unsuccessful
170       if(! (r == dst.end()) )
171          return false;
172 
173       if(!src.empty())
174          return false;
175       if(dst.size() != 5)
176          return false;
177    }
178    return true;
179 }
180 
181 struct boost_container_set;
182 struct boost_container_multiset;
183 
184 namespace boost {
185 namespace container {
186 namespace test {
187 
188 template<>
189 struct alloc_propagate_base<boost_container_set>
190 {
191    template <class T, class Allocator>
192    struct apply
193    {
194       typedef boost::container::set<T, std::less<T>, Allocator> type;
195    };
196 };
197 
198 template<>
199 struct alloc_propagate_base<boost_container_multiset>
200 {
201    template <class T, class Allocator>
202    struct apply
203    {
204       typedef boost::container::multiset<T, std::less<T>, Allocator> type;
205    };
206 };
207 
constructor_template_auto_deduction_test()208 bool constructor_template_auto_deduction_test()
209 {
210 #ifndef BOOST_CONTAINER_NO_CXX17_CTAD
211    using namespace boost::container;
212    const std::size_t NumElements = 100;
213    {
214       std::set<int> int_set;
215       for (std::size_t i = 0; i != NumElements; ++i) {
216          int_set.insert(static_cast<int>(i));
217       }
218       std::multiset<int> int_mset;
219       for (std::size_t i = 0; i != NumElements; ++i) {
220          int_mset.insert(static_cast<int>(i));
221       }
222 
223       typedef std::less<int> comp_int_t;
224       typedef std::allocator<int> alloc_int_t;
225 
226       //range
227       {
228          auto fset = set(int_set.begin(), int_set.end());
229          if (!CheckEqualContainers(int_set, fset))
230             return false;
231          auto fmset = multiset(int_mset.begin(), int_mset.end());
232          if (!CheckEqualContainers(int_mset, fmset))
233             return false;
234       }
235       //range+comp
236       {
237          auto fset = set(int_set.begin(), int_set.end(), comp_int_t());
238          if (!CheckEqualContainers(int_set, fset))
239             return false;
240          auto fmset = multiset(int_mset.begin(), int_mset.end(), comp_int_t());
241          if (!CheckEqualContainers(int_mset, fmset))
242             return false;
243       }
244       //range+comp+alloc
245       {
246          auto fset = set(int_set.begin(), int_set.end(), comp_int_t(), alloc_int_t());
247          if (!CheckEqualContainers(int_set, fset))
248             return false;
249          auto fmset = multiset(int_mset.begin(), int_mset.end(), comp_int_t(), alloc_int_t());
250          if (!CheckEqualContainers(int_mset, fmset))
251             return false;
252       }
253       //range+alloc
254       {
255          auto fset = set(int_set.begin(), int_set.end(), alloc_int_t());
256          if (!CheckEqualContainers(int_set, fset))
257             return false;
258          auto fmset = multiset(int_mset.begin(), int_mset.end(), alloc_int_t());
259          if (!CheckEqualContainers(int_mset, fmset))
260             return false;
261       }
262 
263       //ordered_unique_range / ordered_range
264 
265       //range
266       {
267          auto fset = set(ordered_unique_range, int_set.begin(), int_set.end());
268          if (!CheckEqualContainers(int_set, fset))
269             return false;
270          auto fmset = multiset(ordered_range, int_mset.begin(), int_mset.end());
271          if (!CheckEqualContainers(int_mset, fmset))
272             return false;
273       }
274       //range+comp
275       {
276          auto fset = set(ordered_unique_range, int_set.begin(), int_set.end(), comp_int_t());
277          if (!CheckEqualContainers(int_set, fset))
278             return false;
279          auto fmset = multiset(ordered_range, int_mset.begin(), int_mset.end(), comp_int_t());
280          if (!CheckEqualContainers(int_mset, fmset))
281             return false;
282       }
283       //range+comp+alloc
284       {
285          auto fset = set(ordered_unique_range, int_set.begin(), int_set.end(), comp_int_t(), alloc_int_t());
286          if (!CheckEqualContainers(int_set, fset))
287             return false;
288          auto fmset = multiset(ordered_range, int_mset.begin(), int_mset.end(), comp_int_t(), alloc_int_t());
289          if (!CheckEqualContainers(int_mset, fmset))
290             return false;
291       }
292       //range+alloc
293       {
294          auto fset = set(ordered_unique_range, int_set.begin(), int_set.end(), alloc_int_t());
295          if (!CheckEqualContainers(int_set, fset))
296             return false;
297          auto fmset = multiset(ordered_range, int_mset.begin(), int_mset.end(), alloc_int_t());
298          if (!CheckEqualContainers(int_mset, fmset))
299             return false;
300       }
301    }
302 #endif
303    return true;
304 }
305 
306 }}}   //boost::container::test
307 
308 template<class VoidAllocator, boost::container::tree_type_enum tree_type_value>
309 struct GetAllocatorSet
310 {
311    template<class ValueType>
312    struct apply
313    {
314       typedef set < ValueType
315                   , std::less<ValueType>
316                   , typename allocator_traits<VoidAllocator>
317                      ::template portable_rebind_alloc<ValueType>::type
318                   , typename boost::container::tree_assoc_options
319                         < boost::container::tree_type<tree_type_value>
320                         >::type
321                   > set_type;
322 
323       typedef multiset < ValueType
324                   , std::less<ValueType>
325                   , typename allocator_traits<VoidAllocator>
326                      ::template portable_rebind_alloc<ValueType>::type
327                   , typename boost::container::tree_assoc_options
328                         < boost::container::tree_type<tree_type_value>
329                         >::type
330                   > multiset_type;
331    };
332 };
333 
test_merge_from_different_comparison()334 void test_merge_from_different_comparison()
335 {
336    set<int> set1;
337    set<int, std::greater<int> > set2;
338    set1.merge(set2);
339 }
340 
test_heterogeneous_lookups()341 bool test_heterogeneous_lookups()
342 {
343    typedef set<int, test::less_transparent> set_t;
344    typedef multiset<int, test::less_transparent> mset_t;
345 
346    set_t set1;
347    mset_t mset1;
348 
349    const set_t &cset1 = set1;
350    const mset_t &cmset1 = mset1;
351 
352    set1.insert(1);
353    set1.insert(1);
354    set1.insert(2);
355    set1.insert(2);
356    set1.insert(3);
357 
358    mset1.insert(1);
359    mset1.insert(1);
360    mset1.insert(2);
361    mset1.insert(2);
362    mset1.insert(3);
363 
364    const test::non_copymovable_int find_me(2);
365 
366    //find
367    if(*set1.find(find_me) != 2)
368       return false;
369    if(*cset1.find(find_me) != 2)
370       return false;
371    if(*mset1.find(find_me) != 2)
372       return false;
373    if(*cmset1.find(find_me) != 2)
374       return false;
375 
376    //count
377    if(set1.count(find_me) != 1)
378       return false;
379    if(cset1.count(find_me) != 1)
380       return false;
381    if(mset1.count(find_me) != 2)
382       return false;
383    if(cmset1.count(find_me) != 2)
384       return false;
385 
386    //contains
387    if(!set1.contains(find_me))
388       return false;
389    if(!cset1.contains(find_me))
390       return false;
391    if(!mset1.contains(find_me))
392       return false;
393    if(!cmset1.contains(find_me))
394       return false;
395 
396    //lower_bound
397    if(*set1.lower_bound(find_me) != 2)
398       return false;
399    if(*cset1.lower_bound(find_me) != 2)
400       return false;
401    if(*mset1.lower_bound(find_me) != 2)
402       return false;
403    if(*cmset1.lower_bound(find_me) != 2)
404       return false;
405 
406    //upper_bound
407    if(*set1.upper_bound(find_me) != 3)
408       return false;
409    if(*cset1.upper_bound(find_me) != 3)
410       return false;
411    if(*mset1.upper_bound(find_me) != 3)
412       return false;
413    if(*cmset1.upper_bound(find_me) != 3)
414       return false;
415 
416    //equal_range
417    if(*set1.equal_range(find_me).first != 2)
418       return false;
419    if(*cset1.equal_range(find_me).second != 3)
420       return false;
421    if(*mset1.equal_range(find_me).first != 2)
422       return false;
423    if(*cmset1.equal_range(find_me).second != 3)
424       return false;
425 
426    return true;
427 }
428 
main()429 int main ()
430 {
431    //Recursive container instantiation
432    {
433       set<recursive_set> set_;
434       multiset<recursive_multiset> multiset_;
435    }
436    //Allocator argument container
437    {
438       set<int> set_((set<int>::allocator_type()));
439       multiset<int> multiset_((multiset<int>::allocator_type()));
440    }
441    //Now test move semantics
442    {
443       test_move<set<recursive_set> >();
444       test_move<multiset<recursive_multiset> >();
445    }
446    //Test std::pair value type as tree has workarounds to make old std::pair
447    //implementations movable that can break things
448    {
449       boost::container::set<std::pair<int,int> > s;
450       std::pair<int,int> p(0, 0);
451       s.insert(p);
452       s.emplace(p);
453    }
454 
455    if (!boost::container::test::instantiate_constructors<set<int>, multiset<int> >())
456       return 1;
457 
458    test_merge_from_different_comparison();
459 
460    ////////////////////////////////////
461    //    Constructor Template Auto Deduction test
462    ////////////////////////////////////
463    if (!test::constructor_template_auto_deduction_test()) {
464       return 1;
465    }
466 
467    if(!test_heterogeneous_lookups())
468       return 1;
469 
470    ////////////////////////////////////
471    //    Testing allocator implementations
472    ////////////////////////////////////
473    {
474       typedef std::set<int>                                          MyStdSet;
475       typedef std::multiset<int>                                     MyStdMultiSet;
476 
477       if (0 != test::set_test
478          < GetAllocatorSet<std::allocator<void>, red_black_tree>::apply<int>::set_type
479          , MyStdSet
480          , GetAllocatorSet<std::allocator<void>, red_black_tree>::apply<int>::multiset_type
481          , MyStdMultiSet>()) {
482          std::cout << "Error in set_test<std::allocator<void>, red_black_tree>" << std::endl;
483          return 1;
484       }
485 
486       if (0 != test::set_test
487          < GetAllocatorSet<new_allocator<void>, avl_tree>::apply<int>::set_type
488          , MyStdSet
489          , GetAllocatorSet<new_allocator<void>, avl_tree>::apply<int>::multiset_type
490          , MyStdMultiSet>()) {
491          std::cout << "Error in set_test<new_allocator<void>, avl_tree>" << std::endl;
492          return 1;
493       }
494 
495       if (0 != test::set_test
496          < GetAllocatorSet<adaptive_pool<void>, scapegoat_tree>::apply<int>::set_type
497          , MyStdSet
498          , GetAllocatorSet<adaptive_pool<void>, scapegoat_tree>::apply<int>::multiset_type
499          , MyStdMultiSet>()) {
500          std::cout << "Error in set_test<adaptive_pool<void>, scapegoat_tree>" << std::endl;
501          return 1;
502       }
503 
504       ///////////
505 
506      if (0 != test::set_test
507          < GetAllocatorSet<new_allocator<void>, splay_tree>::apply<test::movable_int>::set_type
508          , MyStdSet
509          , GetAllocatorSet<new_allocator<void>, splay_tree>::apply<test::movable_int>::multiset_type
510          , MyStdMultiSet>()) {
511          std::cout << "Error in set_test<new_allocator<void>, splay_tree>" << std::endl;
512          return 1;
513       }
514 
515       if (0 != test::set_test
516          < GetAllocatorSet<new_allocator<void>, red_black_tree>::apply<test::copyable_int>::set_type
517          , MyStdSet
518          , GetAllocatorSet<new_allocator<void>, red_black_tree>::apply<test::copyable_int>::multiset_type
519          , MyStdMultiSet>()) {
520          std::cout << "Error in set_test<new_allocator<void>, red_black_tree>" << std::endl;
521          return 1;
522       }
523 
524       if (0 != test::set_test
525          < GetAllocatorSet<new_allocator<void>, red_black_tree>::apply<test::movable_and_copyable_int>::set_type
526          , MyStdSet
527          , GetAllocatorSet<new_allocator<void>, red_black_tree>::apply<test::movable_and_copyable_int>::multiset_type
528          , MyStdMultiSet>()) {
529          std::cout << "Error in set_test<new_allocator<void>, red_black_tree>" << std::endl;
530          return 1;
531       }
532    }
533 
534    ////////////////////////////////////
535    //    Emplace testing
536    ////////////////////////////////////
537    const test::EmplaceOptions SetOptions = (test::EmplaceOptions)(test::EMPLACE_HINT | test::EMPLACE_ASSOC);
538    if(!boost::container::test::test_emplace<set<test::EmplaceInt>, SetOptions>())
539       return 1;
540    if(!boost::container::test::test_emplace<multiset<test::EmplaceInt>, SetOptions>())
541       return 1;
542 
543    ////////////////////////////////////
544    //    Allocator propagation testing
545    ////////////////////////////////////
546    if(!boost::container::test::test_propagate_allocator<boost_container_set>())
547       return 1;
548 
549    if(!boost::container::test::test_propagate_allocator<boost_container_multiset>())
550       return 1;
551 
552    if (!boost::container::test::test_set_methods_with_initializer_list_as_argument_for<set<int> >())
553       return 1;
554 
555    if (!boost::container::test::test_set_methods_with_initializer_list_as_argument_for<multiset<int> >())
556       return 1;
557 
558    ////////////////////////////////////
559    //    Test optimize_size option
560    ////////////////////////////////////
561    //
562    // set
563    //
564    typedef set< int*, std::less<int*>, std::allocator<int*>
565               , tree_assoc_options< optimize_size<false>, tree_type<red_black_tree> >::type > rbset_size_optimized_no;
566 
567    typedef set< int*, std::less<int*>, std::allocator<int*>
568               , tree_assoc_options< optimize_size<true>, tree_type<avl_tree>  >::type > avlset_size_optimized_yes;
569    //
570    // multiset
571    //
572    typedef multiset< int*, std::less<int*>, std::allocator<int*>
573                    , tree_assoc_options< optimize_size<true>, tree_type<red_black_tree>  >::type > rbmset_size_optimized_yes;
574 
575    typedef multiset< int*, std::less<int*>, std::allocator<int*>
576                    , tree_assoc_options< optimize_size<false>, tree_type<avl_tree> >::type > avlmset_size_optimized_no;
577 
578    BOOST_STATIC_ASSERT(sizeof(rbmset_size_optimized_yes) < sizeof(rbset_size_optimized_no));
579    BOOST_STATIC_ASSERT(sizeof(avlset_size_optimized_yes) < sizeof(avlmset_size_optimized_no));
580 
581    ////////////////////////////////////
582    //    Iterator testing
583    ////////////////////////////////////
584    {
585       typedef boost::container::set<int> cont_int;
586       cont_int a; a.insert(0); a.insert(1); a.insert(2);
587       boost::intrusive::test::test_iterator_bidirectional< cont_int >(a);
588       if(boost::report_errors() != 0) {
589          return 1;
590       }
591    }
592    {
593       typedef boost::container::multiset<int> cont_int;
594       cont_int a; a.insert(0); a.insert(1); a.insert(2);
595       boost::intrusive::test::test_iterator_bidirectional< cont_int >(a);
596       if(boost::report_errors() != 0) {
597          return 1;
598       }
599    }
600 
601    ////////////////////////////////////
602    //    Node extraction/insertion testing functions
603    ////////////////////////////////////
604    if(!node_type_test())
605       return 1;
606 
607    ////////////////////////////////////
608    //    has_trivial_destructor_after_move testing
609    ////////////////////////////////////
610    // set, default allocator
611    {
612       typedef boost::container::set<int> cont;
613       typedef boost::container::dtl::tree<int, void, std::less<int>, void, void> tree;
614       if (boost::has_trivial_destructor_after_move<cont>::value !=
615           boost::has_trivial_destructor_after_move<tree>::value) {
616          std::cerr << "has_trivial_destructor_after_move(set, default allocator) test failed" << std::endl;
617          return 1;
618       }
619    }
620    // set, std::allocator
621    {
622       typedef boost::container::set<int, std::less<int>, std::allocator<int> > cont;
623       typedef boost::container::dtl::tree<int, void, std::less<int>, std::allocator<int>, void> tree;
624       if (boost::has_trivial_destructor_after_move<cont>::value !=
625           boost::has_trivial_destructor_after_move<tree>::value) {
626          std::cerr << "has_trivial_destructor_after_move(set, std::allocator) test failed" << std::endl;
627          return 1;
628       }
629    }
630    // multiset, default allocator
631    {
632       typedef boost::container::multiset<int> cont;
633       typedef boost::container::dtl::tree<int, void, std::less<int>, void, void> tree;
634       if (boost::has_trivial_destructor_after_move<cont>::value !=
635           boost::has_trivial_destructor_after_move<tree>::value) {
636          std::cerr << "has_trivial_destructor_after_move(multiset, default allocator) test failed" << std::endl;
637          return 1;
638       }
639    }
640    // multiset, std::allocator
641    {
642       typedef boost::container::multiset<int, std::less<int>, std::allocator<int> > cont;
643       typedef boost::container::dtl::tree<int, void, std::less<int>, std::allocator<int>, void> tree;
644       if (boost::has_trivial_destructor_after_move<cont>::value !=
645           boost::has_trivial_destructor_after_move<tree>::value) {
646          std::cerr << "has_trivial_destructor_after_move(multiset, std::allocator) test failed" << std::endl;
647          return 1;
648       }
649    }
650 
651    return 0;
652 }
653