1*6777b538SAndroid Build Coastguard Worker // Copyright 2012 The Chromium Authors 2*6777b538SAndroid Build Coastguard Worker // Use of this source code is governed by a BSD-style license that can be 3*6777b538SAndroid Build Coastguard Worker // found in the LICENSE file. 4*6777b538SAndroid Build Coastguard Worker 5*6777b538SAndroid Build Coastguard Worker #ifndef BASE_CONTAINERS_SMALL_MAP_H_ 6*6777b538SAndroid Build Coastguard Worker #define BASE_CONTAINERS_SMALL_MAP_H_ 7*6777b538SAndroid Build Coastguard Worker 8*6777b538SAndroid Build Coastguard Worker #include <stddef.h> 9*6777b538SAndroid Build Coastguard Worker 10*6777b538SAndroid Build Coastguard Worker #include <limits> 11*6777b538SAndroid Build Coastguard Worker #include <map> 12*6777b538SAndroid Build Coastguard Worker #include <new> 13*6777b538SAndroid Build Coastguard Worker #include <utility> 14*6777b538SAndroid Build Coastguard Worker 15*6777b538SAndroid Build Coastguard Worker #include "base/check.h" 16*6777b538SAndroid Build Coastguard Worker #include "base/check_op.h" 17*6777b538SAndroid Build Coastguard Worker #include "base/memory/raw_ptr.h" 18*6777b538SAndroid Build Coastguard Worker 19*6777b538SAndroid Build Coastguard Worker inline constexpr size_t kUsingFullMapSentinel = 20*6777b538SAndroid Build Coastguard Worker std::numeric_limits<size_t>::max(); 21*6777b538SAndroid Build Coastguard Worker 22*6777b538SAndroid Build Coastguard Worker namespace base { 23*6777b538SAndroid Build Coastguard Worker 24*6777b538SAndroid Build Coastguard Worker // small_map is a container with a std::map-like interface. It starts out backed 25*6777b538SAndroid Build Coastguard Worker // by an unsorted array but switches to some other container type if it grows 26*6777b538SAndroid Build Coastguard Worker // beyond this fixed size. 27*6777b538SAndroid Build Coastguard Worker // 28*6777b538SAndroid Build Coastguard Worker // Please see //base/containers/README.md for an overview of which container 29*6777b538SAndroid Build Coastguard Worker // to select. 30*6777b538SAndroid Build Coastguard Worker // 31*6777b538SAndroid Build Coastguard Worker // PROS 32*6777b538SAndroid Build Coastguard Worker // 33*6777b538SAndroid Build Coastguard Worker // - Good memory locality and low overhead for smaller maps. 34*6777b538SAndroid Build Coastguard Worker // - Handles large maps without the degenerate performance of flat_map. 35*6777b538SAndroid Build Coastguard Worker // 36*6777b538SAndroid Build Coastguard Worker // CONS 37*6777b538SAndroid Build Coastguard Worker // 38*6777b538SAndroid Build Coastguard Worker // - Larger code size than the alternatives. 39*6777b538SAndroid Build Coastguard Worker // 40*6777b538SAndroid Build Coastguard Worker // IMPORTANT NOTES 41*6777b538SAndroid Build Coastguard Worker // 42*6777b538SAndroid Build Coastguard Worker // - Iterators are invalidated across mutations. 43*6777b538SAndroid Build Coastguard Worker // 44*6777b538SAndroid Build Coastguard Worker // DETAILS 45*6777b538SAndroid Build Coastguard Worker // 46*6777b538SAndroid Build Coastguard Worker // base::small_map will pick up the comparator from the underlying map type. In 47*6777b538SAndroid Build Coastguard Worker // std::map only a "less" operator is defined, which requires us to do two 48*6777b538SAndroid Build Coastguard Worker // comparisons per element when doing the brute-force search in the simple 49*6777b538SAndroid Build Coastguard Worker // array. std::unordered_map has a key_equal function which will be used. 50*6777b538SAndroid Build Coastguard Worker // 51*6777b538SAndroid Build Coastguard Worker // We define default overrides for the common map types to avoid this 52*6777b538SAndroid Build Coastguard Worker // double-compare, but you should be aware of this if you use your own operator< 53*6777b538SAndroid Build Coastguard Worker // for your map and supply your own version of == to the small_map. You can use 54*6777b538SAndroid Build Coastguard Worker // regular operator== by just doing: 55*6777b538SAndroid Build Coastguard Worker // 56*6777b538SAndroid Build Coastguard Worker // base::small_map<std::map<MyKey, MyValue>, 4, std::equal_to<KyKey>> 57*6777b538SAndroid Build Coastguard Worker // 58*6777b538SAndroid Build Coastguard Worker // 59*6777b538SAndroid Build Coastguard Worker // USAGE 60*6777b538SAndroid Build Coastguard Worker // ----- 61*6777b538SAndroid Build Coastguard Worker // 62*6777b538SAndroid Build Coastguard Worker // NormalMap: The map type to fall back to. This also defines the key and value 63*6777b538SAndroid Build Coastguard Worker // types for the small_map. 64*6777b538SAndroid Build Coastguard Worker // kArraySize: The size of the initial array of results. This will be allocated 65*6777b538SAndroid Build Coastguard Worker // with the small_map object rather than separately on the heap. 66*6777b538SAndroid Build Coastguard Worker // Once the map grows beyond this size, the map type will be used 67*6777b538SAndroid Build Coastguard Worker // instead. 68*6777b538SAndroid Build Coastguard Worker // EqualKey: A functor which tests two keys for equality. If the wrapped map 69*6777b538SAndroid Build Coastguard Worker // type has a "key_equal" member (unordered_map does), then that will 70*6777b538SAndroid Build Coastguard Worker // be used by default. If the wrapped map type has a strict weak 71*6777b538SAndroid Build Coastguard Worker // ordering "key_compare" (std::map does), that will be used to 72*6777b538SAndroid Build Coastguard Worker // implement equality by default. 73*6777b538SAndroid Build Coastguard Worker // MapInit: A functor that takes a NormalMap* and uses it to initialize the map. 74*6777b538SAndroid Build Coastguard Worker // This functor will be called at most once per small_map, when the map 75*6777b538SAndroid Build Coastguard Worker // exceeds the threshold of kArraySize and we are about to copy values 76*6777b538SAndroid Build Coastguard Worker // from the array to the map. The functor *must* initialize the 77*6777b538SAndroid Build Coastguard Worker // NormalMap* argument with placement new, since after it runs we 78*6777b538SAndroid Build Coastguard Worker // assume that the NormalMap has been initialized. 79*6777b538SAndroid Build Coastguard Worker // 80*6777b538SAndroid Build Coastguard Worker // Example: 81*6777b538SAndroid Build Coastguard Worker // base::small_map<std::map<string, int>> days; 82*6777b538SAndroid Build Coastguard Worker // days["sunday" ] = 0; 83*6777b538SAndroid Build Coastguard Worker // days["monday" ] = 1; 84*6777b538SAndroid Build Coastguard Worker // days["tuesday" ] = 2; 85*6777b538SAndroid Build Coastguard Worker // days["wednesday"] = 3; 86*6777b538SAndroid Build Coastguard Worker // days["thursday" ] = 4; 87*6777b538SAndroid Build Coastguard Worker // days["friday" ] = 5; 88*6777b538SAndroid Build Coastguard Worker // days["saturday" ] = 6; 89*6777b538SAndroid Build Coastguard Worker 90*6777b538SAndroid Build Coastguard Worker namespace internal { 91*6777b538SAndroid Build Coastguard Worker 92*6777b538SAndroid Build Coastguard Worker template <typename NormalMap> 93*6777b538SAndroid Build Coastguard Worker class small_map_default_init { 94*6777b538SAndroid Build Coastguard Worker public: operator()95*6777b538SAndroid Build Coastguard Worker void operator()(NormalMap* map) const { new (map) NormalMap(); } 96*6777b538SAndroid Build Coastguard Worker }; 97*6777b538SAndroid Build Coastguard Worker 98*6777b538SAndroid Build Coastguard Worker // has_key_equal<M>::value is true iff there exists a type M::key_equal. This is 99*6777b538SAndroid Build Coastguard Worker // used to dispatch to one of the select_equal_key<> metafunctions below. 100*6777b538SAndroid Build Coastguard Worker template <typename M> 101*6777b538SAndroid Build Coastguard Worker struct has_key_equal { 102*6777b538SAndroid Build Coastguard Worker typedef char sml; // "small" is sometimes #defined so we use an abbreviation. 103*6777b538SAndroid Build Coastguard Worker typedef struct { char dummy[2]; } big; 104*6777b538SAndroid Build Coastguard Worker // Two functions, one accepts types that have a key_equal member, and one that 105*6777b538SAndroid Build Coastguard Worker // accepts anything. They each return a value of a different size, so we can 106*6777b538SAndroid Build Coastguard Worker // determine at compile-time which function would have been called. 107*6777b538SAndroid Build Coastguard Worker template <typename U> static big test(typename U::key_equal*); 108*6777b538SAndroid Build Coastguard Worker template <typename> static sml test(...); 109*6777b538SAndroid Build Coastguard Worker // Determines if M::key_equal exists by looking at the size of the return 110*6777b538SAndroid Build Coastguard Worker // type of the compiler-chosen test() function. 111*6777b538SAndroid Build Coastguard Worker static const bool value = (sizeof(test<M>(0)) == sizeof(big)); 112*6777b538SAndroid Build Coastguard Worker }; 113*6777b538SAndroid Build Coastguard Worker template <typename M> const bool has_key_equal<M>::value; 114*6777b538SAndroid Build Coastguard Worker 115*6777b538SAndroid Build Coastguard Worker // Base template used for map types that do NOT have an M::key_equal member, 116*6777b538SAndroid Build Coastguard Worker // e.g., std::map<>. These maps have a strict weak ordering comparator rather 117*6777b538SAndroid Build Coastguard Worker // than an equality functor, so equality will be implemented in terms of that 118*6777b538SAndroid Build Coastguard Worker // comparator. 119*6777b538SAndroid Build Coastguard Worker // 120*6777b538SAndroid Build Coastguard Worker // There's a partial specialization of this template below for map types that do 121*6777b538SAndroid Build Coastguard Worker // have an M::key_equal member. 122*6777b538SAndroid Build Coastguard Worker template <typename M, bool has_key_equal_value> 123*6777b538SAndroid Build Coastguard Worker struct select_equal_key { 124*6777b538SAndroid Build Coastguard Worker struct equal_key { operatorselect_equal_key::equal_key125*6777b538SAndroid Build Coastguard Worker bool operator()(const typename M::key_type& left, 126*6777b538SAndroid Build Coastguard Worker const typename M::key_type& right) { 127*6777b538SAndroid Build Coastguard Worker // Implements equality in terms of a strict weak ordering comparator. 128*6777b538SAndroid Build Coastguard Worker typename M::key_compare comp; 129*6777b538SAndroid Build Coastguard Worker return !comp(left, right) && !comp(right, left); 130*6777b538SAndroid Build Coastguard Worker } 131*6777b538SAndroid Build Coastguard Worker }; 132*6777b538SAndroid Build Coastguard Worker }; 133*6777b538SAndroid Build Coastguard Worker 134*6777b538SAndroid Build Coastguard Worker // Partial template specialization handles case where M::key_equal exists, e.g., 135*6777b538SAndroid Build Coastguard Worker // unordered_map<>. 136*6777b538SAndroid Build Coastguard Worker template <typename M> 137*6777b538SAndroid Build Coastguard Worker struct select_equal_key<M, true> { 138*6777b538SAndroid Build Coastguard Worker typedef typename M::key_equal equal_key; 139*6777b538SAndroid Build Coastguard Worker }; 140*6777b538SAndroid Build Coastguard Worker 141*6777b538SAndroid Build Coastguard Worker } // namespace internal 142*6777b538SAndroid Build Coastguard Worker 143*6777b538SAndroid Build Coastguard Worker template <typename NormalMap, 144*6777b538SAndroid Build Coastguard Worker size_t kArraySize = 4, 145*6777b538SAndroid Build Coastguard Worker typename EqualKey = typename internal::select_equal_key< 146*6777b538SAndroid Build Coastguard Worker NormalMap, 147*6777b538SAndroid Build Coastguard Worker internal::has_key_equal<NormalMap>::value>::equal_key, 148*6777b538SAndroid Build Coastguard Worker typename MapInit = internal::small_map_default_init<NormalMap>> 149*6777b538SAndroid Build Coastguard Worker class small_map { 150*6777b538SAndroid Build Coastguard Worker static_assert(kArraySize > 0, "Initial size must be greater than 0"); 151*6777b538SAndroid Build Coastguard Worker static_assert(kArraySize != kUsingFullMapSentinel, 152*6777b538SAndroid Build Coastguard Worker "Initial size out of range"); 153*6777b538SAndroid Build Coastguard Worker 154*6777b538SAndroid Build Coastguard Worker public: 155*6777b538SAndroid Build Coastguard Worker typedef typename NormalMap::key_type key_type; 156*6777b538SAndroid Build Coastguard Worker typedef typename NormalMap::mapped_type data_type; 157*6777b538SAndroid Build Coastguard Worker typedef typename NormalMap::mapped_type mapped_type; 158*6777b538SAndroid Build Coastguard Worker typedef typename NormalMap::value_type value_type; 159*6777b538SAndroid Build Coastguard Worker typedef EqualKey key_equal; 160*6777b538SAndroid Build Coastguard Worker 161*6777b538SAndroid Build Coastguard Worker small_map() : size_(0), functor_(MapInit()) {} 162*6777b538SAndroid Build Coastguard Worker 163*6777b538SAndroid Build Coastguard Worker explicit small_map(const MapInit& functor) : size_(0), functor_(functor) {} 164*6777b538SAndroid Build Coastguard Worker 165*6777b538SAndroid Build Coastguard Worker // Allow copy-constructor and assignment, since STL allows them too. 166*6777b538SAndroid Build Coastguard Worker small_map(const small_map& src) { 167*6777b538SAndroid Build Coastguard Worker // size_ and functor_ are initted in InitFrom() 168*6777b538SAndroid Build Coastguard Worker InitFrom(src); 169*6777b538SAndroid Build Coastguard Worker } 170*6777b538SAndroid Build Coastguard Worker 171*6777b538SAndroid Build Coastguard Worker void operator=(const small_map& src) { 172*6777b538SAndroid Build Coastguard Worker if (&src == this) return; 173*6777b538SAndroid Build Coastguard Worker 174*6777b538SAndroid Build Coastguard Worker // This is not optimal. If src and dest are both using the small array, we 175*6777b538SAndroid Build Coastguard Worker // could skip the teardown and reconstruct. One problem to be resolved is 176*6777b538SAndroid Build Coastguard Worker // that the value_type itself is pair<const K, V>, and const K is not 177*6777b538SAndroid Build Coastguard Worker // assignable. 178*6777b538SAndroid Build Coastguard Worker Destroy(); 179*6777b538SAndroid Build Coastguard Worker InitFrom(src); 180*6777b538SAndroid Build Coastguard Worker } 181*6777b538SAndroid Build Coastguard Worker 182*6777b538SAndroid Build Coastguard Worker ~small_map() { Destroy(); } 183*6777b538SAndroid Build Coastguard Worker 184*6777b538SAndroid Build Coastguard Worker class const_iterator; 185*6777b538SAndroid Build Coastguard Worker 186*6777b538SAndroid Build Coastguard Worker class iterator { 187*6777b538SAndroid Build Coastguard Worker public: 188*6777b538SAndroid Build Coastguard Worker typedef typename NormalMap::iterator::iterator_category iterator_category; 189*6777b538SAndroid Build Coastguard Worker typedef typename NormalMap::iterator::value_type value_type; 190*6777b538SAndroid Build Coastguard Worker typedef typename NormalMap::iterator::difference_type difference_type; 191*6777b538SAndroid Build Coastguard Worker typedef typename NormalMap::iterator::pointer pointer; 192*6777b538SAndroid Build Coastguard Worker typedef typename NormalMap::iterator::reference reference; 193*6777b538SAndroid Build Coastguard Worker 194*6777b538SAndroid Build Coastguard Worker inline iterator() : array_iter_(nullptr) {} 195*6777b538SAndroid Build Coastguard Worker 196*6777b538SAndroid Build Coastguard Worker inline iterator& operator++() { 197*6777b538SAndroid Build Coastguard Worker if (array_iter_ != nullptr) { 198*6777b538SAndroid Build Coastguard Worker ++array_iter_; 199*6777b538SAndroid Build Coastguard Worker } else { 200*6777b538SAndroid Build Coastguard Worker ++map_iter_; 201*6777b538SAndroid Build Coastguard Worker } 202*6777b538SAndroid Build Coastguard Worker return *this; 203*6777b538SAndroid Build Coastguard Worker } 204*6777b538SAndroid Build Coastguard Worker 205*6777b538SAndroid Build Coastguard Worker inline iterator operator++(int /*unused*/) { 206*6777b538SAndroid Build Coastguard Worker iterator result(*this); 207*6777b538SAndroid Build Coastguard Worker ++(*this); 208*6777b538SAndroid Build Coastguard Worker return result; 209*6777b538SAndroid Build Coastguard Worker } 210*6777b538SAndroid Build Coastguard Worker 211*6777b538SAndroid Build Coastguard Worker inline iterator& operator--() { 212*6777b538SAndroid Build Coastguard Worker if (array_iter_ != nullptr) { 213*6777b538SAndroid Build Coastguard Worker --array_iter_; 214*6777b538SAndroid Build Coastguard Worker } else { 215*6777b538SAndroid Build Coastguard Worker --map_iter_; 216*6777b538SAndroid Build Coastguard Worker } 217*6777b538SAndroid Build Coastguard Worker return *this; 218*6777b538SAndroid Build Coastguard Worker } 219*6777b538SAndroid Build Coastguard Worker 220*6777b538SAndroid Build Coastguard Worker inline iterator operator--(int /*unused*/) { 221*6777b538SAndroid Build Coastguard Worker iterator result(*this); 222*6777b538SAndroid Build Coastguard Worker --(*this); 223*6777b538SAndroid Build Coastguard Worker return result; 224*6777b538SAndroid Build Coastguard Worker } 225*6777b538SAndroid Build Coastguard Worker 226*6777b538SAndroid Build Coastguard Worker inline value_type* operator->() const { 227*6777b538SAndroid Build Coastguard Worker return array_iter_ ? array_iter_.get() : map_iter_.operator->(); 228*6777b538SAndroid Build Coastguard Worker } 229*6777b538SAndroid Build Coastguard Worker 230*6777b538SAndroid Build Coastguard Worker inline value_type& operator*() const { 231*6777b538SAndroid Build Coastguard Worker return array_iter_ ? *array_iter_ : *map_iter_; 232*6777b538SAndroid Build Coastguard Worker } 233*6777b538SAndroid Build Coastguard Worker 234*6777b538SAndroid Build Coastguard Worker inline bool operator==(const iterator& other) const { 235*6777b538SAndroid Build Coastguard Worker if (array_iter_ != nullptr) { 236*6777b538SAndroid Build Coastguard Worker return array_iter_ == other.array_iter_; 237*6777b538SAndroid Build Coastguard Worker } else { 238*6777b538SAndroid Build Coastguard Worker return other.array_iter_ == nullptr && map_iter_ == other.map_iter_; 239*6777b538SAndroid Build Coastguard Worker } 240*6777b538SAndroid Build Coastguard Worker } 241*6777b538SAndroid Build Coastguard Worker 242*6777b538SAndroid Build Coastguard Worker inline bool operator!=(const iterator& other) const { 243*6777b538SAndroid Build Coastguard Worker return !(*this == other); 244*6777b538SAndroid Build Coastguard Worker } 245*6777b538SAndroid Build Coastguard Worker 246*6777b538SAndroid Build Coastguard Worker private: 247*6777b538SAndroid Build Coastguard Worker friend class small_map; 248*6777b538SAndroid Build Coastguard Worker friend class const_iterator; 249*6777b538SAndroid Build Coastguard Worker inline explicit iterator(value_type* init) : array_iter_(init) {} 250*6777b538SAndroid Build Coastguard Worker inline explicit iterator(const typename NormalMap::iterator& init) 251*6777b538SAndroid Build Coastguard Worker : array_iter_(nullptr), map_iter_(init) {} 252*6777b538SAndroid Build Coastguard Worker 253*6777b538SAndroid Build Coastguard Worker raw_ptr<value_type, AllowPtrArithmetic> array_iter_; 254*6777b538SAndroid Build Coastguard Worker typename NormalMap::iterator map_iter_; 255*6777b538SAndroid Build Coastguard Worker }; 256*6777b538SAndroid Build Coastguard Worker 257*6777b538SAndroid Build Coastguard Worker class const_iterator { 258*6777b538SAndroid Build Coastguard Worker public: 259*6777b538SAndroid Build Coastguard Worker typedef typename NormalMap::const_iterator::iterator_category 260*6777b538SAndroid Build Coastguard Worker iterator_category; 261*6777b538SAndroid Build Coastguard Worker typedef typename NormalMap::const_iterator::value_type value_type; 262*6777b538SAndroid Build Coastguard Worker typedef typename NormalMap::const_iterator::difference_type difference_type; 263*6777b538SAndroid Build Coastguard Worker typedef typename NormalMap::const_iterator::pointer pointer; 264*6777b538SAndroid Build Coastguard Worker typedef typename NormalMap::const_iterator::reference reference; 265*6777b538SAndroid Build Coastguard Worker 266*6777b538SAndroid Build Coastguard Worker inline const_iterator() : array_iter_(nullptr) {} 267*6777b538SAndroid Build Coastguard Worker 268*6777b538SAndroid Build Coastguard Worker // Non-explicit constructor lets us convert regular iterators to const 269*6777b538SAndroid Build Coastguard Worker // iterators. 270*6777b538SAndroid Build Coastguard Worker inline const_iterator(const iterator& other) 271*6777b538SAndroid Build Coastguard Worker : array_iter_(other.array_iter_), map_iter_(other.map_iter_) {} 272*6777b538SAndroid Build Coastguard Worker 273*6777b538SAndroid Build Coastguard Worker inline const_iterator& operator++() { 274*6777b538SAndroid Build Coastguard Worker if (array_iter_ != nullptr) { 275*6777b538SAndroid Build Coastguard Worker ++array_iter_; 276*6777b538SAndroid Build Coastguard Worker } else { 277*6777b538SAndroid Build Coastguard Worker ++map_iter_; 278*6777b538SAndroid Build Coastguard Worker } 279*6777b538SAndroid Build Coastguard Worker return *this; 280*6777b538SAndroid Build Coastguard Worker } 281*6777b538SAndroid Build Coastguard Worker 282*6777b538SAndroid Build Coastguard Worker inline const_iterator operator++(int /*unused*/) { 283*6777b538SAndroid Build Coastguard Worker const_iterator result(*this); 284*6777b538SAndroid Build Coastguard Worker ++(*this); 285*6777b538SAndroid Build Coastguard Worker return result; 286*6777b538SAndroid Build Coastguard Worker } 287*6777b538SAndroid Build Coastguard Worker 288*6777b538SAndroid Build Coastguard Worker inline const_iterator& operator--() { 289*6777b538SAndroid Build Coastguard Worker if (array_iter_ != nullptr) { 290*6777b538SAndroid Build Coastguard Worker --array_iter_; 291*6777b538SAndroid Build Coastguard Worker } else { 292*6777b538SAndroid Build Coastguard Worker --map_iter_; 293*6777b538SAndroid Build Coastguard Worker } 294*6777b538SAndroid Build Coastguard Worker return *this; 295*6777b538SAndroid Build Coastguard Worker } 296*6777b538SAndroid Build Coastguard Worker 297*6777b538SAndroid Build Coastguard Worker inline const_iterator operator--(int /*unused*/) { 298*6777b538SAndroid Build Coastguard Worker const_iterator result(*this); 299*6777b538SAndroid Build Coastguard Worker --(*this); 300*6777b538SAndroid Build Coastguard Worker return result; 301*6777b538SAndroid Build Coastguard Worker } 302*6777b538SAndroid Build Coastguard Worker 303*6777b538SAndroid Build Coastguard Worker inline const value_type* operator->() const { 304*6777b538SAndroid Build Coastguard Worker return array_iter_ ? array_iter_.get() : map_iter_.operator->(); 305*6777b538SAndroid Build Coastguard Worker } 306*6777b538SAndroid Build Coastguard Worker 307*6777b538SAndroid Build Coastguard Worker inline const value_type& operator*() const { 308*6777b538SAndroid Build Coastguard Worker return array_iter_ ? *array_iter_ : *map_iter_; 309*6777b538SAndroid Build Coastguard Worker } 310*6777b538SAndroid Build Coastguard Worker 311*6777b538SAndroid Build Coastguard Worker inline bool operator==(const const_iterator& other) const { 312*6777b538SAndroid Build Coastguard Worker if (array_iter_ != nullptr) { 313*6777b538SAndroid Build Coastguard Worker return array_iter_ == other.array_iter_; 314*6777b538SAndroid Build Coastguard Worker } 315*6777b538SAndroid Build Coastguard Worker return other.array_iter_ == nullptr && map_iter_ == other.map_iter_; 316*6777b538SAndroid Build Coastguard Worker } 317*6777b538SAndroid Build Coastguard Worker 318*6777b538SAndroid Build Coastguard Worker inline bool operator!=(const const_iterator& other) const { 319*6777b538SAndroid Build Coastguard Worker return !(*this == other); 320*6777b538SAndroid Build Coastguard Worker } 321*6777b538SAndroid Build Coastguard Worker 322*6777b538SAndroid Build Coastguard Worker private: 323*6777b538SAndroid Build Coastguard Worker friend class small_map; 324*6777b538SAndroid Build Coastguard Worker inline explicit const_iterator(const value_type* init) 325*6777b538SAndroid Build Coastguard Worker : array_iter_(init) {} 326*6777b538SAndroid Build Coastguard Worker inline explicit const_iterator( 327*6777b538SAndroid Build Coastguard Worker const typename NormalMap::const_iterator& init) 328*6777b538SAndroid Build Coastguard Worker : array_iter_(nullptr), map_iter_(init) {} 329*6777b538SAndroid Build Coastguard Worker 330*6777b538SAndroid Build Coastguard Worker raw_ptr<const value_type, AllowPtrArithmetic> array_iter_; 331*6777b538SAndroid Build Coastguard Worker typename NormalMap::const_iterator map_iter_; 332*6777b538SAndroid Build Coastguard Worker }; 333*6777b538SAndroid Build Coastguard Worker 334*6777b538SAndroid Build Coastguard Worker iterator find(const key_type& key) { 335*6777b538SAndroid Build Coastguard Worker key_equal compare; 336*6777b538SAndroid Build Coastguard Worker 337*6777b538SAndroid Build Coastguard Worker if (UsingFullMap()) { 338*6777b538SAndroid Build Coastguard Worker return iterator(map()->find(key)); 339*6777b538SAndroid Build Coastguard Worker } 340*6777b538SAndroid Build Coastguard Worker 341*6777b538SAndroid Build Coastguard Worker for (size_t i = 0; i < size_; ++i) { 342*6777b538SAndroid Build Coastguard Worker if (compare(array_[i].first, key)) { 343*6777b538SAndroid Build Coastguard Worker return iterator(array_ + i); 344*6777b538SAndroid Build Coastguard Worker } 345*6777b538SAndroid Build Coastguard Worker } 346*6777b538SAndroid Build Coastguard Worker return iterator(array_ + size_); 347*6777b538SAndroid Build Coastguard Worker } 348*6777b538SAndroid Build Coastguard Worker 349*6777b538SAndroid Build Coastguard Worker const_iterator find(const key_type& key) const { 350*6777b538SAndroid Build Coastguard Worker key_equal compare; 351*6777b538SAndroid Build Coastguard Worker 352*6777b538SAndroid Build Coastguard Worker if (UsingFullMap()) { 353*6777b538SAndroid Build Coastguard Worker return const_iterator(map()->find(key)); 354*6777b538SAndroid Build Coastguard Worker } 355*6777b538SAndroid Build Coastguard Worker 356*6777b538SAndroid Build Coastguard Worker for (size_t i = 0; i < size_; ++i) { 357*6777b538SAndroid Build Coastguard Worker if (compare(array_[i].first, key)) { 358*6777b538SAndroid Build Coastguard Worker return const_iterator(array_ + i); 359*6777b538SAndroid Build Coastguard Worker } 360*6777b538SAndroid Build Coastguard Worker } 361*6777b538SAndroid Build Coastguard Worker return const_iterator(array_ + size_); 362*6777b538SAndroid Build Coastguard Worker } 363*6777b538SAndroid Build Coastguard Worker 364*6777b538SAndroid Build Coastguard Worker // Invalidates iterators. 365*6777b538SAndroid Build Coastguard Worker data_type& operator[](const key_type& key) { 366*6777b538SAndroid Build Coastguard Worker key_equal compare; 367*6777b538SAndroid Build Coastguard Worker 368*6777b538SAndroid Build Coastguard Worker if (UsingFullMap()) { 369*6777b538SAndroid Build Coastguard Worker return map_[key]; 370*6777b538SAndroid Build Coastguard Worker } 371*6777b538SAndroid Build Coastguard Worker 372*6777b538SAndroid Build Coastguard Worker // Search backwards to favor recently-added elements. 373*6777b538SAndroid Build Coastguard Worker for (size_t i = size_; i > 0; --i) { 374*6777b538SAndroid Build Coastguard Worker const size_t index = i - 1; 375*6777b538SAndroid Build Coastguard Worker if (compare(array_[index].first, key)) { 376*6777b538SAndroid Build Coastguard Worker return array_[index].second; 377*6777b538SAndroid Build Coastguard Worker } 378*6777b538SAndroid Build Coastguard Worker } 379*6777b538SAndroid Build Coastguard Worker 380*6777b538SAndroid Build Coastguard Worker if (size_ == kArraySize) { 381*6777b538SAndroid Build Coastguard Worker ConvertToRealMap(); 382*6777b538SAndroid Build Coastguard Worker return map_[key]; 383*6777b538SAndroid Build Coastguard Worker } 384*6777b538SAndroid Build Coastguard Worker 385*6777b538SAndroid Build Coastguard Worker DCHECK(size_ < kArraySize); 386*6777b538SAndroid Build Coastguard Worker new (&array_[size_]) value_type(key, data_type()); 387*6777b538SAndroid Build Coastguard Worker return array_[size_++].second; 388*6777b538SAndroid Build Coastguard Worker } 389*6777b538SAndroid Build Coastguard Worker 390*6777b538SAndroid Build Coastguard Worker // Invalidates iterators. 391*6777b538SAndroid Build Coastguard Worker std::pair<iterator, bool> insert(const value_type& x) { 392*6777b538SAndroid Build Coastguard Worker key_equal compare; 393*6777b538SAndroid Build Coastguard Worker 394*6777b538SAndroid Build Coastguard Worker if (UsingFullMap()) { 395*6777b538SAndroid Build Coastguard Worker std::pair<typename NormalMap::iterator, bool> ret = map_.insert(x); 396*6777b538SAndroid Build Coastguard Worker return std::make_pair(iterator(ret.first), ret.second); 397*6777b538SAndroid Build Coastguard Worker } 398*6777b538SAndroid Build Coastguard Worker 399*6777b538SAndroid Build Coastguard Worker for (size_t i = 0; i < size_; ++i) { 400*6777b538SAndroid Build Coastguard Worker if (compare(array_[i].first, x.first)) { 401*6777b538SAndroid Build Coastguard Worker return std::make_pair(iterator(array_ + i), false); 402*6777b538SAndroid Build Coastguard Worker } 403*6777b538SAndroid Build Coastguard Worker } 404*6777b538SAndroid Build Coastguard Worker 405*6777b538SAndroid Build Coastguard Worker if (size_ == kArraySize) { 406*6777b538SAndroid Build Coastguard Worker ConvertToRealMap(); // Invalidates all iterators! 407*6777b538SAndroid Build Coastguard Worker std::pair<typename NormalMap::iterator, bool> ret = map_.insert(x); 408*6777b538SAndroid Build Coastguard Worker return std::make_pair(iterator(ret.first), ret.second); 409*6777b538SAndroid Build Coastguard Worker } 410*6777b538SAndroid Build Coastguard Worker 411*6777b538SAndroid Build Coastguard Worker DCHECK(size_ < kArraySize); 412*6777b538SAndroid Build Coastguard Worker new (&array_[size_]) value_type(x); 413*6777b538SAndroid Build Coastguard Worker return std::make_pair(iterator(array_ + size_++), true); 414*6777b538SAndroid Build Coastguard Worker } 415*6777b538SAndroid Build Coastguard Worker 416*6777b538SAndroid Build Coastguard Worker // Invalidates iterators. 417*6777b538SAndroid Build Coastguard Worker template <class InputIterator> 418*6777b538SAndroid Build Coastguard Worker void insert(InputIterator f, InputIterator l) { 419*6777b538SAndroid Build Coastguard Worker while (f != l) { 420*6777b538SAndroid Build Coastguard Worker insert(*f); 421*6777b538SAndroid Build Coastguard Worker ++f; 422*6777b538SAndroid Build Coastguard Worker } 423*6777b538SAndroid Build Coastguard Worker } 424*6777b538SAndroid Build Coastguard Worker 425*6777b538SAndroid Build Coastguard Worker // Invalidates iterators. 426*6777b538SAndroid Build Coastguard Worker template <typename... Args> 427*6777b538SAndroid Build Coastguard Worker std::pair<iterator, bool> emplace(Args&&... args) { 428*6777b538SAndroid Build Coastguard Worker key_equal compare; 429*6777b538SAndroid Build Coastguard Worker 430*6777b538SAndroid Build Coastguard Worker if (UsingFullMap()) { 431*6777b538SAndroid Build Coastguard Worker std::pair<typename NormalMap::iterator, bool> ret = 432*6777b538SAndroid Build Coastguard Worker map_.emplace(std::forward<Args>(args)...); 433*6777b538SAndroid Build Coastguard Worker return std::make_pair(iterator(ret.first), ret.second); 434*6777b538SAndroid Build Coastguard Worker } 435*6777b538SAndroid Build Coastguard Worker 436*6777b538SAndroid Build Coastguard Worker value_type x(std::forward<Args>(args)...); 437*6777b538SAndroid Build Coastguard Worker for (size_t i = 0; i < size_; ++i) { 438*6777b538SAndroid Build Coastguard Worker if (compare(array_[i].first, x.first)) { 439*6777b538SAndroid Build Coastguard Worker return std::make_pair(iterator(array_ + i), false); 440*6777b538SAndroid Build Coastguard Worker } 441*6777b538SAndroid Build Coastguard Worker } 442*6777b538SAndroid Build Coastguard Worker 443*6777b538SAndroid Build Coastguard Worker if (size_ == kArraySize) { 444*6777b538SAndroid Build Coastguard Worker ConvertToRealMap(); // Invalidates all iterators! 445*6777b538SAndroid Build Coastguard Worker std::pair<typename NormalMap::iterator, bool> ret = 446*6777b538SAndroid Build Coastguard Worker map_.emplace(std::move(x)); 447*6777b538SAndroid Build Coastguard Worker return std::make_pair(iterator(ret.first), ret.second); 448*6777b538SAndroid Build Coastguard Worker } 449*6777b538SAndroid Build Coastguard Worker 450*6777b538SAndroid Build Coastguard Worker DCHECK(size_ < kArraySize); 451*6777b538SAndroid Build Coastguard Worker new (&array_[size_]) value_type(std::move(x)); 452*6777b538SAndroid Build Coastguard Worker return std::make_pair(iterator(array_ + size_++), true); 453*6777b538SAndroid Build Coastguard Worker } 454*6777b538SAndroid Build Coastguard Worker 455*6777b538SAndroid Build Coastguard Worker iterator begin() { 456*6777b538SAndroid Build Coastguard Worker return UsingFullMap() ? iterator(map_.begin()) : iterator(array_); 457*6777b538SAndroid Build Coastguard Worker } 458*6777b538SAndroid Build Coastguard Worker 459*6777b538SAndroid Build Coastguard Worker const_iterator begin() const { 460*6777b538SAndroid Build Coastguard Worker return UsingFullMap() ? const_iterator(map_.begin()) 461*6777b538SAndroid Build Coastguard Worker : const_iterator(array_); 462*6777b538SAndroid Build Coastguard Worker } 463*6777b538SAndroid Build Coastguard Worker 464*6777b538SAndroid Build Coastguard Worker iterator end() { 465*6777b538SAndroid Build Coastguard Worker return UsingFullMap() ? iterator(map_.end()) : iterator(array_ + size_); 466*6777b538SAndroid Build Coastguard Worker } 467*6777b538SAndroid Build Coastguard Worker 468*6777b538SAndroid Build Coastguard Worker const_iterator end() const { 469*6777b538SAndroid Build Coastguard Worker return UsingFullMap() ? const_iterator(map_.end()) 470*6777b538SAndroid Build Coastguard Worker : const_iterator(array_ + size_); 471*6777b538SAndroid Build Coastguard Worker } 472*6777b538SAndroid Build Coastguard Worker 473*6777b538SAndroid Build Coastguard Worker void clear() { 474*6777b538SAndroid Build Coastguard Worker if (UsingFullMap()) { 475*6777b538SAndroid Build Coastguard Worker map_.~NormalMap(); 476*6777b538SAndroid Build Coastguard Worker } else { 477*6777b538SAndroid Build Coastguard Worker for (size_t i = 0; i < size_; ++i) { 478*6777b538SAndroid Build Coastguard Worker array_[i].~value_type(); 479*6777b538SAndroid Build Coastguard Worker } 480*6777b538SAndroid Build Coastguard Worker } 481*6777b538SAndroid Build Coastguard Worker size_ = 0; 482*6777b538SAndroid Build Coastguard Worker } 483*6777b538SAndroid Build Coastguard Worker 484*6777b538SAndroid Build Coastguard Worker // Invalidates iterators. Returns iterator following the last removed element. 485*6777b538SAndroid Build Coastguard Worker iterator erase(const iterator& position) { 486*6777b538SAndroid Build Coastguard Worker if (UsingFullMap()) { 487*6777b538SAndroid Build Coastguard Worker return iterator(map_.erase(position.map_iter_)); 488*6777b538SAndroid Build Coastguard Worker } 489*6777b538SAndroid Build Coastguard Worker 490*6777b538SAndroid Build Coastguard Worker size_t i = static_cast<size_t>(position.array_iter_ - array_); 491*6777b538SAndroid Build Coastguard Worker // TODO(crbug.com/817982): When we have a checked iterator, this CHECK might 492*6777b538SAndroid Build Coastguard Worker // not be necessary. 493*6777b538SAndroid Build Coastguard Worker CHECK_LE(i, size_); 494*6777b538SAndroid Build Coastguard Worker array_[i].~value_type(); 495*6777b538SAndroid Build Coastguard Worker --size_; 496*6777b538SAndroid Build Coastguard Worker if (i != size_) { 497*6777b538SAndroid Build Coastguard Worker new (&array_[i]) value_type(std::move(array_[size_])); 498*6777b538SAndroid Build Coastguard Worker array_[size_].~value_type(); 499*6777b538SAndroid Build Coastguard Worker return iterator(array_ + i); 500*6777b538SAndroid Build Coastguard Worker } 501*6777b538SAndroid Build Coastguard Worker return end(); 502*6777b538SAndroid Build Coastguard Worker } 503*6777b538SAndroid Build Coastguard Worker 504*6777b538SAndroid Build Coastguard Worker size_t erase(const key_type& key) { 505*6777b538SAndroid Build Coastguard Worker iterator iter = find(key); 506*6777b538SAndroid Build Coastguard Worker if (iter == end()) { 507*6777b538SAndroid Build Coastguard Worker return 0; 508*6777b538SAndroid Build Coastguard Worker } 509*6777b538SAndroid Build Coastguard Worker erase(iter); 510*6777b538SAndroid Build Coastguard Worker return 1; 511*6777b538SAndroid Build Coastguard Worker } 512*6777b538SAndroid Build Coastguard Worker 513*6777b538SAndroid Build Coastguard Worker size_t count(const key_type& key) const { 514*6777b538SAndroid Build Coastguard Worker return (find(key) == end()) ? 0 : 1; 515*6777b538SAndroid Build Coastguard Worker } 516*6777b538SAndroid Build Coastguard Worker 517*6777b538SAndroid Build Coastguard Worker size_t size() const { return UsingFullMap() ? map_.size() : size_; } 518*6777b538SAndroid Build Coastguard Worker 519*6777b538SAndroid Build Coastguard Worker bool empty() const { return UsingFullMap() ? map_.empty() : size_ == 0; } 520*6777b538SAndroid Build Coastguard Worker 521*6777b538SAndroid Build Coastguard Worker // Returns true if we have fallen back to using the underlying map 522*6777b538SAndroid Build Coastguard Worker // representation. 523*6777b538SAndroid Build Coastguard Worker bool UsingFullMap() const { return size_ == kUsingFullMapSentinel; } 524*6777b538SAndroid Build Coastguard Worker 525*6777b538SAndroid Build Coastguard Worker inline NormalMap* map() { 526*6777b538SAndroid Build Coastguard Worker CHECK(UsingFullMap()); 527*6777b538SAndroid Build Coastguard Worker return &map_; 528*6777b538SAndroid Build Coastguard Worker } 529*6777b538SAndroid Build Coastguard Worker 530*6777b538SAndroid Build Coastguard Worker inline const NormalMap* map() const { 531*6777b538SAndroid Build Coastguard Worker CHECK(UsingFullMap()); 532*6777b538SAndroid Build Coastguard Worker return &map_; 533*6777b538SAndroid Build Coastguard Worker } 534*6777b538SAndroid Build Coastguard Worker 535*6777b538SAndroid Build Coastguard Worker private: 536*6777b538SAndroid Build Coastguard Worker // When `size_ == kUsingFullMapSentinel`, we have switched storage strategies 537*6777b538SAndroid Build Coastguard Worker // from `array_[kArraySize] to `NormalMap map_`. See ConvertToRealMap and 538*6777b538SAndroid Build Coastguard Worker // UsingFullMap. 539*6777b538SAndroid Build Coastguard Worker size_t size_; 540*6777b538SAndroid Build Coastguard Worker 541*6777b538SAndroid Build Coastguard Worker MapInit functor_; 542*6777b538SAndroid Build Coastguard Worker 543*6777b538SAndroid Build Coastguard Worker // We want to call constructors and destructors manually, but we don't want 544*6777b538SAndroid Build Coastguard Worker // to allocate and deallocate the memory used for them separately. Since 545*6777b538SAndroid Build Coastguard Worker // array_ and map_ are mutually exclusive, we'll put them in a union. 546*6777b538SAndroid Build Coastguard Worker union { 547*6777b538SAndroid Build Coastguard Worker value_type array_[kArraySize]; 548*6777b538SAndroid Build Coastguard Worker NormalMap map_; 549*6777b538SAndroid Build Coastguard Worker }; 550*6777b538SAndroid Build Coastguard Worker 551*6777b538SAndroid Build Coastguard Worker void ConvertToRealMap() { 552*6777b538SAndroid Build Coastguard Worker // Storage for the elements in the temporary array. This is intentionally 553*6777b538SAndroid Build Coastguard Worker // declared as a union to avoid having to default-construct |kArraySize| 554*6777b538SAndroid Build Coastguard Worker // elements, only to move construct over them in the initial loop. 555*6777b538SAndroid Build Coastguard Worker union Storage { 556*6777b538SAndroid Build Coastguard Worker Storage() {} 557*6777b538SAndroid Build Coastguard Worker ~Storage() {} 558*6777b538SAndroid Build Coastguard Worker value_type array[kArraySize]; 559*6777b538SAndroid Build Coastguard Worker } temp; 560*6777b538SAndroid Build Coastguard Worker 561*6777b538SAndroid Build Coastguard Worker // Move the current elements into a temporary array. 562*6777b538SAndroid Build Coastguard Worker for (size_t i = 0; i < kArraySize; ++i) { 563*6777b538SAndroid Build Coastguard Worker new (&temp.array[i]) value_type(std::move(array_[i])); 564*6777b538SAndroid Build Coastguard Worker array_[i].~value_type(); 565*6777b538SAndroid Build Coastguard Worker } 566*6777b538SAndroid Build Coastguard Worker 567*6777b538SAndroid Build Coastguard Worker // Initialize the map. 568*6777b538SAndroid Build Coastguard Worker size_ = kUsingFullMapSentinel; 569*6777b538SAndroid Build Coastguard Worker functor_(&map_); 570*6777b538SAndroid Build Coastguard Worker 571*6777b538SAndroid Build Coastguard Worker // Insert elements into it. 572*6777b538SAndroid Build Coastguard Worker for (size_t i = 0; i < kArraySize; ++i) { 573*6777b538SAndroid Build Coastguard Worker map_.insert(std::move(temp.array[i])); 574*6777b538SAndroid Build Coastguard Worker temp.array[i].~value_type(); 575*6777b538SAndroid Build Coastguard Worker } 576*6777b538SAndroid Build Coastguard Worker } 577*6777b538SAndroid Build Coastguard Worker 578*6777b538SAndroid Build Coastguard Worker // Helpers for constructors and destructors. 579*6777b538SAndroid Build Coastguard Worker void InitFrom(const small_map& src) { 580*6777b538SAndroid Build Coastguard Worker functor_ = src.functor_; 581*6777b538SAndroid Build Coastguard Worker size_ = src.size_; 582*6777b538SAndroid Build Coastguard Worker if (src.UsingFullMap()) { 583*6777b538SAndroid Build Coastguard Worker functor_(&map_); 584*6777b538SAndroid Build Coastguard Worker map_ = src.map_; 585*6777b538SAndroid Build Coastguard Worker } else { 586*6777b538SAndroid Build Coastguard Worker for (size_t i = 0; i < size_; ++i) { 587*6777b538SAndroid Build Coastguard Worker new (&array_[i]) value_type(src.array_[i]); 588*6777b538SAndroid Build Coastguard Worker } 589*6777b538SAndroid Build Coastguard Worker } 590*6777b538SAndroid Build Coastguard Worker } 591*6777b538SAndroid Build Coastguard Worker 592*6777b538SAndroid Build Coastguard Worker void Destroy() { 593*6777b538SAndroid Build Coastguard Worker if (UsingFullMap()) { 594*6777b538SAndroid Build Coastguard Worker map_.~NormalMap(); 595*6777b538SAndroid Build Coastguard Worker } else { 596*6777b538SAndroid Build Coastguard Worker for (size_t i = 0; i < size_; ++i) { 597*6777b538SAndroid Build Coastguard Worker array_[i].~value_type(); 598*6777b538SAndroid Build Coastguard Worker } 599*6777b538SAndroid Build Coastguard Worker } 600*6777b538SAndroid Build Coastguard Worker } 601*6777b538SAndroid Build Coastguard Worker }; 602*6777b538SAndroid Build Coastguard Worker 603*6777b538SAndroid Build Coastguard Worker } // namespace base 604*6777b538SAndroid Build Coastguard Worker 605*6777b538SAndroid Build Coastguard Worker #endif // BASE_CONTAINERS_SMALL_MAP_H_ 606