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 #if __INTEL_COMPILER && _MSC_VER
18 #pragma warning(disable : 2586) // decorated name length exceeded, name was truncated
19 #endif
20 
21 
22 #include "oneapi/tbb/concurrent_unordered_set.h"
23 #include <common/test.h>
24 #include <common/utils.h>
25 #include <common/concurrent_unordered_common.h>
26 #include <memory>
27 #include <type_traits>
28 
29 //! \file conformance_concurrent_unordered_set.cpp
30 //! \brief Test for [containers.concurrent_unordered_set containers.concurrent_unordered_multiset] specifications
31 
32 template <typename... Args>
33 struct AllowMultimapping<oneapi::tbb::concurrent_unordered_multiset<Args...>> : std::true_type {};
34 
35 template <typename Key>
36 using Allocator = LocalCountingAllocator<std::allocator<Key>>;
37 
38 using set_type = oneapi::tbb::concurrent_unordered_set<int, std::hash<int>, std::equal_to<int>, Allocator<int>>;
39 using multiset_type = oneapi::tbb::concurrent_unordered_multiset<int, std::hash<int>, std::equal_to<int>, Allocator<int>>;
40 
41 template <template <typename...> class ContainerType>
test_member_types()42 void test_member_types() {
43     using default_container_type = ContainerType<int>;
44     static_assert(std::is_same<typename default_container_type::hasher, std::hash<int>>::value,
45                   "Incorrect default template hasher");
46     static_assert(std::is_same<typename default_container_type::key_equal, std::equal_to<int>>::value,
47                   "Incorrect default template key equality");
48     static_assert(std::is_same<typename default_container_type::allocator_type, oneapi::tbb::tbb_allocator<int>>::value,
49                   "Incorrect default template allocator");
50 
51     auto test_hasher = [](const int&)->std::size_t { return 0; };
52     auto test_equality = [](const int&, const int&)->bool { return true; };
53     using test_allocator_type = std::allocator<int>;
54 
55     using container_type = ContainerType<int, decltype(test_hasher), decltype(test_equality), test_allocator_type>;
56 
57     static_assert(std::is_same<typename container_type::key_type, int>::value,
58                   "Incorrect container key_type member type");
59     static_assert(std::is_same<typename container_type::value_type, int>::value,
60                   "Incorrect container value_type member type");
61 
62     static_assert(std::is_unsigned<typename container_type::size_type>::value,
63                   "Incorrect container size_type member type");
64     static_assert(std::is_signed<typename container_type::difference_type>::value,
65                   "Incorrect container difference_type member type");
66 
67     static_assert(std::is_same<typename container_type::hasher, decltype(test_hasher)>::value,
68                   "Incorrect container hasher member type");
69     static_assert(std::is_same<typename container_type::key_equal, decltype(test_equality)>::value,
70                   "Incorrect container key_equal member type");
71 
72     using transparent_container_type = ContainerType<int, hasher_with_transparent_key_equal,
73                                                      std::equal_to<int>, test_allocator_type>;
74 
75     static_assert(std::is_same<typename transparent_container_type::key_equal, transparent_key_equality>::value,
76                   "Incorrect container key_equal member type");
77     static_assert(std::is_same<typename container_type::allocator_type, test_allocator_type>::value,
78                   "Incorrect container allocator_type member type");
79 
80     using value_type = typename container_type::value_type;
81     static_assert(std::is_same<typename container_type::reference, value_type&>::value,
82                   "Incorrect container reference member type");
83     static_assert(std::is_same<typename container_type::const_reference, const value_type&>::value,
84                   "Incorrect container const_reference member type");
85     using allocator_type = typename container_type::allocator_type;
86     static_assert(std::is_same<typename container_type::pointer, typename std::allocator_traits<allocator_type>::pointer>::value,
87                   "Incorrect container pointer member type");
88     static_assert(std::is_same<typename container_type::const_pointer, typename std::allocator_traits<allocator_type>::const_pointer>::value,
89                   "Incorrect container const_pointer member type");
90 
91     static_assert(utils::is_forward_iterator<typename container_type::iterator>::value,
92                   "Incorrect container iterator member type");
93     static_assert(!std::is_const<typename container_type::iterator::value_type>::value,
94                   "Incorrect container iterator member type");
95     static_assert(utils::is_forward_iterator<typename container_type::const_iterator>::value,
96                   "Incorrect container const_iterator member type");
97     static_assert(std::is_const<typename container_type::const_iterator::value_type>::value,
98                   "Incorrect container iterator member type");
99     static_assert(utils::is_forward_iterator<typename container_type::local_iterator>::value,
100                   "Incorrect container local_iterator member type");
101     static_assert(!std::is_const<typename container_type::local_iterator::value_type>::value,
102                   "Incorrect container local_iterator member type");
103     static_assert(utils::is_forward_iterator<typename container_type::const_local_iterator>::value,
104                   "Incorrect container const_local_iterator member type");
105     static_assert(std::is_const<typename container_type::const_local_iterator::value_type>::value,
106                   "Incorrect container const_local_iterator member type");
107 }
108 
109 struct CusetTraits : UnorderedMoveTraitsBase {
110     template <typename T, typename Allocator>
111     using container_type = oneapi::tbb::concurrent_unordered_set<T, std::hash<T>, std::equal_to<T>, Allocator>;
112 
113     template <typename T>
114     using container_value_type = T;
115 
116     using init_iterator_type = move_support_tests::FooIterator;
117 }; // struct CusetTraits
118 
119 struct CumultisetTraits : UnorderedMoveTraitsBase {
120     template <typename T, typename Allocator>
121     using container_type = oneapi::tbb::concurrent_unordered_multiset<T, std::hash<T>, std::equal_to<T>, Allocator>;
122 
123     template <typename T>
124     using container_value_type = T;
125 
126     using init_iterator_type = move_support_tests::FooIterator;
127 }; // struct CumultisetTraits
128 
129 #if __TBB_CPP17_DEDUCTION_GUIDES_PRESENT
130 template <template <typename ...> typename TSet>
test_deduction_guides()131 void test_deduction_guides() {
132     using ComplexType = const std::string *;
133     std::vector<ComplexType> v;
134     std::string s = "s";
135     auto l = { ComplexType(&s), ComplexType(&s)};
136     using custom_allocator_type = std::allocator<ComplexType>;
137 
138     // check TSet(InputIterator,InputIterator)
139     TSet s1(v.begin(), v.end());
140     static_assert(std::is_same<decltype(s1), TSet<ComplexType>>::value);
141 
142     // check TSet(InputIterator,InputIterator, size_t, Hasher)
143     TSet s2(v.begin(), v.end(), 5, degenerate_hash<ComplexType>());
144     static_assert(std::is_same<decltype(s2), TSet<ComplexType, degenerate_hash<ComplexType>>>::value);
145 
146     // check TSet(InputIterator,InputIterator, size_t, Hasher, Equality)
147     TSet s3(v.begin(), v.end(), 5, degenerate_hash<ComplexType>(), std::less<ComplexType>());
148     static_assert(std::is_same<decltype(s3), TSet<ComplexType, degenerate_hash<ComplexType>,
149         std::less<ComplexType>>>::value);
150 
151     // check TSet(InputIterator,InputIterator, size_t, Hasher, Equality, Allocator)
152     TSet s4(v.begin(), v.end(), 5, degenerate_hash<ComplexType>(), std::less<ComplexType>(),
153             custom_allocator_type{});
154     static_assert(std::is_same<decltype(s4), TSet<ComplexType, degenerate_hash<ComplexType>,
155         std::less<ComplexType>, custom_allocator_type>>::value);
156 
157     // check TSet(InputIterator,InputIterator, size_t, Allocator)
158     TSet s5(v.begin(), v.end(), 5, custom_allocator_type{});
159     static_assert(std::is_same<decltype(s5), TSet<ComplexType, std::hash<ComplexType>,
160         std::equal_to<ComplexType>, custom_allocator_type>>::value);
161 
162     // check TSet(InputIterator,InputIterator, size_t, Hasher, Allocator)
163     TSet s6(v.begin(), v.end(), 5, degenerate_hash<ComplexType>(), custom_allocator_type{});
164     static_assert(std::is_same<decltype(s6), TSet<ComplexType, degenerate_hash<ComplexType>,
165         std::equal_to<ComplexType>, custom_allocator_type>>::value);
166 
167     // check TSet(std::initializer_list)
168     TSet s7(l);
169     static_assert(std::is_same<decltype(s7), TSet<ComplexType>>::value);
170 
171     // check TSet(std::initializer_list, size_t, Hasher)
172     TSet s8(l, 5, degenerate_hash<ComplexType>());
173     static_assert(std::is_same<decltype(s8), TSet<ComplexType, degenerate_hash<ComplexType>>>::value);
174 
175     // check TSet(std::initializer_list, size_t, Hasher, Equality)
176     TSet s9(l, 5, degenerate_hash<ComplexType>(), std::less<ComplexType>());
177     static_assert(std::is_same<decltype(s9), TSet<ComplexType, degenerate_hash<ComplexType>,
178         std::less<ComplexType>>>::value);
179 
180     // check TSet(std::initializer_list, size_t, Hasher, Equality, Allocator)
181     TSet s10(l, 5, degenerate_hash<ComplexType>(), std::less<ComplexType>(), custom_allocator_type{});
182     static_assert(std::is_same<decltype(s10), TSet<ComplexType, degenerate_hash<ComplexType>,
183         std::less<ComplexType>, custom_allocator_type>>::value);
184 
185     // check TSet(std::initializer_list, size_t, Allocator)
186     TSet s11(l, 5, custom_allocator_type{});
187     static_assert(std::is_same<decltype(s11), TSet<ComplexType, std::hash<ComplexType>,
188         std::equal_to<ComplexType>, custom_allocator_type>>::value);
189 
190     // check TSet(std::initializer_list, size_t, Hasher, Allocator)
191     TSet s12(l, 5, std::hash<ComplexType>(), custom_allocator_type{});
192     static_assert(std::is_same<decltype(s12), TSet<ComplexType, std::hash<ComplexType>,
193         std::equal_to<ComplexType>, custom_allocator_type>>::value);
194 
195     // check TSet(TSet &)
196     TSet s13(s1);
197     static_assert(std::is_same<decltype(s13), decltype(s1)>::value);
198 
199     // check TSet(TSet &, Allocator)
200     TSet s14(s5, custom_allocator_type{});
201     // TODO: investigate why no implicit deduction guides generated for this ctor
202     static_assert(std::is_same<decltype(s14), decltype(s5)>::value);
203 
204     // check TSet(TSet &&)
205     TSet s15(std::move(s1));
206     static_assert(std::is_same<decltype(s15), decltype(s1)>::value);
207 
208     // check TSet(TSet &&, Allocator)
209     TSet s16(std::move(s5), custom_allocator_type{});
210     // TODO: investigate why no implicit deduction guides generated for this ctor
211     static_assert(std::is_same<decltype(s16), decltype(s5)>::value);
212 }
213 #endif // __TBB_CPP17_DEDUCTION_GUIDES_PRESENT
214 
215 //! Testing concurrent_unordered_set member types
216 //! \brief \ref interface \ref requirement
217 TEST_CASE("concurrent_unordered_set member types") {
218     test_member_types<oneapi::tbb::concurrent_unordered_set>();
219 }
220 
221 //! Testing requirements of concurrent_unordered_set
222 //! \brief \ref interface \ref requirement
223 TEST_CASE("concurrent_unordered_set requirements") {
224     test_basic<set_type>();
225 }
226 
227 //! Testing multithreading support in concurrent_unordered_set
228 //! \brief \ref requirement
229 TEST_CASE("concurrent_unordered_set multithreading support") {
230     test_concurrent<set_type>();
231 }
232 
233 //! Testing move constructors and assignment operator in concurrent_unordered_set
234 //! \brief \ref interface \ref requirement
235 TEST_CASE("concurrent_unordered_set move semantics support") {
236     test_rvalue_ref_support<CusetTraits>();
237 }
238 
239 //! Testing std::initializer_list constructors and modifiers in concurrent_unordered_set
240 //! \brief \ref interface \ref requirement
241 TEST_CASE("std::initializer_list support in concurrent_unordered_set") {
242     test_initializer_list_support<set_type>({1, 2, 3, 4, 5});
243 }
244 
245 //! Testing node handling in concurrent_unordered_set
246 //! \brief \ref interface \ref requirement
247 TEST_CASE("node handling support in concurrent_unordered_set") {
248     node_handling_tests::test_node_handling_support<set_type>();
249 }
250 
251 //! Testing std::allocator_traits support in concurrent_unordered_set
252 //! \brief \ref interface \ref requirement
253 TEST_CASE("std::allocator_traits support in concurrent_unordered_set") {
254     test_allocator_traits_support<CusetTraits>();
255 }
256 
257 //! Testing heterogeneous overloads in concurrent_unordered_set
258 //! \brief \ref interface \ref requirement
259 TEST_CASE("heterogeneous overloads in concurrent_unordered_set") {
260     check_heterogeneous_functions_key_int<oneapi::tbb::concurrent_unordered_set, int>();
261     check_heterogeneous_functions_key_string<oneapi::tbb::concurrent_unordered_set, std::string>();
262 }
263 
264 #if __TBB_CPP17_DEDUCTION_GUIDES_PRESENT
265 //! Testing Class Template Argument Deduction in concurrent_unordered_set
266 //! \brief \ref interface \ref requirement
267 TEST_CASE("CTAD support in concurrent_unordered_set") {
268     test_deduction_guides<oneapi::tbb::concurrent_unordered_set>();
269 }
270 #endif
271 
272 //! Testing comparisons in concurrent_unordered_set
273 //! \brief \ref interface \ref requirement
274 TEST_CASE("concurrent_unordered_set comparisons") {
275     test_set_comparisons<oneapi::tbb::concurrent_unordered_set>();
276 }
277 
278 //! Testing concurrent_unordered_multiset member types
279 //! \brief \ref interface \ref requirement
280 TEST_CASE("concurrent_unordered_multiset member types") {
281     test_member_types<oneapi::tbb::concurrent_unordered_multiset>();
282 }
283 
284 //! Testing requirements of concurrent_unordered_multiset
285 //! \brief \ref interface \ref requirement
286 TEST_CASE("concurrent_unordered_multiset requirements") {
287     test_basic<multiset_type>();
288 }
289 
290 //! Testing move constructors and assignment operator in concurrent_unordered_multiset
291 //! \brief \ref requirement
292 TEST_CASE("concurrent_unordered_multiset multithreading support") {
293     test_concurrent<multiset_type>();
294 }
295 
296 //! Testing move constructors and assignment operator in concurrent_unordered_multiset
297 //! \brief \ref interface \ref requirement
298 TEST_CASE("concurrent_unordered_multiset move semantics support") {
299     test_rvalue_ref_support<CumultisetTraits>();
300 }
301 
302 //! Testing std::initializer_list constructors and modifiers in concurrent_unordered_multiset
303 //! \brief \ref interface \ref requirement
304 TEST_CASE("std::initializer_list support in concurrent_unordered_multiset") {
305     test_initializer_list_support<multiset_type>({1, 2, 3, 4, 5, 5});
306 }
307 
308 //! Testing node handling support in concurrent_unordered_multiset
309 //! \brief \ref interface \ref requirement
310 TEST_CASE("node handling support in concurrent_unordered_multiset") {
311     node_handling_tests::test_node_handling_support<multiset_type>();
312 }
313 
314 //! Testing std::allocator_traits support in concurrent_unordered_multiset
315 //! \brief \ref interface \ref requirement
316 TEST_CASE("std::allocator_traits support in concurrent_unordered_multiset") {
317     test_allocator_traits_support<CumultisetTraits>();
318 }
319 
320 //! Testing heterogeneous overloads in concurrent_unordered_multiset
321 //! \brief \ref interface \ref requirement
322 TEST_CASE("heterogeneous overloads in concurrent_unordered_multiset") {
323     check_heterogeneous_functions_key_int<oneapi::tbb::concurrent_unordered_multiset, int>();
324     check_heterogeneous_functions_key_string<oneapi::tbb::concurrent_unordered_multiset, std::string>();
325 }
326 
327 #if __TBB_CPP17_DEDUCTION_GUIDES_PRESENT
328 //! Testing Class Template Argument Deduction in concurrent_unordered_multiset
329 //! \brief \ref interface \ref requirement
330 TEST_CASE("CTAD support in concurrent_unordered_multiset") {
331     test_deduction_guides<oneapi::tbb::concurrent_unordered_multiset>();
332 }
333 #endif
334 
335 //! Testing comparisons in concurrent_unordered_multiset
336 //! \brief \ref interface \ref requirement
337 TEST_CASE("concurrent_unordered_multiset comparisons") {
338     test_set_comparisons<oneapi::tbb::concurrent_unordered_multiset>();
339 }
340 
341 //! Testing of merge operation in concurrent_unordered_set and concurrent_unordered_multiset
342 //! \brief \ref interface \ref requirement
343 TEST_CASE("merge operations") {
344     node_handling_tests::test_merge<set_type, multiset_type>(1000);
345 }
346