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