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