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

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: windows 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 // !!!!!!!!!!!!!!!!! CAUTION !!!!!!!!!!!!! !!!!
25 // set(), find() and foreach() all allow mutable access to table entries.
26 // If you change an entry so that it no longer has the same key, all hell
27 // will break loose. Do not do that!
28 //
29 // Please prefer to use SkTHashMap or SkTHashSet, which do not have this dan ger.
30
31 // The pointers returned by set() and find() are valid only until the next c all to set().
32 // The pointers you receive in foreach() are only valid for its duration.
33
34 // Copy val into the hash table, returning a pointer to the copy now in the table.
35 // If there already is an entry in the table with the same key, we overwrite it.
36 T* set(T val) {
37 if (4 * fCount >= 3 * fCapacity) {
38 this->resize(fCapacity > 0 ? fCapacity * 2 : 4);
39 }
40 return this->uncheckedSet(val);
41 }
42
43 // If there is an entry in the table with this key, return a pointer to it. If not, NULL.
44 T* find(K key) const {
45 uint32_t hash = Hash(key);
46 int index = hash & (fCapacity-1);
47 for (int n = 0; n < fCapacity; n++) {
48 Slot& s = fSlots[index];
49 if (s.empty()) {
50 return NULL;
51 }
52 if (hash == s.hash && key == Traits::GetKey(s.val)) {
53 return &s.val;
54 }
55 index = this->next(index, n);
56 }
57 SkASSERT(fCapacity == 0);
58 return NULL;
59 }
60
61 // Call fn on every entry in the table. You may mutate the entries, but be very careful.
62 template <typename Arg>
63 void foreach(void(*fn)(T*, Arg), Arg arg) {
64 for (int i = 0; i < fCapacity; i++) {
65 Slot& s = fSlots[i];
66 if (!s.empty()) {
67 fn(&s.val, arg);
68 }
69 }
70 }
71
72 private:
73 T* uncheckedSet(T val) {
74 K key = Traits::GetKey(val);
75 uint32_t hash = Hash(key);
76 int index = hash & (fCapacity-1);
77 for (int n = 0; n < fCapacity; n++) {
78 Slot& s = fSlots[index];
79 if (s.empty()) {
80 // New entry.
81 s.val = val;
82 s.hash = hash;
83 fCount++;
84 return &s.val;
85 }
86 if (hash == s.hash && key == Traits::GetKey(s.val)) {
87 // Overwrite previous entry.
88 s.val = val;
89 return &s.val;
90 }
91 index = this->next(index, n);
92 }
93 SkASSERT(false);
94 return NULL;
95 }
96
97 void resize(int capacity) {
98 int oldCapacity = fCapacity;
99 SkDEBUGCODE(int oldCount = fCount);
100
101 fCount = 0;
102 fCapacity = capacity;
103 SkAutoTArray<Slot> oldSlots(capacity);
104 oldSlots.swap(fSlots);
105
106 for (int i = 0; i < oldCapacity; i++) {
107 const Slot& s = oldSlots[i];
108 if (!s.empty()) {
109 this->uncheckedSet(s.val);
110 }
111 }
112 SkASSERT(fCount == oldCount);
113 }
114
115 int next(int index, int n) const {
116 // A valid strategy explores all slots in [0, fCapacity) as n walks from 0 to fCapacity-1.
117 // Both of these strategies are valid:
118 //return (index + 0 + 1) & (fCapacity-1); // Linear probing.
119 return (index + n + 1) & (fCapacity-1); // Quadratic probing.
120 }
121
122 static uint32_t Hash(K key) {
123 uint32_t hash = Traits::Hash(key);
124 return hash == 0 ? 1 : hash; // We reserve hash == 0 to mark empty slot s.
125 }
126
127 struct Slot {
128 Slot() : hash(0) {}
129 bool empty() const { return hash == 0; }
130
131 T val;
132 uint32_t hash;
133 };
134
135 int fCount, fCapacity;
136 SkAutoTArray<Slot> fSlots;
137 };
138
139 // Maps K->V. A more user-friendly wrapper around SkTHashTable, suitable for mo st use cases.
140 // K and V are treated as ordinary copyable C++ types, with no assumed relations hip between the two.
141 template <typename K, typename V, uint32_t(*HashK)(K)>
142 class SkTHashMap : SkNoncopyable {
143 public:
144 SkTHashMap() {}
145
146 // How many key/value pairs are in the table?
147 int count() const { return fTable.count(); }
148
149 // N.B. The pointers returned by set() and find() are valid only until the n ext call to set().
150
151 // Set key to val in the table, replacing any previous value with the same k ey.
152 // We copy both key and val, and return a pointer to the value copy now in t he table.
153 V* set(K key, V val) {
154 Pair in = { key, val };
155 Pair* out = fTable.set(in);
156 return &out->val;
157 }
158
159 // If there is key/value entry in the table with this key, return a pointer to the value.
160 // If not, return NULL.
161 V* find(K key) const {
162 if (Pair* p = fTable.find(key)) {
163 return &p->val;
164 }
165 return NULL;
166 }
167
168 // Call fn on every key/value pair in the table. You may mutate the value b ut not the key.
169 void foreach(void(*fn)(K, V*)) { fTable.foreach(ForEach, fn); }
170
171 private:
172 struct Pair {
173 K key;
174 V val;
175 static K GetKey(Pair p) { return p.key; }
176 static uint32_t Hash(K key) { return HashK(key); }
177 };
178 static void ForEach(Pair* p, void (*fn)(K, V*)) { fn(p->key, &p->val); }
179
180 SkTHashTable<Pair, K> fTable;
181 };
182
183 // A set of T. T is treated as an ordiary copyable C++ type.
184 template <typename T, uint32_t(*HashT)(T)>
185 class SkTHashSet : SkNoncopyable {
186 public:
187 SkTHashSet() {}
188
189 // How many items are in the set?
190 int count() const { return fTable.count(); }
191
192 // Copy an item into the set.
193 void add(T item) { fTable.set(item); }
194
195 // Is this item in the set?
196 bool contains(T item) const { return SkToBool(fTable.find(item)); }
197
198 private:
199 struct Traits {
200 static T GetKey(T item) { return item; }
201 static uint32_t Hash(T item) { return HashT(item); }
202 };
203 SkTHashTable<T, T, Traits> fTable;
204 };
205
206 #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