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

Side by Side Diff: base/containers/flat_tree.h

Issue 2776793002: Make flat containers stable, allow constructing from vector. (Closed)
Patch Set: Checkpoint 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 unified diff | Download patch
OLDNEW
1 // Copyright 2017 The Chromium Authors. All rights reserved. 1 // Copyright 2017 The Chromium Authors. All rights reserved.
2 // Use of this source code is governed by a BSD-style license that can be 2 // Use of this source code is governed by a BSD-style license that can be
3 // found in the LICENSE file. 3 // found in the LICENSE file.
4 4
5 #ifndef BASE_CONTAINERS_FLAT_TREE_H_ 5 #ifndef BASE_CONTAINERS_FLAT_TREE_H_
6 #define BASE_CONTAINERS_FLAT_TREE_H_ 6 #define BASE_CONTAINERS_FLAT_TREE_H_
7 7
8 #include <algorithm> 8 #include <algorithm>
9 #include <vector> 9 #include <vector>
10 10
11 namespace base { 11 namespace base {
12
13 enum FlatContainerDupes {
14 KEEP_FIRST_OF_DUPES,
15 KEEP_LAST_OF_DUPES,
16 };
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
17
18 // This algorithm is like unique() from the standard library except it
19 // selects only the last of consecutive values instead of the first.
20 template <class Iterator, class BinaryPredicate>
21 typename Iterator LastUnique(Iterator first,
22 Iterator last,
23 BinaryPredicate compare) {
24 if (first == last)
25 return last;
26
27 InputIterator dest = first;
28 Iterator cur = first;
29 Iterator prev = cur;
30 while (++cur != last) {
31 if (!compare(*prev, *cur) && dest != prev) {
32 // Non-identical one.
33 *dest = std::move(*prev);
34 ++dest;
35 }
36 prev = cur;
37 }
38
39 if (dest != prev)
40 *dest = std::move(*prev);
41 return ++dest;
42 }
dyaroshev 2017/03/31 13:58:46 A - this should be defined as std::unique - it use
43
12 namespace internal { 44 namespace internal {
13 45
14 // Implementation of a sorted vector for backing flat_set and flat_map. Do not 46 // Implementation of a sorted vector for backing flat_set and flat_map. Do not
15 // use directly. 47 // use directly.
16 // 48 //
17 // The use of "value" in this is like std::map uses, meaning it's the thing 49 // The use of "value" in this is like std::map uses, meaning it's the thing
18 // contained (in the case of map it's a <Kay, Mapped> pair). The Key is how 50 // contained (in the case of map it's a <Kay, Mapped> pair). The Key is how
19 // things are looked up. In the case of a set, Key == Value. In the case of 51 // things are looked up. In the case of a set, Key == Value. In the case of
20 // a map, the Key is a component of a Value. 52 // a map, the Key is a component of a Value.
21 // 53 //
22 // The helper class GetKeyFromValue provides the means to extract a key from a 54 // The helper class GetKeyFromValue provides the means to extract a key from a
23 // value for comparison purposes. It should implement: 55 // value for comparison purposes. It should implement:
24 // const Key& operator()(const Value&). 56 // const Key& operator()(const Value&).
25 template <class Key, class Value, class GetKeyFromValue, class KeyCompare> 57 template <class Key, class Value, class GetKeyFromValue, class KeyCompare>
26 class flat_tree { 58 class flat_tree {
27 public:
28 private: 59 private:
29 using underlying_type = std::vector<Value>; 60 using underlying_type = std::vector<Value>;
30 61
31 public: 62 public:
32 // -------------------------------------------------------------------------- 63 // --------------------------------------------------------------------------
33 // Types. 64 // Types.
34 // 65 //
35 using key_type = Key; 66 using key_type = Key;
36 using key_compare = KeyCompare; 67 using key_compare = KeyCompare;
37 using value_type = Value; 68 using value_type = Value;
(...skipping 26 matching lines...) Expand all
64 typename underlying_type::const_reverse_iterator; 95 typename underlying_type::const_reverse_iterator;
65 96
66 // -------------------------------------------------------------------------- 97 // --------------------------------------------------------------------------
67 // Lifetime. 98 // Lifetime.
68 // 99 //
69 // Constructors that take range guarantee O(N * log^2(N)) + O(N) complexity 100 // Constructors that take range guarantee O(N * log^2(N)) + O(N) complexity
70 // and take O(N * log(N)) + O(N) if extra memory is available (N is a range 101 // and take O(N * log(N)) + O(N) if extra memory is available (N is a range
71 // length). 102 // length).
72 // 103 //
73 // Assume that move constructors invalidate iterators and references. 104 // Assume that move constructors invalidate iterators and references.
105 //
106 // The constructors that take ranges, lists, and vectors do not require that
107 // the input be sorted. If there are duplcates, the first one in the input
108 // will be selected.
74 109
75 flat_tree(); 110 flat_tree();
76 explicit flat_tree(const key_compare& comp); 111 explicit flat_tree(const key_compare& comp);
77 112
78 // Not stable in the presence of duplicates in the initializer list.
79 template <class InputIterator> 113 template <class InputIterator>
80 flat_tree(InputIterator first, 114 flat_tree(InputIterator first,
81 InputIterator last, 115 InputIterator last,
116 FlatContainerDupes dupe_handling = KEEP_FIRST_OF_DUPES,
82 const key_compare& comp = key_compare()); 117 const key_compare& comp = key_compare());
dyaroshev 2017/03/31 07:46:52 I think this parametr should go first. And should
83 118
84 flat_tree(const flat_tree&); 119 flat_tree(const flat_tree&);
85 flat_tree(flat_tree&&); 120 flat_tree(flat_tree&&);
86 121
87 // Not stable in the presence of duplicates in the initializer list. 122 flat_tree(std::vector<value_type>&& items,
123 FlatContainerDupes dupe_handling = KEEP_FIRST_OF_DUPES,
124 const key_compare& comp = key_compare());
125
88 flat_tree(std::initializer_list<value_type> ilist, 126 flat_tree(std::initializer_list<value_type> ilist,
127 FlatContainerDupes dupe_handling = KEEP_FIRST_OF_DUPES,
89 const key_compare& comp = key_compare()); 128 const key_compare& comp = key_compare());
90 129
91 ~flat_tree(); 130 ~flat_tree();
92 131
93 // -------------------------------------------------------------------------- 132 // --------------------------------------------------------------------------
94 // Assignments. 133 // Assignments.
95 // 134 //
96 // Assume that move assignment invalidates iterators and references. 135 // Assume that move assignment invalidates iterators and references.
97 136
98 flat_tree& operator=(const flat_tree&); 137 flat_tree& operator=(const flat_tree&);
99 flat_tree& operator=(flat_tree&&); 138 flat_tree& operator=(flat_tree&&);
100 // Not stable in the presence of duplicates in the initializer list. 139 // Takes the first if there are duplicates in the initializer list.
101 flat_tree& operator=(std::initializer_list<value_type> ilist); 140 flat_tree& operator=(std::initializer_list<value_type> ilist);
102 141
103 // -------------------------------------------------------------------------- 142 // --------------------------------------------------------------------------
104 // Memory management. 143 // Memory management.
105 // 144 //
106 // Beware that shrink_to_fit() simply forwards the request to the 145 // Beware that shrink_to_fit() simply forwards the request to the
107 // underlying_type and its implementation is free to optimize otherwise and 146 // underlying_type and its implementation is free to optimize otherwise and
108 // leave capacity() to be greater that its size. 147 // leave capacity() to be greater that its size.
109 // 148 //
110 // reserve() and shrink_to_fit() invalidate iterators and references. 149 // reserve() and shrink_to_fit() invalidate iterators and references.
(...skipping 158 matching lines...) Expand 10 before | Expand all | Expand 10 after
269 const key_compare& key_comp_; 308 const key_compare& key_comp_;
270 }; 309 };
271 310
272 const flat_tree& as_const() { return *this; } 311 const flat_tree& as_const() { return *this; }
273 312
274 iterator const_cast_it(const_iterator c_it) { 313 iterator const_cast_it(const_iterator c_it) {
275 auto distance = std::distance(cbegin(), c_it); 314 auto distance = std::distance(cbegin(), c_it);
276 return std::next(begin(), distance); 315 return std::next(begin(), distance);
277 } 316 }
278 317
279 void sort_and_unique() { 318 void sort_and_unique(FlatContainerDupes dupes) {
280 // std::set sorts elements preserving stability because it doesn't have any 319 // We need to preserve stability here and take only the first element.
281 // performance wins in not doing that. We do, so we use an unstable sort. 320 std::stable_sort(begin(), end(), impl_.get_value_comp());
282 std::sort(begin(), end(), impl_.get_value_comp()); 321 iterator erase_after;
283 erase(std::unique(begin(), end(), 322 switch (dupes) {
284 [this](const value_type& lhs, const value_type& rhs) { 323 case KEEP_FIRST_OF_DUPES:
285 // lhs is already <= rhs due to sort, therefore 324 erase_after =
286 // !(lhs < rhs) <=> lhs == rhs. 325 std::unique(begin(), end(),
287 return !impl_.get_value_comp()(lhs, rhs); 326 [this](const value_type& lhs, const value_type& rhs) {
288 }), 327 // lhs is already <= rhs due to sort, therefore
289 end()); 328 // !(lhs < rhs) <=> lhs == rhs.
329 return !impl_.get_value_comp()(lhs, rhs);
330 }) break;
331 case KEEP_LAST_OF_DUPES:
332 erase_after =
333 LastUnique(begin(), end(),
334 [this](const value_type& lhs, const value_type& rhs) {
335 // lhs is already <= rhs due to sort, therefore
336 // !(lhs < rhs) <=> lhs == rhs.
337 return !impl_.get_value_comp()(lhs, rhs);
338 }) break;
339 }
dyaroshev 2017/03/31 07:46:52 Just do the unique algorithm first. And, I still
340 erase(erase_after, end());
290 } 341 }
291 342
292 // To support comparators that may not be possible to default-construct, we 343 // To support comparators that may not be possible to default-construct, we
293 // have to store an instance of Compare. Using this to store all internal 344 // have to store an instance of Compare. Using this to store all internal
294 // state of flat_tree and using private inheritance to store compare lets us 345 // state of flat_tree and using private inheritance to store compare lets us
295 // take advantage of an empty base class optimization to avoid extra space in 346 // take advantage of an empty base class optimization to avoid extra space in
296 // the common case when Compare has no state. 347 // the common case when Compare has no state.
297 struct Impl : private value_compare { 348 struct Impl : private value_compare {
298 Impl() = default; 349 Impl() = default;
299 350
(...skipping 18 matching lines...) Expand all
318 template <class Key, class Value, class GetKeyFromValue, class KeyCompare> 369 template <class Key, class Value, class GetKeyFromValue, class KeyCompare>
319 flat_tree<Key, Value, GetKeyFromValue, KeyCompare>::flat_tree( 370 flat_tree<Key, Value, GetKeyFromValue, KeyCompare>::flat_tree(
320 const KeyCompare& comp) 371 const KeyCompare& comp)
321 : impl_(comp) {} 372 : impl_(comp) {}
322 373
323 template <class Key, class Value, class GetKeyFromValue, class KeyCompare> 374 template <class Key, class Value, class GetKeyFromValue, class KeyCompare>
324 template <class InputIterator> 375 template <class InputIterator>
325 flat_tree<Key, Value, GetKeyFromValue, KeyCompare>::flat_tree( 376 flat_tree<Key, Value, GetKeyFromValue, KeyCompare>::flat_tree(
326 InputIterator first, 377 InputIterator first,
327 InputIterator last, 378 InputIterator last,
379 FlatContainerDupes dupe_handling,
328 const KeyCompare& comp) 380 const KeyCompare& comp)
329 : impl_(comp, first, last) { 381 : impl_(comp, first, last) {
330 sort_and_unique(); 382 sort_and_unique(dupe_handling);
331 } 383 }
332 384
333 template <class Key, class Value, class GetKeyFromValue, class KeyCompare> 385 template <class Key, class Value, class GetKeyFromValue, class KeyCompare>
334 flat_tree<Key, Value, GetKeyFromValue, KeyCompare>::flat_tree( 386 flat_tree<Key, Value, GetKeyFromValue, KeyCompare>::flat_tree(
335 const flat_tree&) = default; 387 const flat_tree&) = default;
336 388
337 template <class Key, class Value, class GetKeyFromValue, class KeyCompare> 389 template <class Key, class Value, class GetKeyFromValue, class KeyCompare>
338 flat_tree<Key, Value, GetKeyFromValue, KeyCompare>::flat_tree(flat_tree&&) = 390 flat_tree<Key, Value, GetKeyFromValue, KeyCompare>::flat_tree(flat_tree&&) =
339 default; 391 default;
340 392
341 template <class Key, class Value, class GetKeyFromValue, class KeyCompare> 393 template <class Key, class Value, class GetKeyFromValue, class KeyCompare>
342 flat_tree<Key, Value, GetKeyFromValue, KeyCompare>::flat_tree( 394 flat_tree<Key, Value, GetKeyFromValue, KeyCompare>::flat_tree(
395 std::vector<value_type>&& items,
396 FlatContainerDupes dupe_handling,
397 const KeyCompare& comp)
398 : impl_(comp, std::move(items)) {
399 sort_and_unique(dupe_handling);
400 }
401
402 template <class Key, class Value, class GetKeyFromValue, class KeyCompare>
403 flat_tree<Key, Value, GetKeyFromValue, KeyCompare>::flat_tree(
343 std::initializer_list<value_type> ilist, 404 std::initializer_list<value_type> ilist,
405 FlatContainerDupes dupe_handling,
344 const KeyCompare& comp) 406 const KeyCompare& comp)
345 : flat_tree(std::begin(ilist), std::end(ilist), comp) {} 407 : flat_tree(std::begin(ilist), std::end(ilist), dupe_handling, comp) {}
346 408
347 template <class Key, class Value, class GetKeyFromValue, class KeyCompare> 409 template <class Key, class Value, class GetKeyFromValue, class KeyCompare>
348 flat_tree<Key, Value, GetKeyFromValue, KeyCompare>::~flat_tree() = default; 410 flat_tree<Key, Value, GetKeyFromValue, KeyCompare>::~flat_tree() = default;
349 411
350 // ---------------------------------------------------------------------------- 412 // ----------------------------------------------------------------------------
351 // Assignments. 413 // Assignments.
352 414
353 template <class Key, class Value, class GetKeyFromValue, class KeyCompare> 415 template <class Key, class Value, class GetKeyFromValue, class KeyCompare>
354 auto flat_tree<Key, Value, GetKeyFromValue, KeyCompare>::operator=( 416 auto flat_tree<Key, Value, GetKeyFromValue, KeyCompare>::operator=(
355 const flat_tree&) -> flat_tree& = default; 417 const flat_tree&) -> flat_tree& = default;
(...skipping 352 matching lines...) Expand 10 before | Expand all | Expand 10 after
708 void EraseIf(base::internal::flat_tree<Key, Value, GetKeyFromValue, KeyCompare>& 770 void EraseIf(base::internal::flat_tree<Key, Value, GetKeyFromValue, KeyCompare>&
709 container, 771 container,
710 Predicate pred) { 772 Predicate pred) {
711 container.erase(std::remove_if(container.begin(), container.end(), pred), 773 container.erase(std::remove_if(container.begin(), container.end(), pred),
712 container.end()); 774 container.end());
713 } 775 }
714 776
715 } // namespace base 777 } // namespace base
716 778
717 #endif // BASE_CONTAINERS_FLAT_TREE_H_ 779 #endif // BASE_CONTAINERS_FLAT_TREE_H_
OLDNEW

Powered by Google App Engine
This is Rietveld 408576698