1 /*
2     Copyright (c) 2005-2020 Intel Corporation
3 
4     Licensed under the Apache License, Version 2.0 (the "License");
5     you may not use this file except in compliance with the License.
6     You may obtain a copy of the License at
7 
8         http://www.apache.org/licenses/LICENSE-2.0
9 
10     Unless required by applicable law or agreed to in writing, software
11     distributed under the License is distributed on an "AS IS" BASIS,
12     WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
13     See the License for the specific language governing permissions and
14     limitations under the License.
15 */
16 
17 #define TBB_DEFINE_STD_HASH_SPECIALIZATIONS 1
18 #include <tbb/concurrent_unordered_set.h>
19 #include "common/concurrent_unordered_common.h"
20 
21 //! \file test_concurrent_unordered_set.cpp
22 //! \brief Test for [containers.concurrent_unordered_set containers.concurrent_unordered_multiset] specifications
23 
24 template <typename... Args>
25 struct AllowMultimapping<tbb::concurrent_unordered_multiset<Args...>> : std::true_type {};
26 
27 template <typename Value>
28 using MyAllocator = LocalCountingAllocator<std::allocator<Value>>;
29 
30 using move_support_tests::FooWithAssign;
31 
32 using set_type = tbb::concurrent_unordered_set<int, std::hash<int>, std::equal_to<int>, MyAllocator<int>>;
33 using multiset_type = tbb::concurrent_unordered_multiset<int, std::hash<int>, std::equal_to<int>, MyAllocator<int>>;
34 using degenerate_set_type = tbb::concurrent_unordered_set<int, degenerate_hash<int>, std::equal_to<int>, MyAllocator<int>>;
35 using degenerate_multiset_type = tbb::concurrent_unordered_multiset<int, degenerate_hash<int>, std::equal_to<int>, MyAllocator<int>>;
36 
37 using checked_set_type = tbb::concurrent_unordered_set<CheckType<int>, std::hash<CheckType<int>>, std::equal_to<CheckType<int>>, MyAllocator<CheckType<int>>>;
38 using checked_multiset_type = tbb::concurrent_unordered_multiset<CheckType<int>, std::hash<CheckType<int>>,
39                                                                  std::equal_to<CheckType<int>>, MyAllocator<CheckType<int>>>;
40 using checked_state_set_type = tbb::concurrent_unordered_set<FooWithAssign, std::hash<FooWithAssign>, std::equal_to<FooWithAssign>,
41                                                              MyAllocator<FooWithAssign>>;
42 using checked_state_multiset_type = tbb::concurrent_unordered_multiset<FooWithAssign, std::hash<FooWithAssign>, std::equal_to<FooWithAssign>,
43                                                                        MyAllocator<FooWithAssign>>;
44 
45 struct CusetTraits : UnorderedMoveTraitsBase {
46     template <typename T, typename Allocator>
47     using container_type = tbb::concurrent_unordered_set<T, std::hash<T>, std::equal_to<T>, Allocator>;
48 
49     template <typename T>
50     using container_value_type = T;
51 
52     using init_iterator_type = move_support_tests::FooIterator;
53 }; // struct CusetTraits
54 
55 struct CumultisetTraits : UnorderedMoveTraitsBase {
56     template <typename T, typename Allocator>
57     using container_type = tbb::concurrent_unordered_multiset<T, std::hash<T>, std::equal_to<T>, Allocator>;
58 
59     template <typename T>
60     using container_value_type = T;
61 
62     using init_iterator_type = move_support_tests::FooIterator;
63 }; // struct CumultisetTraits
64 
65 struct UnorderedSetTypesTester {
66     template <bool DefCtorPresent, typename ValueType>
67     void check( const std::list<ValueType>& lst ) {
68         TypeTester<DefCtorPresent, tbb::concurrent_unordered_set<ValueType, std::hash<ValueType>, utils::IsEqual>>(lst);
69         TypeTester<DefCtorPresent, tbb::concurrent_unordered_multiset<ValueType, std::hash<ValueType>, utils::IsEqual>>(lst);
70     }
71 };
72 
73 void test_specific_types() {
74     test_set_specific_types<UnorderedSetTypesTester>();
75 
76     // Regressiong test for a problem with excessive requirements of emplace()
77     test_emplace_insert<tbb::concurrent_unordered_set<test::unique_ptr<int>>,
78                         std::false_type>(new int, new int);
79     test_emplace_insert<tbb::concurrent_unordered_multiset<test::unique_ptr<int>>,
80                         std::false_type>(new int, new int);
81 }
82 
83 //! \brief \ref stress \ref error_guessing
84 TEST_CASE("basic test for concurrent_unordered_set with degenerate hash") {
85     test_basic<degenerate_set_type>();
86 }
87 
88 //! \brief \ref stress \ref error_guessing
89 TEST_CASE("basic test for concurrent_unordered_multiset with degenerate hash") {
90     test_basic<degenerate_multiset_type>();
91 }
92 
93 //! \brief \ref resource_usage
94 TEST_CASE("basic test for concurrent_unordered_set with elements ctor and dtor check") {
95     Checker<checked_set_type::value_type> checker;
96     test_basic<checked_set_type>();
97 }
98 
99 //! \brief \ref resource_usage
100 TEST_CASE("basic test for concurrent_unordered_multiset with elements ctor and dtor check") {
101     Checker<checked_multiset_type::value_type> checker;
102     test_basic<checked_multiset_type>();
103 }
104 
105 //! \brief \ref resource_usage
106 TEST_CASE("basic test for concurrent_unordered_set with elements state check") {
107     test_basic<checked_state_set_type, /*CheckState = */std::true_type>();
108 }
109 
110 //! \brief \ref resource_usage
111 TEST_CASE("basic test for concurrent_unordered_multiset with elements state check") {
112     test_basic<checked_state_multiset_type, /*CheckState = */std::true_type>();
113 }
114 
115 //! \brief \ref stress \ref error_guessing
116 TEST_CASE("multithreading support in concurrent_unordered_set with degenerate hash") {
117     test_concurrent<degenerate_set_type>();
118 }
119 
120 //! \brief \ref stress \ref error_guessing
121 TEST_CASE("multithreading support in concurrent_unordered_multiset with degenerate hash") {
122     test_concurrent<degenerate_multiset_type>();
123 }
124 
125 //! \brief \ref stress \ref error_guessing
126 TEST_CASE("multithreading support in concurrent_unordered_multiset with no unique keys") {
127     test_concurrent<multiset_type>(true);
128 }
129 
130 //! \brief \ref stress \ref error_guessing
131 TEST_CASE("multithreading support in concurrent_unordered_multiset with degenerate hash and no unique keys") {
132     test_concurrent<degenerate_multiset_type>(true);
133 }
134 
135 //! \brief \ref resource_usage
136 TEST_CASE("multithreading support in concurrent_unordered_set with elements ctor and dtor check") {
137     Checker<checked_set_type::value_type> checker;
138     test_concurrent<checked_set_type>();
139 }
140 
141 //! \brief \ref resource_usage
142 TEST_CASE("multithreading support in concurrent_unordered_multiset with elements ctor and dtor check") {
143     Checker<checked_multiset_type::value_type> checker;
144     test_concurrent<checked_multiset_type>();
145 }
146 
147 //! \brief \ref resource_usage
148 TEST_CASE("multithreading support in concurrent_unordered_set with elements state check") {
149     test_concurrent<checked_state_set_type>();
150 }
151 
152 //! \brief \ref resource_usage
153 TEST_CASE("multithreading support in concurrent_unordered_multiset with elements state check") {
154     test_concurrent<checked_state_multiset_type>();
155 }
156 
157 //! \brief \ref interface \ref error_guessing
158 TEST_CASE("range based for support in concurrent_unordered_set") {
159     test_range_based_for_support<set_type>();
160 }
161 
162 //! \brief \ref interface \ref error_guessing
163 TEST_CASE("range based for support in concurrent_unordered_multiset") {
164     test_range_based_for_support<multiset_type>();
165 }
166 
167 //! \brief \ref stress \ref error_guessing
168 TEST_CASE("merge and concurrent merge in concurrent_unordered_set and set with degenerate hash") {
169     node_handling_tests::test_merge<set_type, degenerate_set_type>(1000);
170 }
171 
172 //! \brief \ref regression
173 TEST_CASE("concurrent_unordered_set/multiset with specific key types") {
174     test_specific_types();
175 }
176 
177 //! \brief \ref error_guessing
178 TEST_CASE("concurrent_unordered_set with std::scoped_allocator_adaptor") {
179     test_scoped_allocator<CusetTraits>();
180 }
181 
182 //! \brief \ref error_guessing
183 TEST_CASE("concurrent_unordered_multiset with std::scoped_allocator_adaptor") {
184     test_scoped_allocator<CumultisetTraits>();
185 }
186 
187 //! \brief \ref error_guessing
188 TEST_CASE("concurrent_unordered_set::swap with not always equal allocator") {
189     using not_always_equal_alloc_set_type = tbb::concurrent_unordered_set<int, std::hash<int>, std::equal_to<int>,
190                                                                           NotAlwaysEqualAllocator<int>>;
191     test_swap_not_always_equal_allocator<not_always_equal_alloc_set_type>();
192 }
193 
194 //! \brief \ref error_guessing
195 TEST_CASE("concurrent_unordered_multiset::swap with not always equal allocator") {
196     using not_always_equal_alloc_mset_type = tbb::concurrent_unordered_multiset<int, std::hash<int>, std::equal_to<int>,
197                                                                                 NotAlwaysEqualAllocator<int>>;
198     test_swap_not_always_equal_allocator<not_always_equal_alloc_mset_type>();
199 }
200 
201 #if __TBB_USE_EXCEPTIONS
202 //! \brief \ref error_guessing
203 TEST_CASE("concurrent_unordered_set throwing copy constructor") {
204     using exception_set_type = tbb::concurrent_unordered_set<ThrowOnCopy>;
205     test_exception_on_copy_ctor<exception_set_type>();
206 }
207 
208 //! \brief \ref error_guessing
209 TEST_CASE("concurrent_unordered_multimap throwing copy constructor") {
210     using exception_mset_type = tbb::concurrent_unordered_multiset<ThrowOnCopy>;
211     test_exception_on_copy_ctor<exception_mset_type>();
212 }
213 #endif // __TBB_USE_EXCEPTIONS
214