Chromium Code Reviews
chromiumcodereview-hr@appspot.gserviceaccount.com (chromiumcodereview-hr) | Please choose your nickname with Settings | Help | Chromium Project | Gerrit Changes | Sign out
(759)

Unified Diff: base/containers/flat_tree.h

Issue 2776793002: Make flat containers stable, allow constructing from vector. (Closed)
Patch Set: Merge Created 3 years, 8 months ago
Use n/p to move between diff chunks; N/P to move between comments. Draft comments are only viewable by you.
Jump to:
View side-by-side diff with in-line comments
Download patch
Index: base/containers/flat_tree.h
diff --git a/base/containers/flat_tree.h b/base/containers/flat_tree.h
index 57335d8882b0268fb6d607595b4bec9579f27c55..23642976057a73a8141f726eac649fd43f37c0b9 100644
--- a/base/containers/flat_tree.h
+++ b/base/containers/flat_tree.h
@@ -9,6 +9,37 @@
#include <vector>
namespace base {
+
+enum FlatContainerDupes {
+ KEEP_FIRST_OF_DUPES,
+ KEEP_LAST_OF_DUPES,
+};
+
+// 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>
+Iterator LastUnique(Iterator first, Iterator last, BinaryPredicate compare) {
danakj 2017/04/05 21:33:43 Maybe this belongs in stl_util.h? Or somewhere.. b
brettw 2017/04/07 21:59:04 I started by writing this in a separate file (I th
danakj 2017/04/07 22:02:53 I think it should be in base::internal if you want
brettw 2017/04/07 22:13:37 Oh, I meant to do that actually. Thanks.
+ if (first == last)
danakj 2017/04/05 21:33:43 Curious why you wrote your own LastUnique instead
dyaroshev 2017/04/06 09:45:18 It moves elements in the wrong direction - you'll
+ return last;
+
+ Iterator dest = first;
+ Iterator cur = first;
+ Iterator prev = cur;
+ while (++cur != last) {
+ if (!compare(*prev, *cur)) {
+ // Non-identical one.
+ if (dest != prev)
+ *dest = std::move(*prev);
+ ++dest;
+ }
+ prev = cur;
+ }
+
+ if (dest != prev)
+ *dest = std::move(*prev);
+ return ++dest;
+}
+
namespace internal {
// Implementation of a sorted vector for backing flat_set and flat_map. Do not
@@ -24,7 +55,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 +101,30 @@ 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
danakj 2017/04/05 21:33:43 Same as from map, the first is kept part seems wro
brettw 2017/04/07 21:59:04 Done.
+ // 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,
const key_compare& comp = key_compare());
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,
+ const key_compare& comp = key_compare());
+
+ // Takes the first if there are duplicates in the initializer list.
flat_tree(std::initializer_list<value_type> ilist,
+ FlatContainerDupes dupe_handling,
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,26 @@ 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.
danakj 2017/04/05 21:33:43 "first element" isn't always correct, right?
brettw 2017/04/07 21:59:04 Done.
+ std::stable_sort(begin(), end(), impl_.get_value_comp());
+
+ auto comparator = [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);
+ };
+
+ iterator erase_after;
+ switch (dupes) {
+ case KEEP_FIRST_OF_DUPES:
+ erase_after = std::unique(begin(), end(), comparator);
+ break;
+ case KEEP_LAST_OF_DUPES:
+ erase_after = LastUnique(begin(), end(), comparator);
+ break;
+ }
+ erase(erase_after, end());
}
// To support comparators that may not be possible to default-construct, we
@@ -325,9 +373,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 +389,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;
@@ -362,7 +421,7 @@ template <class Key, class Value, class GetKeyFromValue, class KeyCompare>
auto flat_tree<Key, Value, GetKeyFromValue, KeyCompare>::operator=(
std::initializer_list<value_type> ilist) -> flat_tree& {
impl_.body_ = ilist;
- sort_and_unique();
+ sort_and_unique(KEEP_FIRST_OF_DUPES);
return *this;
}

Powered by Google App Engine
This is Rietveld 408576698