Rietveld Code Review Tool
Help | Bug tracker | Discussion group | Source code

Side by Side Diff: compiled/StringMap.h

Issue 29333474: Issue 4125 - [emscripten] Convert filter classes to C++ (Closed)
Patch Set: Rebased, addressed comments, changed StringMap::find() return value Created Feb. 18, 2016, 4:02 p.m.
Left:
Right:
Use n/p to move between diff chunks; N/P to move between comments.
Jump to:
View unified diff | Download patch
OLDNEW
(Empty)
1 #pragma once
2
3 #include <cstddef>
4 #include <cmath>
5 #include <initializer_list>
6 #include <memory>
7
8 #include "String.h"
9 #include "debug.h"
10
11 template<typename T>
12 class StringMap;
13
14 namespace StringMap_internal
15 {
16 template<typename Entry>
17 struct HashContainerIterator
18 {
19 typedef Entry entry_type;
20 typedef HashContainerIterator<Entry> iterator;
21
22 const entry_type* mPos;
23 const entry_type* mEnd;
24
25 explicit HashContainerIterator(const entry_type* start, const entry_type* en d)
26 : mPos(start), mEnd(end)
27 {
28 if (mPos != mEnd && mPos->first.is_invalid())
29 ++(*this);
30 }
31
32 const entry_type& operator*() const
33 {
34 return *mPos;
35 }
36
37 const entry_type* operator->() const
38 {
39 return mPos;
40 }
41
42 iterator& operator++()
43 {
44 do {
45 ++mPos;
46 } while(mPos != mEnd && mPos->first.is_invalid());
47 return *this;
48 }
49
50 bool operator==(const iterator& it) const
51 {
52 return mPos == it.mPos;
53 }
54
55 bool operator!=(const iterator& it) const
56 {
57 return mPos != it.mPos;
58 }
59 };
60
61 template<typename Entry>
62 struct HashContainerReference
63 {
64 typedef Entry entry_type;
65
66 const entry_type* mEntry;
67
68 explicit HashContainerReference(const entry_type* entry)
69 : mEntry(entry)
70 {
71 }
72
73 const entry_type* operator->() const
74 {
75 return mEntry;
76 }
77
78 operator bool() const
79 {
80 return !mEntry->first.is_invalid();
81 }
82 };
83
84 template<typename Entry>
85 class HashContainer
86 {
87 public:
88 typedef Entry entry_type;
89 typedef size_t size_type;
90 typedef HashContainerIterator<Entry> const_iterator;
91 typedef HashContainerReference<Entry> const_reference;
92
93 private:
94 HashContainer(const HashContainer& other);
95 void operator=(const HashContainer& other);
96
97 protected:
98 static constexpr size_type MIN_BUCKETS = 1;
99 static constexpr double LOAD_FACTOR = 0.8;
100 std::unique_ptr<entry_type[]> mBuckets;
101 size_type mBucketCount;
102 size_type mEntryCount;
103
104 explicit HashContainer(size_type expectedEntries = 0)
105 : mEntryCount(0)
106 {
107 expectedEntries = ceil(expectedEntries / LOAD_FACTOR);
108 mBucketCount = MIN_BUCKETS;
109 while (mBucketCount < expectedEntries)
110 mBucketCount <<= 1;
111
112 mBuckets.reset(new entry_type[mBucketCount]);
113 // Working around https://github.com/waywardmonkeys/emscripten-trace-colle ctor/issues/2 here
114 annotate_address(reinterpret_cast<size_type*>(mBuckets.get()) - 1, "Hash t able buffer");
115 }
116
117 static size_type hash(const String& str)
118 {
119 // FNV-1a hash function
120 size_type result = 2166136261;
121 for (String::size_type i = 0; i < str.length(); i++)
122 result = (result ^ str[i]) * 16777619;
123 return result;
124 }
125
126 entry_type* find_bucket(const String& key) const
127 {
128 size_type h = hash(key);
129
130 // This does quadratic probing, effectively the following formula is used:
131 // pos = (hash + 1/2 i + 1/2 i ^ 2) mod bucketCount
132 for (size_type i = 0; ; ++i)
133 {
134 // mBucketCount is 2^n so (h & mBucketCount - 1) is equivalent to
135 // h % mBucketCount but significantly faster.
136 entry_type* entry = &mBuckets[h & mBucketCount - 1];
137 if (entry->first.is_invalid() || entry->first.equals(key))
138 return entry;
139 h += i;
140 }
141 }
142
143 void resize(size_type bucketCount)
144 {
145 std::unique_ptr<entry_type[]> oldBuckets(std::move(mBuckets));
146 size_type oldCount = mBucketCount;
147
148 mEntryCount = 0;
149 mBucketCount = bucketCount;
150 mBuckets.reset(new entry_type[mBucketCount]);
151 // Working around https://github.com/waywardmonkeys/emscripten-trace-colle ctor/issues/2 here
152 annotate_address(reinterpret_cast<size_type*>(mBuckets.get()) - 1, "Hash t able buffer");
153
154 // Copy old entries into the new buffer
155 for (size_type i = 0; i < oldCount; i++)
156 {
157 entry_type& entry = oldBuckets[i];
158 if (!entry.first.is_invalid())
159 {
160 *find_bucket(entry.first) = entry;
161 mEntryCount++;
162 }
163 }
164 }
165
166 entry_type* assign(entry_type* existing, const entry_type& entry)
167 {
168 if (existing->first.is_invalid())
169 {
170 if (mEntryCount + 1 >= mBucketCount * LOAD_FACTOR)
171 {
172 resize(mBucketCount << 1);
173 existing = find_bucket(entry.first);
174 }
175 mEntryCount++;
176 }
177 *existing = entry;
178 return existing;
179 }
180
181 public:
182 void insert(const entry_type& entry)
183 {
184 assign(find_bucket(entry.first), entry);
185 }
186
187 const_reference find(const String& key) const
188 {
189 return const_reference(find_bucket(key));
190 }
191
192 const_iterator begin() const
193 {
194 return const_iterator(&mBuckets[0], &mBuckets[mBucketCount]);
195 }
196
197 const_iterator end() const
198 {
199 return const_iterator(&mBuckets[mBucketCount], &mBuckets[mBucketCount]);
200 }
201 };
202
203 struct StringSetEntry
204 {
205 StringSetEntry() {}
206 StringSetEntry(const String& key)
207 : first(key)
208 {
209 }
210
211 DependentString first;
212 };
213
214 template<typename T>
215 struct StringMapEntry
216 {
217 StringMapEntry() {}
218 StringMapEntry(const String& key)
219 : first(key)
220 {
221 }
222 StringMapEntry(const String& key, T value)
223 : first(key), second(value)
224 {
225 }
226
227 DependentString first;
228 T second;
229 };
230
231 template<typename T>
232 struct StringMapEntryReference : public HashContainerReference<StringMapEntry< T>>
233 {
234 typedef HashContainerReference<StringMapEntry<T>> super;
235 typedef typename super::entry_type entry_type;
236 typedef StringMap<T> map_type;
237
238 map_type* mMap;
239
240 StringMapEntryReference(map_type* map, const entry_type* entry)
241 : super(entry), mMap(map)
242 {
243 }
244
245 void assign(const String& key, const T& value)
sergei 2016/02/22 12:46:03 I have noticed a couple of asserts here in the rep
Wladimir Palant 2016/02/23 12:37:36 As explained under https://codereview.adblockplus.
246 {
247 mMap->assign(const_cast<entry_type*>(super::mEntry), entry_type(key, value ));
sergei 2016/02/22 12:46:02 `super::mEntry` is also accessible by `this->mEntr
sergei 2016/02/22 12:46:05 It's not necessary to use `const_cast` here. We ca
Wladimir Palant 2016/02/23 12:37:34 Done.
Wladimir Palant 2016/02/23 12:37:37 Done.
248 }
249 };
250 }
251
252 class StringSet
253 : public StringMap_internal::HashContainer<StringMap_internal::StringSetEntry>
254 {
255 };
256
257 template<typename T>
258 class StringMap
259 : public StringMap_internal::HashContainer<StringMap_internal::StringMapEntry< T>>
260 {
261 public:
262 typedef StringMap_internal::HashContainer<StringMap_internal::StringMapEntry<T >> super;
263 typedef typename super::size_type size_type;
264 typedef typename super::entry_type entry_type;
265 typedef typename super::const_reference const_reference;
266 typedef StringMap_internal::StringMapEntryReference<T> reference;
267 friend class StringMap_internal::StringMapEntryReference<T>;
268
269 explicit StringMap(size_type expectedEntries = 0)
270 : super(expectedEntries)
271 {
272 }
273
274 StringMap(std::initializer_list<entry_type> list)
275 : super(list.size())
276 {
277 for (auto it = list.begin(); it != list.end(); ++it)
278 super::insert(*it);
279 }
280
281 ~StringMap()
282 {
283 }
284
285 T& operator[](const String& key)
286 {
287 entry_type* entry = super::find_bucket(key);
288 if (entry->first.is_invalid())
289 entry = super::assign(entry, key);
290 return entry->second;
291 }
292
293 const_reference find(const String& key) const
294 {
295 return super::find(key);
296 }
297
298 reference find(const String& key)
299 {
300 return reference(this, super::find_bucket(key));
301 }
302 };
OLDNEW

Powered by Google App Engine
This is Rietveld