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