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

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

Issue 925613002: Spin off SkTHashTable, SkTHashMap, SkTHashSet (Closed) Base URL: https://skia.googlesource.com/skia.git@master
Patch Set: Created 5 years, 10 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 | « include/core/SkTemplates.h ('k') | tests/HashTest.cpp » ('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 #ifndef SkTHash_DEFINED
2 #define SkTHash_DEFINED
3
4 #include "SkTypes.h"
5 #include "SkTemplates.h"
6
7 // Before trying to use SkTHashTable, look below to see if SkTHashMap or SkTHash Set works for you.
8 // They're easier to use, usually perform the same, and have fewer sharp edges.
9
10 // T and K are treated as ordinary copyable C++ types.
11 // Traits must have:
12 // - static K GetKey(T)
13 // - static uint32_t Hash(K)
14 // If the key is large and stored inside T, you may want to make K a const&.
15 // Similarly, if T is large you might want it to be a pointer.
16 template <typename T, typename K, typename Traits = T>
17 class SkTHashTable : SkNoncopyable {
18 public:
19 SkTHashTable() : fCount(0), fCapacity(0) {}
20
21 // How many entries are in the table?
22 int count() const { return fCount; }
23
24 // N.B. The pointers returned by set() and find() are valid only until the n ext call to set().
25
26 // Copy val into the hash table, returning a pointer to the copy now in the table.
27 // If there already is an entry in the table with the same key, we overwrite it.
28 T* set(T val) {
f(malita) 2015/02/12 19:37:11 Shouldn't all these return const T* (if anything)?
reed1 2015/02/12 19:49:15 When is (const T& val) better or worse?
mtklein 2015/02/12 20:09:52 So far, I haven't seen it matter. This all being
mtklein 2015/02/12 20:09:52 Yeah, that's one of the sharp edges of why we don'
29 if (4 * fCount >= 3 * fCapacity) {
30 this->resize(fCapacity > 0 ? fCapacity * 2 : 4);
31 }
32 return this->uncheckedSet(val);
33 }
34
35 // If there is an entry in the table with this key, return a pointer to it. If not, NULL.
36 T* find(K key) const {
37 uint32_t hash = Hash(key);
38 int index = hash & (fCapacity-1);
39 for (int n = 0; n < fCapacity; n++) {
40 Slot& s = fSlots[index];
41 if (s.empty()) {
42 return NULL;
43 }
44 if (hash == s.hash && key == Traits::GetKey(s.val)) {
45 return &s.val;
46 }
47 index = this->next(index, n);
48 }
49 SkASSERT(fCapacity == 0);
50 return NULL;
51 }
52
53 // Call fn on every entry in the table. You may mutate the entries, but be very careful.
54 // If you change an entry so that it no longer has the same key,
55 // all hell will break loose the next time you call set() or find(). Do not do that!
56 template <typename Arg>
57 void foreach(void(*fn)(T*, Arg), Arg arg) {
58 for (int i = 0; i < fCapacity; i++) {
59 Slot& s = fSlots[i];
60 if (!s.empty()) {
61 fn(&s.val, arg);
62 }
63 }
64 }
65
66 private:
67 T* uncheckedSet(T val) {
68 K key = Traits::GetKey(val);
69 uint32_t hash = Hash(key);
70 int index = hash & (fCapacity-1);
71 for (int n = 0; n < fCapacity; n++) {
72 Slot& s = fSlots[index];
73 if (s.empty()) {
74 // New entry.
75 s.val = val;
76 s.hash = hash;
77 fCount++;
78 return &s.val;
79 }
80 if (hash == s.hash && key == Traits::GetKey(s.val)) {
81 // Overwrite previous entry.
82 s.val = val;
83 return &s.val;
84 }
85 index = this->next(index, n);
86 }
87 SkASSERT(false);
88 return NULL;
89 }
90
91 void resize(int capacity) {
92 int oldCapacity = fCapacity;
93 SkDEBUGCODE(int oldCount = fCount);
94
95 fCount = 0;
96 fCapacity = capacity;
97 SkAutoTArray<Slot> oldSlots(capacity);
98 oldSlots.swap(fSlots);
99
100 for (int i = 0; i < oldCapacity; i++) {
101 const Slot& s = oldSlots[i];
102 if (!s.empty()) {
103 this->uncheckedSet(s.val);
104 }
105 }
106 SkASSERT(fCount == oldCount);
107 }
108
109 int next(int index, int n) const {
110 // A valid strategy explores all slots in [0, fCapacity) as n walks from 0 to fCapacity-1.
111 // Both of these stragegies are valid:
112 //return (index + 0 + 1) & (fCapacity-1); // Linear probing.
113 return (index + n + 1) & (fCapacity-1); // Quadratic probing.
114 }
115
116 static uint32_t Hash(K key) {
117 uint32_t hash = Traits::Hash(key);
118 return hash == 0 ? 1 : hash; // We reserve hash == 0 to mark empty slot s.
119 }
120
121 struct Slot {
122 Slot() : hash(0) {}
123 bool empty() const { return hash == 0; }
124
125 T val;
126 uint32_t hash;
127 };
128
129 int fCount, fCapacity;
130 SkAutoTArray<Slot> fSlots;
131 };
132
133 // Maps K->V. A more user-friendly wrapper around SkTHashTable, suitable for mo st use cases.
134 // K and V are treated as ordinary copyable C++ types, with no assumed relations hip between the two.
135 template <typename K, typename V, uint32_t(*HashK)(K)>
136 class SkTHashMap : SkNoncopyable {
137 public:
138 SkTHashMap() {}
139
140 // How many key/value pairs are in the table?
141 int count() const { return fTable.count(); }
142
143 // N.B. The pointers returned by set() and find() are valid only until the n ext call to set().
144
145 // Set key to val in the table, replacing any previous value with the same k ey.
146 // We copy both key and val, and return a pointer to the value copy now in t he table.
147 V* set(K key, V val) {
148 Pair in = { key, val };
149 Pair* out = fTable.set(in);
150 return &out->val;
151 }
152
153 // If there is key/value entry in the table with this key, return a pointer to the value.
154 // If not, return NULL.
155 V* find(K key) const {
156 if (Pair* p = fTable.find(key)) {
157 return &p->val;
158 }
159 return NULL;
160 }
161
162 // Call fn on every key/value pair in the table. You may mutate the value b ut not the key.
163 void foreach(void(*fn)(K, V*)) { fTable.foreach(ForEach, fn); }
164
165 private:
166 struct Pair {
167 K key;
168 V val;
169 static K GetKey(Pair p) { return p.key; }
170 static uint32_t Hash(K key) { return HashK(key); }
171 };
172 static void ForEach(Pair* p, void (*fn)(K, V*)) { fn(p->key, &p->val); }
173
174 SkTHashTable<Pair, K> fTable;
175 };
176
177 // A set of T. T is treated as an ordiary copyable C++ type.
178 template <typename T, uint32_t(*HashT)(T)>
179 class SkTHashSet : SkNoncopyable {
180 public:
181 SkTHashSet() {}
182
183 // How many items are in the set?
184 int count() const { return fTable.count(); }
185
186 // N.B. The pointers returned by add() and find() are valid only until the n ext call to add().
187
188 // Copy an item into the set. If there is an item in the set already that i s equal
189 // to this one, overwrite it. Returns a pointer to the copy of the item now in the set.
190 T* add(T item) {
191 return fTable.set(item);
192 }
193
194 // If an item is in the set equal to this one, return a pointer to it, other wise return NULL.
195 T* find(T item) {
f(malita) 2015/02/12 19:37:11 Nit: I think we could use an even simpler interfac
f(malita) 2015/02/12 19:37:11 const
mtklein 2015/02/12 20:09:52 Done.
mtklein 2015/02/12 20:09:52 Done.
196 return fTable.find(item);
197 }
198
199 private:
200 struct Traits {
201 static T GetKey(T item) { return item; }
202 static uint32_t Hash(T item) { return HashT(item); }
203 };
204 SkTHashTable<T, T, Traits> fTable;
205 };
206
207 #endif//SkTHash_DEFINED
OLDNEW
« no previous file with comments | « include/core/SkTemplates.h ('k') | tests/HashTest.cpp » ('j') | no next file with comments »

Powered by Google App Engine
This is Rietveld 408576698