OLD | NEW |
---|---|
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 Loading... | |
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 Loading... | |
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 Loading... | |
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 Loading... | |
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_ |
OLD | NEW |