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

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

Issue 2776793002: Make flat containers stable, allow constructing from vector. (Closed)
Patch Set: Put back media log change lost in 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 unified diff | Download patch
« no previous file with comments | « base/containers/flat_set_unittest.cc ('k') | base/containers/flat_tree_unittest.cc » ('j') | no next file with comments »
Toggle Intra-line Diffs ('i') | Expand Comments ('e') | Collapse Comments ('c') | Show Comments Hide Comments ('s')
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 };
17
12 namespace internal { 18 namespace internal {
13 19
20 // This algorithm is like unique() from the standard library except it
21 // selects only the last of consecutive values instead of the first.
22 template <class Iterator, class BinaryPredicate>
23 Iterator LastUnique(Iterator first, Iterator last, BinaryPredicate compare) {
24 if (first == last)
25 return last;
26
27 Iterator dest = first;
28 Iterator cur = first;
29 Iterator prev = cur;
30 while (++cur != last) {
31 if (!compare(*prev, *cur)) {
32 // Non-identical one.
33 if (dest != prev)
34 *dest = std::move(*prev);
35 ++dest;
36 }
37 prev = cur;
38 }
39
40 if (dest != prev)
41 *dest = std::move(*prev);
42 return ++dest;
43 }
44
14 // Implementation of a sorted vector for backing flat_set and flat_map. Do not 45 // Implementation of a sorted vector for backing flat_set and flat_map. Do not
15 // use directly. 46 // use directly.
16 // 47 //
17 // The use of "value" in this is like std::map uses, meaning it's the thing 48 // 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 49 // 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 50 // 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. 51 // a map, the Key is a component of a Value.
21 // 52 //
22 // The helper class GetKeyFromValue provides the means to extract a key from a 53 // The helper class GetKeyFromValue provides the means to extract a key from a
23 // value for comparison purposes. It should implement: 54 // value for comparison purposes. It should implement:
24 // const Key& operator()(const Value&). 55 // const Key& operator()(const Value&).
25 template <class Key, class Value, class GetKeyFromValue, class KeyCompare> 56 template <class Key, class Value, class GetKeyFromValue, class KeyCompare>
26 class flat_tree { 57 class flat_tree {
27 public:
28 private: 58 private:
29 using underlying_type = std::vector<Value>; 59 using underlying_type = std::vector<Value>;
30 60
31 public: 61 public:
32 // -------------------------------------------------------------------------- 62 // --------------------------------------------------------------------------
33 // Types. 63 // Types.
34 // 64 //
35 using key_type = Key; 65 using key_type = Key;
36 using key_compare = KeyCompare; 66 using key_compare = KeyCompare;
37 using value_type = Value; 67 using value_type = Value;
(...skipping 26 matching lines...) Expand all
64 typename underlying_type::const_reverse_iterator; 94 typename underlying_type::const_reverse_iterator;
65 95
66 // -------------------------------------------------------------------------- 96 // --------------------------------------------------------------------------
67 // Lifetime. 97 // Lifetime.
68 // 98 //
69 // Constructors that take range guarantee O(N * log^2(N)) + O(N) complexity 99 // 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 100 // and take O(N * log(N)) + O(N) if extra memory is available (N is a range
71 // length). 101 // length).
72 // 102 //
73 // Assume that move constructors invalidate iterators and references. 103 // Assume that move constructors invalidate iterators and references.
104 //
105 // The constructors that take ranges, lists, and vectors do not require that
106 // the input be sorted.
74 107
75 flat_tree(); 108 flat_tree();
76 explicit flat_tree(const key_compare& comp); 109 explicit flat_tree(const key_compare& comp);
77 110
78 // Not stable in the presence of duplicates in the initializer list.
79 template <class InputIterator> 111 template <class InputIterator>
80 flat_tree(InputIterator first, 112 flat_tree(InputIterator first,
81 InputIterator last, 113 InputIterator last,
114 FlatContainerDupes dupe_handling,
82 const key_compare& comp = key_compare()); 115 const key_compare& comp = key_compare());
83 116
84 flat_tree(const flat_tree&); 117 flat_tree(const flat_tree&);
85 flat_tree(flat_tree&&); 118 flat_tree(flat_tree&&);
86 119
87 // Not stable in the presence of duplicates in the initializer list. 120 flat_tree(std::vector<value_type> items,
121 FlatContainerDupes dupe_handling,
122 const key_compare& comp = key_compare());
123
88 flat_tree(std::initializer_list<value_type> ilist, 124 flat_tree(std::initializer_list<value_type> ilist,
125 FlatContainerDupes dupe_handling,
89 const key_compare& comp = key_compare()); 126 const key_compare& comp = key_compare());
90 127
91 ~flat_tree(); 128 ~flat_tree();
92 129
93 // -------------------------------------------------------------------------- 130 // --------------------------------------------------------------------------
94 // Assignments. 131 // Assignments.
95 // 132 //
96 // Assume that move assignment invalidates iterators and references. 133 // Assume that move assignment invalidates iterators and references.
97 134
98 flat_tree& operator=(const flat_tree&); 135 flat_tree& operator=(const flat_tree&);
99 flat_tree& operator=(flat_tree&&); 136 flat_tree& operator=(flat_tree&&);
100 // Not stable in the presence of duplicates in the initializer list. 137 // Takes the first if there are duplicates in the initializer list.
101 flat_tree& operator=(std::initializer_list<value_type> ilist); 138 flat_tree& operator=(std::initializer_list<value_type> ilist);
102 139
103 // -------------------------------------------------------------------------- 140 // --------------------------------------------------------------------------
104 // Memory management. 141 // Memory management.
105 // 142 //
106 // Beware that shrink_to_fit() simply forwards the request to the 143 // Beware that shrink_to_fit() simply forwards the request to the
107 // underlying_type and its implementation is free to optimize otherwise and 144 // underlying_type and its implementation is free to optimize otherwise and
108 // leave capacity() to be greater that its size. 145 // leave capacity() to be greater that its size.
109 // 146 //
110 // reserve() and shrink_to_fit() invalidate iterators and references. 147 // 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_; 306 const key_compare& key_comp_;
270 }; 307 };
271 308
272 const flat_tree& as_const() { return *this; } 309 const flat_tree& as_const() { return *this; }
273 310
274 iterator const_cast_it(const_iterator c_it) { 311 iterator const_cast_it(const_iterator c_it) {
275 auto distance = std::distance(cbegin(), c_it); 312 auto distance = std::distance(cbegin(), c_it);
276 return std::next(begin(), distance); 313 return std::next(begin(), distance);
277 } 314 }
278 315
279 void sort_and_unique() { 316 void sort_and_unique(FlatContainerDupes dupes) {
280 // std::set sorts elements preserving stability because it doesn't have any 317 // Preserve stability for the unique code below.
281 // performance wins in not doing that. We do, so we use an unstable sort. 318 std::stable_sort(begin(), end(), impl_.get_value_comp());
282 std::sort(begin(), end(), impl_.get_value_comp()); 319
283 erase(std::unique(begin(), end(), 320 auto comparator = [this](const value_type& lhs, const value_type& rhs) {
284 [this](const value_type& lhs, const value_type& rhs) { 321 // lhs is already <= rhs due to sort, therefore
285 // lhs is already <= rhs due to sort, therefore 322 // !(lhs < rhs) <=> lhs == rhs.
286 // !(lhs < rhs) <=> lhs == rhs. 323 return !impl_.get_value_comp()(lhs, rhs);
287 return !impl_.get_value_comp()(lhs, rhs); 324 };
288 }), 325
289 end()); 326 iterator erase_after;
327 switch (dupes) {
328 case KEEP_FIRST_OF_DUPES:
329 erase_after = std::unique(begin(), end(), comparator);
330 break;
331 case KEEP_LAST_OF_DUPES:
332 erase_after = LastUnique(begin(), end(), comparator);
333 break;
334 }
335 erase(erase_after, end());
290 } 336 }
291 337
292 // To support comparators that may not be possible to default-construct, we 338 // 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 339 // 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 340 // 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 341 // take advantage of an empty base class optimization to avoid extra space in
296 // the common case when Compare has no state. 342 // the common case when Compare has no state.
297 struct Impl : private value_compare { 343 struct Impl : private value_compare {
298 Impl() = default; 344 Impl() = default;
299 345
(...skipping 18 matching lines...) Expand all
318 template <class Key, class Value, class GetKeyFromValue, class KeyCompare> 364 template <class Key, class Value, class GetKeyFromValue, class KeyCompare>
319 flat_tree<Key, Value, GetKeyFromValue, KeyCompare>::flat_tree( 365 flat_tree<Key, Value, GetKeyFromValue, KeyCompare>::flat_tree(
320 const KeyCompare& comp) 366 const KeyCompare& comp)
321 : impl_(comp) {} 367 : impl_(comp) {}
322 368
323 template <class Key, class Value, class GetKeyFromValue, class KeyCompare> 369 template <class Key, class Value, class GetKeyFromValue, class KeyCompare>
324 template <class InputIterator> 370 template <class InputIterator>
325 flat_tree<Key, Value, GetKeyFromValue, KeyCompare>::flat_tree( 371 flat_tree<Key, Value, GetKeyFromValue, KeyCompare>::flat_tree(
326 InputIterator first, 372 InputIterator first,
327 InputIterator last, 373 InputIterator last,
374 FlatContainerDupes dupe_handling,
328 const KeyCompare& comp) 375 const KeyCompare& comp)
329 : impl_(comp, first, last) { 376 : impl_(comp, first, last) {
330 sort_and_unique(); 377 sort_and_unique(dupe_handling);
331 } 378 }
332 379
333 template <class Key, class Value, class GetKeyFromValue, class KeyCompare> 380 template <class Key, class Value, class GetKeyFromValue, class KeyCompare>
334 flat_tree<Key, Value, GetKeyFromValue, KeyCompare>::flat_tree( 381 flat_tree<Key, Value, GetKeyFromValue, KeyCompare>::flat_tree(
335 const flat_tree&) = default; 382 const flat_tree&) = default;
336 383
337 template <class Key, class Value, class GetKeyFromValue, class KeyCompare> 384 template <class Key, class Value, class GetKeyFromValue, class KeyCompare>
338 flat_tree<Key, Value, GetKeyFromValue, KeyCompare>::flat_tree(flat_tree&&) = 385 flat_tree<Key, Value, GetKeyFromValue, KeyCompare>::flat_tree(flat_tree&&) =
339 default; 386 default;
340 387
341 template <class Key, class Value, class GetKeyFromValue, class KeyCompare> 388 template <class Key, class Value, class GetKeyFromValue, class KeyCompare>
342 flat_tree<Key, Value, GetKeyFromValue, KeyCompare>::flat_tree( 389 flat_tree<Key, Value, GetKeyFromValue, KeyCompare>::flat_tree(
390 std::vector<value_type> items,
391 FlatContainerDupes dupe_handling,
392 const KeyCompare& comp)
393 : impl_(comp, std::move(items)) {
394 sort_and_unique(dupe_handling);
395 }
396
397 template <class Key, class Value, class GetKeyFromValue, class KeyCompare>
398 flat_tree<Key, Value, GetKeyFromValue, KeyCompare>::flat_tree(
343 std::initializer_list<value_type> ilist, 399 std::initializer_list<value_type> ilist,
400 FlatContainerDupes dupe_handling,
344 const KeyCompare& comp) 401 const KeyCompare& comp)
345 : flat_tree(std::begin(ilist), std::end(ilist), comp) {} 402 : flat_tree(std::begin(ilist), std::end(ilist), dupe_handling, comp) {}
346 403
347 template <class Key, class Value, class GetKeyFromValue, class KeyCompare> 404 template <class Key, class Value, class GetKeyFromValue, class KeyCompare>
348 flat_tree<Key, Value, GetKeyFromValue, KeyCompare>::~flat_tree() = default; 405 flat_tree<Key, Value, GetKeyFromValue, KeyCompare>::~flat_tree() = default;
349 406
350 // ---------------------------------------------------------------------------- 407 // ----------------------------------------------------------------------------
351 // Assignments. 408 // Assignments.
352 409
353 template <class Key, class Value, class GetKeyFromValue, class KeyCompare> 410 template <class Key, class Value, class GetKeyFromValue, class KeyCompare>
354 auto flat_tree<Key, Value, GetKeyFromValue, KeyCompare>::operator=( 411 auto flat_tree<Key, Value, GetKeyFromValue, KeyCompare>::operator=(
355 const flat_tree&) -> flat_tree& = default; 412 const flat_tree&) -> flat_tree& = default;
356 413
357 template <class Key, class Value, class GetKeyFromValue, class KeyCompare> 414 template <class Key, class Value, class GetKeyFromValue, class KeyCompare>
358 auto flat_tree<Key, Value, GetKeyFromValue, KeyCompare>::operator=(flat_tree &&) 415 auto flat_tree<Key, Value, GetKeyFromValue, KeyCompare>::operator=(flat_tree &&)
359 -> flat_tree& = default; 416 -> flat_tree& = default;
360 417
361 template <class Key, class Value, class GetKeyFromValue, class KeyCompare> 418 template <class Key, class Value, class GetKeyFromValue, class KeyCompare>
362 auto flat_tree<Key, Value, GetKeyFromValue, KeyCompare>::operator=( 419 auto flat_tree<Key, Value, GetKeyFromValue, KeyCompare>::operator=(
363 std::initializer_list<value_type> ilist) -> flat_tree& { 420 std::initializer_list<value_type> ilist) -> flat_tree& {
364 impl_.body_ = ilist; 421 impl_.body_ = ilist;
365 sort_and_unique(); 422 sort_and_unique(KEEP_FIRST_OF_DUPES);
366 return *this; 423 return *this;
367 } 424 }
368 425
369 // ---------------------------------------------------------------------------- 426 // ----------------------------------------------------------------------------
370 // Memory management. 427 // Memory management.
371 428
372 template <class Key, class Value, class GetKeyFromValue, class KeyCompare> 429 template <class Key, class Value, class GetKeyFromValue, class KeyCompare>
373 void flat_tree<Key, Value, GetKeyFromValue, KeyCompare>::reserve( 430 void flat_tree<Key, Value, GetKeyFromValue, KeyCompare>::reserve(
374 size_type new_capacity) { 431 size_type new_capacity) {
375 impl_.body_.reserve(new_capacity); 432 impl_.body_.reserve(new_capacity);
(...skipping 332 matching lines...) Expand 10 before | Expand all | Expand 10 after
708 void EraseIf(base::internal::flat_tree<Key, Value, GetKeyFromValue, KeyCompare>& 765 void EraseIf(base::internal::flat_tree<Key, Value, GetKeyFromValue, KeyCompare>&
709 container, 766 container,
710 Predicate pred) { 767 Predicate pred) {
711 container.erase(std::remove_if(container.begin(), container.end(), pred), 768 container.erase(std::remove_if(container.begin(), container.end(), pred),
712 container.end()); 769 container.end());
713 } 770 }
714 771
715 } // namespace base 772 } // namespace base
716 773
717 #endif // BASE_CONTAINERS_FLAT_TREE_H_ 774 #endif // BASE_CONTAINERS_FLAT_TREE_H_
OLDNEW
« no previous file with comments | « base/containers/flat_set_unittest.cc ('k') | base/containers/flat_tree_unittest.cc » ('j') | no next file with comments »

Powered by Google App Engine
This is Rietveld 408576698