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 |