// Copyright 2014 The Crashpad Authors. All rights reserved. // // Licensed under the Apache License, Version 2.0 (the "License"); // you may not use this file except in compliance with the License. // You may obtain a copy of the License at // // http://www.apache.org/licenses/LICENSE-2.0 // // Unless required by applicable law or agreed to in writing, software // distributed under the License is distributed on an "AS IS" BASIS, // WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. // See the License for the specific language governing permissions and // limitations under the License. #ifndef CRASHPAD_CLIENT_SIMPLE_STRING_DICTIONARY_H_ #define CRASHPAD_CLIENT_SIMPLE_STRING_DICTIONARY_H_ #include #include "base/basictypes.h" #include "base/logging.h" namespace crashpad { // Opaque type for the serialized representation of a TSimpleStringDictionary. // One is created in TSimpleStringDictionary::Serialize and can be deserialized // using one of the constructors. struct SerializedSimpleStringDictionary; // TSimpleStringDictionary is an implementation of a map/dictionary collection // that uses a fixed amount of storage, so that it does not perform any dynamic // allocations for its operations. // // The actual map storage (the Entry) is guaranteed to be POD, so that it can be // transmitted over various IPC mechanisms. // // The template parameters control the amount of storage used for the key, // value, and map. The KeySize and ValueSize are measured in bytes, not glyphs, // and includes space for a \0 byte. This gives space for KeySize-1 and // ValueSize-1 characters in an entry. NumEntries is the total number of entries // that will fit in the map. template class TSimpleStringDictionary { public: // Constant and publicly accessible versions of the template parameters. static const size_t key_size = KeySize; static const size_t value_size = ValueSize; static const size_t num_entries = NumEntries; // An Entry object is a single entry in the map. If the key is a 0-length // NUL-terminated string, the entry is empty. struct Entry { char key[KeySize]; char value[ValueSize]; bool is_active() const { return key[0] != '\0'; } }; // An Iterator can be used to iterate over all the active entries in a // TSimpleStringDictionary. class Iterator { public: explicit Iterator(const TSimpleStringDictionary& map) : map_(map), current_(0) { } // Returns the next entry in the map, or NULL if at the end of the // collection. const Entry* Next() { while (current_ < map_.num_entries) { const Entry* entry = &map_.entries_[current_++]; if (entry->is_active()) { return entry; } } return NULL; } private: const TSimpleStringDictionary& map_; size_t current_; DISALLOW_COPY_AND_ASSIGN(Iterator); }; TSimpleStringDictionary() : entries_() { } TSimpleStringDictionary(const TSimpleStringDictionary& other) { *this = other; } TSimpleStringDictionary& operator=(const TSimpleStringDictionary& other) { memcpy(entries_, other.entries_, sizeof(entries_)); return *this; } // Constructs a map from its serialized form. |map| should be the out // parameter from Serialize() and |size| should be its return value. TSimpleStringDictionary( const SerializedSimpleStringDictionary* map, size_t size) { DCHECK_EQ(size, sizeof(entries_)); if (size == sizeof(entries_)) { memcpy(entries_, map, size); } } // Returns the number of active key/value pairs. The upper limit for this is // NumEntries. size_t GetCount() const { size_t count = 0; for (size_t i = 0; i < num_entries; ++i) { if (entries_[i].is_active()) { ++count; } } return count; } // Given |key|, returns its corresponding |value|. |key| must not be NULL. If // the key is not found, NULL is returned. const char* GetValueForKey(const char* key) const { DCHECK(key); if (!key) { return NULL; } const Entry* entry = GetConstEntryForKey(key); if (!entry) { return NULL; } return entry->value; } // Stores |value| into |key|, replacing the existing value if |key| is already // present. |key| must not be NULL. If |value| is NULL, the key is removed // from the map. If there is no more space in the map, then the operation // silently fails. void SetKeyValue(const char* key, const char* value) { if (!value) { RemoveKey(key); return; } DCHECK(key); if (!key) { return; } // Key must not be an empty string. DCHECK_NE(key[0], '\0'); if (key[0] == '\0') { return; } Entry* entry = GetEntryForKey(key); // If it does not yet exist, attempt to insert it. if (!entry) { for (size_t i = 0; i < num_entries; ++i) { if (!entries_[i].is_active()) { entry = &entries_[i]; strncpy(entry->key, key, key_size); entry->key[key_size - 1] = '\0'; break; } } } // If the map is out of space, entry will be NULL. if (!entry) { return; } #ifndef NDEBUG // Sanity check that the key only appears once. int count = 0; for (size_t i = 0; i < num_entries; ++i) { if (strncmp(entries_[i].key, key, key_size) == 0) { ++count; } } DCHECK_EQ(count, 1); #endif strncpy(entry->value, value, value_size); entry->value[value_size - 1] = '\0'; } // Given |key|, removes any associated value. |key| must not be NULL. If the // key is not found, this is a noop. void RemoveKey(const char* key) { DCHECK(key); if (!key) { return; } Entry* entry = GetEntryForKey(key); if (entry) { entry->key[0] = '\0'; entry->value[0] = '\0'; } DCHECK_EQ(GetEntryForKey(key), static_cast(NULL)); } // Places a serialized version of the map into |map| and returns the size. // Both of these should be passed to the deserializing constructor. Note that // the serialized |map| is scoped to the lifetime of the non-serialized // instance of this class. The |map| can be copied across IPC boundaries. size_t Serialize(const SerializedSimpleStringDictionary** map) const { *map = reinterpret_cast(entries_); return sizeof(entries_); } private: const Entry* GetConstEntryForKey(const char* key) const { for (size_t i = 0; i < num_entries; ++i) { if (strncmp(key, entries_[i].key, key_size) == 0) { return &entries_[i]; } } return NULL; } Entry* GetEntryForKey(const char* key) { return const_cast(GetConstEntryForKey(key)); } Entry entries_[NumEntries]; }; // For historical reasons this specialized version is available with the same // size factors as a previous implementation. typedef TSimpleStringDictionary<256, 256, 64> SimpleStringDictionary; } // namespace crashpad #endif // CRASHPAD_CLIENT_SIMPLE_STRING_DICTIONARY_H_