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