1 /* 2 Copyright 2010 Google Inc. 3 4 Licensed under the Apache License, Version 2.0 (the "License"); 5 you may not use this file except in compliance with the License. 6 You may obtain a copy of the License at 7 8 http://www.apache.org/licenses/LICENSE-2.0 9 10 Unless required by applicable law or agreed to in writing, software 11 distributed under the License is distributed on an "AS IS" BASIS, 12 WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 13 See the License for the specific language governing permissions and 14 limitations under the License. 15 */ 16 17 18 #ifndef GrTHashCache_DEFINED 19 #define GrTHashCache_DEFINED 20 21 #include "GrTDArray.h" 22 23 /** 24 * Key needs 25 * static bool EQ(const Entry&, const HashKey&); 26 * static bool LT(const Entry&, const HashKey&); 27 * uint32_t getHash() const; 28 * 29 * Allows duplicate key entries but on find you may get 30 * any of the duplicate entries returned. 31 */ 32 template <typename T, typename Key, size_t kHashBits> class GrTHashTable { 33 public: 34 GrTHashTable() { Gr_bzero(fHash, sizeof(fHash)); } 35 ~GrTHashTable() {} 36 37 int count() const { return fSorted.count(); } 38 T* find(const Key&) const; 39 // return true if key was unique when inserted. 40 bool insert(const Key&, T*); 41 void remove(const Key&, const T*); 42 T* removeAt(int index, uint32_t hash); 43 void removeAll(); 44 void deleteAll(); 45 void unrefAll(); 46 47 /** 48 * Return the index for the element, using a linear search. 49 */ 50 int slowFindIndex(T* elem) const { return fSorted.find(elem); } 51 52 #if GR_DEBUG 53 void validate() const; 54 bool contains(T*) const; 55 #endif 56 57 // testing 58 const GrTDArray<T*>& getArray() const { return fSorted; } 59 private: 60 enum { 61 kHashCount = 1 << kHashBits, 62 kHashMask = kHashCount - 1 63 }; 64 static unsigned hash2Index(uint32_t hash) { 65 hash ^= hash >> 16; 66 if (kHashBits <= 8) { 67 hash ^= hash >> 8; 68 } 69 return hash & kHashMask; 70 } 71 72 mutable T* fHash[kHashCount]; 73 GrTDArray<T*> fSorted; 74 75 // search fSorted, and return the found index, or ~index of where it 76 // should be inserted 77 int searchArray(const Key&) const; 78 }; 79 80 /////////////////////////////////////////////////////////////////////////////// 81 82 template <typename T, typename Key, size_t kHashBits> 83 int GrTHashTable<T, Key, kHashBits>::searchArray(const Key& key) const { 84 int count = fSorted.count(); 85 if (0 == count) { 86 // we should insert it at 0 87 return ~0; 88 } 89 90 const T* const* array = fSorted.begin(); 91 int high = count - 1; 92 int low = 0; 93 while (high > low) { 94 int index = (low + high) >> 1; 95 if (Key::LT(*array[index], key)) { 96 low = index + 1; 97 } else { 98 high = index; 99 } 100 } 101 102 // check if we found it 103 if (Key::EQ(*array[high], key)) { 104 // above search should have found the first occurrence if there 105 // are multiple. 106 GrAssert(0 == high || Key::LT(*array[high - 1], key)); 107 return high; 108 } 109 110 // now return the ~ of where we should insert it 111 if (Key::LT(*array[high], key)) { 112 high += 1; 113 } 114 return ~high; 115 } 116 117 template <typename T, typename Key, size_t kHashBits> 118 T* GrTHashTable<T, Key, kHashBits>::find(const Key& key) const { 119 int hashIndex = hash2Index(key.getHash()); 120 T* elem = fHash[hashIndex]; 121 122 if (NULL == elem || !Key::EQ(*elem, key)) { 123 // bsearch for the key in our sorted array 124 int index = this->searchArray(key); 125 if (index < 0) { 126 return NULL; 127 } 128 elem = fSorted[index]; 129 // update the hash 130 fHash[hashIndex] = elem; 131 } 132 return elem; 133 } 134 135 template <typename T, typename Key, size_t kHashBits> 136 bool GrTHashTable<T, Key, kHashBits>::insert(const Key& key, T* elem) { 137 int index = this->searchArray(key); 138 bool first = index < 0; 139 if (first) { 140 // turn it into the actual index 141 index = ~index; 142 } 143 // add it to our array 144 *fSorted.insert(index) = elem; 145 // update our hash table (overwrites any dupe's position in the hash) 146 fHash[hash2Index(key.getHash())] = elem; 147 return first; 148 } 149 150 template <typename T, typename Key, size_t kHashBits> 151 void GrTHashTable<T, Key, kHashBits>::remove(const Key& key, const T* elem) { 152 int index = hash2Index(key.getHash()); 153 if (fHash[index] == elem) { 154 fHash[index] = NULL; 155 } 156 157 // remove from our sorted array 158 index = this->searchArray(key); 159 GrAssert(index >= 0); 160 // if there are multiple matches searchArray will give us the first match 161 // march forward until we find elem. 162 while (elem != fSorted[index]) { 163 ++index; 164 GrAssert(index < fSorted.count()); 165 } 166 GrAssert(elem == fSorted[index]); 167 fSorted.remove(index); 168 } 169 170 template <typename T, typename Key, size_t kHashBits> 171 T* GrTHashTable<T, Key, kHashBits>::removeAt(int elemIndex, uint32_t hash) { 172 int hashIndex = hash2Index(hash); 173 if (fHash[hashIndex] == fSorted[elemIndex]) { 174 fHash[hashIndex] = NULL; 175 } 176 // remove from our sorted array 177 T* elem = fSorted[elemIndex]; 178 fSorted.remove(elemIndex); 179 return elem; 180 } 181 182 template <typename T, typename Key, size_t kHashBits> 183 void GrTHashTable<T, Key, kHashBits>::removeAll() { 184 fSorted.reset(); 185 Gr_bzero(fHash, sizeof(fHash)); 186 } 187 188 template <typename T, typename Key, size_t kHashBits> 189 void GrTHashTable<T, Key, kHashBits>::deleteAll() { 190 fSorted.deleteAll(); 191 Gr_bzero(fHash, sizeof(fHash)); 192 } 193 194 template <typename T, typename Key, size_t kHashBits> 195 void GrTHashTable<T, Key, kHashBits>::unrefAll() { 196 fSorted.unrefAll(); 197 Gr_bzero(fHash, sizeof(fHash)); 198 } 199 200 #if GR_DEBUG 201 template <typename T, typename Key, size_t kHashBits> 202 void GrTHashTable<T, Key, kHashBits>::validate() const { 203 for (size_t i = 0; i < GR_ARRAY_COUNT(fHash); i++) { 204 if (fHash[i]) { 205 unsigned hashIndex = hash2Index(Key::GetHash(*fHash[i])); 206 GrAssert(hashIndex == i); 207 } 208 } 209 210 int count = fSorted.count(); 211 for (int i = 1; i < count; i++) { 212 GrAssert(Key::LT(*fSorted[i - 1], *fSorted[i]) || 213 Key::EQ(*fSorted[i - 1], *fSorted[i])); 214 } 215 } 216 217 template <typename T, typename Key, size_t kHashBits> 218 bool GrTHashTable<T, Key, kHashBits>::contains(T* elem) const { 219 int index = fSorted.find(elem); 220 return index >= 0; 221 } 222 223 #endif 224 225 #endif 226 227