1 // Copyright 2018 The Abseil Authors. 2 // 3 // Licensed under the Apache License, Version 2.0 (the "License"); 4 // you may not use this file except in compliance with the License. 5 // You may obtain a copy of the License at 6 // 7 // https://www.apache.org/licenses/LICENSE-2.0 8 // 9 // Unless required by applicable law or agreed to in writing, software 10 // distributed under the License is distributed on an "AS IS" BASIS, 11 // WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 12 // See the License for the specific language governing permissions and 13 // limitations under the License. 14 15 #ifndef ABSL_CONTAINER_INTERNAL_BTREE_CONTAINER_H_ 16 #define ABSL_CONTAINER_INTERNAL_BTREE_CONTAINER_H_ 17 18 #include <algorithm> 19 #include <initializer_list> 20 #include <iterator> 21 #include <utility> 22 23 #include "absl/base/attributes.h" 24 #include "absl/base/internal/throw_delegate.h" 25 #include "absl/container/internal/btree.h" // IWYU pragma: export 26 #include "absl/container/internal/common.h" 27 #include "absl/memory/memory.h" 28 #include "absl/meta/type_traits.h" 29 30 namespace absl { 31 ABSL_NAMESPACE_BEGIN 32 namespace container_internal { 33 34 // A common base class for btree_set, btree_map, btree_multiset, and 35 // btree_multimap. 36 template <typename Tree> 37 class btree_container { 38 using params_type = typename Tree::params_type; 39 40 protected: 41 // Alias used for heterogeneous lookup functions. 42 // `key_arg<K>` evaluates to `K` when the functors are transparent and to 43 // `key_type` otherwise. It permits template argument deduction on `K` for the 44 // transparent case. 45 template <class K> 46 using key_arg = 47 typename KeyArg<params_type::kIsKeyCompareTransparent>::template type< 48 K, typename Tree::key_type>; 49 50 public: 51 using key_type = typename Tree::key_type; 52 using value_type = typename Tree::value_type; 53 using size_type = typename Tree::size_type; 54 using difference_type = typename Tree::difference_type; 55 using key_compare = typename Tree::original_key_compare; 56 using value_compare = typename Tree::value_compare; 57 using allocator_type = typename Tree::allocator_type; 58 using reference = typename Tree::reference; 59 using const_reference = typename Tree::const_reference; 60 using pointer = typename Tree::pointer; 61 using const_pointer = typename Tree::const_pointer; 62 using iterator = typename Tree::iterator; 63 using const_iterator = typename Tree::const_iterator; 64 using reverse_iterator = typename Tree::reverse_iterator; 65 using const_reverse_iterator = typename Tree::const_reverse_iterator; 66 using node_type = typename Tree::node_handle_type; 67 68 struct extract_and_get_next_return_type { 69 node_type node; 70 iterator next; 71 }; 72 73 // Constructors/assignments. btree_container()74 btree_container() : tree_(key_compare(), allocator_type()) {} 75 explicit btree_container(const key_compare &comp, 76 const allocator_type &alloc = allocator_type()) tree_(comp,alloc)77 : tree_(comp, alloc) {} btree_container(const allocator_type & alloc)78 explicit btree_container(const allocator_type &alloc) 79 : tree_(key_compare(), alloc) {} 80 btree_container(const btree_container & other)81 btree_container(const btree_container &other) 82 : btree_container(other, absl::allocator_traits<allocator_type>:: 83 select_on_container_copy_construction( 84 other.get_allocator())) {} btree_container(const btree_container & other,const allocator_type & alloc)85 btree_container(const btree_container &other, const allocator_type &alloc) 86 : tree_(other.tree_, alloc) {} 87 88 btree_container(btree_container &&other) noexcept( 89 std::is_nothrow_move_constructible<Tree>::value) = default; btree_container(btree_container && other,const allocator_type & alloc)90 btree_container(btree_container &&other, const allocator_type &alloc) 91 : tree_(std::move(other.tree_), alloc) {} 92 93 btree_container &operator=(const btree_container &other) = default; 94 btree_container &operator=(btree_container &&other) noexcept( 95 std::is_nothrow_move_assignable<Tree>::value) = default; 96 97 // Iterator routines. begin()98 iterator begin() ABSL_ATTRIBUTE_LIFETIME_BOUND { return tree_.begin(); } begin()99 const_iterator begin() const ABSL_ATTRIBUTE_LIFETIME_BOUND { 100 return tree_.begin(); 101 } cbegin()102 const_iterator cbegin() const ABSL_ATTRIBUTE_LIFETIME_BOUND { 103 return tree_.begin(); 104 } end()105 iterator end() ABSL_ATTRIBUTE_LIFETIME_BOUND { return tree_.end(); } end()106 const_iterator end() const ABSL_ATTRIBUTE_LIFETIME_BOUND { 107 return tree_.end(); 108 } cend()109 const_iterator cend() const ABSL_ATTRIBUTE_LIFETIME_BOUND { 110 return tree_.end(); 111 } rbegin()112 reverse_iterator rbegin() ABSL_ATTRIBUTE_LIFETIME_BOUND { 113 return tree_.rbegin(); 114 } rbegin()115 const_reverse_iterator rbegin() const ABSL_ATTRIBUTE_LIFETIME_BOUND { 116 return tree_.rbegin(); 117 } crbegin()118 const_reverse_iterator crbegin() const ABSL_ATTRIBUTE_LIFETIME_BOUND { 119 return tree_.rbegin(); 120 } rend()121 reverse_iterator rend() ABSL_ATTRIBUTE_LIFETIME_BOUND { return tree_.rend(); } rend()122 const_reverse_iterator rend() const ABSL_ATTRIBUTE_LIFETIME_BOUND { 123 return tree_.rend(); 124 } crend()125 const_reverse_iterator crend() const ABSL_ATTRIBUTE_LIFETIME_BOUND { 126 return tree_.rend(); 127 } 128 129 // Lookup routines. 130 template <typename K = key_type> count(const key_arg<K> & key)131 size_type count(const key_arg<K> &key) const { 132 auto equal_range = this->equal_range(key); 133 return equal_range.second - equal_range.first; 134 } 135 template <typename K = key_type> find(const key_arg<K> & key)136 iterator find(const key_arg<K> &key) ABSL_ATTRIBUTE_LIFETIME_BOUND { 137 return tree_.find(key); 138 } 139 template <typename K = key_type> find(const key_arg<K> & key)140 const_iterator find(const key_arg<K> &key) const 141 ABSL_ATTRIBUTE_LIFETIME_BOUND { 142 return tree_.find(key); 143 } 144 template <typename K = key_type> contains(const key_arg<K> & key)145 bool contains(const key_arg<K> &key) const { 146 return find(key) != end(); 147 } 148 template <typename K = key_type> lower_bound(const key_arg<K> & key)149 iterator lower_bound(const key_arg<K> &key) ABSL_ATTRIBUTE_LIFETIME_BOUND { 150 return tree_.lower_bound(key); 151 } 152 template <typename K = key_type> lower_bound(const key_arg<K> & key)153 const_iterator lower_bound(const key_arg<K> &key) const 154 ABSL_ATTRIBUTE_LIFETIME_BOUND { 155 return tree_.lower_bound(key); 156 } 157 template <typename K = key_type> upper_bound(const key_arg<K> & key)158 iterator upper_bound(const key_arg<K> &key) ABSL_ATTRIBUTE_LIFETIME_BOUND { 159 return tree_.upper_bound(key); 160 } 161 template <typename K = key_type> upper_bound(const key_arg<K> & key)162 const_iterator upper_bound(const key_arg<K> &key) const 163 ABSL_ATTRIBUTE_LIFETIME_BOUND { 164 return tree_.upper_bound(key); 165 } 166 template <typename K = key_type> equal_range(const key_arg<K> & key)167 std::pair<iterator, iterator> equal_range(const key_arg<K> &key) 168 ABSL_ATTRIBUTE_LIFETIME_BOUND { 169 return tree_.equal_range(key); 170 } 171 template <typename K = key_type> equal_range(const key_arg<K> & key)172 std::pair<const_iterator, const_iterator> equal_range( 173 const key_arg<K> &key) const ABSL_ATTRIBUTE_LIFETIME_BOUND { 174 return tree_.equal_range(key); 175 } 176 177 // Deletion routines. Note that there is also a deletion routine that is 178 // specific to btree_set_container/btree_multiset_container. 179 180 // Erase the specified iterator from the btree. The iterator must be valid 181 // (i.e. not equal to end()). Return an iterator pointing to the node after 182 // the one that was erased (or end() if none exists). erase(const_iterator iter)183 iterator erase(const_iterator iter) ABSL_ATTRIBUTE_LIFETIME_BOUND { 184 return tree_.erase(iterator(iter)); 185 } erase(iterator iter)186 iterator erase(iterator iter) ABSL_ATTRIBUTE_LIFETIME_BOUND { 187 return tree_.erase(iter); 188 } erase(const_iterator first,const_iterator last)189 iterator erase(const_iterator first, 190 const_iterator last) ABSL_ATTRIBUTE_LIFETIME_BOUND { 191 return tree_.erase_range(iterator(first), iterator(last)).second; 192 } 193 template <typename K = key_type> erase(const key_arg<K> & key)194 size_type erase(const key_arg<K> &key) { 195 auto equal_range = this->equal_range(key); 196 return tree_.erase_range(equal_range.first, equal_range.second).first; 197 } 198 199 // Extract routines. extract_and_get_next(const_iterator position)200 extract_and_get_next_return_type extract_and_get_next(const_iterator position) 201 ABSL_ATTRIBUTE_LIFETIME_BOUND { 202 // Use Construct instead of Transfer because the rebalancing code will 203 // destroy the slot later. 204 // Note: we rely on erase() taking place after Construct(). 205 return {CommonAccess::Construct<node_type>(get_allocator(), 206 iterator(position).slot()), 207 erase(position)}; 208 } extract(iterator position)209 node_type extract(iterator position) { 210 // Use Construct instead of Transfer because the rebalancing code will 211 // destroy the slot later. 212 auto node = 213 CommonAccess::Construct<node_type>(get_allocator(), position.slot()); 214 erase(position); 215 return node; 216 } extract(const_iterator position)217 node_type extract(const_iterator position) { 218 return extract(iterator(position)); 219 } 220 221 // Utility routines. clear()222 ABSL_ATTRIBUTE_REINITIALIZES void clear() { tree_.clear(); } swap(btree_container & other)223 void swap(btree_container &other) { tree_.swap(other.tree_); } verify()224 void verify() const { tree_.verify(); } 225 226 // Size routines. size()227 size_type size() const { return tree_.size(); } max_size()228 size_type max_size() const { return tree_.max_size(); } empty()229 bool empty() const { return tree_.empty(); } 230 231 friend bool operator==(const btree_container &x, const btree_container &y) { 232 if (x.size() != y.size()) return false; 233 return std::equal(x.begin(), x.end(), y.begin()); 234 } 235 236 friend bool operator!=(const btree_container &x, const btree_container &y) { 237 return !(x == y); 238 } 239 240 friend bool operator<(const btree_container &x, const btree_container &y) { 241 return std::lexicographical_compare(x.begin(), x.end(), y.begin(), y.end()); 242 } 243 244 friend bool operator>(const btree_container &x, const btree_container &y) { 245 return y < x; 246 } 247 248 friend bool operator<=(const btree_container &x, const btree_container &y) { 249 return !(y < x); 250 } 251 252 friend bool operator>=(const btree_container &x, const btree_container &y) { 253 return !(x < y); 254 } 255 256 // The allocator used by the btree. get_allocator()257 allocator_type get_allocator() const { return tree_.get_allocator(); } 258 259 // The key comparator used by the btree. key_comp()260 key_compare key_comp() const { return key_compare(tree_.key_comp()); } value_comp()261 value_compare value_comp() const { return tree_.value_comp(); } 262 263 // Support absl::Hash. 264 template <typename State> AbslHashValue(State h,const btree_container & b)265 friend State AbslHashValue(State h, const btree_container &b) { 266 for (const auto &v : b) { 267 h = State::combine(std::move(h), v); 268 } 269 return State::combine(std::move(h), b.size()); 270 } 271 272 protected: 273 friend struct btree_access; 274 Tree tree_; 275 }; 276 277 // A common base class for btree_set and btree_map. 278 template <typename Tree> 279 class btree_set_container : public btree_container<Tree> { 280 using super_type = btree_container<Tree>; 281 using params_type = typename Tree::params_type; 282 using init_type = typename params_type::init_type; 283 using is_key_compare_to = typename params_type::is_key_compare_to; 284 friend class BtreeNodePeer; 285 286 protected: 287 template <class K> 288 using key_arg = typename super_type::template key_arg<K>; 289 290 public: 291 using key_type = typename Tree::key_type; 292 using value_type = typename Tree::value_type; 293 using size_type = typename Tree::size_type; 294 using key_compare = typename Tree::original_key_compare; 295 using allocator_type = typename Tree::allocator_type; 296 using iterator = typename Tree::iterator; 297 using const_iterator = typename Tree::const_iterator; 298 using node_type = typename super_type::node_type; 299 using insert_return_type = InsertReturnType<iterator, node_type>; 300 301 // Inherit constructors. 302 using super_type::super_type; btree_set_container()303 btree_set_container() {} 304 305 // Range constructors. 306 template <class InputIterator> 307 btree_set_container(InputIterator b, InputIterator e, 308 const key_compare &comp = key_compare(), 309 const allocator_type &alloc = allocator_type()) super_type(comp,alloc)310 : super_type(comp, alloc) { 311 insert(b, e); 312 } 313 template <class InputIterator> btree_set_container(InputIterator b,InputIterator e,const allocator_type & alloc)314 btree_set_container(InputIterator b, InputIterator e, 315 const allocator_type &alloc) 316 : btree_set_container(b, e, key_compare(), alloc) {} 317 318 // Initializer list constructors. 319 btree_set_container(std::initializer_list<init_type> init, 320 const key_compare &comp = key_compare(), 321 const allocator_type &alloc = allocator_type()) 322 : btree_set_container(init.begin(), init.end(), comp, alloc) {} btree_set_container(std::initializer_list<init_type> init,const allocator_type & alloc)323 btree_set_container(std::initializer_list<init_type> init, 324 const allocator_type &alloc) 325 : btree_set_container(init.begin(), init.end(), alloc) {} 326 327 // Insertion routines. insert(const value_type & v)328 std::pair<iterator, bool> insert(const value_type &v) 329 ABSL_ATTRIBUTE_LIFETIME_BOUND { 330 return this->tree_.insert_unique(params_type::key(v), v); 331 } insert(value_type && v)332 std::pair<iterator, bool> insert(value_type &&v) 333 ABSL_ATTRIBUTE_LIFETIME_BOUND { 334 return this->tree_.insert_unique(params_type::key(v), std::move(v)); 335 } 336 template <typename... Args> emplace(Args &&...args)337 std::pair<iterator, bool> emplace(Args &&...args) 338 ABSL_ATTRIBUTE_LIFETIME_BOUND { 339 // Use a node handle to manage a temp slot. 340 auto node = CommonAccess::Construct<node_type>(this->get_allocator(), 341 std::forward<Args>(args)...); 342 auto *slot = CommonAccess::GetSlot(node); 343 return this->tree_.insert_unique(params_type::key(slot), slot); 344 } insert(const_iterator hint,const value_type & v)345 iterator insert(const_iterator hint, 346 const value_type &v) ABSL_ATTRIBUTE_LIFETIME_BOUND { 347 return this->tree_ 348 .insert_hint_unique(iterator(hint), params_type::key(v), v) 349 .first; 350 } insert(const_iterator hint,value_type && v)351 iterator insert(const_iterator hint, 352 value_type &&v) ABSL_ATTRIBUTE_LIFETIME_BOUND { 353 return this->tree_ 354 .insert_hint_unique(iterator(hint), params_type::key(v), std::move(v)) 355 .first; 356 } 357 template <typename... Args> emplace_hint(const_iterator hint,Args &&...args)358 iterator emplace_hint(const_iterator hint, 359 Args &&...args) ABSL_ATTRIBUTE_LIFETIME_BOUND { 360 // Use a node handle to manage a temp slot. 361 auto node = CommonAccess::Construct<node_type>(this->get_allocator(), 362 std::forward<Args>(args)...); 363 auto *slot = CommonAccess::GetSlot(node); 364 return this->tree_ 365 .insert_hint_unique(iterator(hint), params_type::key(slot), slot) 366 .first; 367 } 368 template <typename InputIterator> insert(InputIterator b,InputIterator e)369 void insert(InputIterator b, InputIterator e) { 370 this->tree_.insert_iterator_unique(b, e, 0); 371 } insert(std::initializer_list<init_type> init)372 void insert(std::initializer_list<init_type> init) { 373 this->tree_.insert_iterator_unique(init.begin(), init.end(), 0); 374 } insert(node_type && node)375 insert_return_type insert(node_type &&node) ABSL_ATTRIBUTE_LIFETIME_BOUND { 376 if (!node) return {this->end(), false, node_type()}; 377 std::pair<iterator, bool> res = 378 this->tree_.insert_unique(params_type::key(CommonAccess::GetSlot(node)), 379 CommonAccess::GetSlot(node)); 380 if (res.second) { 381 CommonAccess::Destroy(&node); 382 return {res.first, true, node_type()}; 383 } else { 384 return {res.first, false, std::move(node)}; 385 } 386 } insert(const_iterator hint,node_type && node)387 iterator insert(const_iterator hint, 388 node_type &&node) ABSL_ATTRIBUTE_LIFETIME_BOUND { 389 if (!node) return this->end(); 390 std::pair<iterator, bool> res = this->tree_.insert_hint_unique( 391 iterator(hint), params_type::key(CommonAccess::GetSlot(node)), 392 CommonAccess::GetSlot(node)); 393 if (res.second) CommonAccess::Destroy(&node); 394 return res.first; 395 } 396 397 // Node extraction routines. 398 template <typename K = key_type> extract(const key_arg<K> & key)399 node_type extract(const key_arg<K> &key) { 400 const std::pair<iterator, bool> lower_and_equal = 401 this->tree_.lower_bound_equal(key); 402 return lower_and_equal.second ? extract(lower_and_equal.first) 403 : node_type(); 404 } 405 using super_type::extract; 406 407 // Merge routines. 408 // Moves elements from `src` into `this`. If the element already exists in 409 // `this`, it is left unmodified in `src`. 410 template < 411 typename T, 412 typename absl::enable_if_t< 413 absl::conjunction< 414 std::is_same<value_type, typename T::value_type>, 415 std::is_same<allocator_type, typename T::allocator_type>, 416 std::is_same<typename params_type::is_map_container, 417 typename T::params_type::is_map_container>>::value, 418 int> = 0> merge(btree_container<T> & src)419 void merge(btree_container<T> &src) { // NOLINT 420 for (auto src_it = src.begin(); src_it != src.end();) { 421 if (insert(std::move(params_type::element(src_it.slot()))).second) { 422 src_it = src.erase(src_it); 423 } else { 424 ++src_it; 425 } 426 } 427 } 428 429 template < 430 typename T, 431 typename absl::enable_if_t< 432 absl::conjunction< 433 std::is_same<value_type, typename T::value_type>, 434 std::is_same<allocator_type, typename T::allocator_type>, 435 std::is_same<typename params_type::is_map_container, 436 typename T::params_type::is_map_container>>::value, 437 int> = 0> merge(btree_container<T> && src)438 void merge(btree_container<T> &&src) { 439 merge(src); 440 } 441 }; 442 443 // Base class for btree_map. 444 template <typename Tree> 445 class btree_map_container : public btree_set_container<Tree> { 446 using super_type = btree_set_container<Tree>; 447 using params_type = typename Tree::params_type; 448 friend class BtreeNodePeer; 449 450 private: 451 template <class K> 452 using key_arg = typename super_type::template key_arg<K>; 453 454 public: 455 using key_type = typename Tree::key_type; 456 using mapped_type = typename params_type::mapped_type; 457 using value_type = typename Tree::value_type; 458 using key_compare = typename Tree::original_key_compare; 459 using allocator_type = typename Tree::allocator_type; 460 using iterator = typename Tree::iterator; 461 using const_iterator = typename Tree::const_iterator; 462 463 // Inherit constructors. 464 using super_type::super_type; btree_map_container()465 btree_map_container() {} 466 467 // Insertion routines. 468 // Note: the nullptr template arguments and extra `const M&` overloads allow 469 // for supporting bitfield arguments. 470 template <typename K = key_type, class M> insert_or_assign(const key_arg<K> & k,const M & obj)471 std::pair<iterator, bool> insert_or_assign(const key_arg<K> &k, const M &obj) 472 ABSL_ATTRIBUTE_LIFETIME_BOUND { 473 return insert_or_assign_impl(k, obj); 474 } 475 template <typename K = key_type, class M, K * = nullptr> insert_or_assign(key_arg<K> && k,const M & obj)476 std::pair<iterator, bool> insert_or_assign(key_arg<K> &&k, const M &obj) 477 ABSL_ATTRIBUTE_LIFETIME_BOUND { 478 return insert_or_assign_impl(std::forward<K>(k), obj); 479 } 480 template <typename K = key_type, class M, M * = nullptr> insert_or_assign(const key_arg<K> & k,M && obj)481 std::pair<iterator, bool> insert_or_assign(const key_arg<K> &k, M &&obj) 482 ABSL_ATTRIBUTE_LIFETIME_BOUND { 483 return insert_or_assign_impl(k, std::forward<M>(obj)); 484 } 485 template <typename K = key_type, class M, K * = nullptr, M * = nullptr> insert_or_assign(key_arg<K> && k,M && obj)486 std::pair<iterator, bool> insert_or_assign(key_arg<K> &&k, M &&obj) 487 ABSL_ATTRIBUTE_LIFETIME_BOUND { 488 return insert_or_assign_impl(std::forward<K>(k), std::forward<M>(obj)); 489 } 490 template <typename K = key_type, class M> insert_or_assign(const_iterator hint,const key_arg<K> & k,const M & obj)491 iterator insert_or_assign(const_iterator hint, const key_arg<K> &k, 492 const M &obj) ABSL_ATTRIBUTE_LIFETIME_BOUND { 493 return insert_or_assign_hint_impl(hint, k, obj); 494 } 495 template <typename K = key_type, class M, K * = nullptr> insert_or_assign(const_iterator hint,key_arg<K> && k,const M & obj)496 iterator insert_or_assign(const_iterator hint, key_arg<K> &&k, 497 const M &obj) ABSL_ATTRIBUTE_LIFETIME_BOUND { 498 return insert_or_assign_hint_impl(hint, std::forward<K>(k), obj); 499 } 500 template <typename K = key_type, class M, M * = nullptr> insert_or_assign(const_iterator hint,const key_arg<K> & k,M && obj)501 iterator insert_or_assign(const_iterator hint, const key_arg<K> &k, 502 M &&obj) ABSL_ATTRIBUTE_LIFETIME_BOUND { 503 return insert_or_assign_hint_impl(hint, k, std::forward<M>(obj)); 504 } 505 template <typename K = key_type, class M, K * = nullptr, M * = nullptr> insert_or_assign(const_iterator hint,key_arg<K> && k,M && obj)506 iterator insert_or_assign(const_iterator hint, key_arg<K> &&k, 507 M &&obj) ABSL_ATTRIBUTE_LIFETIME_BOUND { 508 return insert_or_assign_hint_impl(hint, std::forward<K>(k), 509 std::forward<M>(obj)); 510 } 511 512 template <typename K = key_type, typename... Args, 513 typename absl::enable_if_t< 514 !std::is_convertible<K, const_iterator>::value, int> = 0> try_emplace(const key_arg<K> & k,Args &&...args)515 std::pair<iterator, bool> try_emplace(const key_arg<K> &k, Args &&...args) 516 ABSL_ATTRIBUTE_LIFETIME_BOUND { 517 return try_emplace_impl(k, std::forward<Args>(args)...); 518 } 519 template <typename K = key_type, typename... Args, 520 typename absl::enable_if_t< 521 !std::is_convertible<K, const_iterator>::value, int> = 0> try_emplace(key_arg<K> && k,Args &&...args)522 std::pair<iterator, bool> try_emplace(key_arg<K> &&k, Args &&...args) 523 ABSL_ATTRIBUTE_LIFETIME_BOUND { 524 return try_emplace_impl(std::forward<K>(k), std::forward<Args>(args)...); 525 } 526 template <typename K = key_type, typename... Args> try_emplace(const_iterator hint,const key_arg<K> & k,Args &&...args)527 iterator try_emplace(const_iterator hint, const key_arg<K> &k, 528 Args &&...args) ABSL_ATTRIBUTE_LIFETIME_BOUND { 529 return try_emplace_hint_impl(hint, k, std::forward<Args>(args)...); 530 } 531 template <typename K = key_type, typename... Args> try_emplace(const_iterator hint,key_arg<K> && k,Args &&...args)532 iterator try_emplace(const_iterator hint, key_arg<K> &&k, 533 Args &&...args) ABSL_ATTRIBUTE_LIFETIME_BOUND { 534 return try_emplace_hint_impl(hint, std::forward<K>(k), 535 std::forward<Args>(args)...); 536 } 537 538 template <typename K = key_type> 539 mapped_type &operator[](const key_arg<K> &k) ABSL_ATTRIBUTE_LIFETIME_BOUND { 540 return try_emplace(k).first->second; 541 } 542 template <typename K = key_type> 543 mapped_type &operator[](key_arg<K> &&k) ABSL_ATTRIBUTE_LIFETIME_BOUND { 544 return try_emplace(std::forward<K>(k)).first->second; 545 } 546 547 template <typename K = key_type> at(const key_arg<K> & key)548 mapped_type &at(const key_arg<K> &key) ABSL_ATTRIBUTE_LIFETIME_BOUND { 549 auto it = this->find(key); 550 if (it == this->end()) 551 base_internal::ThrowStdOutOfRange("absl::btree_map::at"); 552 return it->second; 553 } 554 template <typename K = key_type> at(const key_arg<K> & key)555 const mapped_type &at(const key_arg<K> &key) const 556 ABSL_ATTRIBUTE_LIFETIME_BOUND { 557 auto it = this->find(key); 558 if (it == this->end()) 559 base_internal::ThrowStdOutOfRange("absl::btree_map::at"); 560 return it->second; 561 } 562 563 private: 564 // Note: when we call `std::forward<M>(obj)` twice, it's safe because 565 // insert_unique/insert_hint_unique are guaranteed to not consume `obj` when 566 // `ret.second` is false. 567 template <class K, class M> insert_or_assign_impl(K && k,M && obj)568 std::pair<iterator, bool> insert_or_assign_impl(K &&k, M &&obj) { 569 const std::pair<iterator, bool> ret = 570 this->tree_.insert_unique(k, std::forward<K>(k), std::forward<M>(obj)); 571 if (!ret.second) ret.first->second = std::forward<M>(obj); 572 return ret; 573 } 574 template <class K, class M> insert_or_assign_hint_impl(const_iterator hint,K && k,M && obj)575 iterator insert_or_assign_hint_impl(const_iterator hint, K &&k, M &&obj) { 576 const std::pair<iterator, bool> ret = this->tree_.insert_hint_unique( 577 iterator(hint), k, std::forward<K>(k), std::forward<M>(obj)); 578 if (!ret.second) ret.first->second = std::forward<M>(obj); 579 return ret.first; 580 } 581 582 template <class K, class... Args> try_emplace_impl(K && k,Args &&...args)583 std::pair<iterator, bool> try_emplace_impl(K &&k, Args &&... args) { 584 return this->tree_.insert_unique( 585 k, std::piecewise_construct, std::forward_as_tuple(std::forward<K>(k)), 586 std::forward_as_tuple(std::forward<Args>(args)...)); 587 } 588 template <class K, class... Args> try_emplace_hint_impl(const_iterator hint,K && k,Args &&...args)589 iterator try_emplace_hint_impl(const_iterator hint, K &&k, Args &&... args) { 590 return this->tree_ 591 .insert_hint_unique(iterator(hint), k, std::piecewise_construct, 592 std::forward_as_tuple(std::forward<K>(k)), 593 std::forward_as_tuple(std::forward<Args>(args)...)) 594 .first; 595 } 596 }; 597 598 // A common base class for btree_multiset and btree_multimap. 599 template <typename Tree> 600 class btree_multiset_container : public btree_container<Tree> { 601 using super_type = btree_container<Tree>; 602 using params_type = typename Tree::params_type; 603 using init_type = typename params_type::init_type; 604 using is_key_compare_to = typename params_type::is_key_compare_to; 605 friend class BtreeNodePeer; 606 607 template <class K> 608 using key_arg = typename super_type::template key_arg<K>; 609 610 public: 611 using key_type = typename Tree::key_type; 612 using value_type = typename Tree::value_type; 613 using size_type = typename Tree::size_type; 614 using key_compare = typename Tree::original_key_compare; 615 using allocator_type = typename Tree::allocator_type; 616 using iterator = typename Tree::iterator; 617 using const_iterator = typename Tree::const_iterator; 618 using node_type = typename super_type::node_type; 619 620 // Inherit constructors. 621 using super_type::super_type; btree_multiset_container()622 btree_multiset_container() {} 623 624 // Range constructors. 625 template <class InputIterator> 626 btree_multiset_container(InputIterator b, InputIterator e, 627 const key_compare &comp = key_compare(), 628 const allocator_type &alloc = allocator_type()) super_type(comp,alloc)629 : super_type(comp, alloc) { 630 insert(b, e); 631 } 632 template <class InputIterator> btree_multiset_container(InputIterator b,InputIterator e,const allocator_type & alloc)633 btree_multiset_container(InputIterator b, InputIterator e, 634 const allocator_type &alloc) 635 : btree_multiset_container(b, e, key_compare(), alloc) {} 636 637 // Initializer list constructors. 638 btree_multiset_container(std::initializer_list<init_type> init, 639 const key_compare &comp = key_compare(), 640 const allocator_type &alloc = allocator_type()) 641 : btree_multiset_container(init.begin(), init.end(), comp, alloc) {} btree_multiset_container(std::initializer_list<init_type> init,const allocator_type & alloc)642 btree_multiset_container(std::initializer_list<init_type> init, 643 const allocator_type &alloc) 644 : btree_multiset_container(init.begin(), init.end(), alloc) {} 645 646 // Insertion routines. insert(const value_type & v)647 iterator insert(const value_type &v) ABSL_ATTRIBUTE_LIFETIME_BOUND { 648 return this->tree_.insert_multi(v); 649 } insert(value_type && v)650 iterator insert(value_type &&v) ABSL_ATTRIBUTE_LIFETIME_BOUND { 651 return this->tree_.insert_multi(std::move(v)); 652 } insert(const_iterator hint,const value_type & v)653 iterator insert(const_iterator hint, 654 const value_type &v) ABSL_ATTRIBUTE_LIFETIME_BOUND { 655 return this->tree_.insert_hint_multi(iterator(hint), v); 656 } insert(const_iterator hint,value_type && v)657 iterator insert(const_iterator hint, 658 value_type &&v) ABSL_ATTRIBUTE_LIFETIME_BOUND { 659 return this->tree_.insert_hint_multi(iterator(hint), std::move(v)); 660 } 661 template <typename InputIterator> insert(InputIterator b,InputIterator e)662 void insert(InputIterator b, InputIterator e) { 663 this->tree_.insert_iterator_multi(b, e); 664 } insert(std::initializer_list<init_type> init)665 void insert(std::initializer_list<init_type> init) { 666 this->tree_.insert_iterator_multi(init.begin(), init.end()); 667 } 668 template <typename... Args> emplace(Args &&...args)669 iterator emplace(Args &&...args) ABSL_ATTRIBUTE_LIFETIME_BOUND { 670 // Use a node handle to manage a temp slot. 671 auto node = CommonAccess::Construct<node_type>(this->get_allocator(), 672 std::forward<Args>(args)...); 673 return this->tree_.insert_multi(CommonAccess::GetSlot(node)); 674 } 675 template <typename... Args> emplace_hint(const_iterator hint,Args &&...args)676 iterator emplace_hint(const_iterator hint, 677 Args &&...args) ABSL_ATTRIBUTE_LIFETIME_BOUND { 678 // Use a node handle to manage a temp slot. 679 auto node = CommonAccess::Construct<node_type>(this->get_allocator(), 680 std::forward<Args>(args)...); 681 return this->tree_.insert_hint_multi(iterator(hint), 682 CommonAccess::GetSlot(node)); 683 } insert(node_type && node)684 iterator insert(node_type &&node) ABSL_ATTRIBUTE_LIFETIME_BOUND { 685 if (!node) return this->end(); 686 iterator res = 687 this->tree_.insert_multi(params_type::key(CommonAccess::GetSlot(node)), 688 CommonAccess::GetSlot(node)); 689 CommonAccess::Destroy(&node); 690 return res; 691 } insert(const_iterator hint,node_type && node)692 iterator insert(const_iterator hint, 693 node_type &&node) ABSL_ATTRIBUTE_LIFETIME_BOUND { 694 if (!node) return this->end(); 695 iterator res = this->tree_.insert_hint_multi( 696 iterator(hint), 697 std::move(params_type::element(CommonAccess::GetSlot(node)))); 698 CommonAccess::Destroy(&node); 699 return res; 700 } 701 702 // Node extraction routines. 703 template <typename K = key_type> extract(const key_arg<K> & key)704 node_type extract(const key_arg<K> &key) { 705 const std::pair<iterator, bool> lower_and_equal = 706 this->tree_.lower_bound_equal(key); 707 return lower_and_equal.second ? extract(lower_and_equal.first) 708 : node_type(); 709 } 710 using super_type::extract; 711 712 // Merge routines. 713 // Moves all elements from `src` into `this`. 714 template < 715 typename T, 716 typename absl::enable_if_t< 717 absl::conjunction< 718 std::is_same<value_type, typename T::value_type>, 719 std::is_same<allocator_type, typename T::allocator_type>, 720 std::is_same<typename params_type::is_map_container, 721 typename T::params_type::is_map_container>>::value, 722 int> = 0> merge(btree_container<T> & src)723 void merge(btree_container<T> &src) { // NOLINT 724 for (auto src_it = src.begin(), end = src.end(); src_it != end; ++src_it) { 725 insert(std::move(params_type::element(src_it.slot()))); 726 } 727 src.clear(); 728 } 729 730 template < 731 typename T, 732 typename absl::enable_if_t< 733 absl::conjunction< 734 std::is_same<value_type, typename T::value_type>, 735 std::is_same<allocator_type, typename T::allocator_type>, 736 std::is_same<typename params_type::is_map_container, 737 typename T::params_type::is_map_container>>::value, 738 int> = 0> merge(btree_container<T> && src)739 void merge(btree_container<T> &&src) { 740 merge(src); 741 } 742 }; 743 744 // A base class for btree_multimap. 745 template <typename Tree> 746 class btree_multimap_container : public btree_multiset_container<Tree> { 747 using super_type = btree_multiset_container<Tree>; 748 using params_type = typename Tree::params_type; 749 friend class BtreeNodePeer; 750 751 public: 752 using mapped_type = typename params_type::mapped_type; 753 754 // Inherit constructors. 755 using super_type::super_type; btree_multimap_container()756 btree_multimap_container() {} 757 }; 758 759 } // namespace container_internal 760 ABSL_NAMESPACE_END 761 } // namespace absl 762 763 #endif // ABSL_CONTAINER_INTERNAL_BTREE_CONTAINER_H_ 764