generation_prohibited.c: Remove, swap can indeed throw (DR 774).
[platform/upstream/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