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> |
(...skipping 13 matching lines...) Expand all Loading... | |
24 // WHAT TYPE OF MAP SHOULD YOU USE? | 24 // WHAT TYPE OF MAP SHOULD YOU USE? |
25 // -------------------------------- | 25 // -------------------------------- |
26 // | 26 // |
27 // - std::map should be the default if you're not sure, since it's the most | 27 // - std::map should be the default if you're not sure, since it's the most |
28 // difficult to mess up. Generally this is backed by a red-black tree. It | 28 // difficult to mess up. Generally this is backed by a red-black tree. It |
29 // will generate a lot of code (if you use a common key type like int or | 29 // will generate a lot of code (if you use a common key type like int or |
30 // string the linker will probably emiminate the duplicates). It will | 30 // string the linker will probably emiminate the duplicates). It will |
31 // do heap allocations for each element. | 31 // do heap allocations for each element. |
32 // | 32 // |
33 // - If you only ever keep a couple of items and have very simple usage, | 33 // - If you only ever keep a couple of items and have very simple usage, |
34 // consider whether a using a vector and brute-force searching it will be | 34 // use a base::flat_map. |
35 // the most efficient. It's not a lot of generated code (less than a | |
36 // red-black tree if your key is "weird" and not eliminated as duplicate of | |
37 // something else) and will probably be faster and do fewer heap allocations | |
38 // than std::map if you have just a couple of items. | |
39 // | 35 // |
40 // - base::hash_map should be used if you need O(1) lookups. It may waste | 36 // - std::unordered_map should be used if you need O(1) lookups. It may waste |
41 // space in the hash table, and it can be easy to write correct-looking | 37 // space in the hash table, and it can be easy to write correct-looking |
42 // code with the default hash function being wrong or poorly-behaving. | 38 // code with the default hash function being wrong or poorly-behaving. |
43 // | 39 // |
44 // - SmallMap combines the performance benefits of the brute-force-searched | 40 // - base::small_map combines the performance benefits of the |
45 // vector for small cases (no extra heap allocations), but can efficiently | 41 // brute-force-searched vector for small cases (no extra heap allocations), |
46 // fall back if you end up adding many items. It will generate more code | 42 // but can efficiently fall back if you end up adding many items. It will |
47 // than std::map (at least 160 bytes for operator[]) which is bad if you | 43 // generate more code than std::map (at least 160 bytes for operator[]) |
48 // have a "weird" key where map functions can't be | 44 // which is bad if you have a "weird" key where map functions can't be |
49 // duplicate-code-eliminated. If you have a one-off key and aren't in | 45 // duplicate-code-eliminated. If you have a one-off key and aren't in |
50 // performance-critical code, this bloat may negate some of the benefits and | 46 // performance-critical code, this bloat may negate some of the benefits and |
51 // you should consider on of the other options. | 47 // you should consider on of the other options. |
52 // | 48 // |
53 // SmallMap will pick up the comparator from the underlying map type. In | 49 // base::small_map will pick up the comparator from the underlying map type. In |
54 // std::map (and in MSVC additionally hash_map) only a "less" operator is | 50 // std::map (and in MSVC additionally hash_map) only a "less" operator is |
55 // defined, which requires us to do two comparisons per element when doing the | 51 // defined, which requires us to do two comparisons per element when doing the |
56 // brute-force search in the simple array. | 52 // brute-force search in the simple array. |
57 // | 53 // |
58 // We define default overrides for the common map types to avoid this | 54 // We define default overrides for the common map types to avoid this |
59 // double-compare, but you should be aware of this if you use your own | 55 // double-compare, but you should be aware of this if you use your own |
60 // operator< for your map and supply yor own version of == to the SmallMap. | 56 // operator< for your map and supply yor own version of == to the small_map. |
61 // You can use regular operator== by just doing: | 57 // You can use regular operator== by just doing: |
62 // | 58 // |
63 // base::SmallMap<std::map<MyKey, MyValue>, 4, std::equal_to<KyKey> > | 59 // base::small_map<std::map<MyKey, MyValue>, 4, std::equal_to<KyKey> > |
danakj
2017/04/19 17:32:16
Oh, this has an extra space in the > > too
| |
64 // | 60 // |
65 // | 61 // |
66 // USAGE | 62 // USAGE |
67 // ----- | 63 // ----- |
68 // | 64 // |
69 // NormalMap: The map type to fall back to. This also defines the key | 65 // NormalMap: The map type to fall back to. This also defines the key |
70 // and value types for the SmallMap. | 66 // and value types for the small_map. |
71 // kArraySize: The size of the initial array of results. This will be | 67 // kArraySize: The size of the initial array of results. This will be |
72 // allocated with the SmallMap object rather than separately on | 68 // allocated with the small_map object rather than separately on |
73 // the heap. Once the map grows beyond this size, the map type | 69 // the heap. Once the map grows beyond this size, the map type |
74 // will be used instead. | 70 // will be used instead. |
75 // EqualKey: A functor which tests two keys for equality. If the wrapped | 71 // EqualKey: A functor which tests two keys for equality. If the wrapped |
76 // map type has a "key_equal" member (hash_map does), then that will | 72 // map type has a "key_equal" member (hash_map does), then that will |
77 // be used by default. If the wrapped map type has a strict weak | 73 // be used by default. If the wrapped map type has a strict weak |
78 // ordering "key_compare" (std::map does), that will be used to | 74 // ordering "key_compare" (std::map does), that will be used to |
79 // implement equality by default. | 75 // implement equality by default. |
80 // MapInit: A functor that takes a ManualConstructor<NormalMap>* and uses it to | 76 // MapInit: A functor that takes a ManualConstructor<NormalMap>* and uses it to |
81 // initialize the map. This functor will be called at most once per | 77 // initialize the map. This functor will be called at most once per |
82 // SmallMap, when the map exceeds the threshold of kArraySize and we | 78 // small_map, when the map exceeds the threshold of kArraySize and we |
83 // are about to copy values from the array to the map. The functor | 79 // are about to copy values from the array to the map. The functor |
84 // *must* call one of the Init() methods provided by | 80 // *must* call one of the Init() methods provided by |
85 // ManualConstructor, since after it runs we assume that the NormalMap | 81 // ManualConstructor, since after it runs we assume that the NormalMap |
86 // has been initialized. | 82 // has been initialized. |
87 // | 83 // |
88 // example: | 84 // example: |
89 // base::SmallMap< std::map<string, int> > days; | 85 // base::small_map<std::map<string, int>> days; |
90 // days["sunday" ] = 0; | 86 // days["sunday" ] = 0; |
91 // days["monday" ] = 1; | 87 // days["monday" ] = 1; |
92 // days["tuesday" ] = 2; | 88 // days["tuesday" ] = 2; |
93 // days["wednesday"] = 3; | 89 // days["wednesday"] = 3; |
94 // days["thursday" ] = 4; | 90 // days["thursday" ] = 4; |
95 // days["friday" ] = 5; | 91 // days["friday" ] = 5; |
96 // days["saturday" ] = 6; | 92 // days["saturday" ] = 6; |
97 // | 93 // |
98 // You should assume that SmallMap might invalidate all the iterators | 94 // You should assume that small_map might invalidate all the iterators |
99 // on any call to erase(), insert() and operator[]. | 95 // on any call to erase(), insert() and operator[]. |
100 | 96 |
101 namespace internal { | 97 namespace internal { |
102 | 98 |
103 template <typename NormalMap> | 99 template <typename NormalMap> |
104 class SmallMapDefaultInit { | 100 class small_map_default_init { |
105 public: | 101 public: |
106 void operator()(ManualConstructor<NormalMap>* map) const { | 102 void operator()(ManualConstructor<NormalMap>* map) const { |
107 map->Init(); | 103 map->Init(); |
108 } | 104 } |
109 }; | 105 }; |
110 | 106 |
111 // has_key_equal<M>::value is true iff there exists a type M::key_equal. This is | 107 // has_key_equal<M>::value is true iff there exists a type M::key_equal. This is |
112 // used to dispatch to one of the select_equal_key<> metafunctions below. | 108 // used to dispatch to one of the select_equal_key<> metafunctions below. |
113 template <typename M> | 109 template <typename M> |
114 struct has_key_equal { | 110 struct has_key_equal { |
(...skipping 56 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... | |
171 // hash_map<>. | 167 // hash_map<>. |
172 template <typename M> | 168 template <typename M> |
173 struct select_equal_key<M, true> { | 169 struct select_equal_key<M, true> { |
174 typedef typename M::key_equal equal_key; | 170 typedef typename M::key_equal equal_key; |
175 }; | 171 }; |
176 | 172 |
177 } // namespace internal | 173 } // namespace internal |
178 | 174 |
179 template <typename NormalMap, | 175 template <typename NormalMap, |
180 int kArraySize = 4, | 176 int kArraySize = 4, |
181 typename EqualKey = | 177 typename EqualKey = typename internal::select_equal_key< |
182 typename internal::select_equal_key< | 178 NormalMap, |
183 NormalMap, | 179 internal::has_key_equal<NormalMap>::value>::equal_key, |
184 internal::has_key_equal<NormalMap>::value>::equal_key, | 180 typename MapInit = internal::small_map_default_init<NormalMap>> |
185 typename MapInit = internal::SmallMapDefaultInit<NormalMap> > | 181 class small_map { |
186 class SmallMap { | |
187 // We cannot rely on the compiler to reject array of size 0. In | 182 // We cannot rely on the compiler to reject array of size 0. In |
188 // particular, gcc 2.95.3 does it but later versions allow 0-length | 183 // particular, gcc 2.95.3 does it but later versions allow 0-length |
189 // arrays. Therefore, we explicitly reject non-positive kArraySize | 184 // arrays. Therefore, we explicitly reject non-positive kArraySize |
190 // here. | 185 // here. |
191 static_assert(kArraySize > 0, "default initial size should be positive"); | 186 static_assert(kArraySize > 0, "default initial size should be positive"); |
192 | 187 |
193 public: | 188 public: |
194 typedef typename NormalMap::key_type key_type; | 189 typedef typename NormalMap::key_type key_type; |
195 typedef typename NormalMap::mapped_type data_type; | 190 typedef typename NormalMap::mapped_type data_type; |
196 typedef typename NormalMap::mapped_type mapped_type; | 191 typedef typename NormalMap::mapped_type mapped_type; |
197 typedef typename NormalMap::value_type value_type; | 192 typedef typename NormalMap::value_type value_type; |
198 typedef EqualKey key_equal; | 193 typedef EqualKey key_equal; |
199 | 194 |
200 SmallMap() : size_(0), functor_(MapInit()) {} | 195 small_map() : size_(0), functor_(MapInit()) {} |
201 | 196 |
202 explicit SmallMap(const MapInit& functor) : size_(0), functor_(functor) {} | 197 explicit small_map(const MapInit& functor) : size_(0), functor_(functor) {} |
203 | 198 |
204 // Allow copy-constructor and assignment, since STL allows them too. | 199 // Allow copy-constructor and assignment, since STL allows them too. |
205 SmallMap(const SmallMap& src) { | 200 small_map(const small_map& src) { |
206 // size_ and functor_ are initted in InitFrom() | 201 // size_ and functor_ are initted in InitFrom() |
207 InitFrom(src); | 202 InitFrom(src); |
208 } | 203 } |
209 void operator=(const SmallMap& src) { | 204 void operator=(const small_map& src) { |
210 if (&src == this) return; | 205 if (&src == this) return; |
211 | 206 |
212 // This is not optimal. If src and dest are both using the small | 207 // This is not optimal. If src and dest are both using the small |
213 // array, we could skip the teardown and reconstruct. One problem | 208 // array, we could skip the teardown and reconstruct. One problem |
214 // to be resolved is that the value_type itself is pair<const K, | 209 // to be resolved is that the value_type itself is pair<const K, |
215 // V>, and const K is not assignable. | 210 // V>, and const K is not assignable. |
216 Destroy(); | 211 Destroy(); |
217 InitFrom(src); | 212 InitFrom(src); |
218 } | 213 } |
219 ~SmallMap() { | 214 ~small_map() { Destroy(); } |
220 Destroy(); | |
221 } | |
222 | 215 |
223 class const_iterator; | 216 class const_iterator; |
224 | 217 |
225 class iterator { | 218 class iterator { |
226 public: | 219 public: |
227 typedef typename NormalMap::iterator::iterator_category iterator_category; | 220 typedef typename NormalMap::iterator::iterator_category iterator_category; |
228 typedef typename NormalMap::iterator::value_type value_type; | 221 typedef typename NormalMap::iterator::value_type value_type; |
229 typedef typename NormalMap::iterator::difference_type difference_type; | 222 typedef typename NormalMap::iterator::difference_type difference_type; |
230 typedef typename NormalMap::iterator::pointer pointer; | 223 typedef typename NormalMap::iterator::pointer pointer; |
231 typedef typename NormalMap::iterator::reference reference; | 224 typedef typename NormalMap::iterator::reference reference; |
(...skipping 51 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... | |
283 } | 276 } |
284 | 277 |
285 inline bool operator!=(const iterator& other) const { | 278 inline bool operator!=(const iterator& other) const { |
286 return !(*this == other); | 279 return !(*this == other); |
287 } | 280 } |
288 | 281 |
289 bool operator==(const const_iterator& other) const; | 282 bool operator==(const const_iterator& other) const; |
290 bool operator!=(const const_iterator& other) const; | 283 bool operator!=(const const_iterator& other) const; |
291 | 284 |
292 private: | 285 private: |
293 friend class SmallMap; | 286 friend class small_map; |
294 friend class const_iterator; | 287 friend class const_iterator; |
295 inline explicit iterator(ManualConstructor<value_type>* init) | 288 inline explicit iterator(ManualConstructor<value_type>* init) |
296 : array_iter_(init) {} | 289 : array_iter_(init) {} |
297 inline explicit iterator(const typename NormalMap::iterator& init) | 290 inline explicit iterator(const typename NormalMap::iterator& init) |
298 : array_iter_(NULL), hash_iter_(init) {} | 291 : array_iter_(NULL), hash_iter_(init) {} |
299 | 292 |
300 ManualConstructor<value_type>* array_iter_; | 293 ManualConstructor<value_type>* array_iter_; |
301 typename NormalMap::iterator hash_iter_; | 294 typename NormalMap::iterator hash_iter_; |
302 }; | 295 }; |
303 | 296 |
(...skipping 61 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... | |
365 } else { | 358 } else { |
366 return other.array_iter_ == NULL && hash_iter_ == other.hash_iter_; | 359 return other.array_iter_ == NULL && hash_iter_ == other.hash_iter_; |
367 } | 360 } |
368 } | 361 } |
369 | 362 |
370 inline bool operator!=(const const_iterator& other) const { | 363 inline bool operator!=(const const_iterator& other) const { |
371 return !(*this == other); | 364 return !(*this == other); |
372 } | 365 } |
373 | 366 |
374 private: | 367 private: |
375 friend class SmallMap; | 368 friend class small_map; |
376 inline explicit const_iterator( | 369 inline explicit const_iterator( |
377 const ManualConstructor<value_type>* init) | 370 const ManualConstructor<value_type>* init) |
378 : array_iter_(init) {} | 371 : array_iter_(init) {} |
379 inline explicit const_iterator( | 372 inline explicit const_iterator( |
380 const typename NormalMap::const_iterator& init) | 373 const typename NormalMap::const_iterator& init) |
381 : array_iter_(NULL), hash_iter_(init) {} | 374 : array_iter_(NULL), hash_iter_(init) {} |
382 | 375 |
383 const ManualConstructor<value_type>* array_iter_; | 376 const ManualConstructor<value_type>* array_iter_; |
384 typename NormalMap::const_iterator hash_iter_; | 377 typename NormalMap::const_iterator hash_iter_; |
385 }; | 378 }; |
(...skipping 214 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... | |
600 functor_(&map_); | 593 functor_(&map_); |
601 | 594 |
602 // Insert elements into it. | 595 // Insert elements into it. |
603 for (int i = 0; i < kArraySize; i++) { | 596 for (int i = 0; i < kArraySize; i++) { |
604 map_->insert(std::move(*temp_array[i])); | 597 map_->insert(std::move(*temp_array[i])); |
605 temp_array[i].Destroy(); | 598 temp_array[i].Destroy(); |
606 } | 599 } |
607 } | 600 } |
608 | 601 |
609 // Helpers for constructors and destructors. | 602 // Helpers for constructors and destructors. |
610 void InitFrom(const SmallMap& src) { | 603 void InitFrom(const small_map& src) { |
611 functor_ = src.functor_; | 604 functor_ = src.functor_; |
612 size_ = src.size_; | 605 size_ = src.size_; |
613 if (src.size_ >= 0) { | 606 if (src.size_ >= 0) { |
614 for (int i = 0; i < size_; i++) { | 607 for (int i = 0; i < size_; i++) { |
615 array_[i].Init(*src.array_[i]); | 608 array_[i].Init(*src.array_[i]); |
616 } | 609 } |
617 } else { | 610 } else { |
618 functor_(&map_); | 611 functor_(&map_); |
619 (*map_.get()) = (*src.map_.get()); | 612 (*map_.get()) = (*src.map_.get()); |
620 } | 613 } |
621 } | 614 } |
622 void Destroy() { | 615 void Destroy() { |
623 if (size_ >= 0) { | 616 if (size_ >= 0) { |
624 for (int i = 0; i < size_; i++) { | 617 for (int i = 0; i < size_; i++) { |
625 array_[i].Destroy(); | 618 array_[i].Destroy(); |
626 } | 619 } |
627 } else { | 620 } else { |
628 map_.Destroy(); | 621 map_.Destroy(); |
629 } | 622 } |
630 } | 623 } |
631 }; | 624 }; |
632 | 625 |
633 template <typename NormalMap, int kArraySize, typename EqualKey, | 626 template <typename NormalMap, |
627 int kArraySize, | |
628 typename EqualKey, | |
634 typename Functor> | 629 typename Functor> |
635 inline bool SmallMap<NormalMap, kArraySize, EqualKey, | 630 inline bool small_map<NormalMap, kArraySize, EqualKey, Functor>::iterator:: |
636 Functor>::iterator::operator==( | 631 operator==(const const_iterator& other) const { |
637 const const_iterator& other) const { | |
638 return other == *this; | 632 return other == *this; |
639 } | 633 } |
640 template <typename NormalMap, int kArraySize, typename EqualKey, | 634 template <typename NormalMap, |
635 int kArraySize, | |
636 typename EqualKey, | |
641 typename Functor> | 637 typename Functor> |
642 inline bool SmallMap<NormalMap, kArraySize, EqualKey, | 638 inline bool small_map<NormalMap, kArraySize, EqualKey, Functor>::iterator:: |
643 Functor>::iterator::operator!=( | 639 operator!=(const const_iterator& other) const { |
644 const const_iterator& other) const { | |
645 return other != *this; | 640 return other != *this; |
646 } | 641 } |
647 | 642 |
648 } // namespace base | 643 } // namespace base |
649 | 644 |
650 #endif // BASE_CONTAINERS_SMALL_MAP_H_ | 645 #endif // BASE_CONTAINERS_SMALL_MAP_H_ |
OLD | NEW |