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