1 // -*- C++ -*-
2 
3 // Copyright (C) 2009-2013 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
generatesetup_base38     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 
value_typesetup_base::generate_unique75 	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
230 	  = std::distance(__test.begin(), __test.end());
231 	const size_type szc
232 	  = std::distance(__control.begin(), __control.end());
233 
234 	if (szt != szc)
235 	  throw std::logic_error(
236 		"setup_base::compare containers size not equal");
237 
238 	// Should test iterator validity before and after exception.
239 	bool __equal_it = std::equal(__test.begin(), __test.end(),
240 				     __control.begin());
241 
242 	if (!__equal_it)
243 	  throw std::logic_error(
244 		"setup_base::compare containers iterators not equal");
245 
246 	return true;
247       }
248   };
249 
250 
251   // Containing structure holding functors.
252   struct functor_base : public setup_base
253   {
254     // Abstract the erase function.
255     template<typename _Tp>
256       struct erase_base
257       {
258 	typedef typename _Tp::iterator 			iterator;
259 	typedef typename _Tp::const_iterator		const_iterator;
260 
261 	iterator (_Tp::* _F_erase_point)(const_iterator);
262 	iterator (_Tp::* _F_erase_range)(const_iterator, const_iterator);
263 
264 	erase_base()
265 	: _F_erase_point(&_Tp::erase), _F_erase_range(&_Tp::erase) { }
266       };
267 
268     // Specializations, old C++03 signatures.
269     template<typename _Tp1, typename _Tp2, typename _Tp3>
270       struct erase_base<std::basic_string<_Tp1, _Tp2, _Tp3>>
271       {
272 	typedef std::basic_string<_Tp1, _Tp2, _Tp3>     container_type;
273 	typedef typename container_type::iterator 	iterator;
274 
275 	iterator (container_type::* _F_erase_point)(iterator);
276 	iterator (container_type::* _F_erase_range)(iterator, iterator);
277 
278 	erase_base()
279 	: _F_erase_point(&container_type::erase),
280 	  _F_erase_range(&container_type::erase) { }
281       };
282 
283     template<typename _Tp1, typename _Tp2, typename _Tp3,
284 	     template <typename, typename, typename> class _Tp4>
285       struct erase_base<__gnu_cxx::__versa_string<_Tp1, _Tp2, _Tp3, _Tp4>>
286       {
287 	typedef __gnu_cxx::__versa_string<_Tp1, _Tp2, _Tp3, _Tp4>
288 	                                                container_type;
289 	typedef typename container_type::iterator 	iterator;
290 
291 	iterator (container_type::* _F_erase_point)(iterator);
292 	iterator (container_type::* _F_erase_range)(iterator, iterator);
293 
294 	erase_base()
295 	: _F_erase_point(&container_type::erase),
296 	  _F_erase_range(&container_type::erase) { }
297       };
298 
299     template<typename _Tp1, typename _Tp2>
300       struct erase_base<std::deque<_Tp1, _Tp2>>
301       {
302 	typedef std::deque<_Tp1, _Tp2> 		        container_type;
303 	typedef typename container_type::iterator 	iterator;
304 
305 	iterator (container_type::* _F_erase_point)(iterator);
306 	iterator (container_type::* _F_erase_range)(iterator, iterator);
307 
308 	erase_base()
309 	: _F_erase_point(&container_type::erase),
310 	  _F_erase_range(&container_type::erase) { }
311       };
312 
313     template<typename _Tp1, typename _Tp2>
314       struct erase_base<std::list<_Tp1, _Tp2>>
315       {
316 	typedef std::list<_Tp1, _Tp2> 		        container_type;
317 	typedef typename container_type::iterator 	iterator;
318 
319 	iterator (container_type::* _F_erase_point)(iterator);
320 	iterator (container_type::* _F_erase_range)(iterator, iterator);
321 
322 	erase_base()
323 	: _F_erase_point(&container_type::erase),
324 	  _F_erase_range(&container_type::erase) { }
325       };
326 
327     template<typename _Tp1, typename _Tp2>
328       struct erase_base<std::vector<_Tp1, _Tp2>>
329       {
330 	typedef std::vector<_Tp1, _Tp2>		        container_type;
331 	typedef typename container_type::iterator 	iterator;
332 
333 	iterator (container_type::* _F_erase_point)(iterator);
334 	iterator (container_type::* _F_erase_range)(iterator, iterator);
335 
336 	erase_base()
337 	: _F_erase_point(&container_type::erase),
338 	  _F_erase_range(&container_type::erase) { }
339       };
340 
341     // Specialization, as forward_list has erase_after.
342     template<typename _Tp1, typename _Tp2>
343       struct erase_base<std::forward_list<_Tp1, _Tp2>>
344       {
345 	typedef std::forward_list<_Tp1, _Tp2> 		container_type;
346 	typedef typename container_type::iterator 	iterator;
347 	typedef typename container_type::const_iterator const_iterator;
348 
349 	iterator (container_type::* _F_erase_point)(const_iterator);
350 	iterator (container_type::* _F_erase_range)(const_iterator,
351 						    const_iterator);
352 
353 	erase_base()
354 	: _F_erase_point(&container_type::erase_after),
355 	  _F_erase_range(&container_type::erase_after) { }
356       };
357 
358     template<typename _Tp,
359 	     bool = traits<_Tp>::has_erase::value,
360 	     bool = traits<_Tp>::has_erase_after::value>
361       struct erase_point;
362 
363     // Specialization for most containers.
364     template<typename _Tp>
365       struct erase_point<_Tp, true, false> : public erase_base<_Tp>
366       {
367 	using erase_base<_Tp>::_F_erase_point;
368 
369 	void
370 	operator()(_Tp& __container)
371 	{
372 	  try
373 	    {
374 	      // NB: Should be equivalent to size() member function, but
375 	      // computed with begin() and end().
376 	      const size_type sz = std::distance(__container.begin(),
377 						 __container.end());
378 
379 	      // NB: Lowest common denominator: use forward iterator operations.
380 	      auto i = __container.begin();
381 	      std::advance(i, generate(sz));
382 
383 	      // Makes it easier to think of this as __container.erase(i)
384 	      (__container.*_F_erase_point)(i);
385 	    }
386 	  catch(const __gnu_cxx::forced_error&)
387 	    { throw; }
388 	}
389       };
390 
391     // Specialization for forward_list.
392     template<typename _Tp>
393       struct erase_point<_Tp, false, true> : public erase_base<_Tp>
394       {
395 	using erase_base<_Tp>::_F_erase_point;
396 
397 	void
398 	operator()(_Tp& __container)
399 	{
400 	  try
401 	    {
402 	      // NB: Should be equivalent to size() member function, but
403 	      // computed with begin() and end().
404 	      const size_type sz = std::distance(__container.begin(),
405 						 __container.end());
406 
407 	      // NB: Lowest common denominator: use forward iterator operations.
408 	      auto i = __container.before_begin();
409 	      std::advance(i, generate(sz));
410 
411 	      // Makes it easier to think of this as __container.erase(i)
412 	      (__container.*_F_erase_point)(i);
413 	    }
414 	  catch(const __gnu_cxx::forced_error&)
415 	    { throw; }
416 	}
417       };
418 
419     // Specialization, empty.
420     template<typename _Tp>
421       struct erase_point<_Tp, false, false>
422       {
423 	void
424 	operator()(_Tp&) { }
425       };
426 
427 
428     template<typename _Tp,
429 	     bool = traits<_Tp>::has_erase::value,
430 	     bool = traits<_Tp>::has_erase_after::value>
431       struct erase_range;
432 
433     // Specialization for most containers.
434     template<typename _Tp>
435       struct erase_range<_Tp, true, false> : public erase_base<_Tp>
436       {
437 	using erase_base<_Tp>::_F_erase_range;
438 
439 	void
440 	operator()(_Tp& __container)
441 	{
442 	  try
443 	    {
444 	      const size_type sz = std::distance(__container.begin(),
445 						 __container.end());
446 	      size_type s1 = generate(sz);
447 	      size_type s2 = generate(sz);
448 	      auto i1 = __container.begin();
449 	      auto i2 = __container.begin();
450 	      std::advance(i1, std::min(s1, s2));
451 	      std::advance(i2, std::max(s1, s2));
452 
453 	      // Makes it easier to think of this as __container.erase(i1, i2).
454 	      (__container.*_F_erase_range)(i1, i2);
455 	    }
456 	  catch(const __gnu_cxx::forced_error&)
457 	    { throw; }
458 	}
459       };
460 
461     // Specialization for forward_list.
462     template<typename _Tp>
463       struct erase_range<_Tp, false, true> : public erase_base<_Tp>
464       {
465 	using erase_base<_Tp>::_F_erase_range;
466 
467 	void
468 	operator()(_Tp& __container)
469 	{
470 	  try
471 	    {
472 	      const size_type sz = std::distance(__container.begin(),
473 						 __container.end());
474 	      size_type s1 = generate(sz);
475 	      size_type s2 = generate(sz);
476 	      auto i1 = __container.before_begin();
477 	      auto i2 = __container.before_begin();
478 	      std::advance(i1, std::min(s1, s2));
479 	      std::advance(i2, std::max(s1, s2));
480 
481 	      // Makes it easier to think of this as __container.erase(i1, i2).
482 	      (__container.*_F_erase_range)(i1, i2);
483 	    }
484 	  catch(const __gnu_cxx::forced_error&)
485 	    { throw; }
486 	}
487       };
488 
489     // Specialization, empty.
490     template<typename _Tp>
491       struct erase_range<_Tp, false, false>
492       {
493 	void
494 	operator()(_Tp&) { }
495       };
496 
497 
498     template<typename _Tp, bool = traits<_Tp>::has_push_pop::value>
499       struct pop_front
500       {
501 	void
502 	operator()(_Tp& __container)
503 	{
504 	  try
505 	    {
506 	      __container.pop_front();
507 	    }
508 	  catch(const __gnu_cxx::forced_error&)
509 	    { throw; }
510 	}
511       };
512 
513     // Specialization, empty.
514     template<typename _Tp>
515       struct pop_front<_Tp, false>
516       {
517 	void
518 	operator()(_Tp&) { }
519       };
520 
521 
522     template<typename _Tp, bool = traits<_Tp>::has_push_pop::value
523 				  && traits<_Tp>::is_reversible::value>
524       struct pop_back
525       {
526 	void
527 	operator()(_Tp& __container)
528 	{
529 	  try
530 	    {
531 	      __container.pop_back();
532 	    }
533 	  catch(const __gnu_cxx::forced_error&)
534 	    { throw; }
535 	}
536       };
537 
538     // Specialization, empty.
539     template<typename _Tp>
540       struct pop_back<_Tp, false>
541       {
542 	void
543 	operator()(_Tp&) { }
544       };
545 
546 
547     template<typename _Tp, bool = traits<_Tp>::has_push_pop::value>
548       struct push_front
549       {
550 	typedef _Tp 					container_type;
551 	typedef typename container_type::value_type    	value_type;
552 
553 	void
554 	operator()(_Tp& __test)
555 	{
556 	  try
557 	    {
558 	      const value_type cv = generate_unique<value_type>();
559 	      __test.push_front(cv);
560 	    }
561 	  catch(const __gnu_cxx::forced_error&)
562 	    { throw; }
563 	}
564 
565 	// Assumes containers start out equivalent.
566 	void
567 	operator()(_Tp& __control, _Tp& __test)
568 	{
569 	  try
570 	    {
571 	      const value_type cv = generate_unique<value_type>();
572 	      __test.push_front(cv);
573 	    }
574 	  catch(const __gnu_cxx::forced_error&)
575 	    { throw; }
576 	}
577     };
578 
579     // Specialization, empty.
580     template<typename _Tp>
581       struct push_front<_Tp, false>
582       {
583 	void
584 	operator()(_Tp&) { }
585 
586 	void
587 	operator()(_Tp&, _Tp&) { }
588       };
589 
590 
591     template<typename _Tp, bool = traits<_Tp>::has_push_pop::value
592 				  && traits<_Tp>::is_reversible::value>
593       struct push_back
594       {
595 	typedef _Tp 					container_type;
596 	typedef typename container_type::value_type    	value_type;
597 
598 	void
599 	operator()(_Tp& __test)
600 	{
601 	  try
602 	    {
603 	      const value_type cv = generate_unique<value_type>();
604 	      __test.push_back(cv);
605 	    }
606 	  catch(const __gnu_cxx::forced_error&)
607 	    { throw; }
608 	}
609 
610 	// Assumes containers start out equivalent.
611 	void
612 	operator()(_Tp& __control, _Tp& __test)
613 	{
614 	  try
615 	    {
616 	      const value_type cv = generate_unique<value_type>();
617 	      __test.push_back(cv);
618 	    }
619 	  catch(const __gnu_cxx::forced_error&)
620 	    { throw; }
621 	}
622     };
623 
624     // Specialization, empty.
625     template<typename _Tp>
626       struct push_back<_Tp, false>
627       {
628 	void
629 	operator()(_Tp&) { }
630 
631 	void
632 	operator()(_Tp&, _Tp&) { }
633       };
634 
635     template<typename _Tp, bool = traits<_Tp>::has_push_pop::value
636 				  && traits<_Tp>::has_emplace::value>
637       struct emplace_front
638       {
639 	typedef _Tp 					container_type;
640 	typedef typename container_type::value_type    	value_type;
641 
642 	void
643 	operator()(_Tp& __test)
644 	{
645 	  try
646 	    {
647 	      const value_type cv = generate_unique<value_type>();
648 	      __test.emplace_front(cv);
649 	    }
650 	  catch(const __gnu_cxx::forced_error&)
651 	    { throw; }
652 	}
653 
654 	// Assumes containers start out equivalent.
655 	void
656 	operator()(_Tp& __control, _Tp& __test)
657 	{
658 	  try
659 	    {
660 	      const value_type cv = generate_unique<value_type>();
661 	      __test.emplace_front(cv);
662 	    }
663 	  catch(const __gnu_cxx::forced_error&)
664 	    { throw; }
665 	}
666     };
667 
668     // Specialization, empty.
669     template<typename _Tp>
670       struct emplace_front<_Tp, false>
671       {
672 	void
673 	operator()(_Tp&) { }
674 
675 	void
676 	operator()(_Tp&, _Tp&) { }
677       };
678 
679 
680     template<typename _Tp, bool = traits<_Tp>::has_push_pop::value
681 				  && traits<_Tp>::has_emplace::value
682 				  && traits<_Tp>::is_reversible::value>
683       struct emplace_back
684       {
685 	typedef _Tp 					container_type;
686 	typedef typename container_type::value_type    	value_type;
687 
688 	void
689 	operator()(_Tp& __test)
690 	{
691 	  try
692 	    {
693 	      const value_type cv = generate_unique<value_type>();
694 	      __test.emplace_back(cv);
695 	    }
696 	  catch(const __gnu_cxx::forced_error&)
697 	    { throw; }
698 	}
699 
700 	// Assumes containers start out equivalent.
701 	void
702 	operator()(_Tp& __control, _Tp& __test)
703 	{
704 	  try
705 	    {
706 	      const value_type cv = generate_unique<value_type>();
707 	      __test.push_back(cv);
708 	    }
709 	  catch(const __gnu_cxx::forced_error&)
710 	    { throw; }
711 	}
712     };
713 
714     // Specialization, empty.
715     template<typename _Tp>
716       struct emplace_back<_Tp, false>
717       {
718 	void
719 	operator()(_Tp&) { }
720 
721 	void
722 	operator()(_Tp&, _Tp&) { }
723       };
724 
725 
726     // Abstract the insert function into two parts:
727     // 1, insert_base_functions == holds function pointer
728     // 2, insert_base == links function pointer to class insert method
729     template<typename _Tp>
730       struct insert_base
731       {
732 	typedef typename _Tp::iterator 			iterator;
733 	typedef typename _Tp::const_iterator    	const_iterator;
734 	typedef typename _Tp::value_type 		value_type;
735 
736 	iterator (_Tp::* _F_insert_point)(const_iterator, const value_type&);
737 
738 	insert_base() : _F_insert_point(&_Tp::insert) { }
739       };
740 
741     // Specializations, old C++03 signatures.
742     template<typename _Tp1, typename _Tp2>
743       struct insert_base<std::deque<_Tp1, _Tp2>>
744       {
745 	typedef std::deque<_Tp1, _Tp2> 	                container_type;
746 	typedef typename container_type::iterator 	iterator;
747 	typedef typename container_type::value_type 	value_type;
748 
749 	iterator (container_type::* _F_insert_point)(iterator,
750 						     const value_type&);
751 
752 	insert_base() : _F_insert_point(&container_type::insert) { }
753       };
754 
755     template<typename _Tp1, typename _Tp2>
756       struct insert_base<std::list<_Tp1, _Tp2>>
757       {
758 	typedef std::list<_Tp1, _Tp2>    	        container_type;
759 	typedef typename container_type::iterator 	iterator;
760 	typedef typename container_type::value_type 	value_type;
761 
762 	iterator (container_type::* _F_insert_point)(iterator,
763 						     const value_type&);
764 
765 	insert_base() : _F_insert_point(&container_type::insert) { }
766       };
767 
768     template<typename _Tp1, typename _Tp2>
769       struct insert_base<std::vector<_Tp1, _Tp2>>
770       {
771 	typedef std::vector<_Tp1, _Tp2> 	        container_type;
772 	typedef typename container_type::iterator 	iterator;
773 	typedef typename container_type::value_type 	value_type;
774 
775 	iterator (container_type::* _F_insert_point)(iterator,
776 						     const value_type&);
777 
778 	insert_base() : _F_insert_point(&container_type::insert) { }
779       };
780 
781     // Specialization, as string insertion has a different signature.
782     template<typename _Tp1, typename _Tp2, typename _Tp3>
783       struct insert_base<std::basic_string<_Tp1, _Tp2, _Tp3>>
784       {
785 	typedef std::basic_string<_Tp1, _Tp2, _Tp3> 	container_type;
786 	typedef typename container_type::iterator 	iterator;
787 	typedef typename container_type::value_type 	value_type;
788 
789 	iterator (container_type::* _F_insert_point)(iterator, value_type);
790 
791 	insert_base() : _F_insert_point(&container_type::insert) { }
792       };
793 
794     // Likewise for __versa_string.
795     template<typename _Tp1, typename _Tp2, typename _Tp3,
796 	     template <typename, typename, typename> class _Tp4>
797       struct insert_base<__gnu_cxx::__versa_string<_Tp1, _Tp2, _Tp3, _Tp4>>
798       {
799 	typedef __gnu_cxx::__versa_string<_Tp1, _Tp2, _Tp3, _Tp4>
800 	                                                container_type;
801 	typedef typename container_type::iterator 	iterator;
802 	typedef typename container_type::value_type 	value_type;
803 
804 	iterator (container_type::* _F_insert_point)(iterator, value_type);
805 
806 	insert_base() : _F_insert_point(&container_type::insert) { }
807       };
808 
809     // Specialization, as forward_list has insert_after.
810     template<typename _Tp1, typename _Tp2>
811       struct insert_base<std::forward_list<_Tp1, _Tp2>>
812       {
813 	typedef std::forward_list<_Tp1, _Tp2> container_type;
814 	typedef typename container_type::iterator 	iterator;
815 	typedef typename container_type::const_iterator const_iterator;
816 	typedef typename container_type::value_type 	value_type;
817 
818 	iterator (container_type::* _F_insert_point)(const_iterator,
819 						     const value_type&);
820 
821 	insert_base() : _F_insert_point(&container_type::insert_after) { }
822       };
823 
824     template<typename _Tp, bool = traits<_Tp>::has_insert::value,
825 			   bool = traits<_Tp>::has_insert_after::value>
826       struct insert_point;
827 
828     // Specialization for most containers.
829     template<typename _Tp>
830       struct insert_point<_Tp, true, false> : public insert_base<_Tp>
831       {
832 	typedef _Tp 				       	container_type;
833 	typedef typename container_type::value_type 	value_type;
834 	using insert_base<_Tp>::_F_insert_point;
835 
836 	void
837 	operator()(_Tp& __test)
838 	{
839 	  try
840 	    {
841 	      const value_type cv = generate_unique<value_type>();
842 	      const size_type sz = std::distance(__test.begin(), __test.end());
843 	      size_type s = generate(sz);
844 	      auto i = __test.begin();
845 	      std::advance(i, s);
846 	      (__test.*_F_insert_point)(i, cv);
847 	    }
848 	  catch(const __gnu_cxx::forced_error&)
849 	    { throw; }
850 	}
851 
852 	// Assumes containers start out equivalent.
853 	void
854 	operator()(_Tp& __control, _Tp& __test)
855 	{
856 	  try
857 	    {
858 	      const value_type cv = generate_unique<value_type>();
859 	      const size_type sz = std::distance(__test.begin(), __test.end());
860 	      size_type s = generate(sz);
861 	      auto i = __test.begin();
862 	      std::advance(i, s);
863 	      (__test.*_F_insert_point)(i, cv);
864 	    }
865 	  catch(const __gnu_cxx::forced_error&)
866 	    { throw; }
867  	}
868       };
869 
870     // Specialization for forward_list.
871     template<typename _Tp>
872       struct insert_point<_Tp, false, true> : public insert_base<_Tp>
873       {
874 	typedef _Tp 				       	container_type;
875 	typedef typename container_type::value_type 	value_type;
876 	using insert_base<_Tp>::_F_insert_point;
877 
878 	void
879 	operator()(_Tp& __test)
880 	{
881 	  try
882 	    {
883 	      const value_type cv = generate_unique<value_type>();
884 	      const size_type sz = std::distance(__test.begin(), __test.end());
885 	      size_type s = generate(sz);
886 	      auto i = __test.before_begin();
887 	      std::advance(i, s);
888 	      (__test.*_F_insert_point)(i, cv);
889 	    }
890 	  catch(const __gnu_cxx::forced_error&)
891 	    { throw; }
892 	}
893 
894 	// Assumes containers start out equivalent.
895 	void
896 	operator()(_Tp& __control, _Tp& __test)
897 	{
898 	  try
899 	    {
900 	      const value_type cv = generate_unique<value_type>();
901 	      const size_type sz = std::distance(__test.begin(), __test.end());
902 	      size_type s = generate(sz);
903 	      auto i = __test.before_begin();
904 	      std::advance(i, s);
905 	      (__test.*_F_insert_point)(i, cv);
906 	    }
907 	  catch(const __gnu_cxx::forced_error&)
908 	    { throw; }
909  	}
910       };
911 
912     // Specialization, empty.
913     template<typename _Tp>
914       struct insert_point<_Tp, false, false>
915       {
916 	void
917 	operator()(_Tp&) { }
918 
919 	void
920 	operator()(_Tp&, _Tp&) { }
921       };
922 
923     template<typename _Tp, bool = traits<_Tp>::has_emplace::value
924 				  && (traits<_Tp>::is_associative::value
925 				      || traits<_Tp>::is_unordered::value)>
926       struct emplace;
927 
928     // Specialization for associative and unordered containers.
929     template<typename _Tp>
930       struct emplace<_Tp, true>
931       {
932 	typedef _Tp					container_type;
933 	typedef typename container_type::value_type	value_type;
934 	typedef typename container_type::size_type	size_type;
935 
936 	void
937 	operator()(_Tp& __test)
938 	{
939 	  try
940 	    {
941 	      const value_type cv = generate_unique<value_type>();
942 	      __test.emplace(cv);
943 	    }
944 	  catch(const __gnu_cxx::forced_error&)
945 	    { throw; }
946 	}
947 
948 	// Assumes containers start out equivalent.
949 	void
950 	operator()(_Tp& __control, _Tp& __test)
951 	{
952 	  try
953 	    {
954 	      const value_type cv = generate_unique<value_type>();
955 	      __test.emplace(cv);
956 	    }
957 	  catch(const __gnu_cxx::forced_error&)
958 	    { throw; }
959  	}
960       };
961 
962     // Specialization, empty.
963     template<typename _Tp>
964       struct emplace<_Tp, false>
965       {
966 	void
967 	operator()(_Tp&) { }
968 
969 	void
970 	operator()(_Tp&, _Tp&) { }
971       };
972 
973     template<typename _Tp, bool = traits<_Tp>::has_emplace::value,
974 			   bool = traits<_Tp>::is_associative::value
975 				  || traits<_Tp>::is_unordered::value,
976 			   bool = traits<_Tp>::has_insert_after::value>
977       struct emplace_point;
978 
979     // Specialization for most containers.
980     template<typename _Tp>
981       struct emplace_point<_Tp, true, false, false>
982       {
983 	typedef _Tp 				       	container_type;
984 	typedef typename container_type::value_type 	value_type;
985 
986 	void
987 	operator()(_Tp& __test)
988 	{
989 	  try
990 	    {
991 	      const value_type cv = generate_unique<value_type>();
992 	      const size_type sz = std::distance(__test.begin(), __test.end());
993 	      size_type s = generate(sz);
994 	      auto i = __test.begin();
995 	      std::advance(i, s);
996 	      __test.emplace(i, cv);
997 	    }
998 	  catch(const __gnu_cxx::forced_error&)
999 	    { throw; }
1000 	}
1001 
1002 	// Assumes containers start out equivalent.
1003 	void
1004 	operator()(_Tp& __control, _Tp& __test)
1005 	{
1006 	  try
1007 	    {
1008 	      const value_type cv = generate_unique<value_type>();
1009 	      const size_type sz = std::distance(__test.begin(), __test.end());
1010 	      size_type s = generate(sz);
1011 	      auto i = __test.begin();
1012 	      std::advance(i, s);
1013 	      __test.emplace(i, cv);
1014 	    }
1015 	  catch(const __gnu_cxx::forced_error&)
1016 	    { throw; }
1017  	}
1018       };
1019 
1020     // Specialization for associative and unordered containers.
1021     template<typename _Tp>
1022       struct emplace_point<_Tp, true, true, false>
1023       {
1024 	typedef _Tp 				       	container_type;
1025 	typedef typename container_type::value_type 	value_type;
1026 
1027 	void
1028 	operator()(_Tp& __test)
1029 	{
1030 	  try
1031 	    {
1032 	      const value_type cv = generate_unique<value_type>();
1033 	      const size_type sz = std::distance(__test.begin(), __test.end());
1034 	      size_type s = generate(sz);
1035 	      auto i = __test.begin();
1036 	      std::advance(i, s);
1037 	      __test.emplace_hint(i, cv);
1038 	    }
1039 	  catch(const __gnu_cxx::forced_error&)
1040 	    { throw; }
1041 	}
1042 
1043 	// Assumes containers start out equivalent.
1044 	void
1045 	operator()(_Tp& __control, _Tp& __test)
1046 	{
1047 	  try
1048 	    {
1049 	      const value_type cv = generate_unique<value_type>();
1050 	      const size_type sz = std::distance(__test.begin(), __test.end());
1051 	      size_type s = generate(sz);
1052 	      auto i = __test.begin();
1053 	      std::advance(i, s);
1054 	      __test.emplace_hint(i, cv);
1055 	    }
1056 	  catch(const __gnu_cxx::forced_error&)
1057 	    { throw; }
1058  	}
1059       };
1060 
1061     // Specialization for forward_list.
1062     template<typename _Tp>
1063       struct emplace_point<_Tp, true, false, true>
1064       {
1065 	typedef _Tp 				       	container_type;
1066 	typedef typename container_type::value_type 	value_type;
1067 
1068 	void
1069 	operator()(_Tp& __test)
1070 	{
1071 	  try
1072 	    {
1073 	      const value_type cv = generate_unique<value_type>();
1074 	      const size_type sz = std::distance(__test.begin(), __test.end());
1075 	      size_type s = generate(sz);
1076 	      auto i = __test.before_begin();
1077 	      std::advance(i, s);
1078 	      __test.emplace_after(i, cv);
1079 	    }
1080 	  catch(const __gnu_cxx::forced_error&)
1081 	    { throw; }
1082 	}
1083 
1084 	// Assumes containers start out equivalent.
1085 	void
1086 	operator()(_Tp& __control, _Tp& __test)
1087 	{
1088 	  try
1089 	    {
1090 	      const value_type cv = generate_unique<value_type>();
1091 	      const size_type sz = std::distance(__test.begin(), __test.end());
1092 	      size_type s = generate(sz);
1093 	      auto i = __test.before_begin();
1094 	      std::advance(i, s);
1095 	      __test.emplace_after(i, cv);
1096 	    }
1097 	  catch(const __gnu_cxx::forced_error&)
1098 	    { throw; }
1099  	}
1100       };
1101 
1102     // Specialization, empty.
1103     template<typename _Tp, bool is_associative_or_unordered,
1104 			   bool has_insert_after>
1105       struct emplace_point<_Tp, false, is_associative_or_unordered,
1106 			   has_insert_after>
1107       {
1108 	void
1109 	operator()(_Tp&) { }
1110 
1111 	void
1112 	operator()(_Tp&, _Tp&) { }
1113       };
1114 
1115     template<typename _Tp, bool = traits<_Tp>::is_associative::value
1116 				  || traits<_Tp>::is_unordered::value>
1117       struct clear
1118       {
1119 	void
1120 	operator()(_Tp& __container)
1121 	{
1122 	  try
1123 	    {
1124 	      __container.clear();
1125 	    }
1126 	  catch(const __gnu_cxx::forced_error&)
1127 	    { throw; }
1128 	}
1129       };
1130 
1131     // Specialization, empty.
1132     template<typename _Tp>
1133       struct clear<_Tp, false>
1134       {
1135 	void
1136 	operator()(_Tp&) { }
1137       };
1138 
1139 
1140     template<typename _Tp, bool = traits<_Tp>::is_unordered::value>
1141       struct rehash
1142       {
1143 	void
1144 	operator()(_Tp& __test)
1145 	{
1146 	  try
1147 	    {
1148 	      size_type s = generate(__test.bucket_count());
1149 	      __test.rehash(s);
1150 	    }
1151 	  catch(const __gnu_cxx::forced_error&)
1152 	    { throw; }
1153 	}
1154 
1155 	void
1156 	operator()(_Tp& __control, _Tp& __test)
1157 	{
1158 	  try
1159 	    {
1160 	      size_type s = generate(__test.bucket_count());
1161 	      __test.rehash(s);
1162 	    }
1163 	  catch(const __gnu_cxx::forced_error&)
1164 	    {
1165 	      // Also check hash status.
1166 	      bool fail(false);
1167 	      if (__control.load_factor() != __test.load_factor())
1168 		fail = true;
1169 	      if (__control.max_load_factor() != __test.max_load_factor())
1170 		fail = true;
1171 	      if (__control.bucket_count() != __test.bucket_count())
1172 		fail = true;
1173 	      if (__control.max_bucket_count() != __test.max_bucket_count())
1174 		fail = true;
1175 
1176 	      if (fail)
1177 		{
1178 		  char buf[40];
1179 		  std::string __s("setup_base::rehash "
1180 				  "containers not equal");
1181 		  __s += "\n";
1182 		  __s += "\n";
1183 		  __s += "\t\t\tcontrol : test";
1184 		  __s += "\n";
1185 		  __s += "load_factor\t\t";
1186 		  __builtin_sprintf(buf, "%lu", __control.load_factor());
1187 		  __s += buf;
1188 		  __s += " : ";
1189 		  __builtin_sprintf(buf, "%lu", __test.load_factor());
1190 		  __s += buf;
1191 		  __s += "\n";
1192 
1193 		  __s += "max_load_factor\t\t";
1194 		  __builtin_sprintf(buf, "%lu", __control.max_load_factor());
1195 		  __s += buf;
1196 		  __s += " : ";
1197 		  __builtin_sprintf(buf, "%lu", __test.max_load_factor());
1198 		  __s += buf;
1199 		  __s += "\n";
1200 
1201 		  __s += "bucket_count\t\t";
1202 		  __builtin_sprintf(buf, "%lu", __control.bucket_count());
1203 		  __s += buf;
1204 		  __s += " : ";
1205 		  __builtin_sprintf(buf, "%lu", __test.bucket_count());
1206 		  __s += buf;
1207 		  __s += "\n";
1208 
1209 		  __s += "max_bucket_count\t";
1210 		  __builtin_sprintf(buf, "%lu", __control.max_bucket_count());
1211 		  __s += buf;
1212 		  __s += " : ";
1213 		  __builtin_sprintf(buf, "%lu", __test.max_bucket_count());
1214 		  __s += buf;
1215 		  __s += "\n";
1216 
1217 		  std::__throw_logic_error(__s.c_str());
1218 		}
1219 	    }
1220  	}
1221       };
1222 
1223     // Specialization, empty.
1224     template<typename _Tp>
1225       struct rehash<_Tp, false>
1226       {
1227 	void
1228 	operator()(_Tp&) { }
1229 
1230 	void
1231 	operator()(_Tp&, _Tp&) { }
1232       };
1233 
1234 
1235     template<typename _Tp>
1236       struct swap
1237       {
1238 	_Tp _M_other;
1239 
1240 	void
1241 	operator()(_Tp& __container)
1242 	{
1243 	  try
1244 	    {
1245 	      __container.swap(_M_other);
1246 	    }
1247 	  catch(const __gnu_cxx::forced_error&)
1248 	    { throw; }
1249 	}
1250       };
1251 
1252 
1253     template<typename _Tp>
1254       struct iterator_operations
1255       {
1256 	typedef _Tp 					container_type;
1257 	typedef typename container_type::iterator       iterator;
1258 
1259 	void
1260 	operator()(_Tp& __container)
1261 	{
1262 	  try
1263 	    {
1264 	      // Any will do.
1265 	      iterator i = __container.begin();
1266 	      iterator __attribute__((unused)) icopy(i);
1267 	      iterator __attribute__((unused)) iassign = i;
1268 	    }
1269 	  catch(const __gnu_cxx::forced_error&)
1270 	    { throw; }
1271 	}
1272       };
1273 
1274 
1275     template<typename _Tp>
1276       struct const_iterator_operations
1277       {
1278 	typedef _Tp 					container_type;
1279 	typedef typename container_type::const_iterator	const_iterator;
1280 
1281 	void
1282 	operator()(_Tp& __container)
1283 	{
1284 	  try
1285 	    {
1286 	      // Any will do.
1287 	      const_iterator i = __container.begin();
1288 	      const_iterator __attribute__((unused)) icopy(i);
1289 	      const_iterator __attribute__((unused)) iassign = i;
1290 	    }
1291 	  catch(const __gnu_cxx::forced_error&)
1292 	    { throw; }
1293 	}
1294       };
1295   };
1296 
1297   // Base class for exception tests.
1298   template<typename _Tp>
1299     struct test_base: public functor_base
1300     {
1301       typedef _Tp 					container_type;
1302 
1303       typedef functor_base				base_type;
1304       typedef populate<container_type> 	       		populate;
1305       typedef make_container_n<container_type> 	       	make_container_n;
1306 
1307       typedef clear<container_type> 		       	clear;
1308       typedef erase_point<container_type> 	       	erase_point;
1309       typedef erase_range<container_type> 	       	erase_range;
1310       typedef insert_point<container_type> 	       	insert_point;
1311       typedef emplace<container_type>			emplace;
1312       typedef emplace_point<container_type>		emplace_point;
1313       typedef emplace_front<container_type>		emplace_front;
1314       typedef emplace_back<container_type>		emplace_back;
1315       typedef pop_front<container_type> 	       	pop_front;
1316       typedef pop_back<container_type> 			pop_back;
1317       typedef push_front<container_type> 	       	push_front;
1318       typedef push_back<container_type> 	       	push_back;
1319       typedef rehash<container_type> 			rehash;
1320       typedef swap<container_type> 			swap;
1321       typedef iterator_operations<container_type>	iterator_ops;
1322       typedef const_iterator_operations<container_type>	const_iterator_ops;
1323 
1324       using base_type::compare;
1325 
1326       // Functor objects.
1327       clear			_M_clear;
1328       erase_point		_M_erasep;
1329       erase_range		_M_eraser;
1330       insert_point		_M_insertp;
1331       emplace			_M_emplace;
1332       emplace_point		_M_emplacep;
1333       emplace_front		_M_emplacef;
1334       emplace_back		_M_emplaceb;
1335       pop_front			_M_popf;
1336       pop_back			_M_popb;
1337       push_front	       	_M_pushf;
1338       push_back			_M_pushb;
1339       rehash			_M_rehash;
1340       swap			_M_swap;
1341 
1342       iterator_ops	       	_M_iops;
1343       const_iterator_ops	_M_ciops;
1344     };
1345 
1346 
1347   // Run through all member functions for basic exception safety
1348   // guarantee: no resource leaks when exceptions are thrown.
1349   //
1350   // Types of resources checked: memory.
1351   //
1352   // For each member function, use throw_value and throw_allocator as
1353   // value_type and allocator_type to force potential exception safety
1354   // errors.
1355   //
1356   // NB: Assumes
1357   // _Tp::value_type is __gnu_cxx::throw_value_*
1358   // _Tp::allocator_type is __gnu_cxx::throw_allocator_*
1359   // And that the _Cond template parameter for them both is
1360   // __gnu_cxx::limit_condition.
1361   template<typename _Tp>
1362     struct basic_safety : public test_base<_Tp>
1363     {
1364       typedef _Tp 					container_type;
1365       typedef test_base<container_type>			base_type;
1366       typedef typename base_type::populate 		populate;
1367       typedef std::function<void(container_type&)> 	function_type;
1368       typedef __gnu_cxx::limit_condition		condition_type;
1369 
1370       using base_type::generate;
1371 
1372       container_type 					_M_container;
1373       std::vector<function_type>			_M_functions;
1374 
1375       basic_safety() { run(); }
1376 
1377       void
1378       run()
1379       {
1380 	// Setup.
1381 	condition_type::never_adjustor off;
1382 
1383 	// Construct containers.
1384 	populate p1(_M_container);
1385 	populate p2(base_type::_M_swap._M_other);
1386 
1387 	// Construct list of member functions to exercise.
1388 	_M_functions.push_back(function_type(base_type::_M_iops));
1389 	_M_functions.push_back(function_type(base_type::_M_ciops));
1390 
1391 	_M_functions.push_back(function_type(base_type::_M_erasep));
1392 	_M_functions.push_back(function_type(base_type::_M_eraser));
1393 	_M_functions.push_back(function_type(base_type::_M_insertp));
1394 	_M_functions.push_back(function_type(base_type::_M_emplace));
1395 	_M_functions.push_back(function_type(base_type::_M_emplacep));
1396 	_M_functions.push_back(function_type(base_type::_M_emplacef));
1397 	_M_functions.push_back(function_type(base_type::_M_emplaceb));
1398 	_M_functions.push_back(function_type(base_type::_M_popf));
1399 	_M_functions.push_back(function_type(base_type::_M_popb));
1400 	_M_functions.push_back(function_type(base_type::_M_pushf));
1401 	_M_functions.push_back(function_type(base_type::_M_pushb));
1402 	_M_functions.push_back(function_type(base_type::_M_rehash));
1403 	_M_functions.push_back(function_type(base_type::_M_swap));
1404 
1405 	// Last.
1406 	_M_functions.push_back(function_type(base_type::_M_clear));
1407 
1408 	// Run tests.
1409 	for (auto i = _M_functions.begin(); i != _M_functions.end(); ++i)
1410 	  {
1411 	    function_type& f = *i;
1412 	    run_steps_to_limit(f);
1413 	  }
1414       }
1415 
1416       template<typename _Funct>
1417 	void
1418 	run_steps_to_limit(const _Funct& __f)
1419 	{
1420 	  size_t i(1);
1421 	  bool exit(false);
1422 	  auto a = _M_container.get_allocator();
1423 
1424 	  do
1425 	    {
1426 	      // Use the current step as an allocator label.
1427 	      a.set_label(i);
1428 
1429 	      try
1430 		{
1431 		  condition_type::limit_adjustor limit(i);
1432 		  __f(_M_container);
1433 
1434 		  // If we get here, done.
1435 		  exit = true;
1436 		}
1437 	      catch(const __gnu_cxx::forced_error&)
1438 		{
1439 		  // Check this step for allocations.
1440 		  // NB: Will throw std::logic_error if allocations.
1441 		  a.check_allocated(i);
1442 
1443 		  // Check memory allocated with operator new.
1444 
1445 		  ++i;
1446 		}
1447 	    }
1448 	  while (!exit);
1449 
1450 	  // Log count info.
1451 	  std::cout << __f.target_type().name() << std::endl;
1452 	  std::cout << "end count " << i << std::endl;
1453 	}
1454   };
1455 
1456 
1457   // Run through all member functions with a no throw requirement, sudden death.
1458   // all: member functions erase, pop_back, pop_front, swap
1459   //      iterator copy ctor, assignment operator
1460   // unordered and associative: clear
1461   // NB: Assumes _Tp::allocator_type is __gnu_cxx::throw_allocator_random.
1462   template<typename _Tp>
1463     struct generation_prohibited : public test_base<_Tp>
1464     {
1465       typedef _Tp 					container_type;
1466       typedef test_base<container_type>			base_type;
1467       typedef typename base_type::populate 		populate;
1468       typedef __gnu_cxx::random_condition		condition_type;
1469 
1470       container_type 					_M_container;
1471 
1472       generation_prohibited()  { run(); }
1473 
1474       void
1475       run()
1476       {
1477 	// Furthermore, assumes that the test functor will throw
1478 	// forced_exception via throw_allocator, that all errors are
1479 	// propagated and in error. Sudden death!
1480 
1481 	// Setup.
1482 	{
1483 	  condition_type::never_adjustor off;
1484 	  populate p1(_M_container);
1485 	  populate p2(base_type::_M_swap._M_other);
1486 	}
1487 
1488 	// Run tests.
1489 	{
1490 	  condition_type::always_adjustor on;
1491 
1492 	  // NB: Vector and deque are special, erase can throw if the copy
1493 	  // constructor or assignment operator of value_type throws.
1494 	  if (!traits<container_type>::has_throwing_erase::value)
1495 	    {
1496 	      this->_M_erasep(_M_container);
1497 	      this->_M_eraser(_M_container);
1498 	    }
1499 
1500 	  this->_M_popf(_M_container);
1501 	  this->_M_popb(_M_container);
1502 
1503 	  this->_M_iops(_M_container);
1504 	  this->_M_ciops(_M_container);
1505 
1506 	  this->_M_swap(_M_container);
1507 
1508 	  // Last.
1509 	  this->_M_clear(_M_container);
1510 	}
1511       }
1512     };
1513 
1514 
1515   // Test strong exception guarantee.
1516   // Run through all member functions with a roll-back, consistent
1517   // coherent requirement.
1518   // all: member functions insert and emplace of a single element, push_back,
1519   // push_front
1520   // unordered: rehash
1521   template<typename _Tp>
1522     struct propagation_consistent : public test_base<_Tp>
1523     {
1524       typedef _Tp 					container_type;
1525       typedef test_base<container_type>			base_type;
1526       typedef typename base_type::populate 		populate;
1527       typedef std::function<void(container_type&)> 	function_type;
1528       typedef __gnu_cxx::limit_condition		condition_type;
1529 
1530       using base_type::compare;
1531 
1532       container_type 					_M_container_test;
1533       container_type 					_M_container_control;
1534       std::vector<function_type>			_M_functions;
1535 
1536       propagation_consistent() { run(); }
1537 
1538       void
1539       sync()
1540       { _M_container_test = _M_container_control; }
1541 
1542       // Run test.
1543       void
1544       run()
1545       {
1546 	// Setup.
1547 	condition_type::never_adjustor off;
1548 
1549 	// Construct containers.
1550 	populate p(_M_container_control);
1551 
1552 	// Construct list of member functions to exercise.
1553 	_M_functions.push_back(function_type(base_type::_M_emplace));
1554 	_M_functions.push_back(function_type(base_type::_M_emplacep));
1555 	_M_functions.push_back(function_type(base_type::_M_emplacef));
1556 	_M_functions.push_back(function_type(base_type::_M_emplaceb));
1557 	_M_functions.push_back(function_type(base_type::_M_pushf));
1558 	_M_functions.push_back(function_type(base_type::_M_pushb));
1559 	_M_functions.push_back(function_type(base_type::_M_insertp));
1560 	_M_functions.push_back(function_type(base_type::_M_rehash));
1561 
1562 	// Run tests.
1563 	for (auto i = _M_functions.begin(); i != _M_functions.end(); ++i)
1564 	  {
1565 	    function_type& f = *i;
1566 	    run_steps_to_limit(f);
1567 	  }
1568       }
1569 
1570       template<typename _Funct>
1571 	void
1572 	run_steps_to_limit(const _Funct& __f)
1573 	{
1574 	  size_t i(1);
1575 	  bool exit(false);
1576 
1577 	  do
1578 	    {
1579 	      sync();
1580 
1581 	      try
1582 		{
1583 		  condition_type::limit_adjustor limit(i);
1584 		  __f(_M_container_test);
1585 
1586 		  // If we get here, done.
1587 		  exit = true;
1588 		}
1589 	      catch(const __gnu_cxx::forced_error&)
1590 		{
1591 		  compare(_M_container_control, _M_container_test);
1592 		  ++i;
1593 		}
1594 	    }
1595 	  while (!exit);
1596 
1597 	  // Log count info.
1598 	  std::cout << __f.target_type().name() << std::endl;
1599 	  std::cout << "end count " << i << std::endl;
1600 	}
1601     };
1602 
1603 } // namespace __gnu_test
1604 
1605 #endif
1606