tor-browser

The Tor Browser
git clone https://git.dasho.dev/tor-browser.git
Log | Files | Refs | README | LICENSE

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_