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