149e08aacStbbdev /*
2b15aabb3Stbbdev Copyright (c) 2019-2021 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_map_H
1849e08aacStbbdev #define __TBB_concurrent_map_H
1949e08aacStbbdev
2049e08aacStbbdev #include "detail/_namespace_injection.h"
2149e08aacStbbdev #include "detail/_concurrent_skip_list.h"
2249e08aacStbbdev #include "tbb_allocator.h"
2349e08aacStbbdev #include <functional>
2449e08aacStbbdev #include <tuple>
2549e08aacStbbdev #include <utility>
2649e08aacStbbdev
2749e08aacStbbdev namespace tbb {
2849e08aacStbbdev namespace detail {
29d8251013SAnton Potapov namespace d2 {
3049e08aacStbbdev
3149e08aacStbbdev template<typename Key, typename Value, typename KeyCompare, typename RandomGenerator,
3249e08aacStbbdev typename Allocator, bool AllowMultimapping>
3349e08aacStbbdev struct map_traits {
3449e08aacStbbdev static constexpr std::size_t max_level = RandomGenerator::max_level;
3549e08aacStbbdev using random_level_generator_type = RandomGenerator;
3649e08aacStbbdev using key_type = Key;
3749e08aacStbbdev using mapped_type = Value;
3849e08aacStbbdev using compare_type = KeyCompare;
3949e08aacStbbdev using value_type = std::pair<const key_type, mapped_type>;
4049e08aacStbbdev using reference = value_type&;
4149e08aacStbbdev using const_reference = const value_type&;
4249e08aacStbbdev using allocator_type = Allocator;
4349e08aacStbbdev
4449e08aacStbbdev static constexpr bool allow_multimapping = AllowMultimapping;
4549e08aacStbbdev
4649e08aacStbbdev class value_compare {
4749e08aacStbbdev public:
operatormap_traits4849e08aacStbbdev bool operator()(const value_type& lhs, const value_type& rhs) const {
4949e08aacStbbdev return comp(lhs.first, rhs.first);
5049e08aacStbbdev }
5149e08aacStbbdev
5249e08aacStbbdev protected:
value_comparemap_traits5349e08aacStbbdev value_compare(compare_type c) : comp(c) {}
5449e08aacStbbdev
5549e08aacStbbdev friend struct map_traits;
5649e08aacStbbdev
5749e08aacStbbdev compare_type comp;
5849e08aacStbbdev };
5949e08aacStbbdev
value_compmap_traits6049e08aacStbbdev static value_compare value_comp(compare_type comp) { return value_compare(comp); }
6149e08aacStbbdev
get_keymap_traits6249e08aacStbbdev static const key_type& get_key(const_reference val) {
6349e08aacStbbdev return val.first;
6449e08aacStbbdev }
6549e08aacStbbdev }; // struct map_traits
6649e08aacStbbdev
6749e08aacStbbdev template <typename Key, typename Value, typename Compare, typename Allocator>
6849e08aacStbbdev class concurrent_multimap;
6949e08aacStbbdev
7049e08aacStbbdev template <typename Key, typename Value, typename Compare = std::less<Key>, typename Allocator = tbb::tbb_allocator<std::pair<const Key, Value>>>
7149e08aacStbbdev class concurrent_map : public concurrent_skip_list<map_traits<Key, Value, Compare, concurrent_geometric_level_generator<32>, Allocator, false>> {
7249e08aacStbbdev using base_type = concurrent_skip_list<map_traits<Key, Value, Compare, concurrent_geometric_level_generator<32>, Allocator, false>>;
7349e08aacStbbdev public:
7449e08aacStbbdev using key_type = Key;
7549e08aacStbbdev using mapped_type = Value;
7649e08aacStbbdev using value_type = typename base_type::value_type;
7749e08aacStbbdev using size_type = typename base_type::size_type;
7849e08aacStbbdev using difference_type = typename base_type::difference_type;
7949e08aacStbbdev using key_compare = Compare;
8049e08aacStbbdev using value_compare = typename base_type::value_compare;
8149e08aacStbbdev using allocator_type = Allocator;
8249e08aacStbbdev
8349e08aacStbbdev using reference = typename base_type::reference;
8449e08aacStbbdev using const_reference = typename base_type::const_reference;
8549e08aacStbbdev using pointer = typename base_type::pointer;
8649e08aacStbbdev using const_pointer = typename base_type::const_pointer;
8749e08aacStbbdev
8849e08aacStbbdev using iterator = typename base_type::iterator;
8949e08aacStbbdev using const_iterator = typename base_type::const_iterator;
9049e08aacStbbdev
9149e08aacStbbdev using node_type = typename base_type::node_type;
9249e08aacStbbdev
9349e08aacStbbdev // Include constructors of base type
9449e08aacStbbdev using base_type::base_type;
9549e08aacStbbdev
96d86ed7fbStbbdev // Required for implicit deduction guides
97d86ed7fbStbbdev concurrent_map() = default;
98d86ed7fbStbbdev concurrent_map( const concurrent_map& ) = default;
concurrent_map(const concurrent_map & other,const allocator_type & alloc)99d86ed7fbStbbdev concurrent_map( const concurrent_map& other, const allocator_type& alloc ) : base_type(other, alloc) {}
100d86ed7fbStbbdev concurrent_map( concurrent_map&& ) = default;
concurrent_map(concurrent_map && other,const allocator_type & alloc)101d86ed7fbStbbdev concurrent_map( concurrent_map&& other, const allocator_type& alloc ) : base_type(std::move(other), alloc) {}
102d86ed7fbStbbdev // Required to respect the rule of 5
103d86ed7fbStbbdev concurrent_map& operator=( const concurrent_map& ) = default;
104d86ed7fbStbbdev concurrent_map& operator=( concurrent_map&& ) = default;
105d86ed7fbStbbdev
106*2713d41eSIlya Isaev concurrent_map& operator=( std::initializer_list<value_type> il ) {
107*2713d41eSIlya Isaev base_type::operator= (il);
108*2713d41eSIlya Isaev return *this;
109*2713d41eSIlya Isaev }
110*2713d41eSIlya Isaev
11149e08aacStbbdev // Observers
at(const key_type & key)11249e08aacStbbdev mapped_type& at(const key_type& key) {
11349e08aacStbbdev iterator it = this->find(key);
11449e08aacStbbdev
11549e08aacStbbdev if (it == this->end()) {
11649e08aacStbbdev throw_exception(exception_id::invalid_key);
11749e08aacStbbdev }
11849e08aacStbbdev return it->second;
11949e08aacStbbdev }
12049e08aacStbbdev
at(const key_type & key)12149e08aacStbbdev const mapped_type& at(const key_type& key) const {
12249e08aacStbbdev return const_cast<concurrent_map*>(this)->at(key);
12349e08aacStbbdev }
12449e08aacStbbdev
12549e08aacStbbdev mapped_type& operator[](const key_type& key) {
12649e08aacStbbdev iterator it = this->find(key);
12749e08aacStbbdev
12849e08aacStbbdev if (it == this->end()) {
12949e08aacStbbdev it = this->emplace(std::piecewise_construct, std::forward_as_tuple(key), std::tuple<>()).first;
13049e08aacStbbdev }
13149e08aacStbbdev return it->second;
13249e08aacStbbdev }
13349e08aacStbbdev
13449e08aacStbbdev mapped_type& operator[](key_type&& key) {
13549e08aacStbbdev iterator it = this->find(key);
13649e08aacStbbdev
13749e08aacStbbdev if (it == this->end()) {
13849e08aacStbbdev it = this->emplace(std::piecewise_construct, std::forward_as_tuple(std::move(key)), std::tuple<>()).first;
13949e08aacStbbdev }
14049e08aacStbbdev return it->second;
14149e08aacStbbdev }
14249e08aacStbbdev
14349e08aacStbbdev using base_type::insert;
14449e08aacStbbdev
14549e08aacStbbdev template <typename P>
14649e08aacStbbdev typename std::enable_if<std::is_constructible<value_type, P&&>::value,
insert(P && value)14749e08aacStbbdev std::pair<iterator, bool>>::type insert( P&& value )
14849e08aacStbbdev {
14949e08aacStbbdev return this->emplace(std::forward<P>(value));
15049e08aacStbbdev }
15149e08aacStbbdev
15249e08aacStbbdev template <typename P>
15349e08aacStbbdev typename std::enable_if<std::is_constructible<value_type, P&&>::value,
insert(const_iterator hint,P && value)15449e08aacStbbdev iterator>::type insert( const_iterator hint, P&& value )
15549e08aacStbbdev {
15649e08aacStbbdev return this->emplace_hint(hint, std::forward<P>(value));
15749e08aacStbbdev }
15849e08aacStbbdev
15949e08aacStbbdev template<typename OtherCompare>
merge(concurrent_map<key_type,mapped_type,OtherCompare,Allocator> & source)16049e08aacStbbdev void merge(concurrent_map<key_type, mapped_type, OtherCompare, Allocator>& source) {
16149e08aacStbbdev this->internal_merge(source);
16249e08aacStbbdev }
16349e08aacStbbdev
16449e08aacStbbdev template<typename OtherCompare>
merge(concurrent_map<key_type,mapped_type,OtherCompare,Allocator> && source)16549e08aacStbbdev void merge(concurrent_map<key_type, mapped_type, OtherCompare, Allocator>&& source) {
16649e08aacStbbdev this->internal_merge(std::move(source));
16749e08aacStbbdev }
16849e08aacStbbdev
16949e08aacStbbdev template<typename OtherCompare>
merge(concurrent_multimap<key_type,mapped_type,OtherCompare,Allocator> & source)17049e08aacStbbdev void merge(concurrent_multimap<key_type, mapped_type, OtherCompare, Allocator>& source) {
17149e08aacStbbdev this->internal_merge(source);
17249e08aacStbbdev }
17349e08aacStbbdev
17449e08aacStbbdev template<typename OtherCompare>
merge(concurrent_multimap<key_type,mapped_type,OtherCompare,Allocator> && source)17549e08aacStbbdev void merge(concurrent_multimap<key_type, mapped_type, OtherCompare, Allocator>&& source) {
17649e08aacStbbdev this->internal_merge(std::move(source));
17749e08aacStbbdev }
17849e08aacStbbdev }; // class concurrent_map
17949e08aacStbbdev
18049e08aacStbbdev #if __TBB_CPP17_DEDUCTION_GUIDES_PRESENT
18149e08aacStbbdev
182d86ed7fbStbbdev template <typename It,
183d86ed7fbStbbdev typename Comp = std::less<iterator_key_t<It>>,
184d86ed7fbStbbdev typename Alloc = tbb::tbb_allocator<iterator_alloc_pair_t<It>>,
185d86ed7fbStbbdev typename = std::enable_if_t<is_input_iterator_v<It>>,
186d86ed7fbStbbdev typename = std::enable_if_t<is_allocator_v<Alloc>>,
187d86ed7fbStbbdev typename = std::enable_if_t<!is_allocator_v<Comp>>>
188d86ed7fbStbbdev concurrent_map( It, It, Comp = Comp(), Alloc = Alloc() )
189d86ed7fbStbbdev -> concurrent_map<iterator_key_t<It>, iterator_mapped_t<It>, Comp, Alloc>;
19049e08aacStbbdev
191d86ed7fbStbbdev template <typename Key, typename T,
192d86ed7fbStbbdev typename Comp = std::less<std::remove_const_t<Key>>,
193d86ed7fbStbbdev typename Alloc = tbb::tbb_allocator<std::pair<const Key, T>>,
194d86ed7fbStbbdev typename = std::enable_if_t<is_allocator_v<Alloc>>,
195d86ed7fbStbbdev typename = std::enable_if_t<!is_allocator_v<Comp>>>
196d86ed7fbStbbdev concurrent_map( std::initializer_list<std::pair<Key, T>>, Comp = Comp(), Alloc = Alloc() )
197d86ed7fbStbbdev -> concurrent_map<std::remove_const_t<Key>, T, Comp, Alloc>;
19849e08aacStbbdev
199d86ed7fbStbbdev template <typename It, typename Alloc,
200d86ed7fbStbbdev typename = std::enable_if_t<is_input_iterator_v<It>>,
201d86ed7fbStbbdev typename = std::enable_if_t<is_allocator_v<Alloc>>>
202d86ed7fbStbbdev concurrent_map( It, It, Alloc )
203d86ed7fbStbbdev -> concurrent_map<iterator_key_t<It>, iterator_mapped_t<It>,
204d86ed7fbStbbdev std::less<iterator_key_t<It>>, Alloc>;
205d86ed7fbStbbdev
206d86ed7fbStbbdev template <typename Key, typename T, typename Alloc,
207d86ed7fbStbbdev typename = std::enable_if_t<is_allocator_v<Alloc>>>
208d86ed7fbStbbdev concurrent_map( std::initializer_list<std::pair<Key, T>>, Alloc )
209d86ed7fbStbbdev -> concurrent_map<std::remove_const_t<Key>, T, std::less<std::remove_const_t<Key>>, Alloc>;
21049e08aacStbbdev
21149e08aacStbbdev #endif // __TBB_CPP17_DEDUCTION_GUIDES_PRESENT
21249e08aacStbbdev
21349e08aacStbbdev template <typename Key, typename Value, typename Compare, typename Allocator>
swap(concurrent_map<Key,Value,Compare,Allocator> & lhs,concurrent_map<Key,Value,Compare,Allocator> & rhs)21449e08aacStbbdev void swap( concurrent_map<Key, Value, Compare, Allocator>& lhs,
21549e08aacStbbdev concurrent_map<Key, Value, Compare, Allocator>& rhs )
21649e08aacStbbdev {
21749e08aacStbbdev lhs.swap(rhs);
21849e08aacStbbdev }
21949e08aacStbbdev
22049e08aacStbbdev template <typename Key, typename Value, typename Compare = std::less<Key>, typename Allocator = tbb::tbb_allocator<std::pair<const Key, Value>>>
22149e08aacStbbdev class concurrent_multimap : public concurrent_skip_list<map_traits<Key, Value, Compare, concurrent_geometric_level_generator<32>, Allocator, true>> {
22249e08aacStbbdev using base_type = concurrent_skip_list<map_traits<Key, Value, Compare, concurrent_geometric_level_generator<32>, Allocator, true>>;
22349e08aacStbbdev public:
22449e08aacStbbdev using key_type = Key;
22549e08aacStbbdev using mapped_type = Value;
22649e08aacStbbdev using value_type = typename base_type::value_type;
22749e08aacStbbdev using size_type = typename base_type::size_type;
22849e08aacStbbdev using difference_type = typename base_type::difference_type;
22949e08aacStbbdev using key_compare = Compare;
23049e08aacStbbdev using value_compare = typename base_type::value_compare;
23149e08aacStbbdev using allocator_type = Allocator;
23249e08aacStbbdev
23349e08aacStbbdev using reference = typename base_type::reference;
23449e08aacStbbdev using const_reference = typename base_type::const_reference;
23549e08aacStbbdev using pointer = typename base_type::pointer;
23649e08aacStbbdev using const_pointer = typename base_type::const_pointer;
23749e08aacStbbdev
23849e08aacStbbdev using iterator = typename base_type::iterator;
23949e08aacStbbdev using const_iterator = typename base_type::const_iterator;
24049e08aacStbbdev
24149e08aacStbbdev using node_type = typename base_type::node_type;
24249e08aacStbbdev
24349e08aacStbbdev // Include constructors of base_type
24449e08aacStbbdev using base_type::base_type;
24549e08aacStbbdev using base_type::insert;
24649e08aacStbbdev
247d86ed7fbStbbdev // Required for implicit deduction guides
248d86ed7fbStbbdev concurrent_multimap() = default;
249d86ed7fbStbbdev concurrent_multimap( const concurrent_multimap& ) = default;
concurrent_multimap(const concurrent_multimap & other,const allocator_type & alloc)250d86ed7fbStbbdev concurrent_multimap( const concurrent_multimap& other, const allocator_type& alloc ) : base_type(other, alloc) {}
251d86ed7fbStbbdev concurrent_multimap( concurrent_multimap&& ) = default;
concurrent_multimap(concurrent_multimap && other,const allocator_type & alloc)252d86ed7fbStbbdev concurrent_multimap( concurrent_multimap&& other, const allocator_type& alloc ) : base_type(std::move(other), alloc) {}
253d86ed7fbStbbdev // Required to respect the rule of 5
254d86ed7fbStbbdev concurrent_multimap& operator=( const concurrent_multimap& ) = default;
255d86ed7fbStbbdev concurrent_multimap& operator=( concurrent_multimap&& ) = default;
256d86ed7fbStbbdev
257*2713d41eSIlya Isaev concurrent_multimap& operator=( std::initializer_list<value_type> il ) {
258*2713d41eSIlya Isaev base_type::operator= (il);
259*2713d41eSIlya Isaev return *this;
260*2713d41eSIlya Isaev }
261*2713d41eSIlya Isaev
26249e08aacStbbdev template <typename P>
26349e08aacStbbdev typename std::enable_if<std::is_constructible<value_type, P&&>::value,
insert(P && value)26449e08aacStbbdev std::pair<iterator, bool>>::type insert( P&& value )
26549e08aacStbbdev {
26649e08aacStbbdev return this->emplace(std::forward<P>(value));
26749e08aacStbbdev }
26849e08aacStbbdev
26949e08aacStbbdev template <typename P>
27049e08aacStbbdev typename std::enable_if<std::is_constructible<value_type, P&&>::value,
insert(const_iterator hint,P && value)27149e08aacStbbdev iterator>::type insert( const_iterator hint, P&& value )
27249e08aacStbbdev {
27349e08aacStbbdev return this->emplace_hint(hint, std::forward<P>(value));
27449e08aacStbbdev }
27549e08aacStbbdev
27649e08aacStbbdev template<typename OtherCompare>
merge(concurrent_multimap<key_type,mapped_type,OtherCompare,Allocator> & source)27749e08aacStbbdev void merge(concurrent_multimap<key_type, mapped_type, OtherCompare, Allocator>& source) {
27849e08aacStbbdev this->internal_merge(source);
27949e08aacStbbdev }
28049e08aacStbbdev
28149e08aacStbbdev template<typename OtherCompare>
merge(concurrent_multimap<key_type,mapped_type,OtherCompare,Allocator> && source)28249e08aacStbbdev void merge(concurrent_multimap<key_type, mapped_type, OtherCompare, Allocator>&& source) {
28349e08aacStbbdev this->internal_merge(std::move(source));
28449e08aacStbbdev }
28549e08aacStbbdev
28649e08aacStbbdev template<typename OtherCompare>
merge(concurrent_map<key_type,mapped_type,OtherCompare,Allocator> & source)28749e08aacStbbdev void merge(concurrent_map<key_type, mapped_type, OtherCompare, Allocator>& source) {
28849e08aacStbbdev this->internal_merge(source);
28949e08aacStbbdev }
29049e08aacStbbdev
29149e08aacStbbdev template<typename OtherCompare>
merge(concurrent_map<key_type,mapped_type,OtherCompare,Allocator> && source)29249e08aacStbbdev void merge(concurrent_map<key_type, mapped_type, OtherCompare, Allocator>&& source) {
29349e08aacStbbdev this->internal_merge(std::move(source));
29449e08aacStbbdev }
29549e08aacStbbdev }; // class concurrent_multimap
29649e08aacStbbdev
29749e08aacStbbdev #if __TBB_CPP17_DEDUCTION_GUIDES_PRESENT
29849e08aacStbbdev
299d86ed7fbStbbdev template <typename It,
300d86ed7fbStbbdev typename Comp = std::less<iterator_key_t<It>>,
301d86ed7fbStbbdev typename Alloc = tbb::tbb_allocator<iterator_alloc_pair_t<It>>,
302d86ed7fbStbbdev typename = std::enable_if_t<is_input_iterator_v<It>>,
303d86ed7fbStbbdev typename = std::enable_if_t<is_allocator_v<Alloc>>,
304d86ed7fbStbbdev typename = std::enable_if_t<!is_allocator_v<Comp>>>
305d86ed7fbStbbdev concurrent_multimap( It, It, Comp = Comp(), Alloc = Alloc() )
306d86ed7fbStbbdev -> concurrent_multimap<iterator_key_t<It>, iterator_mapped_t<It>, Comp, Alloc>;
30749e08aacStbbdev
308d86ed7fbStbbdev template <typename Key, typename T,
309d86ed7fbStbbdev typename Comp = std::less<std::remove_const_t<Key>>,
310d86ed7fbStbbdev typename Alloc = tbb::tbb_allocator<std::pair<const Key, T>>,
311d86ed7fbStbbdev typename = std::enable_if_t<is_allocator_v<Alloc>>,
312d86ed7fbStbbdev typename = std::enable_if_t<!is_allocator_v<Comp>>>
313d86ed7fbStbbdev concurrent_multimap( std::initializer_list<std::pair<Key, T>>, Comp = Comp(), Alloc = Alloc() )
314d86ed7fbStbbdev -> concurrent_multimap<std::remove_const_t<Key>, T, Comp, Alloc>;
315d86ed7fbStbbdev
316d86ed7fbStbbdev template <typename It, typename Alloc,
317d86ed7fbStbbdev typename = std::enable_if_t<is_input_iterator_v<It>>,
318d86ed7fbStbbdev typename = std::enable_if_t<is_allocator_v<Alloc>>>
319d86ed7fbStbbdev concurrent_multimap( It, It, Alloc )
320d86ed7fbStbbdev -> concurrent_multimap<iterator_key_t<It>, iterator_mapped_t<It>,
321d86ed7fbStbbdev std::less<iterator_key_t<It>>, Alloc>;
322d86ed7fbStbbdev
323d86ed7fbStbbdev template <typename Key, typename T, typename Alloc,
324d86ed7fbStbbdev typename = std::enable_if_t<is_allocator_v<Alloc>>>
325d86ed7fbStbbdev concurrent_multimap( std::initializer_list<std::pair<Key, T>>, Alloc )
326d86ed7fbStbbdev -> concurrent_multimap<std::remove_const_t<Key>, T, std::less<std::remove_const_t<Key>>, Alloc>;
327d86ed7fbStbbdev
32849e08aacStbbdev
32949e08aacStbbdev #endif // __TBB_CPP17_DEDUCTION_GUIDES_PRESENT
33049e08aacStbbdev
33149e08aacStbbdev template <typename Key, typename Value, typename Compare, typename Allocator>
swap(concurrent_multimap<Key,Value,Compare,Allocator> & lhs,concurrent_multimap<Key,Value,Compare,Allocator> & rhs)33249e08aacStbbdev void swap( concurrent_multimap<Key, Value, Compare, Allocator>& lhs,
33349e08aacStbbdev concurrent_multimap<Key, Value, Compare, Allocator>& rhs )
33449e08aacStbbdev {
33549e08aacStbbdev lhs.swap(rhs);
33649e08aacStbbdev }
33749e08aacStbbdev
338d8251013SAnton Potapov } // namespace d2
33949e08aacStbbdev } // namespace detail
34049e08aacStbbdev
34149e08aacStbbdev inline namespace v1 {
34249e08aacStbbdev
343d8251013SAnton Potapov using detail::d2::concurrent_map;
344d8251013SAnton Potapov using detail::d2::concurrent_multimap;
34549e08aacStbbdev using detail::split;
34649e08aacStbbdev
34749e08aacStbbdev } // inline namespace v1
34849e08aacStbbdev } // namespace tbb
34949e08aacStbbdev
35049e08aacStbbdev #endif // __TBB_concurrent_map_H
351