• Home
  • Line#
  • Scopes#
  • Navigate#
  • Raw
  • Download
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 <initializer_list>
12 #include <iterator>
13 #include <type_traits>
14 #include <utility>
15 
16 #include "base/check.h"
17 #include "base/compiler_specific.h"
18 #include "base/functional/not_fn.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, base::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     // This field was not rewritten into `const raw_ref<const key_compare>` due
402     // to binary size increase. There's also little value to rewriting this
403     // member as it points to `flat_tree::comp_`. The flat_tree itself should be
404     // holding raw_ptr/raw_ref if necessary.
405     RAW_PTR_EXCLUSION const key_compare& comp_;
406   };
407 
const_cast_it(const_iterator c_it)408   iterator const_cast_it(const_iterator c_it) {
409     auto distance = std::distance(cbegin(), c_it);
410     return std::next(begin(), distance);
411   }
412 
413   // This method is inspired by both std::map::insert(P&&) and
414   // std::map::insert_or_assign(const K&, V&&). It inserts val if an equivalent
415   // element is not present yet, otherwise it overwrites. It returns an iterator
416   // to the modified element and a flag indicating whether insertion or
417   // assignment happened.
418   template <class V>
insert_or_assign(V && val)419   std::pair<iterator, bool> insert_or_assign(V&& val) {
420     auto position = lower_bound(GetKeyFromValue()(val));
421 
422     if (position == end() || value_comp()(val, *position))
423       return {body_.emplace(position, std::forward<V>(val)), true};
424 
425     *position = std::forward<V>(val);
426     return {position, false};
427   }
428 
429   // This method is similar to insert_or_assign, with the following differences:
430   // - Instead of searching [begin(), end()) it only searches [first, last).
431   // - In case no equivalent element is found, val is appended to the end of the
432   //   underlying body and an iterator to the next bigger element in [first,
433   //   last) is returned.
434   template <class V>
append_or_assign(iterator first,iterator last,V && val)435   std::pair<iterator, bool> append_or_assign(iterator first,
436                                              iterator last,
437                                              V&& val) {
438     auto position = std::lower_bound(first, last, val, value_comp());
439 
440     if (position == last || value_comp()(val, *position)) {
441       // emplace_back might invalidate position, which is why distance needs to
442       // be cached.
443       const difference_type distance = std::distance(begin(), position);
444       body_.emplace_back(std::forward<V>(val));
445       return {std::next(begin(), distance), true};
446     }
447 
448     *position = std::forward<V>(val);
449     return {position, false};
450   }
451 
452   // This method is similar to insert, with the following differences:
453   // - Instead of searching [begin(), end()) it only searches [first, last).
454   // - In case no equivalent element is found, val is appended to the end of the
455   //   underlying body and an iterator to the next bigger element in [first,
456   //   last) is returned.
457   template <class V>
append_unique(iterator first,iterator last,V && val)458   std::pair<iterator, bool> append_unique(iterator first,
459                                           iterator last,
460                                           V&& val) {
461     auto position = std::lower_bound(first, last, val, value_comp());
462 
463     if (position == last || value_comp()(val, *position)) {
464       // emplace_back might invalidate position, which is why distance needs to
465       // be cached.
466       const difference_type distance = std::distance(begin(), position);
467       body_.emplace_back(std::forward<V>(val));
468       return {std::next(begin(), distance), true};
469     }
470 
471     return {position, false};
472   }
473 
sort_and_unique(iterator first,iterator last)474   void sort_and_unique(iterator first, iterator last) {
475     // Preserve stability for the unique code below.
476     std::stable_sort(first, last, value_comp());
477 
478     // lhs is already <= rhs due to sort, therefore !(lhs < rhs) <=> lhs == rhs.
479     auto equal_comp = base::not_fn(value_comp());
480     erase(std::unique(first, last, equal_comp), last);
481   }
482 
sort_and_unique()483   void sort_and_unique() { sort_and_unique(begin(), end()); }
484 
485   // To support comparators that may not be possible to default-construct, we
486   // have to store an instance of Compare. Since Compare commonly is stateless,
487   // we use the NO_UNIQUE_ADDRESS attribute to save space.
488   NO_UNIQUE_ADDRESS key_compare comp_;
489   // Declare after |key_compare_comp_| to workaround GCC ICE. For details
490   // see https://crbug.com/1156268
491   container_type body_;
492 
493   // If the compare is not transparent we want to construct key_type once.
494   template <typename K>
495   using KeyTypeOrK = std::conditional_t<requires {
496     typename key_compare::is_transparent;
497   }, K, key_type>;
498 };
499 
500 // ----------------------------------------------------------------------------
501 // Lifetime.
502 
503 template <class Key, class GetKeyFromValue, class KeyCompare, class Container>
flat_tree(const KeyCompare & comp)504 flat_tree<Key, GetKeyFromValue, KeyCompare, Container>::flat_tree(
505     const KeyCompare& comp)
506     : comp_(comp) {}
507 
508 template <class Key, class GetKeyFromValue, class KeyCompare, class Container>
509 template <class InputIterator>
flat_tree(InputIterator first,InputIterator last,const KeyCompare & comp)510 flat_tree<Key, GetKeyFromValue, KeyCompare, Container>::flat_tree(
511     InputIterator first,
512     InputIterator last,
513     const KeyCompare& comp)
514     : comp_(comp), body_(first, last) {
515   sort_and_unique();
516 }
517 
518 template <class Key, class GetKeyFromValue, class KeyCompare, class Container>
flat_tree(const container_type & items,const KeyCompare & comp)519 flat_tree<Key, GetKeyFromValue, KeyCompare, Container>::flat_tree(
520     const container_type& items,
521     const KeyCompare& comp)
522     : comp_(comp), body_(items) {
523   sort_and_unique();
524 }
525 
526 template <class Key, class GetKeyFromValue, class KeyCompare, class Container>
flat_tree(container_type && items,const KeyCompare & comp)527 flat_tree<Key, GetKeyFromValue, KeyCompare, Container>::flat_tree(
528     container_type&& items,
529     const KeyCompare& comp)
530     : comp_(comp), body_(std::move(items)) {
531   sort_and_unique();
532 }
533 
534 template <class Key, class GetKeyFromValue, class KeyCompare, class Container>
flat_tree(std::initializer_list<value_type> ilist,const KeyCompare & comp)535 flat_tree<Key, GetKeyFromValue, KeyCompare, Container>::flat_tree(
536     std::initializer_list<value_type> ilist,
537     const KeyCompare& comp)
538     : flat_tree(std::begin(ilist), std::end(ilist), comp) {}
539 
540 template <class Key, class GetKeyFromValue, class KeyCompare, class Container>
541 template <class InputIterator>
flat_tree(sorted_unique_t,InputIterator first,InputIterator last,const KeyCompare & comp)542 flat_tree<Key, GetKeyFromValue, KeyCompare, Container>::flat_tree(
543     sorted_unique_t,
544     InputIterator first,
545     InputIterator last,
546     const KeyCompare& comp)
547     : comp_(comp), body_(first, last) {
548   DCHECK(is_sorted_and_unique(*this, value_comp()));
549 }
550 
551 template <class Key, class GetKeyFromValue, class KeyCompare, class Container>
flat_tree(sorted_unique_t,const container_type & items,const KeyCompare & comp)552 flat_tree<Key, GetKeyFromValue, KeyCompare, Container>::flat_tree(
553     sorted_unique_t,
554     const container_type& items,
555     const KeyCompare& comp)
556     : comp_(comp), body_(items) {
557   DCHECK(is_sorted_and_unique(*this, value_comp()));
558 }
559 
560 template <class Key, class GetKeyFromValue, class KeyCompare, class Container>
flat_tree(sorted_unique_t,container_type && items,const KeyCompare & comp)561 constexpr flat_tree<Key, GetKeyFromValue, KeyCompare, Container>::flat_tree(
562     sorted_unique_t,
563     container_type&& items,
564     const KeyCompare& comp)
565     : comp_(comp), body_(std::move(items)) {
566   DCHECK(is_sorted_and_unique(*this, value_comp()));
567 }
568 
569 template <class Key, class GetKeyFromValue, class KeyCompare, class Container>
flat_tree(sorted_unique_t,std::initializer_list<value_type> ilist,const KeyCompare & comp)570 flat_tree<Key, GetKeyFromValue, KeyCompare, Container>::flat_tree(
571     sorted_unique_t,
572     std::initializer_list<value_type> ilist,
573     const KeyCompare& comp)
574     : flat_tree(sorted_unique, std::begin(ilist), std::end(ilist), comp) {}
575 
576 // ----------------------------------------------------------------------------
577 // Assignments.
578 
579 template <class Key, class GetKeyFromValue, class KeyCompare, class Container>
580 auto flat_tree<Key, GetKeyFromValue, KeyCompare, Container>::operator=(
581     std::initializer_list<value_type> ilist) -> flat_tree& {
582   body_ = ilist;
583   sort_and_unique();
584   return *this;
585 }
586 
587 // ----------------------------------------------------------------------------
588 // Memory management.
589 
590 template <class Key, class GetKeyFromValue, class KeyCompare, class Container>
reserve(size_type new_capacity)591 void flat_tree<Key, GetKeyFromValue, KeyCompare, Container>::reserve(
592     size_type new_capacity) {
593   body_.reserve(new_capacity);
594 }
595 
596 template <class Key, class GetKeyFromValue, class KeyCompare, class Container>
597 auto flat_tree<Key, GetKeyFromValue, KeyCompare, Container>::capacity() const
598     -> size_type {
599   return body_.capacity();
600 }
601 
602 template <class Key, class GetKeyFromValue, class KeyCompare, class Container>
shrink_to_fit()603 void flat_tree<Key, GetKeyFromValue, KeyCompare, Container>::shrink_to_fit() {
604   body_.shrink_to_fit();
605 }
606 
607 // ----------------------------------------------------------------------------
608 // Size management.
609 
610 template <class Key, class GetKeyFromValue, class KeyCompare, class Container>
clear()611 void flat_tree<Key, GetKeyFromValue, KeyCompare, Container>::clear() {
612   body_.clear();
613 }
614 
615 template <class Key, class GetKeyFromValue, class KeyCompare, class Container>
616 constexpr auto flat_tree<Key, GetKeyFromValue, KeyCompare, Container>::size()
617     const -> size_type {
618   return body_.size();
619 }
620 
621 template <class Key, class GetKeyFromValue, class KeyCompare, class Container>
622 constexpr auto
623 flat_tree<Key, GetKeyFromValue, KeyCompare, Container>::max_size() const
624     -> size_type {
625   return body_.max_size();
626 }
627 
628 template <class Key, class GetKeyFromValue, class KeyCompare, class Container>
empty()629 constexpr bool flat_tree<Key, GetKeyFromValue, KeyCompare, Container>::empty()
630     const {
631   return body_.empty();
632 }
633 
634 // ----------------------------------------------------------------------------
635 // Iterators.
636 
637 template <class Key, class GetKeyFromValue, class KeyCompare, class Container>
638 auto flat_tree<Key, GetKeyFromValue, KeyCompare, Container>::begin()
639     -> iterator {
640   return body_.begin();
641 }
642 
643 template <class Key, class GetKeyFromValue, class KeyCompare, class Container>
644 constexpr auto flat_tree<Key, GetKeyFromValue, KeyCompare, Container>::begin()
645     const -> const_iterator {
646   return ranges::begin(body_);
647 }
648 
649 template <class Key, class GetKeyFromValue, class KeyCompare, class Container>
650 auto flat_tree<Key, GetKeyFromValue, KeyCompare, Container>::cbegin() const
651     -> const_iterator {
652   return body_.cbegin();
653 }
654 
655 template <class Key, class GetKeyFromValue, class KeyCompare, class Container>
656 auto flat_tree<Key, GetKeyFromValue, KeyCompare, Container>::end() -> iterator {
657   return body_.end();
658 }
659 
660 template <class Key, class GetKeyFromValue, class KeyCompare, class Container>
661 constexpr auto flat_tree<Key, GetKeyFromValue, KeyCompare, Container>::end()
662     const -> const_iterator {
663   return ranges::end(body_);
664 }
665 
666 template <class Key, class GetKeyFromValue, class KeyCompare, class Container>
667 auto flat_tree<Key, GetKeyFromValue, KeyCompare, Container>::cend() const
668     -> const_iterator {
669   return body_.cend();
670 }
671 
672 template <class Key, class GetKeyFromValue, class KeyCompare, class Container>
673 auto flat_tree<Key, GetKeyFromValue, KeyCompare, Container>::rbegin()
674     -> reverse_iterator {
675   return body_.rbegin();
676 }
677 
678 template <class Key, class GetKeyFromValue, class KeyCompare, class Container>
679 auto flat_tree<Key, GetKeyFromValue, KeyCompare, Container>::rbegin() const
680     -> const_reverse_iterator {
681   return body_.rbegin();
682 }
683 
684 template <class Key, class GetKeyFromValue, class KeyCompare, class Container>
685 auto flat_tree<Key, GetKeyFromValue, KeyCompare, Container>::crbegin() const
686     -> const_reverse_iterator {
687   return body_.crbegin();
688 }
689 
690 template <class Key, class GetKeyFromValue, class KeyCompare, class Container>
691 auto flat_tree<Key, GetKeyFromValue, KeyCompare, Container>::rend()
692     -> reverse_iterator {
693   return body_.rend();
694 }
695 
696 template <class Key, class GetKeyFromValue, class KeyCompare, class Container>
697 auto flat_tree<Key, GetKeyFromValue, KeyCompare, Container>::rend() const
698     -> const_reverse_iterator {
699   return body_.rend();
700 }
701 
702 template <class Key, class GetKeyFromValue, class KeyCompare, class Container>
703 auto flat_tree<Key, GetKeyFromValue, KeyCompare, Container>::crend() const
704     -> const_reverse_iterator {
705   return body_.crend();
706 }
707 
708 // ----------------------------------------------------------------------------
709 // Insert operations.
710 //
711 // Currently we use position_hint the same way as eastl or boost:
712 // https://github.com/electronicarts/EASTL/blob/master/include/EASTL/vector_set.h#L493
713 
714 template <class Key, class GetKeyFromValue, class KeyCompare, class Container>
715 auto flat_tree<Key, GetKeyFromValue, KeyCompare, Container>::insert(
716     const value_type& val) -> std::pair<iterator, bool> {
717   return emplace_key_args(GetKeyFromValue()(val), val);
718 }
719 
720 template <class Key, class GetKeyFromValue, class KeyCompare, class Container>
721 auto flat_tree<Key, GetKeyFromValue, KeyCompare, Container>::insert(
722     value_type&& val) -> std::pair<iterator, bool> {
723   return emplace_key_args(GetKeyFromValue()(val), std::move(val));
724 }
725 
726 template <class Key, class GetKeyFromValue, class KeyCompare, class Container>
727 auto flat_tree<Key, GetKeyFromValue, KeyCompare, Container>::insert(
728     const_iterator position_hint,
729     const value_type& val) -> iterator {
730   return emplace_hint_key_args(position_hint, GetKeyFromValue()(val), val)
731       .first;
732 }
733 
734 template <class Key, class GetKeyFromValue, class KeyCompare, class Container>
735 auto flat_tree<Key, GetKeyFromValue, KeyCompare, Container>::insert(
736     const_iterator position_hint,
737     value_type&& val) -> iterator {
738   return emplace_hint_key_args(position_hint, GetKeyFromValue()(val),
739                                std::move(val))
740       .first;
741 }
742 
743 template <class Key, class GetKeyFromValue, class KeyCompare, class Container>
744 template <class InputIterator>
insert(InputIterator first,InputIterator last)745 void flat_tree<Key, GetKeyFromValue, KeyCompare, Container>::insert(
746     InputIterator first,
747     InputIterator last) {
748   if (first == last)
749     return;
750 
751   // Dispatch to single element insert if the input range contains a single
752   // element.
753   if (std::forward_iterator<InputIterator> && std::next(first) == last) {
754     insert(end(), *first);
755     return;
756   }
757 
758   // Provide a convenience lambda to obtain an iterator pointing past the last
759   // old element. This needs to be dymanic due to possible re-allocations.
760   auto middle = [this, size = size()] {
761     return std::next(begin(), static_cast<difference_type>(size));
762   };
763 
764   // For batch updates initialize the first insertion point.
765   auto pos_first_new = static_cast<difference_type>(size());
766 
767   // Loop over the input range while appending new values and overwriting
768   // existing ones, if applicable. Keep track of the first insertion point.
769   for (; first != last; ++first) {
770     std::pair<iterator, bool> result = append_unique(begin(), middle(), *first);
771     if (result.second) {
772       pos_first_new =
773           std::min(pos_first_new, std::distance(begin(), result.first));
774     }
775   }
776 
777   // The new elements might be unordered and contain duplicates, so post-process
778   // the just inserted elements and merge them with the rest, inserting them at
779   // the previously found spot.
780   sort_and_unique(middle(), end());
781   std::inplace_merge(std::next(begin(), pos_first_new), middle(), end(),
782                      value_comp());
783 }
784 
785 template <class Key, class GetKeyFromValue, class KeyCompare, class Container>
786 template <class... Args>
787 auto flat_tree<Key, GetKeyFromValue, KeyCompare, Container>::emplace(
788     Args&&... args) -> std::pair<iterator, bool> {
789   return insert(value_type(std::forward<Args>(args)...));
790 }
791 
792 template <class Key, class GetKeyFromValue, class KeyCompare, class Container>
793 template <class... Args>
794 auto flat_tree<Key, GetKeyFromValue, KeyCompare, Container>::emplace_hint(
795     const_iterator position_hint,
796     Args&&... args) -> iterator {
797   return insert(position_hint, value_type(std::forward<Args>(args)...));
798 }
799 
800 // ----------------------------------------------------------------------------
801 // Underlying type operations.
802 
803 template <class Key, class GetKeyFromValue, class KeyCompare, class Container>
804 auto flat_tree<Key, GetKeyFromValue, KeyCompare, Container>::
805     extract() && -> container_type {
806   return std::exchange(body_, container_type());
807 }
808 
809 template <class Key, class GetKeyFromValue, class KeyCompare, class Container>
replace(container_type && body)810 void flat_tree<Key, GetKeyFromValue, KeyCompare, Container>::replace(
811     container_type&& body) {
812   // Ensure that `body` is sorted and has no repeated elements according to
813   // `value_comp()`.
814   DCHECK(is_sorted_and_unique(body, value_comp()));
815   body_ = std::move(body);
816 }
817 
818 // ----------------------------------------------------------------------------
819 // Erase operations.
820 
821 template <class Key, class GetKeyFromValue, class KeyCompare, class Container>
822 auto flat_tree<Key, GetKeyFromValue, KeyCompare, Container>::erase(
823     iterator position) -> iterator {
824   CHECK(position != body_.end());
825   return body_.erase(position);
826 }
827 
828 template <class Key, class GetKeyFromValue, class KeyCompare, class Container>
829 template <typename DummyT>
830 auto flat_tree<Key, GetKeyFromValue, KeyCompare, Container>::erase(
831     const_iterator position) -> iterator {
832   CHECK(position != body_.end());
833   return body_.erase(position);
834 }
835 
836 template <class Key, class GetKeyFromValue, class KeyCompare, class Container>
837 auto flat_tree<Key, GetKeyFromValue, KeyCompare, Container>::erase(
838     const Key& val) -> size_type {
839   auto eq_range = equal_range(val);
840   auto res =
841       static_cast<size_type>(std::distance(eq_range.first, eq_range.second));
842   erase(eq_range.first, eq_range.second);
843   return res;
844 }
845 
846 template <class Key, class GetKeyFromValue, class KeyCompare, class Container>
847 template <typename K>
848 auto flat_tree<Key, GetKeyFromValue, KeyCompare, Container>::erase(const K& val)
849     -> size_type {
850   auto eq_range = equal_range(val);
851   auto res =
852       static_cast<size_type>(std::distance(eq_range.first, eq_range.second));
853   erase(eq_range.first, eq_range.second);
854   return res;
855 }
856 
857 template <class Key, class GetKeyFromValue, class KeyCompare, class Container>
858 auto flat_tree<Key, GetKeyFromValue, KeyCompare, Container>::erase(
859     const_iterator first,
860     const_iterator last) -> iterator {
861   return body_.erase(first, last);
862 }
863 
864 // ----------------------------------------------------------------------------
865 // Comparators.
866 
867 template <class Key, class GetKeyFromValue, class KeyCompare, class Container>
868 constexpr auto
869 flat_tree<Key, GetKeyFromValue, KeyCompare, Container>::key_comp() const
870     -> key_compare {
871   return comp_;
872 }
873 
874 template <class Key, class GetKeyFromValue, class KeyCompare, class Container>
875 constexpr auto
876 flat_tree<Key, GetKeyFromValue, KeyCompare, Container>::value_comp() const
877     -> value_compare {
878   return value_compare{comp_};
879 }
880 
881 // ----------------------------------------------------------------------------
882 // Search operations.
883 
884 template <class Key, class GetKeyFromValue, class KeyCompare, class Container>
885 template <typename K>
886 auto flat_tree<Key, GetKeyFromValue, KeyCompare, Container>::count(
887     const K& key) const -> size_type {
888   auto eq_range = equal_range(key);
889   return static_cast<size_type>(std::distance(eq_range.first, eq_range.second));
890 }
891 
892 template <class Key, class GetKeyFromValue, class KeyCompare, class Container>
893 auto flat_tree<Key, GetKeyFromValue, KeyCompare, Container>::count(
894     const Key& key) const -> size_type {
895   auto eq_range = equal_range(key);
896   return static_cast<size_type>(std::distance(eq_range.first, eq_range.second));
897 }
898 
899 template <class Key, class GetKeyFromValue, class KeyCompare, class Container>
900 auto flat_tree<Key, GetKeyFromValue, KeyCompare, Container>::find(
901     const Key& key) -> iterator {
902   return const_cast_it(std::as_const(*this).find(key));
903 }
904 
905 template <class Key, class GetKeyFromValue, class KeyCompare, class Container>
906 auto flat_tree<Key, GetKeyFromValue, KeyCompare, Container>::find(
907     const Key& key) const -> const_iterator {
908   auto eq_range = equal_range(key);
909   return (eq_range.first == eq_range.second) ? end() : eq_range.first;
910 }
911 
912 template <class Key, class GetKeyFromValue, class KeyCompare, class Container>
913 template <typename K>
914 auto flat_tree<Key, GetKeyFromValue, KeyCompare, Container>::find(const K& key)
915     -> iterator {
916   return const_cast_it(std::as_const(*this).find(key));
917 }
918 
919 template <class Key, class GetKeyFromValue, class KeyCompare, class Container>
920 template <typename K>
921 auto flat_tree<Key, GetKeyFromValue, KeyCompare, Container>::find(
922     const K& key) const -> const_iterator {
923   auto eq_range = equal_range(key);
924   return (eq_range.first == eq_range.second) ? end() : eq_range.first;
925 }
926 
927 template <class Key, class GetKeyFromValue, class KeyCompare, class Container>
contains(const Key & key)928 bool flat_tree<Key, GetKeyFromValue, KeyCompare, Container>::contains(
929     const Key& key) const {
930   auto lower = lower_bound(key);
931   return lower != end() && !comp_(key, GetKeyFromValue()(*lower));
932 }
933 
934 template <class Key, class GetKeyFromValue, class KeyCompare, class Container>
935 template <typename K>
contains(const K & key)936 bool flat_tree<Key, GetKeyFromValue, KeyCompare, Container>::contains(
937     const K& key) const {
938   auto lower = lower_bound(key);
939   return lower != end() && !comp_(key, GetKeyFromValue()(*lower));
940 }
941 
942 template <class Key, class GetKeyFromValue, class KeyCompare, class Container>
943 auto flat_tree<Key, GetKeyFromValue, KeyCompare, Container>::equal_range(
944     const Key& key) -> std::pair<iterator, iterator> {
945   auto res = std::as_const(*this).equal_range(key);
946   return {const_cast_it(res.first), const_cast_it(res.second)};
947 }
948 
949 template <class Key, class GetKeyFromValue, class KeyCompare, class Container>
950 auto flat_tree<Key, GetKeyFromValue, KeyCompare, Container>::equal_range(
951     const Key& key) const -> std::pair<const_iterator, const_iterator> {
952   auto lower = lower_bound(key);
953 
954   KeyValueCompare comp(comp_);
955   if (lower == end() || comp(key, *lower))
956     return {lower, lower};
957 
958   return {lower, std::next(lower)};
959 }
960 
961 template <class Key, class GetKeyFromValue, class KeyCompare, class Container>
962 template <typename K>
963 auto flat_tree<Key, GetKeyFromValue, KeyCompare, Container>::equal_range(
964     const K& key) -> std::pair<iterator, iterator> {
965   auto res = std::as_const(*this).equal_range(key);
966   return {const_cast_it(res.first), const_cast_it(res.second)};
967 }
968 
969 template <class Key, class GetKeyFromValue, class KeyCompare, class Container>
970 template <typename K>
971 auto flat_tree<Key, GetKeyFromValue, KeyCompare, Container>::equal_range(
972     const K& key) const -> std::pair<const_iterator, const_iterator> {
973   auto lower = lower_bound(key);
974 
975   KeyValueCompare comp(comp_);
976   if (lower == end() || comp(key, *lower))
977     return {lower, lower};
978 
979   return {lower, std::next(lower)};
980 }
981 
982 template <class Key, class GetKeyFromValue, class KeyCompare, class Container>
983 auto flat_tree<Key, GetKeyFromValue, KeyCompare, Container>::lower_bound(
984     const Key& key) -> iterator {
985   return const_cast_it(std::as_const(*this).lower_bound(key));
986 }
987 
988 template <class Key, class GetKeyFromValue, class KeyCompare, class Container>
989 auto flat_tree<Key, GetKeyFromValue, KeyCompare, Container>::lower_bound(
990     const Key& key) const -> const_iterator {
991   KeyValueCompare comp(comp_);
992   return ranges::lower_bound(*this, key, comp);
993 }
994 
995 template <class Key, class GetKeyFromValue, class KeyCompare, class Container>
996 template <typename K>
997 auto flat_tree<Key, GetKeyFromValue, KeyCompare, Container>::lower_bound(
998     const K& key) -> iterator {
999   return const_cast_it(std::as_const(*this).lower_bound(key));
1000 }
1001 
1002 template <class Key, class GetKeyFromValue, class KeyCompare, class Container>
1003 template <typename K>
1004 auto flat_tree<Key, GetKeyFromValue, KeyCompare, Container>::lower_bound(
1005     const K& key) const -> const_iterator {
1006   static_assert(std::is_convertible_v<const KeyTypeOrK<K>&, const K&>,
1007                 "Requested type cannot be bound to the container's key_type "
1008                 "which is required for a non-transparent compare.");
1009 
1010   const KeyTypeOrK<K>& key_ref = key;
1011 
1012   KeyValueCompare comp(comp_);
1013   return ranges::lower_bound(*this, key_ref, comp);
1014 }
1015 
1016 template <class Key, class GetKeyFromValue, class KeyCompare, class Container>
1017 auto flat_tree<Key, GetKeyFromValue, KeyCompare, Container>::upper_bound(
1018     const Key& key) -> iterator {
1019   return const_cast_it(std::as_const(*this).upper_bound(key));
1020 }
1021 
1022 template <class Key, class GetKeyFromValue, class KeyCompare, class Container>
1023 auto flat_tree<Key, GetKeyFromValue, KeyCompare, Container>::upper_bound(
1024     const Key& key) const -> const_iterator {
1025   KeyValueCompare comp(comp_);
1026   return ranges::upper_bound(*this, key, comp);
1027 }
1028 
1029 template <class Key, class GetKeyFromValue, class KeyCompare, class Container>
1030 template <typename K>
1031 auto flat_tree<Key, GetKeyFromValue, KeyCompare, Container>::upper_bound(
1032     const K& key) -> iterator {
1033   return const_cast_it(std::as_const(*this).upper_bound(key));
1034 }
1035 
1036 template <class Key, class GetKeyFromValue, class KeyCompare, class Container>
1037 template <typename K>
1038 auto flat_tree<Key, GetKeyFromValue, KeyCompare, Container>::upper_bound(
1039     const K& key) const -> const_iterator {
1040   static_assert(std::is_convertible_v<const KeyTypeOrK<K>&, const K&>,
1041                 "Requested type cannot be bound to the container's key_type "
1042                 "which is required for a non-transparent compare.");
1043 
1044   const KeyTypeOrK<K>& key_ref = key;
1045 
1046   KeyValueCompare comp(comp_);
1047   return ranges::upper_bound(*this, key_ref, comp);
1048 }
1049 
1050 // ----------------------------------------------------------------------------
1051 // General operations.
1052 
1053 template <class Key, class GetKeyFromValue, class KeyCompare, class Container>
swap(flat_tree & other)1054 void flat_tree<Key, GetKeyFromValue, KeyCompare, Container>::swap(
1055     flat_tree& other) noexcept {
1056   std::swap(*this, other);
1057 }
1058 
1059 template <class Key, class GetKeyFromValue, class KeyCompare, class Container>
1060 template <class... Args>
1061 auto flat_tree<Key, GetKeyFromValue, KeyCompare, Container>::unsafe_emplace(
1062     const_iterator position,
1063     Args&&... args) -> iterator {
1064   return body_.emplace(position, std::forward<Args>(args)...);
1065 }
1066 
1067 template <class Key, class GetKeyFromValue, class KeyCompare, class Container>
1068 template <class K, class... Args>
1069 auto flat_tree<Key, GetKeyFromValue, KeyCompare, Container>::emplace_key_args(
1070     const K& key,
1071     Args&&... args) -> std::pair<iterator, bool> {
1072   auto lower = lower_bound(key);
1073   if (lower == end() || comp_(key, GetKeyFromValue()(*lower)))
1074     return {unsafe_emplace(lower, std::forward<Args>(args)...), true};
1075   return {lower, false};
1076 }
1077 
1078 template <class Key, class GetKeyFromValue, class KeyCompare, class Container>
1079 template <class K, class... Args>
1080 auto flat_tree<Key, GetKeyFromValue, KeyCompare, Container>::
1081     emplace_hint_key_args(const_iterator hint, const K& key, Args&&... args)
1082         -> std::pair<iterator, bool> {
1083   KeyValueCompare comp(comp_);
1084   if ((hint == begin() || comp(*std::prev(hint), key))) {
1085     if (hint == end() || comp(key, *hint)) {
1086       // *(hint - 1) < key < *hint => key did not exist and hint is correct.
1087       return {unsafe_emplace(hint, std::forward<Args>(args)...), true};
1088     }
1089     if (!comp(*hint, key)) {
1090       // key == *hint => no-op, return correct hint.
1091       return {const_cast_it(hint), false};
1092     }
1093   }
1094   // hint was not helpful, dispatch to hintless version.
1095   return emplace_key_args(key, std::forward<Args>(args)...);
1096 }
1097 
1098 }  // namespace internal
1099 
1100 // ----------------------------------------------------------------------------
1101 // Free functions.
1102 
1103 // Erases all elements that match predicate. It has O(size) complexity.
1104 template <class Key,
1105           class GetKeyFromValue,
1106           class KeyCompare,
1107           class Container,
1108           typename Predicate>
EraseIf(base::internal::flat_tree<Key,GetKeyFromValue,KeyCompare,Container> & container,Predicate pred)1109 size_t EraseIf(
1110     base::internal::flat_tree<Key, GetKeyFromValue, KeyCompare, Container>&
1111         container,
1112     Predicate pred) {
1113   auto it = ranges::remove_if(container, pred);
1114   size_t removed = std::distance(it, container.end());
1115   container.erase(it, container.end());
1116   return removed;
1117 }
1118 
1119 }  // namespace base
1120 
1121 #endif  // BASE_CONTAINERS_FLAT_TREE_H_
1122