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