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