1 /*
2     Copyright (c) 2005-2021 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 shuold 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 T, typename CheckElementState>
429 void test_basic_common()
430 {
431     T cont;
432     const T &ccont(cont);
433     CheckNoAllocations(cont);
434     // bool empty() const;
435     REQUIRE_MESSAGE(ccont.empty(), "Concurrent container is not empty after construction");
436 
437     // size_type size() const;
438     REQUIRE_MESSAGE(ccont.size() == 0, "Concurrent container is not empty after construction");
439 
440     // size_type max_size() const;
441     REQUIRE_MESSAGE(ccont.max_size() > 0, "Concurrent container max size is invalid");
442 
443     //iterator begin();
444     //iterator end();
445     REQUIRE_MESSAGE(cont.begin() == cont.end(), "Concurrent container iterators are invalid after construction");
446     REQUIRE_MESSAGE(ccont.begin() == ccont.end(), "Concurrent container iterators are invalid after construction");
447     REQUIRE_MESSAGE(cont.cbegin() == cont.cend(), "Concurrent container iterators are invalid after construction");
448 
449     //std::pair<iterator, bool> insert(const value_type& obj);
450     std::pair<typename T::iterator, bool> ins = cont.insert(Value<T>::make(1));
451     REQUIRE_MESSAGE((ins.second == true && Value<T>::get(*(ins.first)) == 1), "Element 1 has not been inserted properly");
452 
453     test_rvalue_insert<T,CheckElementState>(1,2);
454     test_emplace_insert<T,CheckElementState>(1,2);
455 
456     // bool empty() const;
457     REQUIRE_MESSAGE(!ccont.empty(), "Concurrent container is empty after adding an element");
458 
459     // size_type size() const;
460     REQUIRE_MESSAGE(ccont.size() == 1, "Concurrent container size is incorrect");
461 
462     std::pair<typename T::iterator, bool> ins2 = cont.insert(Value<T>::make(1));
463 
464     if (AllowMultimapping<T>::value)
465     {
466         // std::pair<iterator, bool> insert(const value_type& obj);
467         REQUIRE_MESSAGE((ins2.second == true && Value<T>::get(*(ins2.first)) == 1), "Element 1 has not been inserted properly");
468 
469         // size_type size() const;
470         REQUIRE_MESSAGE(ccont.size() == 2, "Concurrent container size is incorrect");
471 
472         // size_type count(const key_type& k) const;
473         REQUIRE_MESSAGE(ccont.count(1) == 2, "Concurrent container count(1) is incorrect");
474         // std::pair<iterator, iterator> equal_range(const key_type& k);
475         std::pair<typename T::iterator, typename T::iterator> range = cont.equal_range(1);
476         typename T::iterator it;
477         it = range.first;
478         REQUIRE_MESSAGE((it != cont.end() && Value<T>::get(*it) == 1), "Element 1 has not been found properly");
479         unsigned int count = 0;
480         for (; it != range.second; it++)
481         {
482             count++;
483             REQUIRE_MESSAGE((Value<T>::get(*it) == 1), "Element 1 has not been found properly");
484         }
485 
486         REQUIRE_MESSAGE(count == 2, "Range doesn't have the right number of elements");
487     }
488     else
489     {
490         // std::pair<iterator, bool> insert(const value_type& obj);
491         REQUIRE_MESSAGE((ins2.second == false && ins2.first == ins.first), "Element 1 should not be re-inserted");
492 
493         // size_type size() const;
494         REQUIRE_MESSAGE(ccont.size() == 1, "Concurrent container size is incorrect");
495 
496         // size_type count(const key_type& k) const;
497         REQUIRE_MESSAGE(ccont.count(1) == 1, "Concurrent container count(1) is incorrect");
498 
499         // std::pair<const_iterator, const_iterator> equal_range(const key_type& k) const;
500         // std::pair<iterator, iterator> equal_range(const key_type& k);
501         std::pair<typename T::iterator, typename T::iterator> range = cont.equal_range(1);
502         typename T::iterator it = range.first;
503         REQUIRE_MESSAGE((it != cont.end() && Value<T>::get(*it) == 1), "Element 1 has not been found properly");
504         REQUIRE_MESSAGE((++it == range.second), "Range doesn't have the right number of elements");
505     }
506 
507     // const_iterator find(const key_type& k) const;
508     // iterator find(const key_type& k);
509     typename T::iterator it = cont.find(1);
510     REQUIRE_MESSAGE((it != cont.end() && Value<T>::get(*(it)) == 1), "Element 1 has not been found properly");
511     REQUIRE_MESSAGE(ccont.find(1) == it, "Element 1 has not been found properly");
512 
513     //bool contains(const key_type&k) const
514     REQUIRE_MESSAGE(cont.contains(1), "contains() cannot detect existing element");
515     REQUIRE_MESSAGE(!cont.contains(0), "contains() detect not existing element");
516 
517     // iterator insert(const_iterator hint, const value_type& obj);
518     typename T::iterator it2 = cont.insert(ins.first, Value<T>::make(2));
519     REQUIRE_MESSAGE((Value<T>::get(*it2) == 2), "Element 2 has not been inserted properly");
520 
521     // T(const T& _Umap)
522     T newcont = ccont;
523 
524     REQUIRE_MESSAGE((AllowMultimapping<T>{} ? (newcont.size() == 3) : (newcont.size() == 2)), "Copy construction has not copied the elements properly");
525 
526     // size_type unsafe_erase(const key_type& k);
527     typename T::size_type size;
528 #if _MSC_VER && __INTEL_COMPILER == 1900
529     // The compiler optimizes the next line too aggressively.
530 #pragma noinline
531 #endif
532     size = cont.unsafe_erase(1);
533 
534     REQUIRE_MESSAGE((AllowMultimapping<T>{} ? (size == 2) : (size == 1)), "Erase has not removed the right number of elements");
535 
536     // iterator unsafe_erase(iterator position);
537     typename T::iterator it4 = cont.unsafe_erase(cont.find(2));
538 
539     REQUIRE_MESSAGE((it4 == cont.end() && cont.size() == 0), "Erase has not removed the last element properly");
540 
541     // iterator unsafe_erase(const_iterator position);
542     cont.insert(Value<T>::make(3));
543     typename T::iterator it5 = cont.unsafe_erase(cont.cbegin());
544     REQUIRE_MESSAGE((it5 == cont.end() && cont.size() == 0), "Erase has not removed the last element properly");
545 
546     // template<class InputIterator> void insert(InputIterator first, InputIterator last);
547 
548     cont.insert(newcont.begin(), newcont.end());
549 
550     REQUIRE_MESSAGE((AllowMultimapping<T>{} ? (cont.size() == 3) : (cont.size() == 2)), "Range insert has not copied the elements properly");
551 
552     // iterator unsafe_erase(const_iterator first, const_iterator last);
553     std::pair<typename T::iterator, typename T::iterator> range2 = newcont.equal_range(1);
554 
555     newcont.unsafe_erase(range2.first, range2.second);
556     REQUIRE_MESSAGE(newcont.size() == 1, "Range erase has not erased the elements properly");
557 
558     // void clear();
559     newcont.clear();
560     REQUIRE_MESSAGE((newcont.begin() == newcont.end() && newcont.size() == 0), "Clear has not cleared the container");
561 
562     // void insert(std::initializer_list<value_type> &il);
563     newcont.insert( { Value<T>::make( 1 ), Value<T>::make( 2 ), Value<T>::make( 1 ) } );
564     if (AllowMultimapping<T>::value) {
565 
566         REQUIRE_MESSAGE(newcont.size() == 3, "Concurrent container size is incorrect");
567         REQUIRE_MESSAGE(newcont.count(1) == 2, "Concurrent container count(1) is incorrect");
568         REQUIRE_MESSAGE(newcont.count(2) == 1, "Concurrent container count(2) is incorrect");
569         std::pair<typename T::iterator, typename T::iterator> range = cont.equal_range(1);
570         it = range.first;
571         // REQUIRE_MESSAGE((it != newcont.end() && Value<T>::get(*it) == 1), "Element 1 has not been found properly");
572         REQUIRE_MESSAGE((it != newcont.end()), "iterator" );
573         REQUIRE_MESSAGE((Value<T>::get(*it) == 1), "value");
574         unsigned int count = 0;
575         for (; it != range.second; it++) {
576             count++;
577             REQUIRE_MESSAGE(Value<T>::get(*it) == 1, "Element 1 has not been found properly");
578         }
579         REQUIRE_MESSAGE(count == 2, "Range doesn't have the right number of elements");
580         range = newcont.equal_range(2); it = range.first;
581         REQUIRE_MESSAGE((it != newcont.end() && Value<T>::get(*it) == 2), "Element 2 has not been found properly");
582         count = 0;
583         for (; it != range.second; it++) {
584             count++;
585             REQUIRE_MESSAGE(Value<T>::get(*it) == 2, "Element 2 has not been found properly");
586         }
587         REQUIRE_MESSAGE(count == 1, "Range doesn't have the right number of elements");
588     } else {
589         REQUIRE_MESSAGE(newcont.size() == 2, "Concurrent container size is incorrect");
590         REQUIRE_MESSAGE(newcont.count(1) == 1, "Concurrent container count(1) is incorrect");
591         REQUIRE_MESSAGE(newcont.count(2) == 1, "Concurrent container count(2) is incorrect");
592         std::pair<typename T::iterator, typename T::iterator> range = newcont.equal_range(1);
593         it = range.first;
594         REQUIRE_MESSAGE((it != newcont.end() && Value<T>::get(*it) == 1), "Element 1 has not been found properly");
595         REQUIRE_MESSAGE((++it == range.second), "Range doesn't have the right number of elements");
596         range = newcont.equal_range(2);
597         it = range.first;
598         REQUIRE_MESSAGE((it != newcont.end() && Value<T>::get(*it) == 2), "Element 2 has not been found properly");
599         REQUIRE_MESSAGE((++it == range.second), "Range doesn't have the right number of elements");
600     }
601 
602     // T& operator=(const T& _Umap)
603     newcont = ccont;
604     REQUIRE_MESSAGE((AllowMultimapping<T>{} ? (newcont.size() == 3) : (newcont.size() == 2)), "Assignment operator has not copied the elements properly");
605 
606 
607     cont.clear();
608     CheckNoAllocations(cont);
609     for (int i = 0; i < 256; i++)
610     {
611         std::pair<typename T::iterator, bool> ins3 = cont.insert(Value<T>::make(i));
612         REQUIRE_MESSAGE((ins3.second == true && Value<T>::get(*(ins3.first)) == i), "Element 1 has not been inserted properly");
613     }
614     REQUIRE_MESSAGE(cont.size() == 256, "Wrong number of elements have been inserted");
615     REQUIRE(!cont.range().empty());
616     REQUIRE(!ccont.range().empty());
617     REQUIRE((256 == CheckRecursiveRange<T,typename T::iterator>(cont.range()).first));
618     REQUIRE((256 == CheckRecursiveRange<T,typename T::const_iterator>(ccont.range()).first));
619     REQUIRE(cont.range().grainsize() > 0);
620     REQUIRE(ccont.range().grainsize() > 0);
621 
622     // void swap(T&);
623     cont.swap(newcont);
624     REQUIRE_MESSAGE(newcont.size() == 256, "Wrong number of elements after swap");
625     REQUIRE_MESSAGE(newcont.count(200) == 1, "Element with key 200 is not present after swap");
626     REQUIRE_MESSAGE(newcont.count(16) == 1, "Element with key 16 is not present after swap");
627     REQUIRE_MESSAGE(newcont.count(99) == 1, "Element with key 99 is not present after swap");
628     REQUIRE_MESSAGE((AllowMultimapping<T>{} ? (cont.size() == 3) : (cont.size() == 2)), "Assignment operator has not copied the elements properly");
629 
630     T newcont_bkp = newcont;
631     newcont.swap(newcont);
632     REQUIRE_MESSAGE(newcont == newcont_bkp, "Unexpected swap-with-itself behavior");
633 
634     test_comparison_operators<T>();
635 
636     SpecialTests<T>::Test();
637 }
638 
639 template <typename Container>
640 class FillTable {
641     Container& my_table;
642     const int my_items;
643     bool my_asymptotic;
644 
645     using pair_ib = std::pair<typename Container::iterator, bool>;
646 public:
647     FillTable(Container& table, int items, bool asymptotic)
648         : my_table(table), my_items(items), my_asymptotic(asymptotic)
649     {
650         REQUIRE((!(items&1) && items > 100));
651     }
652 
653     void operator()( int thread_index ) const {
654         if (thread_index == 0) { // Fill even keys forward (single thread)
655             bool last_inserted = true;
656 
657             for (int i = 0; i < my_items; i += 2) {
658                 int val = my_asymptotic ? 1 : i;
659                 pair_ib pib = my_table.insert(Value<Container>::make(val));
660                 REQUIRE_MESSAGE((Value<Container>::get(*(pib.first)) == val),
661                                 "Element not properly inserted");
662                 REQUIRE_MESSAGE((last_inserted || !pib.second),
663                                 "Previous key was not inserted but current key is inserted");
664                 last_inserted = pib.second;
665             }
666         } else if (thread_index == 1) { // Fill even keys backward (single thread)
667             bool last_inserted = true;
668 
669             for (int i = my_items - 2; i >= 0; i -= 2) {
670                 int val = my_asymptotic ? 1 : i;
671                 pair_ib pib = my_table.insert(Value<Container>::make(val));
672                 REQUIRE_MESSAGE((Value<Container>::get(*(pib.first)) == val),
673                                 "Element not properly inserted");
674                 REQUIRE_MESSAGE((last_inserted || !pib.second),
675                                 "Previous key was not inserted but current key is inserted");
676                 last_inserted = pib.second;
677             }
678         } else if (!(thread_index & 1)) { // Fill odd keys forward (multiple threads)
679             for (int i = 1; i < my_items; i += 2) {
680                 if (i % 32 == 1 && i + 6 < my_items) {
681                     if (my_asymptotic) {
682                         auto init = { Value<Container>::make(1), Value<Container>::make(1), Value<Container>::make(1) };
683                         my_table.insert(init);
684                         REQUIRE_MESSAGE(Value<Container>::get(*my_table.find(1)) == 1, "Element not properly inserted");
685                     } else {
686                         auto init = { Value<Container>::make(i), Value<Container>::make(i + 2),
687                                       Value<Container>::make(i + 4) };
688                         my_table.insert(init);
689                         REQUIRE_MESSAGE(Value<Container>::get(*my_table.find(i)) == i, "Element i not properly inserted");
690                         REQUIRE_MESSAGE(Value<Container>::get(*my_table.find(i + 2)) == i + 2, "Element i + 2 not properly inserted");
691                         REQUIRE_MESSAGE(Value<Container>::get(*my_table.find(i + 4)) == i + 4, "Element i + 4 not properly inserted");
692                     }
693                     i += 4;
694                 } else {
695                     pair_ib pib = my_table.insert(Value<Container>::make(my_asymptotic ? 1 : i));
696                     REQUIRE_MESSAGE(Value<Container>::get(*(pib.first)) == (my_asymptotic ? 1 : i), "Element not properly inserted");
697                 }
698             }
699         } else { // Check odd keys backward (multiple threads)
700             if (!my_asymptotic) {
701                 bool last_found = false;
702                 for (int i = my_items - 1; i >= 0; i -= 2) {
703                     typename Container::iterator it = my_table.find(i);
704 
705                     if (it != my_table.end()) { // found
706                         REQUIRE_MESSAGE(Value<Container>::get(*it) == i, "Element not properly inserted");
707                         last_found = true;
708                     } else {
709                         REQUIRE_MESSAGE(!last_found, "Previous key was found, but current was not found");
710                     }
711                 }
712             }
713         }
714     }
715 }; // class FillTable
716 
717 template <typename Container, typename Range>
718 struct ParallelTraverseBody {
719     const int n;
720     atomic_byte_type* const array;
721 
722     ParallelTraverseBody( atomic_byte_type arr[], int num )
723         : n(num), array(arr) {}
724 
725     void operator()( const Range& range ) const {
726         for (auto i = range.begin(); i != range.end(); ++i) {
727             int k = static_cast<int>(Value<Container>::key(*i));
728             REQUIRE(k == Value<Container>::get(*i));
729             REQUIRE(0 <= k);
730             REQUIRE(k < n);
731             ++array[k];
732         }
733     }
734 }; // struct ParallelTraverseBody
735 
736 template<typename T>
737 class CheckTable : utils::NoAssign {
738     T& table;
739 public:
740     CheckTable(T& t) : NoAssign(), table(t) {}
741     void operator()(int i) const {
742         int c = (int)table.count(i);
743         CHECK_MESSAGE(c, "must exist");
744     }
745 };
746 
747 template <typename Container>
748 void test_concurrent_common( bool asymptotic = false ) {
749 #if __TBB_USE_ASSERT
750     int items = 2000;
751 #else
752     int items = 20000;
753 #endif
754     int items_inserted = 0;
755     int num_threads = 16;
756 
757     Container table;
758 
759     if (AllowMultimapping<Container>::value) {
760         // TODO: comment
761         items = 4 * items / (num_threads + 2);
762         items_inserted = items + (num_threads - 2) * items / 4;
763     } else {
764         items_inserted = items;
765     }
766 
767     utils::NativeParallelFor(num_threads, FillTable<Container>(table, items, asymptotic));
768 
769     REQUIRE(int(table.size()) == items_inserted);
770 
771     if (!asymptotic) {
772         atomic_byte_type* array = new atomic_byte_type[items];
773         std::memset(static_cast<void*>(array), 0, items * sizeof(atomic_byte_type));
774 
775         typename Container::range_type r = table.range();
776 
777         auto p = CheckRecursiveRange<Container, typename Container::iterator>(r);
778         REQUIRE(items_inserted == p.first);
779 
780         tbb::parallel_for(r, ParallelTraverseBody<Container, typename Container::range_type>(array, items));
781         CheckRange(array, items, AllowMultimapping<Container>::value, (num_threads - 1)/2);
782 
783         const Container& const_table = table;
784         std::memset(static_cast<void*>(array), 0, items * sizeof(atomic_byte_type));
785         typename Container::const_range_type cr = const_table.range();
786 
787         p = CheckRecursiveRange<Container, typename Container::const_iterator>(cr);
788         REQUIRE(items_inserted == p.first);
789 
790         tbb::parallel_for(cr, ParallelTraverseBody<Container, typename Container::const_range_type>(array, items));
791         CheckRange(array, items, AllowMultimapping<Container>::value, (num_threads - 1) / 2);
792         delete[] array;
793 
794         tbb::parallel_for(0, items, CheckTable<Container>(table));
795     }
796 
797     table.clear();
798     // TODO: add check for container allocator counters
799 }
800 
801 template <typename ContainerTraits>
802 void test_rvalue_ref_support() {
803     using namespace move_support_tests;
804     test_move_constructor<ContainerTraits>();
805     test_move_assignment<ContainerTraits>();
806 #if TBB_USE_EXCEPTIONS
807     test_ex_move_constructor<ContainerTraits>();
808 #endif
809 }
810 
811 template <typename Container>
812 void test_range_based_for_support() {
813     using namespace range_based_for_support_tests;
814 
815     Container cont;
816     const int sequence_length = 100;
817 
818     for (int i = 1; i <= sequence_length; ++i) {
819         cont.insert(Value<Container>::make(i));
820     }
821 
822     auto range_based_for_result = range_based_for_accumulate(cont, UnifiedSummer{}, 0);
823     auto reference_result = gauss_summ_of_int_sequence(sequence_length);
824     REQUIRE_MESSAGE(range_based_for_result == reference_result,
825                     "Incorrect accumulated value generated via range based for");
826 }
827 
828 template <typename Container>
829 void test_initializer_list_support( std::initializer_list<typename Container::value_type> init ) {
830     using namespace initializer_list_support_tests;
831 
832     test_initializer_list_support_without_assign<Container, TestInsertMethod>(init);
833     test_initializer_list_support_without_assign<Container, TestInsertMethod>({});
834 }
835 
836 template <typename Checker>
837 void test_set_specific_types() {
838     // TODO: add tests for atomics
839     Checker check_types;
840     const int num = 10;
841 
842     // Test int
843     std::list<int> arr_int;
844     for (int i = 0; i != num; ++i) {
845         arr_int.emplace_back(i);
846     }
847     check_types.template check</*DefCtorPresent = */true>(arr_int);
848 
849     // Test reference_wrapper
850     std::list<std::reference_wrapper<int>> arr_ref;
851     for (auto it = arr_int.begin(); it != arr_int.end(); ++it) {
852         arr_ref.emplace_back(*it);
853     }
854     check_types.template check</*DefCtorPresent = */false>(arr_ref);
855 
856     // Test share_ptr
857     std::list<std::shared_ptr<int>> arr_shr;
858     for (int i = 0; i != num; ++i) {
859         arr_shr.emplace_back(std::make_shared<int>(i));
860     }
861     check_types.template check</*DefCtorPresent = */true>(arr_shr);
862 
863     // Test weak_ptr
864     std::list<std::weak_ptr<int>> arr_weak;
865     std::copy(arr_shr.begin(), arr_shr.end(), std::back_inserter(arr_weak));
866     check_types.template check</*DefCtorPresent = */true>(arr_weak);
867 
868     // Test std::pair
869     std::list<std::pair<int, int>> arr_pairs;
870     for (int i = 0; i != num; ++i) {
871         arr_pairs.emplace_back(i, i);
872     }
873     check_types.template check</*DefCtorPresent = */true>(arr_pairs);
874 
875     // Test std::basic_string
876     std::list<std::basic_string<char, std::char_traits<char>, tbb::tbb_allocator<char>>> arr_strings;
877     for (int i = 0; i != num; ++i) {
878         arr_strings.emplace_back(i, char(i));
879     }
880     check_types.template check</*DefCtorPresent = */true>(arr_strings);
881 }
882 
883 template <typename Checker>
884 void test_map_specific_types() {
885     // TODO: add tests for int-atomic pairs
886     Checker check_types;
887     const int num = 10;
888 
889     // Test int-int pairs
890     std::list<std::pair<const int, int>> arr_int_int_pairs;
891     for (int i = 0; i != num; ++i) {
892         arr_int_int_pairs.emplace_back(i, num - i);
893     }
894     check_types.template check</*DefCtorPresent = */true>(arr_int_int_pairs);
895 
896     // Test reference_wrapper-int pairs
897     std::list<std::pair<const std::reference_wrapper<const int>, int>> arr_ref_int_pairs;
898     for (auto& item : arr_int_int_pairs) {
899         arr_ref_int_pairs.emplace_back(item.first, item.second);
900     }
901     check_types.template check</*DefCtorPresent = */true>(arr_ref_int_pairs);
902 
903     // Test int-reference_wrapper pairs
904     std::list<std::pair<const int, std::reference_wrapper<int>>> arr_int_ref_pairs;
905     for (auto& item : arr_int_int_pairs) {
906         arr_int_ref_pairs.emplace_back(item.first, item.second);
907     }
908     check_types.template check</*DefCtorPresent = */false>(arr_int_ref_pairs);
909 
910     // Test shared_ptr
911     std::list<std::pair<const std::shared_ptr<int>, std::shared_ptr<int>>> arr_shared_pairs;
912     for (int i = 0; i != num; ++i) {
913         const int num_minus_i = num - i;
914         arr_shared_pairs.emplace_back(std::make_shared<int>(i), std::make_shared<int>(num_minus_i));
915     }
916     check_types.template check</*DefCtorPresent = */true>(arr_shared_pairs);
917 
918     // Test weak_ptr
919     std::list<std::pair<const std::weak_ptr<int>, std::weak_ptr<int>>> arr_wick_pairs;
920     std::copy(arr_shared_pairs.begin(), arr_shared_pairs.end(), std::back_inserter(arr_wick_pairs));
921     check_types.template check</*DefCtorPresent = */true>(arr_wick_pairs);
922 
923     // Test std::pair
924     using pair_key_type = std::pair<int, int>;
925     std::list<std::pair<const pair_key_type, int>> arr_pair_int_pairs;
926     for (int i = 0; i != num; ++i) {
927         arr_pair_int_pairs.emplace_back(pair_key_type{i, i}, i);
928     }
929     check_types.template check</*DefCtorPresent = */true>(arr_pair_int_pairs);
930 
931     // Test std::basic_string
932     using tbb_string_key_type = std::basic_string<char, std::char_traits<char>, tbb::tbb_allocator<char>>;
933     std::list<std::pair<const tbb_string_key_type, int>> arr_tbb_string_pairs;
934     for (int i = 0; i != num; ++i) {
935         tbb_string_key_type key(i, char(i));
936         arr_tbb_string_pairs.emplace_back(key, i);
937     }
938     check_types.template check</*DefCtorPresent = */true>(arr_tbb_string_pairs);
939 }
940 
941 namespace test {
942 
943 // For the sake of simplified testing, make std::unique_ptr implicitly convertible to/from the pointer
944 template <typename T>
945 class unique_ptr : public std::unique_ptr<T> {
946 public:
947     using pointer = typename std::unique_ptr<T>::pointer;
948 
949     unique_ptr( pointer p ) : std::unique_ptr<T>(p) {}
950     operator pointer() const { return this->get(); }
951 }; // class unique_ptr
952 
953 } // namespace test
954 
955 namespace std {
956 template <typename T>
957 struct hash<test::unique_ptr<T>> {
958     std::size_t operator()(const test::unique_ptr<T>& ptr) const {
959         return std::hash<std::unique_ptr<T>>{}(ptr);
960     }
961 };
962 }
963 
964 template <bool Condition>
965 struct CallIf {
966     template <typename Func>
967     void operator()( Func func ) const { func(); }
968 };
969 
970 template <>
971 struct CallIf<false> {
972     template <typename Func>
973     void operator()( Func ) const {}
974 };
975 
976 template <typename Table>
977 class TestOperatorSquareBrackets {
978     using value_type = typename Table::value_type;
979     Table& my_c;
980     const value_type& my_value;
981 public:
982     TestOperatorSquareBrackets( Table& c, const value_type& value )
983         : my_c(c), my_value(value) {}
984 
985     void operator()() const {
986         utils::IsEqual equal;
987         REQUIRE(equal(my_c[my_value.first], my_value.second));
988         typename Table::key_type temp_key = my_value.first;
989         REQUIRE(equal(my_c[std::move(temp_key)], my_value.second));
990     }
991 }; // class TestOperatorSquareBrackets
992 
993 template <bool DefCtorPresent, typename Table, typename Value>
994 void TestSquareBracketsAndAt( Table&, const Value&, /*multimap = */std::true_type ) {
995     // operator [] and at are not presented in the multimap
996 }
997 
998 template <bool DefCtorPresent, typename Table, typename Value>
999 void TestSquareBracketsAndAt( Table& c, const Value& value, /*multimap = */std::false_type ) {
1000     CallIf<DefCtorPresent>()(TestOperatorSquareBrackets<Table>(c, value));
1001     utils::IsEqual equal;
1002     REQUIRE(equal(c.at(value.first), value.second));
1003     // TODO: add test for at exceptions
1004     const Table& constC = c;
1005     REQUIRE(equal(constC.at(value.first), value.second));
1006 }
1007 
1008 template <bool DefCtorPresent, typename Table, typename Value>
1009 void TestMapSpecificMethods( Table&, const Value& ) {}
1010 
1011 template <bool DefCtorPresent, typename Table>
1012 void TestMapSpecificMethods( Table& c, const std::pair<const typename Table::key_type,
1013                                                        typename Table::mapped_type>& value )
1014 {
1015     TestSquareBracketsAndAt<DefCtorPresent>(c, value, std::integral_constant<bool, AllowMultimapping<Table>::value>{});
1016 }
1017 
1018 template <bool DefCtorPresent, typename Table>
1019 class CheckValue {
1020     Table& my_c;
1021 public:
1022     CheckValue( Table& c ) : my_c(c) {}
1023     void operator()( const typename Table::value_type& value ) {
1024         using iterator = typename Table::iterator;
1025         using const_iterator = typename Table::const_iterator;
1026         const Table& constC = my_c;
1027         // count
1028         REQUIRE(my_c.count(Value<Table>::key(value)) == 1);
1029         // find
1030         utils::IsEqual equal;
1031         REQUIRE(equal(*my_c.find(Value<Table>::key(value)), value));
1032         REQUIRE(equal(*constC.find(Value<Table>::key(value)), value));
1033         // erase
1034         REQUIRE(my_c.unsafe_erase(Value<Table>::key(value)) != 0);
1035         REQUIRE(my_c.unsafe_erase(Value<Table>::key(value)) == 0);
1036         // insert
1037         std::pair<iterator, bool> res = my_c.insert(value);
1038         REQUIRE(equal(*res.first, value));
1039         REQUIRE(res.second);
1040         // erase
1041         iterator it = res.first;
1042         ++it;
1043         REQUIRE(my_c.unsafe_erase(res.first) == it);
1044         // insert
1045         REQUIRE(equal(*my_c.insert(my_c.begin(), value), value));
1046         // equal_range
1047         std::pair<iterator, iterator> r1 = my_c.equal_range(Value<Table>::key(value));
1048         REQUIRE((equal(*r1.first, value) && ++r1.first == r1.second));
1049         std::pair<const_iterator, const_iterator> r2 = constC.equal_range(Value<Table>::key(value));
1050         REQUIRE((equal(*r2.first, value) && ++r2.first == r2.second));
1051 
1052         TestMapSpecificMethods<DefCtorPresent>(my_c, value);
1053     }
1054 }; // class CheckValue
1055 
1056 namespace detail {
1057 
1058 #if (__INTEL_COMPILER || __clang__ ) && __TBB_GLIBCXX_VERSION && __TBB_GLIBCXX_VERSION < 40900
1059 template <typename T>
1060 struct assignable_atomic : std::atomic<T> {
1061     using std::atomic<T>::operator=;
1062     assignable_atomic& operator=(const assignable_atomic& a) {
1063         store(a.load(std::memory_order_relaxed), std::memory_order_relaxed);
1064     }
1065 };
1066 
1067 template <typename T>
1068 using atomic_type = assignable_atomic<T>;
1069 #else
1070 template <typename T>
1071 using atomic_type = std::atomic<T>;
1072 #endif
1073 }
1074 
1075 template <typename Value>
1076 class TestRange {
1077     const std::list<Value>& my_lst;
1078     std::vector<detail::atomic_type<bool>>& my_marks;
1079 public:
1080     TestRange( const std::list<Value>& lst, std::vector<detail::atomic_type<bool>>& marks )
1081         : my_lst(lst), my_marks(marks)
1082     {
1083         std::fill(my_marks.begin(), my_marks.end(), false);
1084     }
1085 
1086     template <typename Range>
1087     void operator()( const Range& r ) const {
1088         do_test_range(r.begin(), r.end());
1089     }
1090 
1091     template <typename Iterator>
1092     void do_test_range( Iterator i, Iterator j ) const {
1093         for (Iterator it = i; it != j;) {
1094             Iterator prev_it = it++;
1095             auto it2 = std::search(my_lst.begin(), my_lst.end(), prev_it, it, utils::IsEqual());
1096             REQUIRE(it2 != my_lst.end());
1097             auto dist = std::distance(my_lst.begin(), it2);
1098             REQUIRE(!my_marks[dist]);
1099             my_marks[dist] = true;
1100         }
1101     }
1102 }; // class TestRange
1103 
1104 template <bool DefCtorPresent, typename Table>
1105 void CommonExamine( Table c, const std::list<typename Table::value_type>& lst ) {
1106     using value_type = typename Table::value_type;
1107 
1108     if (!(!c.empty() && c.size() == lst.size() && c.max_size() >= c.size())) {
1109         std::cout << std::boolalpha;
1110         std::cout << "Empty? " << c.empty() << std::endl;
1111         std::cout << "sizes equal? " << (c.size() == lst.size()) << std::endl;
1112         std::cout << "\t" << c.size() << std::endl;
1113         std::cout << "\t" << lst.size() << std::endl;
1114         std::cout << "Max size greater? " << (c.max_size() >= c.size()) << std::endl;
1115     }
1116     REQUIRE((!c.empty() && c.size() == lst.size() && c.max_size() >= c.size()));
1117 
1118     std::for_each(lst.begin(), lst.end(), CheckValue<DefCtorPresent, Table>(c));
1119 
1120     std::vector<detail::atomic_type<bool>> marks(lst.size());
1121 
1122     TestRange<value_type>(lst, marks).do_test_range(c.begin(), c.end());
1123     REQUIRE(std::find(marks.begin(), marks.end(), false) == marks.end());
1124 
1125     const Table constC = c;
1126     REQUIRE(c.size() == constC.size());
1127 
1128     TestRange<value_type>(lst, marks).do_test_range(c.begin(), c.end());
1129     REQUIRE(std::find(marks.begin(), marks.end(), false) == marks.end());
1130 
1131     tbb::parallel_for(c.range(), TestRange<value_type>(lst, marks));
1132     REQUIRE(std::find(marks.begin(), marks.end(), false) == marks.end());
1133 
1134     tbb::parallel_for(constC.range(), TestRange<value_type>(lst, marks));
1135     REQUIRE(std::find(marks.begin(), marks.end(), false) == marks.end());
1136 
1137     Table c2;
1138     auto begin5 = lst.begin();
1139     std::advance(begin5, 5);
1140     c2.insert(lst.begin(), begin5);
1141     std::for_each(lst.begin(), begin5, CheckValue<DefCtorPresent, Table>(c2));
1142 
1143     c2.swap(c);
1144     REQUIRE(c2.size() == lst.size());
1145     REQUIRE(c.size() == 5);
1146 
1147     std::for_each(lst.begin(), lst.end(), CheckValue<DefCtorPresent, Table>(c2));
1148 
1149     c2.clear();
1150     REQUIRE(c2.size() == 0);
1151 
1152     auto alloc = c.get_allocator();
1153     value_type* ptr = alloc.allocate(1);
1154     REQUIRE(ptr != nullptr);
1155     alloc.deallocate(ptr, 1);
1156 }
1157 
1158 template <typename ContainerTraits>
1159 void test_scoped_allocator() {
1160     using allocator_data_type = AllocatorAwareData<std::scoped_allocator_adaptor<std::allocator<int>>>;
1161     using basic_allocator_type = std::scoped_allocator_adaptor<std::allocator<allocator_data_type>>;
1162     using container_value_type = typename ContainerTraits::template container_value_type<allocator_data_type>;
1163     using allocator_type = typename std::allocator_traits<basic_allocator_type>::template rebind_alloc<container_value_type>;
1164     using container_type = typename ContainerTraits::template container_type<allocator_data_type, allocator_type>;
1165 
1166     allocator_type allocator;
1167     allocator_data_type key1(1, allocator);
1168     allocator_data_type key2(2, allocator);
1169 
1170     container_value_type value1 = Value<container_type>::make(key1);
1171     container_value_type value2 = Value<container_type>::make(key2);
1172 
1173     auto init_list = { value1, value2 };
1174 
1175     container_type c1(allocator);
1176     container_type c2(allocator);
1177 
1178     allocator_data_type::activate();
1179 
1180     emplace_helpers::call_emplace(c1, key1);
1181     emplace_helpers::call_emplace(c2, std::move(key2));
1182 
1183     c1.clear();
1184     c2.clear();
1185 
1186     c1.insert(value1);
1187     c2.insert(std::move(value2));
1188 
1189     c1.clear();
1190     c2.clear();
1191 
1192     c1.insert(init_list);
1193     c2.insert(value1);
1194 
1195     c1 = c2;
1196     c2 = std::move(c1);
1197 
1198     allocator_data_type::deactivate();
1199 }
1200 
1201 
1202 struct int_key {
1203     int my_item;
1204     int_key(int i) : my_item(i) {}
1205 };
1206 
1207 bool operator==(const int_key& ik, int i) { return ik.my_item == i; }
1208 bool operator==(int i, const int_key& ik) { return i == ik.my_item; }
1209 bool operator==(const int_key& ik1, const int_key& ik2) { return ik1.my_item == ik2.my_item; }
1210 
1211 bool operator<( const int_key& ik, int i ) { return ik.my_item < i; }
1212 bool operator<( int i, const int_key& ik ) { return i < ik.my_item; }
1213 bool operator<( const int_key& ik1, const int_key& ik2 ) { return ik1.my_item < ik2.my_item; }
1214 
1215 struct char_key {
1216     const char* my_item;
1217     char_key(const char* c) : my_item(c) {}
1218 
1219     const char& operator[] (std::size_t pos) const {
1220         return my_item[pos];
1221     }
1222 
1223     std::size_t size() const {
1224         return std::strlen(my_item);
1225     }
1226 };
1227 
1228 bool operator==(const char_key& ck, std::string c) {
1229     std::size_t i = 0;
1230     while (ck[i] != '\0' && i < c.size() && ck[i] == c[i]) { ++i;}
1231     return c.size() == i && ck[i] == '\0';
1232 }
1233 bool operator==(std::string c, const char_key& ck) {
1234     return ck == c;
1235 }
1236 bool operator==(const char_key& ck1, const char_key& ck2) {
1237     std::size_t i = 0;
1238     while (ck1[i] != '\0' && ck2[i] != '\0' && ck1[i] == ck2[i]) { ++i;}
1239     return ck1[i] == ck2[i];
1240 }
1241 
1242 bool operator<( const char_key& ck, std::string c ) {
1243     return std::lexicographical_compare(ck.my_item, ck.my_item + ck.size(), c.begin(), c.end());
1244 }
1245 
1246 bool operator<(std::string c, const char_key& ck) {
1247     return std::lexicographical_compare(c.begin(), c.end(), ck.my_item, ck.my_item + ck.size());
1248 }
1249 
1250 bool operator<( const char_key& ck1, const char_key& ck2 ) {
1251     return std::lexicographical_compare(ck1.my_item, ck1.my_item + ck1.size(), ck2.my_item, ck2.my_item + ck2.size());
1252 }
1253 
1254 struct equal_to {
1255     using is_transparent = int;
1256     template <typename T, typename W>
1257     bool operator()(const T &lhs, const W &rhs) const {
1258         return lhs == rhs;
1259     }
1260 };
1261 
1262 struct hash_with_transparent_key_equal {
1263     template <typename T>
1264     size_t operator()(const T& key) const { return hash(key); }
1265     using transparent_key_equal = equal_to;
1266     int prime = 433494437;
1267     int first_factor = 41241245;
1268     int second_factor = 2523422;
1269 
1270     size_t hash(const int& key) const { return (first_factor * key + second_factor) % prime; }
1271 
1272     size_t hash(const int_key& key) const { return (first_factor * key.my_item + second_factor) % prime; }
1273 
1274     size_t hash(const std::string& key) const {
1275         int sum = 0;
1276         for (auto it = key.begin(); it != key.end(); ++it) {
1277             sum += first_factor * (*it) + second_factor;
1278         }
1279         return sum % prime;
1280     }
1281 
1282     size_t hash(const char_key& key) const {
1283         int sum = 0;
1284         int i = 0;
1285         while (key[i] != '\0') {
1286             sum += first_factor * key[i++] + second_factor;
1287         }
1288         return sum % prime;
1289     }
1290 
1291 };
1292 
1293 template <typename Container>
1294 void check_heterogeneous_functions_key_int_impl() {
1295     static_assert(std::is_same<typename Container::key_type, int>::value,
1296                   "incorrect key_type for heterogeneous lookup test");
1297     // Initialization
1298     Container c;
1299     int size = 10;
1300     for (int i = 0; i < size; i++) {
1301         c.insert(Value<Container>::make(i));
1302     }
1303     // Insert first duplicated element for multicontainers
1304     if (AllowMultimapping<Container>::value) {
1305         c.insert(Value<Container>::make(0));
1306     }
1307 
1308     // Look up testing
1309     for (int i = 0; i < size; i++) {
1310         int_key k(i);
1311         int key = i;
1312         REQUIRE_MESSAGE(c.find(k) == c.find(key), "Incorrect heterogeneous find return value");
1313         REQUIRE_MESSAGE(c.count(k) == c.count(key), "Incorrect heterogeneous count return value");
1314     }
1315 
1316     // unsafe_extract testing
1317     for (int i = 0; i < size; i++) {
1318         Container extract_c = c;
1319         int_key int_k(i);
1320         auto int_key_extract = extract_c.unsafe_extract(int_k);
1321         if (!AllowMultimapping<Container>::value) {
1322             REQUIRE_MESSAGE(extract_c.find(int_k) == extract_c.end(), "Key exists after extract");
1323         }
1324         REQUIRE_MESSAGE(!int_key_extract.empty(), "Empty node with exists key");
1325         REQUIRE_MESSAGE(node_handling_tests::compare_handle_getters(int_key_extract, Value<Container>::make(i)), "Incorrect node");
1326     }
1327 
1328     // unsafe_extract not exists key
1329     auto not_exists = c.unsafe_extract(int_key(100));
1330     REQUIRE_MESSAGE(not_exists.empty(), "Not empty node with not exists key");
1331 
1332     // multimap unsafe_extract testing
1333     if (AllowMultimapping<Container>::value) {
1334         Container extract_m;
1335         for (int i = 0; i < size; i++) {
1336             extract_m.insert(Value<Container>::make(i));
1337             extract_m.insert(Value<Container>::make(i, i + 1));
1338         }
1339         for (int i = 0; i < size; i++) {
1340             int_key int_k(i);
1341             auto int_key_extract = extract_m.unsafe_extract(int_k);
1342             REQUIRE_MESSAGE(!int_key_extract.empty(), "Empty node with exists key");
1343             REQUIRE_MESSAGE((node_handling_tests::compare_handle_getters(int_key_extract, Value<Container>::make(i, i)) ||
1344                     node_handling_tests::compare_handle_getters(int_key_extract, Value<Container>::make(i, i + 1))), "Incorrect node");
1345             REQUIRE_MESSAGE(extract_m.find(int_k) != extract_m.end(), "All nodes for key deleted");
1346         }
1347     }
1348 
1349     // Erase testing
1350     for (int i = 0; i < size; i++) {
1351         auto count_before_erase = c.count(i);
1352         auto result = c.unsafe_erase(int_key(i));
1353         REQUIRE_MESSAGE(count_before_erase == result,"Incorrect erased elements count");
1354         REQUIRE_MESSAGE(c.count(i) == 0, "Some elements was not erased");
1355     }
1356 
1357 }
1358 
1359 template <typename Container>
1360 void check_heterogeneous_functions_key_string_impl() {
1361     static_assert(std::is_same<typename Container::key_type, std::string>::value,
1362                   "incorrect key_type for heterogeneous lookup test");
1363     // Initialization
1364     std::vector<const char*> keys{"key1", "key2", "key3", "key4",
1365         "key5", "key6", "key7", "key8", "key9", "key10"};
1366     std::vector<const char*> values{"value1", "value2", "value3", "value4",
1367         "value5", "value6", "value7", "value8", "value9", "value10", "value11"};
1368     Container c;
1369     for (auto it = keys.begin(); it != keys.end(); ++it) {
1370         c.insert(Value<Container>::make(*it));
1371     }
1372     // Insert first duplicated element for multicontainers
1373     if (AllowMultimapping<Container>::value) {
1374         c.insert(Value<Container>::make(*keys.begin()));
1375     }
1376 
1377     // Look up testing
1378     for (auto it = keys.begin(); it != keys.end(); ++it) {
1379         std::string key = *it;
1380         char_key k{*it};
1381         REQUIRE_MESSAGE(c.find(k) == c.find(key), "Incorrect heterogeneous find return value");
1382         REQUIRE_MESSAGE(c.count(k) == c.count(key), "Incorrect heterogeneous count return value");
1383     }
1384 
1385     // unsafe_extract testing
1386     for (auto it = keys.begin(); it != keys.end(); ++it) {
1387         Container extract_c = c;
1388         char_key k{*it};
1389         auto char_key_extract = extract_c.unsafe_extract(k);
1390         REQUIRE_MESSAGE(!char_key_extract.empty(), "Empty node with exists key");
1391         REQUIRE_MESSAGE(node_handling_tests::compare_handle_getters(char_key_extract, Value<Container>::make(*it)), "Incorrect node");
1392     }
1393 
1394     // unsafe_extract not exists key
1395     auto not_exists = c.unsafe_extract(char_key("not exists"));
1396     REQUIRE_MESSAGE(not_exists.empty(), "Not empty node with not exists key");
1397 
1398     // multimap unsafe_extract testing
1399     if (AllowMultimapping<Container>::value){
1400         Container extract_m;
1401         for (std::size_t i = 0; i < keys.size(); i++) {
1402             extract_m.insert(Value<Container>::make(keys[i], values[i]));
1403             extract_m.insert(Value<Container>::make(keys[i], values[i + 1]));
1404         }
1405         for (std::size_t i = 0; i < keys.size(); i++) {
1406             char_key char_k(keys[i]);
1407             auto char_key_extract = extract_m.unsafe_extract(char_k);
1408             REQUIRE_MESSAGE(!char_key_extract.empty(), "Empty node with exists key");
1409             REQUIRE_MESSAGE((node_handling_tests::compare_handle_getters(char_key_extract, Value<Container>::make(keys[i], values[i])) ||
1410                     node_handling_tests::compare_handle_getters(char_key_extract, Value<Container>::make(keys[i], values[i + 1]))), "Incorrect node");
1411             REQUIRE_MESSAGE(extract_m.find(char_k) != extract_m.end(), "All nodes for key deleted");
1412         }
1413     }
1414 
1415     // Erase testing
1416     for (auto it = keys.begin(); it != keys.end(); ++it) {
1417         std::string key = *it;
1418         char_key k{*it};
1419         auto count_before_erase = c.count(key);
1420         auto result = c.unsafe_erase(k);
1421         REQUIRE_MESSAGE(count_before_erase==result,"Incorrect erased elements count");
1422         REQUIRE_MESSAGE(c.count(key)==0, "Some elements was not erased");
1423     }
1424 }
1425 
1426 struct CountingKey {
1427     static std::size_t counter;
1428 
1429     CountingKey() { ++counter; }
1430     CountingKey( const CountingKey& ) { ++counter; }
1431     ~CountingKey() {}
1432     CountingKey& operator=( const CountingKey& ) { return *this; }
1433 
1434     static void reset() { counter = 0; }
1435 };
1436 
1437 std::size_t CountingKey::counter;
1438 
1439 namespace std {
1440 template <>
1441 struct hash<CountingKey> {
1442     std::size_t operator()( const CountingKey& ) const { return 0; }
1443 };
1444 }
1445 
1446 bool operator==( const CountingKey&, const CountingKey& ) { return true; }
1447 
1448 bool operator<( const CountingKey&, const CountingKey& ) { return true; }
1449 
1450 struct int_constructible_object {
1451     int_constructible_object(int k) : key(k) {}
1452     int key;
1453 }; // struct int_constructible_object
1454 
1455 bool operator==( const int_constructible_object& lhs, const int_constructible_object rhs ) {
1456     return lhs.key == rhs.key;
1457 }
1458 
1459 // A test for
1460 // template <typename P> insert(P&&) in maps
1461 template <template <typename...> class Container>
1462 void test_insert_by_generic_pair() {
1463     using value_type = std::pair<const int, int_constructible_object>;
1464     using generic_pair_type = std::pair<int, int>;
1465 
1466     static_assert(std::is_constructible<value_type, generic_pair_type>::value,
1467                   "Incorrect test setup");
1468 
1469     Container<int, int_constructible_object> cont1, cont2;
1470     using iterator = typename Container<int, int_constructible_object>::iterator;
1471 
1472     for (int i = 0; i != 10; ++i) {
1473         std::pair<iterator, bool> res_generic_insert = cont1.insert(generic_pair_type(1, i));
1474         std::pair<iterator, bool> res_value_insert = cont2.insert(value_type(1, int_constructible_object(i)));
1475 
1476         REQUIRE_MESSAGE(*res_generic_insert.first == *res_value_insert.first, "Insert by generic pair returned wrong iterator");
1477         REQUIRE_MESSAGE(res_generic_insert.second == res_value_insert.second, "Insert by generic pair returned wrong insertion value");
1478     }
1479 
1480     for (int i = 0; i != 10; ++i) {
1481         iterator res_generic_insert_hint = cont1.insert(cont1.cbegin(), generic_pair_type(2, i));
1482         iterator res_value_insert_hint = cont2.insert(cont2.cbegin(), value_type(2, int_constructible_object(i)));
1483 
1484         REQUIRE_MESSAGE(*res_generic_insert_hint == *res_value_insert_hint, "Hinted insert by generic pair returned wrong iterator");
1485     }
1486 
1487     Container<CountingKey, int_constructible_object> counting_cont;
1488     using counting_generic_pair = std::pair<CountingKey, int>;
1489 
1490     static_assert(std::is_constructible<typename decltype(counting_cont)::value_type, counting_generic_pair>::value,
1491                   "Incorrect test setup");
1492 
1493     counting_generic_pair counting_pair(CountingKey{}, 1);
1494     CountingKey::reset();
1495 
1496     counting_cont.insert(counting_pair);
1497     REQUIRE_MESSAGE(CountingKey::counter == 1, "Only one element should be constructed in-place during the generic pair insertion");
1498 
1499     CountingKey::reset();
1500 }
1501 
1502 template <typename Container>
1503 void test_swap_not_always_equal_allocator() {
1504     static_assert(std::is_same<typename Container::allocator_type, NotAlwaysEqualAllocator<typename Container::value_type>>::value,
1505                   "Incorrect allocator in not always equal test");
1506     Container c1{};
1507     Container c2{Value<Container>::make(1), Value<Container>::make(2)};
1508 
1509     Container c1_copy = c1;
1510     Container c2_copy = c2;
1511 
1512     c1.swap(c2);
1513 
1514     REQUIRE_MESSAGE(c1 == c2_copy, "Incorrect swap with not always equal allocator");
1515     REQUIRE_MESSAGE(c2 == c1_copy, "Incorrect swap with not always equal allocator");
1516 }
1517 
1518 #if TBB_USE_EXCEPTIONS
1519 template <typename Container>
1520 void test_exception_on_copy_ctor() {
1521     Container c1;
1522     c1.emplace(Value<Container>::make(ThrowOnCopy{}));
1523 
1524     using container_allocator_type = std::allocator<Container>;
1525     using alloc_traits = std::allocator_traits<container_allocator_type>;
1526     container_allocator_type container_allocator;
1527     Container* c2_ptr = alloc_traits::allocate(container_allocator, 1);
1528 
1529     ThrowOnCopy::activate();
1530     // Test copy ctor
1531     try {
1532         alloc_traits::construct(container_allocator, c2_ptr, c1);
1533     } catch ( int error_code ) {
1534         REQUIRE_MESSAGE(error_code == ThrowOnCopy::error_code(), "Incorrect code was thrown");
1535     }
1536 
1537     REQUIRE_MESSAGE(c2_ptr->empty(), "Incorrect container state after throwing copy constructor");
1538 
1539     alloc_traits::deallocate(container_allocator, c2_ptr, 1);
1540     c2_ptr = alloc_traits::allocate(container_allocator, 1);
1541 
1542     // Test copy ctor with allocator
1543     try {
1544         auto value_allocator = c1.get_allocator();
1545         alloc_traits::construct(container_allocator, c2_ptr, c1, value_allocator);
1546     } catch( int error_code ) {
1547         REQUIRE_MESSAGE(error_code == ThrowOnCopy::error_code(), "Incorrect code was thrown");
1548     }
1549 
1550     REQUIRE_MESSAGE(c2_ptr->empty(), "Incorrect container state after throwing copy ctor with allocator");
1551     alloc_traits::deallocate(container_allocator, c2_ptr, 1);
1552     ThrowOnCopy::deactivate();
1553 }
1554 #endif // TBB_USE_EXCEPTIONS
1555 
1556 #endif // __TBB_test_common_concurrent_associative_common_H
1557