1 /*
2     Copyright (c) 2005-2023 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 #ifndef __TBB_test_common_concurrent_associative_common_H
18 #define __TBB_test_common_concurrent_associative_common_H
19 
20 #include "config.h"
21 
22 #include "custom_allocators.h"
23 #include "utils.h"
24 #include "utils_concurrency_limit.h"
25 #include "container_move_support.h"
26 #include "checktype.h"
27 #include "range_based_for_support.h"
28 #include "initializer_list_support.h"
29 #include "node_handling_support.h"
30 #include "containers_common.h"
31 #include "test_comparisons.h"
32 #include "concepts_common.h"
33 #include <list>
34 #include <cstring>
35 
36 #include "oneapi/tbb/parallel_for.h"
37 
38 // This structure should be specialized for multimap and multiset classes
39 template <typename T>
40 struct AllowMultimapping : std::false_type {};
41 
42 template<typename Table>
43 inline void CheckAllocator(typename Table::allocator_type& a, size_t expected_allocs, size_t expected_frees,
44                            bool exact = true) {
45     if(exact) {
46         REQUIRE( a.allocations == expected_allocs);
47         REQUIRE( a.frees == expected_frees);
48     } else {
49         REQUIRE( a.allocations >= expected_allocs);
50         REQUIRE( a.frees >= expected_frees);
51         REQUIRE( a.allocations - a.frees == expected_allocs - expected_frees );
52     }
53 }
54 
55 // value generator for maps
56 template <typename Key, typename Value = std::pair<const Key, Key>>
57 struct ValueFactoryBase {
58     using strip_key = typename std::remove_const<Key>::type;
makeValueFactoryBase59     static Value make( const Key& key ) { return Value(key, key); }
makeValueFactoryBase60     static Value make( const Key& key, const Key& mapped ) { return Value(key, mapped); }
keyValueFactoryBase61     static strip_key key( const Value& value ) { return value.first; }
getValueFactoryBase62     static strip_key get( const Value& value ) { return strip_key(value.second); }
63     template <typename U>
convertValueFactoryBase64     static U convert( const Value& value ) { return U(value.second); }
65 };
66 
67 template <typename T>
68 struct SpecialTests {
TestSpecialTests69     static void Test() {}
70 };
71 
72 // value generator for sets
73 template <typename Key>
74 struct ValueFactoryBase<Key, Key> {
75     static Key make( const Key& key ) { return key; }
76     static Key make( const Key& key, const Key& ) { return key; }
77     static Key key( const Key& value ) { return value; }
78     static Key get( const Key& value ) { return value; }
79     template <typename U>
80     static U convert( const Key& value ) { return U(value); }
81 };
82 
83 template <typename Container>
84 struct Value : ValueFactoryBase<typename Container::key_type, typename Container::value_type> {
85     template <typename U>
86     static bool compare( const typename Container::iterator& it, U val ) {
87         return (Value::template convert<U>(*it) == val);
88     }
89 };
90 
91 template <typename Map>
92 void SpecialMapTests(){
93     Map cont;
94     const Map &ccont( cont );
95 
96     // mapped_type& operator[](const key_type& k);
97     cont[1] = 2;
98 
99     // bool empty() const;
100     REQUIRE_MESSAGE( !ccont.empty( ), "Concurrent container empty after adding an element" );
101 
102     // size_type size() const;
103     REQUIRE_MESSAGE( ccont.size( ) == 1, "Concurrent container size incorrect" );
104     REQUIRE_MESSAGE( cont[1] == 2, "Concurrent container value incorrect" );
105 
106     // mapped_type& at( const key_type& k );
107     // const mapped_type& at(const key_type& k) const;
108     REQUIRE_MESSAGE( cont.at( 1 ) == 2, "Concurrent container value incorrect" );
109     REQUIRE_MESSAGE( ccont.at( 1 ) == 2, "Concurrent container value incorrect" );
110 
111     // iterator find(const key_type& k);
112     typename Map::iterator it = cont.find( 1 );
113     REQUIRE_MESSAGE((it != cont.end( ) && Value<Map>::get( *(it) ) == 2), "Element with key 1 not properly found" );
114     cont.unsafe_erase( it );
115 
116     it = cont.find( 1 );
117     REQUIRE_MESSAGE( it == cont.end( ), "Element with key 1 not properly erased" );
118 }
119 
120 template <typename MultiMap>
121 void CheckMultiMap(MultiMap &m, int *targets, int tcount, int key) {
122     std::vector<bool> vfound(tcount,false);
123     std::pair<typename MultiMap::iterator, typename MultiMap::iterator> range = m.equal_range( key );
124     for(typename MultiMap::iterator it = range.first; it != range.second; ++it) {
125         bool found = false;
126         for( int i = 0; i < tcount; ++i) {
127             if((*it).second == targets[i]) {
128                 if(!vfound[i])  { // we can insert duplicate values
129                     vfound[i] = found = true;
130                     break;
131                 }
132             }
133         }
134         // just in case an extra value in equal_range...
135         REQUIRE_MESSAGE(found, "extra value from equal range");
136     }
137     for(int i = 0; i < tcount; ++i) REQUIRE_MESSAGE(vfound[i], "missing value");
138 }
139 
140 template <typename MultiMap>
141 void MultiMapEraseTests(){
142     MultiMap cont1, cont2;
143 
144     // Assignment to begin to avoid maybe-uninitialized warning
145     typename MultiMap::iterator erased_it = cont1.begin();
146     for (int i = 0; i < 10; ++i) {
147         if ( i != 1 ) {
148             cont1.insert(std::make_pair(1, i));
149             cont2.insert(std::make_pair(1, i));
150         } else {
151             erased_it = cont1.insert(std::make_pair(1, i)).first;
152         }
153     }
154 
155     cont1.unsafe_erase(erased_it);
156 
157     REQUIRE_MESSAGE(cont1.size() == cont2.size(), "Incorrect count of elements was erased");
158     typename MultiMap::iterator it1 = cont1.begin();
159     typename MultiMap::iterator it2 = cont2.begin();
160 
161     for (typename MultiMap::size_type i = 0; i < cont2.size(); ++i) {
162         REQUIRE_MESSAGE((*(it1++) == *(it2++)), "Multimap repetitive key was not erased properly");
163     }
164 }
165 
166 template <typename MultiMap>
167 void SpecialMultiMapTests(){
168     int one_values[] = { 7, 2, 13, 23, 13 };
169     int zero_values[] = { 4, 9, 13, 29, 42, 111};
170     int n_zero_values = sizeof(zero_values) / sizeof(int);
171     int n_one_values = sizeof(one_values) / sizeof(int);
172     MultiMap cont;
173     const MultiMap &ccont( cont );
174     // mapped_type& operator[](const key_type& k);
175     cont.insert( std::make_pair( 1, one_values[0] ) );
176 
177     // bool empty() const;
178     REQUIRE_MESSAGE( !ccont.empty( ), "Concurrent container empty after adding an element" );
179 
180     // size_type size() const;
181     REQUIRE_MESSAGE( ccont.size( ) == 1, "Concurrent container size incorrect" );
182     REQUIRE_MESSAGE( (*(cont.begin( ))).second == one_values[0], "Concurrent container value incorrect" );
183     REQUIRE_MESSAGE( (*(cont.equal_range( 1 )).first).second == one_values[0], "Improper value from equal_range" );
184     REQUIRE_MESSAGE( ((cont.equal_range( 1 )).second == cont.end( )), "Improper iterator from equal_range" );
185 
186     cont.insert( std::make_pair( 1, one_values[1] ) );
187 
188     // bool empty() const;
189     REQUIRE_MESSAGE( !ccont.empty( ), "Concurrent container empty after adding an element" );
190 
191     // size_type size() const;
192     REQUIRE_MESSAGE( ccont.size( ) == 2, "Concurrent container size incorrect" );
193     CheckMultiMap(cont, one_values, 2, 1);
194 
195     // insert the other {1,x} values
196     for( int i = 2; i < n_one_values; ++i ) {
197         cont.insert( std::make_pair( 1, one_values[i] ) );
198     }
199 
200     CheckMultiMap(cont, one_values, n_one_values, 1);
201     REQUIRE_MESSAGE( (cont.equal_range( 1 )).second == cont.end( ), "Improper iterator from equal_range" );
202 
203     cont.insert( std::make_pair( 0, zero_values[0] ) );
204 
205     // bool empty() const;
206     REQUIRE_MESSAGE( !ccont.empty( ), "Concurrent container empty after adding an element" );
207 
208     // size_type size() const;
209     REQUIRE_MESSAGE( ccont.size( ) == (size_t)(n_one_values+1), "Concurrent container size incorrect" );
210     CheckMultiMap(cont, one_values, n_one_values, 1);
211     CheckMultiMap(cont, zero_values, 1, 0);
212     REQUIRE_MESSAGE( (*cont.find(0)).second == zero_values[0], "Concurrent container value incorrect");
213     // insert the rest of the zero values
214     for( int i = 1; i < n_zero_values; ++i) {
215         cont.insert( std::make_pair( 0, zero_values[i] ) );
216     }
217     CheckMultiMap(cont, one_values, n_one_values, 1);
218     CheckMultiMap(cont, zero_values, n_zero_values, 0);
219 
220     // clear, reinsert interleaved
221     cont.clear();
222     int bigger_num = ( n_one_values > n_zero_values ) ? n_one_values : n_zero_values;
223     for( int i = 0; i < bigger_num; ++i ) {
224         if(i < n_one_values) cont.insert( std::make_pair( 1, one_values[i] ) );
225         if(i < n_zero_values) cont.insert( std::make_pair( 0, zero_values[i] ) );
226     }
227     CheckMultiMap(cont, one_values, n_one_values, 1);
228     CheckMultiMap(cont, zero_values, n_zero_values, 0);
229 
230     MultiMapEraseTests<MultiMap>();
231 
232 }
233 
234 template <StateTrackableBase::StateValue desired_state, typename T>
235 void check_value_state( const T& t, std::true_type ) {
236     REQUIRE_MESSAGE(is_state_predicate<desired_state>{}(t), "Unexpected value state");
237 }
238 
239 template <StateTrackableBase::StateValue desired_state, typename T>
240 void check_value_state(const T&, std::false_type) {}
241 
242 template <typename Container, typename CheckElementState, typename Key>
243 void test_rvalue_insert( Key k1, Key k2 ) {
244     Container cont;
245 
246     std::pair<typename Container::iterator, bool> ins = cont.insert(Value<Container>::make(k1));
247     REQUIRE_MESSAGE(ins.second, "Element 1 has not been inserted");
248     REQUIRE_MESSAGE(Value<Container>::get(*ins.first) == k1, "Element 1 has not been inserted");
249     check_value_state<StateTrackableBase::MoveInitialized>(*ins.first, CheckElementState{});
250 
251     typename Container::iterator it2 = cont.insert(ins.first, Value<Container>::make(k2));
252     REQUIRE_MESSAGE(Value<Container>::get(*it2) == k2, "Element 2 has not been inserted");
253     check_value_state<StateTrackableBase::MoveInitialized>(*it2, CheckElementState{});
254 
255 }
256 
257 namespace emplace_helpers {
258 
259 template <typename Container, typename Arg, typename Value>
260 std::pair<typename Container::iterator, bool> call_emplace_impl( Container& c, Arg&& k, Value* ) {
261     // Call emplace implementation for sets
262     return c.emplace(std::forward<Arg>(k));
263 }
264 
265 template <typename Container, typename Arg, typename FirstType, typename SecondType>
266 std::pair<typename Container::iterator, bool> call_emplace_impl( Container& c, Arg&& k, std::pair<FirstType, SecondType>* ) {
267     // Call emplace implementation for maps
268     return c.emplace(k, std::forward<Arg>(k));
269 }
270 
271 template <typename Container, typename Arg, typename Value>
272 typename Container::iterator call_emplace_hint_impl( Container& c, typename Container::const_iterator hint,
273                                                      Arg&& k, Value* )
274 {
275     // Call emplace_hint implementation for sets
276     return c.emplace_hint(hint, std::forward<Arg>(k));
277 }
278 
279 template <typename Container, typename Arg, typename FirstType, typename SecondType>
280 typename Container::iterator call_emplace_hint_impl( Container& c, typename Container::const_iterator hint,
281                                                      Arg&& k, std::pair<FirstType, SecondType>* )
282 {
283     // Call emplace_hint implementation for maps
284     return c.emplace_hint(hint, k, std::forward<Arg>(k));
285 }
286 
287 template <typename Container, typename Arg>
288 std::pair<typename Container::iterator, bool> call_emplace( Container& c, Arg&& k ) {
289     typename Container::value_type* selector = nullptr;
290     return call_emplace_impl(c, std::forward<Arg>(k), selector);
291 }
292 
293 template <typename Container, typename Arg>
294 typename Container::iterator call_emplace_hint( Container& c, typename Container::const_iterator hint, Arg&& k ) {
295     typename Container::value_type* selector = nullptr;
296     return call_emplace_hint_impl(c, hint, std::forward<Arg>(k), selector);
297 }
298 
299 } // namespace emplace_helpers
300 
301 template <typename Container, typename CheckElementState, typename Key>
302 void test_emplace_insert( Key key1, Key key2 ) {
303     Container cont;
304 
305     std::pair<typename Container::iterator, bool> ins = emplace_helpers::call_emplace(cont, key1);
306     REQUIRE_MESSAGE(ins.second, "Element 1 has not been inserted");
307     REQUIRE_MESSAGE(Value<Container>::compare(ins.first, key1), "Element 1 has not been inserted");
308     check_value_state<StateTrackableBase::DirectInitialized>(*ins.first, CheckElementState{});
309 
310      //if (!AllowMultimapping<Container>::value) {
311      //  std::pair<typename Container::iterator, bool> rep_ins = emplace_helpers::call_emplace(cont, key1);
312      //  REQUIRE_MESSAGE(!rep_ins.second, "Element 1 has been emplaced twice into the container with unique keys");
313      //  REQUIRE(Value<Container>::compare(rep_ins.first, key1));
314      //}
315 
316     typename Container::iterator it2 = emplace_helpers::call_emplace_hint(cont, ins.first, key2);
317     REQUIRE_MESSAGE(Value<Container>::compare(it2, key2), "Element 2 has not been inserted");
318     check_value_state<StateTrackableBase::DirectInitialized>(*it2, CheckElementState{});
319 }
320 
321 template <typename Container, typename Iterator, typename Range>
322 std::pair<intptr_t, intptr_t> CheckRecursiveRange( Range range ) {
323     std::pair<intptr_t, intptr_t> sum(0, 0); // count, sum
324 
325     for (Iterator i = range.begin(); i != range.end(); ++i) {
326         ++sum.first;
327         sum.second += Value<Container>::get(*i);
328     }
329 
330     if (range.is_divisible()) {
331         Range range2(range, tbb::split{});
332 
333         auto sum1 = CheckRecursiveRange<Container, Iterator>(range);
334         auto sum2 = CheckRecursiveRange<Container, Iterator>(range2);
335         sum1.first += sum2.first; sum1.second += sum2.second;
336         REQUIRE_MESSAGE(sum == sum1, "Mismatched ranges afted division");
337     }
338     return sum;
339 }
340 
341 using atomic_byte_type = std::atomic<unsigned char>;
342 
343 void CheckRange( atomic_byte_type array[], int n, bool allow_multimapping, int odd_count ) {
344     if (allow_multimapping) {
345         for (int k = 0; k < n; ++k) {
346             if (k % 2) {
347                 REQUIRE(array[k] == odd_count);
348             } else {
349                 REQUIRE(array[k] == 2);
350             }
351         }
352     } else {
353         for (int k = 0; k < n; ++k) {
354             REQUIRE(array[k] == 1);
355         }
356     }
357 }
358 
359 template <typename T>
360 void check_equal( const T& cont1, const T& cont2 ) {
361     REQUIRE_MESSAGE(cont1 == cont2, "Containers should be equal");
362     REQUIRE_MESSAGE(cont2 == cont1, "Containers should be equal");
363     REQUIRE_MESSAGE(!(cont1 != cont2), "Containers should not be unequal");
364     REQUIRE_MESSAGE(!(cont2 != cont1), "Containers should not be unequal");
365 }
366 
367 template <typename T>
368 void check_unequal( const T& cont1, const T& cont2 ) {
369     REQUIRE_MESSAGE(cont1 != cont2, "Containers should be unequal");
370     REQUIRE_MESSAGE(cont2 != cont1, "Containers should be unequal");
371     REQUIRE_MESSAGE(!(cont1 == cont2), "Containers should not be equal");
372     REQUIRE_MESSAGE(!(cont2 == cont1), "Containers should not be equal");
373 }
374 
375 // Break value for maps
376 template <typename First, typename Second>
377 void break_value( std::pair<First, Second>& value ) {
378     ++value.second;
379 }
380 
381 template <typename First>
382 void break_value( std::pair<First, move_support_tests::FooWithAssign>& value ) {
383     ++value.second.bar();
384 }
385 
386 // Break value for sets
387 template <typename T>
388 void break_value( T& value ) {
389     ++value;
390 }
391 
392 void break_value( move_support_tests::FooWithAssign& value ) {
393     ++value.bar();
394 }
395 
396 template <typename T>
397 void test_comparison_operators() {
398     T cont;
399     check_equal(cont, cont);
400 
401     cont.insert(Value<T>::make(1));
402     cont.insert(Value<T>::make(2));
403 
404     T cont2 = cont;
405     check_equal(cont, cont2);
406 
407     T cont3;
408     check_unequal(cont, cont3);
409 
410     T cont4;
411     cont4.insert(Value<T>::make(1));
412     cont4.insert(Value<T>::make(2));
413     check_equal(cont, cont4);
414 
415     T cont5;
416     cont5.insert(Value<T>::make(1));
417     cont5.insert(Value<T>::make(3));
418     check_unequal(cont, cont5);
419 
420     T cont6;
421     cont6.insert(Value<T>::make(1));
422     auto value2 = Value<T>::make(2);
423     break_value(value2);
424     cont6.insert(value2);
425     check_unequal(cont, cont6);
426 }
427 
428 template <typename Range, typename Container>
429 void test_empty_container_range(Container&& cont) {
430     REQUIRE(cont.empty());
431     Range r = cont.range();
432     REQUIRE_MESSAGE(r.empty(), "Empty container range should be empty");
433     REQUIRE_MESSAGE(!r.is_divisible(), "Empty container range should not be divisible");
434     REQUIRE_MESSAGE(r.begin() == r.end(), "Incorrect iterators on empty range");
435     REQUIRE_MESSAGE(r.begin() == cont.begin(), "Incorrect iterators on empty range");
436 }
437 
438 template<typename T, typename CheckElementState>
439 void test_basic_common()
440 {
441     T cont;
442     const T &ccont(cont);
443     CheckNoAllocations(cont);
444     // bool empty() const;
445     REQUIRE_MESSAGE(ccont.empty(), "Concurrent container is not empty after construction");
446 
447     // size_type size() const;
448     REQUIRE_MESSAGE(ccont.size() == 0, "Concurrent container is not empty after construction");
449 
450     // size_type max_size() const;
451     REQUIRE_MESSAGE(ccont.max_size() > 0, "Concurrent container max size is invalid");
452 
453     //iterator begin();
454     //iterator end();
455     REQUIRE_MESSAGE(cont.begin() == cont.end(), "Concurrent container iterators are invalid after construction");
456     REQUIRE_MESSAGE(ccont.begin() == ccont.end(), "Concurrent container iterators are invalid after construction");
457     REQUIRE_MESSAGE(cont.cbegin() == cont.cend(), "Concurrent container iterators are invalid after construction");
458 
459     // Test range for empty container
460     using range_type = typename T::range_type;
461     using const_range_type = typename T::const_range_type;
462     test_empty_container_range<range_type>(cont);
463     test_empty_container_range<const_range_type>(cont);
464     test_empty_container_range<const_range_type>(ccont);
465 
466     T empty_cont;
467     const T& empty_ccont = empty_cont;
468 
469     for (int i = 0; i < 1000; ++i) {
470         empty_cont.insert(Value<T>::make(i));
471     }
472     empty_cont.clear();
473 
474     test_empty_container_range<range_type>(empty_cont);
475     test_empty_container_range<const_range_type>(empty_cont);
476     test_empty_container_range<const_range_type>(empty_ccont);
477 
478     //std::pair<iterator, bool> insert(const value_type& obj);
479     std::pair<typename T::iterator, bool> ins = cont.insert(Value<T>::make(1));
480     REQUIRE_MESSAGE((ins.second == true && Value<T>::get(*(ins.first)) == 1), "Element 1 has not been inserted properly");
481 
482     test_rvalue_insert<T,CheckElementState>(1,2);
483     test_emplace_insert<T,CheckElementState>(1,2);
484 
485     // bool empty() const;
486     REQUIRE_MESSAGE(!ccont.empty(), "Concurrent container is empty after adding an element");
487 
488     // size_type size() const;
489     REQUIRE_MESSAGE(ccont.size() == 1, "Concurrent container size is incorrect");
490 
491     std::pair<typename T::iterator, bool> ins2 = cont.insert(Value<T>::make(1));
492 
493     if (AllowMultimapping<T>::value)
494     {
495         // std::pair<iterator, bool> insert(const value_type& obj);
496         REQUIRE_MESSAGE((ins2.second == true && Value<T>::get(*(ins2.first)) == 1), "Element 1 has not been inserted properly");
497 
498         // size_type size() const;
499         REQUIRE_MESSAGE(ccont.size() == 2, "Concurrent container size is incorrect");
500 
501         // size_type count(const key_type& k) const;
502         REQUIRE_MESSAGE(ccont.count(1) == 2, "Concurrent container count(1) is incorrect");
503         // std::pair<iterator, iterator> equal_range(const key_type& k);
504         std::pair<typename T::iterator, typename T::iterator> range = cont.equal_range(1);
505         typename T::iterator it;
506         it = range.first;
507         REQUIRE_MESSAGE((it != cont.end() && Value<T>::get(*it) == 1), "Element 1 has not been found properly");
508         unsigned int count = 0;
509         for (; it != range.second; it++)
510         {
511             count++;
512             REQUIRE_MESSAGE((Value<T>::get(*it) == 1), "Element 1 has not been found properly");
513         }
514 
515         REQUIRE_MESSAGE(count == 2, "Range doesn't have the right number of elements");
516     }
517     else
518     {
519         // std::pair<iterator, bool> insert(const value_type& obj);
520         REQUIRE_MESSAGE((ins2.second == false && ins2.first == ins.first), "Element 1 should not be re-inserted");
521 
522         // size_type size() const;
523         REQUIRE_MESSAGE(ccont.size() == 1, "Concurrent container size is incorrect");
524 
525         // size_type count(const key_type& k) const;
526         REQUIRE_MESSAGE(ccont.count(1) == 1, "Concurrent container count(1) is incorrect");
527 
528         // std::pair<const_iterator, const_iterator> equal_range(const key_type& k) const;
529         // std::pair<iterator, iterator> equal_range(const key_type& k);
530         std::pair<typename T::iterator, typename T::iterator> range = cont.equal_range(1);
531         typename T::iterator it = range.first;
532         REQUIRE_MESSAGE((it != cont.end() && Value<T>::get(*it) == 1), "Element 1 has not been found properly");
533         REQUIRE_MESSAGE((++it == range.second), "Range doesn't have the right number of elements");
534     }
535 
536     // const_iterator find(const key_type& k) const;
537     // iterator find(const key_type& k);
538     typename T::iterator it = cont.find(1);
539     REQUIRE_MESSAGE((it != cont.end() && Value<T>::get(*(it)) == 1), "Element 1 has not been found properly");
540     REQUIRE_MESSAGE(ccont.find(1) == it, "Element 1 has not been found properly");
541 
542     //bool contains(const key_type&k) const
543     REQUIRE_MESSAGE(cont.contains(1), "contains() cannot detect existing element");
544     REQUIRE_MESSAGE(!cont.contains(0), "contains() detect not existing element");
545 
546     // iterator insert(const_iterator hint, const value_type& obj);
547     typename T::iterator it2 = cont.insert(ins.first, Value<T>::make(2));
548     REQUIRE_MESSAGE((Value<T>::get(*it2) == 2), "Element 2 has not been inserted properly");
549 
550     // T(const T& _Umap)
551     T newcont = ccont;
552 
553     REQUIRE_MESSAGE((AllowMultimapping<T>{} ? (newcont.size() == 3) : (newcont.size() == 2)), "Copy construction has not copied the elements properly");
554 
555     // size_type unsafe_erase(const key_type& k);
556     typename T::size_type size;
557 #if _MSC_VER && __INTEL_COMPILER == 1900
558     // The compiler optimizes the next line too aggressively.
559 #pragma noinline
560 #endif
561     size = cont.unsafe_erase(1);
562 
563     REQUIRE_MESSAGE((AllowMultimapping<T>{} ? (size == 2) : (size == 1)), "Erase has not removed the right number of elements");
564 
565     // iterator unsafe_erase(iterator position);
566     typename T::iterator it4 = cont.unsafe_erase(cont.find(2));
567 
568     REQUIRE_MESSAGE((it4 == cont.end() && cont.size() == 0), "Erase has not removed the last element properly");
569 
570     // iterator unsafe_erase(const_iterator position);
571     cont.insert(Value<T>::make(3));
572     typename T::iterator it5 = cont.unsafe_erase(cont.cbegin());
573     REQUIRE_MESSAGE((it5 == cont.end() && cont.size() == 0), "Erase has not removed the last element properly");
574 
575     // template<class InputIterator> void insert(InputIterator first, InputIterator last);
576 
577     cont.insert(newcont.begin(), newcont.end());
578 
579     REQUIRE_MESSAGE((AllowMultimapping<T>{} ? (cont.size() == 3) : (cont.size() == 2)), "Range insert has not copied the elements properly");
580 
581     // iterator unsafe_erase(const_iterator first, const_iterator last);
582     std::pair<typename T::iterator, typename T::iterator> range2 = newcont.equal_range(1);
583 
584     newcont.unsafe_erase(range2.first, range2.second);
585     REQUIRE_MESSAGE(newcont.size() == 1, "Range erase has not erased the elements properly");
586 
587     // void clear();
588     newcont.clear();
589     REQUIRE_MESSAGE((newcont.begin() == newcont.end() && newcont.size() == 0), "Clear has not cleared the container");
590 
591     // void insert(std::initializer_list<value_type> &il);
592     newcont.insert( { Value<T>::make( 1 ), Value<T>::make( 2 ), Value<T>::make( 1 ) } );
593     if (AllowMultimapping<T>::value) {
594 
595         REQUIRE_MESSAGE(newcont.size() == 3, "Concurrent container size is incorrect");
596         REQUIRE_MESSAGE(newcont.count(1) == 2, "Concurrent container count(1) is incorrect");
597         REQUIRE_MESSAGE(newcont.count(2) == 1, "Concurrent container count(2) is incorrect");
598         std::pair<typename T::iterator, typename T::iterator> range = cont.equal_range(1);
599         it = range.first;
600         // REQUIRE_MESSAGE((it != newcont.end() && Value<T>::get(*it) == 1), "Element 1 has not been found properly");
601         REQUIRE_MESSAGE((it != newcont.end()), "iterator" );
602         REQUIRE_MESSAGE((Value<T>::get(*it) == 1), "value");
603         unsigned int count = 0;
604         for (; it != range.second; it++) {
605             count++;
606             REQUIRE_MESSAGE(Value<T>::get(*it) == 1, "Element 1 has not been found properly");
607         }
608         REQUIRE_MESSAGE(count == 2, "Range doesn't have the right number of elements");
609         range = newcont.equal_range(2); it = range.first;
610         REQUIRE_MESSAGE((it != newcont.end() && Value<T>::get(*it) == 2), "Element 2 has not been found properly");
611         count = 0;
612         for (; it != range.second; it++) {
613             count++;
614             REQUIRE_MESSAGE(Value<T>::get(*it) == 2, "Element 2 has not been found properly");
615         }
616         REQUIRE_MESSAGE(count == 1, "Range doesn't have the right number of elements");
617     } else {
618         REQUIRE_MESSAGE(newcont.size() == 2, "Concurrent container size is incorrect");
619         REQUIRE_MESSAGE(newcont.count(1) == 1, "Concurrent container count(1) is incorrect");
620         REQUIRE_MESSAGE(newcont.count(2) == 1, "Concurrent container count(2) is incorrect");
621         std::pair<typename T::iterator, typename T::iterator> range = newcont.equal_range(1);
622         it = range.first;
623         REQUIRE_MESSAGE((it != newcont.end() && Value<T>::get(*it) == 1), "Element 1 has not been found properly");
624         REQUIRE_MESSAGE((++it == range.second), "Range doesn't have the right number of elements");
625         range = newcont.equal_range(2);
626         it = range.first;
627         REQUIRE_MESSAGE((it != newcont.end() && Value<T>::get(*it) == 2), "Element 2 has not been found properly");
628         REQUIRE_MESSAGE((++it == range.second), "Range doesn't have the right number of elements");
629     }
630 
631     // T& operator=(const T& _Umap)
632     newcont = ccont;
633     REQUIRE_MESSAGE((AllowMultimapping<T>{} ? (newcont.size() == 3) : (newcont.size() == 2)), "Assignment operator has not copied the elements properly");
634 
635 
636     cont.clear();
637     CheckNoAllocations(cont);
638     for (int i = 0; i < 256; i++)
639     {
640         std::pair<typename T::iterator, bool> ins3 = cont.insert(Value<T>::make(i));
641         REQUIRE_MESSAGE((ins3.second == true && Value<T>::get(*(ins3.first)) == i), "Element 1 has not been inserted properly");
642     }
643     REQUIRE_MESSAGE(cont.size() == 256, "Wrong number of elements have been inserted");
644     REQUIRE(!cont.range().empty());
645     REQUIRE(!ccont.range().empty());
646     REQUIRE((256 == CheckRecursiveRange<T,typename T::iterator>(cont.range()).first));
647     REQUIRE((256 == CheckRecursiveRange<T,typename T::const_iterator>(ccont.range()).first));
648     REQUIRE(cont.range().grainsize() > 0);
649     REQUIRE(ccont.range().grainsize() > 0);
650 
651     // void swap(T&);
652     cont.swap(newcont);
653     REQUIRE_MESSAGE(newcont.size() == 256, "Wrong number of elements after swap");
654     REQUIRE_MESSAGE(newcont.count(200) == 1, "Element with key 200 is not present after swap");
655     REQUIRE_MESSAGE(newcont.count(16) == 1, "Element with key 16 is not present after swap");
656     REQUIRE_MESSAGE(newcont.count(99) == 1, "Element with key 99 is not present after swap");
657     REQUIRE_MESSAGE((AllowMultimapping<T>{} ? (cont.size() == 3) : (cont.size() == 2)), "Assignment operator has not copied the elements properly");
658 
659     T newcont_bkp = newcont;
660     newcont.swap(newcont);
661     REQUIRE_MESSAGE(newcont == newcont_bkp, "Unexpected swap-with-itself behavior");
662 
663     test_comparison_operators<T>();
664 
665     SpecialTests<T>::Test();
666 }
667 
668 template <typename Container>
669 class FillTable {
670     Container& my_table;
671     const int my_items;
672     bool my_asymptotic;
673 
674     using pair_ib = std::pair<typename Container::iterator, bool>;
675 public:
676     FillTable(Container& table, int items, bool asymptotic)
677         : my_table(table), my_items(items), my_asymptotic(asymptotic)
678     {
679         REQUIRE((!(items&1) && items > 100));
680     }
681 
682     void operator()( int thread_index ) const {
683         if (thread_index == 0) { // Fill even keys forward (single thread)
684             bool last_inserted = true;
685 
686             for (int i = 0; i < my_items; i += 2) {
687                 int val = my_asymptotic ? 1 : i;
688                 pair_ib pib = my_table.insert(Value<Container>::make(val));
689                 REQUIRE_MESSAGE((Value<Container>::get(*(pib.first)) == val),
690                                 "Element not properly inserted");
691                 REQUIRE_MESSAGE((last_inserted || !pib.second),
692                                 "Previous key was not inserted but current key is inserted");
693                 last_inserted = pib.second;
694             }
695         } else if (thread_index == 1) { // Fill even keys backward (single thread)
696             bool last_inserted = true;
697 
698             for (int i = my_items - 2; i >= 0; i -= 2) {
699                 int val = my_asymptotic ? 1 : i;
700                 pair_ib pib = my_table.insert(Value<Container>::make(val));
701                 REQUIRE_MESSAGE((Value<Container>::get(*(pib.first)) == val),
702                                 "Element not properly inserted");
703                 REQUIRE_MESSAGE((last_inserted || !pib.second),
704                                 "Previous key was not inserted but current key is inserted");
705                 last_inserted = pib.second;
706             }
707         } else if (!(thread_index & 1)) { // Fill odd keys forward (multiple threads)
708             for (int i = 1; i < my_items; i += 2) {
709                 if (i % 32 == 1 && i + 6 < my_items) {
710                     if (my_asymptotic) {
711                         auto init = { Value<Container>::make(1), Value<Container>::make(1), Value<Container>::make(1) };
712                         my_table.insert(init);
713                         REQUIRE_MESSAGE(Value<Container>::get(*my_table.find(1)) == 1, "Element not properly inserted");
714                     } else {
715                         auto init = { Value<Container>::make(i), Value<Container>::make(i + 2),
716                                       Value<Container>::make(i + 4) };
717                         my_table.insert(init);
718                         REQUIRE_MESSAGE(Value<Container>::get(*my_table.find(i)) == i, "Element i not properly inserted");
719                         REQUIRE_MESSAGE(Value<Container>::get(*my_table.find(i + 2)) == i + 2, "Element i + 2 not properly inserted");
720                         REQUIRE_MESSAGE(Value<Container>::get(*my_table.find(i + 4)) == i + 4, "Element i + 4 not properly inserted");
721                     }
722                     i += 4;
723                 } else {
724                     pair_ib pib = my_table.insert(Value<Container>::make(my_asymptotic ? 1 : i));
725                     REQUIRE_MESSAGE(Value<Container>::get(*(pib.first)) == (my_asymptotic ? 1 : i), "Element not properly inserted");
726                 }
727             }
728         } else { // Check odd keys backward (multiple threads)
729             if (!my_asymptotic) {
730                 bool last_found = false;
731                 for (int i = my_items - 1; i >= 0; i -= 2) {
732                     typename Container::iterator it = my_table.find(i);
733 
734                     if (it != my_table.end()) { // found
735                         REQUIRE_MESSAGE(Value<Container>::get(*it) == i, "Element not properly inserted");
736                         last_found = true;
737                     } else {
738                         REQUIRE_MESSAGE(!last_found, "Previous key was found, but current was not found");
739                     }
740                 }
741             }
742         }
743     }
744 }; // class FillTable
745 
746 template <typename Container, typename Range>
747 struct ParallelTraverseBody {
748     const int n;
749     atomic_byte_type* const array;
750 
751     ParallelTraverseBody( atomic_byte_type arr[], int num )
752         : n(num), array(arr) {}
753 
754     void operator()( const Range& range ) const {
755         for (auto i = range.begin(); i != range.end(); ++i) {
756             int k = static_cast<int>(Value<Container>::key(*i));
757             REQUIRE(k == Value<Container>::get(*i));
758             REQUIRE(0 <= k);
759             REQUIRE(k < n);
760             ++array[k];
761         }
762     }
763 }; // struct ParallelTraverseBody
764 
765 template<typename T>
766 class CheckTable : utils::NoAssign {
767     T& table;
768 public:
769     CheckTable(T& t) : NoAssign(), table(t) {}
770     void operator()(int i) const {
771         int c = (int)table.count(i);
772         CHECK_MESSAGE(c, "must exist");
773     }
774 };
775 
776 template <typename Container>
777 void test_concurrent_common( bool asymptotic = false ) {
778 #if __TBB_USE_ASSERT
779     int items = 2000;
780 #else
781     int items = 20000;
782 #endif
783     int items_inserted = 0;
784     int num_threads = 16;
785 
786     Container table;
787 
788     if (AllowMultimapping<Container>::value) {
789         // TODO: comment
790         items = 4 * items / (num_threads + 2);
791         items_inserted = items + (num_threads - 2) * items / 4;
792     } else {
793         items_inserted = items;
794     }
795 
796     utils::NativeParallelFor(num_threads, FillTable<Container>(table, items, asymptotic));
797 
798     REQUIRE(int(table.size()) == items_inserted);
799 
800     if (!asymptotic) {
801         atomic_byte_type* array = new atomic_byte_type[items];
802         std::memset(static_cast<void*>(array), 0, items * sizeof(atomic_byte_type));
803 
804         typename Container::range_type r = table.range();
805 
806         auto p = CheckRecursiveRange<Container, typename Container::iterator>(r);
807         REQUIRE(items_inserted == p.first);
808 
809         tbb::parallel_for(r, ParallelTraverseBody<Container, typename Container::range_type>(array, items));
810         CheckRange(array, items, AllowMultimapping<Container>::value, (num_threads - 1)/2);
811 
812         const Container& const_table = table;
813         std::memset(static_cast<void*>(array), 0, items * sizeof(atomic_byte_type));
814         typename Container::const_range_type cr = const_table.range();
815 
816         p = CheckRecursiveRange<Container, typename Container::const_iterator>(cr);
817         REQUIRE(items_inserted == p.first);
818 
819         tbb::parallel_for(cr, ParallelTraverseBody<Container, typename Container::const_range_type>(array, items));
820         CheckRange(array, items, AllowMultimapping<Container>::value, (num_threads - 1) / 2);
821         delete[] array;
822 
823         tbb::parallel_for(0, items, CheckTable<Container>(table));
824     }
825 
826     table.clear();
827     // TODO: add check for container allocator counters
828 }
829 
830 template <typename ContainerTraits>
831 void test_rvalue_ref_support() {
832     using namespace move_support_tests;
833     test_move_constructor<ContainerTraits>();
834     test_move_assignment<ContainerTraits>();
835 #if TBB_USE_EXCEPTIONS
836     test_ex_move_constructor<ContainerTraits>();
837 #endif
838 }
839 
840 template <typename Container>
841 void test_range_based_for_support() {
842     using namespace range_based_for_support_tests;
843 
844     Container cont;
845     const int sequence_length = 100;
846 
847     for (int i = 1; i <= sequence_length; ++i) {
848         cont.insert(Value<Container>::make(i));
849     }
850 
851     auto range_based_for_result = range_based_for_accumulate(cont, UnifiedSummer{}, 0);
852     auto reference_result = gauss_summ_of_int_sequence(sequence_length);
853     REQUIRE_MESSAGE(range_based_for_result == reference_result,
854                     "Incorrect accumulated value generated via range based for");
855 }
856 
857 template <typename Container>
858 void test_initializer_list_support( std::initializer_list<typename Container::value_type> init ) {
859     using namespace initializer_list_support_tests;
860 
861     test_initializer_list_support_without_assign<Container, TestInsertMethod>(init);
862     test_initializer_list_support_without_assign<Container, TestInsertMethod>({});
863 }
864 
865 template <typename Checker>
866 void test_set_specific_types() {
867     // TODO: add tests for atomics
868     Checker check_types;
869     const int num = 10;
870 
871     // Test int
872     std::list<int> arr_int;
873     for (int i = 0; i != num; ++i) {
874         arr_int.emplace_back(i);
875     }
876     check_types.template check</*DefCtorPresent = */true>(arr_int);
877 
878     // Test reference_wrapper
879     std::list<std::reference_wrapper<int>> arr_ref;
880     for (auto it = arr_int.begin(); it != arr_int.end(); ++it) {
881         arr_ref.emplace_back(*it);
882     }
883     check_types.template check</*DefCtorPresent = */false>(arr_ref);
884 
885     // Test share_ptr
886     std::list<std::shared_ptr<int>> arr_shr;
887     for (int i = 0; i != num; ++i) {
888         arr_shr.emplace_back(std::make_shared<int>(i));
889     }
890     check_types.template check</*DefCtorPresent = */true>(arr_shr);
891 
892     // Test weak_ptr
893     std::list<std::weak_ptr<int>> arr_weak;
894     std::copy(arr_shr.begin(), arr_shr.end(), std::back_inserter(arr_weak));
895     check_types.template check</*DefCtorPresent = */true>(arr_weak);
896 
897     // Test std::pair
898     std::list<std::pair<int, int>> arr_pairs;
899     for (int i = 0; i != num; ++i) {
900         arr_pairs.emplace_back(i, i);
901     }
902     check_types.template check</*DefCtorPresent = */true>(arr_pairs);
903 
904     // Test std::basic_string
905     std::list<std::basic_string<char, std::char_traits<char>, tbb::tbb_allocator<char>>> arr_strings;
906     for (int i = 0; i != num; ++i) {
907         arr_strings.emplace_back(i, char(i));
908     }
909     check_types.template check</*DefCtorPresent = */true>(arr_strings);
910 }
911 
912 template <typename Checker>
913 void test_map_specific_types() {
914     // TODO: add tests for int-atomic pairs
915     Checker check_types;
916     const int num = 10;
917 
918     // Test int-int pairs
919     std::list<std::pair<const int, int>> arr_int_int_pairs;
920     for (int i = 0; i != num; ++i) {
921         arr_int_int_pairs.emplace_back(i, num - i);
922     }
923     check_types.template check</*DefCtorPresent = */true>(arr_int_int_pairs);
924 
925     // Test reference_wrapper-int pairs
926     std::list<std::pair<const std::reference_wrapper<const int>, int>> arr_ref_int_pairs;
927     for (auto& item : arr_int_int_pairs) {
928         arr_ref_int_pairs.emplace_back(item.first, item.second);
929     }
930     check_types.template check</*DefCtorPresent = */true>(arr_ref_int_pairs);
931 
932     // Test int-reference_wrapper pairs
933     std::list<std::pair<const int, std::reference_wrapper<int>>> arr_int_ref_pairs;
934     for (auto& item : arr_int_int_pairs) {
935         arr_int_ref_pairs.emplace_back(item.first, item.second);
936     }
937     check_types.template check</*DefCtorPresent = */false>(arr_int_ref_pairs);
938 
939     // Test shared_ptr
940     std::list<std::pair<const std::shared_ptr<int>, std::shared_ptr<int>>> arr_shared_pairs;
941     for (int i = 0; i != num; ++i) {
942         const int num_minus_i = num - i;
943         arr_shared_pairs.emplace_back(std::make_shared<int>(i), std::make_shared<int>(num_minus_i));
944     }
945     check_types.template check</*DefCtorPresent = */true>(arr_shared_pairs);
946 
947     // Test weak_ptr
948     std::list<std::pair<const std::weak_ptr<int>, std::weak_ptr<int>>> arr_wick_pairs;
949     std::copy(arr_shared_pairs.begin(), arr_shared_pairs.end(), std::back_inserter(arr_wick_pairs));
950     check_types.template check</*DefCtorPresent = */true>(arr_wick_pairs);
951 
952     // Test std::pair
953     using pair_key_type = std::pair<int, int>;
954     std::list<std::pair<const pair_key_type, int>> arr_pair_int_pairs;
955     for (int i = 0; i != num; ++i) {
956         arr_pair_int_pairs.emplace_back(pair_key_type{i, i}, i);
957     }
958     check_types.template check</*DefCtorPresent = */true>(arr_pair_int_pairs);
959 
960     // Test std::basic_string
961     using tbb_string_key_type = std::basic_string<char, std::char_traits<char>, tbb::tbb_allocator<char>>;
962     std::list<std::pair<const tbb_string_key_type, int>> arr_tbb_string_pairs;
963     for (int i = 0; i != num; ++i) {
964         tbb_string_key_type key(i, char(i));
965         arr_tbb_string_pairs.emplace_back(key, i);
966     }
967     check_types.template check</*DefCtorPresent = */true>(arr_tbb_string_pairs);
968 }
969 
970 namespace test {
971 
972 // For the sake of simplified testing, make std::unique_ptr implicitly convertible to/from the pointer
973 template <typename T>
974 class unique_ptr : public std::unique_ptr<T> {
975 public:
976     using pointer = typename std::unique_ptr<T>::pointer;
977 
978     unique_ptr( pointer p ) : std::unique_ptr<T>(p) {}
979     operator pointer() const { return this->get(); }
980 }; // class unique_ptr
981 
982 } // namespace test
983 
984 namespace std {
985 template <typename T>
986 struct hash<test::unique_ptr<T>> {
987     std::size_t operator()(const test::unique_ptr<T>& ptr) const {
988         return std::hash<std::unique_ptr<T>>{}(ptr);
989     }
990 };
991 }
992 
993 template <bool Condition>
994 struct CallIf {
995     template <typename Func>
996     void operator()( Func func ) const { func(); }
997 };
998 
999 template <>
1000 struct CallIf<false> {
1001     template <typename Func>
1002     void operator()( Func ) const {}
1003 };
1004 
1005 template <typename Table>
1006 class TestOperatorSquareBrackets {
1007     using value_type = typename Table::value_type;
1008     Table& my_c;
1009     const value_type& my_value;
1010 public:
1011     TestOperatorSquareBrackets( Table& c, const value_type& value )
1012         : my_c(c), my_value(value) {}
1013 
1014     void operator()() const {
1015         utils::IsEqual equal;
1016         REQUIRE(equal(my_c[my_value.first], my_value.second));
1017         typename Table::key_type temp_key = my_value.first;
1018         REQUIRE(equal(my_c[std::move(temp_key)], my_value.second));
1019     }
1020 }; // class TestOperatorSquareBrackets
1021 
1022 template <bool DefCtorPresent, typename Table, typename Value>
1023 void TestSquareBracketsAndAt( Table&, const Value&, /*multimap = */std::true_type ) {
1024     // operator [] and at are not presented in the multimap
1025 }
1026 
1027 template <bool DefCtorPresent, typename Table, typename Value>
1028 void TestSquareBracketsAndAt( Table& c, const Value& value, /*multimap = */std::false_type ) {
1029     CallIf<DefCtorPresent>()(TestOperatorSquareBrackets<Table>(c, value));
1030     utils::IsEqual equal;
1031     REQUIRE(equal(c.at(value.first), value.second));
1032     // TODO: add test for at exceptions
1033     const Table& constC = c;
1034     REQUIRE(equal(constC.at(value.first), value.second));
1035 }
1036 
1037 template <bool DefCtorPresent, typename Table, typename Value>
1038 void TestMapSpecificMethods( Table&, const Value& ) {}
1039 
1040 template <bool DefCtorPresent, typename Table>
1041 void TestMapSpecificMethods( Table& c, const std::pair<const typename Table::key_type,
1042                                                        typename Table::mapped_type>& value )
1043 {
1044     TestSquareBracketsAndAt<DefCtorPresent>(c, value, std::integral_constant<bool, AllowMultimapping<Table>::value>{});
1045 }
1046 
1047 template <bool DefCtorPresent, typename Table>
1048 class CheckValue {
1049     Table& my_c;
1050 public:
1051     CheckValue( Table& c ) : my_c(c) {}
1052     void operator()( const typename Table::value_type& value ) {
1053         using iterator = typename Table::iterator;
1054         using const_iterator = typename Table::const_iterator;
1055         const Table& constC = my_c;
1056         // count
1057         REQUIRE(my_c.count(Value<Table>::key(value)) == 1);
1058         // find
1059         utils::IsEqual equal;
1060         REQUIRE(equal(*my_c.find(Value<Table>::key(value)), value));
1061         REQUIRE(equal(*constC.find(Value<Table>::key(value)), value));
1062         // erase
1063         REQUIRE(my_c.unsafe_erase(Value<Table>::key(value)) != 0);
1064         REQUIRE(my_c.unsafe_erase(Value<Table>::key(value)) == 0);
1065         // insert
1066         std::pair<iterator, bool> res = my_c.insert(value);
1067         REQUIRE(equal(*res.first, value));
1068         REQUIRE(res.second);
1069         // erase
1070         iterator it = res.first;
1071         ++it;
1072         REQUIRE(my_c.unsafe_erase(res.first) == it);
1073         // insert
1074         REQUIRE(equal(*my_c.insert(my_c.begin(), value), value));
1075         // equal_range
1076         std::pair<iterator, iterator> r1 = my_c.equal_range(Value<Table>::key(value));
1077         REQUIRE((equal(*r1.first, value) && ++r1.first == r1.second));
1078         std::pair<const_iterator, const_iterator> r2 = constC.equal_range(Value<Table>::key(value));
1079         REQUIRE((equal(*r2.first, value) && ++r2.first == r2.second));
1080 
1081         TestMapSpecificMethods<DefCtorPresent>(my_c, value);
1082     }
1083 }; // class CheckValue
1084 
1085 namespace detail {
1086 
1087 #if (__INTEL_COMPILER || __clang__ ) && __TBB_GLIBCXX_VERSION && __TBB_GLIBCXX_VERSION < 40900
1088 template <typename T>
1089 struct assignable_atomic : std::atomic<T> {
1090     using std::atomic<T>::operator=;
1091     assignable_atomic& operator=(const assignable_atomic& a) {
1092         store(a.load(std::memory_order_relaxed), std::memory_order_relaxed);
1093     }
1094 };
1095 
1096 template <typename T>
1097 using atomic_type = assignable_atomic<T>;
1098 #else
1099 template <typename T>
1100 using atomic_type = std::atomic<T>;
1101 #endif
1102 }
1103 
1104 template <typename Value>
1105 class TestRange {
1106     const std::list<Value>& my_lst;
1107     std::vector<detail::atomic_type<bool>>& my_marks;
1108 public:
1109     TestRange( const std::list<Value>& lst, std::vector<detail::atomic_type<bool>>& marks )
1110         : my_lst(lst), my_marks(marks)
1111     {
1112         std::fill(my_marks.begin(), my_marks.end(), false);
1113     }
1114 
1115     template <typename Range>
1116     void operator()( const Range& r ) const {
1117         do_test_range(r.begin(), r.end());
1118     }
1119 
1120     template <typename Iterator>
1121     void do_test_range( Iterator i, Iterator j ) const {
1122         for (Iterator it = i; it != j;) {
1123             Iterator prev_it = it++;
1124             auto it2 = std::search(my_lst.begin(), my_lst.end(), prev_it, it, utils::IsEqual());
1125             REQUIRE(it2 != my_lst.end());
1126             auto dist = std::distance(my_lst.begin(), it2);
1127             REQUIRE(!my_marks[dist]);
1128             my_marks[dist] = true;
1129         }
1130     }
1131 }; // class TestRange
1132 
1133 template <bool DefCtorPresent, typename Table>
1134 void CommonExamine( Table c, const std::list<typename Table::value_type>& lst ) {
1135     using value_type = typename Table::value_type;
1136 
1137     if (!(!c.empty() && c.size() == lst.size() && c.max_size() >= c.size())) {
1138         std::cout << std::boolalpha;
1139         std::cout << "Empty? " << c.empty() << std::endl;
1140         std::cout << "sizes equal? " << (c.size() == lst.size()) << std::endl;
1141         std::cout << "\t" << c.size() << std::endl;
1142         std::cout << "\t" << lst.size() << std::endl;
1143         std::cout << "Max size greater? " << (c.max_size() >= c.size()) << std::endl;
1144     }
1145     REQUIRE((!c.empty() && c.size() == lst.size() && c.max_size() >= c.size()));
1146 
1147     std::for_each(lst.begin(), lst.end(), CheckValue<DefCtorPresent, Table>(c));
1148 
1149     std::vector<detail::atomic_type<bool>> marks(lst.size());
1150 
1151     TestRange<value_type>(lst, marks).do_test_range(c.begin(), c.end());
1152     REQUIRE(std::find(marks.begin(), marks.end(), false) == marks.end());
1153 
1154     const Table constC = c;
1155     REQUIRE(c.size() == constC.size());
1156 
1157     TestRange<value_type>(lst, marks).do_test_range(c.begin(), c.end());
1158     REQUIRE(std::find(marks.begin(), marks.end(), false) == marks.end());
1159 
1160     tbb::parallel_for(c.range(), TestRange<value_type>(lst, marks));
1161     REQUIRE(std::find(marks.begin(), marks.end(), false) == marks.end());
1162 
1163     tbb::parallel_for(constC.range(), TestRange<value_type>(lst, marks));
1164     REQUIRE(std::find(marks.begin(), marks.end(), false) == marks.end());
1165 
1166     Table c2;
1167     auto begin5 = lst.begin();
1168     std::advance(begin5, 5);
1169     c2.insert(lst.begin(), begin5);
1170     std::for_each(lst.begin(), begin5, CheckValue<DefCtorPresent, Table>(c2));
1171 
1172     c2.swap(c);
1173     REQUIRE(c2.size() == lst.size());
1174     REQUIRE(c.size() == 5);
1175 
1176     std::for_each(lst.begin(), lst.end(), CheckValue<DefCtorPresent, Table>(c2));
1177 
1178     c2.clear();
1179     REQUIRE(c2.size() == 0);
1180 
1181     auto alloc = c.get_allocator();
1182     value_type* ptr = alloc.allocate(1);
1183     REQUIRE(ptr != nullptr);
1184     alloc.deallocate(ptr, 1);
1185 }
1186 
1187 template <typename ContainerTraits>
1188 void test_scoped_allocator() {
1189     using allocator_data_type = AllocatorAwareData<std::scoped_allocator_adaptor<std::allocator<int>>>;
1190     using basic_allocator_type = std::scoped_allocator_adaptor<std::allocator<allocator_data_type>>;
1191     using container_value_type = typename ContainerTraits::template container_value_type<allocator_data_type>;
1192     using allocator_type = typename std::allocator_traits<basic_allocator_type>::template rebind_alloc<container_value_type>;
1193     using container_type = typename ContainerTraits::template container_type<allocator_data_type, allocator_type>;
1194 
1195     allocator_type allocator;
1196     allocator_data_type key1(1, allocator);
1197     allocator_data_type key2(2, allocator);
1198 
1199     container_value_type value1 = Value<container_type>::make(key1);
1200     container_value_type value2 = Value<container_type>::make(key2);
1201 
1202     auto init_list = { value1, value2 };
1203 
1204     container_type c1(allocator);
1205     container_type c2(allocator);
1206 
1207     allocator_data_type::activate();
1208 
1209     emplace_helpers::call_emplace(c1, key1);
1210     emplace_helpers::call_emplace(c2, std::move(key2));
1211 
1212     c1.clear();
1213     c2.clear();
1214 
1215     c1.insert(value1);
1216     c2.insert(std::move(value2));
1217 
1218     c1.clear();
1219     c2.clear();
1220 
1221     c1.insert(init_list);
1222     c2.insert(value1);
1223 
1224     c1 = c2;
1225     c2 = std::move(c1);
1226 
1227     allocator_data_type::deactivate();
1228 }
1229 
1230 
1231 struct int_key {
1232     int my_item;
1233     int_key(int i) : my_item(i) {}
1234 };
1235 
1236 bool operator==(const int_key& ik, int i) { return ik.my_item == i; }
1237 bool operator==(int i, const int_key& ik) { return i == ik.my_item; }
1238 bool operator==(const int_key& ik1, const int_key& ik2) { return ik1.my_item == ik2.my_item; }
1239 
1240 bool operator<( const int_key& ik, int i ) { return ik.my_item < i; }
1241 bool operator<( int i, const int_key& ik ) { return i < ik.my_item; }
1242 bool operator<( const int_key& ik1, const int_key& ik2 ) { return ik1.my_item < ik2.my_item; }
1243 
1244 struct char_key {
1245     const char* my_item;
1246     char_key(const char* c) : my_item(c) {}
1247 
1248     const char& operator[] (std::size_t pos) const {
1249         return my_item[pos];
1250     }
1251 
1252     std::size_t size() const {
1253         return std::strlen(my_item);
1254     }
1255 };
1256 
1257 bool operator==(const char_key& ck, std::string c) {
1258     std::size_t i = 0;
1259     while (ck[i] != '\0' && i < c.size() && ck[i] == c[i]) { ++i;}
1260     return c.size() == i && ck[i] == '\0';
1261 }
1262 bool operator==(std::string c, const char_key& ck) {
1263     return ck == c;
1264 }
1265 bool operator==(const char_key& ck1, const char_key& ck2) {
1266     std::size_t i = 0;
1267     while (ck1[i] != '\0' && ck2[i] != '\0' && ck1[i] == ck2[i]) { ++i;}
1268     return ck1[i] == ck2[i];
1269 }
1270 
1271 bool operator<( const char_key& ck, std::string c ) {
1272     return std::lexicographical_compare(ck.my_item, ck.my_item + ck.size(), c.begin(), c.end());
1273 }
1274 
1275 bool operator<(std::string c, const char_key& ck) {
1276     return std::lexicographical_compare(c.begin(), c.end(), ck.my_item, ck.my_item + ck.size());
1277 }
1278 
1279 bool operator<( const char_key& ck1, const char_key& ck2 ) {
1280     return std::lexicographical_compare(ck1.my_item, ck1.my_item + ck1.size(), ck2.my_item, ck2.my_item + ck2.size());
1281 }
1282 
1283 struct equal_to {
1284     using is_transparent = int;
1285     template <typename T, typename W>
1286     bool operator()(const T &lhs, const W &rhs) const {
1287         return lhs == rhs;
1288     }
1289 };
1290 
1291 struct hash_with_transparent_key_equal {
1292     template <typename T>
1293     size_t operator()(const T& key) const { return hash(key); }
1294     using transparent_key_equal = equal_to;
1295     int prime = 433494437;
1296     int first_factor = 41241245;
1297     int second_factor = 2523422;
1298 
1299     size_t hash(const int& key) const { return (first_factor * key + second_factor) % prime; }
1300 
1301     size_t hash(const int_key& key) const { return (first_factor * key.my_item + second_factor) % prime; }
1302 
1303     size_t hash(const std::string& key) const {
1304         int sum = 0;
1305         for (auto it = key.begin(); it != key.end(); ++it) {
1306             sum += first_factor * (*it) + second_factor;
1307         }
1308         return sum % prime;
1309     }
1310 
1311     size_t hash(const char_key& key) const {
1312         int sum = 0;
1313         int i = 0;
1314         while (key[i] != '\0') {
1315             sum += first_factor * key[i++] + second_factor;
1316         }
1317         return sum % prime;
1318     }
1319 
1320 };
1321 
1322 template <typename Container>
1323 void check_heterogeneous_functions_key_int_impl() {
1324     static_assert(std::is_same<typename Container::key_type, int>::value,
1325                   "incorrect key_type for heterogeneous lookup test");
1326     // Initialization
1327     Container c;
1328     int size = 10;
1329     for (int i = 0; i < size; i++) {
1330         c.insert(Value<Container>::make(i));
1331     }
1332     // Insert first duplicated element for multicontainers
1333     if (AllowMultimapping<Container>::value) {
1334         c.insert(Value<Container>::make(0));
1335     }
1336 
1337     // Look up testing
1338     for (int i = 0; i < size; i++) {
1339         int_key k(i);
1340         int key = i;
1341         REQUIRE_MESSAGE(c.find(k) == c.find(key), "Incorrect heterogeneous find return value");
1342         REQUIRE_MESSAGE(c.count(k) == c.count(key), "Incorrect heterogeneous count return value");
1343     }
1344 
1345     // unsafe_extract testing
1346     for (int i = 0; i < size; i++) {
1347         Container extract_c = c;
1348         int_key int_k(i);
1349         auto int_key_extract = extract_c.unsafe_extract(int_k);
1350         if (!AllowMultimapping<Container>::value) {
1351             REQUIRE_MESSAGE(extract_c.find(int_k) == extract_c.end(), "Key exists after extract");
1352         }
1353         REQUIRE_MESSAGE(!int_key_extract.empty(), "Empty node with exists key");
1354         REQUIRE_MESSAGE(node_handling_tests::compare_handle_getters(int_key_extract, Value<Container>::make(i)), "Incorrect node");
1355     }
1356 
1357     // unsafe_extract not exists key
1358     auto not_exists = c.unsafe_extract(int_key(100));
1359     REQUIRE_MESSAGE(not_exists.empty(), "Not empty node with not exists key");
1360 
1361     // multimap unsafe_extract testing
1362     if (AllowMultimapping<Container>::value) {
1363         Container extract_m;
1364         for (int i = 0; i < size; i++) {
1365             extract_m.insert(Value<Container>::make(i));
1366             extract_m.insert(Value<Container>::make(i, i + 1));
1367         }
1368         for (int i = 0; i < size; i++) {
1369             int_key int_k(i);
1370             auto int_key_extract = extract_m.unsafe_extract(int_k);
1371             REQUIRE_MESSAGE(!int_key_extract.empty(), "Empty node with exists key");
1372             REQUIRE_MESSAGE((node_handling_tests::compare_handle_getters(int_key_extract, Value<Container>::make(i, i)) ||
1373                     node_handling_tests::compare_handle_getters(int_key_extract, Value<Container>::make(i, i + 1))), "Incorrect node");
1374             REQUIRE_MESSAGE(extract_m.find(int_k) != extract_m.end(), "All nodes for key deleted");
1375         }
1376     }
1377 
1378     // Erase testing
1379     for (int i = 0; i < size; i++) {
1380         auto count_before_erase = c.count(i);
1381         auto result = c.unsafe_erase(int_key(i));
1382         REQUIRE_MESSAGE(count_before_erase == result,"Incorrect erased elements count");
1383         REQUIRE_MESSAGE(c.count(i) == 0, "Some elements was not erased");
1384     }
1385 
1386 }
1387 
1388 template <typename Container>
1389 void check_heterogeneous_functions_key_string_impl() {
1390     static_assert(std::is_same<typename Container::key_type, std::string>::value,
1391                   "incorrect key_type for heterogeneous lookup test");
1392     // Initialization
1393     std::vector<const char*> keys{"key1", "key2", "key3", "key4",
1394         "key5", "key6", "key7", "key8", "key9", "key10"};
1395     std::vector<const char*> values{"value1", "value2", "value3", "value4",
1396         "value5", "value6", "value7", "value8", "value9", "value10", "value11"};
1397     Container c;
1398     for (auto it = keys.begin(); it != keys.end(); ++it) {
1399         c.insert(Value<Container>::make(*it));
1400     }
1401     // Insert first duplicated element for multicontainers
1402     if (AllowMultimapping<Container>::value) {
1403         c.insert(Value<Container>::make(*keys.begin()));
1404     }
1405 
1406     // Look up testing
1407     for (auto it = keys.begin(); it != keys.end(); ++it) {
1408         std::string key = *it;
1409         char_key k{*it};
1410         REQUIRE_MESSAGE(c.find(k) == c.find(key), "Incorrect heterogeneous find return value");
1411         REQUIRE_MESSAGE(c.count(k) == c.count(key), "Incorrect heterogeneous count return value");
1412     }
1413 
1414     // unsafe_extract testing
1415     for (auto it = keys.begin(); it != keys.end(); ++it) {
1416         Container extract_c = c;
1417         char_key k{*it};
1418         auto char_key_extract = extract_c.unsafe_extract(k);
1419         REQUIRE_MESSAGE(!char_key_extract.empty(), "Empty node with exists key");
1420         REQUIRE_MESSAGE(node_handling_tests::compare_handle_getters(char_key_extract, Value<Container>::make(*it)), "Incorrect node");
1421     }
1422 
1423     // unsafe_extract not exists key
1424     auto not_exists = c.unsafe_extract(char_key("not exists"));
1425     REQUIRE_MESSAGE(not_exists.empty(), "Not empty node with not exists key");
1426 
1427     // multimap unsafe_extract testing
1428     if (AllowMultimapping<Container>::value){
1429         Container extract_m;
1430         for (std::size_t i = 0; i < keys.size(); i++) {
1431             extract_m.insert(Value<Container>::make(keys[i], values[i]));
1432             extract_m.insert(Value<Container>::make(keys[i], values[i + 1]));
1433         }
1434         for (std::size_t i = 0; i < keys.size(); i++) {
1435             char_key char_k(keys[i]);
1436             auto char_key_extract = extract_m.unsafe_extract(char_k);
1437             REQUIRE_MESSAGE(!char_key_extract.empty(), "Empty node with exists key");
1438             REQUIRE_MESSAGE((node_handling_tests::compare_handle_getters(char_key_extract, Value<Container>::make(keys[i], values[i])) ||
1439                     node_handling_tests::compare_handle_getters(char_key_extract, Value<Container>::make(keys[i], values[i + 1]))), "Incorrect node");
1440             REQUIRE_MESSAGE(extract_m.find(char_k) != extract_m.end(), "All nodes for key deleted");
1441         }
1442     }
1443 
1444     // Erase testing
1445     for (auto it = keys.begin(); it != keys.end(); ++it) {
1446         std::string key = *it;
1447         char_key k{*it};
1448         auto count_before_erase = c.count(key);
1449         auto result = c.unsafe_erase(k);
1450         REQUIRE_MESSAGE(count_before_erase==result,"Incorrect erased elements count");
1451         REQUIRE_MESSAGE(c.count(key)==0, "Some elements was not erased");
1452     }
1453 }
1454 
1455 struct CountingKey {
1456     static std::size_t counter;
1457 
1458     CountingKey() { ++counter; }
1459     CountingKey( const CountingKey& ) { ++counter; }
1460     ~CountingKey() {}
1461     CountingKey& operator=( const CountingKey& ) { return *this; }
1462 
1463     static void reset() { counter = 0; }
1464 };
1465 
1466 std::size_t CountingKey::counter;
1467 
1468 namespace std {
1469 template <>
1470 struct hash<CountingKey> {
1471     std::size_t operator()( const CountingKey& ) const { return 0; }
1472 };
1473 }
1474 
1475 bool operator==( const CountingKey&, const CountingKey& ) { return true; }
1476 
1477 bool operator<( const CountingKey&, const CountingKey& ) { return true; }
1478 
1479 struct int_constructible_object {
1480     int_constructible_object(int k) : key(k) {}
1481     int key;
1482 }; // struct int_constructible_object
1483 
1484 bool operator==( const int_constructible_object& lhs, const int_constructible_object rhs ) {
1485     return lhs.key == rhs.key;
1486 }
1487 
1488 // A test for
1489 // template <typename P> insert(P&&) in maps
1490 template <template <typename...> class Container>
1491 void test_insert_by_generic_pair() {
1492     using value_type = std::pair<const int, int_constructible_object>;
1493     using generic_pair_type = std::pair<int, int>;
1494 
1495     static_assert(std::is_constructible<value_type, generic_pair_type>::value,
1496                   "Incorrect test setup");
1497 
1498     Container<int, int_constructible_object> cont1, cont2;
1499     using iterator = typename Container<int, int_constructible_object>::iterator;
1500 
1501     for (int i = 0; i != 10; ++i) {
1502         std::pair<iterator, bool> res_generic_insert = cont1.insert(generic_pair_type(1, i));
1503         std::pair<iterator, bool> res_value_insert = cont2.insert(value_type(1, int_constructible_object(i)));
1504 
1505         REQUIRE_MESSAGE(*res_generic_insert.first == *res_value_insert.first, "Insert by generic pair returned wrong iterator");
1506         REQUIRE_MESSAGE(res_generic_insert.second == res_value_insert.second, "Insert by generic pair returned wrong insertion value");
1507     }
1508 
1509     for (int i = 0; i != 10; ++i) {
1510         iterator res_generic_insert_hint = cont1.insert(cont1.cbegin(), generic_pair_type(2, i));
1511         iterator res_value_insert_hint = cont2.insert(cont2.cbegin(), value_type(2, int_constructible_object(i)));
1512 
1513         REQUIRE_MESSAGE(*res_generic_insert_hint == *res_value_insert_hint, "Hinted insert by generic pair returned wrong iterator");
1514     }
1515 
1516     Container<CountingKey, int_constructible_object> counting_cont;
1517     using counting_generic_pair = std::pair<CountingKey, int>;
1518 
1519     static_assert(std::is_constructible<typename decltype(counting_cont)::value_type, counting_generic_pair>::value,
1520                   "Incorrect test setup");
1521 
1522     counting_generic_pair counting_pair(CountingKey{}, 1);
1523     CountingKey::reset();
1524 
1525     counting_cont.insert(counting_pair);
1526     REQUIRE_MESSAGE(CountingKey::counter == 1, "Only one element should be constructed in-place during the generic pair insertion");
1527 
1528     CountingKey::reset();
1529 }
1530 
1531 template <typename Container>
1532 void test_swap_not_always_equal_allocator() {
1533     static_assert(std::is_same<typename Container::allocator_type, NotAlwaysEqualAllocator<typename Container::value_type>>::value,
1534                   "Incorrect allocator in not always equal test");
1535     Container c1{};
1536     Container c2{Value<Container>::make(1), Value<Container>::make(2)};
1537 
1538     Container c1_copy = c1;
1539     Container c2_copy = c2;
1540 
1541     c1.swap(c2);
1542 
1543     REQUIRE_MESSAGE(c1 == c2_copy, "Incorrect swap with not always equal allocator");
1544     REQUIRE_MESSAGE(c2 == c1_copy, "Incorrect swap with not always equal allocator");
1545 }
1546 
1547 #if TBB_USE_EXCEPTIONS
1548 template <typename Container>
1549 void test_exception_on_copy_ctor() {
1550     Container c1;
1551     c1.emplace(Value<Container>::make(ThrowOnCopy{}));
1552 
1553     using container_allocator_type = std::allocator<Container>;
1554     using alloc_traits = std::allocator_traits<container_allocator_type>;
1555     container_allocator_type container_allocator;
1556     Container* c2_ptr = alloc_traits::allocate(container_allocator, 1);
1557 
1558     ThrowOnCopy::activate();
1559     // Test copy ctor
1560     try {
1561         alloc_traits::construct(container_allocator, c2_ptr, c1);
1562     } catch ( int error_code ) {
1563         REQUIRE_MESSAGE(error_code == ThrowOnCopy::error_code(), "Incorrect code was thrown");
1564     }
1565 
1566     REQUIRE_MESSAGE(c2_ptr->empty(), "Incorrect container state after throwing copy constructor");
1567 
1568     alloc_traits::deallocate(container_allocator, c2_ptr, 1);
1569     c2_ptr = alloc_traits::allocate(container_allocator, 1);
1570 
1571     // Test copy ctor with allocator
1572     try {
1573         auto value_allocator = c1.get_allocator();
1574         alloc_traits::construct(container_allocator, c2_ptr, c1, value_allocator);
1575     } catch( int error_code ) {
1576         REQUIRE_MESSAGE(error_code == ThrowOnCopy::error_code(), "Incorrect code was thrown");
1577     }
1578 
1579     REQUIRE_MESSAGE(c2_ptr->empty(), "Incorrect container state after throwing copy ctor with allocator");
1580     alloc_traits::deallocate(container_allocator, c2_ptr, 1);
1581     ThrowOnCopy::deactivate();
1582 }
1583 #endif // TBB_USE_EXCEPTIONS
1584 
1585 #endif // __TBB_test_common_concurrent_associative_common_H
1586