OSDN Git Service

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