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

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

Issue 2944523002: Improving flat containers interface. (Closed)
Patch Set: Review, round 4. Created 3 years, 5 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 <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
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
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
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
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
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
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
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_
OLDNEW

Powered by Google App Engine
This is Rietveld 408576698