]> git.ipfire.org Git - thirdparty/gcc.git/blob - libstdc++-v3/testsuite/util/exception/safety.h
re PR fortran/42309 (Problem with a pointer array passed to a subroutine)
[thirdparty/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", random);
56 __s += buf;
57 __s += " on range [";
58 __builtin_sprintf(buf, "%lu", distribution.min());
59 __s += buf;
60 __s += ", ";
61 __builtin_sprintf(buf, "%lu", 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
255 iterator (_Tp::* _F_erase_point)(iterator);
256 iterator (_Tp::* _F_erase_range)(iterator, iterator);
257
258 erase_base()
259 : _F_erase_point(&_Tp::erase), _F_erase_range(&_Tp::erase) { }
260 };
261
262 // Specialization, as forward_list has erase_after.
263 template<typename _Tp1, typename _Tp2>
264 struct erase_base<std::forward_list<_Tp1, _Tp2>>
265 {
266 typedef std::forward_list<_Tp1, _Tp2> container_type;
267 typedef typename container_type::iterator iterator;
268 typedef typename container_type::const_iterator const_iterator;
269
270 void (container_type::* _F_erase_point)(const_iterator);
271 void (container_type::* _F_erase_range)(const_iterator, const_iterator);
272
273 erase_base()
274 : _F_erase_point(&container_type::erase_after),
275 _F_erase_range(&container_type::erase_after) { }
276 };
277
278 template<typename _Tp, bool = traits<_Tp>::has_erase::value>
279 struct erase_point : public erase_base<_Tp>
280 {
281 using erase_base<_Tp>::_F_erase_point;
282
283 void
284 operator()(_Tp& __container)
285 {
286 try
287 {
288 // NB: Should be equivalent to size() member function, but
289 // computed with begin() and end().
290 const size_type sz = std::distance(__container.begin(),
291 __container.end());
292
293 // NB: Lowest common denominator: use forward iterator operations.
294 auto i = __container.begin();
295 std::advance(i, generate(sz));
296
297 // Makes it easier to think of this as __container.erase(i)
298 (__container.*_F_erase_point)(i);
299 }
300 catch(const __gnu_cxx::forced_error&)
301 { throw; }
302 }
303 };
304
305 // Specialization, empty.
306 template<typename _Tp>
307 struct erase_point<_Tp, false>
308 {
309 void
310 operator()(_Tp&) { }
311 };
312
313
314 template<typename _Tp, bool = traits<_Tp>::has_erase::value>
315 struct erase_range : public erase_base<_Tp>
316 {
317 using erase_base<_Tp>::_F_erase_range;
318
319 void
320 operator()(_Tp& __container)
321 {
322 try
323 {
324 const size_type sz = std::distance(__container.begin(),
325 __container.end());
326 size_type s1 = generate(sz);
327 size_type s2 = generate(sz);
328 auto i1 = __container.begin();
329 auto i2 = __container.begin();
330 std::advance(i1, std::min(s1, s2));
331 std::advance(i2, std::max(s1, s2));
332
333 // Makes it easier to think of this as __container.erase(i1, i2).
334 (__container.*_F_erase_range)(i1, i2);
335 }
336 catch(const __gnu_cxx::forced_error&)
337 { throw; }
338 }
339 };
340
341 // Specialization, empty.
342 template<typename _Tp>
343 struct erase_range<_Tp, false>
344 {
345 void
346 operator()(_Tp&) { }
347 };
348
349
350 template<typename _Tp, bool = traits<_Tp>::has_push_pop::value>
351 struct pop_front
352 {
353 void
354 operator()(_Tp& __container)
355 {
356 try
357 {
358 __container.pop_front();
359 }
360 catch(const __gnu_cxx::forced_error&)
361 { throw; }
362 }
363 };
364
365 // Specialization, empty.
366 template<typename _Tp>
367 struct pop_front<_Tp, false>
368 {
369 void
370 operator()(_Tp&) { }
371 };
372
373
374 template<typename _Tp, bool = traits<_Tp>::has_push_pop::value
375 && traits<_Tp>::is_reversible::value>
376 struct pop_back
377 {
378 void
379 operator()(_Tp& __container)
380 {
381 try
382 {
383 __container.pop_back();
384 }
385 catch(const __gnu_cxx::forced_error&)
386 { throw; }
387 }
388 };
389
390 // Specialization, empty.
391 template<typename _Tp>
392 struct pop_back<_Tp, false>
393 {
394 void
395 operator()(_Tp&) { }
396 };
397
398
399 template<typename _Tp, bool = traits<_Tp>::has_push_pop::value>
400 struct push_front
401 {
402 typedef _Tp container_type;
403 typedef typename container_type::value_type value_type;
404
405 void
406 operator()(_Tp& __test)
407 {
408 try
409 {
410 const value_type cv = generate_unique<value_type>();
411 __test.push_front(cv);
412 }
413 catch(const __gnu_cxx::forced_error&)
414 { throw; }
415 }
416
417 // Assumes containers start out equivalent.
418 void
419 operator()(_Tp& __control, _Tp& __test)
420 {
421 try
422 {
423 const value_type cv = generate_unique<value_type>();
424 __test.push_front(cv);
425 }
426 catch(const __gnu_cxx::forced_error&)
427 { throw; }
428 }
429 };
430
431 // Specialization, empty.
432 template<typename _Tp>
433 struct push_front<_Tp, false>
434 {
435 void
436 operator()(_Tp&) { }
437
438 void
439 operator()(_Tp&, _Tp&) { }
440 };
441
442
443 template<typename _Tp, bool = traits<_Tp>::has_push_pop::value
444 && traits<_Tp>::is_reversible::value>
445 struct push_back
446 {
447 typedef _Tp container_type;
448 typedef typename container_type::value_type value_type;
449
450 void
451 operator()(_Tp& __test)
452 {
453 try
454 {
455 const value_type cv = generate_unique<value_type>();
456 __test.push_back(cv);
457 }
458 catch(const __gnu_cxx::forced_error&)
459 { throw; }
460 }
461
462 // Assumes containers start out equivalent.
463 void
464 operator()(_Tp& __control, _Tp& __test)
465 {
466 try
467 {
468 const value_type cv = generate_unique<value_type>();
469 __test.push_back(cv);
470 }
471 catch(const __gnu_cxx::forced_error&)
472 { throw; }
473 }
474 };
475
476 // Specialization, empty.
477 template<typename _Tp>
478 struct push_back<_Tp, false>
479 {
480 void
481 operator()(_Tp&) { }
482
483 void
484 operator()(_Tp&, _Tp&) { }
485 };
486
487
488 // Abstract the insert function into two parts:
489 // 1, insert_base_functions == holds function pointer
490 // 2, insert_base == links function pointer to class insert method
491 template<typename _Tp>
492 struct insert_base
493 {
494 typedef typename _Tp::iterator iterator;
495 typedef typename _Tp::value_type value_type;
496
497 iterator (_Tp::* _F_insert_point)(iterator, const value_type&);
498
499 insert_base() : _F_insert_point(&_Tp::insert) { }
500 };
501
502 // Specialization, as string insertion has a different signature.
503 template<typename _Tp1, typename _Tp2, typename _Tp3>
504 struct insert_base<std::basic_string<_Tp1, _Tp2, _Tp3>>
505 {
506 typedef std::basic_string<_Tp1, _Tp2, _Tp3> container_type;
507 typedef typename container_type::iterator iterator;
508 typedef typename container_type::value_type value_type;
509
510 iterator (container_type::* _F_insert_point)(iterator, value_type);
511
512 insert_base() : _F_insert_point(&container_type::insert) { }
513 };
514
515 template<typename _Tp1, typename _Tp2, typename _Tp3,
516 template <typename, typename, typename> class _Tp4>
517 struct insert_base<__gnu_cxx::__versa_string<_Tp1, _Tp2, _Tp3, _Tp4>>
518 {
519 typedef __gnu_cxx::__versa_string<_Tp1, _Tp2, _Tp3, _Tp4>
520 container_type;
521 typedef typename container_type::iterator iterator;
522 typedef typename container_type::value_type value_type;
523
524 iterator (container_type::* _F_insert_point)(iterator, value_type);
525
526 insert_base() : _F_insert_point(&container_type::insert) { }
527 };
528
529 // Specialization, as forward_list insertion has a different signature.
530 template<typename _Tp1, typename _Tp2>
531 struct insert_base<std::forward_list<_Tp1, _Tp2>>
532 {
533 typedef std::forward_list<_Tp1, _Tp2> container_type;
534 typedef typename container_type::iterator iterator;
535 typedef typename container_type::const_iterator const_iterator;
536 typedef typename container_type::value_type value_type;
537
538 iterator (container_type::* _F_insert_point)(const_iterator,
539 const value_type&);
540
541 insert_base() : _F_insert_point(&container_type::insert_after) { }
542 };
543
544 template<typename _Tp, bool = traits<_Tp>::has_insert::value>
545 struct insert_point : public insert_base<_Tp>
546 {
547 typedef _Tp container_type;
548 typedef typename container_type::value_type value_type;
549 using insert_base<_Tp>::_F_insert_point;
550
551 void
552 operator()(_Tp& __test)
553 {
554 try
555 {
556 const value_type cv = generate_unique<value_type>();
557 const size_type sz = std::distance(__test.begin(), __test.end());
558 size_type s = generate(sz);
559 auto i = __test.begin();
560 std::advance(i, s);
561 (__test.*_F_insert_point)(i, cv);
562 }
563 catch(const __gnu_cxx::forced_error&)
564 { throw; }
565 }
566
567 // Assumes containers start out equivalent.
568 void
569 operator()(_Tp& __control, _Tp& __test)
570 {
571 try
572 {
573 const value_type cv = generate_unique<value_type>();
574 const size_type sz = std::distance(__test.begin(), __test.end());
575 size_type s = generate(sz);
576 auto i = __test.begin();
577 std::advance(i, s);
578 (__test.*_F_insert_point)(i, cv);
579 }
580 catch(const __gnu_cxx::forced_error&)
581 { throw; }
582 }
583 };
584
585 // Specialization, empty.
586 template<typename _Tp>
587 struct insert_point<_Tp, false>
588 {
589 void
590 operator()(_Tp&) { }
591
592 void
593 operator()(_Tp&, _Tp&) { }
594 };
595
596
597 template<typename _Tp, bool = traits<_Tp>::is_associative::value
598 || traits<_Tp>::is_unordered::value>
599 struct clear
600 {
601 void
602 operator()(_Tp& __container)
603 {
604 try
605 {
606 __container.clear();
607 }
608 catch(const __gnu_cxx::forced_error&)
609 { throw; }
610 }
611 };
612
613 // Specialization, empty.
614 template<typename _Tp>
615 struct clear<_Tp, false>
616 {
617 void
618 operator()(_Tp&) { }
619 };
620
621
622 template<typename _Tp, bool = traits<_Tp>::is_unordered::value>
623 struct rehash
624 {
625 void
626 operator()(_Tp& __test)
627 {
628 try
629 {
630 size_type s = generate(__test.bucket_count());
631 __test.rehash(s);
632 }
633 catch(const __gnu_cxx::forced_error&)
634 { throw; }
635 }
636
637 void
638 operator()(_Tp& __control, _Tp& __test)
639 {
640 try
641 {
642 size_type s = generate(__test.bucket_count());
643 __test.rehash(s);
644 }
645 catch(const __gnu_cxx::forced_error&)
646 {
647 // Also check hash status.
648 bool fail(false);
649 if (__control.load_factor() != __test.load_factor())
650 fail = true;
651 if (__control.max_load_factor() != __test.max_load_factor())
652 fail = true;
653 if (__control.bucket_count() != __test.bucket_count())
654 fail = true;
655 if (__control.max_bucket_count() != __test.max_bucket_count())
656 fail = true;
657
658 if (fail)
659 {
660 char buf[40];
661 std::string __s("setup_base::rehash "
662 "containers not equal");
663 __s += "\n";
664 __s += "\n";
665 __s += "\t\t\tcontrol : test";
666 __s += "\n";
667 __s += "load_factor\t\t";
668 __builtin_sprintf(buf, "%lu", __control.load_factor());
669 __s += buf;
670 __s += " : ";
671 __builtin_sprintf(buf, "%lu", __test.load_factor());
672 __s += buf;
673 __s += "\n";
674
675 __s += "max_load_factor\t\t";
676 __builtin_sprintf(buf, "%lu", __control.max_load_factor());
677 __s += buf;
678 __s += " : ";
679 __builtin_sprintf(buf, "%lu", __test.max_load_factor());
680 __s += buf;
681 __s += "\n";
682
683 __s += "bucket_count\t\t";
684 __builtin_sprintf(buf, "%lu", __control.bucket_count());
685 __s += buf;
686 __s += " : ";
687 __builtin_sprintf(buf, "%lu", __test.bucket_count());
688 __s += buf;
689 __s += "\n";
690
691 __s += "max_bucket_count\t";
692 __builtin_sprintf(buf, "%lu", __control.max_bucket_count());
693 __s += buf;
694 __s += " : ";
695 __builtin_sprintf(buf, "%lu", __test.max_bucket_count());
696 __s += buf;
697 __s += "\n";
698
699 std::__throw_logic_error(__s.c_str());
700 }
701 }
702 }
703 };
704
705 // Specialization, empty.
706 template<typename _Tp>
707 struct rehash<_Tp, false>
708 {
709 void
710 operator()(_Tp&) { }
711
712 void
713 operator()(_Tp&, _Tp&) { }
714 };
715
716
717 template<typename _Tp>
718 struct swap
719 {
720 _Tp _M_other;
721
722 void
723 operator()(_Tp& __container)
724 {
725 try
726 {
727 __container.swap(_M_other);
728 }
729 catch(const __gnu_cxx::forced_error&)
730 { throw; }
731 }
732 };
733
734
735 template<typename _Tp>
736 struct iterator_operations
737 {
738 typedef _Tp container_type;
739 typedef typename container_type::iterator iterator;
740
741 void
742 operator()(_Tp& __container)
743 {
744 try
745 {
746 // Any will do.
747 iterator i = __container.begin();
748 iterator __attribute__((unused)) icopy(i);
749 iterator __attribute__((unused)) iassign = i;
750 }
751 catch(const __gnu_cxx::forced_error&)
752 { throw; }
753 }
754 };
755
756
757 template<typename _Tp>
758 struct const_iterator_operations
759 {
760 typedef _Tp container_type;
761 typedef typename container_type::const_iterator const_iterator;
762
763 void
764 operator()(_Tp& __container)
765 {
766 try
767 {
768 // Any will do.
769 const_iterator i = __container.begin();
770 const_iterator __attribute__((unused)) icopy(i);
771 const_iterator __attribute__((unused)) iassign = i;
772 }
773 catch(const __gnu_cxx::forced_error&)
774 { throw; }
775 }
776 };
777 };
778
779 // Base class for exception tests.
780 template<typename _Tp>
781 struct test_base: public functor_base
782 {
783 typedef _Tp container_type;
784
785 typedef functor_base base_type;
786 typedef populate<container_type> populate;
787 typedef make_container_n<container_type> make_container_n;
788
789 typedef clear<container_type> clear;
790 typedef erase_point<container_type> erase_point;
791 typedef erase_range<container_type> erase_range;
792 typedef insert_point<container_type> insert_point;
793 typedef pop_front<container_type> pop_front;
794 typedef pop_back<container_type> pop_back;
795 typedef push_front<container_type> push_front;
796 typedef push_back<container_type> push_back;
797 typedef rehash<container_type> rehash;
798 typedef swap<container_type> swap;
799 typedef iterator_operations<container_type> iterator_ops;
800 typedef const_iterator_operations<container_type> const_iterator_ops;
801
802 using base_type::compare;
803
804 // Functor objects.
805 clear _M_clear;
806 erase_point _M_erasep;
807 erase_range _M_eraser;
808 insert_point _M_insertp;
809 pop_front _M_popf;
810 pop_back _M_popb;
811 push_front _M_pushf;
812 push_back _M_pushb;
813 rehash _M_rehash;
814 swap _M_swap;
815
816 iterator_ops _M_iops;
817 const_iterator_ops _M_ciops;
818 };
819
820
821 // Run through all member functions for basic exception safety
822 // guarantee: no resource leaks when exceptions are thrown.
823 //
824 // Types of resources checked: memory.
825 //
826 // For each member function, use throw_value and throw_allocator as
827 // value_type and allocator_type to force potential exception safety
828 // errors.
829 //
830 // NB: Assumes
831 // _Tp::value_type is __gnu_cxx::throw_value_*
832 // _Tp::allocator_type is __gnu_cxx::throw_allocator_*
833 // And that the _Cond template parameter for them both is
834 // __gnu_cxx::limit_condition.
835 template<typename _Tp>
836 struct basic_safety : public test_base<_Tp>
837 {
838 typedef _Tp container_type;
839 typedef test_base<container_type> base_type;
840 typedef typename base_type::populate populate;
841 typedef std::function<void(container_type&)> function_type;
842 typedef __gnu_cxx::limit_condition condition_type;
843
844 using base_type::generate;
845
846 container_type _M_container;
847 std::vector<function_type> _M_functions;
848
849 basic_safety() { run(); }
850
851 void
852 run()
853 {
854 // Setup.
855 condition_type::never_adjustor off;
856
857 // Construct containers.
858 populate p1(_M_container);
859 populate p2(base_type::_M_swap._M_other);
860
861 // Construct list of member functions to exercise.
862 _M_functions.push_back(function_type(base_type::_M_iops));
863 _M_functions.push_back(function_type(base_type::_M_ciops));
864
865 _M_functions.push_back(function_type(base_type::_M_erasep));
866 _M_functions.push_back(function_type(base_type::_M_eraser));
867 _M_functions.push_back(function_type(base_type::_M_insertp));
868 _M_functions.push_back(function_type(base_type::_M_popf));
869 _M_functions.push_back(function_type(base_type::_M_popb));
870 _M_functions.push_back(function_type(base_type::_M_pushf));
871 _M_functions.push_back(function_type(base_type::_M_pushb));
872 _M_functions.push_back(function_type(base_type::_M_rehash));
873 _M_functions.push_back(function_type(base_type::_M_swap));
874
875 // Last.
876 _M_functions.push_back(function_type(base_type::_M_clear));
877
878 // Run tests.
879 auto i = _M_functions.begin();
880 for (auto i = _M_functions.begin(); i != _M_functions.end(); ++i)
881 {
882 function_type& f = *i;
883 run_steps_to_limit(f);
884 }
885 }
886
887 template<typename _Funct>
888 void
889 run_steps_to_limit(const _Funct& __f)
890 {
891 size_t i(1);
892 bool exit(false);
893 auto a = _M_container.get_allocator();
894
895 do
896 {
897 // Use the current step as an allocator label.
898 a.set_label(i);
899
900 try
901 {
902 condition_type::limit_adjustor limit(i);
903 __f(_M_container);
904
905 // If we get here, done.
906 exit = true;
907 }
908 catch(const __gnu_cxx::forced_error&)
909 {
910 // Check this step for allocations.
911 // NB: Will throw std::logic_error if allocations.
912 a.check_allocated(i);
913
914 // Check memory allocated with operator new.
915
916 ++i;
917 }
918 }
919 while (!exit);
920
921 // Log count info.
922 std::cout << __f.target_type().name() << std::endl;
923 std::cout << "end count " << i << std::endl;
924 }
925 };
926
927
928 // Run through all member functions with a no throw requirement, sudden death.
929 // all: member functions erase, pop_back, pop_front, swap
930 // iterator copy ctor, assignment operator
931 // unordered and associative: clear
932 // NB: Assumes _Tp::allocator_type is __gnu_cxx::throw_allocator_random.
933 template<typename _Tp>
934 struct generation_prohibited : public test_base<_Tp>
935 {
936 typedef _Tp container_type;
937 typedef test_base<container_type> base_type;
938 typedef typename base_type::populate populate;
939 typedef __gnu_cxx::random_condition condition_type;
940
941 container_type _M_container;
942
943 generation_prohibited() { run(); }
944
945 void
946 run()
947 {
948 // Furthermore, assumes that the test functor will throw
949 // forced_exception via throw_allocator, that all errors are
950 // propagated and in error. Sudden death!
951
952 // Setup.
953 {
954 condition_type::never_adjustor off;
955 populate p1(_M_container);
956 populate p2(base_type::_M_swap._M_other);
957 }
958
959 // Run tests.
960 {
961 condition_type::always_adjustor on;
962
963 _M_erasep(_M_container);
964 _M_eraser(_M_container);
965
966 _M_popf(_M_container);
967 _M_popb(_M_container);
968
969 _M_iops(_M_container);
970 _M_ciops(_M_container);
971
972 _M_swap(_M_container);
973
974 // Last.
975 _M_clear(_M_container);
976 }
977 }
978 };
979
980
981 // Test strong exception guarantee.
982 // Run through all member functions with a roll-back, consistent
983 // coherent requirement.
984 // all: member functions insert of a single element, push_back, push_front
985 // unordered: rehash
986 template<typename _Tp>
987 struct propagation_consistent : public test_base<_Tp>
988 {
989 typedef _Tp container_type;
990 typedef test_base<container_type> base_type;
991 typedef typename base_type::populate populate;
992 typedef std::function<void(container_type&)> function_type;
993 typedef __gnu_cxx::limit_condition condition_type;
994
995 using base_type::compare;
996
997 container_type _M_container_test;
998 container_type _M_container_control;
999 std::vector<function_type> _M_functions;
1000
1001 propagation_consistent() { run(); }
1002
1003 void
1004 sync()
1005 { _M_container_test = _M_container_control; }
1006
1007 // Run test.
1008 void
1009 run()
1010 {
1011 // Setup.
1012 condition_type::never_adjustor off;
1013
1014 // Construct containers.
1015 populate p(_M_container_control);
1016 sync();
1017
1018 // Construct list of member functions to exercise.
1019 _M_functions.push_back(function_type(base_type::_M_pushf));
1020 _M_functions.push_back(function_type(base_type::_M_pushb));
1021 _M_functions.push_back(function_type(base_type::_M_insertp));
1022 _M_functions.push_back(function_type(base_type::_M_rehash));
1023
1024 // Run tests.
1025 auto i = _M_functions.begin();
1026 for (auto i = _M_functions.begin(); i != _M_functions.end(); ++i)
1027 {
1028 function_type& f = *i;
1029 run_steps_to_limit(f);
1030 }
1031 }
1032
1033 template<typename _Funct>
1034 void
1035 run_steps_to_limit(const _Funct& __f)
1036 {
1037 size_t i(1);
1038 bool exit(false);
1039
1040 do
1041 {
1042 sync();
1043
1044 try
1045 {
1046 condition_type::limit_adjustor limit(i);
1047 __f(_M_container_test);
1048
1049 // If we get here, done.
1050 exit = true;
1051 }
1052 catch(const __gnu_cxx::forced_error&)
1053 {
1054 compare(_M_container_control, _M_container_test);
1055 ++i;
1056 }
1057 }
1058 while (!exit);
1059
1060 // Log count info.
1061 std::cout << __f.target_type().name() << std::endl;
1062 std::cout << "end count " << i << std::endl;
1063 }
1064 };
1065
1066 } // namespace __gnu_test
1067
1068 #endif