OLD | NEW |
| (Empty) |
1 | |
2 /* | |
3 * Copyright 2010 Google Inc. | |
4 * | |
5 * Use of this source code is governed by a BSD-style license that can be | |
6 * found in the LICENSE file. | |
7 */ | |
8 | |
9 | |
10 | |
11 #ifndef GrTHashCache_DEFINED | |
12 #define GrTHashCache_DEFINED | |
13 | |
14 #include "GrTypes.h" | |
15 #include "SkTDArray.h" | |
16 | |
17 // GrTDefaultFindFunctor implements the default find behavior for | |
18 // GrTHashTable (i.e., return the first resource that matches the | |
19 // provided key) | |
20 template <typename T> class GrTDefaultFindFunctor { | |
21 public: | |
22 // always accept the first element examined | |
23 bool operator()(const T*) const { return true; } | |
24 }; | |
25 | |
26 /** | |
27 * Key needs | |
28 * static bool EQ(const Entry&, const HashKey&); | |
29 * static bool LT(const Entry&, const HashKey&); | |
30 * uint32_t getHash() const; | |
31 * | |
32 * Allows duplicate key entries but on find you may get | |
33 * any of the duplicate entries returned. | |
34 */ | |
35 template <typename T, typename Key, size_t kHashBits> class GrTHashTable { | |
36 public: | |
37 GrTHashTable() { sk_bzero(fHash, sizeof(fHash)); } | |
38 ~GrTHashTable() {} | |
39 | |
40 int count() const { return fSorted.count(); } | |
41 T* find(const Key&) const; | |
42 template <typename FindFuncType> T* find(const Key&, const FindFuncType&) c
onst; | |
43 // return true if key was unique when inserted. | |
44 bool insert(const Key&, T*); | |
45 void remove(const Key&, const T*); | |
46 T* removeAt(int index, uint32_t hash); | |
47 void removeAll(); | |
48 void deleteAll(); | |
49 void unrefAll(); | |
50 | |
51 /** | |
52 * Return the index for the element, using a linear search. | |
53 */ | |
54 int slowFindIndex(T* elem) const { return fSorted.find(elem); } | |
55 | |
56 #ifdef SK_DEBUG | |
57 void validate() const; | |
58 bool contains(T*) const; | |
59 #endif | |
60 | |
61 // testing | |
62 const SkTDArray<T*>& getArray() const { return fSorted; } | |
63 SkTDArray<T*>& getArray() { return fSorted; } | |
64 private: | |
65 enum { | |
66 kHashCount = 1 << kHashBits, | |
67 kHashMask = kHashCount - 1 | |
68 }; | |
69 static unsigned hash2Index(uint32_t hash) { | |
70 hash ^= hash >> 16; | |
71 if (kHashBits <= 8) { | |
72 hash ^= hash >> 8; | |
73 } | |
74 return hash & kHashMask; | |
75 } | |
76 | |
77 mutable T* fHash[kHashCount]; | |
78 SkTDArray<T*> fSorted; | |
79 | |
80 // search fSorted, and return the found index, or ~index of where it | |
81 // should be inserted | |
82 int searchArray(const Key&) const; | |
83 }; | |
84 | |
85 /////////////////////////////////////////////////////////////////////////////// | |
86 | |
87 template <typename T, typename Key, size_t kHashBits> | |
88 int GrTHashTable<T, Key, kHashBits>::searchArray(const Key& key) const { | |
89 int count = fSorted.count(); | |
90 if (0 == count) { | |
91 // we should insert it at 0 | |
92 return ~0; | |
93 } | |
94 | |
95 const T* const* array = fSorted.begin(); | |
96 int high = count - 1; | |
97 int low = 0; | |
98 while (high > low) { | |
99 int index = (low + high) >> 1; | |
100 if (Key::LT(*array[index], key)) { | |
101 low = index + 1; | |
102 } else { | |
103 high = index; | |
104 } | |
105 } | |
106 | |
107 // check if we found it | |
108 if (Key::EQ(*array[high], key)) { | |
109 // above search should have found the first occurrence if there | |
110 // are multiple. | |
111 SkASSERT(0 == high || Key::LT(*array[high - 1], key)); | |
112 return high; | |
113 } | |
114 | |
115 // now return the ~ of where we should insert it | |
116 if (Key::LT(*array[high], key)) { | |
117 high += 1; | |
118 } | |
119 return ~high; | |
120 } | |
121 | |
122 template <typename T, typename Key, size_t kHashBits> | |
123 T* GrTHashTable<T, Key, kHashBits>::find(const Key& key) const { | |
124 GrTDefaultFindFunctor<T> find; | |
125 | |
126 return this->find(key, find); | |
127 } | |
128 | |
129 template <typename T, typename Key, size_t kHashBits> | |
130 template <typename FindFuncType> | |
131 T* GrTHashTable<T, Key, kHashBits>::find(const Key& key, const FindFuncType& fin
dFunc) const { | |
132 | |
133 int hashIndex = hash2Index(key.getHash()); | |
134 T* elem = fHash[hashIndex]; | |
135 | |
136 if (NULL != elem && Key::EQ(*elem, key) && findFunc(elem)) { | |
137 return elem; | |
138 } | |
139 | |
140 // bsearch for the key in our sorted array | |
141 int index = this->searchArray(key); | |
142 if (index < 0) { | |
143 return NULL; | |
144 } | |
145 | |
146 const T* const* array = fSorted.begin(); | |
147 | |
148 // above search should have found the first occurrence if there | |
149 // are multiple. | |
150 SkASSERT(0 == index || Key::LT(*array[index - 1], key)); | |
151 | |
152 for ( ; index < count() && Key::EQ(*array[index], key); ++index) { | |
153 if (findFunc(fSorted[index])) { | |
154 // update the hash | |
155 fHash[hashIndex] = fSorted[index]; | |
156 return fSorted[index]; | |
157 } | |
158 } | |
159 | |
160 return NULL; | |
161 } | |
162 | |
163 template <typename T, typename Key, size_t kHashBits> | |
164 bool GrTHashTable<T, Key, kHashBits>::insert(const Key& key, T* elem) { | |
165 int index = this->searchArray(key); | |
166 bool first = index < 0; | |
167 if (first) { | |
168 // turn it into the actual index | |
169 index = ~index; | |
170 } | |
171 // add it to our array | |
172 *fSorted.insert(index) = elem; | |
173 // update our hash table (overwrites any dupe's position in the hash) | |
174 fHash[hash2Index(key.getHash())] = elem; | |
175 return first; | |
176 } | |
177 | |
178 template <typename T, typename Key, size_t kHashBits> | |
179 void GrTHashTable<T, Key, kHashBits>::remove(const Key& key, const T* elem) { | |
180 int index = hash2Index(key.getHash()); | |
181 if (fHash[index] == elem) { | |
182 fHash[index] = NULL; | |
183 } | |
184 | |
185 // remove from our sorted array | |
186 index = this->searchArray(key); | |
187 SkASSERT(index >= 0); | |
188 // if there are multiple matches searchArray will give us the first match | |
189 // march forward until we find elem. | |
190 while (elem != fSorted[index]) { | |
191 ++index; | |
192 SkASSERT(index < fSorted.count()); | |
193 } | |
194 SkASSERT(elem == fSorted[index]); | |
195 fSorted.remove(index); | |
196 } | |
197 | |
198 template <typename T, typename Key, size_t kHashBits> | |
199 T* GrTHashTable<T, Key, kHashBits>::removeAt(int elemIndex, uint32_t hash) { | |
200 int hashIndex = hash2Index(hash); | |
201 if (fHash[hashIndex] == fSorted[elemIndex]) { | |
202 fHash[hashIndex] = NULL; | |
203 } | |
204 // remove from our sorted array | |
205 T* elem = fSorted[elemIndex]; | |
206 fSorted.remove(elemIndex); | |
207 return elem; | |
208 } | |
209 | |
210 template <typename T, typename Key, size_t kHashBits> | |
211 void GrTHashTable<T, Key, kHashBits>::removeAll() { | |
212 fSorted.reset(); | |
213 sk_bzero(fHash, sizeof(fHash)); | |
214 } | |
215 | |
216 template <typename T, typename Key, size_t kHashBits> | |
217 void GrTHashTable<T, Key, kHashBits>::deleteAll() { | |
218 fSorted.deleteAll(); | |
219 sk_bzero(fHash, sizeof(fHash)); | |
220 } | |
221 | |
222 template <typename T, typename Key, size_t kHashBits> | |
223 void GrTHashTable<T, Key, kHashBits>::unrefAll() { | |
224 fSorted.unrefAll(); | |
225 sk_bzero(fHash, sizeof(fHash)); | |
226 } | |
227 | |
228 #ifdef SK_DEBUG | |
229 template <typename T, typename Key, size_t kHashBits> | |
230 void GrTHashTable<T, Key, kHashBits>::validate() const { | |
231 int count = fSorted.count(); | |
232 for (int i = 1; i < count; i++) { | |
233 SkASSERT(Key::LT(*fSorted[i - 1], *fSorted[i]) || | |
234 Key::EQ(*fSorted[i - 1], *fSorted[i])); | |
235 } | |
236 } | |
237 | |
238 template <typename T, typename Key, size_t kHashBits> | |
239 bool GrTHashTable<T, Key, kHashBits>::contains(T* elem) const { | |
240 int index = fSorted.find(elem); | |
241 return index >= 0; | |
242 } | |
243 | |
244 #endif | |
245 | |
246 #endif | |
OLD | NEW |