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