| OLD | NEW |
| (Empty) |
| 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 | |
| 3 // found in the LICENSE file. | |
| 4 | |
| 5 #ifndef BASE_CONTAINERS_SMALL_MAP_H_ | |
| 6 #define BASE_CONTAINERS_SMALL_MAP_H_ | |
| 7 | |
| 8 #include <map> | |
| 9 #include <string> | |
| 10 #include <utility> | |
| 11 | |
| 12 #include "base/basictypes.h" | |
| 13 #include "base/containers/hash_tables.h" | |
| 14 #include "base/logging.h" | |
| 15 #include "base/memory/manual_constructor.h" | |
| 16 | |
| 17 namespace base { | |
| 18 | |
| 19 // An STL-like associative container which starts out backed by a simple | |
| 20 // array but switches to some other container type if it grows beyond a | |
| 21 // fixed size. | |
| 22 // | |
| 23 // WHAT TYPE OF MAP SHOULD YOU USE? | |
| 24 // -------------------------------- | |
| 25 // | |
| 26 // - std::map should be the default if you're not sure, since it's the most | |
| 27 // difficult to mess up. Generally this is backed by a red-black tree. It | |
| 28 // will generate a lot of code (if you use a common key type like int or | |
| 29 // string the linker will probably emiminate the duplicates). It will | |
| 30 // do heap allocations for each element. | |
| 31 // | |
| 32 // - If you only ever keep a couple of items and have very simple usage, | |
| 33 // consider whether a using a vector and brute-force searching it will be | |
| 34 // the most efficient. It's not a lot of generated code (less then a | |
| 35 // red-black tree if your key is "weird" and not eliminated as duplicate of | |
| 36 // something else) and will probably be faster and do fewer heap allocations | |
| 37 // than std::map if you have just a couple of items. | |
| 38 // | |
| 39 // - base::hash_map should be used if you need O(1) lookups. It may waste | |
| 40 // space in the hash table, and it can be easy to write correct-looking | |
| 41 // code with the default hash function being wrong or poorly-behaving. | |
| 42 // | |
| 43 // - SmallMap combines the performance benefits of the brute-force-searched | |
| 44 // vector for small cases (no extra heap allocations), but can efficiently | |
| 45 // fall back if you end up adding many items. It will generate more code | |
| 46 // than std::map (at least 160 bytes for operator[]) which is bad if you | |
| 47 // have a "weird" key where map functions can't be | |
| 48 // duplicate-code-eliminated. If you have a one-off key and aren't in | |
| 49 // performance-critical code, this bloat may negate some of the benefits and | |
| 50 // you should consider on of the other options. | |
| 51 // | |
| 52 // SmallMap will pick up the comparator from the underlying map type. In | |
| 53 // std::map (and in MSVC additionally hash_map) only a "less" operator is | |
| 54 // defined, which requires us to do two comparisons per element when doing the | |
| 55 // brute-force search in the simple array. | |
| 56 // | |
| 57 // We define default overrides for the common map types to avoid this | |
| 58 // double-compare, but you should be aware of this if you use your own | |
| 59 // operator< for your map and supply yor own version of == to the SmallMap. | |
| 60 // You can use regular operator== by just doing: | |
| 61 // | |
| 62 // base::SmallMap<std::map<MyKey, MyValue>, 4, std::equal_to<KyKey> > | |
| 63 // | |
| 64 // | |
| 65 // USAGE | |
| 66 // ----- | |
| 67 // | |
| 68 // NormalMap: The map type to fall back to. This also defines the key | |
| 69 // and value types for the SmallMap. | |
| 70 // kArraySize: The size of the initial array of results. This will be | |
| 71 // allocated with the SmallMap object rather than separately on | |
| 72 // the heap. Once the map grows beyond this size, the map type | |
| 73 // will be used instead. | |
| 74 // EqualKey: A functor which tests two keys for equality. If the wrapped | |
| 75 // map type has a "key_equal" member (hash_map does), then that will | |
| 76 // be used by default. If the wrapped map type has a strict weak | |
| 77 // ordering "key_compare" (std::map does), that will be used to | |
| 78 // implement equality by default. | |
| 79 // MapInit: A functor that takes a ManualConstructor<NormalMap>* and uses it to | |
| 80 // initialize the map. This functor will be called at most once per | |
| 81 // SmallMap, when the map exceeds the threshold of kArraySize and we | |
| 82 // are about to copy values from the array to the map. The functor | |
| 83 // *must* call one of the Init() methods provided by | |
| 84 // ManualConstructor, since after it runs we assume that the NormalMap | |
| 85 // has been initialized. | |
| 86 // | |
| 87 // example: | |
| 88 // base::SmallMap< std::map<string, int> > days; | |
| 89 // days["sunday" ] = 0; | |
| 90 // days["monday" ] = 1; | |
| 91 // days["tuesday" ] = 2; | |
| 92 // days["wednesday"] = 3; | |
| 93 // days["thursday" ] = 4; | |
| 94 // days["friday" ] = 5; | |
| 95 // days["saturday" ] = 6; | |
| 96 // | |
| 97 // You should assume that SmallMap might invalidate all the iterators | |
| 98 // on any call to erase(), insert() and operator[]. | |
| 99 | |
| 100 namespace internal { | |
| 101 | |
| 102 template <typename NormalMap> | |
| 103 class SmallMapDefaultInit { | |
| 104 public: | |
| 105 void operator()(ManualConstructor<NormalMap>* map) const { | |
| 106 map->Init(); | |
| 107 } | |
| 108 }; | |
| 109 | |
| 110 // has_key_equal<M>::value is true iff there exists a type M::key_equal. This is | |
| 111 // used to dispatch to one of the select_equal_key<> metafunctions below. | |
| 112 template <typename M> | |
| 113 struct has_key_equal { | |
| 114 typedef char sml; // "small" is sometimes #defined so we use an abbreviation. | |
| 115 typedef struct { char dummy[2]; } big; | |
| 116 // Two functions, one accepts types that have a key_equal member, and one that | |
| 117 // accepts anything. They each return a value of a different size, so we can | |
| 118 // determine at compile-time which function would have been called. | |
| 119 template <typename U> static big test(typename U::key_equal*); | |
| 120 template <typename> static sml test(...); | |
| 121 // Determines if M::key_equal exists by looking at the size of the return | |
| 122 // type of the compiler-chosen test() function. | |
| 123 static const bool value = (sizeof(test<M>(0)) == sizeof(big)); | |
| 124 }; | |
| 125 template <typename M> const bool has_key_equal<M>::value; | |
| 126 | |
| 127 // Base template used for map types that do NOT have an M::key_equal member, | |
| 128 // e.g., std::map<>. These maps have a strict weak ordering comparator rather | |
| 129 // than an equality functor, so equality will be implemented in terms of that | |
| 130 // comparator. | |
| 131 // | |
| 132 // There's a partial specialization of this template below for map types that do | |
| 133 // have an M::key_equal member. | |
| 134 template <typename M, bool has_key_equal_value> | |
| 135 struct select_equal_key { | |
| 136 struct equal_key { | |
| 137 bool operator()(const typename M::key_type& left, | |
| 138 const typename M::key_type& right) { | |
| 139 // Implements equality in terms of a strict weak ordering comparator. | |
| 140 typename M::key_compare comp; | |
| 141 return !comp(left, right) && !comp(right, left); | |
| 142 } | |
| 143 }; | |
| 144 }; | |
| 145 | |
| 146 // Provide overrides to use operator== for key compare for the "normal" map and | |
| 147 // hash map types. If you override the default comparator or allocator for a | |
| 148 // map or hash_map, or use another type of map, this won't get used. | |
| 149 // | |
| 150 // If we switch to using std::unordered_map for base::hash_map, then the | |
| 151 // hash_map specialization can be removed. | |
| 152 template <typename KeyType, typename ValueType> | |
| 153 struct select_equal_key< std::map<KeyType, ValueType>, false> { | |
| 154 struct equal_key { | |
| 155 bool operator()(const KeyType& left, const KeyType& right) { | |
| 156 return left == right; | |
| 157 } | |
| 158 }; | |
| 159 }; | |
| 160 template <typename KeyType, typename ValueType> | |
| 161 struct select_equal_key< base::hash_map<KeyType, ValueType>, false> { | |
| 162 struct equal_key { | |
| 163 bool operator()(const KeyType& left, const KeyType& right) { | |
| 164 return left == right; | |
| 165 } | |
| 166 }; | |
| 167 }; | |
| 168 | |
| 169 // Partial template specialization handles case where M::key_equal exists, e.g., | |
| 170 // hash_map<>. | |
| 171 template <typename M> | |
| 172 struct select_equal_key<M, true> { | |
| 173 typedef typename M::key_equal equal_key; | |
| 174 }; | |
| 175 | |
| 176 } // namespace internal | |
| 177 | |
| 178 template <typename NormalMap, | |
| 179 int kArraySize = 4, | |
| 180 typename EqualKey = | |
| 181 typename internal::select_equal_key< | |
| 182 NormalMap, | |
| 183 internal::has_key_equal<NormalMap>::value>::equal_key, | |
| 184 typename MapInit = internal::SmallMapDefaultInit<NormalMap> > | |
| 185 class SmallMap { | |
| 186 // We cannot rely on the compiler to reject array of size 0. In | |
| 187 // particular, gcc 2.95.3 does it but later versions allow 0-length | |
| 188 // arrays. Therefore, we explicitly reject non-positive kArraySize | |
| 189 // here. | |
| 190 COMPILE_ASSERT(kArraySize > 0, default_initial_size_should_be_positive); | |
| 191 | |
| 192 public: | |
| 193 typedef typename NormalMap::key_type key_type; | |
| 194 typedef typename NormalMap::mapped_type data_type; | |
| 195 typedef typename NormalMap::mapped_type mapped_type; | |
| 196 typedef typename NormalMap::value_type value_type; | |
| 197 typedef EqualKey key_equal; | |
| 198 | |
| 199 SmallMap() : size_(0), functor_(MapInit()) {} | |
| 200 | |
| 201 explicit SmallMap(const MapInit& functor) : size_(0), functor_(functor) {} | |
| 202 | |
| 203 // Allow copy-constructor and assignment, since STL allows them too. | |
| 204 SmallMap(const SmallMap& src) { | |
| 205 // size_ and functor_ are initted in InitFrom() | |
| 206 InitFrom(src); | |
| 207 } | |
| 208 void operator=(const SmallMap& src) { | |
| 209 if (&src == this) return; | |
| 210 | |
| 211 // This is not optimal. If src and dest are both using the small | |
| 212 // array, we could skip the teardown and reconstruct. One problem | |
| 213 // to be resolved is that the value_type itself is pair<const K, | |
| 214 // V>, and const K is not assignable. | |
| 215 Destroy(); | |
| 216 InitFrom(src); | |
| 217 } | |
| 218 ~SmallMap() { | |
| 219 Destroy(); | |
| 220 } | |
| 221 | |
| 222 class const_iterator; | |
| 223 | |
| 224 class iterator { | |
| 225 public: | |
| 226 typedef typename NormalMap::iterator::iterator_category iterator_category; | |
| 227 typedef typename NormalMap::iterator::value_type value_type; | |
| 228 typedef typename NormalMap::iterator::difference_type difference_type; | |
| 229 typedef typename NormalMap::iterator::pointer pointer; | |
| 230 typedef typename NormalMap::iterator::reference reference; | |
| 231 | |
| 232 inline iterator(): array_iter_(NULL) {} | |
| 233 | |
| 234 inline iterator& operator++() { | |
| 235 if (array_iter_ != NULL) { | |
| 236 ++array_iter_; | |
| 237 } else { | |
| 238 ++hash_iter_; | |
| 239 } | |
| 240 return *this; | |
| 241 } | |
| 242 inline iterator operator++(int /*unused*/) { | |
| 243 iterator result(*this); | |
| 244 ++(*this); | |
| 245 return result; | |
| 246 } | |
| 247 inline iterator& operator--() { | |
| 248 if (array_iter_ != NULL) { | |
| 249 --array_iter_; | |
| 250 } else { | |
| 251 --hash_iter_; | |
| 252 } | |
| 253 return *this; | |
| 254 } | |
| 255 inline iterator operator--(int /*unused*/) { | |
| 256 iterator result(*this); | |
| 257 --(*this); | |
| 258 return result; | |
| 259 } | |
| 260 inline value_type* operator->() const { | |
| 261 if (array_iter_ != NULL) { | |
| 262 return array_iter_->get(); | |
| 263 } else { | |
| 264 return hash_iter_.operator->(); | |
| 265 } | |
| 266 } | |
| 267 | |
| 268 inline value_type& operator*() const { | |
| 269 if (array_iter_ != NULL) { | |
| 270 return *array_iter_->get(); | |
| 271 } else { | |
| 272 return *hash_iter_; | |
| 273 } | |
| 274 } | |
| 275 | |
| 276 inline bool operator==(const iterator& other) const { | |
| 277 if (array_iter_ != NULL) { | |
| 278 return array_iter_ == other.array_iter_; | |
| 279 } else { | |
| 280 return other.array_iter_ == NULL && hash_iter_ == other.hash_iter_; | |
| 281 } | |
| 282 } | |
| 283 | |
| 284 inline bool operator!=(const iterator& other) const { | |
| 285 return !(*this == other); | |
| 286 } | |
| 287 | |
| 288 bool operator==(const const_iterator& other) const; | |
| 289 bool operator!=(const const_iterator& other) const; | |
| 290 | |
| 291 private: | |
| 292 friend class SmallMap; | |
| 293 friend class const_iterator; | |
| 294 inline explicit iterator(ManualConstructor<value_type>* init) | |
| 295 : array_iter_(init) {} | |
| 296 inline explicit iterator(const typename NormalMap::iterator& init) | |
| 297 : array_iter_(NULL), hash_iter_(init) {} | |
| 298 | |
| 299 ManualConstructor<value_type>* array_iter_; | |
| 300 typename NormalMap::iterator hash_iter_; | |
| 301 }; | |
| 302 | |
| 303 class const_iterator { | |
| 304 public: | |
| 305 typedef typename NormalMap::const_iterator::iterator_category | |
| 306 iterator_category; | |
| 307 typedef typename NormalMap::const_iterator::value_type value_type; | |
| 308 typedef typename NormalMap::const_iterator::difference_type difference_type; | |
| 309 typedef typename NormalMap::const_iterator::pointer pointer; | |
| 310 typedef typename NormalMap::const_iterator::reference reference; | |
| 311 | |
| 312 inline const_iterator(): array_iter_(NULL) {} | |
| 313 // Non-explicit ctor lets us convert regular iterators to const iterators | |
| 314 inline const_iterator(const iterator& other) | |
| 315 : array_iter_(other.array_iter_), hash_iter_(other.hash_iter_) {} | |
| 316 | |
| 317 inline const_iterator& operator++() { | |
| 318 if (array_iter_ != NULL) { | |
| 319 ++array_iter_; | |
| 320 } else { | |
| 321 ++hash_iter_; | |
| 322 } | |
| 323 return *this; | |
| 324 } | |
| 325 inline const_iterator operator++(int /*unused*/) { | |
| 326 const_iterator result(*this); | |
| 327 ++(*this); | |
| 328 return result; | |
| 329 } | |
| 330 | |
| 331 inline const_iterator& operator--() { | |
| 332 if (array_iter_ != NULL) { | |
| 333 --array_iter_; | |
| 334 } else { | |
| 335 --hash_iter_; | |
| 336 } | |
| 337 return *this; | |
| 338 } | |
| 339 inline const_iterator operator--(int /*unused*/) { | |
| 340 const_iterator result(*this); | |
| 341 --(*this); | |
| 342 return result; | |
| 343 } | |
| 344 | |
| 345 inline const value_type* operator->() const { | |
| 346 if (array_iter_ != NULL) { | |
| 347 return array_iter_->get(); | |
| 348 } else { | |
| 349 return hash_iter_.operator->(); | |
| 350 } | |
| 351 } | |
| 352 | |
| 353 inline const value_type& operator*() const { | |
| 354 if (array_iter_ != NULL) { | |
| 355 return *array_iter_->get(); | |
| 356 } else { | |
| 357 return *hash_iter_; | |
| 358 } | |
| 359 } | |
| 360 | |
| 361 inline bool operator==(const const_iterator& other) const { | |
| 362 if (array_iter_ != NULL) { | |
| 363 return array_iter_ == other.array_iter_; | |
| 364 } else { | |
| 365 return other.array_iter_ == NULL && hash_iter_ == other.hash_iter_; | |
| 366 } | |
| 367 } | |
| 368 | |
| 369 inline bool operator!=(const const_iterator& other) const { | |
| 370 return !(*this == other); | |
| 371 } | |
| 372 | |
| 373 private: | |
| 374 friend class SmallMap; | |
| 375 inline explicit const_iterator( | |
| 376 const ManualConstructor<value_type>* init) | |
| 377 : array_iter_(init) {} | |
| 378 inline explicit const_iterator( | |
| 379 const typename NormalMap::const_iterator& init) | |
| 380 : array_iter_(NULL), hash_iter_(init) {} | |
| 381 | |
| 382 const ManualConstructor<value_type>* array_iter_; | |
| 383 typename NormalMap::const_iterator hash_iter_; | |
| 384 }; | |
| 385 | |
| 386 iterator find(const key_type& key) { | |
| 387 key_equal compare; | |
| 388 if (size_ >= 0) { | |
| 389 for (int i = 0; i < size_; i++) { | |
| 390 if (compare(array_[i]->first, key)) { | |
| 391 return iterator(array_ + i); | |
| 392 } | |
| 393 } | |
| 394 return iterator(array_ + size_); | |
| 395 } else { | |
| 396 return iterator(map()->find(key)); | |
| 397 } | |
| 398 } | |
| 399 | |
| 400 const_iterator find(const key_type& key) const { | |
| 401 key_equal compare; | |
| 402 if (size_ >= 0) { | |
| 403 for (int i = 0; i < size_; i++) { | |
| 404 if (compare(array_[i]->first, key)) { | |
| 405 return const_iterator(array_ + i); | |
| 406 } | |
| 407 } | |
| 408 return const_iterator(array_ + size_); | |
| 409 } else { | |
| 410 return const_iterator(map()->find(key)); | |
| 411 } | |
| 412 } | |
| 413 | |
| 414 // Invalidates iterators. | |
| 415 data_type& operator[](const key_type& key) { | |
| 416 key_equal compare; | |
| 417 | |
| 418 if (size_ >= 0) { | |
| 419 // operator[] searches backwards, favoring recently-added | |
| 420 // elements. | |
| 421 for (int i = size_-1; i >= 0; --i) { | |
| 422 if (compare(array_[i]->first, key)) { | |
| 423 return array_[i]->second; | |
| 424 } | |
| 425 } | |
| 426 if (size_ == kArraySize) { | |
| 427 ConvertToRealMap(); | |
| 428 return (*map_)[key]; | |
| 429 } else { | |
| 430 array_[size_].Init(key, data_type()); | |
| 431 return array_[size_++]->second; | |
| 432 } | |
| 433 } else { | |
| 434 return (*map_)[key]; | |
| 435 } | |
| 436 } | |
| 437 | |
| 438 // Invalidates iterators. | |
| 439 std::pair<iterator, bool> insert(const value_type& x) { | |
| 440 key_equal compare; | |
| 441 | |
| 442 if (size_ >= 0) { | |
| 443 for (int i = 0; i < size_; i++) { | |
| 444 if (compare(array_[i]->first, x.first)) { | |
| 445 return std::make_pair(iterator(array_ + i), false); | |
| 446 } | |
| 447 } | |
| 448 if (size_ == kArraySize) { | |
| 449 ConvertToRealMap(); // Invalidates all iterators! | |
| 450 std::pair<typename NormalMap::iterator, bool> ret = map_->insert(x); | |
| 451 return std::make_pair(iterator(ret.first), ret.second); | |
| 452 } else { | |
| 453 array_[size_].Init(x); | |
| 454 return std::make_pair(iterator(array_ + size_++), true); | |
| 455 } | |
| 456 } else { | |
| 457 std::pair<typename NormalMap::iterator, bool> ret = map_->insert(x); | |
| 458 return std::make_pair(iterator(ret.first), ret.second); | |
| 459 } | |
| 460 } | |
| 461 | |
| 462 // Invalidates iterators. | |
| 463 template <class InputIterator> | |
| 464 void insert(InputIterator f, InputIterator l) { | |
| 465 while (f != l) { | |
| 466 insert(*f); | |
| 467 ++f; | |
| 468 } | |
| 469 } | |
| 470 | |
| 471 iterator begin() { | |
| 472 if (size_ >= 0) { | |
| 473 return iterator(array_); | |
| 474 } else { | |
| 475 return iterator(map_->begin()); | |
| 476 } | |
| 477 } | |
| 478 const_iterator begin() const { | |
| 479 if (size_ >= 0) { | |
| 480 return const_iterator(array_); | |
| 481 } else { | |
| 482 return const_iterator(map_->begin()); | |
| 483 } | |
| 484 } | |
| 485 | |
| 486 iterator end() { | |
| 487 if (size_ >= 0) { | |
| 488 return iterator(array_ + size_); | |
| 489 } else { | |
| 490 return iterator(map_->end()); | |
| 491 } | |
| 492 } | |
| 493 const_iterator end() const { | |
| 494 if (size_ >= 0) { | |
| 495 return const_iterator(array_ + size_); | |
| 496 } else { | |
| 497 return const_iterator(map_->end()); | |
| 498 } | |
| 499 } | |
| 500 | |
| 501 void clear() { | |
| 502 if (size_ >= 0) { | |
| 503 for (int i = 0; i < size_; i++) { | |
| 504 array_[i].Destroy(); | |
| 505 } | |
| 506 } else { | |
| 507 map_.Destroy(); | |
| 508 } | |
| 509 size_ = 0; | |
| 510 } | |
| 511 | |
| 512 // Invalidates iterators. | |
| 513 void erase(const iterator& position) { | |
| 514 if (size_ >= 0) { | |
| 515 int i = position.array_iter_ - array_; | |
| 516 array_[i].Destroy(); | |
| 517 --size_; | |
| 518 if (i != size_) { | |
| 519 array_[i].Init(*array_[size_]); | |
| 520 array_[size_].Destroy(); | |
| 521 } | |
| 522 } else { | |
| 523 map_->erase(position.hash_iter_); | |
| 524 } | |
| 525 } | |
| 526 | |
| 527 size_t erase(const key_type& key) { | |
| 528 iterator iter = find(key); | |
| 529 if (iter == end()) return 0u; | |
| 530 erase(iter); | |
| 531 return 1u; | |
| 532 } | |
| 533 | |
| 534 size_t count(const key_type& key) const { | |
| 535 return (find(key) == end()) ? 0 : 1; | |
| 536 } | |
| 537 | |
| 538 size_t size() const { | |
| 539 if (size_ >= 0) { | |
| 540 return static_cast<size_t>(size_); | |
| 541 } else { | |
| 542 return map_->size(); | |
| 543 } | |
| 544 } | |
| 545 | |
| 546 bool empty() const { | |
| 547 if (size_ >= 0) { | |
| 548 return (size_ == 0); | |
| 549 } else { | |
| 550 return map_->empty(); | |
| 551 } | |
| 552 } | |
| 553 | |
| 554 // Returns true if we have fallen back to using the underlying map | |
| 555 // representation. | |
| 556 bool UsingFullMap() const { | |
| 557 return size_ < 0; | |
| 558 } | |
| 559 | |
| 560 inline NormalMap* map() { | |
| 561 CHECK(UsingFullMap()); | |
| 562 return map_.get(); | |
| 563 } | |
| 564 inline const NormalMap* map() const { | |
| 565 CHECK(UsingFullMap()); | |
| 566 return map_.get(); | |
| 567 } | |
| 568 | |
| 569 private: | |
| 570 int size_; // negative = using hash_map | |
| 571 | |
| 572 MapInit functor_; | |
| 573 | |
| 574 // We want to call constructors and destructors manually, but we don't | |
| 575 // want to allocate and deallocate the memory used for them separately. | |
| 576 // So, we use this crazy ManualConstructor class. | |
| 577 // | |
| 578 // Since array_ and map_ are mutually exclusive, we'll put them in a | |
| 579 // union, too. We add in a dummy_ value which quiets MSVC from otherwise | |
| 580 // giving an erroneous "union member has copy constructor" error message | |
| 581 // (C2621). This dummy member has to come before array_ to quiet the | |
| 582 // compiler. | |
| 583 // | |
| 584 // TODO(brettw) remove this and use C++11 unions when we require C++11. | |
| 585 union { | |
| 586 ManualConstructor<value_type> dummy_; | |
| 587 ManualConstructor<value_type> array_[kArraySize]; | |
| 588 ManualConstructor<NormalMap> map_; | |
| 589 }; | |
| 590 | |
| 591 void ConvertToRealMap() { | |
| 592 // Move the current elements into a temporary array. | |
| 593 ManualConstructor<value_type> temp_array[kArraySize]; | |
| 594 | |
| 595 for (int i = 0; i < kArraySize; i++) { | |
| 596 temp_array[i].Init(*array_[i]); | |
| 597 array_[i].Destroy(); | |
| 598 } | |
| 599 | |
| 600 // Initialize the map. | |
| 601 size_ = -1; | |
| 602 functor_(&map_); | |
| 603 | |
| 604 // Insert elements into it. | |
| 605 for (int i = 0; i < kArraySize; i++) { | |
| 606 map_->insert(*temp_array[i]); | |
| 607 temp_array[i].Destroy(); | |
| 608 } | |
| 609 } | |
| 610 | |
| 611 // Helpers for constructors and destructors. | |
| 612 void InitFrom(const SmallMap& src) { | |
| 613 functor_ = src.functor_; | |
| 614 size_ = src.size_; | |
| 615 if (src.size_ >= 0) { | |
| 616 for (int i = 0; i < size_; i++) { | |
| 617 array_[i].Init(*src.array_[i]); | |
| 618 } | |
| 619 } else { | |
| 620 functor_(&map_); | |
| 621 (*map_.get()) = (*src.map_.get()); | |
| 622 } | |
| 623 } | |
| 624 void Destroy() { | |
| 625 if (size_ >= 0) { | |
| 626 for (int i = 0; i < size_; i++) { | |
| 627 array_[i].Destroy(); | |
| 628 } | |
| 629 } else { | |
| 630 map_.Destroy(); | |
| 631 } | |
| 632 } | |
| 633 }; | |
| 634 | |
| 635 template <typename NormalMap, int kArraySize, typename EqualKey, | |
| 636 typename Functor> | |
| 637 inline bool SmallMap<NormalMap, kArraySize, EqualKey, | |
| 638 Functor>::iterator::operator==( | |
| 639 const const_iterator& other) const { | |
| 640 return other == *this; | |
| 641 } | |
| 642 template <typename NormalMap, int kArraySize, typename EqualKey, | |
| 643 typename Functor> | |
| 644 inline bool SmallMap<NormalMap, kArraySize, EqualKey, | |
| 645 Functor>::iterator::operator!=( | |
| 646 const const_iterator& other) const { | |
| 647 return other != *this; | |
| 648 } | |
| 649 | |
| 650 } // namespace base | |
| 651 | |
| 652 #endif // BASE_CONTAINERS_SMALL_MAP_H_ | |
| OLD | NEW |