1 /*
2 Copyright (c) 2005-2022 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_concurrent_unordered_set_H
18 #define __TBB_concurrent_unordered_set_H
19
20 #include "detail/_namespace_injection.h"
21 #include "detail/_concurrent_unordered_base.h"
22 #include "tbb_allocator.h"
23
24 namespace tbb {
25 namespace detail {
26 namespace d1 {
27
28 template <typename Key, typename Hash, typename KeyEqual, typename Allocator, bool AllowMultimapping>
29 struct concurrent_unordered_set_traits {
30 using key_type = Key;
31 using value_type = key_type;
32 using allocator_type = Allocator;
33 using hash_compare_type = hash_compare<key_type, Hash, KeyEqual>;
34 static constexpr bool allow_multimapping = AllowMultimapping;
35
get_keyconcurrent_unordered_set_traits36 static constexpr const key_type& get_key( const value_type& value ) {
37 return value;
38 }
39 }; // class concurrent_unordered_set_traits
40
41 template <typename Key, typename Hash, typename KeyEqual, typename Allocator>
42 class concurrent_unordered_multiset;
43
44 template <typename Key, typename Hash = std::hash<Key>, typename KeyEqual = std::equal_to<Key>,
45 typename Allocator = tbb::tbb_allocator<Key>>
46 class concurrent_unordered_set
47 : public concurrent_unordered_base<concurrent_unordered_set_traits<Key, Hash, KeyEqual, Allocator, false>>
48 {
49 using traits_type = concurrent_unordered_set_traits<Key, Hash, KeyEqual, Allocator, false>;
50 using base_type = concurrent_unordered_base<traits_type>;
51 public:
52 using key_type = typename base_type::key_type;
53 using value_type = typename base_type::value_type;
54 using size_type = typename base_type::size_type;
55 using difference_type = typename base_type::difference_type;
56 using hasher = typename base_type::hasher;
57 using key_equal = typename base_type::key_equal;
58 using allocator_type = typename base_type::allocator_type;
59 using reference = typename base_type::reference;
60 using const_reference = typename base_type::const_reference;
61 using pointer = typename base_type::pointer;
62 using const_pointer = typename base_type::const_pointer;
63 using iterator = typename base_type::iterator;
64 using const_iterator = typename base_type::const_iterator;
65 using local_iterator = typename base_type::local_iterator;
66 using const_local_iterator = typename base_type::const_local_iterator;
67 using node_type = typename base_type::node_type;
68
69 // Include constructors of base_type;
70 using base_type::base_type;
71
72 // Required for implicit deduction guides
73 concurrent_unordered_set() = default;
74 concurrent_unordered_set( const concurrent_unordered_set& ) = default;
concurrent_unordered_set(const concurrent_unordered_set & other,const allocator_type & alloc)75 concurrent_unordered_set( const concurrent_unordered_set& other, const allocator_type& alloc ) : base_type(other, alloc) {}
76 concurrent_unordered_set( concurrent_unordered_set&& ) = default;
concurrent_unordered_set(concurrent_unordered_set && other,const allocator_type & alloc)77 concurrent_unordered_set( concurrent_unordered_set&& other, const allocator_type& alloc ) : base_type(std::move(other), alloc) {}
78 // Required to respect the rule of 5
79 concurrent_unordered_set& operator=( const concurrent_unordered_set& ) = default;
80 concurrent_unordered_set& operator=( concurrent_unordered_set&& ) = default;
81
82 concurrent_unordered_set& operator=( std::initializer_list<value_type> il ) {
83 base_type::operator= (il);
84 return *this;
85 }
86
87 template <typename OtherHash, typename OtherKeyEqual>
merge(concurrent_unordered_set<key_type,OtherHash,OtherKeyEqual,allocator_type> & source)88 void merge( concurrent_unordered_set<key_type, OtherHash, OtherKeyEqual, allocator_type>& source ) {
89 this->internal_merge(source);
90 }
91
92 template <typename OtherHash, typename OtherKeyEqual>
merge(concurrent_unordered_set<key_type,OtherHash,OtherKeyEqual,allocator_type> && source)93 void merge( concurrent_unordered_set<key_type, OtherHash, OtherKeyEqual, allocator_type>&& source ) {
94 this->internal_merge(std::move(source));
95 }
96
97 template <typename OtherHash, typename OtherKeyEqual>
merge(concurrent_unordered_multiset<key_type,OtherHash,OtherKeyEqual,allocator_type> & source)98 void merge( concurrent_unordered_multiset<key_type, OtherHash, OtherKeyEqual, allocator_type>& source ) {
99 this->internal_merge(source);
100 }
101
102 template <typename OtherHash, typename OtherKeyEqual>
merge(concurrent_unordered_multiset<key_type,OtherHash,OtherKeyEqual,allocator_type> && source)103 void merge( concurrent_unordered_multiset<key_type, OtherHash, OtherKeyEqual, allocator_type>&& source ) {
104 this->internal_merge(std::move(source));
105 }
106 }; // class concurrent_unordered_set
107
108 #if __TBB_CPP17_DEDUCTION_GUIDES_PRESENT
109
110 template <typename It,
111 typename Hash = std::hash<iterator_value_t<It>>,
112 typename KeyEq = std::equal_to<iterator_value_t<It>>,
113 typename Alloc = tbb::tbb_allocator<iterator_value_t<It>>,
114 typename = std::enable_if_t<is_input_iterator_v<It>>,
115 typename = std::enable_if_t<is_allocator_v<Alloc>>,
116 typename = std::enable_if_t<!is_allocator_v<Hash>>,
117 typename = std::enable_if_t<!is_allocator_v<KeyEq>>,
118 typename = std::enable_if_t<!std::is_integral_v<Hash>>>
119 concurrent_unordered_set( It, It, std::size_t = {}, Hash = Hash(), KeyEq = KeyEq(), Alloc = Alloc() )
120 -> concurrent_unordered_set<iterator_value_t<It>, Hash, KeyEq, Alloc>;
121
122 template <typename T,
123 typename Hash = std::hash<T>,
124 typename KeyEq = std::equal_to<T>,
125 typename Alloc = tbb::tbb_allocator<T>,
126 typename = std::enable_if_t<is_allocator_v<Alloc>>,
127 typename = std::enable_if_t<!is_allocator_v<Hash>>,
128 typename = std::enable_if_t<!is_allocator_v<KeyEq>>,
129 typename = std::enable_if_t<!std::is_integral_v<Hash>>>
130 concurrent_unordered_set( std::initializer_list<T>, std::size_t = {},
131 Hash = Hash(), KeyEq = KeyEq(), Alloc = Alloc() )
132 -> concurrent_unordered_set<T, Hash, KeyEq, Alloc>;
133
134 template <typename It, typename Alloc,
135 typename = std::enable_if_t<is_input_iterator_v<It>>,
136 typename = std::enable_if_t<is_allocator_v<Alloc>>>
137 concurrent_unordered_set( It, It, std::size_t, Alloc )
138 -> concurrent_unordered_set<iterator_value_t<It>, std::hash<iterator_value_t<It>>,
139 std::equal_to<iterator_value_t<It>>, Alloc>;
140
141 template <typename It, typename Hash, typename Alloc,
142 typename = std::enable_if_t<is_input_iterator_v<It>>,
143 typename = std::enable_if_t<is_allocator_v<Alloc>>,
144 typename = std::enable_if_t<!is_allocator_v<Hash>>,
145 typename = std::enable_if_t<!std::is_integral_v<Hash>>>
146 concurrent_unordered_set( It, It, std::size_t, Hash, Alloc )
147 -> concurrent_unordered_set<iterator_value_t<It>, Hash, std::equal_to<iterator_value_t<It>>, Alloc>;
148
149 template <typename T, typename Alloc,
150 typename = std::enable_if_t<is_allocator_v<Alloc>>>
151 concurrent_unordered_set( std::initializer_list<T>, std::size_t, Alloc )
152 -> concurrent_unordered_set<T, std::hash<T>, std::equal_to<T>, Alloc>;
153
154 template <typename T, typename Alloc,
155 typename = std::enable_if_t<is_allocator_v<Alloc>>>
156 concurrent_unordered_set( std::initializer_list<T>, Alloc )
157 -> concurrent_unordered_set<T, std::hash<T>, std::equal_to<T>, Alloc>;
158
159 template <typename T, typename Hash, typename Alloc,
160 typename = std::enable_if_t<is_allocator_v<Alloc>>,
161 typename = std::enable_if_t<!is_allocator_v<Hash>>,
162 typename = std::enable_if_t<!std::is_integral_v<Hash>>>
163 concurrent_unordered_set( std::initializer_list<T>, std::size_t, Hash, Alloc )
164 -> concurrent_unordered_set<T, Hash, std::equal_to<T>, Alloc>;
165
166 #if __APPLE__ && __TBB_CLANG_VERSION == 100000
167 // An explicit deduction guide is required for copy/move constructor with allocator for APPLE LLVM 10.0.0
168 // due to an issue with generating an implicit deduction guide for these constructors under several strange surcumstances.
169 // Currently the issue takes place because the last template parameter for Traits is boolean, it should not affect the deduction guides
170 // The issue reproduces only on this version of the compiler
171 template <typename T, typename Hash, typename KeyEq, typename Alloc>
172 concurrent_unordered_set( concurrent_unordered_set<T, Hash, KeyEq, Alloc>, Alloc )
173 -> concurrent_unordered_set<T, Hash, KeyEq, Alloc>;
174 #endif
175 #endif // __TBB_CPP17_DEDUCTION_GUIDES_PRESENT
176
177 template <typename Key, typename Hash, typename KeyEqual, typename Allocator>
swap(concurrent_unordered_set<Key,Hash,KeyEqual,Allocator> & lhs,concurrent_unordered_set<Key,Hash,KeyEqual,Allocator> & rhs)178 void swap( concurrent_unordered_set<Key, Hash, KeyEqual, Allocator>& lhs,
179 concurrent_unordered_set<Key, Hash, KeyEqual, Allocator>& rhs ) {
180 lhs.swap(rhs);
181 }
182
183 template <typename Key, typename Hash = std::hash<Key>, typename KeyEqual = std::equal_to<Key>,
184 typename Allocator = tbb::tbb_allocator<Key>>
185 class concurrent_unordered_multiset
186 : public concurrent_unordered_base<concurrent_unordered_set_traits<Key, Hash, KeyEqual, Allocator, true>>
187 {
188 using traits_type = concurrent_unordered_set_traits<Key, Hash, KeyEqual, Allocator, true>;
189 using base_type = concurrent_unordered_base<traits_type>;
190 public:
191 using key_type = typename base_type::key_type;
192 using value_type = typename base_type::value_type;
193 using size_type = typename base_type::size_type;
194 using difference_type = typename base_type::difference_type;
195 using hasher = typename base_type::hasher;
196 using key_equal = typename base_type::key_equal;
197 using allocator_type = typename base_type::allocator_type;
198 using reference = typename base_type::reference;
199 using const_reference = typename base_type::const_reference;
200 using pointer = typename base_type::pointer;
201 using const_pointer = typename base_type::const_pointer;
202 using iterator = typename base_type::iterator;
203 using const_iterator = typename base_type::const_iterator;
204 using local_iterator = typename base_type::local_iterator;
205 using const_local_iterator = typename base_type::const_local_iterator;
206 using node_type = typename base_type::node_type;
207
208 // Include constructors of base_type;
209 using base_type::base_type;
210
211 // Required for implicit deduction guides
212 concurrent_unordered_multiset() = default;
213 concurrent_unordered_multiset( const concurrent_unordered_multiset& ) = default;
concurrent_unordered_multiset(const concurrent_unordered_multiset & other,const allocator_type & alloc)214 concurrent_unordered_multiset( const concurrent_unordered_multiset& other, const allocator_type& alloc ) : base_type(other, alloc) {}
215 concurrent_unordered_multiset( concurrent_unordered_multiset&& ) = default;
concurrent_unordered_multiset(concurrent_unordered_multiset && other,const allocator_type & alloc)216 concurrent_unordered_multiset( concurrent_unordered_multiset&& other, const allocator_type& alloc ) : base_type(std::move(other), alloc) {}
217 // Required to respect the rule of 5
218 concurrent_unordered_multiset& operator=( const concurrent_unordered_multiset& ) = default;
219 concurrent_unordered_multiset& operator=( concurrent_unordered_multiset&& ) = default;
220
221 concurrent_unordered_multiset& operator=( std::initializer_list<value_type> il ) {
222 base_type::operator= (il);
223 return *this;
224 }
225
226 template <typename OtherHash, typename OtherKeyEqual>
merge(concurrent_unordered_set<key_type,OtherHash,OtherKeyEqual,allocator_type> & source)227 void merge( concurrent_unordered_set<key_type, OtherHash, OtherKeyEqual, allocator_type>& source ) {
228 this->internal_merge(source);
229 }
230
231 template <typename OtherHash, typename OtherKeyEqual>
merge(concurrent_unordered_set<key_type,OtherHash,OtherKeyEqual,allocator_type> && source)232 void merge( concurrent_unordered_set<key_type, OtherHash, OtherKeyEqual, allocator_type>&& source ) {
233 this->internal_merge(std::move(source));
234 }
235
236 template <typename OtherHash, typename OtherKeyEqual>
merge(concurrent_unordered_multiset<key_type,OtherHash,OtherKeyEqual,allocator_type> & source)237 void merge( concurrent_unordered_multiset<key_type, OtherHash, OtherKeyEqual, allocator_type>& source ) {
238 this->internal_merge(source);
239 }
240
241 template <typename OtherHash, typename OtherKeyEqual>
merge(concurrent_unordered_multiset<key_type,OtherHash,OtherKeyEqual,allocator_type> && source)242 void merge( concurrent_unordered_multiset<key_type, OtherHash, OtherKeyEqual, allocator_type>&& source ) {
243 this->internal_merge(std::move(source));
244 }
245 }; // class concurrent_unordered_multiset
246
247 #if __TBB_CPP17_DEDUCTION_GUIDES_PRESENT
248 template <typename It,
249 typename Hash = std::hash<iterator_value_t<It>>,
250 typename KeyEq = std::equal_to<iterator_value_t<It>>,
251 typename Alloc = tbb::tbb_allocator<iterator_value_t<It>>,
252 typename = std::enable_if_t<is_input_iterator_v<It>>,
253 typename = std::enable_if_t<is_allocator_v<Alloc>>,
254 typename = std::enable_if_t<!is_allocator_v<Hash>>,
255 typename = std::enable_if_t<!is_allocator_v<KeyEq>>,
256 typename = std::enable_if_t<!std::is_integral_v<Hash>>>
257 concurrent_unordered_multiset( It, It, std::size_t = {}, Hash = Hash(), KeyEq = KeyEq(), Alloc = Alloc() )
258 -> concurrent_unordered_multiset<iterator_value_t<It>, Hash, KeyEq, Alloc>;
259
260 template <typename T,
261 typename Hash = std::hash<T>,
262 typename KeyEq = std::equal_to<T>,
263 typename Alloc = tbb::tbb_allocator<T>,
264 typename = std::enable_if_t<is_allocator_v<Alloc>>,
265 typename = std::enable_if_t<!is_allocator_v<Hash>>,
266 typename = std::enable_if_t<!is_allocator_v<KeyEq>>,
267 typename = std::enable_if_t<!std::is_integral_v<Hash>>>
268 concurrent_unordered_multiset( std::initializer_list<T>, std::size_t = {},
269 Hash = Hash(), KeyEq = KeyEq(), Alloc = Alloc() )
270 -> concurrent_unordered_multiset<T, Hash, KeyEq, Alloc>;
271
272 template <typename It, typename Alloc,
273 typename = std::enable_if_t<is_input_iterator_v<It>>,
274 typename = std::enable_if_t<is_allocator_v<Alloc>>>
275 concurrent_unordered_multiset( It, It, std::size_t, Alloc )
276 -> concurrent_unordered_multiset<iterator_value_t<It>, std::hash<iterator_value_t<It>>,
277 std::equal_to<iterator_value_t<It>>, Alloc>;
278
279 template <typename It, typename Hash, typename Alloc,
280 typename = std::enable_if_t<is_input_iterator_v<It>>,
281 typename = std::enable_if_t<is_allocator_v<Alloc>>,
282 typename = std::enable_if_t<!is_allocator_v<Hash>>,
283 typename = std::enable_if_t<!std::is_integral_v<Hash>>>
284 concurrent_unordered_multiset( It, It, std::size_t, Hash, Alloc )
285 -> concurrent_unordered_multiset<iterator_value_t<It>, Hash, std::equal_to<iterator_value_t<It>>, Alloc>;
286
287 template <typename T, typename Alloc,
288 typename = std::enable_if_t<is_allocator_v<Alloc>>>
289 concurrent_unordered_multiset( std::initializer_list<T>, std::size_t, Alloc )
290 -> concurrent_unordered_multiset<T, std::hash<T>, std::equal_to<T>, Alloc>;
291
292 template <typename T, typename Alloc,
293 typename = std::enable_if_t<is_allocator_v<Alloc>>>
294 concurrent_unordered_multiset( std::initializer_list<T>, Alloc )
295 -> concurrent_unordered_multiset<T, std::hash<T>, std::equal_to<T>, Alloc>;
296
297 template <typename T, typename Hash, typename Alloc,
298 typename = std::enable_if_t<is_allocator_v<Alloc>>,
299 typename = std::enable_if_t<!is_allocator_v<Hash>>,
300 typename = std::enable_if_t<!std::is_integral_v<Hash>>>
301 concurrent_unordered_multiset( std::initializer_list<T>, std::size_t, Hash, Alloc )
302 -> concurrent_unordered_multiset<T, Hash, std::equal_to<T>, Alloc>;
303
304 #if __APPLE__ && __TBB_CLANG_VERSION == 100000
305 // An explicit deduction guide is required for copy/move constructor with allocator for APPLE LLVM 10.0.0
306 // due to an issue with generating an implicit deduction guide for these constructors under several strange surcumstances.
307 // Currently the issue takes place because the last template parameter for Traits is boolean, it should not affect the deduction guides
308 // The issue reproduces only on this version of the compiler
309 template <typename T, typename Hash, typename KeyEq, typename Alloc>
310 concurrent_unordered_multiset( concurrent_unordered_multiset<T, Hash, KeyEq, Alloc>, Alloc )
311 -> concurrent_unordered_multiset<T, Hash, KeyEq, Alloc>;
312 #endif
313 #endif // __TBB_CPP17_DEDUCTION_GUIDES_PRESENT
314
315 template <typename Key, typename Hash, typename KeyEqual, typename Allocator>
swap(concurrent_unordered_multiset<Key,Hash,KeyEqual,Allocator> & lhs,concurrent_unordered_multiset<Key,Hash,KeyEqual,Allocator> & rhs)316 void swap( concurrent_unordered_multiset<Key, Hash, KeyEqual, Allocator>& lhs,
317 concurrent_unordered_multiset<Key, Hash, KeyEqual, Allocator>& rhs ) {
318 lhs.swap(rhs);
319 }
320
321 } // namespace d1
322 } // namespace detail
323
324 inline namespace v1 {
325
326 using detail::d1::concurrent_unordered_set;
327 using detail::d1::concurrent_unordered_multiset;
328 using detail::split;
329
330 } // inline namespace v1
331 } // namespace tbb
332
333 #endif // __TBB_concurrent_unordered_set_H
334