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     const Entry* entry = GetConstEntryForKey(key);
151     if (!entry)
152       return NULL;
153 
154     return entry->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.
SetKeyValue(const char * key,const char * value)161   void SetKeyValue(const char* key, const char* value) {
162     if (!value) {
163       RemoveKey(key);
164       return;
165     }
166 
167     assert(key);
168     if (!key)
169       return;
170 
171     // Key must not be an empty string.
172     assert(key[0] != '\0');
173     if (key[0] == '\0')
174       return;
175 
176     Entry* entry = GetEntryForKey(key);
177 
178     // If it does not yet exist, attempt to insert it.
179     if (!entry) {
180       for (size_t i = 0; i < num_entries; ++i) {
181         if (!entries_[i].is_active()) {
182           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)
194       return;
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(entry->value, value, value_size);
207     entry->value[value_size - 1] = '\0';
208   }
209 
210   // Given |key|, removes any associated value. |key| must not be NULL. If
211   // the key is not found, this is a noop.
RemoveKey(const char * key)212   void RemoveKey(const char* key) {
213     assert(key);
214     if (!key)
215       return;
216 
217     Entry* entry = GetEntryForKey(key);
218     if (entry) {
219       entry->key[0] = '\0';
220       entry->value[0] = '\0';
221     }
222 
223 #ifndef NDEBUG
224     assert(GetEntryForKey(key) == NULL);
225 #endif
226   }
227 
228   // Places a serialized version of the map into |map| and returns the size.
229   // Both of these should be passed to the deserializing constructor. Note that
230   // the serialized |map| is scoped to the lifetime of the non-serialized
231   // instance of this class. The |map| can be copied across IPC boundaries.
Serialize(const SerializedNonAllocatingMap ** map)232   size_t Serialize(const SerializedNonAllocatingMap** map) const {
233     *map = reinterpret_cast<const SerializedNonAllocatingMap*>(entries_);
234     return sizeof(entries_);
235   }
236 
237  private:
GetConstEntryForKey(const char * key)238   const Entry* GetConstEntryForKey(const char* key) const {
239     for (size_t i = 0; i < num_entries; ++i) {
240       if (strncmp(key, entries_[i].key, key_size) == 0) {
241         return &entries_[i];
242       }
243     }
244     return NULL;
245   }
246 
GetEntryForKey(const char * key)247   Entry* GetEntryForKey(const char* key) {
248     return const_cast<Entry*>(GetConstEntryForKey(key));
249   }
250 
251   Entry entries_[NumEntries];
252 };
253 
254 // For historical reasons this specialized version is available with the same
255 // size factors as a previous implementation.
256 typedef NonAllocatingMap<256, 256, 64> SimpleStringDictionary;
257 
258 }  // namespace google_breakpad
259 
260 #endif  // COMMON_SIMPLE_STRING_DICTIONARY_H_
261