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