flat_tree.h (44417B)
1 // Copyright 2017 The Chromium Authors 2 // Use of this source code is governed by a BSD-style license that can be 3 // found in the LICENSE file. 4 5 #ifndef BASE_CONTAINERS_FLAT_TREE_H_ 6 #define BASE_CONTAINERS_FLAT_TREE_H_ 7 8 #include <algorithm> 9 #include <array> 10 #include <initializer_list> 11 #include <iterator> 12 #include <type_traits> 13 #include <utility> 14 15 #include "base/check.h" 16 #include "base/compiler_specific.h" 17 #include "base/functional/not_fn.h" 18 #include "base/memory/raw_ptr_exclusion.h" 19 #include "base/ranges/algorithm.h" 20 21 namespace base { 22 23 // Tag type that allows skipping the sort_and_unique step when constructing a 24 // flat_tree in case the underlying container is already sorted and has no 25 // duplicate elements. 26 struct sorted_unique_t { 27 constexpr explicit sorted_unique_t() = default; 28 }; 29 extern sorted_unique_t sorted_unique; 30 31 namespace internal { 32 33 // Helper functions used in DCHECKs below to make sure that inputs tagged with 34 // sorted_unique are indeed sorted and unique. 35 template <typename Range, typename Comp> 36 constexpr bool is_sorted_and_unique(const Range& range, Comp comp) { 37 // Being unique implies that there are no adjacent elements that 38 // compare equal. So this checks that each element is strictly less 39 // than the element after it. 40 return ranges::adjacent_find(range, base::not_fn(comp)) == ranges::end(range); 41 } 42 43 // This is a convenience trait inheriting from std::true_type if Iterator is at 44 // least a ForwardIterator and thus supports multiple passes over a range. 45 template <class Iterator> 46 using is_multipass = std::is_base_of< 47 std::forward_iterator_tag, 48 typename std::iterator_traits<Iterator>::iterator_category>; 49 50 // Uses SFINAE to detect whether type has is_transparent member. 51 template <typename T, typename = void> 52 struct IsTransparentCompare : std::false_type {}; 53 template <typename T> 54 struct IsTransparentCompare<T, std::void_t<typename T::is_transparent>> 55 : std::true_type {}; 56 57 // Helper inspired by C++20's std::to_array to convert a C-style array to a 58 // std::array. As opposed to the C++20 version this implementation does not 59 // provide an overload for rvalues and does not strip cv qualifers from the 60 // returned std::array::value_type. The returned value_type needs to be 61 // specified explicitly, allowing the construction of std::arrays with const 62 // elements. 63 // 64 // Reference: https://en.cppreference.com/w/cpp/container/array/to_array 65 template <typename U, typename T, size_t N, size_t... I> 66 constexpr std::array<U, N> ToArrayImpl(const T (&data)[N], 67 std::index_sequence<I...>) { 68 return {{data[I]...}}; 69 } 70 71 template <typename U, typename T, size_t N> 72 constexpr std::array<U, N> ToArray(const T (&data)[N]) { 73 return ToArrayImpl<U>(data, std::make_index_sequence<N>()); 74 } 75 76 // Helper that calls `container.reserve(std::size(source))`. 77 template <typename T, typename U> 78 constexpr void ReserveIfSupported(const T&, const U&) {} 79 80 template <typename T, typename U> 81 auto ReserveIfSupported(T& container, const U& source) 82 -> decltype(container.reserve(std::size(source)), void()) { 83 container.reserve(std::size(source)); 84 } 85 86 // std::pair's operator= is not constexpr prior to C++20. Thus we need this 87 // small helper to invoke operator= on the .first and .second member explicitly. 88 template <typename T> 89 constexpr void Assign(T& lhs, T&& rhs) { 90 lhs = std::move(rhs); 91 } 92 93 template <typename T, typename U> 94 constexpr void Assign(std::pair<T, U>& lhs, std::pair<T, U>&& rhs) { 95 Assign(lhs.first, std::move(rhs.first)); 96 Assign(lhs.second, std::move(rhs.second)); 97 } 98 99 // constexpr swap implementation. std::swap is not constexpr prior to C++20. 100 template <typename T> 101 constexpr void Swap(T& lhs, T& rhs) { 102 T tmp = std::move(lhs); 103 Assign(lhs, std::move(rhs)); 104 Assign(rhs, std::move(tmp)); 105 } 106 107 // constexpr prev implementation. std::prev is not constexpr prior to C++17. 108 template <typename BidirIt> 109 constexpr BidirIt Prev(BidirIt it) { 110 return --it; 111 } 112 113 // constexpr next implementation. std::next is not constexpr prior to C++17. 114 template <typename InputIt> 115 constexpr InputIt Next(InputIt it) { 116 return ++it; 117 } 118 119 // constexpr sort implementation. std::sort is not constexpr prior to C++20. 120 // While insertion sort has a quadratic worst case complexity, it was chosen 121 // because it has linear complexity for nearly sorted data, is stable, and 122 // simple to implement. 123 template <typename BidirIt, typename Compare> 124 constexpr void InsertionSort(BidirIt first, BidirIt last, const Compare& comp) { 125 if (first == last) 126 return; 127 128 for (auto it = Next(first); it != last; ++it) { 129 for (auto curr = it; curr != first && comp(*curr, *Prev(curr)); --curr) 130 Swap(*curr, *Prev(curr)); 131 } 132 } 133 134 // Implementation ------------------------------------------------------------- 135 136 // Implementation for the sorted associative flat_set and flat_map using a 137 // sorted vector as the backing store. Do not use directly. 138 // 139 // The use of "value" in this is like std::map uses, meaning it's the thing 140 // contained (in the case of map it's a <Key, Mapped> pair). The Key is how 141 // things are looked up. In the case of a set, Key == Value. In the case of 142 // a map, the Key is a component of a Value. 143 // 144 // The helper class GetKeyFromValue provides the means to extract a key from a 145 // value for comparison purposes. It should implement: 146 // const Key& operator()(const Value&). 147 template <class Key, class GetKeyFromValue, class KeyCompare, class Container> 148 class flat_tree { 149 public: 150 // -------------------------------------------------------------------------- 151 // Types. 152 // 153 using key_type = Key; 154 using key_compare = KeyCompare; 155 using value_type = typename Container::value_type; 156 157 // Wraps the templated key comparison to compare values. 158 struct value_compare { 159 constexpr bool operator()(const value_type& left, 160 const value_type& right) const { 161 GetKeyFromValue extractor; 162 return comp(extractor(left), extractor(right)); 163 } 164 165 NO_UNIQUE_ADDRESS key_compare comp; 166 }; 167 168 using pointer = typename Container::pointer; 169 using const_pointer = typename Container::const_pointer; 170 using reference = typename Container::reference; 171 using const_reference = typename Container::const_reference; 172 using size_type = typename Container::size_type; 173 using difference_type = typename Container::difference_type; 174 using iterator = typename Container::iterator; 175 using const_iterator = typename Container::const_iterator; 176 using reverse_iterator = typename Container::reverse_iterator; 177 using const_reverse_iterator = typename Container::const_reverse_iterator; 178 using container_type = Container; 179 180 // -------------------------------------------------------------------------- 181 // Lifetime. 182 // 183 // Constructors that take range guarantee O(N * log^2(N)) + O(N) complexity 184 // and take O(N * log(N)) + O(N) if extra memory is available (N is a range 185 // length). 186 // 187 // Assume that move constructors invalidate iterators and references. 188 // 189 // The constructors that take ranges, lists, and vectors do not require that 190 // the input be sorted. 191 // 192 // When passing the base::sorted_unique tag as the first argument no sort and 193 // unique step takes places. This is useful if the underlying container 194 // already has the required properties. 195 196 flat_tree() = default; 197 flat_tree(const flat_tree&) = default; 198 flat_tree(flat_tree&&) = default; 199 200 explicit flat_tree(const key_compare& comp); 201 202 template <class InputIterator> 203 flat_tree(InputIterator first, 204 InputIterator last, 205 const key_compare& comp = key_compare()); 206 207 flat_tree(const container_type& items, 208 const key_compare& comp = key_compare()); 209 210 flat_tree(container_type&& items, const key_compare& comp = key_compare()); 211 212 flat_tree(std::initializer_list<value_type> ilist, 213 const key_compare& comp = key_compare()); 214 215 template <class InputIterator> 216 flat_tree(sorted_unique_t, 217 InputIterator first, 218 InputIterator last, 219 const key_compare& comp = key_compare()); 220 221 flat_tree(sorted_unique_t, 222 const container_type& items, 223 const key_compare& comp = key_compare()); 224 225 constexpr flat_tree(sorted_unique_t, 226 container_type&& items, 227 const key_compare& comp = key_compare()); 228 229 flat_tree(sorted_unique_t, 230 std::initializer_list<value_type> ilist, 231 const key_compare& comp = key_compare()); 232 233 ~flat_tree() = default; 234 235 // -------------------------------------------------------------------------- 236 // Assignments. 237 // 238 // Assume that move assignment invalidates iterators and references. 239 240 flat_tree& operator=(const flat_tree&) = default; 241 flat_tree& operator=(flat_tree&&) = default; 242 // Takes the first if there are duplicates in the initializer list. 243 flat_tree& operator=(std::initializer_list<value_type> ilist); 244 245 // -------------------------------------------------------------------------- 246 // Memory management. 247 // 248 // Beware that shrink_to_fit() simply forwards the request to the 249 // container_type and its implementation is free to optimize otherwise and 250 // leave capacity() to be greater that its size. 251 // 252 // reserve() and shrink_to_fit() invalidate iterators and references. 253 254 void reserve(size_type new_capacity); 255 size_type capacity() const; 256 void shrink_to_fit(); 257 258 // -------------------------------------------------------------------------- 259 // Size management. 260 // 261 // clear() leaves the capacity() of the flat_tree unchanged. 262 263 void clear(); 264 265 constexpr size_type size() const; 266 constexpr size_type max_size() const; 267 constexpr bool empty() const; 268 269 // -------------------------------------------------------------------------- 270 // Iterators. 271 // 272 // Iterators follow the ordering defined by the key comparator used in 273 // construction of the flat_tree. 274 275 iterator begin(); 276 constexpr const_iterator begin() const; 277 const_iterator cbegin() const; 278 279 iterator end(); 280 constexpr const_iterator end() const; 281 const_iterator cend() const; 282 283 reverse_iterator rbegin(); 284 const_reverse_iterator rbegin() const; 285 const_reverse_iterator crbegin() const; 286 287 reverse_iterator rend(); 288 const_reverse_iterator rend() const; 289 const_reverse_iterator crend() const; 290 291 // -------------------------------------------------------------------------- 292 // Insert operations. 293 // 294 // Assume that every operation invalidates iterators and references. 295 // Insertion of one element can take O(size). Capacity of flat_tree grows in 296 // an implementation-defined manner. 297 // 298 // NOTE: Prefer to build a new flat_tree from a std::vector (or similar) 299 // instead of calling insert() repeatedly. 300 301 std::pair<iterator, bool> insert(const value_type& val); 302 std::pair<iterator, bool> insert(value_type&& val); 303 304 iterator insert(const_iterator position_hint, const value_type& x); 305 iterator insert(const_iterator position_hint, value_type&& x); 306 307 // This method inserts the values from the range [first, last) into the 308 // current tree. 309 template <class InputIterator> 310 void insert(InputIterator first, InputIterator last); 311 312 template <class... Args> 313 std::pair<iterator, bool> emplace(Args&&... args); 314 315 template <class... Args> 316 iterator emplace_hint(const_iterator position_hint, Args&&... args); 317 318 // -------------------------------------------------------------------------- 319 // Underlying type operations. 320 // 321 // Assume that either operation invalidates iterators and references. 322 323 // Extracts the container_type and returns it to the caller. Ensures that 324 // `this` is `empty()` afterwards. 325 container_type extract() &&; 326 327 // Replaces the container_type with `body`. Expects that `body` is sorted 328 // and has no repeated elements with regard to value_comp(). 329 void replace(container_type&& body); 330 331 // -------------------------------------------------------------------------- 332 // Erase operations. 333 // 334 // Assume that every operation invalidates iterators and references. 335 // 336 // erase(position), erase(first, last) can take O(size). 337 // erase(key) may take O(size) + O(log(size)). 338 // 339 // Prefer base::EraseIf() or some other variation on erase(remove(), end()) 340 // idiom when deleting multiple non-consecutive elements. 341 342 iterator erase(iterator position); 343 // Artificially templatized to break ambiguity if `iterator` and 344 // `const_iterator` are the same type. 345 template <typename DummyT = void> 346 iterator erase(const_iterator position); 347 iterator erase(const_iterator first, const_iterator last); 348 size_type erase(const Key& key); 349 template <typename K> 350 size_type erase(const K& key); 351 352 // -------------------------------------------------------------------------- 353 // Comparators. 354 355 constexpr key_compare key_comp() const; 356 constexpr value_compare value_comp() const; 357 358 // -------------------------------------------------------------------------- 359 // Search operations. 360 // 361 // Search operations have O(log(size)) complexity. 362 363 size_type count(const Key& key) const; 364 template <typename K> 365 size_type count(const K& key) const; 366 367 iterator find(const Key& key); 368 const_iterator find(const Key& key) const; 369 template <typename K> 370 iterator find(const K& key); 371 template <typename K> 372 const_iterator find(const K& key) const; 373 374 bool contains(const Key& key) const; 375 template <typename K> 376 bool contains(const K& key) const; 377 378 std::pair<iterator, iterator> equal_range(const Key& key); 379 std::pair<const_iterator, const_iterator> equal_range(const Key& key) const; 380 template <typename K> 381 std::pair<iterator, iterator> equal_range(const K& key); 382 template <typename K> 383 std::pair<const_iterator, const_iterator> equal_range(const K& key) const; 384 385 iterator lower_bound(const Key& key); 386 const_iterator lower_bound(const Key& key) const; 387 template <typename K> 388 iterator lower_bound(const K& key); 389 template <typename K> 390 const_iterator lower_bound(const K& key) const; 391 392 iterator upper_bound(const Key& key); 393 const_iterator upper_bound(const Key& key) const; 394 template <typename K> 395 iterator upper_bound(const K& key); 396 template <typename K> 397 const_iterator upper_bound(const K& key) const; 398 399 // -------------------------------------------------------------------------- 400 // General operations. 401 // 402 // Assume that swap invalidates iterators and references. 403 // 404 // Implementation note: currently we use operator==() and operator<() on 405 // std::vector, because they have the same contract we need, so we use them 406 // directly for brevity and in case it is more optimal than calling equal() 407 // and lexicograhpical_compare(). If the underlying container type is changed, 408 // this code may need to be modified. 409 410 void swap(flat_tree& other) noexcept; 411 412 friend bool operator==(const flat_tree& lhs, const flat_tree& rhs) { 413 return lhs.body_ == rhs.body_; 414 } 415 416 friend bool operator!=(const flat_tree& lhs, const flat_tree& rhs) { 417 return !(lhs == rhs); 418 } 419 420 friend bool operator<(const flat_tree& lhs, const flat_tree& rhs) { 421 return lhs.body_ < rhs.body_; 422 } 423 424 friend bool operator>(const flat_tree& lhs, const flat_tree& rhs) { 425 return rhs < lhs; 426 } 427 428 friend bool operator>=(const flat_tree& lhs, const flat_tree& rhs) { 429 return !(lhs < rhs); 430 } 431 432 friend bool operator<=(const flat_tree& lhs, const flat_tree& rhs) { 433 return !(lhs > rhs); 434 } 435 436 friend void swap(flat_tree& lhs, flat_tree& rhs) noexcept { lhs.swap(rhs); } 437 438 protected: 439 // Emplaces a new item into the tree that is known not to be in it. This 440 // is for implementing map operator[]. 441 template <class... Args> 442 iterator unsafe_emplace(const_iterator position, Args&&... args); 443 444 // Attempts to emplace a new element with key |key|. Only if |key| is not yet 445 // present, construct value_type from |args| and insert it. Returns an 446 // iterator to the element with key |key| and a bool indicating whether an 447 // insertion happened. 448 template <class K, class... Args> 449 std::pair<iterator, bool> emplace_key_args(const K& key, Args&&... args); 450 451 // Similar to |emplace_key_args|, but checks |hint| first as a possible 452 // insertion position. 453 template <class K, class... Args> 454 std::pair<iterator, bool> emplace_hint_key_args(const_iterator hint, 455 const K& key, 456 Args&&... args); 457 458 private: 459 // Helper class for e.g. lower_bound that can compare a value on the left 460 // to a key on the right. 461 struct KeyValueCompare { 462 // The key comparison object must outlive this class. 463 explicit KeyValueCompare(const key_compare& comp) : comp_(comp) {} 464 465 template <typename T, typename U> 466 bool operator()(const T& lhs, const U& rhs) const { 467 return comp_(extract_if_value_type(lhs), extract_if_value_type(rhs)); 468 } 469 470 private: 471 const key_type& extract_if_value_type(const value_type& v) const { 472 GetKeyFromValue extractor; 473 return extractor(v); 474 } 475 476 template <typename K> 477 const K& extract_if_value_type(const K& k) const { 478 return k; 479 } 480 // This field was not rewritten into `const raw_ref<const key_compare>` due 481 // to binary size increase. There's also little value to rewriting this 482 // member as it points to `flat_tree::comp_`. The flat_tree itself should be 483 // holding raw_ptr/raw_ref if necessary. 484 RAW_PTR_EXCLUSION const key_compare& comp_; 485 }; 486 487 iterator const_cast_it(const_iterator c_it) { 488 auto distance = std::distance(cbegin(), c_it); 489 return std::next(begin(), distance); 490 } 491 492 // This method is inspired by both std::map::insert(P&&) and 493 // std::map::insert_or_assign(const K&, V&&). It inserts val if an equivalent 494 // element is not present yet, otherwise it overwrites. It returns an iterator 495 // to the modified element and a flag indicating whether insertion or 496 // assignment happened. 497 template <class V> 498 std::pair<iterator, bool> insert_or_assign(V&& val) { 499 auto position = lower_bound(GetKeyFromValue()(val)); 500 501 if (position == end() || value_comp()(val, *position)) 502 return {body_.emplace(position, std::forward<V>(val)), true}; 503 504 *position = std::forward<V>(val); 505 return {position, false}; 506 } 507 508 // This method is similar to insert_or_assign, with the following differences: 509 // - Instead of searching [begin(), end()) it only searches [first, last). 510 // - In case no equivalent element is found, val is appended to the end of the 511 // underlying body and an iterator to the next bigger element in [first, 512 // last) is returned. 513 template <class V> 514 std::pair<iterator, bool> append_or_assign(iterator first, 515 iterator last, 516 V&& val) { 517 auto position = std::lower_bound(first, last, val, value_comp()); 518 519 if (position == last || value_comp()(val, *position)) { 520 // emplace_back might invalidate position, which is why distance needs to 521 // be cached. 522 const difference_type distance = std::distance(begin(), position); 523 body_.emplace_back(std::forward<V>(val)); 524 return {std::next(begin(), distance), true}; 525 } 526 527 *position = std::forward<V>(val); 528 return {position, false}; 529 } 530 531 // This method is similar to insert, with the following differences: 532 // - Instead of searching [begin(), end()) it only searches [first, last). 533 // - In case no equivalent element is found, val is appended to the end of the 534 // underlying body and an iterator to the next bigger element in [first, 535 // last) is returned. 536 template <class V> 537 std::pair<iterator, bool> append_unique(iterator first, 538 iterator last, 539 V&& val) { 540 auto position = std::lower_bound(first, last, val, value_comp()); 541 542 if (position == last || value_comp()(val, *position)) { 543 // emplace_back might invalidate position, which is why distance needs to 544 // be cached. 545 const difference_type distance = std::distance(begin(), position); 546 body_.emplace_back(std::forward<V>(val)); 547 return {std::next(begin(), distance), true}; 548 } 549 550 return {position, false}; 551 } 552 553 void sort_and_unique(iterator first, iterator last) { 554 // Preserve stability for the unique code below. 555 std::stable_sort(first, last, value_comp()); 556 557 // lhs is already <= rhs due to sort, therefore !(lhs < rhs) <=> lhs == rhs. 558 auto equal_comp = base::not_fn(value_comp()); 559 erase(std::unique(first, last, equal_comp), last); 560 } 561 562 void sort_and_unique() { sort_and_unique(begin(), end()); } 563 564 // To support comparators that may not be possible to default-construct, we 565 // have to store an instance of Compare. Since Compare commonly is stateless, 566 // we use the NO_UNIQUE_ADDRESS attribute to save space. 567 NO_UNIQUE_ADDRESS key_compare comp_; 568 // Declare after |key_compare_comp_| to workaround GCC ICE. For details 569 // see https://crbug.com/1156268 570 container_type body_; 571 572 // If the compare is not transparent we want to construct key_type once. 573 template <typename K> 574 using KeyTypeOrK = typename std:: 575 conditional<IsTransparentCompare<key_compare>::value, K, key_type>::type; 576 }; 577 578 // ---------------------------------------------------------------------------- 579 // Lifetime. 580 581 template <class Key, class GetKeyFromValue, class KeyCompare, class Container> 582 flat_tree<Key, GetKeyFromValue, KeyCompare, Container>::flat_tree( 583 const KeyCompare& comp) 584 : comp_(comp) {} 585 586 template <class Key, class GetKeyFromValue, class KeyCompare, class Container> 587 template <class InputIterator> 588 flat_tree<Key, GetKeyFromValue, KeyCompare, Container>::flat_tree( 589 InputIterator first, 590 InputIterator last, 591 const KeyCompare& comp) 592 : comp_(comp), body_(first, last) { 593 sort_and_unique(); 594 } 595 596 template <class Key, class GetKeyFromValue, class KeyCompare, class Container> 597 flat_tree<Key, GetKeyFromValue, KeyCompare, Container>::flat_tree( 598 const container_type& items, 599 const KeyCompare& comp) 600 : comp_(comp), body_(items) { 601 sort_and_unique(); 602 } 603 604 template <class Key, class GetKeyFromValue, class KeyCompare, class Container> 605 flat_tree<Key, GetKeyFromValue, KeyCompare, Container>::flat_tree( 606 container_type&& items, 607 const KeyCompare& comp) 608 : comp_(comp), body_(std::move(items)) { 609 sort_and_unique(); 610 } 611 612 template <class Key, class GetKeyFromValue, class KeyCompare, class Container> 613 flat_tree<Key, GetKeyFromValue, KeyCompare, Container>::flat_tree( 614 std::initializer_list<value_type> ilist, 615 const KeyCompare& comp) 616 : flat_tree(std::begin(ilist), std::end(ilist), comp) {} 617 618 template <class Key, class GetKeyFromValue, class KeyCompare, class Container> 619 template <class InputIterator> 620 flat_tree<Key, GetKeyFromValue, KeyCompare, Container>::flat_tree( 621 sorted_unique_t, 622 InputIterator first, 623 InputIterator last, 624 const KeyCompare& comp) 625 : comp_(comp), body_(first, last) { 626 DCHECK(is_sorted_and_unique(*this, value_comp())); 627 } 628 629 template <class Key, class GetKeyFromValue, class KeyCompare, class Container> 630 flat_tree<Key, GetKeyFromValue, KeyCompare, Container>::flat_tree( 631 sorted_unique_t, 632 const container_type& items, 633 const KeyCompare& comp) 634 : comp_(comp), body_(items) { 635 DCHECK(is_sorted_and_unique(*this, value_comp())); 636 } 637 638 template <class Key, class GetKeyFromValue, class KeyCompare, class Container> 639 constexpr flat_tree<Key, GetKeyFromValue, KeyCompare, Container>::flat_tree( 640 sorted_unique_t, 641 container_type&& items, 642 const KeyCompare& comp) 643 : comp_(comp), body_(std::move(items)) { 644 DCHECK(is_sorted_and_unique(*this, value_comp())); 645 } 646 647 template <class Key, class GetKeyFromValue, class KeyCompare, class Container> 648 flat_tree<Key, GetKeyFromValue, KeyCompare, Container>::flat_tree( 649 sorted_unique_t, 650 std::initializer_list<value_type> ilist, 651 const KeyCompare& comp) 652 : flat_tree(sorted_unique, std::begin(ilist), std::end(ilist), comp) {} 653 654 // ---------------------------------------------------------------------------- 655 // Assignments. 656 657 template <class Key, class GetKeyFromValue, class KeyCompare, class Container> 658 auto flat_tree<Key, GetKeyFromValue, KeyCompare, Container>::operator=( 659 std::initializer_list<value_type> ilist) -> flat_tree& { 660 body_ = ilist; 661 sort_and_unique(); 662 return *this; 663 } 664 665 // ---------------------------------------------------------------------------- 666 // Memory management. 667 668 template <class Key, class GetKeyFromValue, class KeyCompare, class Container> 669 void flat_tree<Key, GetKeyFromValue, KeyCompare, Container>::reserve( 670 size_type new_capacity) { 671 body_.reserve(new_capacity); 672 } 673 674 template <class Key, class GetKeyFromValue, class KeyCompare, class Container> 675 auto flat_tree<Key, GetKeyFromValue, KeyCompare, Container>::capacity() const 676 -> size_type { 677 return body_.capacity(); 678 } 679 680 template <class Key, class GetKeyFromValue, class KeyCompare, class Container> 681 void flat_tree<Key, GetKeyFromValue, KeyCompare, Container>::shrink_to_fit() { 682 body_.shrink_to_fit(); 683 } 684 685 // ---------------------------------------------------------------------------- 686 // Size management. 687 688 template <class Key, class GetKeyFromValue, class KeyCompare, class Container> 689 void flat_tree<Key, GetKeyFromValue, KeyCompare, Container>::clear() { 690 body_.clear(); 691 } 692 693 template <class Key, class GetKeyFromValue, class KeyCompare, class Container> 694 constexpr auto flat_tree<Key, GetKeyFromValue, KeyCompare, Container>::size() 695 const -> size_type { 696 return body_.size(); 697 } 698 699 template <class Key, class GetKeyFromValue, class KeyCompare, class Container> 700 constexpr auto 701 flat_tree<Key, GetKeyFromValue, KeyCompare, Container>::max_size() const 702 -> size_type { 703 return body_.max_size(); 704 } 705 706 template <class Key, class GetKeyFromValue, class KeyCompare, class Container> 707 constexpr bool flat_tree<Key, GetKeyFromValue, KeyCompare, Container>::empty() 708 const { 709 return body_.empty(); 710 } 711 712 // ---------------------------------------------------------------------------- 713 // Iterators. 714 715 template <class Key, class GetKeyFromValue, class KeyCompare, class Container> 716 auto flat_tree<Key, GetKeyFromValue, KeyCompare, Container>::begin() 717 -> iterator { 718 return body_.begin(); 719 } 720 721 template <class Key, class GetKeyFromValue, class KeyCompare, class Container> 722 constexpr auto flat_tree<Key, GetKeyFromValue, KeyCompare, Container>::begin() 723 const -> const_iterator { 724 return ranges::begin(body_); 725 } 726 727 template <class Key, class GetKeyFromValue, class KeyCompare, class Container> 728 auto flat_tree<Key, GetKeyFromValue, KeyCompare, Container>::cbegin() const 729 -> const_iterator { 730 return body_.cbegin(); 731 } 732 733 template <class Key, class GetKeyFromValue, class KeyCompare, class Container> 734 auto flat_tree<Key, GetKeyFromValue, KeyCompare, Container>::end() -> iterator { 735 return body_.end(); 736 } 737 738 template <class Key, class GetKeyFromValue, class KeyCompare, class Container> 739 constexpr auto flat_tree<Key, GetKeyFromValue, KeyCompare, Container>::end() 740 const -> const_iterator { 741 return ranges::end(body_); 742 } 743 744 template <class Key, class GetKeyFromValue, class KeyCompare, class Container> 745 auto flat_tree<Key, GetKeyFromValue, KeyCompare, Container>::cend() const 746 -> const_iterator { 747 return body_.cend(); 748 } 749 750 template <class Key, class GetKeyFromValue, class KeyCompare, class Container> 751 auto flat_tree<Key, GetKeyFromValue, KeyCompare, Container>::rbegin() 752 -> reverse_iterator { 753 return body_.rbegin(); 754 } 755 756 template <class Key, class GetKeyFromValue, class KeyCompare, class Container> 757 auto flat_tree<Key, GetKeyFromValue, KeyCompare, Container>::rbegin() const 758 -> const_reverse_iterator { 759 return body_.rbegin(); 760 } 761 762 template <class Key, class GetKeyFromValue, class KeyCompare, class Container> 763 auto flat_tree<Key, GetKeyFromValue, KeyCompare, Container>::crbegin() const 764 -> const_reverse_iterator { 765 return body_.crbegin(); 766 } 767 768 template <class Key, class GetKeyFromValue, class KeyCompare, class Container> 769 auto flat_tree<Key, GetKeyFromValue, KeyCompare, Container>::rend() 770 -> reverse_iterator { 771 return body_.rend(); 772 } 773 774 template <class Key, class GetKeyFromValue, class KeyCompare, class Container> 775 auto flat_tree<Key, GetKeyFromValue, KeyCompare, Container>::rend() const 776 -> const_reverse_iterator { 777 return body_.rend(); 778 } 779 780 template <class Key, class GetKeyFromValue, class KeyCompare, class Container> 781 auto flat_tree<Key, GetKeyFromValue, KeyCompare, Container>::crend() const 782 -> const_reverse_iterator { 783 return body_.crend(); 784 } 785 786 // ---------------------------------------------------------------------------- 787 // Insert operations. 788 // 789 // Currently we use position_hint the same way as eastl or boost: 790 // https://github.com/electronicarts/EASTL/blob/master/include/EASTL/vector_set.h#L493 791 792 template <class Key, class GetKeyFromValue, class KeyCompare, class Container> 793 auto flat_tree<Key, GetKeyFromValue, KeyCompare, Container>::insert( 794 const value_type& val) -> std::pair<iterator, bool> { 795 return emplace_key_args(GetKeyFromValue()(val), val); 796 } 797 798 template <class Key, class GetKeyFromValue, class KeyCompare, class Container> 799 auto flat_tree<Key, GetKeyFromValue, KeyCompare, Container>::insert( 800 value_type&& val) -> std::pair<iterator, bool> { 801 return emplace_key_args(GetKeyFromValue()(val), std::move(val)); 802 } 803 804 template <class Key, class GetKeyFromValue, class KeyCompare, class Container> 805 auto flat_tree<Key, GetKeyFromValue, KeyCompare, Container>::insert( 806 const_iterator position_hint, 807 const value_type& val) -> iterator { 808 return emplace_hint_key_args(position_hint, GetKeyFromValue()(val), val) 809 .first; 810 } 811 812 template <class Key, class GetKeyFromValue, class KeyCompare, class Container> 813 auto flat_tree<Key, GetKeyFromValue, KeyCompare, Container>::insert( 814 const_iterator position_hint, 815 value_type&& val) -> iterator { 816 return emplace_hint_key_args(position_hint, GetKeyFromValue()(val), 817 std::move(val)) 818 .first; 819 } 820 821 template <class Key, class GetKeyFromValue, class KeyCompare, class Container> 822 template <class InputIterator> 823 void flat_tree<Key, GetKeyFromValue, KeyCompare, Container>::insert( 824 InputIterator first, 825 InputIterator last) { 826 if (first == last) 827 return; 828 829 // Dispatch to single element insert if the input range contains a single 830 // element. 831 if (is_multipass<InputIterator>() && std::next(first) == last) { 832 insert(end(), *first); 833 return; 834 } 835 836 // Provide a convenience lambda to obtain an iterator pointing past the last 837 // old element. This needs to be dymanic due to possible re-allocations. 838 auto middle = [this, size = size()] { 839 return std::next(begin(), static_cast<difference_type>(size)); 840 }; 841 842 // For batch updates initialize the first insertion point. 843 auto pos_first_new = static_cast<difference_type>(size()); 844 845 // Loop over the input range while appending new values and overwriting 846 // existing ones, if applicable. Keep track of the first insertion point. 847 for (; first != last; ++first) { 848 std::pair<iterator, bool> result = append_unique(begin(), middle(), *first); 849 if (result.second) { 850 pos_first_new = 851 std::min(pos_first_new, std::distance(begin(), result.first)); 852 } 853 } 854 855 // The new elements might be unordered and contain duplicates, so post-process 856 // the just inserted elements and merge them with the rest, inserting them at 857 // the previously found spot. 858 sort_and_unique(middle(), end()); 859 std::inplace_merge(std::next(begin(), pos_first_new), middle(), end(), 860 value_comp()); 861 } 862 863 template <class Key, class GetKeyFromValue, class KeyCompare, class Container> 864 template <class... Args> 865 auto flat_tree<Key, GetKeyFromValue, KeyCompare, Container>::emplace( 866 Args&&... args) -> std::pair<iterator, bool> { 867 return insert(value_type(std::forward<Args>(args)...)); 868 } 869 870 template <class Key, class GetKeyFromValue, class KeyCompare, class Container> 871 template <class... Args> 872 auto flat_tree<Key, GetKeyFromValue, KeyCompare, Container>::emplace_hint( 873 const_iterator position_hint, 874 Args&&... args) -> iterator { 875 return insert(position_hint, value_type(std::forward<Args>(args)...)); 876 } 877 878 // ---------------------------------------------------------------------------- 879 // Underlying type operations. 880 881 template <class Key, class GetKeyFromValue, class KeyCompare, class Container> 882 auto flat_tree<Key, GetKeyFromValue, KeyCompare, Container>:: 883 extract() && -> container_type { 884 return std::exchange(body_, container_type()); 885 } 886 887 template <class Key, class GetKeyFromValue, class KeyCompare, class Container> 888 void flat_tree<Key, GetKeyFromValue, KeyCompare, Container>::replace( 889 container_type&& body) { 890 // Ensure that `body` is sorted and has no repeated elements according to 891 // `value_comp()`. 892 DCHECK(is_sorted_and_unique(body, value_comp())); 893 body_ = std::move(body); 894 } 895 896 // ---------------------------------------------------------------------------- 897 // Erase operations. 898 899 template <class Key, class GetKeyFromValue, class KeyCompare, class Container> 900 auto flat_tree<Key, GetKeyFromValue, KeyCompare, Container>::erase( 901 iterator position) -> iterator { 902 CHECK(position != body_.end()); 903 return body_.erase(position); 904 } 905 906 template <class Key, class GetKeyFromValue, class KeyCompare, class Container> 907 template <typename DummyT> 908 auto flat_tree<Key, GetKeyFromValue, KeyCompare, Container>::erase( 909 const_iterator position) -> iterator { 910 CHECK(position != body_.end()); 911 return body_.erase(position); 912 } 913 914 template <class Key, class GetKeyFromValue, class KeyCompare, class Container> 915 auto flat_tree<Key, GetKeyFromValue, KeyCompare, Container>::erase( 916 const Key& val) -> size_type { 917 auto eq_range = equal_range(val); 918 auto res = 919 static_cast<size_type>(std::distance(eq_range.first, eq_range.second)); 920 erase(eq_range.first, eq_range.second); 921 return res; 922 } 923 924 template <class Key, class GetKeyFromValue, class KeyCompare, class Container> 925 template <typename K> 926 auto flat_tree<Key, GetKeyFromValue, KeyCompare, Container>::erase(const K& val) 927 -> size_type { 928 auto eq_range = equal_range(val); 929 auto res = 930 static_cast<size_type>(std::distance(eq_range.first, eq_range.second)); 931 erase(eq_range.first, eq_range.second); 932 return res; 933 } 934 935 template <class Key, class GetKeyFromValue, class KeyCompare, class Container> 936 auto flat_tree<Key, GetKeyFromValue, KeyCompare, Container>::erase( 937 const_iterator first, 938 const_iterator last) -> iterator { 939 return body_.erase(first, last); 940 } 941 942 // ---------------------------------------------------------------------------- 943 // Comparators. 944 945 template <class Key, class GetKeyFromValue, class KeyCompare, class Container> 946 constexpr auto 947 flat_tree<Key, GetKeyFromValue, KeyCompare, Container>::key_comp() const 948 -> key_compare { 949 return comp_; 950 } 951 952 template <class Key, class GetKeyFromValue, class KeyCompare, class Container> 953 constexpr auto 954 flat_tree<Key, GetKeyFromValue, KeyCompare, Container>::value_comp() const 955 -> value_compare { 956 return value_compare{comp_}; 957 } 958 959 // ---------------------------------------------------------------------------- 960 // Search operations. 961 962 template <class Key, class GetKeyFromValue, class KeyCompare, class Container> 963 template <typename K> 964 auto flat_tree<Key, GetKeyFromValue, KeyCompare, Container>::count( 965 const K& key) const -> size_type { 966 auto eq_range = equal_range(key); 967 return static_cast<size_type>(std::distance(eq_range.first, eq_range.second)); 968 } 969 970 template <class Key, class GetKeyFromValue, class KeyCompare, class Container> 971 auto flat_tree<Key, GetKeyFromValue, KeyCompare, Container>::count( 972 const Key& key) const -> size_type { 973 auto eq_range = equal_range(key); 974 return static_cast<size_type>(std::distance(eq_range.first, eq_range.second)); 975 } 976 977 template <class Key, class GetKeyFromValue, class KeyCompare, class Container> 978 auto flat_tree<Key, GetKeyFromValue, KeyCompare, Container>::find( 979 const Key& key) -> iterator { 980 return const_cast_it(std::as_const(*this).find(key)); 981 } 982 983 template <class Key, class GetKeyFromValue, class KeyCompare, class Container> 984 auto flat_tree<Key, GetKeyFromValue, KeyCompare, Container>::find( 985 const Key& key) const -> const_iterator { 986 auto eq_range = equal_range(key); 987 return (eq_range.first == eq_range.second) ? end() : eq_range.first; 988 } 989 990 template <class Key, class GetKeyFromValue, class KeyCompare, class Container> 991 template <typename K> 992 auto flat_tree<Key, GetKeyFromValue, KeyCompare, Container>::find(const K& key) 993 -> iterator { 994 return const_cast_it(std::as_const(*this).find(key)); 995 } 996 997 template <class Key, class GetKeyFromValue, class KeyCompare, class Container> 998 template <typename K> 999 auto flat_tree<Key, GetKeyFromValue, KeyCompare, Container>::find( 1000 const K& key) const -> const_iterator { 1001 auto eq_range = equal_range(key); 1002 return (eq_range.first == eq_range.second) ? end() : eq_range.first; 1003 } 1004 1005 template <class Key, class GetKeyFromValue, class KeyCompare, class Container> 1006 bool flat_tree<Key, GetKeyFromValue, KeyCompare, Container>::contains( 1007 const Key& key) const { 1008 auto lower = lower_bound(key); 1009 return lower != end() && !comp_(key, GetKeyFromValue()(*lower)); 1010 } 1011 1012 template <class Key, class GetKeyFromValue, class KeyCompare, class Container> 1013 template <typename K> 1014 bool flat_tree<Key, GetKeyFromValue, KeyCompare, Container>::contains( 1015 const K& key) const { 1016 auto lower = lower_bound(key); 1017 return lower != end() && !comp_(key, GetKeyFromValue()(*lower)); 1018 } 1019 1020 template <class Key, class GetKeyFromValue, class KeyCompare, class Container> 1021 auto flat_tree<Key, GetKeyFromValue, KeyCompare, Container>::equal_range( 1022 const Key& key) -> std::pair<iterator, iterator> { 1023 auto res = std::as_const(*this).equal_range(key); 1024 return {const_cast_it(res.first), const_cast_it(res.second)}; 1025 } 1026 1027 template <class Key, class GetKeyFromValue, class KeyCompare, class Container> 1028 auto flat_tree<Key, GetKeyFromValue, KeyCompare, Container>::equal_range( 1029 const Key& key) const -> std::pair<const_iterator, const_iterator> { 1030 auto lower = lower_bound(key); 1031 1032 KeyValueCompare comp(comp_); 1033 if (lower == end() || comp(key, *lower)) 1034 return {lower, lower}; 1035 1036 return {lower, std::next(lower)}; 1037 } 1038 1039 template <class Key, class GetKeyFromValue, class KeyCompare, class Container> 1040 template <typename K> 1041 auto flat_tree<Key, GetKeyFromValue, KeyCompare, Container>::equal_range( 1042 const K& key) -> std::pair<iterator, iterator> { 1043 auto res = std::as_const(*this).equal_range(key); 1044 return {const_cast_it(res.first), const_cast_it(res.second)}; 1045 } 1046 1047 template <class Key, class GetKeyFromValue, class KeyCompare, class Container> 1048 template <typename K> 1049 auto flat_tree<Key, GetKeyFromValue, KeyCompare, Container>::equal_range( 1050 const K& key) const -> std::pair<const_iterator, const_iterator> { 1051 auto lower = lower_bound(key); 1052 1053 KeyValueCompare comp(comp_); 1054 if (lower == end() || comp(key, *lower)) 1055 return {lower, lower}; 1056 1057 return {lower, std::next(lower)}; 1058 } 1059 1060 template <class Key, class GetKeyFromValue, class KeyCompare, class Container> 1061 auto flat_tree<Key, GetKeyFromValue, KeyCompare, Container>::lower_bound( 1062 const Key& key) -> iterator { 1063 return const_cast_it(std::as_const(*this).lower_bound(key)); 1064 } 1065 1066 template <class Key, class GetKeyFromValue, class KeyCompare, class Container> 1067 auto flat_tree<Key, GetKeyFromValue, KeyCompare, Container>::lower_bound( 1068 const Key& key) const -> const_iterator { 1069 KeyValueCompare comp(comp_); 1070 return ranges::lower_bound(*this, key, comp); 1071 } 1072 1073 template <class Key, class GetKeyFromValue, class KeyCompare, class Container> 1074 template <typename K> 1075 auto flat_tree<Key, GetKeyFromValue, KeyCompare, Container>::lower_bound( 1076 const K& key) -> iterator { 1077 return const_cast_it(std::as_const(*this).lower_bound(key)); 1078 } 1079 1080 template <class Key, class GetKeyFromValue, class KeyCompare, class Container> 1081 template <typename K> 1082 auto flat_tree<Key, GetKeyFromValue, KeyCompare, Container>::lower_bound( 1083 const K& key) const -> const_iterator { 1084 static_assert(std::is_convertible_v<const KeyTypeOrK<K>&, const K&>, 1085 "Requested type cannot be bound to the container's key_type " 1086 "which is required for a non-transparent compare."); 1087 1088 const KeyTypeOrK<K>& key_ref = key; 1089 1090 KeyValueCompare comp(comp_); 1091 return ranges::lower_bound(*this, key_ref, comp); 1092 } 1093 1094 template <class Key, class GetKeyFromValue, class KeyCompare, class Container> 1095 auto flat_tree<Key, GetKeyFromValue, KeyCompare, Container>::upper_bound( 1096 const Key& key) -> iterator { 1097 return const_cast_it(std::as_const(*this).upper_bound(key)); 1098 } 1099 1100 template <class Key, class GetKeyFromValue, class KeyCompare, class Container> 1101 auto flat_tree<Key, GetKeyFromValue, KeyCompare, Container>::upper_bound( 1102 const Key& key) const -> const_iterator { 1103 KeyValueCompare comp(comp_); 1104 return ranges::upper_bound(*this, key, comp); 1105 } 1106 1107 template <class Key, class GetKeyFromValue, class KeyCompare, class Container> 1108 template <typename K> 1109 auto flat_tree<Key, GetKeyFromValue, KeyCompare, Container>::upper_bound( 1110 const K& key) -> iterator { 1111 return const_cast_it(std::as_const(*this).upper_bound(key)); 1112 } 1113 1114 template <class Key, class GetKeyFromValue, class KeyCompare, class Container> 1115 template <typename K> 1116 auto flat_tree<Key, GetKeyFromValue, KeyCompare, Container>::upper_bound( 1117 const K& key) const -> const_iterator { 1118 static_assert(std::is_convertible_v<const KeyTypeOrK<K>&, const K&>, 1119 "Requested type cannot be bound to the container's key_type " 1120 "which is required for a non-transparent compare."); 1121 1122 const KeyTypeOrK<K>& key_ref = key; 1123 1124 KeyValueCompare comp(comp_); 1125 return ranges::upper_bound(*this, key_ref, comp); 1126 } 1127 1128 // ---------------------------------------------------------------------------- 1129 // General operations. 1130 1131 template <class Key, class GetKeyFromValue, class KeyCompare, class Container> 1132 void flat_tree<Key, GetKeyFromValue, KeyCompare, Container>::swap( 1133 flat_tree& other) noexcept { 1134 std::swap(*this, other); 1135 } 1136 1137 template <class Key, class GetKeyFromValue, class KeyCompare, class Container> 1138 template <class... Args> 1139 auto flat_tree<Key, GetKeyFromValue, KeyCompare, Container>::unsafe_emplace( 1140 const_iterator position, 1141 Args&&... args) -> iterator { 1142 return body_.emplace(position, std::forward<Args>(args)...); 1143 } 1144 1145 template <class Key, class GetKeyFromValue, class KeyCompare, class Container> 1146 template <class K, class... Args> 1147 auto flat_tree<Key, GetKeyFromValue, KeyCompare, Container>::emplace_key_args( 1148 const K& key, 1149 Args&&... args) -> std::pair<iterator, bool> { 1150 auto lower = lower_bound(key); 1151 if (lower == end() || comp_(key, GetKeyFromValue()(*lower))) 1152 return {unsafe_emplace(lower, std::forward<Args>(args)...), true}; 1153 return {lower, false}; 1154 } 1155 1156 template <class Key, class GetKeyFromValue, class KeyCompare, class Container> 1157 template <class K, class... Args> 1158 auto flat_tree<Key, GetKeyFromValue, KeyCompare, Container>:: 1159 emplace_hint_key_args(const_iterator hint, const K& key, Args&&... args) 1160 -> std::pair<iterator, bool> { 1161 KeyValueCompare comp(comp_); 1162 if ((hint == begin() || comp(*std::prev(hint), key))) { 1163 if (hint == end() || comp(key, *hint)) { 1164 // *(hint - 1) < key < *hint => key did not exist and hint is correct. 1165 return {unsafe_emplace(hint, std::forward<Args>(args)...), true}; 1166 } 1167 if (!comp(*hint, key)) { 1168 // key == *hint => no-op, return correct hint. 1169 return {const_cast_it(hint), false}; 1170 } 1171 } 1172 // hint was not helpful, dispatch to hintless version. 1173 return emplace_key_args(key, std::forward<Args>(args)...); 1174 } 1175 1176 } // namespace internal 1177 1178 // ---------------------------------------------------------------------------- 1179 // Free functions. 1180 1181 // Erases all elements that match predicate. It has O(size) complexity. 1182 template <class Key, 1183 class GetKeyFromValue, 1184 class KeyCompare, 1185 class Container, 1186 typename Predicate> 1187 size_t EraseIf( 1188 base::internal::flat_tree<Key, GetKeyFromValue, KeyCompare, Container>& 1189 container, 1190 Predicate pred) { 1191 auto it = ranges::remove_if(container, pred); 1192 size_t removed = std::distance(it, container.end()); 1193 container.erase(it, container.end()); 1194 return removed; 1195 } 1196 1197 } // namespace base 1198 1199 #endif // BASE_CONTAINERS_FLAT_TREE_H_