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 <iterator> | 9 #include <iterator> |
10 #include <vector> | 10 #include <vector> |
11 | 11 |
12 #include "base/template_util.h" | |
13 | |
12 namespace base { | 14 namespace base { |
13 | 15 |
14 enum FlatContainerDupes { | 16 enum FlatContainerDupes { |
15 KEEP_FIRST_OF_DUPES, | 17 KEEP_FIRST_OF_DUPES, |
16 KEEP_LAST_OF_DUPES, | 18 KEEP_LAST_OF_DUPES, |
17 }; | 19 }; |
18 | 20 |
19 namespace internal { | 21 namespace internal { |
20 | 22 |
21 // This is a convenience method returning true if Iterator is at least a | 23 // This is a convenience method returning true if Iterator is at least a |
(...skipping 26 matching lines...) Expand all Loading... | |
48 for (Iterator next = std::next(first); next != last; ++next, ++first) { | 50 for (Iterator next = std::next(first); next != last; ++next, ++first) { |
49 if (!compare(*first, *next)) | 51 if (!compare(*first, *next)) |
50 *replacable++ = std::move(*first); | 52 *replacable++ = std::move(*first); |
51 } | 53 } |
52 | 54 |
53 // Last element should be copied unconditionally. | 55 // Last element should be copied unconditionally. |
54 *replacable++ = std::move(*first); | 56 *replacable++ = std::move(*first); |
55 return replacable; | 57 return replacable; |
56 } | 58 } |
57 | 59 |
60 // Uses SFINAE to detect whether type has is_transparent member. | |
61 template <typename T, typename = void> | |
62 struct IsTransparentCompare : std::false_type {}; | |
63 template <typename T> | |
64 struct IsTransparentCompare<T, void_t<typename T::is_transparent>> | |
65 : std::true_type {}; | |
66 | |
67 // Implementation ------------------------------------------------------------- | |
68 | |
58 // Implementation of a sorted vector for backing flat_set and flat_map. Do not | 69 // Implementation of a sorted vector for backing flat_set and flat_map. Do not |
59 // use directly. | 70 // use directly. |
60 // | 71 // |
61 // The use of "value" in this is like std::map uses, meaning it's the thing | 72 // The use of "value" in this is like std::map uses, meaning it's the thing |
62 // contained (in the case of map it's a <Kay, Mapped> pair). The Key is how | 73 // contained (in the case of map it's a <Kay, Mapped> pair). The Key is how |
63 // things are looked up. In the case of a set, Key == Value. In the case of | 74 // things are looked up. In the case of a set, Key == Value. In the case of |
64 // a map, the Key is a component of a Value. | 75 // a map, the Key is a component of a Value. |
65 // | 76 // |
66 // The helper class GetKeyFromValue provides the means to extract a key from a | 77 // The helper class GetKeyFromValue provides the means to extract a key from a |
67 // value for comparison purposes. It should implement: | 78 // value for comparison purposes. It should implement: |
(...skipping 159 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... | |
227 // Erase operations. | 238 // Erase operations. |
228 // | 239 // |
229 // Assume that every operation invalidates iterators and references. | 240 // Assume that every operation invalidates iterators and references. |
230 // | 241 // |
231 // erase(position), erase(first, last) can take O(size). | 242 // erase(position), erase(first, last) can take O(size). |
232 // erase(key) may take O(size) + O(log(size)). | 243 // erase(key) may take O(size) + O(log(size)). |
233 // | 244 // |
234 // Prefer base::EraseIf() or some other variation on erase(remove(), end()) | 245 // Prefer base::EraseIf() or some other variation on erase(remove(), end()) |
235 // idiom when deleting multiple non-consecutive elements. | 246 // idiom when deleting multiple non-consecutive elements. |
236 | 247 |
248 iterator erase(iterator position); | |
237 iterator erase(const_iterator position); | 249 iterator erase(const_iterator position); |
238 iterator erase(const_iterator first, const_iterator last); | 250 iterator erase(const_iterator first, const_iterator last); |
239 size_type erase(const key_type& key); | 251 template <typename K> |
252 size_type erase(const K& key); | |
240 | 253 |
241 // -------------------------------------------------------------------------- | 254 // -------------------------------------------------------------------------- |
242 // Comparators. | 255 // Comparators. |
243 | 256 |
244 key_compare key_comp() const; | 257 key_compare key_comp() const; |
245 value_compare value_comp() const; | 258 value_compare value_comp() const; |
246 | 259 |
247 // -------------------------------------------------------------------------- | 260 // -------------------------------------------------------------------------- |
248 // Search operations. | 261 // Search operations. |
249 // | 262 // |
250 // Search operations have O(log(size)) complexity. | 263 // Search operations have O(log(size)) complexity. |
251 | 264 |
252 size_type count(const key_type& key) const; | 265 template <typename K> |
266 size_type count(const K& key) const; | |
253 | 267 |
254 iterator find(const key_type& key); | 268 template <typename K> |
255 const_iterator find(const key_type& key) const; | 269 iterator find(const K& key); |
256 | 270 |
257 std::pair<iterator, iterator> equal_range(const key_type& ket); | 271 template <typename K> |
258 std::pair<const_iterator, const_iterator> equal_range( | 272 const_iterator find(const K& key) const; |
259 const key_type& key) const; | |
260 | 273 |
261 iterator lower_bound(const key_type& key); | 274 template <typename K> |
262 const_iterator lower_bound(const key_type& key) const; | 275 std::pair<iterator, iterator> equal_range(const K& key); |
263 | 276 |
264 iterator upper_bound(const key_type& key); | 277 template <typename K> |
265 const_iterator upper_bound(const key_type& key) const; | 278 std::pair<const_iterator, const_iterator> equal_range(const K& key) const; |
279 | |
280 template <typename K> | |
281 iterator lower_bound(const K& key); | |
282 | |
283 template <typename K> | |
284 const_iterator lower_bound(const K& key) const; | |
285 | |
286 template <typename K> | |
287 iterator upper_bound(const K& key); | |
288 | |
289 template <typename K> | |
290 const_iterator upper_bound(const K& key) const; | |
266 | 291 |
267 // -------------------------------------------------------------------------- | 292 // -------------------------------------------------------------------------- |
268 // General operations. | 293 // General operations. |
269 // | 294 // |
270 // Assume that swap invalidates iterators and references. | 295 // Assume that swap invalidates iterators and references. |
271 // | 296 // |
272 // Implementation note: currently we use operator==() and operator<() on | 297 // Implementation note: currently we use operator==() and operator<() on |
273 // std::vector, because they have the same contract we need, so we use them | 298 // std::vector, because they have the same contract we need, so we use them |
274 // directly for brevity and in case it is more optimal than calling equal() | 299 // directly for brevity and in case it is more optimal than calling equal() |
275 // and lexicograhpical_compare(). If the underlying container type is changed, | 300 // and lexicograhpical_compare(). If the underlying container type is changed, |
(...skipping 34 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... | |
310 iterator unsafe_emplace(const_iterator position, Args&&... args); | 335 iterator unsafe_emplace(const_iterator position, Args&&... args); |
311 | 336 |
312 private: | 337 private: |
313 // Helper class for e.g. lower_bound that can compare a value on the left | 338 // Helper class for e.g. lower_bound that can compare a value on the left |
314 // to a key on the right. | 339 // to a key on the right. |
315 struct KeyValueCompare { | 340 struct KeyValueCompare { |
316 // The key comparison object must outlive this class. | 341 // The key comparison object must outlive this class. |
317 explicit KeyValueCompare(const key_compare& key_comp) | 342 explicit KeyValueCompare(const key_compare& key_comp) |
318 : key_comp_(key_comp) {} | 343 : key_comp_(key_comp) {} |
319 | 344 |
320 bool operator()(const value_type& left, const key_type& right) const { | 345 template <typename T, typename U> |
321 GetKeyFromValue extractor; | 346 bool operator()(const T& lhs, const U& rhs) const { |
322 return key_comp_(extractor(left), right); | 347 return key_comp_(extract_if_value_type(lhs), extract_if_value_type(rhs)); |
323 } | 348 } |
324 | 349 |
325 private: | 350 private: |
351 const key_type& extract_if_value_type(const value_type& v) const { | |
352 GetKeyFromValue extractor; | |
353 return extractor(v); | |
354 } | |
355 | |
356 template <typename K> | |
357 const K& extract_if_value_type(const K& k) const { | |
358 return k; | |
359 } | |
360 | |
326 const key_compare& key_comp_; | 361 const key_compare& key_comp_; |
327 }; | 362 }; |
328 | 363 |
329 const flat_tree& as_const() { return *this; } | 364 const flat_tree& as_const() { return *this; } |
330 | 365 |
331 iterator const_cast_it(const_iterator c_it) { | 366 iterator const_cast_it(const_iterator c_it) { |
332 auto distance = std::distance(cbegin(), c_it); | 367 auto distance = std::distance(cbegin(), c_it); |
333 return std::next(begin(), distance); | 368 return std::next(begin(), distance); |
334 } | 369 } |
335 | 370 |
(...skipping 93 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... | |
429 template <class Cmp, class... Body> | 464 template <class Cmp, class... Body> |
430 explicit Impl(Cmp&& compare_arg, Body&&... underlying_type_args) | 465 explicit Impl(Cmp&& compare_arg, Body&&... underlying_type_args) |
431 : value_compare(std::forward<Cmp>(compare_arg)), | 466 : value_compare(std::forward<Cmp>(compare_arg)), |
432 body_(std::forward<Body>(underlying_type_args)...) {} | 467 body_(std::forward<Body>(underlying_type_args)...) {} |
433 | 468 |
434 const value_compare& get_value_comp() const { return *this; } | 469 const value_compare& get_value_comp() const { return *this; } |
435 const key_compare& get_key_comp() const { return *this; } | 470 const key_compare& get_key_comp() const { return *this; } |
436 | 471 |
437 underlying_type body_; | 472 underlying_type body_; |
438 } impl_; | 473 } impl_; |
474 | |
475 // If the compare is not transparent we want to construct key_type once. | |
476 template <typename K> | |
477 using KeyTypeOrK = typename std:: | |
478 conditional<IsTransparentCompare<key_compare>::value, K, key_type>::type; | |
439 }; | 479 }; |
440 | 480 |
441 // ---------------------------------------------------------------------------- | 481 // ---------------------------------------------------------------------------- |
442 // Lifetime. | 482 // Lifetime. |
443 | 483 |
444 template <class Key, class Value, class GetKeyFromValue, class KeyCompare> | 484 template <class Key, class Value, class GetKeyFromValue, class KeyCompare> |
445 flat_tree<Key, Value, GetKeyFromValue, KeyCompare>::flat_tree() = default; | 485 flat_tree<Key, Value, GetKeyFromValue, KeyCompare>::flat_tree() = default; |
446 | 486 |
447 template <class Key, class Value, class GetKeyFromValue, class KeyCompare> | 487 template <class Key, class Value, class GetKeyFromValue, class KeyCompare> |
448 flat_tree<Key, Value, GetKeyFromValue, KeyCompare>::flat_tree( | 488 flat_tree<Key, Value, GetKeyFromValue, KeyCompare>::flat_tree( |
(...skipping 311 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... | |
760 const_iterator position_hint, | 800 const_iterator position_hint, |
761 Args&&... args) -> iterator { | 801 Args&&... args) -> iterator { |
762 return insert(position_hint, value_type(std::forward<Args>(args)...)); | 802 return insert(position_hint, value_type(std::forward<Args>(args)...)); |
763 } | 803 } |
764 | 804 |
765 // ---------------------------------------------------------------------------- | 805 // ---------------------------------------------------------------------------- |
766 // Erase operations. | 806 // Erase operations. |
767 | 807 |
768 template <class Key, class Value, class GetKeyFromValue, class KeyCompare> | 808 template <class Key, class Value, class GetKeyFromValue, class KeyCompare> |
769 auto flat_tree<Key, Value, GetKeyFromValue, KeyCompare>::erase( | 809 auto flat_tree<Key, Value, GetKeyFromValue, KeyCompare>::erase( |
810 iterator position) -> iterator { | |
811 return impl_.body_.erase(position); | |
812 } | |
813 | |
814 template <class Key, class Value, class GetKeyFromValue, class KeyCompare> | |
815 auto flat_tree<Key, Value, GetKeyFromValue, KeyCompare>::erase( | |
770 const_iterator position) -> iterator { | 816 const_iterator position) -> iterator { |
771 // We have to cast away const because of crbug.com/677044. | 817 // We have to cast away const because of crbug.com/677044. |
772 return impl_.body_.erase(const_cast_it(position)); | 818 return erase(const_cast_it(position)); |
773 } | 819 } |
774 | 820 |
775 template <class Key, class Value, class GetKeyFromValue, class KeyCompare> | 821 template <class Key, class Value, class GetKeyFromValue, class KeyCompare> |
776 auto flat_tree<Key, Value, GetKeyFromValue, KeyCompare>::erase( | 822 template <typename K> |
777 const key_type& val) -> size_type { | 823 auto flat_tree<Key, Value, GetKeyFromValue, KeyCompare>::erase(const K& val) |
824 -> size_type { | |
778 auto eq_range = equal_range(val); | 825 auto eq_range = equal_range(val); |
779 auto res = std::distance(eq_range.first, eq_range.second); | 826 auto res = std::distance(eq_range.first, eq_range.second); |
780 // We have to cast away const because of crbug.com/677044. | 827 // We have to cast away const because of crbug.com/677044. |
781 erase(const_cast_it(eq_range.first), const_cast_it(eq_range.second)); | 828 erase(const_cast_it(eq_range.first), const_cast_it(eq_range.second)); |
782 return res; | 829 return res; |
783 } | 830 } |
784 | 831 |
785 template <class Key, class Value, class GetKeyFromValue, class KeyCompare> | 832 template <class Key, class Value, class GetKeyFromValue, class KeyCompare> |
786 auto flat_tree<Key, Value, GetKeyFromValue, KeyCompare>::erase( | 833 auto flat_tree<Key, Value, GetKeyFromValue, KeyCompare>::erase( |
787 const_iterator first, | 834 const_iterator first, |
(...skipping 14 matching lines...) Expand all Loading... | |
802 template <class Key, class Value, class GetKeyFromValue, class KeyCompare> | 849 template <class Key, class Value, class GetKeyFromValue, class KeyCompare> |
803 auto flat_tree<Key, Value, GetKeyFromValue, KeyCompare>::value_comp() const | 850 auto flat_tree<Key, Value, GetKeyFromValue, KeyCompare>::value_comp() const |
804 -> value_compare { | 851 -> value_compare { |
805 return impl_.get_value_comp(); | 852 return impl_.get_value_comp(); |
806 } | 853 } |
807 | 854 |
808 // ---------------------------------------------------------------------------- | 855 // ---------------------------------------------------------------------------- |
809 // Search operations. | 856 // Search operations. |
810 | 857 |
811 template <class Key, class Value, class GetKeyFromValue, class KeyCompare> | 858 template <class Key, class Value, class GetKeyFromValue, class KeyCompare> |
859 template <typename K> | |
812 auto flat_tree<Key, Value, GetKeyFromValue, KeyCompare>::count( | 860 auto flat_tree<Key, Value, GetKeyFromValue, KeyCompare>::count( |
813 const key_type& key) const -> size_type { | 861 const K& key) const -> size_type { |
814 auto eq_range = equal_range(key); | 862 auto eq_range = equal_range(key); |
815 return std::distance(eq_range.first, eq_range.second); | 863 return std::distance(eq_range.first, eq_range.second); |
816 } | 864 } |
817 | 865 |
818 template <class Key, class Value, class GetKeyFromValue, class KeyCompare> | 866 template <class Key, class Value, class GetKeyFromValue, class KeyCompare> |
819 auto flat_tree<Key, Value, GetKeyFromValue, KeyCompare>::find( | 867 template <typename K> |
820 const key_type& key) -> iterator { | 868 auto flat_tree<Key, Value, GetKeyFromValue, KeyCompare>::find(const K& key) |
869 -> iterator { | |
821 return const_cast_it(as_const().find(key)); | 870 return const_cast_it(as_const().find(key)); |
822 } | 871 } |
823 | 872 |
824 template <class Key, class Value, class GetKeyFromValue, class KeyCompare> | 873 template <class Key, class Value, class GetKeyFromValue, class KeyCompare> |
874 template <typename K> | |
825 auto flat_tree<Key, Value, GetKeyFromValue, KeyCompare>::find( | 875 auto flat_tree<Key, Value, GetKeyFromValue, KeyCompare>::find( |
826 const key_type& key) const -> const_iterator { | 876 const K& key) const -> const_iterator { |
827 auto eq_range = equal_range(key); | 877 auto eq_range = equal_range(key); |
828 return (eq_range.first == eq_range.second) ? end() : eq_range.first; | 878 return (eq_range.first == eq_range.second) ? end() : eq_range.first; |
829 } | 879 } |
830 | 880 |
831 template <class Key, class Value, class GetKeyFromValue, class KeyCompare> | 881 template <class Key, class Value, class GetKeyFromValue, class KeyCompare> |
882 template <typename K> | |
832 auto flat_tree<Key, Value, GetKeyFromValue, KeyCompare>::equal_range( | 883 auto flat_tree<Key, Value, GetKeyFromValue, KeyCompare>::equal_range( |
833 const key_type& key) -> std::pair<iterator, iterator> { | 884 const K& key) -> std::pair<iterator, iterator> { |
834 auto res = as_const().equal_range(key); | 885 auto res = as_const().equal_range(key); |
835 return {const_cast_it(res.first), const_cast_it(res.second)}; | 886 return {const_cast_it(res.first), const_cast_it(res.second)}; |
836 } | 887 } |
837 | 888 |
838 template <class Key, class Value, class GetKeyFromValue, class KeyCompare> | 889 template <class Key, class Value, class GetKeyFromValue, class KeyCompare> |
890 template <typename K> | |
839 auto flat_tree<Key, Value, GetKeyFromValue, KeyCompare>::equal_range( | 891 auto flat_tree<Key, Value, GetKeyFromValue, KeyCompare>::equal_range( |
840 const key_type& key) const -> std::pair<const_iterator, const_iterator> { | 892 const K& key) const -> std::pair<const_iterator, const_iterator> { |
841 auto lower = lower_bound(key); | 893 auto lower = lower_bound(key); |
842 | 894 |
843 GetKeyFromValue extractor; | 895 GetKeyFromValue extractor; |
844 if (lower == end() || impl_.get_key_comp()(key, extractor(*lower))) | 896 if (lower == end() || impl_.get_key_comp()(key, extractor(*lower))) |
845 return {lower, lower}; | 897 return {lower, lower}; |
846 | 898 |
847 return {lower, std::next(lower)}; | 899 return {lower, std::next(lower)}; |
848 } | 900 } |
849 | 901 |
850 template <class Key, class Value, class GetKeyFromValue, class KeyCompare> | 902 template <class Key, class Value, class GetKeyFromValue, class KeyCompare> |
903 template <typename K> | |
851 auto flat_tree<Key, Value, GetKeyFromValue, KeyCompare>::lower_bound( | 904 auto flat_tree<Key, Value, GetKeyFromValue, KeyCompare>::lower_bound( |
852 const key_type& key) -> iterator { | 905 const K& key) -> iterator { |
853 return const_cast_it(as_const().lower_bound(key)); | 906 return const_cast_it(as_const().lower_bound(key)); |
854 } | 907 } |
855 | 908 |
856 template <class Key, class Value, class GetKeyFromValue, class KeyCompare> | 909 template <class Key, class Value, class GetKeyFromValue, class KeyCompare> |
910 template <typename K> | |
857 auto flat_tree<Key, Value, GetKeyFromValue, KeyCompare>::lower_bound( | 911 auto flat_tree<Key, Value, GetKeyFromValue, KeyCompare>::lower_bound( |
858 const key_type& key) const -> const_iterator { | 912 const K& key) const -> const_iterator { |
913 // Only compile when conversion is implicit. | |
danakj
2017/06/26 19:33:12
What does the compiler error look like when this f
dyaroshev
2017/06/26 22:40:42
If you type:
```
base::flat_set<std::unique_ptr<
vmpstr
2017/06/27 16:09:58
We talked a bit about this. The error is somewhat
| |
914 const KeyTypeOrK<K>& key_ref = key; | |
915 | |
859 KeyValueCompare key_value(impl_.get_key_comp()); | 916 KeyValueCompare key_value(impl_.get_key_comp()); |
860 return std::lower_bound(begin(), end(), key, key_value); | 917 return std::lower_bound(begin(), end(), key_ref, key_value); |
861 } | 918 } |
862 | 919 |
863 template <class Key, class Value, class GetKeyFromValue, class KeyCompare> | 920 template <class Key, class Value, class GetKeyFromValue, class KeyCompare> |
921 template <typename K> | |
864 auto flat_tree<Key, Value, GetKeyFromValue, KeyCompare>::upper_bound( | 922 auto flat_tree<Key, Value, GetKeyFromValue, KeyCompare>::upper_bound( |
865 const key_type& key) -> iterator { | 923 const K& key) -> iterator { |
866 return const_cast_it(as_const().upper_bound(key)); | 924 return const_cast_it(as_const().upper_bound(key)); |
867 } | 925 } |
868 | 926 |
869 template <class Key, class Value, class GetKeyFromValue, class KeyCompare> | 927 template <class Key, class Value, class GetKeyFromValue, class KeyCompare> |
928 template <typename K> | |
870 auto flat_tree<Key, Value, GetKeyFromValue, KeyCompare>::upper_bound( | 929 auto flat_tree<Key, Value, GetKeyFromValue, KeyCompare>::upper_bound( |
871 const key_type& key) const -> const_iterator { | 930 const K& key) const -> const_iterator { |
931 // Only compile when conversion is implicit. | |
932 const KeyTypeOrK<K>& key_ref = key; | |
933 | |
872 KeyValueCompare key_value(impl_.get_key_comp()); | 934 KeyValueCompare key_value(impl_.get_key_comp()); |
873 return std::upper_bound(begin(), end(), key, key_value); | 935 return std::upper_bound(begin(), end(), key_ref, key_value); |
874 } | 936 } |
875 | 937 |
876 // ---------------------------------------------------------------------------- | 938 // ---------------------------------------------------------------------------- |
877 // General operations. | 939 // General operations. |
878 | 940 |
879 template <class Key, class Value, class GetKeyFromValue, class KeyCompare> | 941 template <class Key, class Value, class GetKeyFromValue, class KeyCompare> |
880 void flat_tree<Key, Value, GetKeyFromValue, KeyCompare>::swap( | 942 void flat_tree<Key, Value, GetKeyFromValue, KeyCompare>::swap( |
881 flat_tree& other) { | 943 flat_tree& other) { |
882 std::swap(impl_, other.impl_); | 944 std::swap(impl_, other.impl_); |
883 } | 945 } |
(...skipping 29 matching lines...) Expand all Loading... | |
913 void EraseIf(base::internal::flat_tree<Key, Value, GetKeyFromValue, KeyCompare>& | 975 void EraseIf(base::internal::flat_tree<Key, Value, GetKeyFromValue, KeyCompare>& |
914 container, | 976 container, |
915 Predicate pred) { | 977 Predicate pred) { |
916 container.erase(std::remove_if(container.begin(), container.end(), pred), | 978 container.erase(std::remove_if(container.begin(), container.end(), pred), |
917 container.end()); | 979 container.end()); |
918 } | 980 } |
919 | 981 |
920 } // namespace base | 982 } // namespace base |
921 | 983 |
922 #endif // BASE_CONTAINERS_FLAT_TREE_H_ | 984 #endif // BASE_CONTAINERS_FLAT_TREE_H_ |
OLD | NEW |