xref: /aosp_15_r20/external/google-breakpad/src/common/simple_string_dictionary.h (revision 9712c20fc9bbfbac4935993a2ca0b3958c5adad2)
1*9712c20fSFrederick Mayle // Copyright 2007 Google LLC
2*9712c20fSFrederick Mayle //
3*9712c20fSFrederick Mayle // Redistribution and use in source and binary forms, with or without
4*9712c20fSFrederick Mayle // modification, are permitted provided that the following conditions are
5*9712c20fSFrederick Mayle // met:
6*9712c20fSFrederick Mayle //
7*9712c20fSFrederick Mayle //     * Redistributions of source code must retain the above copyright
8*9712c20fSFrederick Mayle // notice, this list of conditions and the following disclaimer.
9*9712c20fSFrederick Mayle //     * Redistributions in binary form must reproduce the above
10*9712c20fSFrederick Mayle // copyright notice, this list of conditions and the following disclaimer
11*9712c20fSFrederick Mayle // in the documentation and/or other materials provided with the
12*9712c20fSFrederick Mayle // distribution.
13*9712c20fSFrederick Mayle //     * Neither the name of Google LLC nor the names of its
14*9712c20fSFrederick Mayle // contributors may be used to endorse or promote products derived from
15*9712c20fSFrederick Mayle // this software without specific prior written permission.
16*9712c20fSFrederick Mayle //
17*9712c20fSFrederick Mayle // THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
18*9712c20fSFrederick Mayle // "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
19*9712c20fSFrederick Mayle // LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
20*9712c20fSFrederick Mayle // A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
21*9712c20fSFrederick Mayle // OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
22*9712c20fSFrederick Mayle // SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
23*9712c20fSFrederick Mayle // LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
24*9712c20fSFrederick Mayle // DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
25*9712c20fSFrederick Mayle // THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
26*9712c20fSFrederick Mayle // (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
27*9712c20fSFrederick Mayle // OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
28*9712c20fSFrederick Mayle 
29*9712c20fSFrederick Mayle #ifndef COMMON_SIMPLE_STRING_DICTIONARY_H_
30*9712c20fSFrederick Mayle #define COMMON_SIMPLE_STRING_DICTIONARY_H_
31*9712c20fSFrederick Mayle 
32*9712c20fSFrederick Mayle #include <assert.h>
33*9712c20fSFrederick Mayle #include <string.h>
34*9712c20fSFrederick Mayle 
35*9712c20fSFrederick Mayle namespace google_breakpad {
36*9712c20fSFrederick Mayle 
37*9712c20fSFrederick Mayle // Opaque type for the serialized representation of a NonAllocatingMap. One is
38*9712c20fSFrederick Mayle // created in NonAllocatingMap::Serialize and can be deserialized using one of
39*9712c20fSFrederick Mayle // the constructors.
40*9712c20fSFrederick Mayle struct SerializedNonAllocatingMap;
41*9712c20fSFrederick Mayle 
42*9712c20fSFrederick Mayle // NonAllocatingMap is an implementation of a map/dictionary collection that
43*9712c20fSFrederick Mayle // uses a fixed amount of storage, so that it does not perform any dynamic
44*9712c20fSFrederick Mayle // allocations for its operations.
45*9712c20fSFrederick Mayle //
46*9712c20fSFrederick Mayle // The actual map storage (the Entry) is guaranteed to be POD, so that it can
47*9712c20fSFrederick Mayle // be transmitted over various IPC mechanisms.
48*9712c20fSFrederick Mayle //
49*9712c20fSFrederick Mayle // The template parameters control the amount of storage used for the key,
50*9712c20fSFrederick Mayle // value, and map. The KeySize and ValueSize are measured in bytes, not glyphs,
51*9712c20fSFrederick Mayle // and includes space for a \0 byte. This gives space for KeySize-1 and
52*9712c20fSFrederick Mayle // ValueSize-1 characters in an entry. NumEntries is the total number of
53*9712c20fSFrederick Mayle // entries that will fit in the map.
54*9712c20fSFrederick Mayle template <size_t KeySize, size_t ValueSize, size_t NumEntries>
55*9712c20fSFrederick Mayle class NonAllocatingMap {
56*9712c20fSFrederick Mayle  public:
57*9712c20fSFrederick Mayle   // Constant and publicly accessible versions of the template parameters.
58*9712c20fSFrederick Mayle   static const size_t key_size = KeySize;
59*9712c20fSFrederick Mayle   static const size_t value_size = ValueSize;
60*9712c20fSFrederick Mayle   static const size_t num_entries = NumEntries;
61*9712c20fSFrederick Mayle 
62*9712c20fSFrederick Mayle   // An Entry object is a single entry in the map. If the key is a 0-length
63*9712c20fSFrederick Mayle   // NUL-terminated string, the entry is empty.
64*9712c20fSFrederick Mayle   struct Entry {
65*9712c20fSFrederick Mayle     char key[KeySize];
66*9712c20fSFrederick Mayle     char value[ValueSize];
67*9712c20fSFrederick Mayle 
is_activeEntry68*9712c20fSFrederick Mayle     bool is_active() const {
69*9712c20fSFrederick Mayle       return key[0] != '\0';
70*9712c20fSFrederick Mayle     }
71*9712c20fSFrederick Mayle   };
72*9712c20fSFrederick Mayle 
73*9712c20fSFrederick Mayle   // An Iterator can be used to iterate over all the active entries in a
74*9712c20fSFrederick Mayle   // NonAllocatingMap.
75*9712c20fSFrederick Mayle   class Iterator {
76*9712c20fSFrederick Mayle    public:
Iterator(const NonAllocatingMap & map)77*9712c20fSFrederick Mayle     explicit Iterator(const NonAllocatingMap& map)
78*9712c20fSFrederick Mayle         : map_(map),
79*9712c20fSFrederick Mayle           current_(0) {
80*9712c20fSFrederick Mayle     }
81*9712c20fSFrederick Mayle     Iterator(const Iterator&) = delete;
82*9712c20fSFrederick Mayle     void operator=(const Iterator&) = delete;
83*9712c20fSFrederick Mayle 
84*9712c20fSFrederick Mayle     // Returns the next entry in the map, or NULL if at the end of the
85*9712c20fSFrederick Mayle     // collection.
Next()86*9712c20fSFrederick Mayle     const Entry* Next() {
87*9712c20fSFrederick Mayle       while (current_ < map_.num_entries) {
88*9712c20fSFrederick Mayle         const Entry* entry = &map_.entries_[current_++];
89*9712c20fSFrederick Mayle         if (entry->is_active()) {
90*9712c20fSFrederick Mayle           return entry;
91*9712c20fSFrederick Mayle         }
92*9712c20fSFrederick Mayle       }
93*9712c20fSFrederick Mayle       return nullptr;
94*9712c20fSFrederick Mayle     }
95*9712c20fSFrederick Mayle 
96*9712c20fSFrederick Mayle    private:
97*9712c20fSFrederick Mayle     const NonAllocatingMap& map_;
98*9712c20fSFrederick Mayle     size_t current_;
99*9712c20fSFrederick Mayle   };
100*9712c20fSFrederick Mayle 
NonAllocatingMap()101*9712c20fSFrederick Mayle   NonAllocatingMap() : entries_() {
102*9712c20fSFrederick Mayle   }
103*9712c20fSFrederick Mayle 
NonAllocatingMap(const NonAllocatingMap & other)104*9712c20fSFrederick Mayle   NonAllocatingMap(const NonAllocatingMap& other) {
105*9712c20fSFrederick Mayle     *this = other;
106*9712c20fSFrederick Mayle   }
107*9712c20fSFrederick Mayle 
108*9712c20fSFrederick Mayle   NonAllocatingMap& operator=(const NonAllocatingMap& other) {
109*9712c20fSFrederick Mayle     assert(other.key_size == key_size);
110*9712c20fSFrederick Mayle     assert(other.value_size == value_size);
111*9712c20fSFrederick Mayle     assert(other.num_entries == num_entries);
112*9712c20fSFrederick Mayle     if (other.key_size == key_size && other.value_size == value_size &&
113*9712c20fSFrederick Mayle         other.num_entries == num_entries) {
114*9712c20fSFrederick Mayle       memcpy(entries_, other.entries_, sizeof(entries_));
115*9712c20fSFrederick Mayle     }
116*9712c20fSFrederick Mayle     return *this;
117*9712c20fSFrederick Mayle   }
118*9712c20fSFrederick Mayle 
119*9712c20fSFrederick Mayle   // Constructs a map from its serialized form. |map| should be the out
120*9712c20fSFrederick Mayle   // parameter from Serialize() and |size| should be its return value.
NonAllocatingMap(const SerializedNonAllocatingMap * map,size_t size)121*9712c20fSFrederick Mayle   NonAllocatingMap(const SerializedNonAllocatingMap* map, size_t size) {
122*9712c20fSFrederick Mayle     assert(size == sizeof(entries_));
123*9712c20fSFrederick Mayle     if (size == sizeof(entries_)) {
124*9712c20fSFrederick Mayle       memcpy(entries_, map, size);
125*9712c20fSFrederick Mayle     }
126*9712c20fSFrederick Mayle   }
127*9712c20fSFrederick Mayle 
128*9712c20fSFrederick Mayle   // Returns the number of active key/value pairs. The upper limit for this
129*9712c20fSFrederick Mayle   // is NumEntries.
GetCount()130*9712c20fSFrederick Mayle   size_t GetCount() const {
131*9712c20fSFrederick Mayle     size_t count = 0;
132*9712c20fSFrederick Mayle     for (size_t i = 0; i < num_entries; ++i) {
133*9712c20fSFrederick Mayle       if (entries_[i].is_active()) {
134*9712c20fSFrederick Mayle         ++count;
135*9712c20fSFrederick Mayle       }
136*9712c20fSFrederick Mayle     }
137*9712c20fSFrederick Mayle     return count;
138*9712c20fSFrederick Mayle   }
139*9712c20fSFrederick Mayle 
140*9712c20fSFrederick Mayle   // Given |key|, returns its corresponding |value|. |key| must not be NULL. If
141*9712c20fSFrederick Mayle   // the key is not found, NULL is returned.
GetValueForKey(const char * key)142*9712c20fSFrederick Mayle   const char* GetValueForKey(const char* key) const {
143*9712c20fSFrederick Mayle     assert(key);
144*9712c20fSFrederick Mayle     if (!key)
145*9712c20fSFrederick Mayle       return NULL;
146*9712c20fSFrederick Mayle 
147*9712c20fSFrederick Mayle     size_t index = GetEntryIndexForKey(key);
148*9712c20fSFrederick Mayle     if (index == num_entries)
149*9712c20fSFrederick Mayle       return NULL;
150*9712c20fSFrederick Mayle 
151*9712c20fSFrederick Mayle     return entries_[index].value;
152*9712c20fSFrederick Mayle   }
153*9712c20fSFrederick Mayle 
154*9712c20fSFrederick Mayle   // Stores |value| into |key|, replacing the existing value if |key| is
155*9712c20fSFrederick Mayle   // already present. |key| must not be NULL. If |value| is NULL, the key is
156*9712c20fSFrederick Mayle   // removed from the map. If there is no more space in the map, then the
157*9712c20fSFrederick Mayle   // operation silently fails. Returns an index into the map that can be used
158*9712c20fSFrederick Mayle   // to quickly access the entry, or |num_entries| on failure or when clearing
159*9712c20fSFrederick Mayle   // a key with a null value.
SetKeyValue(const char * key,const char * value)160*9712c20fSFrederick Mayle   size_t SetKeyValue(const char* key, const char* value) {
161*9712c20fSFrederick Mayle     if (!value) {
162*9712c20fSFrederick Mayle       RemoveKey(key);
163*9712c20fSFrederick Mayle       return num_entries;
164*9712c20fSFrederick Mayle     }
165*9712c20fSFrederick Mayle 
166*9712c20fSFrederick Mayle     assert(key);
167*9712c20fSFrederick Mayle     if (!key)
168*9712c20fSFrederick Mayle       return num_entries;
169*9712c20fSFrederick Mayle 
170*9712c20fSFrederick Mayle     // Key must not be an empty string.
171*9712c20fSFrederick Mayle     assert(key[0] != '\0');
172*9712c20fSFrederick Mayle     if (key[0] == '\0')
173*9712c20fSFrederick Mayle       return num_entries;
174*9712c20fSFrederick Mayle 
175*9712c20fSFrederick Mayle     size_t entry_index = GetEntryIndexForKey(key);
176*9712c20fSFrederick Mayle 
177*9712c20fSFrederick Mayle     // If it does not yet exist, attempt to insert it.
178*9712c20fSFrederick Mayle     if (entry_index == num_entries) {
179*9712c20fSFrederick Mayle       for (size_t i = 0; i < num_entries; ++i) {
180*9712c20fSFrederick Mayle         if (!entries_[i].is_active()) {
181*9712c20fSFrederick Mayle           entry_index = i;
182*9712c20fSFrederick Mayle           Entry* entry = &entries_[i];
183*9712c20fSFrederick Mayle 
184*9712c20fSFrederick Mayle           strncpy(entry->key, key, key_size);
185*9712c20fSFrederick Mayle           entry->key[key_size - 1] = '\0';
186*9712c20fSFrederick Mayle 
187*9712c20fSFrederick Mayle           break;
188*9712c20fSFrederick Mayle         }
189*9712c20fSFrederick Mayle       }
190*9712c20fSFrederick Mayle     }
191*9712c20fSFrederick Mayle 
192*9712c20fSFrederick Mayle     // If the map is out of space, entry will be NULL.
193*9712c20fSFrederick Mayle     if (entry_index == num_entries)
194*9712c20fSFrederick Mayle       return num_entries;
195*9712c20fSFrederick Mayle 
196*9712c20fSFrederick Mayle #ifndef NDEBUG
197*9712c20fSFrederick Mayle     // Sanity check that the key only appears once.
198*9712c20fSFrederick Mayle     int count = 0;
199*9712c20fSFrederick Mayle     for (size_t i = 0; i < num_entries; ++i) {
200*9712c20fSFrederick Mayle       if (strncmp(entries_[i].key, key, key_size) == 0)
201*9712c20fSFrederick Mayle         ++count;
202*9712c20fSFrederick Mayle     }
203*9712c20fSFrederick Mayle     assert(count == 1);
204*9712c20fSFrederick Mayle #endif
205*9712c20fSFrederick Mayle 
206*9712c20fSFrederick Mayle     strncpy(entries_[entry_index].value, value, value_size);
207*9712c20fSFrederick Mayle     entries_[entry_index].value[value_size - 1] = '\0';
208*9712c20fSFrederick Mayle 
209*9712c20fSFrederick Mayle     return entry_index;
210*9712c20fSFrederick Mayle   }
211*9712c20fSFrederick Mayle 
212*9712c20fSFrederick Mayle   // Sets a value for a key that has already been set with SetKeyValue(), using
213*9712c20fSFrederick Mayle   // the index returned from that function.
SetValueAtIndex(size_t index,const char * value)214*9712c20fSFrederick Mayle   void SetValueAtIndex(size_t index, const char* value) {
215*9712c20fSFrederick Mayle     assert(index < num_entries);
216*9712c20fSFrederick Mayle     if (index >= num_entries)
217*9712c20fSFrederick Mayle       return;
218*9712c20fSFrederick Mayle 
219*9712c20fSFrederick Mayle     Entry* entry = &entries_[index];
220*9712c20fSFrederick Mayle     assert(entry->key[0] != '\0');
221*9712c20fSFrederick Mayle 
222*9712c20fSFrederick Mayle     strncpy(entry->value, value, value_size);
223*9712c20fSFrederick Mayle     entry->value[value_size - 1] = '\0';
224*9712c20fSFrederick Mayle   }
225*9712c20fSFrederick Mayle 
226*9712c20fSFrederick Mayle   // Given |key|, removes any associated value. |key| must not be NULL. If
227*9712c20fSFrederick Mayle   // the key is not found, this is a noop. This invalidates the index
228*9712c20fSFrederick Mayle   // returned by SetKeyValue().
RemoveKey(const char * key)229*9712c20fSFrederick Mayle   bool RemoveKey(const char* key) {
230*9712c20fSFrederick Mayle     assert(key);
231*9712c20fSFrederick Mayle     if (!key)
232*9712c20fSFrederick Mayle       return false;
233*9712c20fSFrederick Mayle 
234*9712c20fSFrederick Mayle     return RemoveAtIndex(GetEntryIndexForKey(key));
235*9712c20fSFrederick Mayle   }
236*9712c20fSFrederick Mayle 
237*9712c20fSFrederick Mayle   // Removes a value and key using an index that was returned from
238*9712c20fSFrederick Mayle   // SetKeyValue(). After a call to this function, the index is invalidated.
RemoveAtIndex(size_t index)239*9712c20fSFrederick Mayle   bool RemoveAtIndex(size_t index) {
240*9712c20fSFrederick Mayle     if (index >= num_entries)
241*9712c20fSFrederick Mayle       return false;
242*9712c20fSFrederick Mayle 
243*9712c20fSFrederick Mayle     entries_[index].key[0] = '\0';
244*9712c20fSFrederick Mayle     entries_[index].value[0] = '\0';
245*9712c20fSFrederick Mayle     return true;
246*9712c20fSFrederick Mayle   }
247*9712c20fSFrederick Mayle 
248*9712c20fSFrederick Mayle   // Places a serialized version of the map into |map| and returns the size.
249*9712c20fSFrederick Mayle   // Both of these should be passed to the deserializing constructor. Note that
250*9712c20fSFrederick Mayle   // the serialized |map| is scoped to the lifetime of the non-serialized
251*9712c20fSFrederick Mayle   // instance of this class. The |map| can be copied across IPC boundaries.
Serialize(const SerializedNonAllocatingMap ** map)252*9712c20fSFrederick Mayle   size_t Serialize(const SerializedNonAllocatingMap** map) const {
253*9712c20fSFrederick Mayle     *map = reinterpret_cast<const SerializedNonAllocatingMap*>(entries_);
254*9712c20fSFrederick Mayle     return sizeof(entries_);
255*9712c20fSFrederick Mayle   }
256*9712c20fSFrederick Mayle 
257*9712c20fSFrederick Mayle  private:
GetEntryIndexForKey(const char * key)258*9712c20fSFrederick Mayle   size_t GetEntryIndexForKey(const char* key) const {
259*9712c20fSFrederick Mayle     for (size_t i = 0; i < num_entries; ++i) {
260*9712c20fSFrederick Mayle       if (strncmp(key, entries_[i].key, key_size) == 0) {
261*9712c20fSFrederick Mayle         return i;
262*9712c20fSFrederick Mayle       }
263*9712c20fSFrederick Mayle     }
264*9712c20fSFrederick Mayle     return num_entries;
265*9712c20fSFrederick Mayle   }
266*9712c20fSFrederick Mayle 
267*9712c20fSFrederick Mayle   Entry entries_[NumEntries];
268*9712c20fSFrederick Mayle };
269*9712c20fSFrederick Mayle 
270*9712c20fSFrederick Mayle // For historical reasons this specialized version is available with the same
271*9712c20fSFrederick Mayle // size factors as a previous implementation.
272*9712c20fSFrederick Mayle typedef NonAllocatingMap<256, 256, 64> SimpleStringDictionary;
273*9712c20fSFrederick Mayle 
274*9712c20fSFrederick Mayle }  // namespace google_breakpad
275*9712c20fSFrederick Mayle 
276*9712c20fSFrederick Mayle #endif  // COMMON_SIMPLE_STRING_DICTIONARY_H_
277