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

Side by Side 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 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 };
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 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.
22 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
23 return last;
24
25 Iterator dest = first;
26 Iterator cur = first;
27 Iterator prev = cur;
28 while (++cur != last) {
29 if (!compare(*prev, *cur)) {
30 // Non-identical one.
31 if (dest != prev)
32 *dest = std::move(*prev);
33 ++dest;
34 }
35 prev = cur;
36 }
37
38 if (dest != prev)
39 *dest = std::move(*prev);
40 return ++dest;
41 }
42
12 namespace internal { 43 namespace internal {
13 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. 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.
107 // will be selected.
74 108
75 flat_tree(); 109 flat_tree();
76 explicit flat_tree(const key_compare& comp); 110 explicit flat_tree(const key_compare& comp);
77 111
78 // Not stable in the presence of duplicates in the initializer list.
79 template <class InputIterator> 112 template <class InputIterator>
80 flat_tree(InputIterator first, 113 flat_tree(InputIterator first,
81 InputIterator last, 114 InputIterator last,
115 FlatContainerDupes dupe_handling,
82 const key_compare& comp = key_compare()); 116 const key_compare& comp = key_compare());
83 117
84 flat_tree(const flat_tree&); 118 flat_tree(const flat_tree&);
85 flat_tree(flat_tree&&); 119 flat_tree(flat_tree&&);
86 120
87 // Not stable in the presence of duplicates in the initializer list. 121 flat_tree(std::vector<value_type> items,
122 FlatContainerDupes dupe_handling,
123 const key_compare& comp = key_compare());
124
125 // Takes the first if there are duplicates in the initializer list.
88 flat_tree(std::initializer_list<value_type> ilist, 126 flat_tree(std::initializer_list<value_type> ilist,
127 FlatContainerDupes dupe_handling,
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.
danakj 2017/04/05 21:33:43 "first element" isn't always correct, right?
brettw 2017/04/07 21:59:04 Done.
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
283 erase(std::unique(begin(), end(), 322 auto comparator = [this](const value_type& lhs, const value_type& rhs) {
284 [this](const value_type& lhs, const value_type& rhs) { 323 // lhs is already <= rhs due to sort, therefore
285 // lhs is already <= rhs due to sort, therefore 324 // !(lhs < rhs) <=> lhs == rhs.
286 // !(lhs < rhs) <=> lhs == rhs. 325 return !impl_.get_value_comp()(lhs, rhs);
287 return !impl_.get_value_comp()(lhs, rhs); 326 };
288 }), 327
289 end()); 328 iterator erase_after;
329 switch (dupes) {
330 case KEEP_FIRST_OF_DUPES:
331 erase_after = std::unique(begin(), end(), comparator);
332 break;
333 case KEEP_LAST_OF_DUPES:
334 erase_after = LastUnique(begin(), end(), comparator);
335 break;
336 }
337 erase(erase_after, end());
290 } 338 }
291 339
292 // To support comparators that may not be possible to default-construct, we 340 // 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 341 // 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 342 // 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 343 // take advantage of an empty base class optimization to avoid extra space in
296 // the common case when Compare has no state. 344 // the common case when Compare has no state.
297 struct Impl : private value_compare { 345 struct Impl : private value_compare {
298 Impl() = default; 346 Impl() = default;
299 347
(...skipping 18 matching lines...) Expand all
318 template <class Key, class Value, class GetKeyFromValue, class KeyCompare> 366 template <class Key, class Value, class GetKeyFromValue, class KeyCompare>
319 flat_tree<Key, Value, GetKeyFromValue, KeyCompare>::flat_tree( 367 flat_tree<Key, Value, GetKeyFromValue, KeyCompare>::flat_tree(
320 const KeyCompare& comp) 368 const KeyCompare& comp)
321 : impl_(comp) {} 369 : impl_(comp) {}
322 370
323 template <class Key, class Value, class GetKeyFromValue, class KeyCompare> 371 template <class Key, class Value, class GetKeyFromValue, class KeyCompare>
324 template <class InputIterator> 372 template <class InputIterator>
325 flat_tree<Key, Value, GetKeyFromValue, KeyCompare>::flat_tree( 373 flat_tree<Key, Value, GetKeyFromValue, KeyCompare>::flat_tree(
326 InputIterator first, 374 InputIterator first,
327 InputIterator last, 375 InputIterator last,
376 FlatContainerDupes dupe_handling,
328 const KeyCompare& comp) 377 const KeyCompare& comp)
329 : impl_(comp, first, last) { 378 : impl_(comp, first, last) {
330 sort_and_unique(); 379 sort_and_unique(dupe_handling);
331 } 380 }
332 381
333 template <class Key, class Value, class GetKeyFromValue, class KeyCompare> 382 template <class Key, class Value, class GetKeyFromValue, class KeyCompare>
334 flat_tree<Key, Value, GetKeyFromValue, KeyCompare>::flat_tree( 383 flat_tree<Key, Value, GetKeyFromValue, KeyCompare>::flat_tree(
335 const flat_tree&) = default; 384 const flat_tree&) = default;
336 385
337 template <class Key, class Value, class GetKeyFromValue, class KeyCompare> 386 template <class Key, class Value, class GetKeyFromValue, class KeyCompare>
338 flat_tree<Key, Value, GetKeyFromValue, KeyCompare>::flat_tree(flat_tree&&) = 387 flat_tree<Key, Value, GetKeyFromValue, KeyCompare>::flat_tree(flat_tree&&) =
339 default; 388 default;
340 389
341 template <class Key, class Value, class GetKeyFromValue, class KeyCompare> 390 template <class Key, class Value, class GetKeyFromValue, class KeyCompare>
342 flat_tree<Key, Value, GetKeyFromValue, KeyCompare>::flat_tree( 391 flat_tree<Key, Value, GetKeyFromValue, KeyCompare>::flat_tree(
392 std::vector<value_type> items,
393 FlatContainerDupes dupe_handling,
394 const KeyCompare& comp)
395 : impl_(comp, std::move(items)) {
396 sort_and_unique(dupe_handling);
397 }
398
399 template <class Key, class Value, class GetKeyFromValue, class KeyCompare>
400 flat_tree<Key, Value, GetKeyFromValue, KeyCompare>::flat_tree(
343 std::initializer_list<value_type> ilist, 401 std::initializer_list<value_type> ilist,
402 FlatContainerDupes dupe_handling,
344 const KeyCompare& comp) 403 const KeyCompare& comp)
345 : flat_tree(std::begin(ilist), std::end(ilist), comp) {} 404 : flat_tree(std::begin(ilist), std::end(ilist), dupe_handling, comp) {}
346 405
347 template <class Key, class Value, class GetKeyFromValue, class KeyCompare> 406 template <class Key, class Value, class GetKeyFromValue, class KeyCompare>
348 flat_tree<Key, Value, GetKeyFromValue, KeyCompare>::~flat_tree() = default; 407 flat_tree<Key, Value, GetKeyFromValue, KeyCompare>::~flat_tree() = default;
349 408
350 // ---------------------------------------------------------------------------- 409 // ----------------------------------------------------------------------------
351 // Assignments. 410 // Assignments.
352 411
353 template <class Key, class Value, class GetKeyFromValue, class KeyCompare> 412 template <class Key, class Value, class GetKeyFromValue, class KeyCompare>
354 auto flat_tree<Key, Value, GetKeyFromValue, KeyCompare>::operator=( 413 auto flat_tree<Key, Value, GetKeyFromValue, KeyCompare>::operator=(
355 const flat_tree&) -> flat_tree& = default; 414 const flat_tree&) -> flat_tree& = default;
356 415
357 template <class Key, class Value, class GetKeyFromValue, class KeyCompare> 416 template <class Key, class Value, class GetKeyFromValue, class KeyCompare>
358 auto flat_tree<Key, Value, GetKeyFromValue, KeyCompare>::operator=(flat_tree &&) 417 auto flat_tree<Key, Value, GetKeyFromValue, KeyCompare>::operator=(flat_tree &&)
359 -> flat_tree& = default; 418 -> flat_tree& = default;
360 419
361 template <class Key, class Value, class GetKeyFromValue, class KeyCompare> 420 template <class Key, class Value, class GetKeyFromValue, class KeyCompare>
362 auto flat_tree<Key, Value, GetKeyFromValue, KeyCompare>::operator=( 421 auto flat_tree<Key, Value, GetKeyFromValue, KeyCompare>::operator=(
363 std::initializer_list<value_type> ilist) -> flat_tree& { 422 std::initializer_list<value_type> ilist) -> flat_tree& {
364 impl_.body_ = ilist; 423 impl_.body_ = ilist;
365 sort_and_unique(); 424 sort_and_unique(KEEP_FIRST_OF_DUPES);
366 return *this; 425 return *this;
367 } 426 }
368 427
369 // ---------------------------------------------------------------------------- 428 // ----------------------------------------------------------------------------
370 // Memory management. 429 // Memory management.
371 430
372 template <class Key, class Value, class GetKeyFromValue, class KeyCompare> 431 template <class Key, class Value, class GetKeyFromValue, class KeyCompare>
373 void flat_tree<Key, Value, GetKeyFromValue, KeyCompare>::reserve( 432 void flat_tree<Key, Value, GetKeyFromValue, KeyCompare>::reserve(
374 size_type new_capacity) { 433 size_type new_capacity) {
375 impl_.body_.reserve(new_capacity); 434 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>& 767 void EraseIf(base::internal::flat_tree<Key, Value, GetKeyFromValue, KeyCompare>&
709 container, 768 container,
710 Predicate pred) { 769 Predicate pred) {
711 container.erase(std::remove_if(container.begin(), container.end(), pred), 770 container.erase(std::remove_if(container.begin(), container.end(), pred),
712 container.end()); 771 container.end());
713 } 772 }
714 773
715 } // namespace base 774 } // namespace base
716 775
717 #endif // BASE_CONTAINERS_FLAT_TREE_H_ 776 #endif // BASE_CONTAINERS_FLAT_TREE_H_
OLDNEW

Powered by Google App Engine
This is Rietveld 408576698