Chromium Code Reviews| Index: base/containers/flat_tree.h |
| diff --git a/base/containers/flat_tree.h b/base/containers/flat_tree.h |
| index 57335d8882b0268fb6d607595b4bec9579f27c55..4b748816a75fd026e6ba619e425fc11895b059dc 100644 |
| --- a/base/containers/flat_tree.h |
| +++ b/base/containers/flat_tree.h |
| @@ -9,6 +9,38 @@ |
| #include <vector> |
| namespace base { |
| + |
| +enum FlatContainerDupes { |
| + KEEP_FIRST_OF_DUPES, |
| + KEEP_LAST_OF_DUPES, |
| +}; |
|
dyaroshev
2017/03/31 07:46:52
I would prefer delegates that do the algorithm.
dyaroshev
2017/03/31 13:58:46
Possible implementation:
https://godbolt.org/g/Rd
|
| + |
| +// This algorithm is like unique() from the standard library except it |
| +// selects only the last of consecutive values instead of the first. |
| +template <class Iterator, class BinaryPredicate> |
| +typename Iterator LastUnique(Iterator first, |
| + Iterator last, |
| + BinaryPredicate compare) { |
| + if (first == last) |
| + return last; |
| + |
| + InputIterator dest = first; |
| + Iterator cur = first; |
| + Iterator prev = cur; |
| + while (++cur != last) { |
| + if (!compare(*prev, *cur) && dest != prev) { |
| + // Non-identical one. |
| + *dest = std::move(*prev); |
| + ++dest; |
| + } |
| + prev = cur; |
| + } |
| + |
| + if (dest != prev) |
| + *dest = std::move(*prev); |
| + return ++dest; |
| +} |
|
dyaroshev
2017/03/31 13:58:46
A - this should be defined as std::unique - it use
|
| + |
| namespace internal { |
| // Implementation of a sorted vector for backing flat_set and flat_map. Do not |
| @@ -24,7 +56,6 @@ namespace internal { |
| // const Key& operator()(const Value&). |
| template <class Key, class Value, class GetKeyFromValue, class KeyCompare> |
| class flat_tree { |
| - public: |
| private: |
| using underlying_type = std::vector<Value>; |
| @@ -71,21 +102,29 @@ class flat_tree { |
| // length). |
| // |
| // Assume that move constructors invalidate iterators and references. |
| + // |
| + // The constructors that take ranges, lists, and vectors do not require that |
| + // the input be sorted. If there are duplcates, the first one in the input |
| + // will be selected. |
| flat_tree(); |
| explicit flat_tree(const key_compare& comp); |
| - // Not stable in the presence of duplicates in the initializer list. |
| template <class InputIterator> |
| flat_tree(InputIterator first, |
| InputIterator last, |
| + FlatContainerDupes dupe_handling = KEEP_FIRST_OF_DUPES, |
| const key_compare& comp = key_compare()); |
|
dyaroshev
2017/03/31 07:46:52
I think this parametr should go first. And should
|
| flat_tree(const flat_tree&); |
| flat_tree(flat_tree&&); |
| - // Not stable in the presence of duplicates in the initializer list. |
| + flat_tree(std::vector<value_type>&& items, |
| + FlatContainerDupes dupe_handling = KEEP_FIRST_OF_DUPES, |
| + const key_compare& comp = key_compare()); |
| + |
| flat_tree(std::initializer_list<value_type> ilist, |
| + FlatContainerDupes dupe_handling = KEEP_FIRST_OF_DUPES, |
| const key_compare& comp = key_compare()); |
| ~flat_tree(); |
| @@ -97,7 +136,7 @@ class flat_tree { |
| flat_tree& operator=(const flat_tree&); |
| flat_tree& operator=(flat_tree&&); |
| - // Not stable in the presence of duplicates in the initializer list. |
| + // Takes the first if there are duplicates in the initializer list. |
| flat_tree& operator=(std::initializer_list<value_type> ilist); |
| // -------------------------------------------------------------------------- |
| @@ -276,17 +315,29 @@ class flat_tree { |
| return std::next(begin(), distance); |
| } |
| - void sort_and_unique() { |
| - // std::set sorts elements preserving stability because it doesn't have any |
| - // performance wins in not doing that. We do, so we use an unstable sort. |
| - std::sort(begin(), end(), impl_.get_value_comp()); |
| - erase(std::unique(begin(), end(), |
| - [this](const value_type& lhs, const value_type& rhs) { |
| - // lhs is already <= rhs due to sort, therefore |
| - // !(lhs < rhs) <=> lhs == rhs. |
| - return !impl_.get_value_comp()(lhs, rhs); |
| - }), |
| - end()); |
| + void sort_and_unique(FlatContainerDupes dupes) { |
| + // We need to preserve stability here and take only the first element. |
| + std::stable_sort(begin(), end(), impl_.get_value_comp()); |
| + iterator erase_after; |
| + switch (dupes) { |
| + case KEEP_FIRST_OF_DUPES: |
| + erase_after = |
| + std::unique(begin(), end(), |
| + [this](const value_type& lhs, const value_type& rhs) { |
| + // lhs is already <= rhs due to sort, therefore |
| + // !(lhs < rhs) <=> lhs == rhs. |
| + return !impl_.get_value_comp()(lhs, rhs); |
| + }) break; |
| + case KEEP_LAST_OF_DUPES: |
| + erase_after = |
| + LastUnique(begin(), end(), |
| + [this](const value_type& lhs, const value_type& rhs) { |
| + // lhs is already <= rhs due to sort, therefore |
| + // !(lhs < rhs) <=> lhs == rhs. |
| + return !impl_.get_value_comp()(lhs, rhs); |
| + }) break; |
| + } |
|
dyaroshev
2017/03/31 07:46:52
Just do the unique algorithm first.
And, I still
|
| + erase(erase_after, end()); |
| } |
| // To support comparators that may not be possible to default-construct, we |
| @@ -325,9 +376,10 @@ template <class InputIterator> |
| flat_tree<Key, Value, GetKeyFromValue, KeyCompare>::flat_tree( |
| InputIterator first, |
| InputIterator last, |
| + FlatContainerDupes dupe_handling, |
| const KeyCompare& comp) |
| : impl_(comp, first, last) { |
| - sort_and_unique(); |
| + sort_and_unique(dupe_handling); |
| } |
| template <class Key, class Value, class GetKeyFromValue, class KeyCompare> |
| @@ -340,9 +392,19 @@ flat_tree<Key, Value, GetKeyFromValue, KeyCompare>::flat_tree(flat_tree&&) = |
| template <class Key, class Value, class GetKeyFromValue, class KeyCompare> |
| flat_tree<Key, Value, GetKeyFromValue, KeyCompare>::flat_tree( |
| + std::vector<value_type>&& items, |
| + FlatContainerDupes dupe_handling, |
| + const KeyCompare& comp) |
| + : impl_(comp, std::move(items)) { |
| + sort_and_unique(dupe_handling); |
| +} |
| + |
| +template <class Key, class Value, class GetKeyFromValue, class KeyCompare> |
| +flat_tree<Key, Value, GetKeyFromValue, KeyCompare>::flat_tree( |
| std::initializer_list<value_type> ilist, |
| + FlatContainerDupes dupe_handling, |
| const KeyCompare& comp) |
| - : flat_tree(std::begin(ilist), std::end(ilist), comp) {} |
| + : flat_tree(std::begin(ilist), std::end(ilist), dupe_handling, comp) {} |
| template <class Key, class Value, class GetKeyFromValue, class KeyCompare> |
| flat_tree<Key, Value, GetKeyFromValue, KeyCompare>::~flat_tree() = default; |