Chromium Code Reviews
chromiumcodereview-hr@appspot.gserviceaccount.com (chromiumcodereview-hr) | Please choose your nickname with Settings | Help | Chromium Project | Gerrit Changes | Sign out
(490)

Side by Side Diff: client/simple_string_dictionary.h

Issue 489993002: Add SimpleStringDictionary and its test (Closed) Base URL: https://chromium.googlesource.com/crashpad/crashpad@master
Patch Set: Crashpad version Created 6 years, 4 months ago
Use n/p to move between diff chunks; N/P to move between comments. Draft comments are only viewable by you.
Jump to:
View unified diff | Download patch
« no previous file with comments | « client/client.gyp ('k') | client/simple_string_dictionary.cc » ('j') | no next file with comments »
Toggle Intra-line Diffs ('i') | Expand Comments ('e') | Collapse Comments ('c') | Show Comments Hide Comments ('s')
OLDNEW
(Empty)
1 // Copyright 2014 The Crashpad Authors. All rights reserved.
2 //
3 // Licensed under the Apache License, Version 2.0 (the "License");
4 // you may not use this file except in compliance with the License.
5 // You may obtain a copy of the License at
6 //
7 // http://www.apache.org/licenses/LICENSE-2.0
8 //
9 // Unless required by applicable law or agreed to in writing, software
10 // distributed under the License is distributed on an "AS IS" BASIS,
11 // WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
12 // See the License for the specific language governing permissions and
13 // limitations under the License.
14
15 #ifndef CRASHPAD_CLIENT_SIMPLE_STRING_DICTIONARY_H_
16 #define CRASHPAD_CLIENT_SIMPLE_STRING_DICTIONARY_H_
17
18 #include <string.h>
19
20 #include "base/basictypes.h"
21 #include "base/logging.h"
22
23 namespace crashpad {
24
25 // Opaque type for the serialized representation of a NonAllocatingMap. One is
26 // created in NonAllocatingMap::Serialize and can be deserialized using one of
27 // the constructors.
28 struct SerializedNonAllocatingMap;
29
30 // NonAllocatingMap is an implementation of a map/dictionary collection that
31 // uses a fixed amount of storage, so that it does not perform any dynamic
32 // allocations for its operations.
33 //
34 // The actual map storage (the Entry) is guaranteed to be POD, so that it can be
35 // transmitted over various IPC mechanisms.
36 //
37 // The template parameters control the amount of storage used for the key,
38 // value, and map. The KeySize and ValueSize are measured in bytes, not glyphs,
39 // and includes space for a \0 byte. This gives space for KeySize-1 and
40 // ValueSize-1 characters in an entry. NumEntries is the total number of entries
41 // that will fit in the map.
42 template <size_t KeySize, size_t ValueSize, size_t NumEntries>
43 class NonAllocatingMap {
44 public:
45 // Constant and publicly accessible versions of the template parameters.
46 static const size_t key_size = KeySize;
47 static const size_t value_size = ValueSize;
48 static const size_t num_entries = NumEntries;
49
50 // An Entry object is a single entry in the map. If the key is a 0-length
51 // NUL-terminated string, the entry is empty.
52 struct Entry {
53 char key[KeySize];
54 char value[ValueSize];
55
56 bool is_active() const { return key[0] != '\0'; }
57 };
58
59 // An Iterator can be used to iterate over all the active entries in a
60 // NonAllocatingMap.
61 class Iterator {
62 public:
63 explicit Iterator(const NonAllocatingMap& map) : map_(map), current_(0) {}
64
65 // Returns the next entry in the map, or NULL if at the end of the
66 // collection.
67 const Entry* Next() {
68 while (current_ < map_.num_entries) {
69 const Entry* entry = &map_.entries_[current_++];
70 if (entry->is_active()) {
71 return entry;
72 }
73 }
74 return NULL;
75 }
76
77 private:
78 const NonAllocatingMap& map_;
79 size_t current_;
80
81 DISALLOW_COPY_AND_ASSIGN(Iterator);
82 };
83
84 NonAllocatingMap() : entries_() {}
85
86 NonAllocatingMap(const NonAllocatingMap& other) { *this = other; }
87
88 NonAllocatingMap& operator=(const NonAllocatingMap& other) {
89 DCHECK(other.key_size == key_size);
Robert Sesek 2014/08/21 16:55:16 DCHECK_EQ
Mark Mentovai 2014/08/22 14:05:26 rsesek wrote:
90 DCHECK(other.value_size == value_size);
91 DCHECK(other.num_entries == num_entries);
92 if (other.key_size == key_size && other.value_size == value_size &&
93 other.num_entries == num_entries) {
94 memcpy(entries_, other.entries_, sizeof(entries_));
95 }
96 return *this;
97 }
98
99 // Constructs a map from its serialized form. |map| should be the out
100 // parameter from Serialize() and |size| should be its return value.
101 NonAllocatingMap(const SerializedNonAllocatingMap* map, size_t size) {
102 DCHECK_EQ(size, sizeof(entries_));
103 if (size == sizeof(entries_)) {
104 memcpy(entries_, map, size);
105 }
106 }
107
108 // Returns the number of active key/value pairs. The upper limit for this is
109 // NumEntries.
110 size_t GetCount() const {
111 size_t count = 0;
112 for (size_t i = 0; i < num_entries; ++i) {
113 if (entries_[i].is_active()) {
114 ++count;
115 }
116 }
117 return count;
118 }
119
120 // Given |key|, returns its corresponding |value|. |key| must not be NULL. If
121 // the key is not found, NULL is returned.
122 const char* GetValueForKey(const char* key) const {
123 DCHECK(key);
124 if (!key) {
125 return NULL;
126 }
127
128 const Entry* entry = GetConstEntryForKey(key);
129 if (!entry) {
130 return NULL;
131 }
132
133 return entry->value;
134 }
135
136 // Stores |value| into |key|, replacing the existing value if |key| is already
137 // present. |key| must not be NULL. If |value| is NULL, the key is removed
138 // from the map. If there is no more space in the map, then the operation
139 // silently fails.
140 void SetKeyValue(const char* key, const char* value) {
141 if (!value) {
142 RemoveKey(key);
143 return;
144 }
145
146 DCHECK(key);
147 if (!key) {
148 return;
149 }
150
151 // Key must not be an empty string.
152 DCHECK_NE(key[0], '\0');
153 if (key[0] == '\0') {
154 return;
155 }
156
157 Entry* entry = GetEntryForKey(key);
158
159 // If it does not yet exist, attempt to insert it.
160 if (!entry) {
161 for (size_t i = 0; i < num_entries; ++i) {
162 if (!entries_[i].is_active()) {
163 entry = &entries_[i];
164
165 strncpy(entry->key, key, key_size);
166 entry->key[key_size - 1] = '\0';
167
168 break;
169 }
170 }
171 }
172
173 // If the map is out of space, entry will be NULL.
174 if (!entry) {
175 return;
176 }
177
178 #ifndef NDEBUG
179 // Sanity check that the key only appears once.
180 int count = 0;
181 for (size_t i = 0; i < num_entries; ++i) {
182 if (strncmp(entries_[i].key, key, key_size) == 0) {
183 ++count;
184 }
185 }
186 DCHECK_EQ(count, 1);
187 #endif
188
189 strncpy(entry->value, value, value_size);
190 entry->value[value_size - 1] = '\0';
191 }
192
193 // Given |key|, removes any associated value. |key| must not be NULL. If the
194 // key is not found, this is a noop.
195 void RemoveKey(const char* key) {
196 DCHECK(key);
197 if (!key) {
198 return;
199 }
200
201 Entry* entry = GetEntryForKey(key);
202 if (entry) {
203 entry->key[0] = '\0';
204 entry->value[0] = '\0';
205 }
206
207 DCHECK_EQ(GetEntryForKey(key), static_cast<void*>(NULL));
208 }
209
210 // Places a serialized version of the map into |map| and returns the size.
211 // Both of these should be passed to the deserializing constructor. Note that
212 // the serialized |map| is scoped to the lifetime of the non-serialized
213 // instance of this class. The |map| can be copied across IPC boundaries.
214 size_t Serialize(const SerializedNonAllocatingMap** map) const {
215 *map = reinterpret_cast<const SerializedNonAllocatingMap*>(entries_);
216 return sizeof(entries_);
217 }
218
219 private:
220 const Entry* GetConstEntryForKey(const char* key) const {
221 for (size_t i = 0; i < num_entries; ++i) {
222 if (strncmp(key, entries_[i].key, key_size) == 0) {
223 return &entries_[i];
224 }
225 }
226 return NULL;
227 }
228
229 Entry* GetEntryForKey(const char* key) {
230 return const_cast<Entry*>(GetConstEntryForKey(key));
231 }
232
233 Entry entries_[NumEntries];
234 };
235
236 // For historical reasons this specialized version is available with the same
237 // size factors as a previous implementation.
238 typedef NonAllocatingMap<256, 256, 64> SimpleStringDictionary;
Robert Sesek 2014/08/21 16:55:16 Since you've named this file simple_string_diction
Mark Mentovai 2014/08/22 14:05:26 rsesek wrote:
Robert Sesek 2014/08/22 17:04:56 I think so, yes. Or you could provide another type
239
240 } // namespace crashpad
241
242 #endif // CRASHPAD_CLIENT_SIMPLE_STRING_DICTIONARY_H_
OLDNEW
« no previous file with comments | « client/client.gyp ('k') | client/simple_string_dictionary.cc » ('j') | no next file with comments »

Powered by Google App Engine
This is Rietveld 408576698