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