re PR c++/24163 (dependent Base class scope examined during unqualified name lookup...
[gcc.git] / libstdc++-v3 / testsuite / util / exception / safety.h
1 // -*- C++ -*-
2
3 // Copyright (C) 2009, 2010 Free Software Foundation, Inc.
4 //
5 // This file is part of the GNU ISO C++ Library. This library is free
6 // software; you can redistribute it and/or modify it under the terms
7 // of the GNU General Public License as published by the Free Software
8 // Foundation; either version 3, or (at your option) any later
9 // version.
10
11 // This library is distributed in the hope that it will be useful, but
12 // WITHOUT ANY WARRANTY; without even the implied warranty of
13 // MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
14 // General Public License for more details.
15
16 // You should have received a copy of the GNU General Public License along
17 // with this library; see the file COPYING3. If not see
18 // <http://www.gnu.org/licenses/>.
19
20 #ifndef _GLIBCXX_EXCEPTION_SAFETY_H
21 #define _GLIBCXX_EXCEPTION_SAFETY_H
22
23 #include <testsuite_container_traits.h>
24 #include <ext/throw_allocator.h>
25
26 // Container requirement testing.
27 namespace __gnu_test
28 {
29 // Base class for exception testing, contains utilities.
30 struct setup_base
31 {
32 typedef std::size_t size_type;
33 typedef std::uniform_int_distribution<size_type> distribution_type;
34 typedef std::mt19937 engine_type;
35
36 // Return randomly generated integer on range [0, __max_size].
37 static size_type
38 generate(size_type __max_size)
39 {
40 // Make the generator static...
41 const engine_type engine;
42 const distribution_type distribution;
43 static auto generator = std::bind(distribution, engine,
44 std::placeholders::_1);
45
46 // ... but set the range for this particular invocation here.
47 const typename distribution_type::param_type p(0, __max_size);
48 size_type random = generator(p);
49 if (random < distribution.min() || random > distribution.max())
50 {
51 std::string __s("setup_base::generate");
52 __s += "\n";
53 __s += "random number generated is: ";
54 char buf[40];
55 __builtin_sprintf(buf, "%lu", (unsigned long)random);
56 __s += buf;
57 __s += " on range [";
58 __builtin_sprintf(buf, "%lu", (unsigned long)distribution.min());
59 __s += buf;
60 __s += ", ";
61 __builtin_sprintf(buf, "%lu", (unsigned long)distribution.max());
62 __s += buf;
63 __s += "]\n";
64 std::__throw_out_of_range(__s.c_str());
65 }
66 return random;
67 }
68
69 // Given an instantiating type, return a unique value.
70 template<typename _Tp>
71 struct generate_unique
72 {
73 typedef _Tp value_type;
74
75 operator value_type()
76 {
77 static value_type __ret;
78 ++__ret;
79 return __ret;
80 }
81 };
82
83 // Partial specialization for pair.
84 template<typename _Tp1, typename _Tp2>
85 struct generate_unique<std::pair<const _Tp1, _Tp2>>
86 {
87 typedef _Tp1 first_type;
88 typedef _Tp2 second_type;
89 typedef std::pair<const _Tp1, _Tp2> pair_type;
90
91 operator pair_type()
92 {
93 static first_type _S_1;
94 static second_type _S_2;
95 ++_S_1;
96 ++_S_2;
97 return pair_type(_S_1, _S_2);
98 }
99 };
100
101 // Partial specialization for throw_value
102 template<typename _Cond>
103 struct generate_unique<__gnu_cxx::throw_value_base<_Cond>>
104 {
105 typedef __gnu_cxx::throw_value_base<_Cond> value_type;
106
107 operator value_type()
108 {
109 static size_t _S_i(0);
110 return value_type(_S_i++);
111 }
112 };
113
114
115 // Construct container of size n directly. _Tp == container type.
116 template<typename _Tp>
117 struct make_container_base
118 {
119 _Tp _M_container;
120
121 make_container_base() = default;
122 make_container_base(const size_type n): _M_container(n) { }
123
124 operator _Tp&() { return _M_container; }
125 };
126
127 // Construct container of size n, via multiple insertions. For
128 // associated and unordered types, unique value_type elements are
129 // necessary.
130 template<typename _Tp, bool = traits<_Tp>::is_mapped::value>
131 struct make_insert_container_base
132 : public make_container_base<_Tp>
133 {
134 using make_container_base<_Tp>::_M_container;
135 typedef typename _Tp::value_type value_type;
136
137 make_insert_container_base(const size_type n)
138 {
139 for (size_type i = 0; i < n; ++i)
140 {
141 value_type v = generate_unique<value_type>();
142 _M_container.insert(v);
143 }
144 assert(_M_container.size() == n);
145 }
146 };
147
148 template<typename _Tp>
149 struct make_insert_container_base<_Tp, false>
150 : public make_container_base<_Tp>
151 {
152 using make_container_base<_Tp>::_M_container;
153 typedef typename _Tp::value_type value_type;
154
155 make_insert_container_base(const size_type n)
156 {
157 for (size_type i = 0; i < n; ++i)
158 {
159 value_type v = generate_unique<value_type>();
160 _M_container.insert(_M_container.end(), v);
161 }
162 assert(_M_container.size() == n);
163 }
164 };
165
166 template<typename _Tp, bool = traits<_Tp>::has_size_type_constructor::value>
167 struct make_container_n;
168
169 // Specialization for non-associative types that have a constructor with
170 // a size argument.
171 template<typename _Tp>
172 struct make_container_n<_Tp, true>
173 : public make_container_base<_Tp>
174 {
175 make_container_n(const size_type n) : make_container_base<_Tp>(n) { }
176 };
177
178 template<typename _Tp>
179 struct make_container_n<_Tp, false>
180 : public make_insert_container_base<_Tp>
181 {
182 make_container_n(const size_type n)
183 : make_insert_container_base<_Tp>(n) { }
184 };
185
186
187 // Randomly size and populate a given container reference.
188 // NB: Responsibility for turning off exceptions lies with caller.
189 template<typename _Tp, bool = traits<_Tp>::is_allocator_aware::value>
190 struct populate
191 {
192 typedef _Tp container_type;
193 typedef typename container_type::allocator_type allocator_type;
194 typedef typename container_type::value_type value_type;
195
196 populate(_Tp& __container)
197 {
198 const allocator_type a = __container.get_allocator();
199
200 // Size test container.
201 const size_type max_elements = 100;
202 size_type n = generate(max_elements);
203
204 // Construct new container.
205 make_container_n<container_type> made(n);
206 container_type& tmp = made;
207 std::swap(tmp, __container);
208 }
209 };
210
211 // Partial specialization, empty.
212 template<typename _Tp>
213 struct populate<_Tp, false>
214 {
215 populate(_Tp&) { }
216 };
217
218 // Compare two containers for equivalence.
219 // Right now, that means size.
220 // Returns true if equal, throws if not.
221 template<typename _Tp>
222 static bool
223 compare(const _Tp& __control, const _Tp& __test)
224 {
225 // Make sure test container is in a consistent state, as
226 // compared to the control container.
227 // NB: Should be equivalent to __test != __control, but
228 // computed without equivalence operators
229 const size_type szt = std::distance(__test.begin(), __test.end());
230 const size_type szc = std::distance(__control.begin(),
231 __control.end());
232 bool __equal_size = szt == szc;
233
234 // Should test iterator validity before and after exception.
235 bool __equal_it = std::equal(__test.begin(), __test.end(),
236 __control.begin());
237
238 if (!__equal_size || !__equal_it)
239 throw std::logic_error("setup_base::compare containers not equal");
240
241 return true;
242 }
243 };
244
245
246 // Containing structure holding functors.
247 struct functor_base : public setup_base
248 {
249 // Abstract the erase function.
250 template<typename _Tp>
251 struct erase_base
252 {
253 typedef typename _Tp::iterator iterator;
254 typedef typename _Tp::const_iterator const_iterator;
255
256 iterator (_Tp::* _F_erase_point)(const_iterator);
257 iterator (_Tp::* _F_erase_range)(const_iterator, const_iterator);
258
259 erase_base()
260 : _F_erase_point(&_Tp::erase), _F_erase_range(&_Tp::erase) { }
261 };
262
263 // Specializations, old C++03 signatures.
264 template<typename _Tp1, typename _Tp2, typename _Tp3>
265 struct erase_base<std::basic_string<_Tp1, _Tp2, _Tp3>>
266 {
267 typedef std::basic_string<_Tp1, _Tp2, _Tp3> container_type;
268 typedef typename container_type::iterator iterator;
269
270 iterator (container_type::* _F_erase_point)(iterator);
271 iterator (container_type::* _F_erase_range)(iterator, iterator);
272
273 erase_base()
274 : _F_erase_point(&container_type::erase),
275 _F_erase_range(&container_type::erase) { }
276 };
277
278 template<typename _Tp1, typename _Tp2, typename _Tp3,
279 template <typename, typename, typename> class _Tp4>
280 struct erase_base<__gnu_cxx::__versa_string<_Tp1, _Tp2, _Tp3, _Tp4>>
281 {
282 typedef __gnu_cxx::__versa_string<_Tp1, _Tp2, _Tp3, _Tp4>
283 container_type;
284 typedef typename container_type::iterator iterator;
285
286 iterator (container_type::* _F_erase_point)(iterator);
287 iterator (container_type::* _F_erase_range)(iterator, iterator);
288
289 erase_base()
290 : _F_erase_point(&container_type::erase),
291 _F_erase_range(&container_type::erase) { }
292 };
293
294 template<typename _Tp1, typename _Tp2>
295 struct erase_base<std::deque<_Tp1, _Tp2>>
296 {
297 typedef std::deque<_Tp1, _Tp2> container_type;
298 typedef typename container_type::iterator iterator;
299
300 iterator (container_type::* _F_erase_point)(iterator);
301 iterator (container_type::* _F_erase_range)(iterator, iterator);
302
303 erase_base()
304 : _F_erase_point(&container_type::erase),
305 _F_erase_range(&container_type::erase) { }
306 };
307
308 template<typename _Tp1, typename _Tp2>
309 struct erase_base<std::list<_Tp1, _Tp2>>
310 {
311 typedef std::list<_Tp1, _Tp2> container_type;
312 typedef typename container_type::iterator iterator;
313
314 iterator (container_type::* _F_erase_point)(iterator);
315 iterator (container_type::* _F_erase_range)(iterator, iterator);
316
317 erase_base()
318 : _F_erase_point(&container_type::erase),
319 _F_erase_range(&container_type::erase) { }
320 };
321
322 template<typename _Tp1, typename _Tp2>
323 struct erase_base<std::vector<_Tp1, _Tp2>>
324 {
325 typedef std::vector<_Tp1, _Tp2> container_type;
326 typedef typename container_type::iterator iterator;
327
328 iterator (container_type::* _F_erase_point)(iterator);
329 iterator (container_type::* _F_erase_range)(iterator, iterator);
330
331 erase_base()
332 : _F_erase_point(&container_type::erase),
333 _F_erase_range(&container_type::erase) { }
334 };
335
336 // Specialization, as forward_list has erase_after.
337 template<typename _Tp1, typename _Tp2>
338 struct erase_base<std::forward_list<_Tp1, _Tp2>>
339 {
340 typedef std::forward_list<_Tp1, _Tp2> container_type;
341 typedef typename container_type::iterator iterator;
342 typedef typename container_type::const_iterator const_iterator;
343
344 iterator (container_type::* _F_erase_point)(const_iterator);
345 iterator (container_type::* _F_erase_range)(const_iterator,
346 const_iterator);
347
348 erase_base()
349 : _F_erase_point(&container_type::erase_after),
350 _F_erase_range(&container_type::erase_after) { }
351 };
352
353 template<typename _Tp,
354 bool = traits<_Tp>::has_erase::value,
355 bool = traits<_Tp>::has_erase_after::value>
356 struct erase_point;
357
358 // Specialization for most containers.
359 template<typename _Tp>
360 struct erase_point<_Tp, true, false> : public erase_base<_Tp>
361 {
362 using erase_base<_Tp>::_F_erase_point;
363
364 void
365 operator()(_Tp& __container)
366 {
367 try
368 {
369 // NB: Should be equivalent to size() member function, but
370 // computed with begin() and end().
371 const size_type sz = std::distance(__container.begin(),
372 __container.end());
373
374 // NB: Lowest common denominator: use forward iterator operations.
375 auto i = __container.begin();
376 std::advance(i, generate(sz));
377
378 // Makes it easier to think of this as __container.erase(i)
379 (__container.*_F_erase_point)(i);
380 }
381 catch(const __gnu_cxx::forced_error&)
382 { throw; }
383 }
384 };
385
386 // Specialization for forward_list.
387 template<typename _Tp>
388 struct erase_point<_Tp, false, true> : public erase_base<_Tp>
389 {
390 using erase_base<_Tp>::_F_erase_point;
391
392 void
393 operator()(_Tp& __container)
394 {
395 try
396 {
397 // NB: Should be equivalent to size() member function, but
398 // computed with begin() and end().
399 const size_type sz = std::distance(__container.begin(),
400 __container.end());
401
402 // NB: Lowest common denominator: use forward iterator operations.
403 auto i = __container.before_begin();
404 std::advance(i, generate(sz));
405
406 // Makes it easier to think of this as __container.erase(i)
407 (__container.*_F_erase_point)(i);
408 }
409 catch(const __gnu_cxx::forced_error&)
410 { throw; }
411 }
412 };
413
414 // Specialization, empty.
415 template<typename _Tp>
416 struct erase_point<_Tp, false, false>
417 {
418 void
419 operator()(_Tp&) { }
420 };
421
422
423 template<typename _Tp,
424 bool = traits<_Tp>::has_erase::value,
425 bool = traits<_Tp>::has_erase_after::value>
426 struct erase_range;
427
428 // Specialization for most containers.
429 template<typename _Tp>
430 struct erase_range<_Tp, true, false> : public erase_base<_Tp>
431 {
432 using erase_base<_Tp>::_F_erase_range;
433
434 void
435 operator()(_Tp& __container)
436 {
437 try
438 {
439 const size_type sz = std::distance(__container.begin(),
440 __container.end());
441 size_type s1 = generate(sz);
442 size_type s2 = generate(sz);
443 auto i1 = __container.begin();
444 auto i2 = __container.begin();
445 std::advance(i1, std::min(s1, s2));
446 std::advance(i2, std::max(s1, s2));
447
448 // Makes it easier to think of this as __container.erase(i1, i2).
449 (__container.*_F_erase_range)(i1, i2);
450 }
451 catch(const __gnu_cxx::forced_error&)
452 { throw; }
453 }
454 };
455
456 // Specialization for forward_list.
457 template<typename _Tp>
458 struct erase_range<_Tp, false, true> : public erase_base<_Tp>
459 {
460 using erase_base<_Tp>::_F_erase_range;
461
462 void
463 operator()(_Tp& __container)
464 {
465 try
466 {
467 const size_type sz = std::distance(__container.begin(),
468 __container.end());
469 size_type s1 = generate(sz);
470 size_type s2 = generate(sz);
471 auto i1 = __container.before_begin();
472 auto i2 = __container.before_begin();
473 std::advance(i1, std::min(s1, s2));
474 std::advance(i2, std::max(s1, s2));
475
476 // Makes it easier to think of this as __container.erase(i1, i2).
477 (__container.*_F_erase_range)(i1, i2);
478 }
479 catch(const __gnu_cxx::forced_error&)
480 { throw; }
481 }
482 };
483
484 // Specialization, empty.
485 template<typename _Tp>
486 struct erase_range<_Tp, false, false>
487 {
488 void
489 operator()(_Tp&) { }
490 };
491
492
493 template<typename _Tp, bool = traits<_Tp>::has_push_pop::value>
494 struct pop_front
495 {
496 void
497 operator()(_Tp& __container)
498 {
499 try
500 {
501 __container.pop_front();
502 }
503 catch(const __gnu_cxx::forced_error&)
504 { throw; }
505 }
506 };
507
508 // Specialization, empty.
509 template<typename _Tp>
510 struct pop_front<_Tp, false>
511 {
512 void
513 operator()(_Tp&) { }
514 };
515
516
517 template<typename _Tp, bool = traits<_Tp>::has_push_pop::value
518 && traits<_Tp>::is_reversible::value>
519 struct pop_back
520 {
521 void
522 operator()(_Tp& __container)
523 {
524 try
525 {
526 __container.pop_back();
527 }
528 catch(const __gnu_cxx::forced_error&)
529 { throw; }
530 }
531 };
532
533 // Specialization, empty.
534 template<typename _Tp>
535 struct pop_back<_Tp, false>
536 {
537 void
538 operator()(_Tp&) { }
539 };
540
541
542 template<typename _Tp, bool = traits<_Tp>::has_push_pop::value>
543 struct push_front
544 {
545 typedef _Tp container_type;
546 typedef typename container_type::value_type value_type;
547
548 void
549 operator()(_Tp& __test)
550 {
551 try
552 {
553 const value_type cv = generate_unique<value_type>();
554 __test.push_front(cv);
555 }
556 catch(const __gnu_cxx::forced_error&)
557 { throw; }
558 }
559
560 // Assumes containers start out equivalent.
561 void
562 operator()(_Tp& __control, _Tp& __test)
563 {
564 try
565 {
566 const value_type cv = generate_unique<value_type>();
567 __test.push_front(cv);
568 }
569 catch(const __gnu_cxx::forced_error&)
570 { throw; }
571 }
572 };
573
574 // Specialization, empty.
575 template<typename _Tp>
576 struct push_front<_Tp, false>
577 {
578 void
579 operator()(_Tp&) { }
580
581 void
582 operator()(_Tp&, _Tp&) { }
583 };
584
585
586 template<typename _Tp, bool = traits<_Tp>::has_push_pop::value
587 && traits<_Tp>::is_reversible::value>
588 struct push_back
589 {
590 typedef _Tp container_type;
591 typedef typename container_type::value_type value_type;
592
593 void
594 operator()(_Tp& __test)
595 {
596 try
597 {
598 const value_type cv = generate_unique<value_type>();
599 __test.push_back(cv);
600 }
601 catch(const __gnu_cxx::forced_error&)
602 { throw; }
603 }
604
605 // Assumes containers start out equivalent.
606 void
607 operator()(_Tp& __control, _Tp& __test)
608 {
609 try
610 {
611 const value_type cv = generate_unique<value_type>();
612 __test.push_back(cv);
613 }
614 catch(const __gnu_cxx::forced_error&)
615 { throw; }
616 }
617 };
618
619 // Specialization, empty.
620 template<typename _Tp>
621 struct push_back<_Tp, false>
622 {
623 void
624 operator()(_Tp&) { }
625
626 void
627 operator()(_Tp&, _Tp&) { }
628 };
629
630
631 // Abstract the insert function into two parts:
632 // 1, insert_base_functions == holds function pointer
633 // 2, insert_base == links function pointer to class insert method
634 template<typename _Tp>
635 struct insert_base
636 {
637 typedef typename _Tp::iterator iterator;
638 typedef typename _Tp::const_iterator const_iterator;
639 typedef typename _Tp::value_type value_type;
640
641 iterator (_Tp::* _F_insert_point)(const_iterator, const value_type&);
642
643 insert_base() : _F_insert_point(&_Tp::insert) { }
644 };
645
646 // Specializations, old C++03 signatures.
647 template<typename _Tp1, typename _Tp2>
648 struct insert_base<std::deque<_Tp1, _Tp2>>
649 {
650 typedef std::deque<_Tp1, _Tp2> container_type;
651 typedef typename container_type::iterator iterator;
652 typedef typename container_type::value_type value_type;
653
654 iterator (container_type::* _F_insert_point)(iterator,
655 const value_type&);
656
657 insert_base() : _F_insert_point(&container_type::insert) { }
658 };
659
660 template<typename _Tp1, typename _Tp2>
661 struct insert_base<std::list<_Tp1, _Tp2>>
662 {
663 typedef std::list<_Tp1, _Tp2> container_type;
664 typedef typename container_type::iterator iterator;
665 typedef typename container_type::value_type value_type;
666
667 iterator (container_type::* _F_insert_point)(iterator,
668 const value_type&);
669
670 insert_base() : _F_insert_point(&container_type::insert) { }
671 };
672
673 template<typename _Tp1, typename _Tp2>
674 struct insert_base<std::vector<_Tp1, _Tp2>>
675 {
676 typedef std::vector<_Tp1, _Tp2> container_type;
677 typedef typename container_type::iterator iterator;
678 typedef typename container_type::value_type value_type;
679
680 iterator (container_type::* _F_insert_point)(iterator,
681 const value_type&);
682
683 insert_base() : _F_insert_point(&container_type::insert) { }
684 };
685
686 // Specialization, as string insertion has a different signature.
687 template<typename _Tp1, typename _Tp2, typename _Tp3>
688 struct insert_base<std::basic_string<_Tp1, _Tp2, _Tp3>>
689 {
690 typedef std::basic_string<_Tp1, _Tp2, _Tp3> container_type;
691 typedef typename container_type::iterator iterator;
692 typedef typename container_type::value_type value_type;
693
694 iterator (container_type::* _F_insert_point)(iterator, value_type);
695
696 insert_base() : _F_insert_point(&container_type::insert) { }
697 };
698
699 // Likewise for __versa_string.
700 template<typename _Tp1, typename _Tp2, typename _Tp3,
701 template <typename, typename, typename> class _Tp4>
702 struct insert_base<__gnu_cxx::__versa_string<_Tp1, _Tp2, _Tp3, _Tp4>>
703 {
704 typedef __gnu_cxx::__versa_string<_Tp1, _Tp2, _Tp3, _Tp4>
705 container_type;
706 typedef typename container_type::iterator iterator;
707 typedef typename container_type::value_type value_type;
708
709 iterator (container_type::* _F_insert_point)(iterator, value_type);
710
711 insert_base() : _F_insert_point(&container_type::insert) { }
712 };
713
714 // Specialization, as forward_list has insert_after.
715 template<typename _Tp1, typename _Tp2>
716 struct insert_base<std::forward_list<_Tp1, _Tp2>>
717 {
718 typedef std::forward_list<_Tp1, _Tp2> container_type;
719 typedef typename container_type::iterator iterator;
720 typedef typename container_type::const_iterator const_iterator;
721 typedef typename container_type::value_type value_type;
722
723 iterator (container_type::* _F_insert_point)(const_iterator,
724 const value_type&);
725
726 insert_base() : _F_insert_point(&container_type::insert_after) { }
727 };
728
729 template<typename _Tp,
730 bool = traits<_Tp>::has_insert::value,
731 bool = traits<_Tp>::has_insert_after::value>
732 struct insert_point;
733
734 // Specialization for most containers.
735 template<typename _Tp>
736 struct insert_point<_Tp, true, false> : public insert_base<_Tp>
737 {
738 typedef _Tp container_type;
739 typedef typename container_type::value_type value_type;
740 using insert_base<_Tp>::_F_insert_point;
741
742 void
743 operator()(_Tp& __test)
744 {
745 try
746 {
747 const value_type cv = generate_unique<value_type>();
748 const size_type sz = std::distance(__test.begin(), __test.end());
749 size_type s = generate(sz);
750 auto i = __test.begin();
751 std::advance(i, s);
752 (__test.*_F_insert_point)(i, cv);
753 }
754 catch(const __gnu_cxx::forced_error&)
755 { throw; }
756 }
757
758 // Assumes containers start out equivalent.
759 void
760 operator()(_Tp& __control, _Tp& __test)
761 {
762 try
763 {
764 const value_type cv = generate_unique<value_type>();
765 const size_type sz = std::distance(__test.begin(), __test.end());
766 size_type s = generate(sz);
767 auto i = __test.begin();
768 std::advance(i, s);
769 (__test.*_F_insert_point)(i, cv);
770 }
771 catch(const __gnu_cxx::forced_error&)
772 { throw; }
773 }
774 };
775
776 // Specialization for forward_list.
777 template<typename _Tp>
778 struct insert_point<_Tp, false, true> : public insert_base<_Tp>
779 {
780 typedef _Tp container_type;
781 typedef typename container_type::value_type value_type;
782 using insert_base<_Tp>::_F_insert_point;
783
784 void
785 operator()(_Tp& __test)
786 {
787 try
788 {
789 const value_type cv = generate_unique<value_type>();
790 const size_type sz = std::distance(__test.begin(), __test.end());
791 size_type s = generate(sz);
792 auto i = __test.before_begin();
793 std::advance(i, s);
794 (__test.*_F_insert_point)(i, cv);
795 }
796 catch(const __gnu_cxx::forced_error&)
797 { throw; }
798 }
799
800 // Assumes containers start out equivalent.
801 void
802 operator()(_Tp& __control, _Tp& __test)
803 {
804 try
805 {
806 const value_type cv = generate_unique<value_type>();
807 const size_type sz = std::distance(__test.begin(), __test.end());
808 size_type s = generate(sz);
809 auto i = __test.before_begin();
810 std::advance(i, s);
811 (__test.*_F_insert_point)(i, cv);
812 }
813 catch(const __gnu_cxx::forced_error&)
814 { throw; }
815 }
816 };
817
818 // Specialization, empty.
819 template<typename _Tp>
820 struct insert_point<_Tp, false, false>
821 {
822 void
823 operator()(_Tp&) { }
824
825 void
826 operator()(_Tp&, _Tp&) { }
827 };
828
829
830 template<typename _Tp, bool = traits<_Tp>::is_associative::value
831 || traits<_Tp>::is_unordered::value>
832 struct clear
833 {
834 void
835 operator()(_Tp& __container)
836 {
837 try
838 {
839 __container.clear();
840 }
841 catch(const __gnu_cxx::forced_error&)
842 { throw; }
843 }
844 };
845
846 // Specialization, empty.
847 template<typename _Tp>
848 struct clear<_Tp, false>
849 {
850 void
851 operator()(_Tp&) { }
852 };
853
854
855 template<typename _Tp, bool = traits<_Tp>::is_unordered::value>
856 struct rehash
857 {
858 void
859 operator()(_Tp& __test)
860 {
861 try
862 {
863 size_type s = generate(__test.bucket_count());
864 __test.rehash(s);
865 }
866 catch(const __gnu_cxx::forced_error&)
867 { throw; }
868 }
869
870 void
871 operator()(_Tp& __control, _Tp& __test)
872 {
873 try
874 {
875 size_type s = generate(__test.bucket_count());
876 __test.rehash(s);
877 }
878 catch(const __gnu_cxx::forced_error&)
879 {
880 // Also check hash status.
881 bool fail(false);
882 if (__control.load_factor() != __test.load_factor())
883 fail = true;
884 if (__control.max_load_factor() != __test.max_load_factor())
885 fail = true;
886 if (__control.bucket_count() != __test.bucket_count())
887 fail = true;
888 if (__control.max_bucket_count() != __test.max_bucket_count())
889 fail = true;
890
891 if (fail)
892 {
893 char buf[40];
894 std::string __s("setup_base::rehash "
895 "containers not equal");
896 __s += "\n";
897 __s += "\n";
898 __s += "\t\t\tcontrol : test";
899 __s += "\n";
900 __s += "load_factor\t\t";
901 __builtin_sprintf(buf, "%lu", __control.load_factor());
902 __s += buf;
903 __s += " : ";
904 __builtin_sprintf(buf, "%lu", __test.load_factor());
905 __s += buf;
906 __s += "\n";
907
908 __s += "max_load_factor\t\t";
909 __builtin_sprintf(buf, "%lu", __control.max_load_factor());
910 __s += buf;
911 __s += " : ";
912 __builtin_sprintf(buf, "%lu", __test.max_load_factor());
913 __s += buf;
914 __s += "\n";
915
916 __s += "bucket_count\t\t";
917 __builtin_sprintf(buf, "%lu", __control.bucket_count());
918 __s += buf;
919 __s += " : ";
920 __builtin_sprintf(buf, "%lu", __test.bucket_count());
921 __s += buf;
922 __s += "\n";
923
924 __s += "max_bucket_count\t";
925 __builtin_sprintf(buf, "%lu", __control.max_bucket_count());
926 __s += buf;
927 __s += " : ";
928 __builtin_sprintf(buf, "%lu", __test.max_bucket_count());
929 __s += buf;
930 __s += "\n";
931
932 std::__throw_logic_error(__s.c_str());
933 }
934 }
935 }
936 };
937
938 // Specialization, empty.
939 template<typename _Tp>
940 struct rehash<_Tp, false>
941 {
942 void
943 operator()(_Tp&) { }
944
945 void
946 operator()(_Tp&, _Tp&) { }
947 };
948
949
950 template<typename _Tp>
951 struct swap
952 {
953 _Tp _M_other;
954
955 void
956 operator()(_Tp& __container)
957 {
958 try
959 {
960 __container.swap(_M_other);
961 }
962 catch(const __gnu_cxx::forced_error&)
963 { throw; }
964 }
965 };
966
967
968 template<typename _Tp>
969 struct iterator_operations
970 {
971 typedef _Tp container_type;
972 typedef typename container_type::iterator iterator;
973
974 void
975 operator()(_Tp& __container)
976 {
977 try
978 {
979 // Any will do.
980 iterator i = __container.begin();
981 iterator __attribute__((unused)) icopy(i);
982 iterator __attribute__((unused)) iassign = i;
983 }
984 catch(const __gnu_cxx::forced_error&)
985 { throw; }
986 }
987 };
988
989
990 template<typename _Tp>
991 struct const_iterator_operations
992 {
993 typedef _Tp container_type;
994 typedef typename container_type::const_iterator const_iterator;
995
996 void
997 operator()(_Tp& __container)
998 {
999 try
1000 {
1001 // Any will do.
1002 const_iterator i = __container.begin();
1003 const_iterator __attribute__((unused)) icopy(i);
1004 const_iterator __attribute__((unused)) iassign = i;
1005 }
1006 catch(const __gnu_cxx::forced_error&)
1007 { throw; }
1008 }
1009 };
1010 };
1011
1012 // Base class for exception tests.
1013 template<typename _Tp>
1014 struct test_base: public functor_base
1015 {
1016 typedef _Tp container_type;
1017
1018 typedef functor_base base_type;
1019 typedef populate<container_type> populate;
1020 typedef make_container_n<container_type> make_container_n;
1021
1022 typedef clear<container_type> clear;
1023 typedef erase_point<container_type> erase_point;
1024 typedef erase_range<container_type> erase_range;
1025 typedef insert_point<container_type> insert_point;
1026 typedef pop_front<container_type> pop_front;
1027 typedef pop_back<container_type> pop_back;
1028 typedef push_front<container_type> push_front;
1029 typedef push_back<container_type> push_back;
1030 typedef rehash<container_type> rehash;
1031 typedef swap<container_type> swap;
1032 typedef iterator_operations<container_type> iterator_ops;
1033 typedef const_iterator_operations<container_type> const_iterator_ops;
1034
1035 using base_type::compare;
1036
1037 // Functor objects.
1038 clear _M_clear;
1039 erase_point _M_erasep;
1040 erase_range _M_eraser;
1041 insert_point _M_insertp;
1042 pop_front _M_popf;
1043 pop_back _M_popb;
1044 push_front _M_pushf;
1045 push_back _M_pushb;
1046 rehash _M_rehash;
1047 swap _M_swap;
1048
1049 iterator_ops _M_iops;
1050 const_iterator_ops _M_ciops;
1051 };
1052
1053
1054 // Run through all member functions for basic exception safety
1055 // guarantee: no resource leaks when exceptions are thrown.
1056 //
1057 // Types of resources checked: memory.
1058 //
1059 // For each member function, use throw_value and throw_allocator as
1060 // value_type and allocator_type to force potential exception safety
1061 // errors.
1062 //
1063 // NB: Assumes
1064 // _Tp::value_type is __gnu_cxx::throw_value_*
1065 // _Tp::allocator_type is __gnu_cxx::throw_allocator_*
1066 // And that the _Cond template parameter for them both is
1067 // __gnu_cxx::limit_condition.
1068 template<typename _Tp>
1069 struct basic_safety : public test_base<_Tp>
1070 {
1071 typedef _Tp container_type;
1072 typedef test_base<container_type> base_type;
1073 typedef typename base_type::populate populate;
1074 typedef std::function<void(container_type&)> function_type;
1075 typedef __gnu_cxx::limit_condition condition_type;
1076
1077 using base_type::generate;
1078
1079 container_type _M_container;
1080 std::vector<function_type> _M_functions;
1081
1082 basic_safety() { run(); }
1083
1084 void
1085 run()
1086 {
1087 // Setup.
1088 condition_type::never_adjustor off;
1089
1090 // Construct containers.
1091 populate p1(_M_container);
1092 populate p2(base_type::_M_swap._M_other);
1093
1094 // Construct list of member functions to exercise.
1095 _M_functions.push_back(function_type(base_type::_M_iops));
1096 _M_functions.push_back(function_type(base_type::_M_ciops));
1097
1098 _M_functions.push_back(function_type(base_type::_M_erasep));
1099 _M_functions.push_back(function_type(base_type::_M_eraser));
1100 _M_functions.push_back(function_type(base_type::_M_insertp));
1101 _M_functions.push_back(function_type(base_type::_M_popf));
1102 _M_functions.push_back(function_type(base_type::_M_popb));
1103 _M_functions.push_back(function_type(base_type::_M_pushf));
1104 _M_functions.push_back(function_type(base_type::_M_pushb));
1105 _M_functions.push_back(function_type(base_type::_M_rehash));
1106 _M_functions.push_back(function_type(base_type::_M_swap));
1107
1108 // Last.
1109 _M_functions.push_back(function_type(base_type::_M_clear));
1110
1111 // Run tests.
1112 for (auto i = _M_functions.begin(); i != _M_functions.end(); ++i)
1113 {
1114 function_type& f = *i;
1115 run_steps_to_limit(f);
1116 }
1117 }
1118
1119 template<typename _Funct>
1120 void
1121 run_steps_to_limit(const _Funct& __f)
1122 {
1123 size_t i(1);
1124 bool exit(false);
1125 auto a = _M_container.get_allocator();
1126
1127 do
1128 {
1129 // Use the current step as an allocator label.
1130 a.set_label(i);
1131
1132 try
1133 {
1134 condition_type::limit_adjustor limit(i);
1135 __f(_M_container);
1136
1137 // If we get here, done.
1138 exit = true;
1139 }
1140 catch(const __gnu_cxx::forced_error&)
1141 {
1142 // Check this step for allocations.
1143 // NB: Will throw std::logic_error if allocations.
1144 a.check_allocated(i);
1145
1146 // Check memory allocated with operator new.
1147
1148 ++i;
1149 }
1150 }
1151 while (!exit);
1152
1153 // Log count info.
1154 std::cout << __f.target_type().name() << std::endl;
1155 std::cout << "end count " << i << std::endl;
1156 }
1157 };
1158
1159
1160 // Run through all member functions with a no throw requirement, sudden death.
1161 // all: member functions erase, pop_back, pop_front, swap
1162 // iterator copy ctor, assignment operator
1163 // unordered and associative: clear
1164 // NB: Assumes _Tp::allocator_type is __gnu_cxx::throw_allocator_random.
1165 template<typename _Tp>
1166 struct generation_prohibited : public test_base<_Tp>
1167 {
1168 typedef _Tp container_type;
1169 typedef test_base<container_type> base_type;
1170 typedef typename base_type::populate populate;
1171 typedef __gnu_cxx::random_condition condition_type;
1172
1173 container_type _M_container;
1174
1175 generation_prohibited() { run(); }
1176
1177 void
1178 run()
1179 {
1180 // Furthermore, assumes that the test functor will throw
1181 // forced_exception via throw_allocator, that all errors are
1182 // propagated and in error. Sudden death!
1183
1184 // Setup.
1185 {
1186 condition_type::never_adjustor off;
1187 populate p1(_M_container);
1188 populate p2(base_type::_M_swap._M_other);
1189 }
1190
1191 // Run tests.
1192 {
1193 condition_type::always_adjustor on;
1194
1195 // NB: Vector and deque are special, erase can throw if the copy
1196 // constructor or assignment operator of value_type throws.
1197 if (!traits<container_type>::has_throwing_erase::value)
1198 {
1199 this->_M_erasep(_M_container);
1200 this->_M_eraser(_M_container);
1201 }
1202
1203 this->_M_popf(_M_container);
1204 this->_M_popb(_M_container);
1205
1206 this->_M_iops(_M_container);
1207 this->_M_ciops(_M_container);
1208
1209 this->_M_swap(_M_container);
1210
1211 // Last.
1212 this->_M_clear(_M_container);
1213 }
1214 }
1215 };
1216
1217
1218 // Test strong exception guarantee.
1219 // Run through all member functions with a roll-back, consistent
1220 // coherent requirement.
1221 // all: member functions insert of a single element, push_back, push_front
1222 // unordered: rehash
1223 template<typename _Tp>
1224 struct propagation_consistent : public test_base<_Tp>
1225 {
1226 typedef _Tp container_type;
1227 typedef test_base<container_type> base_type;
1228 typedef typename base_type::populate populate;
1229 typedef std::function<void(container_type&)> function_type;
1230 typedef __gnu_cxx::limit_condition condition_type;
1231
1232 using base_type::compare;
1233
1234 container_type _M_container_test;
1235 container_type _M_container_control;
1236 std::vector<function_type> _M_functions;
1237
1238 propagation_consistent() { run(); }
1239
1240 void
1241 sync()
1242 { _M_container_test = _M_container_control; }
1243
1244 // Run test.
1245 void
1246 run()
1247 {
1248 // Setup.
1249 condition_type::never_adjustor off;
1250
1251 // Construct containers.
1252 populate p(_M_container_control);
1253 sync();
1254
1255 // Construct list of member functions to exercise.
1256 _M_functions.push_back(function_type(base_type::_M_pushf));
1257 _M_functions.push_back(function_type(base_type::_M_pushb));
1258 _M_functions.push_back(function_type(base_type::_M_insertp));
1259 _M_functions.push_back(function_type(base_type::_M_rehash));
1260
1261 // Run tests.
1262 for (auto i = _M_functions.begin(); i != _M_functions.end(); ++i)
1263 {
1264 function_type& f = *i;
1265 run_steps_to_limit(f);
1266 }
1267 }
1268
1269 template<typename _Funct>
1270 void
1271 run_steps_to_limit(const _Funct& __f)
1272 {
1273 size_t i(1);
1274 bool exit(false);
1275
1276 do
1277 {
1278 sync();
1279
1280 try
1281 {
1282 condition_type::limit_adjustor limit(i);
1283 __f(_M_container_test);
1284
1285 // If we get here, done.
1286 exit = true;
1287 }
1288 catch(const __gnu_cxx::forced_error&)
1289 {
1290 compare(_M_container_control, _M_container_test);
1291 ++i;
1292 }
1293 }
1294 while (!exit);
1295
1296 // Log count info.
1297 std::cout << __f.target_type().name() << std::endl;
1298 std::cout << "end count " << i << std::endl;
1299 }
1300 };
1301
1302 } // namespace __gnu_test
1303
1304 #endif