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

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

Issue 2944523002: Improving flat containers interface. (Closed)
Patch Set: Review, round 3. 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 PickConstReferenceTypeT =
vmpstr 2017/06/26 15:35:53 nit: Maybe KeyTypeOrT? I'd still weakly prefer thi
dyaroshev 2017/06/26 16:19:28 Done.
478 typename std::conditional<IsTransparentCompare<key_compare>::value,
479 const K&,
480 const key_type&>::type;
439 }; 481 };
440 482
441 // ---------------------------------------------------------------------------- 483 // ----------------------------------------------------------------------------
442 // Lifetime. 484 // Lifetime.
443 485
444 template <class Key, class Value, class GetKeyFromValue, class KeyCompare> 486 template <class Key, class Value, class GetKeyFromValue, class KeyCompare>
445 flat_tree<Key, Value, GetKeyFromValue, KeyCompare>::flat_tree() = default; 487 flat_tree<Key, Value, GetKeyFromValue, KeyCompare>::flat_tree() = default;
446 488
447 template <class Key, class Value, class GetKeyFromValue, class KeyCompare> 489 template <class Key, class Value, class GetKeyFromValue, class KeyCompare>
448 flat_tree<Key, Value, GetKeyFromValue, KeyCompare>::flat_tree( 490 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, 802 const_iterator position_hint,
761 Args&&... args) -> iterator { 803 Args&&... args) -> iterator {
762 return insert(position_hint, value_type(std::forward<Args>(args)...)); 804 return insert(position_hint, value_type(std::forward<Args>(args)...));
763 } 805 }
764 806
765 // ---------------------------------------------------------------------------- 807 // ----------------------------------------------------------------------------
766 // Erase operations. 808 // Erase operations.
767 809
768 template <class Key, class Value, class GetKeyFromValue, class KeyCompare> 810 template <class Key, class Value, class GetKeyFromValue, class KeyCompare>
769 auto flat_tree<Key, Value, GetKeyFromValue, KeyCompare>::erase( 811 auto flat_tree<Key, Value, GetKeyFromValue, KeyCompare>::erase(
812 iterator position) -> iterator {
813 return impl_.body_.erase(position);
814 }
815
816 template <class Key, class Value, class GetKeyFromValue, class KeyCompare>
817 auto flat_tree<Key, Value, GetKeyFromValue, KeyCompare>::erase(
770 const_iterator position) -> iterator { 818 const_iterator position) -> iterator {
771 // We have to cast away const because of crbug.com/677044. 819 // We have to cast away const because of crbug.com/677044.
772 return impl_.body_.erase(const_cast_it(position)); 820 return erase(const_cast_it(position));
773 } 821 }
774 822
775 template <class Key, class Value, class GetKeyFromValue, class KeyCompare> 823 template <class Key, class Value, class GetKeyFromValue, class KeyCompare>
776 auto flat_tree<Key, Value, GetKeyFromValue, KeyCompare>::erase( 824 template <typename K>
777 const key_type& val) -> size_type { 825 auto flat_tree<Key, Value, GetKeyFromValue, KeyCompare>::erase(const K& val)
826 -> size_type {
778 auto eq_range = equal_range(val); 827 auto eq_range = equal_range(val);
779 auto res = std::distance(eq_range.first, eq_range.second); 828 auto res = std::distance(eq_range.first, eq_range.second);
780 // We have to cast away const because of crbug.com/677044. 829 // 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)); 830 erase(const_cast_it(eq_range.first), const_cast_it(eq_range.second));
782 return res; 831 return res;
783 } 832 }
784 833
785 template <class Key, class Value, class GetKeyFromValue, class KeyCompare> 834 template <class Key, class Value, class GetKeyFromValue, class KeyCompare>
786 auto flat_tree<Key, Value, GetKeyFromValue, KeyCompare>::erase( 835 auto flat_tree<Key, Value, GetKeyFromValue, KeyCompare>::erase(
787 const_iterator first, 836 const_iterator first,
(...skipping 14 matching lines...) Expand all
802 template <class Key, class Value, class GetKeyFromValue, class KeyCompare> 851 template <class Key, class Value, class GetKeyFromValue, class KeyCompare>
803 auto flat_tree<Key, Value, GetKeyFromValue, KeyCompare>::value_comp() const 852 auto flat_tree<Key, Value, GetKeyFromValue, KeyCompare>::value_comp() const
804 -> value_compare { 853 -> value_compare {
805 return impl_.get_value_comp(); 854 return impl_.get_value_comp();
806 } 855 }
807 856
808 // ---------------------------------------------------------------------------- 857 // ----------------------------------------------------------------------------
809 // Search operations. 858 // Search operations.
810 859
811 template <class Key, class Value, class GetKeyFromValue, class KeyCompare> 860 template <class Key, class Value, class GetKeyFromValue, class KeyCompare>
861 template <typename K>
812 auto flat_tree<Key, Value, GetKeyFromValue, KeyCompare>::count( 862 auto flat_tree<Key, Value, GetKeyFromValue, KeyCompare>::count(
813 const key_type& key) const -> size_type { 863 const K& key) const -> size_type {
814 auto eq_range = equal_range(key); 864 auto eq_range = equal_range(key);
815 return std::distance(eq_range.first, eq_range.second); 865 return std::distance(eq_range.first, eq_range.second);
816 } 866 }
817 867
818 template <class Key, class Value, class GetKeyFromValue, class KeyCompare> 868 template <class Key, class Value, class GetKeyFromValue, class KeyCompare>
819 auto flat_tree<Key, Value, GetKeyFromValue, KeyCompare>::find( 869 template <typename K>
820 const key_type& key) -> iterator { 870 auto flat_tree<Key, Value, GetKeyFromValue, KeyCompare>::find(const K& key)
871 -> iterator {
821 return const_cast_it(as_const().find(key)); 872 return const_cast_it(as_const().find(key));
822 } 873 }
823 874
824 template <class Key, class Value, class GetKeyFromValue, class KeyCompare> 875 template <class Key, class Value, class GetKeyFromValue, class KeyCompare>
876 template <typename K>
825 auto flat_tree<Key, Value, GetKeyFromValue, KeyCompare>::find( 877 auto flat_tree<Key, Value, GetKeyFromValue, KeyCompare>::find(
826 const key_type& key) const -> const_iterator { 878 const K& key) const -> const_iterator {
827 auto eq_range = equal_range(key); 879 auto eq_range = equal_range(key);
828 return (eq_range.first == eq_range.second) ? end() : eq_range.first; 880 return (eq_range.first == eq_range.second) ? end() : eq_range.first;
829 } 881 }
830 882
831 template <class Key, class Value, class GetKeyFromValue, class KeyCompare> 883 template <class Key, class Value, class GetKeyFromValue, class KeyCompare>
884 template <typename K>
832 auto flat_tree<Key, Value, GetKeyFromValue, KeyCompare>::equal_range( 885 auto flat_tree<Key, Value, GetKeyFromValue, KeyCompare>::equal_range(
833 const key_type& key) -> std::pair<iterator, iterator> { 886 const K& key) -> std::pair<iterator, iterator> {
834 auto res = as_const().equal_range(key); 887 auto res = as_const().equal_range(key);
835 return {const_cast_it(res.first), const_cast_it(res.second)}; 888 return {const_cast_it(res.first), const_cast_it(res.second)};
836 } 889 }
837 890
838 template <class Key, class Value, class GetKeyFromValue, class KeyCompare> 891 template <class Key, class Value, class GetKeyFromValue, class KeyCompare>
892 template <typename K>
839 auto flat_tree<Key, Value, GetKeyFromValue, KeyCompare>::equal_range( 893 auto flat_tree<Key, Value, GetKeyFromValue, KeyCompare>::equal_range(
840 const key_type& key) const -> std::pair<const_iterator, const_iterator> { 894 const K& key) const -> std::pair<const_iterator, const_iterator> {
841 auto lower = lower_bound(key); 895 auto lower = lower_bound(key);
842 896
843 GetKeyFromValue extractor; 897 GetKeyFromValue extractor;
844 if (lower == end() || impl_.get_key_comp()(key, extractor(*lower))) 898 if (lower == end() || impl_.get_key_comp()(key, extractor(*lower)))
845 return {lower, lower}; 899 return {lower, lower};
846 900
847 return {lower, std::next(lower)}; 901 return {lower, std::next(lower)};
848 } 902 }
849 903
850 template <class Key, class Value, class GetKeyFromValue, class KeyCompare> 904 template <class Key, class Value, class GetKeyFromValue, class KeyCompare>
905 template <typename K>
851 auto flat_tree<Key, Value, GetKeyFromValue, KeyCompare>::lower_bound( 906 auto flat_tree<Key, Value, GetKeyFromValue, KeyCompare>::lower_bound(
852 const key_type& key) -> iterator { 907 const K& key) -> iterator {
853 return const_cast_it(as_const().lower_bound(key)); 908 return const_cast_it(as_const().lower_bound(key));
854 } 909 }
855 910
856 template <class Key, class Value, class GetKeyFromValue, class KeyCompare> 911 template <class Key, class Value, class GetKeyFromValue, class KeyCompare>
912 template <typename K>
857 auto flat_tree<Key, Value, GetKeyFromValue, KeyCompare>::lower_bound( 913 auto flat_tree<Key, Value, GetKeyFromValue, KeyCompare>::lower_bound(
858 const key_type& key) const -> const_iterator { 914 const K& key) const -> const_iterator {
915 // Only compile when conversion is implicit.
vmpstr 2017/06/26 15:35:53 I'm not sure what this comment is referring to. Th
dyaroshev 2017/06/26 16:19:28 This is about using assignment over operator(). T
916 PickConstReferenceTypeT<K> key_ref = key;
917
859 KeyValueCompare key_value(impl_.get_key_comp()); 918 KeyValueCompare key_value(impl_.get_key_comp());
860 return std::lower_bound(begin(), end(), key, key_value); 919 return std::lower_bound(begin(), end(), key_ref, key_value);
861 } 920 }
862 921
863 template <class Key, class Value, class GetKeyFromValue, class KeyCompare> 922 template <class Key, class Value, class GetKeyFromValue, class KeyCompare>
923 template <typename K>
864 auto flat_tree<Key, Value, GetKeyFromValue, KeyCompare>::upper_bound( 924 auto flat_tree<Key, Value, GetKeyFromValue, KeyCompare>::upper_bound(
865 const key_type& key) -> iterator { 925 const K& key) -> iterator {
866 return const_cast_it(as_const().upper_bound(key)); 926 return const_cast_it(as_const().upper_bound(key));
867 } 927 }
868 928
869 template <class Key, class Value, class GetKeyFromValue, class KeyCompare> 929 template <class Key, class Value, class GetKeyFromValue, class KeyCompare>
930 template <typename K>
870 auto flat_tree<Key, Value, GetKeyFromValue, KeyCompare>::upper_bound( 931 auto flat_tree<Key, Value, GetKeyFromValue, KeyCompare>::upper_bound(
871 const key_type& key) const -> const_iterator { 932 const K& key) const -> const_iterator {
872 KeyValueCompare key_value(impl_.get_key_comp()); 933 KeyValueCompare key_value(impl_.get_key_comp());
873 return std::upper_bound(begin(), end(), key, key_value); 934
935 // Only compile when conversion is implicit.
936 PickConstReferenceTypeT<K> key_ref = key;
937 return std::upper_bound(begin(), end(), key_ref, key_value);
874 } 938 }
875 939
876 // ---------------------------------------------------------------------------- 940 // ----------------------------------------------------------------------------
877 // General operations. 941 // General operations.
878 942
879 template <class Key, class Value, class GetKeyFromValue, class KeyCompare> 943 template <class Key, class Value, class GetKeyFromValue, class KeyCompare>
880 void flat_tree<Key, Value, GetKeyFromValue, KeyCompare>::swap( 944 void flat_tree<Key, Value, GetKeyFromValue, KeyCompare>::swap(
881 flat_tree& other) { 945 flat_tree& other) {
882 std::swap(impl_, other.impl_); 946 std::swap(impl_, other.impl_);
883 } 947 }
(...skipping 29 matching lines...) Expand all
913 void EraseIf(base::internal::flat_tree<Key, Value, GetKeyFromValue, KeyCompare>& 977 void EraseIf(base::internal::flat_tree<Key, Value, GetKeyFromValue, KeyCompare>&
914 container, 978 container,
915 Predicate pred) { 979 Predicate pred) {
916 container.erase(std::remove_if(container.begin(), container.end(), pred), 980 container.erase(std::remove_if(container.begin(), container.end(), pred),
917 container.end()); 981 container.end());
918 } 982 }
919 983
920 } // namespace base 984 } // namespace base
921 985
922 #endif // BASE_CONTAINERS_FLAT_TREE_H_ 986 #endif // BASE_CONTAINERS_FLAT_TREE_H_
OLDNEW

Powered by Google App Engine
This is Rietveld 408576698