xref: /aosp_15_r20/external/cronet/base/containers/small_map.h (revision 6777b5387eb2ff775bb5750e3f5d96f37fb7352b)
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