1 /* 2 Copyright (c) 2005-2020 Intel Corporation 3 4 Licensed under the Apache License, Version 2.0 (the "License"); 5 you may not use this file except in compliance with the License. 6 You may obtain a copy of the License at 7 8 http://www.apache.org/licenses/LICENSE-2.0 9 10 Unless required by applicable law or agreed to in writing, software 11 distributed under the License is distributed on an "AS IS" BASIS, 12 WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 13 See the License for the specific language governing permissions and 14 limitations under the License. 15 */ 16 17 #if _MSC_VER && !defined(__INTEL_COMPILER) 18 // Workaround for vs2015 and warning name was longer than the compiler limit (4096). 19 #pragma warning (push) 20 #pragma warning (disable: 4503) 21 #endif 22 23 #include <common/test.h> 24 #include <common/utils.h> 25 #include <common/range_based_for_support.h> 26 #include <common/custom_allocators.h> 27 #include <common/containers_common.h> 28 #define TBB_DEFINE_STD_HASH_SPECIALIZATIONS 1 29 #include <tbb/concurrent_hash_map.h> 30 #include <tbb/parallel_for.h> 31 #include <common/concurrent_associative_common.h> 32 #include <vector> 33 #include <list> 34 #include <algorithm> 35 #include <functional> 36 #include <scoped_allocator> 37 38 //! \file test_concurrent_hash_map.cpp 39 //! \brief Test for [containers.concurrent_hash_map containers.tbb_hash_compare] specification 40 41 void TestRangeBasedFor(){ 42 using namespace range_based_for_support_tests; 43 44 INFO("testing range based for loop compatibility \n"); 45 using ch_map = tbb::concurrent_hash_map<int,int>; 46 ch_map a_ch_map; 47 48 const int sequence_length = 100; 49 for (int i = 1; i <= sequence_length; ++i){ 50 a_ch_map.insert(ch_map::value_type(i,i)); 51 } 52 53 REQUIRE_MESSAGE((range_based_for_accumulate(a_ch_map, pair_second_summer(), 0) == gauss_summ_of_int_sequence(sequence_length)), 54 "incorrect accumulated value generated via range based for ?"); 55 } 56 57 // The helper to run a test only when a default construction is present. 58 template <bool default_construction_present> struct do_default_construction_test { 59 template<typename FuncType> void operator() ( FuncType func ) const { func(); } 60 }; 61 62 template <> struct do_default_construction_test<false> { 63 template<typename FuncType> void operator()( FuncType ) const {} 64 }; 65 66 template <typename Table> 67 class test_insert_by_key { 68 using value_type = typename Table::value_type; 69 Table &my_c; 70 const value_type &my_value; 71 public: 72 test_insert_by_key( Table &c, const value_type &value ) : my_c(c), my_value(value) {} 73 void operator()() const { 74 { 75 typename Table::accessor a; 76 CHECK(my_c.insert( a, my_value.first )); 77 CHECK(utils::IsEqual()(a->first, my_value.first)); 78 a->second = my_value.second; 79 } 80 { 81 typename Table::const_accessor ca; 82 CHECK(!my_c.insert( ca, my_value.first )); 83 CHECK(utils::IsEqual()(ca->first, my_value.first)); 84 CHECK(utils::IsEqual()(ca->second, my_value.second)); 85 } 86 } 87 }; 88 89 template <typename Table, typename Iterator, typename Range = typename Table::range_type> 90 class test_range { 91 using value_type = typename Table::value_type; 92 Table &my_c; 93 const std::list<value_type> &my_lst; 94 std::vector<detail::atomic_type<bool>>& my_marks; 95 public: 96 test_range( Table &c, const std::list<value_type> &lst, std::vector<detail::atomic_type<bool>> &marks ) : my_c(c), my_lst(lst), my_marks(marks) { 97 for (std::size_t i = 0; i < my_marks.size(); ++i) { 98 my_marks[i].store(false, std::memory_order_relaxed); 99 } 100 } 101 102 void operator()( const Range &r ) const { do_test_range( r.begin(), r.end() ); } 103 void do_test_range( Iterator i, Iterator j ) const { 104 for ( Iterator it = i; it != j; ) { 105 Iterator it_prev = it++; 106 typename std::list<value_type>::const_iterator it2 = std::search( my_lst.begin(), my_lst.end(), it_prev, it, utils::IsEqual() ); 107 CHECK(it2 != my_lst.end()); 108 typename std::list<value_type>::difference_type dist = std::distance( my_lst.begin(), it2 ); 109 CHECK(!my_marks[dist]); 110 my_marks[dist].store(true); 111 } 112 } 113 }; 114 115 template <bool default_construction_present, typename Table> 116 class check_value { 117 using const_iterator = typename Table::const_iterator; 118 using iterator = typename Table::iterator; 119 using size_type = typename Table::size_type; 120 Table &my_c; 121 public: 122 check_value( Table &c ) : my_c(c) {} 123 void operator()(const typename Table::value_type &value ) { 124 const Table &const_c = my_c; 125 CHECK(my_c.count( value.first ) == 1); 126 { // tests with a const accessor. 127 typename Table::const_accessor ca; 128 // find 129 CHECK(my_c.find( ca, value.first )); 130 CHECK(!ca.empty() ); 131 CHECK(utils::IsEqual()(ca->first, value.first)); 132 CHECK(utils::IsEqual()(ca->second, value.second)); 133 // erase 134 CHECK(my_c.erase( ca )); 135 CHECK(my_c.count( value.first ) == 0); 136 // insert (pair) 137 CHECK(my_c.insert( ca, value )); 138 CHECK(utils::IsEqual()(ca->first, value.first)); 139 CHECK(utils::IsEqual()(ca->second, value.second)); 140 } { // tests with a non-const accessor. 141 typename Table::accessor a; 142 // find 143 CHECK(my_c.find( a, value.first )); 144 CHECK(!a.empty() ); 145 CHECK(utils::IsEqual()(a->first, value.first)); 146 CHECK(utils::IsEqual()(a->second, value.second)); 147 // erase 148 CHECK(my_c.erase( a )); 149 CHECK(my_c.count( value.first ) == 0); 150 // insert 151 CHECK(my_c.insert( a, value )); 152 CHECK(utils::IsEqual()(a->first, value.first)); 153 CHECK(utils::IsEqual()(a->second, value.second)); 154 } 155 // erase by key 156 CHECK(my_c.erase( value.first )); 157 CHECK(my_c.count( value.first ) == 0); 158 do_default_construction_test<default_construction_present>()(test_insert_by_key<Table>( my_c, value )); 159 // insert by value 160 CHECK(my_c.insert( value ) != default_construction_present); 161 // equal_range 162 std::pair<iterator,iterator> r1 = my_c.equal_range( value.first ); 163 iterator r1_first_prev = r1.first++; 164 CHECK((utils::IsEqual()( *r1_first_prev, value ) && utils::IsEqual()( r1.first, r1.second ))); 165 std::pair<const_iterator,const_iterator> r2 = const_c.equal_range( value.first ); 166 const_iterator r2_first_prev = r2.first++; 167 CHECK((utils::IsEqual()( *r2_first_prev, value ) && utils::IsEqual()( r2.first, r2.second ))); 168 } 169 }; 170 171 template <typename Value, typename U = Value> 172 struct CompareTables { 173 template <typename T> 174 static bool IsEqual( const T& t1, const T& t2 ) { 175 return (t1 == t2) && !(t1 != t2); 176 } 177 }; 178 179 template <typename U> 180 struct CompareTables< std::pair<const std::weak_ptr<U>, std::weak_ptr<U> > > { 181 template <typename T> 182 static bool IsEqual( const T&, const T& ) { 183 /* do nothing for std::weak_ptr */ 184 return true; 185 } 186 }; 187 188 template <bool default_construction_present, typename Table> 189 void Examine( Table c, const std::list<typename Table::value_type> &lst) { 190 using const_table = const Table; 191 using const_iterator = typename Table::const_iterator; 192 using iterator = typename Table::iterator; 193 using value_type = typename Table::value_type; 194 using size_type = typename Table::size_type; 195 196 CHECK(!c.empty()); 197 CHECK(c.size() == lst.size()); 198 CHECK(c.max_size() >= c.size()); 199 200 const check_value<default_construction_present, Table> cv(c); 201 std::for_each( lst.begin(), lst.end(), cv ); 202 203 std::vector<detail::atomic_type<bool>> marks( lst.size() ); 204 205 test_range<Table,iterator>( c, lst, marks ).do_test_range( c.begin(), c.end() ); 206 CHECK(std::find( marks.begin(), marks.end(), false ) == marks.end()); 207 208 test_range<const_table,const_iterator>( c, lst, marks ).do_test_range( c.begin(), c.end() ); 209 CHECK(std::find( marks.begin(), marks.end(), false ) == marks.end()); 210 211 using range_type = typename Table::range_type; 212 tbb::parallel_for( c.range(), test_range<Table,typename range_type::iterator,range_type>( c, lst, marks ) ); 213 CHECK(std::find( marks.begin(), marks.end(), false ) == marks.end()); 214 215 const_table const_c = c; 216 CHECK(CompareTables<value_type>::IsEqual( c, const_c )); 217 218 const size_type new_bucket_count = 2*c.bucket_count(); 219 c.rehash( new_bucket_count ); 220 CHECK(c.bucket_count() >= new_bucket_count); 221 222 Table c2; 223 typename std::list<value_type>::const_iterator begin5 = lst.begin(); 224 std::advance( begin5, 5 ); 225 c2.insert( lst.begin(), begin5 ); 226 std::for_each( lst.begin(), begin5, check_value<default_construction_present, Table>( c2 ) ); 227 228 c2.swap( c ); 229 CHECK(CompareTables<value_type>::IsEqual( c2, const_c )); 230 CHECK(c.size() == 5); 231 std::for_each( lst.begin(), lst.end(), check_value<default_construction_present,Table>(c2) ); 232 233 swap( c, c2 ); 234 CHECK(CompareTables<value_type>::IsEqual( c, const_c )); 235 CHECK(c2.size() == 5); 236 237 c2.clear(); 238 CHECK(CompareTables<value_type>::IsEqual( c2, Table() )); 239 240 typename Table::allocator_type a = c.get_allocator(); 241 value_type *ptr = a.allocate(1); 242 CHECK(ptr); 243 a.deallocate( ptr, 1 ); 244 } 245 246 template <typename T> 247 struct debug_hash_compare : public tbb::detail::d1::tbb_hash_compare<T> {}; 248 249 template <bool default_construction_present, typename Value> 250 void TypeTester( const std::list<Value> &lst ) { 251 using first_type = typename Value::first_type; 252 using key_type = typename std::remove_const<first_type>::type; 253 using second_type = typename Value::second_type; 254 using ch_map = tbb::concurrent_hash_map<key_type, second_type>; 255 debug_hash_compare<key_type> compare{}; 256 // Construct an empty hash map. 257 ch_map c1; 258 c1.insert( lst.begin(), lst.end() ); 259 Examine<default_construction_present>( c1, lst ); 260 261 // Constructor from initializer_list. 262 typename std::list<Value>::const_iterator it = lst.begin(); 263 std::initializer_list<Value> il = { *it++, *it++, *it++ }; 264 ch_map c2( il ); 265 c2.insert( it, lst.end() ); 266 Examine<default_construction_present>( c2, lst ); 267 268 // Constructor from initializer_list and compare object 269 ch_map c3( il, compare); 270 c3.insert( it, lst.end() ); 271 Examine<default_construction_present>( c3, lst ); 272 273 // Constructor from initializer_list, compare object and allocator 274 ch_map c4( il, compare, typename ch_map::allocator_type()); 275 c4.insert( it, lst.end()); 276 Examine<default_construction_present>( c4, lst ); 277 278 // Copying constructor. 279 ch_map c5(c1); 280 Examine<default_construction_present>( c5, lst ); 281 // Construct with non-default allocator 282 using ch_map_debug_alloc = tbb::concurrent_hash_map<key_type, second_type, 283 tbb::detail::d1::tbb_hash_compare<key_type>, 284 LocalCountingAllocator<std::allocator<Value>>>; 285 ch_map_debug_alloc c6; 286 c6.insert( lst.begin(), lst.end() ); 287 Examine<default_construction_present>( c6, lst ); 288 // Copying constructor 289 ch_map_debug_alloc c7(c6); 290 Examine<default_construction_present>( c7, lst ); 291 // Construction empty table with n preallocated buckets. 292 ch_map c8( lst.size() ); 293 c8.insert( lst.begin(), lst.end() ); 294 Examine<default_construction_present>( c8, lst ); 295 ch_map_debug_alloc c9( lst.size() ); 296 c9.insert( lst.begin(), lst.end() ); 297 Examine<default_construction_present>( c9, lst ); 298 // Construction with copying iteration range. 299 ch_map c10_1( c1.begin(), c1.end() ), c10_2(c1.cbegin(), c1.cend()); 300 Examine<default_construction_present>( c10_1, lst ); 301 Examine<default_construction_present>( c10_2, lst ); 302 // Construction with copying iteration range and given allocator instance. 303 LocalCountingAllocator<std::allocator<Value>> allocator; 304 ch_map_debug_alloc c11( lst.begin(), lst.end(), allocator ); 305 Examine<default_construction_present>( c11, lst ); 306 307 using ch_map_debug_hash = tbb::concurrent_hash_map<key_type, second_type, 308 debug_hash_compare<key_type>, 309 typename ch_map::allocator_type>; 310 311 // Constructor with two iterators and hash_compare 312 ch_map_debug_hash c12(c1.begin(), c1.end(), compare); 313 Examine<default_construction_present>( c12, lst ); 314 315 ch_map_debug_hash c13(c1.begin(), c1.end(), compare, typename ch_map::allocator_type()); 316 Examine<default_construction_present>( c13, lst ); 317 } 318 319 void TestSpecificTypes() { 320 const int NUMBER = 10; 321 322 using int_int_t = std::pair<const int, int>; 323 std::list<int_int_t> arrIntInt; 324 for ( int i=0; i<NUMBER; ++i ) arrIntInt.push_back( int_int_t(i, NUMBER-i) ); 325 TypeTester</*default_construction_present = */true>( arrIntInt ); 326 327 using ref_int_t = std::pair<const std::reference_wrapper<const int>, int>; 328 std::list<ref_int_t> arrRefInt; 329 for ( std::list<int_int_t>::iterator it = arrIntInt.begin(); it != arrIntInt.end(); ++it ) 330 arrRefInt.push_back( ref_int_t( it->first, it->second ) ); 331 TypeTester</*default_construction_present = */true>( arrRefInt ); 332 333 using int_ref_t = std::pair< const int, std::reference_wrapper<int> >; 334 std::list<int_ref_t> arrIntRef; 335 for ( std::list<int_int_t>::iterator it = arrIntInt.begin(); it != arrIntInt.end(); ++it ) 336 arrIntRef.push_back( int_ref_t( it->first, it->second ) ); 337 TypeTester</*default_construction_present = */false>( arrIntRef ); 338 339 using shr_shr_t = std::pair< const std::shared_ptr<int>, std::shared_ptr<int> >; 340 std::list<shr_shr_t> arrShrShr; 341 for ( int i=0; i<NUMBER; ++i ) { 342 const int NUMBER_minus_i = NUMBER - i; 343 arrShrShr.push_back( shr_shr_t( std::make_shared<int>(i), std::make_shared<int>(NUMBER_minus_i) ) ); 344 } 345 TypeTester< /*default_construction_present = */true>( arrShrShr ); 346 347 using wk_wk_t = std::pair< const std::weak_ptr<int>, std::weak_ptr<int> >; 348 std::list< wk_wk_t > arrWkWk; 349 std::copy( arrShrShr.begin(), arrShrShr.end(), std::back_inserter(arrWkWk) ); 350 TypeTester< /*default_construction_present = */true>( arrWkWk ); 351 352 // Check working with deprecated hashers 353 using pair_key_type = std::pair<int, int>; 354 using pair_int_t = std::pair<const pair_key_type, int>; 355 std::list<pair_int_t> arr_pair_int; 356 for (int i = 0; i < NUMBER; ++i) { 357 arr_pair_int.push_back(pair_int_t(pair_key_type{i, i}, i)); 358 } 359 TypeTester</*default_construction_present = */true>(arr_pair_int); 360 361 using tbb_string_key_type = std::basic_string<char, std::char_traits<char>, tbb::tbb_allocator<char>>; 362 using pair_tbb_string_int_t = std::pair<const tbb_string_key_type, int>; 363 std::list<pair_tbb_string_int_t> arr_pair_string_int; 364 for (int i = 0; i < NUMBER; ++i) { 365 tbb_string_key_type key(i, char(i)); 366 arr_pair_string_int.push_back(pair_tbb_string_int_t(key, i)); 367 } 368 TypeTester</*default_construction_present = */true>(arr_pair_string_int); 369 } 370 371 struct custom_hash_compare { 372 template<typename Allocator> 373 size_t hash(const AllocatorAwareData<Allocator>& key) const { 374 return my_hash_compare.hash(key.value()); 375 } 376 377 template<typename Allocator> 378 bool equal(const AllocatorAwareData<Allocator>& key1, const AllocatorAwareData<Allocator>& key2) const { 379 return my_hash_compare.equal(key1.value(), key2.value()); 380 } 381 382 private: 383 tbb::tbb_hash_compare<int> my_hash_compare; 384 }; 385 386 void TestScopedAllocator() { 387 using allocator_data_type = AllocatorAwareData<std::scoped_allocator_adaptor<tbb::tbb_allocator<int>>>; 388 using allocator_type = std::scoped_allocator_adaptor<tbb::tbb_allocator<std::pair<const allocator_data_type, allocator_data_type>>>; 389 using hash_map_type = tbb::concurrent_hash_map<allocator_data_type, allocator_data_type, 390 custom_hash_compare, allocator_type>; 391 392 allocator_type allocator; 393 allocator_data_type key1(1, allocator), key2(2, allocator); 394 allocator_data_type data1(1, allocator), data2(data1, allocator); 395 hash_map_type map1(allocator), map2(allocator); 396 397 hash_map_type::value_type v1(key1, data1), v2(key2, data2); 398 399 auto init_list = { v1, v2 }; 400 401 allocator_data_type::assert_on_constructions = true; 402 map1.emplace(key1, data1); 403 map2.emplace(key2, std::move(data2)); 404 405 map1.clear(); 406 map2.clear(); 407 408 map1.insert(v1); 409 map2.insert(std::move(v2)); 410 411 map1.clear(); 412 map2.clear(); 413 414 map1.insert(init_list); 415 416 map1.clear(); 417 map2.clear(); 418 419 hash_map_type::accessor a; 420 map2.insert(a, allocator_data_type(3)); 421 a.release(); 422 423 map1 = map2; 424 map2 = std::move(map1); 425 426 hash_map_type map3(allocator); 427 map3.rehash(1000); 428 map3 = map2; 429 } 430 431 // A test for undocumented member function internal_fast_find 432 // which is declared protected in concurrent_hash_map for internal TBB use 433 void TestInternalFastFind() { 434 typedef tbb::concurrent_hash_map<int, int> basic_chmap_type; 435 typedef basic_chmap_type::const_pointer const_pointer; 436 437 class chmap : public basic_chmap_type { 438 public: 439 chmap() : basic_chmap_type() {} 440 441 using basic_chmap_type::internal_fast_find; 442 }; 443 444 chmap m; 445 int sz = 100; 446 447 for (int i = 0; i != sz; ++i) { 448 m.insert(std::make_pair(i, i * i)); 449 } 450 REQUIRE_MESSAGE(m.size() == 100, "Incorrect concurrent_hash_map size"); 451 452 for (int i = 0; i != sz; ++i) { 453 const_pointer res = m.internal_fast_find(i); 454 REQUIRE_MESSAGE(res != nullptr, "Incorrect internal_fast_find return value for existing key"); 455 basic_chmap_type::value_type val = *res; 456 REQUIRE_MESSAGE(val.first == i, "Incorrect key in internal_fast_find return value"); 457 REQUIRE_MESSAGE(val.second == i * i, "Incorrect mapped in internal_fast_find return value"); 458 } 459 460 for (int i = sz; i != 2 * sz; ++i) { 461 const_pointer res = m.internal_fast_find(i); 462 REQUIRE_MESSAGE(res == nullptr, "Incorrect internal_fast_find return value for not existing key"); 463 } 464 } 465 466 struct default_container_traits { 467 template <typename container_type, typename iterator_type> 468 static container_type& construct_container(typename std::aligned_storage<sizeof(container_type)>::type& storage, iterator_type begin, iterator_type end){ 469 container_type* ptr = reinterpret_cast<container_type*>(&storage); 470 new (ptr) container_type(begin, end); 471 return *ptr; 472 } 473 474 template <typename container_type, typename iterator_type, typename allocator_type> 475 static container_type& construct_container(typename std::aligned_storage<sizeof(container_type)>::type& storage, iterator_type begin, iterator_type end, allocator_type const& a){ 476 container_type* ptr = reinterpret_cast<container_type*>(&storage); 477 new (ptr) container_type(begin, end, a); 478 return *ptr; 479 } 480 }; 481 482 struct hash_map_traits : default_container_traits { 483 enum{ expected_number_of_items_to_allocate_for_steal_move = 0 }; 484 485 template<typename T> 486 struct hash_compare { 487 bool equal( const T& lhs, const T& rhs ) const { 488 return lhs==rhs; 489 } 490 size_t hash( const T& k ) const { 491 return my_hash_func(k); 492 } 493 std::hash<T> my_hash_func; 494 }; 495 496 template <typename T, typename Allocator> 497 using container_type = tbb::concurrent_hash_map<T, T, hash_compare<T>, Allocator>; 498 499 template <typename T> 500 using container_value_type = std::pair<const T, T>; 501 502 template<typename element_type, typename allocator_type> 503 struct apply { 504 using type = tbb::concurrent_hash_map<element_type, element_type, hash_compare<element_type>, allocator_type>; 505 }; 506 507 using init_iterator_type = move_support_tests::FooPairIterator; 508 template <typename hash_map_type, typename iterator> 509 static bool equal(hash_map_type const& c, iterator begin, iterator end){ 510 bool equal_sizes = ( static_cast<size_t>(std::distance(begin, end)) == c.size() ); 511 if (!equal_sizes) 512 return false; 513 514 for (iterator it = begin; it != end; ++it ){ 515 if (c.count( (*it).first) == 0){ 516 return false; 517 } 518 } 519 return true; 520 } 521 }; 522 523 //! Test of insert operation 524 //! \brief \ref error_guessing 525 TEST_CASE("testing range based for support"){ 526 TestRangeBasedFor(); 527 } 528 529 //! Test concurrent_hash_map with specific key/mapped types 530 //! \brief \ref regression \ref error_guessing 531 TEST_CASE("testing concurrent_hash_map with specific key/mapped types") { 532 TestSpecificTypes(); 533 } 534 535 //! Test work with scoped allocator 536 //! \brief \ref regression 537 TEST_CASE("testing work with scoped allocator") { 538 TestScopedAllocator(); 539 } 540 541 //! Test internal fast find for concurrent_hash_map 542 //! \brief \ref regression 543 TEST_CASE("testing internal fast find for concurrent_hash_map") { 544 TestInternalFastFind(); 545 } 546 547 //! Test constructor with move iterators 548 //! \brief \ref error_guessing 549 TEST_CASE("testing constructor with move iterators"){ 550 move_support_tests::test_constructor_with_move_iterators<hash_map_traits>(); 551 } 552 553 #if TBB_USE_EXCEPTIONS 554 //! Test exception in constructors 555 //! \brief \ref regression \ref error_guessing 556 TEST_CASE("Test exception in constructors") { 557 using allocator_type = StaticSharedCountingAllocator<std::allocator<std::pair<const int, int>>>; 558 using map_type = tbb::concurrent_hash_map<int, int, tbb::tbb_hash_compare<int>, allocator_type>; 559 560 auto init_list = {std::pair<const int, int>(1, 42), std::pair<const int, int>(2, 42), std::pair<const int, int>(3, 42), 561 std::pair<const int, int>(4, 42), std::pair<const int, int>(5, 42), std::pair<const int, int>(6, 42)}; 562 map_type map(init_list); 563 564 allocator_type::set_limits(1); 565 REQUIRE_THROWS_AS( [&] { 566 map_type map1(map); 567 utils::suppress_unused_warning(map1); 568 }(), const std::bad_alloc); 569 570 REQUIRE_THROWS_AS( [&] { 571 map_type map2(init_list.begin(), init_list.end()); 572 utils::suppress_unused_warning(map2); 573 }(), const std::bad_alloc); 574 575 tbb::tbb_hash_compare<int> test_hash; 576 577 REQUIRE_THROWS_AS( [&] { 578 map_type map3(init_list.begin(), init_list.end(), test_hash); 579 utils::suppress_unused_warning(map3); 580 }(), const std::bad_alloc); 581 582 REQUIRE_THROWS_AS( [&] { 583 map_type map4(init_list, test_hash); 584 utils::suppress_unused_warning(map4); 585 }(), const std::bad_alloc); 586 587 REQUIRE_THROWS_AS( [&] { 588 map_type map5(init_list); 589 utils::suppress_unused_warning(map5); 590 }(), const std::bad_alloc); 591 592 allocator_type::set_limits(0); 593 map_type big_map{}; 594 for (std::size_t i = 0; i < 1000; ++i) { 595 big_map.insert(std::pair<const int, int>(i, 42)); 596 } 597 598 allocator_type::init_counters(); 599 allocator_type::set_limits(300); 600 REQUIRE_THROWS_AS( [&] { 601 map_type map6(big_map); 602 utils::suppress_unused_warning(map6); 603 }(), const std::bad_alloc); 604 } 605 #endif // TBB_USE_EXCEPTIONS 606 607 //! \brief \ref error_guessing 608 TEST_CASE("swap with NotAlwaysEqualAllocator allocators"){ 609 using allocator_type = NotAlwaysEqualAllocator<std::pair<const int, int>>; 610 using map_type = tbb::concurrent_hash_map<int, int, tbb::tbb_hash_compare<int>, allocator_type>; 611 612 map_type map1{}; 613 map_type map2({{42, 42}, {24, 42}}); 614 map_type map3(map2); 615 616 swap(map1, map2); 617 618 CHECK(map2.empty()); 619 CHECK(map1 == map3); 620 } 621 622 #if _MSC_VER && !defined(__INTEL_COMPILER) 623 #pragma warning (pop) 624 #endif // warning 4503 is back 625