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

Side by Side Diff: src/core/SkTHash.h

Issue 1260613006: Move SkTHash.h to include/private. (Closed) Base URL: https://skia.googlesource.com/skia.git@master
Patch Set: rm Created 5 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 | « src/core/SkChecksum.h ('k') | src/utils/SkTLogic.h » ('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 /*
2 * Copyright 2015 Google Inc.
3 *
4 * Use of this source code is governed by a BSD-style license that can be
5 * found in the LICENSE file.
6 */
7
8 #ifndef SkTHash_DEFINED
9 #define SkTHash_DEFINED
10
11 #include "SkChecksum.h"
12 #include "SkTypes.h"
13 #include "SkTemplates.h"
14
15 // Before trying to use SkTHashTable, look below to see if SkTHashMap or SkTHash Set works for you.
16 // They're easier to use, usually perform the same, and have fewer sharp edges.
17
18 // T and K are treated as ordinary copyable C++ types.
19 // Traits must have:
20 // - static K GetKey(T)
21 // - static uint32_t Hash(K)
22 // If the key is large and stored inside T, you may want to make K a const&.
23 // Similarly, if T is large you might want it to be a pointer.
24 template <typename T, typename K, typename Traits = T>
25 class SkTHashTable : SkNoncopyable {
26 public:
27 SkTHashTable() : fCount(0), fRemoved(0), fCapacity(0) {}
28
29 // Clear the table.
30 void reset() {
31 this->~SkTHashTable();
32 SkNEW_PLACEMENT(this, SkTHashTable);
33 }
34
35 // How many entries are in the table?
36 int count() const { return fCount; }
37
38 // !!!!!!!!!!!!!!!!! CAUTION !!!!!!!!!!!!! !!!!
39 // set(), find() and foreach() all allow mutable access to table entries.
40 // If you change an entry so that it no longer has the same key, all hell
41 // will break loose. Do not do that!
42 //
43 // Please prefer to use SkTHashMap or SkTHashSet, which do not have this dan ger.
44
45 // The pointers returned by set() and find() are valid only until the next c all to set().
46 // The pointers you receive in foreach() are only valid for its duration.
47
48 // Copy val into the hash table, returning a pointer to the copy now in the table.
49 // If there already is an entry in the table with the same key, we overwrite it.
50 T* set(const T& val) {
51 if (4 * (fCount+fRemoved) >= 3 * fCapacity) {
52 this->resize(fCapacity > 0 ? fCapacity * 2 : 4);
53 }
54 return this->uncheckedSet(val);
55 }
56
57 // If there is an entry in the table with this key, return a pointer to it. If not, NULL.
58 T* find(const K& key) const {
59 uint32_t hash = Hash(key);
60 int index = hash & (fCapacity-1);
61 for (int n = 0; n < fCapacity; n++) {
62 Slot& s = fSlots[index];
63 if (s.empty()) {
64 return NULL;
65 }
66 if (!s.removed() && hash == s.hash && key == Traits::GetKey(s.val)) {
67 return &s.val;
68 }
69 index = this->next(index, n);
70 }
71 SkASSERT(fCapacity == 0);
72 return NULL;
73 }
74
75 // Remove the value with this key from the hash table.
76 void remove(const K& key) {
77 SkASSERT(this->find(key));
78
79 uint32_t hash = Hash(key);
80 int index = hash & (fCapacity-1);
81 for (int n = 0; n < fCapacity; n++) {
82 Slot& s = fSlots[index];
83 SkASSERT(!s.empty());
84 if (!s.removed() && hash == s.hash && key == Traits::GetKey(s.val)) {
85 fRemoved++;
86 fCount--;
87 s.markRemoved();
88 return;
89 }
90 index = this->next(index, n);
91 }
92 SkASSERT(fCapacity == 0);
93 }
94
95 // Call fn on every entry in the table. You may mutate the entries, but be very careful.
96 template <typename Fn> // f(T*)
97 void foreach(Fn&& fn) {
98 for (int i = 0; i < fCapacity; i++) {
99 if (!fSlots[i].empty() && !fSlots[i].removed()) {
100 fn(&fSlots[i].val);
101 }
102 }
103 }
104
105 // Call fn on every entry in the table. You may not mutate anything.
106 template <typename Fn> // f(T) or f(const T&)
107 void foreach(Fn&& fn) const {
108 for (int i = 0; i < fCapacity; i++) {
109 if (!fSlots[i].empty() && !fSlots[i].removed()) {
110 fn(fSlots[i].val);
111 }
112 }
113 }
114
115 private:
116 T* uncheckedSet(const T& val) {
117 const K& key = Traits::GetKey(val);
118 uint32_t hash = Hash(key);
119 int index = hash & (fCapacity-1);
120 for (int n = 0; n < fCapacity; n++) {
121 Slot& s = fSlots[index];
122 if (s.empty() || s.removed()) {
123 // New entry.
124 if (s.removed()) {
125 fRemoved--;
126 }
127 s.val = val;
128 s.hash = hash;
129 fCount++;
130 return &s.val;
131 }
132 if (hash == s.hash && key == Traits::GetKey(s.val)) {
133 // Overwrite previous entry.
134 // Note: this triggers extra copies when adding the same value r epeatedly.
135 s.val = val;
136 return &s.val;
137 }
138 index = this->next(index, n);
139 }
140 SkASSERT(false);
141 return NULL;
142 }
143
144 void resize(int capacity) {
145 int oldCapacity = fCapacity;
146 SkDEBUGCODE(int oldCount = fCount);
147
148 fCount = fRemoved = 0;
149 fCapacity = capacity;
150 SkAutoTArray<Slot> oldSlots(capacity);
151 oldSlots.swap(fSlots);
152
153 for (int i = 0; i < oldCapacity; i++) {
154 const Slot& s = oldSlots[i];
155 if (!s.empty() && !s.removed()) {
156 this->uncheckedSet(s.val);
157 }
158 }
159 SkASSERT(fCount == oldCount);
160 }
161
162 int next(int index, int n) const {
163 // A valid strategy explores all slots in [0, fCapacity) as n walks from 0 to fCapacity-1.
164 // Both of these strategies are valid:
165 //return (index + 0 + 1) & (fCapacity-1); // Linear probing.
166 return (index + n + 1) & (fCapacity-1); // Quadratic probing.
167 }
168
169 static uint32_t Hash(const K& key) {
170 uint32_t hash = Traits::Hash(key);
171 return hash < 2 ? hash+2 : hash; // We reserve hash 0 and 1 to mark emp ty or removed slots.
172 }
173
174 struct Slot {
175 Slot() : hash(0) {}
176 bool empty() const { return this->hash == 0; }
177 bool removed() const { return this->hash == 1; }
178
179 void markRemoved() { this->hash = 1; }
180
181 T val;
182 uint32_t hash;
183 };
184
185 int fCount, fRemoved, fCapacity;
186 SkAutoTArray<Slot> fSlots;
187 };
188
189 // Maps K->V. A more user-friendly wrapper around SkTHashTable, suitable for mo st use cases.
190 // K and V are treated as ordinary copyable C++ types, with no assumed relations hip between the two.
191 template <typename K, typename V, uint32_t(*HashK)(const K&) = &SkGoodHash>
192 class SkTHashMap : SkNoncopyable {
193 public:
194 SkTHashMap() {}
195
196 // Clear the map.
197 void reset() { fTable.reset(); }
198
199 // How many key/value pairs are in the table?
200 int count() const { return fTable.count(); }
201
202 // N.B. The pointers returned by set() and find() are valid only until the n ext call to set().
203
204 // Set key to val in the table, replacing any previous value with the same k ey.
205 // We copy both key and val, and return a pointer to the value copy now in t he table.
206 V* set(const K& key, const V& val) {
207 Pair in = { key, val };
208 Pair* out = fTable.set(in);
209 return &out->val;
210 }
211
212 // If there is key/value entry in the table with this key, return a pointer to the value.
213 // If not, return NULL.
214 V* find(const K& key) const {
215 if (Pair* p = fTable.find(key)) {
216 return &p->val;
217 }
218 return NULL;
219 }
220
221 // Remove the key/value entry in the table with this key.
222 void remove(const K& key) {
223 SkASSERT(this->find(key));
224 fTable.remove(key);
225 }
226
227 // Call fn on every key/value pair in the table. You may mutate the value b ut not the key.
228 template <typename Fn> // f(K, V*) or f(const K&, V*)
229 void foreach(Fn&& fn) {
230 fTable.foreach([&fn](Pair* p){ fn(p->key, &p->val); });
231 }
232
233 // Call fn on every key/value pair in the table. You may not mutate anythin g.
234 template <typename Fn> // f(K, V), f(const K&, V), f(K, const V&) or f(cons t K&, const V&).
235 void foreach(Fn&& fn) const {
236 fTable.foreach([&fn](const Pair& p){ fn(p.key, p.val); });
237 }
238
239 private:
240 struct Pair {
241 K key;
242 V val;
243 static const K& GetKey(const Pair& p) { return p.key; }
244 static uint32_t Hash(const K& key) { return HashK(key); }
245 };
246
247 SkTHashTable<Pair, K> fTable;
248 };
249
250 // A set of T. T is treated as an ordiary copyable C++ type.
251 template <typename T, uint32_t(*HashT)(const T&) = &SkGoodHash>
252 class SkTHashSet : SkNoncopyable {
253 public:
254 SkTHashSet() {}
255
256 // Clear the set.
257 void reset() { fTable.reset(); }
258
259 // How many items are in the set?
260 int count() const { return fTable.count(); }
261
262 // Copy an item into the set.
263 void add(const T& item) { fTable.set(item); }
264
265 // Is this item in the set?
266 bool contains(const T& item) const { return SkToBool(this->find(item)); }
267
268 // If an item equal to this is in the set, return a pointer to it, otherwise null.
269 // This pointer remains valid until the next call to add().
270 const T* find(const T& item) const { return fTable.find(item); }
271
272 // Remove the item in the set equal to this.
273 void remove(const T& item) {
274 SkASSERT(this->contains(item));
275 fTable.remove(item);
276 }
277
278 // Call fn on every item in the set. You may not mutate anything.
279 template <typename Fn> // f(T), f(const T&)
280 void foreach (Fn&& fn) const {
281 fTable.foreach(fn);
282 }
283
284 private:
285 struct Traits {
286 static const T& GetKey(const T& item) { return item; }
287 static uint32_t Hash(const T& item) { return HashT(item); }
288 };
289 SkTHashTable<T, T, Traits> fTable;
290 };
291
292 #endif//SkTHash_DEFINED
OLDNEW
« no previous file with comments | « src/core/SkChecksum.h ('k') | src/utils/SkTLogic.h » ('j') | no next file with comments »

Powered by Google App Engine
This is Rietveld 408576698