OLD | NEW |
---|---|
(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_ | |
OLD | NEW |