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