Chromium Code Reviews| OLD | NEW |
|---|---|
| 1 // Copyright (c) 2012 The Chromium Authors. All rights reserved. | 1 // Copyright (c) 2012 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_SMALL_MAP_H_ | 5 #ifndef BASE_CONTAINERS_SMALL_MAP_H_ |
| 6 #define BASE_CONTAINERS_SMALL_MAP_H_ | 6 #define BASE_CONTAINERS_SMALL_MAP_H_ |
| 7 | 7 |
| 8 #include <stddef.h> | 8 #include <stddef.h> |
| 9 | 9 |
| 10 #include <map> | 10 #include <map> |
| 11 #include <string> | 11 #include <string> |
| 12 #include <utility> | 12 #include <utility> |
| 13 | 13 |
| 14 #include "base/containers/hash_tables.h" | |
| 15 #include "base/logging.h" | 14 #include "base/logging.h" |
| 16 #include "base/memory/manual_constructor.h" | 15 #include "base/memory/manual_constructor.h" |
| 17 | 16 |
| 18 namespace base { | 17 namespace base { |
| 19 | 18 |
| 20 // An STL-like associative container which starts out backed by a simple | 19 // An STL-like associative container which starts out backed by a simple |
| 21 // array but switches to some other container type if it grows beyond a | 20 // array but switches to some other container type if it grows beyond a |
| 22 // fixed size. | 21 // fixed size. |
| 23 // | 22 // |
| 24 // WHAT TYPE OF MAP SHOULD YOU USE? | 23 // WHAT TYPE OF MAP SHOULD YOU USE? |
| (...skipping 15 matching lines...) Expand all Loading... | |
| 40 // - base::small_map combines the performance benefits of the | 39 // - base::small_map combines the performance benefits of the |
| 41 // brute-force-searched vector for small cases (no extra heap allocations), | 40 // brute-force-searched vector for small cases (no extra heap allocations), |
| 42 // but can efficiently fall back if you end up adding many items. It will | 41 // but can efficiently fall back if you end up adding many items. It will |
| 43 // generate more code than std::map (at least 160 bytes for operator[]) | 42 // generate more code than std::map (at least 160 bytes for operator[]) |
| 44 // which is bad if you have a "weird" key where map functions can't be | 43 // which is bad if you have a "weird" key where map functions can't be |
| 45 // duplicate-code-eliminated. If you have a one-off key and aren't in | 44 // duplicate-code-eliminated. If you have a one-off key and aren't in |
| 46 // performance-critical code, this bloat may negate some of the benefits and | 45 // performance-critical code, this bloat may negate some of the benefits and |
| 47 // you should consider on of the other options. | 46 // you should consider on of the other options. |
| 48 // | 47 // |
| 49 // base::small_map will pick up the comparator from the underlying map type. In | 48 // base::small_map will pick up the comparator from the underlying map type. In |
| 50 // std::map (and in MSVC additionally hash_map) only a "less" operator is | 49 // std::map a "less" operator is defined, which requires us to do two |
| 51 // defined, which requires us to do two comparisons per element when doing the | 50 // comparisons per element when doing the brute-force search in the simple |
| 52 // brute-force search in the simple array. | 51 // array. |
| 53 // | 52 // |
| 54 // We define default overrides for the common map types to avoid this | 53 // We define default overrides for the common map types to avoid this |
| 55 // double-compare, but you should be aware of this if you use your own | 54 // double-compare, but you should be aware of this if you use your own |
| 56 // operator< for your map and supply yor own version of == to the small_map. | 55 // operator< for your map and supply yor own version of == to the small_map. |
| 57 // You can use regular operator== by just doing: | 56 // You can use regular operator== by just doing: |
| 58 // | 57 // |
| 59 // base::small_map<std::map<MyKey, MyValue>, 4, std::equal_to<KyKey>> | 58 // base::small_map<std::map<MyKey, MyValue>, 4, std::equal_to<KyKey>> |
| 60 // | 59 // |
| 61 // | 60 // |
| 62 // USAGE | 61 // USAGE |
| 63 // ----- | 62 // ----- |
| 64 // | 63 // |
| 65 // NormalMap: The map type to fall back to. This also defines the key | 64 // NormalMap: The map type to fall back to. This also defines the key |
| 66 // and value types for the small_map. | 65 // and value types for the small_map. |
| 67 // kArraySize: The size of the initial array of results. This will be | 66 // kArraySize: The size of the initial array of results. This will be |
| 68 // allocated with the small_map object rather than separately on | 67 // allocated with the small_map object rather than separately on |
| 69 // the heap. Once the map grows beyond this size, the map type | 68 // the heap. Once the map grows beyond this size, the map type |
| 70 // will be used instead. | 69 // will be used instead. |
| 71 // EqualKey: A functor which tests two keys for equality. If the wrapped | 70 // EqualKey: A functor which tests two keys for equality. If the wrapped |
| 72 // map type has a "key_equal" member (hash_map does), then that will | 71 // map type has a "key_equal" member (unordered_map does), then that |
| 73 // be used by default. If the wrapped map type has a strict weak | 72 // will be used by default. If the wrapped map type has a strict |
| 74 // ordering "key_compare" (std::map does), that will be used to | 73 // weak ordering "key_compare" (std::map does), that will be used to |
| 75 // implement equality by default. | 74 // implement equality by default. |
| 76 // MapInit: A functor that takes a ManualConstructor<NormalMap>* and uses it to | 75 // MapInit: A functor that takes a ManualConstructor<NormalMap>* and uses it to |
| 77 // initialize the map. This functor will be called at most once per | 76 // initialize the map. This functor will be called at most once per |
| 78 // small_map, when the map exceeds the threshold of kArraySize and we | 77 // small_map, when the map exceeds the threshold of kArraySize and we |
| 79 // are about to copy values from the array to the map. The functor | 78 // are about to copy values from the array to the map. The functor |
| 80 // *must* call one of the Init() methods provided by | 79 // *must* call one of the Init() methods provided by |
| 81 // ManualConstructor, since after it runs we assume that the NormalMap | 80 // ManualConstructor, since after it runs we assume that the NormalMap |
| 82 // has been initialized. | 81 // has been initialized. |
| 83 // | 82 // |
| 84 // example: | 83 // example: |
| (...skipping 50 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... | |
| 135 const typename M::key_type& right) { | 134 const typename M::key_type& right) { |
| 136 // Implements equality in terms of a strict weak ordering comparator. | 135 // Implements equality in terms of a strict weak ordering comparator. |
| 137 typename M::key_compare comp; | 136 typename M::key_compare comp; |
| 138 return !comp(left, right) && !comp(right, left); | 137 return !comp(left, right) && !comp(right, left); |
| 139 } | 138 } |
| 140 }; | 139 }; |
| 141 }; | 140 }; |
| 142 | 141 |
| 143 // Provide overrides to use operator== for key compare for the "normal" map and | 142 // Provide overrides to use operator== for key compare for the "normal" map and |
| 144 // hash map types. If you override the default comparator or allocator for a | 143 // hash map types. If you override the default comparator or allocator for a |
| 145 // map or hash_map, or use another type of map, this won't get used. | 144 // map or unordered_map, or use another type of map, this won't get used. |
| 146 // | |
| 147 // If we switch to using std::unordered_map for base::hash_map, then the | |
| 148 // hash_map specialization can be removed. | |
| 149 template <typename KeyType, typename ValueType> | 145 template <typename KeyType, typename ValueType> |
| 150 struct select_equal_key< std::map<KeyType, ValueType>, false> { | 146 struct select_equal_key<std::map<KeyType, ValueType>, false> { |
| 151 struct equal_key { | 147 struct equal_key { |
| 152 bool operator()(const KeyType& left, const KeyType& right) { | 148 bool operator()(const KeyType& left, const KeyType& right) { |
| 153 return left == right; | 149 return left == right; |
| 154 } | |
| 155 }; | |
| 156 }; | |
| 157 template <typename KeyType, typename ValueType> | |
| 158 struct select_equal_key< base::hash_map<KeyType, ValueType>, false> { | |
| 159 struct equal_key { | |
| 160 bool operator()(const KeyType& left, const KeyType& right) { | |
| 161 return left == right; | |
| 162 } | 150 } |
| 163 }; | 151 }; |
| 164 }; | 152 }; |
| 165 | 153 |
| 166 // Partial template specialization handles case where M::key_equal exists, e.g., | 154 // Partial template specialization handles case where M::key_equal exists, e.g., |
| 167 // hash_map<>. | 155 // unordered_map<>. |
| 168 template <typename M> | 156 template <typename M> |
| 169 struct select_equal_key<M, true> { | 157 struct select_equal_key<M, true> { |
| 170 typedef typename M::key_equal equal_key; | 158 typedef typename M::key_equal equal_key; |
| 171 }; | 159 }; |
| 172 | 160 |
| 173 } // namespace internal | 161 } // namespace internal |
| 174 | 162 |
| 175 template <typename NormalMap, | 163 template <typename NormalMap, |
| 176 int kArraySize = 4, | 164 int kArraySize = 4, |
| 177 typename EqualKey = typename internal::select_equal_key< | 165 typename EqualKey = typename internal::select_equal_key< |
| (...skipping 377 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... | |
| 555 inline NormalMap* map() { | 543 inline NormalMap* map() { |
| 556 CHECK(UsingFullMap()); | 544 CHECK(UsingFullMap()); |
| 557 return map_.get(); | 545 return map_.get(); |
| 558 } | 546 } |
| 559 inline const NormalMap* map() const { | 547 inline const NormalMap* map() const { |
| 560 CHECK(UsingFullMap()); | 548 CHECK(UsingFullMap()); |
| 561 return map_.get(); | 549 return map_.get(); |
| 562 } | 550 } |
| 563 | 551 |
| 564 private: | 552 private: |
| 565 int size_; // negative = using hash_map | 553 int size_; // negative = using map |
|
Łukasz Anforowicz
2017/04/24 18:46:10
nit: s/using map/using |map_| instead of |array_|.
| |
| 566 | 554 |
| 567 MapInit functor_; | 555 MapInit functor_; |
| 568 | 556 |
| 569 // We want to call constructors and destructors manually, but we don't | 557 // We want to call constructors and destructors manually, but we don't |
| 570 // want to allocate and deallocate the memory used for them separately. | 558 // want to allocate and deallocate the memory used for them separately. |
| 571 // So, we use this crazy ManualConstructor class. Since C++11 it's possible | 559 // So, we use this crazy ManualConstructor class. Since C++11 it's possible |
| 572 // to use objects in unions like this, but the ManualDestructor syntax is | 560 // to use objects in unions like this, but the ManualDestructor syntax is |
| 573 // a bit better and doesn't have limitations on object type. | 561 // a bit better and doesn't have limitations on object type. |
| 574 // | 562 // |
| 575 // Since array_ and map_ are mutually exclusive, we'll put them in a | 563 // Since array_ and map_ are mutually exclusive, we'll put them in a |
| (...skipping 60 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... | |
| 636 typename EqualKey, | 624 typename EqualKey, |
| 637 typename Functor> | 625 typename Functor> |
| 638 inline bool small_map<NormalMap, kArraySize, EqualKey, Functor>::iterator:: | 626 inline bool small_map<NormalMap, kArraySize, EqualKey, Functor>::iterator:: |
| 639 operator!=(const const_iterator& other) const { | 627 operator!=(const const_iterator& other) const { |
| 640 return other != *this; | 628 return other != *this; |
| 641 } | 629 } |
| 642 | 630 |
| 643 } // namespace base | 631 } // namespace base |
| 644 | 632 |
| 645 #endif // BASE_CONTAINERS_SMALL_MAP_H_ | 633 #endif // BASE_CONTAINERS_SMALL_MAP_H_ |
| OLD | NEW |