OSDN Git Service

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