149e08aacStbbdev /*
2*3fbdbb8bSkboyarinov     Copyright (c) 2005-2022 Intel Corporation
349e08aacStbbdev 
449e08aacStbbdev     Licensed under the Apache License, Version 2.0 (the "License");
549e08aacStbbdev     you may not use this file except in compliance with the License.
649e08aacStbbdev     You may obtain a copy of the License at
749e08aacStbbdev 
849e08aacStbbdev         http://www.apache.org/licenses/LICENSE-2.0
949e08aacStbbdev 
1049e08aacStbbdev     Unless required by applicable law or agreed to in writing, software
1149e08aacStbbdev     distributed under the License is distributed on an "AS IS" BASIS,
1249e08aacStbbdev     WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
1349e08aacStbbdev     See the License for the specific language governing permissions and
1449e08aacStbbdev     limitations under the License.
1549e08aacStbbdev */
1649e08aacStbbdev 
1749e08aacStbbdev #ifndef __TBB_concurrent_unordered_set_H
1849e08aacStbbdev #define __TBB_concurrent_unordered_set_H
1949e08aacStbbdev 
2049e08aacStbbdev #include "detail/_namespace_injection.h"
2149e08aacStbbdev #include "detail/_concurrent_unordered_base.h"
2249e08aacStbbdev #include "tbb_allocator.h"
2349e08aacStbbdev 
2449e08aacStbbdev namespace tbb {
2549e08aacStbbdev namespace detail {
2649e08aacStbbdev namespace d1 {
2749e08aacStbbdev 
2849e08aacStbbdev template <typename Key, typename Hash, typename KeyEqual, typename Allocator, bool AllowMultimapping>
2949e08aacStbbdev struct concurrent_unordered_set_traits {
3049e08aacStbbdev     using key_type = Key;
3149e08aacStbbdev     using value_type = key_type;
3249e08aacStbbdev     using allocator_type = Allocator;
3349e08aacStbbdev     using hash_compare_type = hash_compare<key_type, Hash, KeyEqual>;
3449e08aacStbbdev     static constexpr bool allow_multimapping = AllowMultimapping;
3549e08aacStbbdev 
get_keyconcurrent_unordered_set_traits3649e08aacStbbdev     static constexpr const key_type& get_key( const value_type& value ) {
3749e08aacStbbdev         return value;
3849e08aacStbbdev     }
3949e08aacStbbdev }; // class concurrent_unordered_set_traits
4049e08aacStbbdev 
4149e08aacStbbdev template <typename Key, typename Hash, typename KeyEqual, typename Allocator>
4249e08aacStbbdev class concurrent_unordered_multiset;
4349e08aacStbbdev 
4449e08aacStbbdev template <typename Key, typename Hash = std::hash<Key>, typename KeyEqual = std::equal_to<Key>,
4549e08aacStbbdev           typename Allocator = tbb::tbb_allocator<Key>>
4649e08aacStbbdev class concurrent_unordered_set
4749e08aacStbbdev     : public concurrent_unordered_base<concurrent_unordered_set_traits<Key, Hash, KeyEqual, Allocator, false>>
4849e08aacStbbdev {
4949e08aacStbbdev     using traits_type = concurrent_unordered_set_traits<Key, Hash, KeyEqual, Allocator, false>;
5049e08aacStbbdev     using base_type = concurrent_unordered_base<traits_type>;
5149e08aacStbbdev public:
5249e08aacStbbdev     using key_type = typename base_type::key_type;
5349e08aacStbbdev     using value_type = typename base_type::value_type;
5449e08aacStbbdev     using size_type = typename base_type::size_type;
5549e08aacStbbdev     using difference_type = typename base_type::difference_type;
5649e08aacStbbdev     using hasher = typename base_type::hasher;
5749e08aacStbbdev     using key_equal = typename base_type::key_equal;
5849e08aacStbbdev     using allocator_type = typename base_type::allocator_type;
5949e08aacStbbdev     using reference = typename base_type::reference;
6049e08aacStbbdev     using const_reference = typename base_type::const_reference;
6149e08aacStbbdev     using pointer = typename base_type::pointer;
6249e08aacStbbdev     using const_pointer = typename base_type::const_pointer;
6349e08aacStbbdev     using iterator = typename base_type::iterator;
6449e08aacStbbdev     using const_iterator = typename base_type::const_iterator;
6549e08aacStbbdev     using local_iterator = typename base_type::local_iterator;
6649e08aacStbbdev     using const_local_iterator = typename base_type::const_local_iterator;
6749e08aacStbbdev     using node_type = typename base_type::node_type;
6849e08aacStbbdev 
6949e08aacStbbdev     // Include constructors of base_type;
7049e08aacStbbdev     using base_type::base_type;
712713d41eSIlya Isaev 
72d86ed7fbStbbdev     // Required for implicit deduction guides
73d86ed7fbStbbdev     concurrent_unordered_set() = default;
74d86ed7fbStbbdev     concurrent_unordered_set( const concurrent_unordered_set& ) = default;
concurrent_unordered_set(const concurrent_unordered_set & other,const allocator_type & alloc)75d86ed7fbStbbdev     concurrent_unordered_set( const concurrent_unordered_set& other, const allocator_type& alloc ) : base_type(other, alloc) {}
76d86ed7fbStbbdev     concurrent_unordered_set( concurrent_unordered_set&& ) = default;
concurrent_unordered_set(concurrent_unordered_set && other,const allocator_type & alloc)77d86ed7fbStbbdev     concurrent_unordered_set( concurrent_unordered_set&& other, const allocator_type& alloc ) : base_type(std::move(other), alloc) {}
78d86ed7fbStbbdev     // Required to respect the rule of 5
79d86ed7fbStbbdev     concurrent_unordered_set& operator=( const concurrent_unordered_set& ) = default;
80d86ed7fbStbbdev     concurrent_unordered_set& operator=( concurrent_unordered_set&& ) = default;
8149e08aacStbbdev 
822713d41eSIlya Isaev     concurrent_unordered_set& operator=( std::initializer_list<value_type> il ) {
832713d41eSIlya Isaev         base_type::operator= (il);
842713d41eSIlya Isaev         return *this;
852713d41eSIlya Isaev     }
862713d41eSIlya Isaev 
8749e08aacStbbdev     template <typename OtherHash, typename OtherKeyEqual>
merge(concurrent_unordered_set<key_type,OtherHash,OtherKeyEqual,allocator_type> & source)8849e08aacStbbdev     void merge( concurrent_unordered_set<key_type, OtherHash, OtherKeyEqual, allocator_type>& source ) {
8949e08aacStbbdev         this->internal_merge(source);
9049e08aacStbbdev     }
9149e08aacStbbdev 
9249e08aacStbbdev     template <typename OtherHash, typename OtherKeyEqual>
merge(concurrent_unordered_set<key_type,OtherHash,OtherKeyEqual,allocator_type> && source)9349e08aacStbbdev     void merge( concurrent_unordered_set<key_type, OtherHash, OtherKeyEqual, allocator_type>&& source ) {
9449e08aacStbbdev         this->internal_merge(std::move(source));
9549e08aacStbbdev     }
9649e08aacStbbdev 
9749e08aacStbbdev     template <typename OtherHash, typename OtherKeyEqual>
merge(concurrent_unordered_multiset<key_type,OtherHash,OtherKeyEqual,allocator_type> & source)9849e08aacStbbdev     void merge( concurrent_unordered_multiset<key_type, OtherHash, OtherKeyEqual, allocator_type>& source ) {
9949e08aacStbbdev         this->internal_merge(source);
10049e08aacStbbdev     }
10149e08aacStbbdev 
10249e08aacStbbdev     template <typename OtherHash, typename OtherKeyEqual>
merge(concurrent_unordered_multiset<key_type,OtherHash,OtherKeyEqual,allocator_type> && source)10349e08aacStbbdev     void merge( concurrent_unordered_multiset<key_type, OtherHash, OtherKeyEqual, allocator_type>&& source ) {
10449e08aacStbbdev         this->internal_merge(std::move(source));
10549e08aacStbbdev     }
10649e08aacStbbdev }; // class concurrent_unordered_set
10749e08aacStbbdev 
10849e08aacStbbdev #if __TBB_CPP17_DEDUCTION_GUIDES_PRESENT
10949e08aacStbbdev 
110d86ed7fbStbbdev template <typename It,
111d86ed7fbStbbdev           typename Hash = std::hash<iterator_value_t<It>>,
112d86ed7fbStbbdev           typename KeyEq = std::equal_to<iterator_value_t<It>>,
113d86ed7fbStbbdev           typename Alloc = tbb::tbb_allocator<iterator_value_t<It>>,
114d86ed7fbStbbdev           typename = std::enable_if_t<is_input_iterator_v<It>>,
115d86ed7fbStbbdev           typename = std::enable_if_t<is_allocator_v<Alloc>>,
116d86ed7fbStbbdev           typename = std::enable_if_t<!is_allocator_v<Hash>>,
117d86ed7fbStbbdev           typename = std::enable_if_t<!is_allocator_v<KeyEq>>,
118d86ed7fbStbbdev           typename = std::enable_if_t<!std::is_integral_v<Hash>>>
119d86ed7fbStbbdev concurrent_unordered_set( It, It, std::size_t = {}, Hash = Hash(), KeyEq = KeyEq(), Alloc = Alloc() )
120d86ed7fbStbbdev -> concurrent_unordered_set<iterator_value_t<It>, Hash, KeyEq, Alloc>;
12149e08aacStbbdev 
122d86ed7fbStbbdev template <typename T,
123d86ed7fbStbbdev           typename Hash = std::hash<T>,
124d86ed7fbStbbdev           typename KeyEq = std::equal_to<T>,
125d86ed7fbStbbdev           typename Alloc = tbb::tbb_allocator<T>,
126d86ed7fbStbbdev           typename = std::enable_if_t<is_allocator_v<Alloc>>,
127d86ed7fbStbbdev           typename = std::enable_if_t<!is_allocator_v<Hash>>,
128d86ed7fbStbbdev           typename = std::enable_if_t<!is_allocator_v<KeyEq>>,
129d86ed7fbStbbdev           typename = std::enable_if_t<!std::is_integral_v<Hash>>>
130d86ed7fbStbbdev concurrent_unordered_set( std::initializer_list<T>, std::size_t = {},
131d86ed7fbStbbdev                           Hash = Hash(), KeyEq = KeyEq(), Alloc = Alloc() )
132d86ed7fbStbbdev -> concurrent_unordered_set<T, Hash, KeyEq, Alloc>;
13349e08aacStbbdev 
134d86ed7fbStbbdev template <typename It, typename Alloc,
135d86ed7fbStbbdev           typename = std::enable_if_t<is_input_iterator_v<It>>,
136d86ed7fbStbbdev           typename = std::enable_if_t<is_allocator_v<Alloc>>>
137d86ed7fbStbbdev concurrent_unordered_set( It, It, std::size_t, Alloc )
138d86ed7fbStbbdev -> concurrent_unordered_set<iterator_value_t<It>, std::hash<iterator_value_t<It>>,
139d86ed7fbStbbdev                             std::equal_to<iterator_value_t<It>>, Alloc>;
14049e08aacStbbdev 
141d86ed7fbStbbdev template <typename It, typename Hash, typename Alloc,
142d86ed7fbStbbdev           typename = std::enable_if_t<is_input_iterator_v<It>>,
143d86ed7fbStbbdev           typename = std::enable_if_t<is_allocator_v<Alloc>>,
144d86ed7fbStbbdev           typename = std::enable_if_t<!is_allocator_v<Hash>>,
145d86ed7fbStbbdev           typename = std::enable_if_t<!std::is_integral_v<Hash>>>
146d86ed7fbStbbdev concurrent_unordered_set( It, It, std::size_t, Hash, Alloc )
147d86ed7fbStbbdev -> concurrent_unordered_set<iterator_value_t<It>, Hash, std::equal_to<iterator_value_t<It>>, Alloc>;
14849e08aacStbbdev 
149d86ed7fbStbbdev template <typename T, typename Alloc,
150d86ed7fbStbbdev           typename = std::enable_if_t<is_allocator_v<Alloc>>>
151d86ed7fbStbbdev concurrent_unordered_set( std::initializer_list<T>, std::size_t, Alloc )
152d86ed7fbStbbdev -> concurrent_unordered_set<T, std::hash<T>, std::equal_to<T>, Alloc>;
15349e08aacStbbdev 
154d86ed7fbStbbdev template <typename T, typename Alloc,
155d86ed7fbStbbdev           typename = std::enable_if_t<is_allocator_v<Alloc>>>
156d86ed7fbStbbdev concurrent_unordered_set( std::initializer_list<T>, Alloc )
157d86ed7fbStbbdev -> concurrent_unordered_set<T, std::hash<T>, std::equal_to<T>, Alloc>;
15849e08aacStbbdev 
159d86ed7fbStbbdev template <typename T, typename Hash, typename Alloc,
160d86ed7fbStbbdev           typename = std::enable_if_t<is_allocator_v<Alloc>>,
161d86ed7fbStbbdev           typename = std::enable_if_t<!is_allocator_v<Hash>>,
162d86ed7fbStbbdev           typename = std::enable_if_t<!std::is_integral_v<Hash>>>
163d86ed7fbStbbdev concurrent_unordered_set( std::initializer_list<T>, std::size_t, Hash, Alloc )
164d86ed7fbStbbdev -> concurrent_unordered_set<T, Hash, std::equal_to<T>, Alloc>;
16549e08aacStbbdev 
166*3fbdbb8bSkboyarinov #if __APPLE__ && __TBB_CLANG_VERSION == 100000
167*3fbdbb8bSkboyarinov // An explicit deduction guide is required for copy/move constructor with allocator for APPLE LLVM 10.0.0
168*3fbdbb8bSkboyarinov // due to an issue with generating an implicit deduction guide for these constructors under several strange surcumstances.
169*3fbdbb8bSkboyarinov // Currently the issue takes place because the last template parameter for Traits is boolean, it should not affect the deduction guides
170*3fbdbb8bSkboyarinov // The issue reproduces only on this version of the compiler
171*3fbdbb8bSkboyarinov template <typename T, typename Hash, typename KeyEq, typename Alloc>
172*3fbdbb8bSkboyarinov concurrent_unordered_set( concurrent_unordered_set<T, Hash, KeyEq, Alloc>, Alloc )
173*3fbdbb8bSkboyarinov -> concurrent_unordered_set<T, Hash, KeyEq, Alloc>;
174*3fbdbb8bSkboyarinov #endif
17549e08aacStbbdev #endif // __TBB_CPP17_DEDUCTION_GUIDES_PRESENT
17649e08aacStbbdev 
17749e08aacStbbdev 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)17849e08aacStbbdev void swap( concurrent_unordered_set<Key, Hash, KeyEqual, Allocator>& lhs,
17949e08aacStbbdev            concurrent_unordered_set<Key, Hash, KeyEqual, Allocator>& rhs ) {
18049e08aacStbbdev     lhs.swap(rhs);
18149e08aacStbbdev }
18249e08aacStbbdev 
18349e08aacStbbdev template <typename Key, typename Hash = std::hash<Key>, typename KeyEqual = std::equal_to<Key>,
18449e08aacStbbdev           typename Allocator = tbb::tbb_allocator<Key>>
18549e08aacStbbdev class concurrent_unordered_multiset
18649e08aacStbbdev     : public concurrent_unordered_base<concurrent_unordered_set_traits<Key, Hash, KeyEqual, Allocator, true>>
18749e08aacStbbdev {
18849e08aacStbbdev     using traits_type = concurrent_unordered_set_traits<Key, Hash, KeyEqual, Allocator, true>;
18949e08aacStbbdev     using base_type = concurrent_unordered_base<traits_type>;
19049e08aacStbbdev public:
19149e08aacStbbdev     using key_type = typename base_type::key_type;
19249e08aacStbbdev     using value_type = typename base_type::value_type;
19349e08aacStbbdev     using size_type = typename base_type::size_type;
19449e08aacStbbdev     using difference_type = typename base_type::difference_type;
19549e08aacStbbdev     using hasher = typename base_type::hasher;
19649e08aacStbbdev     using key_equal = typename base_type::key_equal;
19749e08aacStbbdev     using allocator_type = typename base_type::allocator_type;
19849e08aacStbbdev     using reference = typename base_type::reference;
19949e08aacStbbdev     using const_reference = typename base_type::const_reference;
20049e08aacStbbdev     using pointer = typename base_type::pointer;
20149e08aacStbbdev     using const_pointer = typename base_type::const_pointer;
20249e08aacStbbdev     using iterator = typename base_type::iterator;
20349e08aacStbbdev     using const_iterator = typename base_type::const_iterator;
20449e08aacStbbdev     using local_iterator = typename base_type::local_iterator;
20549e08aacStbbdev     using const_local_iterator = typename base_type::const_local_iterator;
20649e08aacStbbdev     using node_type = typename base_type::node_type;
20749e08aacStbbdev 
20849e08aacStbbdev     // Include constructors of base_type;
20949e08aacStbbdev     using base_type::base_type;
21049e08aacStbbdev 
211d86ed7fbStbbdev     // Required for implicit deduction guides
212d86ed7fbStbbdev     concurrent_unordered_multiset() = default;
213d86ed7fbStbbdev     concurrent_unordered_multiset( const concurrent_unordered_multiset& ) = default;
concurrent_unordered_multiset(const concurrent_unordered_multiset & other,const allocator_type & alloc)214d86ed7fbStbbdev     concurrent_unordered_multiset( const concurrent_unordered_multiset& other, const allocator_type& alloc ) : base_type(other, alloc) {}
215d86ed7fbStbbdev     concurrent_unordered_multiset( concurrent_unordered_multiset&& ) = default;
concurrent_unordered_multiset(concurrent_unordered_multiset && other,const allocator_type & alloc)216d86ed7fbStbbdev     concurrent_unordered_multiset( concurrent_unordered_multiset&& other, const allocator_type& alloc ) : base_type(std::move(other), alloc) {}
217d86ed7fbStbbdev     // Required to respect the rule of 5
218d86ed7fbStbbdev     concurrent_unordered_multiset& operator=( const concurrent_unordered_multiset& ) = default;
219d86ed7fbStbbdev     concurrent_unordered_multiset& operator=( concurrent_unordered_multiset&& ) = default;
220d86ed7fbStbbdev 
2212713d41eSIlya Isaev     concurrent_unordered_multiset& operator=( std::initializer_list<value_type> il ) {
2222713d41eSIlya Isaev         base_type::operator= (il);
2232713d41eSIlya Isaev         return *this;
2242713d41eSIlya Isaev     }
2252713d41eSIlya Isaev 
22649e08aacStbbdev     template <typename OtherHash, typename OtherKeyEqual>
merge(concurrent_unordered_set<key_type,OtherHash,OtherKeyEqual,allocator_type> & source)22749e08aacStbbdev     void merge( concurrent_unordered_set<key_type, OtherHash, OtherKeyEqual, allocator_type>& source ) {
22849e08aacStbbdev         this->internal_merge(source);
22949e08aacStbbdev     }
23049e08aacStbbdev 
23149e08aacStbbdev     template <typename OtherHash, typename OtherKeyEqual>
merge(concurrent_unordered_set<key_type,OtherHash,OtherKeyEqual,allocator_type> && source)23249e08aacStbbdev     void merge( concurrent_unordered_set<key_type, OtherHash, OtherKeyEqual, allocator_type>&& source ) {
23349e08aacStbbdev         this->internal_merge(std::move(source));
23449e08aacStbbdev     }
23549e08aacStbbdev 
23649e08aacStbbdev     template <typename OtherHash, typename OtherKeyEqual>
merge(concurrent_unordered_multiset<key_type,OtherHash,OtherKeyEqual,allocator_type> & source)23749e08aacStbbdev     void merge( concurrent_unordered_multiset<key_type, OtherHash, OtherKeyEqual, allocator_type>& source ) {
23849e08aacStbbdev         this->internal_merge(source);
23949e08aacStbbdev     }
24049e08aacStbbdev 
24149e08aacStbbdev     template <typename OtherHash, typename OtherKeyEqual>
merge(concurrent_unordered_multiset<key_type,OtherHash,OtherKeyEqual,allocator_type> && source)24249e08aacStbbdev     void merge( concurrent_unordered_multiset<key_type, OtherHash, OtherKeyEqual, allocator_type>&& source ) {
24349e08aacStbbdev         this->internal_merge(std::move(source));
24449e08aacStbbdev     }
24549e08aacStbbdev }; // class concurrent_unordered_multiset
24649e08aacStbbdev 
24749e08aacStbbdev #if __TBB_CPP17_DEDUCTION_GUIDES_PRESENT
248d86ed7fbStbbdev template <typename It,
249d86ed7fbStbbdev           typename Hash = std::hash<iterator_value_t<It>>,
250d86ed7fbStbbdev           typename KeyEq = std::equal_to<iterator_value_t<It>>,
251d86ed7fbStbbdev           typename Alloc = tbb::tbb_allocator<iterator_value_t<It>>,
252d86ed7fbStbbdev           typename = std::enable_if_t<is_input_iterator_v<It>>,
253d86ed7fbStbbdev           typename = std::enable_if_t<is_allocator_v<Alloc>>,
254d86ed7fbStbbdev           typename = std::enable_if_t<!is_allocator_v<Hash>>,
255d86ed7fbStbbdev           typename = std::enable_if_t<!is_allocator_v<KeyEq>>,
256d86ed7fbStbbdev           typename = std::enable_if_t<!std::is_integral_v<Hash>>>
257d86ed7fbStbbdev concurrent_unordered_multiset( It, It, std::size_t = {}, Hash = Hash(), KeyEq = KeyEq(), Alloc = Alloc() )
258d86ed7fbStbbdev -> concurrent_unordered_multiset<iterator_value_t<It>, Hash, KeyEq, Alloc>;
25949e08aacStbbdev 
260d86ed7fbStbbdev template <typename T,
261d86ed7fbStbbdev           typename Hash = std::hash<T>,
262d86ed7fbStbbdev           typename KeyEq = std::equal_to<T>,
263d86ed7fbStbbdev           typename Alloc = tbb::tbb_allocator<T>,
264d86ed7fbStbbdev           typename = std::enable_if_t<is_allocator_v<Alloc>>,
265d86ed7fbStbbdev           typename = std::enable_if_t<!is_allocator_v<Hash>>,
266d86ed7fbStbbdev           typename = std::enable_if_t<!is_allocator_v<KeyEq>>,
267d86ed7fbStbbdev           typename = std::enable_if_t<!std::is_integral_v<Hash>>>
268d86ed7fbStbbdev concurrent_unordered_multiset( std::initializer_list<T>, std::size_t = {},
269d86ed7fbStbbdev                           Hash = Hash(), KeyEq = KeyEq(), Alloc = Alloc() )
270d86ed7fbStbbdev -> concurrent_unordered_multiset<T, Hash, KeyEq, Alloc>;
27149e08aacStbbdev 
272d86ed7fbStbbdev template <typename It, typename Alloc,
273d86ed7fbStbbdev           typename = std::enable_if_t<is_input_iterator_v<It>>,
274d86ed7fbStbbdev           typename = std::enable_if_t<is_allocator_v<Alloc>>>
275d86ed7fbStbbdev concurrent_unordered_multiset( It, It, std::size_t, Alloc )
276d86ed7fbStbbdev -> concurrent_unordered_multiset<iterator_value_t<It>, std::hash<iterator_value_t<It>>,
277d86ed7fbStbbdev                             std::equal_to<iterator_value_t<It>>, Alloc>;
27849e08aacStbbdev 
279d86ed7fbStbbdev template <typename It, typename Hash, typename Alloc,
280d86ed7fbStbbdev           typename = std::enable_if_t<is_input_iterator_v<It>>,
281d86ed7fbStbbdev           typename = std::enable_if_t<is_allocator_v<Alloc>>,
282d86ed7fbStbbdev           typename = std::enable_if_t<!is_allocator_v<Hash>>,
283d86ed7fbStbbdev           typename = std::enable_if_t<!std::is_integral_v<Hash>>>
284d86ed7fbStbbdev concurrent_unordered_multiset( It, It, std::size_t, Hash, Alloc )
285d86ed7fbStbbdev -> concurrent_unordered_multiset<iterator_value_t<It>, Hash, std::equal_to<iterator_value_t<It>>, Alloc>;
28649e08aacStbbdev 
287d86ed7fbStbbdev template <typename T, typename Alloc,
288d86ed7fbStbbdev           typename = std::enable_if_t<is_allocator_v<Alloc>>>
289d86ed7fbStbbdev concurrent_unordered_multiset( std::initializer_list<T>, std::size_t, Alloc )
290d86ed7fbStbbdev -> concurrent_unordered_multiset<T, std::hash<T>, std::equal_to<T>, Alloc>;
291d86ed7fbStbbdev 
292d86ed7fbStbbdev template <typename T, typename Alloc,
293d86ed7fbStbbdev           typename = std::enable_if_t<is_allocator_v<Alloc>>>
294d86ed7fbStbbdev concurrent_unordered_multiset( std::initializer_list<T>, Alloc )
295d86ed7fbStbbdev -> concurrent_unordered_multiset<T, std::hash<T>, std::equal_to<T>, Alloc>;
296d86ed7fbStbbdev 
297d86ed7fbStbbdev template <typename T, typename Hash, typename Alloc,
298d86ed7fbStbbdev           typename = std::enable_if_t<is_allocator_v<Alloc>>,
299d86ed7fbStbbdev           typename = std::enable_if_t<!is_allocator_v<Hash>>,
300d86ed7fbStbbdev           typename = std::enable_if_t<!std::is_integral_v<Hash>>>
301d86ed7fbStbbdev concurrent_unordered_multiset( std::initializer_list<T>, std::size_t, Hash, Alloc )
302d86ed7fbStbbdev -> concurrent_unordered_multiset<T, Hash, std::equal_to<T>, Alloc>;
30349e08aacStbbdev 
304*3fbdbb8bSkboyarinov #if __APPLE__ && __TBB_CLANG_VERSION == 100000
305*3fbdbb8bSkboyarinov // An explicit deduction guide is required for copy/move constructor with allocator for APPLE LLVM 10.0.0
306*3fbdbb8bSkboyarinov // due to an issue with generating an implicit deduction guide for these constructors under several strange surcumstances.
307*3fbdbb8bSkboyarinov // Currently the issue takes place because the last template parameter for Traits is boolean, it should not affect the deduction guides
308*3fbdbb8bSkboyarinov // The issue reproduces only on this version of the compiler
309*3fbdbb8bSkboyarinov template <typename T, typename Hash, typename KeyEq, typename Alloc>
310*3fbdbb8bSkboyarinov concurrent_unordered_multiset( concurrent_unordered_multiset<T, Hash, KeyEq, Alloc>, Alloc )
311*3fbdbb8bSkboyarinov -> concurrent_unordered_multiset<T, Hash, KeyEq, Alloc>;
312*3fbdbb8bSkboyarinov #endif
31349e08aacStbbdev #endif // __TBB_CPP17_DEDUCTION_GUIDES_PRESENT
31449e08aacStbbdev 
31549e08aacStbbdev 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)31649e08aacStbbdev void swap( concurrent_unordered_multiset<Key, Hash, KeyEqual, Allocator>& lhs,
31749e08aacStbbdev            concurrent_unordered_multiset<Key, Hash, KeyEqual, Allocator>& rhs ) {
31849e08aacStbbdev     lhs.swap(rhs);
31949e08aacStbbdev }
32049e08aacStbbdev 
32149e08aacStbbdev } // namespace d1
32249e08aacStbbdev } // namespace detail
32349e08aacStbbdev 
32449e08aacStbbdev inline namespace v1 {
32549e08aacStbbdev 
32649e08aacStbbdev using detail::d1::concurrent_unordered_set;
32749e08aacStbbdev using detail::d1::concurrent_unordered_multiset;
32849e08aacStbbdev using detail::split;
32949e08aacStbbdev 
33049e08aacStbbdev } // inline namespace v1
33149e08aacStbbdev } // namespace tbb
33249e08aacStbbdev 
33349e08aacStbbdev #endif // __TBB_concurrent_unordered_set_H
334