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