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