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_map_H
1849e08aacStbbdev #define __TBB_concurrent_unordered_map_H
1949e08aacStbbdev
2049e08aacStbbdev #include "detail/_namespace_injection.h"
2149e08aacStbbdev #include "detail/_concurrent_unordered_base.h"
2249e08aacStbbdev #include "tbb_allocator.h"
2349e08aacStbbdev #include <functional>
2449e08aacStbbdev
2549e08aacStbbdev namespace tbb {
2649e08aacStbbdev namespace detail {
2749e08aacStbbdev namespace d1 {
2849e08aacStbbdev
2949e08aacStbbdev template <typename Key, typename T, typename Hash, typename KeyEqual, typename Allocator, bool AllowMultimapping>
3049e08aacStbbdev struct concurrent_unordered_map_traits {
3149e08aacStbbdev using value_type = std::pair<const Key, T>;
3249e08aacStbbdev using key_type = Key;
3349e08aacStbbdev using allocator_type = Allocator;
3449e08aacStbbdev using hash_compare_type = hash_compare<Key, Hash, KeyEqual>;
3549e08aacStbbdev static constexpr bool allow_multimapping = AllowMultimapping;
3649e08aacStbbdev
get_keyconcurrent_unordered_map_traits3749e08aacStbbdev static constexpr const key_type& get_key( const value_type& value ) {
3849e08aacStbbdev return value.first;
3949e08aacStbbdev }
4049e08aacStbbdev }; // struct concurrent_unordered_map_traits
4149e08aacStbbdev
4249e08aacStbbdev template <typename Key, typename T, typename Hash, typename KeyEqual, typename Allocator>
4349e08aacStbbdev class concurrent_unordered_multimap;
4449e08aacStbbdev
4549e08aacStbbdev template <typename Key, typename T, typename Hash = std::hash<Key>, typename KeyEqual = std::equal_to<Key>,
4649e08aacStbbdev typename Allocator = tbb::tbb_allocator<std::pair<const Key, T>> >
4749e08aacStbbdev class concurrent_unordered_map
4849e08aacStbbdev : public concurrent_unordered_base<concurrent_unordered_map_traits<Key, T, Hash, KeyEqual, Allocator, false>>
4949e08aacStbbdev {
5049e08aacStbbdev using traits_type = concurrent_unordered_map_traits<Key, T, Hash, KeyEqual, Allocator, false>;
5149e08aacStbbdev using base_type = concurrent_unordered_base<traits_type>;
5249e08aacStbbdev public:
5349e08aacStbbdev using key_type = typename base_type::key_type;
5449e08aacStbbdev using mapped_type = T;
5549e08aacStbbdev using value_type = typename base_type::value_type;
5649e08aacStbbdev using size_type = typename base_type::size_type;
5749e08aacStbbdev using difference_type = typename base_type::difference_type;
5849e08aacStbbdev using hasher = typename base_type::hasher;
5949e08aacStbbdev using key_equal = typename base_type::key_equal;
6049e08aacStbbdev using allocator_type = typename base_type::allocator_type;
6149e08aacStbbdev using reference = typename base_type::reference;
6249e08aacStbbdev using const_reference = typename base_type::const_reference;
6349e08aacStbbdev using pointer = typename base_type::pointer;
6449e08aacStbbdev using const_pointer = typename base_type::const_pointer;
6549e08aacStbbdev using iterator = typename base_type::iterator;
6649e08aacStbbdev using const_iterator = typename base_type::const_iterator;
6749e08aacStbbdev using local_iterator = typename base_type::local_iterator;
6849e08aacStbbdev using const_local_iterator = typename base_type::const_local_iterator;
6949e08aacStbbdev using node_type = typename base_type::node_type;
7049e08aacStbbdev
7149e08aacStbbdev // Include constructors of base type
7249e08aacStbbdev using base_type::base_type;
7349e08aacStbbdev
74d86ed7fbStbbdev // Required for implicit deduction guides
75d86ed7fbStbbdev concurrent_unordered_map() = default;
76d86ed7fbStbbdev concurrent_unordered_map( const concurrent_unordered_map& ) = default;
concurrent_unordered_map(const concurrent_unordered_map & other,const allocator_type & alloc)77d86ed7fbStbbdev concurrent_unordered_map( const concurrent_unordered_map& other, const allocator_type& alloc ) : base_type(other, alloc) {}
78d86ed7fbStbbdev concurrent_unordered_map( concurrent_unordered_map&& ) = default;
concurrent_unordered_map(concurrent_unordered_map && other,const allocator_type & alloc)79d86ed7fbStbbdev concurrent_unordered_map( concurrent_unordered_map&& other, const allocator_type& alloc ) : base_type(std::move(other), alloc) {}
80d86ed7fbStbbdev // Required to respect the rule of 5
81d86ed7fbStbbdev concurrent_unordered_map& operator=( const concurrent_unordered_map& ) = default;
82d86ed7fbStbbdev concurrent_unordered_map& operator=( concurrent_unordered_map&& ) = default;
83d86ed7fbStbbdev
842713d41eSIlya Isaev concurrent_unordered_map& operator=( std::initializer_list<value_type> il ) {
852713d41eSIlya Isaev base_type::operator= (il);
862713d41eSIlya Isaev return *this;
872713d41eSIlya Isaev }
882713d41eSIlya Isaev
8949e08aacStbbdev // Observers
9049e08aacStbbdev mapped_type& operator[]( const key_type& key ) {
9149e08aacStbbdev iterator where = this->find(key);
9249e08aacStbbdev
9349e08aacStbbdev if (where == this->end()) {
9449e08aacStbbdev where = this->emplace(std::piecewise_construct, std::forward_as_tuple(key), std::tuple<>()).first;
9549e08aacStbbdev }
9649e08aacStbbdev return where->second;
9749e08aacStbbdev }
9849e08aacStbbdev
9949e08aacStbbdev mapped_type& operator[]( key_type&& key ) {
10049e08aacStbbdev iterator where = this->find(key);
10149e08aacStbbdev
10249e08aacStbbdev if (where == this->end()) {
10349e08aacStbbdev where = this->emplace(std::piecewise_construct, std::forward_as_tuple(std::move(key)), std::tuple<>()).first;
10449e08aacStbbdev }
10549e08aacStbbdev return where->second;
10649e08aacStbbdev }
10749e08aacStbbdev
at(const key_type & key)10849e08aacStbbdev mapped_type& at( const key_type& key ) {
10949e08aacStbbdev iterator where = this->find(key);
11049e08aacStbbdev
11149e08aacStbbdev if (where == this->end()) {
11249e08aacStbbdev throw_exception(exception_id::invalid_key);
11349e08aacStbbdev }
11449e08aacStbbdev return where->second;
11549e08aacStbbdev }
11649e08aacStbbdev
at(const key_type & key)11749e08aacStbbdev const mapped_type& at( const key_type& key ) const {
11849e08aacStbbdev const_iterator where = this->find(key);
11949e08aacStbbdev
12049e08aacStbbdev if (where == this->end()) {
12149e08aacStbbdev throw_exception(exception_id::out_of_range);
12249e08aacStbbdev }
12349e08aacStbbdev return where->second;
12449e08aacStbbdev }
12549e08aacStbbdev
12649e08aacStbbdev using base_type::insert;
12749e08aacStbbdev
12849e08aacStbbdev template<typename P>
12949e08aacStbbdev typename std::enable_if<std::is_constructible<value_type, P&&>::value,
insert(P && value)13049e08aacStbbdev std::pair<iterator, bool>>::type insert( P&& value ) {
13149e08aacStbbdev return this->emplace(std::forward<P>(value));
13249e08aacStbbdev }
13349e08aacStbbdev
13449e08aacStbbdev template<typename P>
13549e08aacStbbdev typename std::enable_if<std::is_constructible<value_type, P&&>::value,
insert(const_iterator hint,P && value)13649e08aacStbbdev iterator>::type insert( const_iterator hint, P&& value ) {
13749e08aacStbbdev return this->emplace_hint(hint, std::forward<P>(value));
13849e08aacStbbdev }
13949e08aacStbbdev
14049e08aacStbbdev template <typename OtherHash, typename OtherKeyEqual>
merge(concurrent_unordered_map<key_type,mapped_type,OtherHash,OtherKeyEqual,allocator_type> & source)14149e08aacStbbdev void merge( concurrent_unordered_map<key_type, mapped_type, OtherHash, OtherKeyEqual, allocator_type>& source ) {
14249e08aacStbbdev this->internal_merge(source);
14349e08aacStbbdev }
14449e08aacStbbdev
14549e08aacStbbdev template <typename OtherHash, typename OtherKeyEqual>
merge(concurrent_unordered_map<key_type,mapped_type,OtherHash,OtherKeyEqual,allocator_type> && source)14649e08aacStbbdev void merge( concurrent_unordered_map<key_type, mapped_type, OtherHash, OtherKeyEqual, allocator_type>&& source ) {
14749e08aacStbbdev this->internal_merge(std::move(source));
14849e08aacStbbdev }
14949e08aacStbbdev
15049e08aacStbbdev template <typename OtherHash, typename OtherKeyEqual>
merge(concurrent_unordered_multimap<key_type,mapped_type,OtherHash,OtherKeyEqual,allocator_type> & source)15149e08aacStbbdev void merge( concurrent_unordered_multimap<key_type, mapped_type, OtherHash, OtherKeyEqual, allocator_type>& source ) {
15249e08aacStbbdev this->internal_merge(source);
15349e08aacStbbdev }
15449e08aacStbbdev
15549e08aacStbbdev template <typename OtherHash, typename OtherKeyEqual>
merge(concurrent_unordered_multimap<key_type,mapped_type,OtherHash,OtherKeyEqual,allocator_type> && source)15649e08aacStbbdev void merge( concurrent_unordered_multimap<key_type, mapped_type, OtherHash, OtherKeyEqual, allocator_type>&& source ) {
15749e08aacStbbdev this->internal_merge(std::move(source));
15849e08aacStbbdev }
15949e08aacStbbdev }; // class concurrent_unordered_map
16049e08aacStbbdev
16149e08aacStbbdev #if __TBB_CPP17_DEDUCTION_GUIDES_PRESENT
162d86ed7fbStbbdev template <typename It,
163d86ed7fbStbbdev typename Hash = std::hash<iterator_key_t<It>>,
164d86ed7fbStbbdev typename KeyEq = std::equal_to<iterator_key_t<It>>,
165d86ed7fbStbbdev typename Alloc = tbb::tbb_allocator<iterator_alloc_pair_t<It>>,
166d86ed7fbStbbdev typename = std::enable_if_t<is_input_iterator_v<It>>,
167d86ed7fbStbbdev typename = std::enable_if_t<is_allocator_v<Alloc>>,
168d86ed7fbStbbdev typename = std::enable_if_t<!is_allocator_v<Hash>>,
169d86ed7fbStbbdev typename = std::enable_if_t<!is_allocator_v<KeyEq>>,
170d86ed7fbStbbdev typename = std::enable_if_t<!std::is_integral_v<Hash>>>
171d86ed7fbStbbdev concurrent_unordered_map( It, It, std::size_t = {},
172d86ed7fbStbbdev Hash = Hash(), KeyEq = KeyEq(), Alloc = Alloc() )
173d86ed7fbStbbdev -> concurrent_unordered_map<iterator_key_t<It>, iterator_mapped_t<It>, Hash, KeyEq, Alloc>;
17449e08aacStbbdev
175d86ed7fbStbbdev template <typename Key, typename T,
176d86ed7fbStbbdev typename Hash = std::hash<std::remove_const_t<Key>>,
177d86ed7fbStbbdev typename KeyEq = std::equal_to<std::remove_const_t<Key>>,
178d86ed7fbStbbdev typename Alloc = tbb::tbb_allocator<std::pair<const Key, T>>,
179d86ed7fbStbbdev typename = std::enable_if_t<is_allocator_v<Alloc>>,
180d86ed7fbStbbdev typename = std::enable_if_t<!is_allocator_v<Hash>>,
181d86ed7fbStbbdev typename = std::enable_if_t<!is_allocator_v<KeyEq>>,
182d86ed7fbStbbdev typename = std::enable_if_t<!std::is_integral_v<Hash>>>
183d86ed7fbStbbdev concurrent_unordered_map( std::initializer_list<std::pair<Key, T>>, std::size_t = {},
184d86ed7fbStbbdev Hash = Hash(), KeyEq = KeyEq(), Alloc = Alloc() )
185d86ed7fbStbbdev -> concurrent_unordered_map<std::remove_const_t<Key>, T, Hash, KeyEq, Alloc>;
18649e08aacStbbdev
187d86ed7fbStbbdev template <typename It, typename Alloc,
188d86ed7fbStbbdev typename = std::enable_if_t<is_input_iterator_v<It>>,
189d86ed7fbStbbdev typename = std::enable_if_t<is_allocator_v<Alloc>>>
190d86ed7fbStbbdev concurrent_unordered_map( It, It, std::size_t, Alloc )
191d86ed7fbStbbdev -> concurrent_unordered_map<iterator_key_t<It>, iterator_mapped_t<It>,
192d86ed7fbStbbdev std::hash<iterator_key_t<It>>,
193d86ed7fbStbbdev std::equal_to<iterator_key_t<It>>, Alloc>;
19449e08aacStbbdev
195d86ed7fbStbbdev // TODO: investigate if a deduction guide for concurrent_unordered_map(It, It, Alloc) is needed
19649e08aacStbbdev
197d86ed7fbStbbdev template <typename It, typename Hash, typename Alloc,
198d86ed7fbStbbdev typename = std::enable_if_t<is_input_iterator_v<It>>,
199d86ed7fbStbbdev typename = std::enable_if_t<is_allocator_v<Alloc>>,
200d86ed7fbStbbdev typename = std::enable_if_t<!is_allocator_v<Hash>>,
201d86ed7fbStbbdev typename = std::enable_if_t<!std::is_integral_v<Hash>>>
202d86ed7fbStbbdev concurrent_unordered_map( It, It, std::size_t, Hash, Alloc )
203d86ed7fbStbbdev -> concurrent_unordered_map<iterator_key_t<It>, iterator_mapped_t<It>,
204d86ed7fbStbbdev Hash, std::equal_to<iterator_key_t<It>>, Alloc>;
20549e08aacStbbdev
206d86ed7fbStbbdev template <typename Key, typename T, typename Alloc,
207d86ed7fbStbbdev typename = std::enable_if_t<is_allocator_v<Alloc>>>
208d86ed7fbStbbdev concurrent_unordered_map( std::initializer_list<std::pair<Key, T>>, std::size_t, Alloc )
209d86ed7fbStbbdev -> concurrent_unordered_map<std::remove_const_t<Key>, T, std::hash<std::remove_const_t<Key>>,
210d86ed7fbStbbdev std::equal_to<std::remove_const_t<Key>>, Alloc>;
21149e08aacStbbdev
212d86ed7fbStbbdev template <typename Key, typename T, typename Alloc,
213d86ed7fbStbbdev typename = std::enable_if_t<is_allocator_v<Alloc>>>
214d86ed7fbStbbdev concurrent_unordered_map( std::initializer_list<std::pair<Key, T>>, Alloc )
215d86ed7fbStbbdev -> concurrent_unordered_map<std::remove_const_t<Key>, T, std::hash<std::remove_const_t<Key>>,
216d86ed7fbStbbdev std::equal_to<std::remove_const_t<Key>>, Alloc>;
21749e08aacStbbdev
218d86ed7fbStbbdev template <typename Key, typename T, typename Hash, typename Alloc,
219d86ed7fbStbbdev typename = std::enable_if_t<is_allocator_v<Alloc>>,
220d86ed7fbStbbdev typename = std::enable_if_t<!is_allocator_v<Hash>>,
221d86ed7fbStbbdev typename = std::enable_if_t<!std::is_integral_v<Hash>>>
222d86ed7fbStbbdev concurrent_unordered_map( std::initializer_list<std::pair<Key, T>>, std::size_t, Hash, Alloc )
223d86ed7fbStbbdev -> concurrent_unordered_map<std::remove_const_t<Key>, T, Hash,
224d86ed7fbStbbdev std::equal_to<std::remove_const_t<Key>>, Alloc>;
22549e08aacStbbdev
226*3fbdbb8bSkboyarinov #if __APPLE__ && __TBB_CLANG_VERSION == 100000
227*3fbdbb8bSkboyarinov // An explicit deduction guide is required for copy/move constructor with allocator for APPLE LLVM 10.0.0
228*3fbdbb8bSkboyarinov // due to an issue with generating an implicit deduction guide for these constructors under several strange surcumstances.
229*3fbdbb8bSkboyarinov // Currently the issue takes place because the last template parameter for Traits is boolean, it should not affect the deduction guides
230*3fbdbb8bSkboyarinov // The issue reproduces only on this version of the compiler
231*3fbdbb8bSkboyarinov template <typename Key, typename T, typename Hash, typename KeyEq, typename Alloc>
232*3fbdbb8bSkboyarinov concurrent_unordered_map( concurrent_unordered_map<Key, T, Hash, KeyEq, Alloc>, Alloc )
233*3fbdbb8bSkboyarinov -> concurrent_unordered_map<Key, T, Hash, KeyEq, Alloc>;
234*3fbdbb8bSkboyarinov #endif
235*3fbdbb8bSkboyarinov
23649e08aacStbbdev #endif // __TBB_CPP17_DEDUCTION_GUIDES_PRESENT
23749e08aacStbbdev
23849e08aacStbbdev template <typename Key, typename T, typename Hash, typename KeyEqual, typename Allocator>
swap(concurrent_unordered_map<Key,T,Hash,KeyEqual,Allocator> & lhs,concurrent_unordered_map<Key,T,Hash,KeyEqual,Allocator> & rhs)23949e08aacStbbdev void swap( concurrent_unordered_map<Key, T, Hash, KeyEqual, Allocator>& lhs,
24049e08aacStbbdev concurrent_unordered_map<Key, T, Hash, KeyEqual, Allocator>& rhs ) {
24149e08aacStbbdev lhs.swap(rhs);
24249e08aacStbbdev }
24349e08aacStbbdev
24449e08aacStbbdev template <typename Key, typename T, typename Hash = std::hash<Key>, typename KeyEqual = std::equal_to<Key>,
24549e08aacStbbdev typename Allocator = tbb::tbb_allocator<std::pair<const Key, T>> >
24649e08aacStbbdev class concurrent_unordered_multimap
24749e08aacStbbdev : public concurrent_unordered_base<concurrent_unordered_map_traits<Key, T, Hash, KeyEqual, Allocator, true>>
24849e08aacStbbdev {
24949e08aacStbbdev using traits_type = concurrent_unordered_map_traits<Key, T, Hash, KeyEqual, Allocator, true>;
25049e08aacStbbdev using base_type = concurrent_unordered_base<traits_type>;
25149e08aacStbbdev public:
25249e08aacStbbdev using key_type = typename base_type::key_type;
25349e08aacStbbdev using mapped_type = T;
25449e08aacStbbdev using value_type = typename base_type::value_type;
25549e08aacStbbdev using size_type = typename base_type::size_type;
25649e08aacStbbdev using difference_type = typename base_type::difference_type;
25749e08aacStbbdev using hasher = typename base_type::hasher;
25849e08aacStbbdev using key_equal = typename base_type::key_equal;
25949e08aacStbbdev using allocator_type = typename base_type::allocator_type;
26049e08aacStbbdev using reference = typename base_type::reference;
26149e08aacStbbdev using const_reference = typename base_type::const_reference;
26249e08aacStbbdev using pointer = typename base_type::pointer;
26349e08aacStbbdev using const_pointer = typename base_type::const_pointer;
26449e08aacStbbdev using iterator = typename base_type::iterator;
26549e08aacStbbdev using const_iterator = typename base_type::const_iterator;
26649e08aacStbbdev using local_iterator = typename base_type::local_iterator;
26749e08aacStbbdev using const_local_iterator = typename base_type::const_local_iterator;
26849e08aacStbbdev using node_type = typename base_type::node_type;
26949e08aacStbbdev
27049e08aacStbbdev // Include constructors of base type
27149e08aacStbbdev using base_type::base_type;
27249e08aacStbbdev using base_type::insert;
27349e08aacStbbdev
274d86ed7fbStbbdev // Required for implicit deduction guides
275d86ed7fbStbbdev concurrent_unordered_multimap() = default;
276d86ed7fbStbbdev concurrent_unordered_multimap( const concurrent_unordered_multimap& ) = default;
concurrent_unordered_multimap(const concurrent_unordered_multimap & other,const allocator_type & alloc)277d86ed7fbStbbdev concurrent_unordered_multimap( const concurrent_unordered_multimap& other, const allocator_type& alloc ) : base_type(other, alloc) {}
278d86ed7fbStbbdev concurrent_unordered_multimap( concurrent_unordered_multimap&& ) = default;
concurrent_unordered_multimap(concurrent_unordered_multimap && other,const allocator_type & alloc)279d86ed7fbStbbdev concurrent_unordered_multimap( concurrent_unordered_multimap&& other, const allocator_type& alloc ) : base_type(std::move(other), alloc) {}
280d86ed7fbStbbdev // Required to respect the rule of 5
281d86ed7fbStbbdev concurrent_unordered_multimap& operator=( const concurrent_unordered_multimap& ) = default;
282d86ed7fbStbbdev concurrent_unordered_multimap& operator=( concurrent_unordered_multimap&& ) = default;
283d86ed7fbStbbdev
2842713d41eSIlya Isaev concurrent_unordered_multimap& operator=( std::initializer_list<value_type> il ) {
2852713d41eSIlya Isaev base_type::operator= (il);
2862713d41eSIlya Isaev return *this;
2872713d41eSIlya Isaev }
2882713d41eSIlya Isaev
28949e08aacStbbdev template <typename P>
29049e08aacStbbdev typename std::enable_if<std::is_constructible<value_type, P&&>::value,
insert(P && value)29149e08aacStbbdev std::pair<iterator, bool>>::type insert( P&& value ) {
29249e08aacStbbdev return this->emplace(std::forward<P>(value));
29349e08aacStbbdev }
29449e08aacStbbdev
29549e08aacStbbdev template<typename P>
29649e08aacStbbdev typename std::enable_if<std::is_constructible<value_type, P&&>::value,
insert(const_iterator hint,P && value)29749e08aacStbbdev iterator>::type insert( const_iterator hint, P&& value ) {
29849e08aacStbbdev return this->emplace_hint(hint, std::forward<P&&>(value));
29949e08aacStbbdev }
30049e08aacStbbdev
30149e08aacStbbdev template <typename OtherHash, typename OtherKeyEqual>
merge(concurrent_unordered_map<key_type,mapped_type,OtherHash,OtherKeyEqual,allocator_type> & source)30249e08aacStbbdev void merge( concurrent_unordered_map<key_type, mapped_type, OtherHash, OtherKeyEqual, allocator_type>& source ) {
30349e08aacStbbdev this->internal_merge(source);
30449e08aacStbbdev }
30549e08aacStbbdev
30649e08aacStbbdev template <typename OtherHash, typename OtherKeyEqual>
merge(concurrent_unordered_map<key_type,mapped_type,OtherHash,OtherKeyEqual,allocator_type> && source)30749e08aacStbbdev void merge( concurrent_unordered_map<key_type, mapped_type, OtherHash, OtherKeyEqual, allocator_type>&& source ) {
30849e08aacStbbdev this->internal_merge(std::move(source));
30949e08aacStbbdev }
31049e08aacStbbdev
31149e08aacStbbdev template <typename OtherHash, typename OtherKeyEqual>
merge(concurrent_unordered_multimap<key_type,mapped_type,OtherHash,OtherKeyEqual,allocator_type> & source)31249e08aacStbbdev void merge( concurrent_unordered_multimap<key_type, mapped_type, OtherHash, OtherKeyEqual, allocator_type>& source ) {
31349e08aacStbbdev this->internal_merge(source);
31449e08aacStbbdev }
31549e08aacStbbdev
31649e08aacStbbdev template <typename OtherHash, typename OtherKeyEqual>
merge(concurrent_unordered_multimap<key_type,mapped_type,OtherHash,OtherKeyEqual,allocator_type> && source)31749e08aacStbbdev void merge( concurrent_unordered_multimap<key_type, mapped_type, OtherHash, OtherKeyEqual, allocator_type>&& source ) {
31849e08aacStbbdev this->internal_merge(std::move(source));
31949e08aacStbbdev }
32049e08aacStbbdev }; // class concurrent_unordered_multimap
32149e08aacStbbdev
32249e08aacStbbdev #if __TBB_CPP17_DEDUCTION_GUIDES_PRESENT
32349e08aacStbbdev
324d86ed7fbStbbdev template <typename It,
325d86ed7fbStbbdev typename Hash = std::hash<iterator_key_t<It>>,
326d86ed7fbStbbdev typename KeyEq = std::equal_to<iterator_key_t<It>>,
327d86ed7fbStbbdev typename Alloc = tbb::tbb_allocator<iterator_alloc_pair_t<It>>,
328d86ed7fbStbbdev typename = std::enable_if_t<is_input_iterator_v<It>>,
329d86ed7fbStbbdev typename = std::enable_if_t<is_allocator_v<Alloc>>,
330d86ed7fbStbbdev typename = std::enable_if_t<!is_allocator_v<Hash>>,
331d86ed7fbStbbdev typename = std::enable_if_t<!is_allocator_v<KeyEq>>,
332d86ed7fbStbbdev typename = std::enable_if_t<!std::is_integral_v<Hash>>>
333d86ed7fbStbbdev concurrent_unordered_multimap( It, It, std::size_t = {}, Hash = Hash(), KeyEq = KeyEq(), Alloc = Alloc() )
334d86ed7fbStbbdev -> concurrent_unordered_multimap<iterator_key_t<It>, iterator_mapped_t<It>, Hash, KeyEq, Alloc>;
33549e08aacStbbdev
336d86ed7fbStbbdev template <typename Key, typename T,
337d86ed7fbStbbdev typename Hash = std::hash<std::remove_const_t<Key>>,
338d86ed7fbStbbdev typename KeyEq = std::equal_to<std::remove_const_t<Key>>,
339d86ed7fbStbbdev typename Alloc = tbb::tbb_allocator<std::pair<const Key, T>>,
340d86ed7fbStbbdev typename = std::enable_if_t<is_allocator_v<Alloc>>,
341d86ed7fbStbbdev typename = std::enable_if_t<!is_allocator_v<Hash>>,
342d86ed7fbStbbdev typename = std::enable_if_t<!is_allocator_v<KeyEq>>,
343d86ed7fbStbbdev typename = std::enable_if_t<!std::is_integral_v<Hash>>>
344d86ed7fbStbbdev concurrent_unordered_multimap( std::initializer_list<std::pair<Key, T>>, std::size_t = {},
345d86ed7fbStbbdev Hash = Hash(), KeyEq = KeyEq(), Alloc = Alloc() )
346d86ed7fbStbbdev -> concurrent_unordered_multimap<std::remove_const_t<Key>, T, Hash, KeyEq, Alloc>;
34749e08aacStbbdev
348d86ed7fbStbbdev template <typename It, typename Alloc,
349d86ed7fbStbbdev typename = std::enable_if_t<is_input_iterator_v<It>>,
350d86ed7fbStbbdev typename = std::enable_if_t<is_allocator_v<Alloc>>>
351d86ed7fbStbbdev concurrent_unordered_multimap( It, It, std::size_t, Alloc )
352d86ed7fbStbbdev -> concurrent_unordered_multimap<iterator_key_t<It>, iterator_mapped_t<It>,
353d86ed7fbStbbdev std::hash<iterator_key_t<It>>,
354d86ed7fbStbbdev std::equal_to<iterator_key_t<It>>, Alloc>;
35549e08aacStbbdev
356d86ed7fbStbbdev template <typename It, typename Hash, typename Alloc,
357d86ed7fbStbbdev typename = std::enable_if_t<is_input_iterator_v<It>>,
358d86ed7fbStbbdev typename = std::enable_if_t<is_allocator_v<Alloc>>,
359d86ed7fbStbbdev typename = std::enable_if_t<!is_allocator_v<Hash>>,
360d86ed7fbStbbdev typename = std::enable_if_t<!std::is_integral_v<Hash>>>
361d86ed7fbStbbdev concurrent_unordered_multimap( It, It, std::size_t, Hash, Alloc )
362d86ed7fbStbbdev -> concurrent_unordered_multimap<iterator_key_t<It>, iterator_mapped_t<It>, Hash,
363d86ed7fbStbbdev std::equal_to<iterator_key_t<It>>, Alloc>;
36449e08aacStbbdev
365d86ed7fbStbbdev template <typename Key, typename T, typename Alloc,
366d86ed7fbStbbdev typename = std::enable_if_t<is_allocator_v<Alloc>>>
367d86ed7fbStbbdev concurrent_unordered_multimap( std::initializer_list<std::pair<Key, T>>, std::size_t, Alloc )
368d86ed7fbStbbdev -> concurrent_unordered_multimap<std::remove_const_t<Key>, T, std::hash<std::remove_const_t<Key>>,
369d86ed7fbStbbdev std::equal_to<std::remove_const_t<Key>>, Alloc>;
370d86ed7fbStbbdev
371d86ed7fbStbbdev template <typename Key, typename T, typename Alloc,
372d86ed7fbStbbdev typename = std::enable_if_t<is_allocator_v<Alloc>>>
373d86ed7fbStbbdev concurrent_unordered_multimap( std::initializer_list<std::pair<Key, T>>, Alloc )
374d86ed7fbStbbdev -> concurrent_unordered_multimap<std::remove_const_t<Key>, T, std::hash<std::remove_const_t<Key>>,
375d86ed7fbStbbdev std::equal_to<std::remove_const_t<Key>>, Alloc>;
376d86ed7fbStbbdev
377d86ed7fbStbbdev template <typename Key, typename T, typename Hash, typename Alloc,
378d86ed7fbStbbdev typename = std::enable_if_t<is_allocator_v<Alloc>>,
379d86ed7fbStbbdev typename = std::enable_if_t<!is_allocator_v<Hash>>,
380d86ed7fbStbbdev typename = std::enable_if_t<!std::is_integral_v<Hash>>>
381d86ed7fbStbbdev concurrent_unordered_multimap( std::initializer_list<std::pair<Key, T>>, std::size_t, Hash, Alloc )
382d86ed7fbStbbdev -> concurrent_unordered_multimap<std::remove_const_t<Key>, T, Hash,
383d86ed7fbStbbdev std::equal_to<std::remove_const_t<Key>>, Alloc>;
38449e08aacStbbdev
385*3fbdbb8bSkboyarinov #if __APPLE__ && __TBB_CLANG_VERSION == 100000
386*3fbdbb8bSkboyarinov // An explicit deduction guide is required for copy/move constructor with allocator for APPLE LLVM 10.0.0
387*3fbdbb8bSkboyarinov // due to an issue with generating an implicit deduction guide for these constructors under several strange surcumstances.
388*3fbdbb8bSkboyarinov // Currently the issue takes place because the last template parameter for Traits is boolean, it should not affect the deduction guides
389*3fbdbb8bSkboyarinov // The issue reproduces only on this version of the compiler
390*3fbdbb8bSkboyarinov template <typename Key, typename T, typename Hash, typename KeyEq, typename Alloc>
391*3fbdbb8bSkboyarinov concurrent_unordered_multimap( concurrent_unordered_multimap<Key, T, Hash, KeyEq, Alloc>, Alloc )
392*3fbdbb8bSkboyarinov -> concurrent_unordered_multimap<Key, T, Hash, KeyEq, Alloc>;
393*3fbdbb8bSkboyarinov #endif
39449e08aacStbbdev #endif // __TBB_CPP17_DEDUCTION_GUIDES_PRESENT
39549e08aacStbbdev
39649e08aacStbbdev template <typename Key, typename T, typename Hash, typename KeyEqual, typename Allocator>
swap(concurrent_unordered_multimap<Key,T,Hash,KeyEqual,Allocator> & lhs,concurrent_unordered_multimap<Key,T,Hash,KeyEqual,Allocator> & rhs)39749e08aacStbbdev void swap( concurrent_unordered_multimap<Key, T, Hash, KeyEqual, Allocator>& lhs,
39849e08aacStbbdev concurrent_unordered_multimap<Key, T, Hash, KeyEqual, Allocator>& rhs ) {
39949e08aacStbbdev lhs.swap(rhs);
40049e08aacStbbdev }
40149e08aacStbbdev
40249e08aacStbbdev } // namespace d1
40349e08aacStbbdev } // namespace detail
40449e08aacStbbdev
40549e08aacStbbdev inline namespace v1 {
40649e08aacStbbdev
40749e08aacStbbdev using detail::d1::concurrent_unordered_map;
40849e08aacStbbdev using detail::d1::concurrent_unordered_multimap;
40949e08aacStbbdev using detail::split;
41049e08aacStbbdev
41149e08aacStbbdev } // inline namespace v1
41249e08aacStbbdev } // namespace tbb
41349e08aacStbbdev
41449e08aacStbbdev #endif // __TBB_concurrent_unordered_map_H
415