1 /* 2 Copyright (c) 2019-2020 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_map_H 18 #define __TBB_concurrent_map_H 19 20 #include "detail/_namespace_injection.h" 21 #include "detail/_concurrent_skip_list.h" 22 #include "tbb_allocator.h" 23 #include <functional> 24 #include <tuple> 25 #include <utility> 26 27 namespace tbb { 28 namespace detail { 29 namespace d1 { 30 31 template<typename Key, typename Value, typename KeyCompare, typename RandomGenerator, 32 typename Allocator, bool AllowMultimapping> 33 struct map_traits { 34 static constexpr std::size_t max_level = RandomGenerator::max_level; 35 using random_level_generator_type = RandomGenerator; 36 using key_type = Key; 37 using mapped_type = Value; 38 using compare_type = KeyCompare; 39 using value_type = std::pair<const key_type, mapped_type>; 40 using reference = value_type&; 41 using const_reference = const value_type&; 42 using allocator_type = Allocator; 43 44 static constexpr bool allow_multimapping = AllowMultimapping; 45 46 class value_compare { 47 public: 48 bool operator()(const value_type& lhs, const value_type& rhs) const { 49 return comp(lhs.first, rhs.first); 50 } 51 52 protected: 53 value_compare(compare_type c) : comp(c) {} 54 55 friend struct map_traits; 56 57 compare_type comp; 58 }; 59 60 static value_compare value_comp(compare_type comp) { return value_compare(comp); } 61 62 static const key_type& get_key(const_reference val) { 63 return val.first; 64 } 65 }; // struct map_traits 66 67 template <typename Key, typename Value, typename Compare, typename Allocator> 68 class concurrent_multimap; 69 70 template <typename Key, typename Value, typename Compare = std::less<Key>, typename Allocator = tbb::tbb_allocator<std::pair<const Key, Value>>> 71 class concurrent_map : public concurrent_skip_list<map_traits<Key, Value, Compare, concurrent_geometric_level_generator<32>, Allocator, false>> { 72 using base_type = concurrent_skip_list<map_traits<Key, Value, Compare, concurrent_geometric_level_generator<32>, Allocator, false>>; 73 public: 74 using key_type = Key; 75 using mapped_type = Value; 76 using value_type = typename base_type::value_type; 77 using size_type = typename base_type::size_type; 78 using difference_type = typename base_type::difference_type; 79 using key_compare = Compare; 80 using value_compare = typename base_type::value_compare; 81 using allocator_type = Allocator; 82 83 using reference = typename base_type::reference; 84 using const_reference = typename base_type::const_reference; 85 using pointer = typename base_type::pointer; 86 using const_pointer = typename base_type::const_pointer; 87 88 using iterator = typename base_type::iterator; 89 using const_iterator = typename base_type::const_iterator; 90 91 using node_type = typename base_type::node_type; 92 93 // Include constructors of base type 94 using base_type::base_type; 95 using base_type::operator=; 96 97 // Observers 98 mapped_type& at(const key_type& key) { 99 iterator it = this->find(key); 100 101 if (it == this->end()) { 102 throw_exception(exception_id::invalid_key); 103 } 104 return it->second; 105 } 106 107 const mapped_type& at(const key_type& key) const { 108 return const_cast<concurrent_map*>(this)->at(key); 109 } 110 111 mapped_type& operator[](const key_type& key) { 112 iterator it = this->find(key); 113 114 if (it == this->end()) { 115 it = this->emplace(std::piecewise_construct, std::forward_as_tuple(key), std::tuple<>()).first; 116 } 117 return it->second; 118 } 119 120 mapped_type& operator[](key_type&& key) { 121 iterator it = this->find(key); 122 123 if (it == this->end()) { 124 it = this->emplace(std::piecewise_construct, std::forward_as_tuple(std::move(key)), std::tuple<>()).first; 125 } 126 return it->second; 127 } 128 129 using base_type::insert; 130 131 template <typename P> 132 typename std::enable_if<std::is_constructible<value_type, P&&>::value, 133 std::pair<iterator, bool>>::type insert( P&& value ) 134 { 135 return this->emplace(std::forward<P>(value)); 136 } 137 138 template <typename P> 139 typename std::enable_if<std::is_constructible<value_type, P&&>::value, 140 iterator>::type insert( const_iterator hint, P&& value ) 141 { 142 return this->emplace_hint(hint, std::forward<P>(value)); 143 } 144 145 template<typename OtherCompare> 146 void merge(concurrent_map<key_type, mapped_type, OtherCompare, Allocator>& source) { 147 this->internal_merge(source); 148 } 149 150 template<typename OtherCompare> 151 void merge(concurrent_map<key_type, mapped_type, OtherCompare, Allocator>&& source) { 152 this->internal_merge(std::move(source)); 153 } 154 155 template<typename OtherCompare> 156 void merge(concurrent_multimap<key_type, mapped_type, OtherCompare, Allocator>& source) { 157 this->internal_merge(source); 158 } 159 160 template<typename OtherCompare> 161 void merge(concurrent_multimap<key_type, mapped_type, OtherCompare, Allocator>&& source) { 162 this->internal_merge(std::move(source)); 163 } 164 }; // class concurrent_map 165 166 #if __TBB_CPP17_DEDUCTION_GUIDES_PRESENT 167 168 template<template<typename...> typename Map, typename Key, typename T, typename... Args> 169 using ordered_map_type = Map<Key, T, 170 std::conditional_t< (sizeof...(Args) > 0) && !is_allocator_v<pack_element_t<0, Args...>>, 171 pack_element_t<0, Args...>, 172 std::less<Key>>, 173 std::conditional_t< (sizeof...(Args) > 0) && is_allocator_v<pack_element_t<sizeof...(Args) - 1, Args...>>, 174 pack_element_t<sizeof...(Args) - 1, Args...>, 175 tbb::tbb_allocator<std::pair<const Key, T> > > >; 176 177 template<typename It, typename... Args> 178 concurrent_map(It, It, Args...) 179 -> ordered_map_type<concurrent_map, iterator_key_t<It>, iterator_mapped_t<It>, Args...>; 180 181 template<typename Key, typename T, typename... Args> 182 concurrent_map(std::initializer_list<std::pair<const Key, T>>, Args...) 183 -> ordered_map_type<concurrent_map, Key, T, Args...>; 184 185 #endif // __TBB_CPP17_DEDUCTION_GUIDES_PRESENT 186 187 template <typename Key, typename Value, typename Compare, typename Allocator> 188 void swap( concurrent_map<Key, Value, Compare, Allocator>& lhs, 189 concurrent_map<Key, Value, Compare, Allocator>& rhs ) 190 { 191 lhs.swap(rhs); 192 } 193 194 template <typename Key, typename Value, typename Compare = std::less<Key>, typename Allocator = tbb::tbb_allocator<std::pair<const Key, Value>>> 195 class concurrent_multimap : public concurrent_skip_list<map_traits<Key, Value, Compare, concurrent_geometric_level_generator<32>, Allocator, true>> { 196 using base_type = concurrent_skip_list<map_traits<Key, Value, Compare, concurrent_geometric_level_generator<32>, Allocator, true>>; 197 public: 198 using key_type = Key; 199 using mapped_type = Value; 200 using value_type = typename base_type::value_type; 201 using size_type = typename base_type::size_type; 202 using difference_type = typename base_type::difference_type; 203 using key_compare = Compare; 204 using value_compare = typename base_type::value_compare; 205 using allocator_type = Allocator; 206 207 using reference = typename base_type::reference; 208 using const_reference = typename base_type::const_reference; 209 using pointer = typename base_type::pointer; 210 using const_pointer = typename base_type::const_pointer; 211 212 using iterator = typename base_type::iterator; 213 using const_iterator = typename base_type::const_iterator; 214 215 using node_type = typename base_type::node_type; 216 217 // Include constructors of base_type 218 using base_type::base_type; 219 using base_type::insert; 220 using base_type::operator=; 221 222 template <typename P> 223 typename std::enable_if<std::is_constructible<value_type, P&&>::value, 224 std::pair<iterator, bool>>::type insert( P&& value ) 225 { 226 return this->emplace(std::forward<P>(value)); 227 } 228 229 template <typename P> 230 typename std::enable_if<std::is_constructible<value_type, P&&>::value, 231 iterator>::type insert( const_iterator hint, P&& value ) 232 { 233 return this->emplace_hint(hint, std::forward<P>(value)); 234 } 235 236 template<typename OtherCompare> 237 void merge(concurrent_multimap<key_type, mapped_type, OtherCompare, Allocator>& source) { 238 this->internal_merge(source); 239 } 240 241 template<typename OtherCompare> 242 void merge(concurrent_multimap<key_type, mapped_type, OtherCompare, Allocator>&& source) { 243 this->internal_merge(std::move(source)); 244 } 245 246 template<typename OtherCompare> 247 void merge(concurrent_map<key_type, mapped_type, OtherCompare, Allocator>& source) { 248 this->internal_merge(source); 249 } 250 251 template<typename OtherCompare> 252 void merge(concurrent_map<key_type, mapped_type, OtherCompare, Allocator>&& source) { 253 this->internal_merge(std::move(source)); 254 } 255 }; // class concurrent_multimap 256 257 #if __TBB_CPP17_DEDUCTION_GUIDES_PRESENT 258 259 template<typename It, typename... Args> 260 concurrent_multimap(It, It, Args...) 261 -> ordered_map_type<concurrent_multimap, iterator_key_t<It>, iterator_mapped_t<It>, Args...>; 262 263 template<typename Key, typename T, typename... Args> 264 concurrent_multimap(std::initializer_list<std::pair<const Key, T>>, Args...) 265 -> ordered_map_type<concurrent_multimap, Key, T, Args...>; 266 267 #endif // __TBB_CPP17_DEDUCTION_GUIDES_PRESENT 268 269 template <typename Key, typename Value, typename Compare, typename Allocator> 270 void swap( concurrent_multimap<Key, Value, Compare, Allocator>& lhs, 271 concurrent_multimap<Key, Value, Compare, Allocator>& rhs ) 272 { 273 lhs.swap(rhs); 274 } 275 276 } // namespace d1 277 } // namespace detail 278 279 inline namespace v1 { 280 281 using detail::d1::concurrent_map; 282 using detail::d1::concurrent_multimap; 283 using detail::split; 284 285 } // inline namespace v1 286 } // namespace tbb 287 288 #endif // __TBB_concurrent_map_H 289