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