]>
Commit | Line | Data |
---|---|---|
53179144 BK |
1 | // -*- C++ -*- |
2 | ||
818ab71a | 3 | // Copyright (C) 2009-2016 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. | |
27 | namespace __gnu_test | |
28 | { | |
29 | // Base class for exception testing, contains utilities. | |
30 | struct setup_base | |
31 | { | |
32 | typedef std::size_t size_type; | |
33 | typedef std::uniform_int_distribution<size_type> distribution_type; | |
34 | typedef std::mt19937 engine_type; | |
35 | ||
36 | // Return randomly generated integer on range [0, __max_size]. | |
37 | static size_type | |
38 | generate(size_type __max_size) | |
39 | { | |
40 | // Make the generator static... | |
41 | const engine_type engine; | |
42 | const distribution_type distribution; | |
43 | static auto generator = std::bind(distribution, engine, | |
44 | std::placeholders::_1); | |
45 | ||
46 | // ... but set the range for this particular invocation here. | |
47 | const typename distribution_type::param_type p(0, __max_size); | |
48 | size_type random = generator(p); | |
49 | if (random < distribution.min() || random > distribution.max()) | |
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 | |
615 | && traits<_Tp>::has_emplace::value | |
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)); | |
53179144 | 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)); | |
1355 | #endif | |
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 |