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