diff -r 000000000000 -r 6474c204b198 gfx/skia/trunk/src/gpu/GrTHashTable.h --- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/gfx/skia/trunk/src/gpu/GrTHashTable.h Wed Dec 31 06:09:35 2014 +0100 @@ -0,0 +1,210 @@ + +/* + * Copyright 2010 Google Inc. + * + * Use of this source code is governed by a BSD-style license that can be + * found in the LICENSE file. + */ + + + +#ifndef GrTHashTable_DEFINED +#define GrTHashTable_DEFINED + +#include "GrTypes.h" +#include "SkTDArray.h" + +/** + * Key needs + * static bool Equals(const Entry&, const Key&); + * static bool LessThan(const Entry&, const Key&); + * static bool Equals(const Entry&, const Entry&); for SK_DEBUG if GrTHashTable::validate() is called + * static bool LessThan(const Entry&, const Entry&); for SK_DEBUG if GrTHashTable::validate() is called + * uint32_t getHash() const; + * + * Allows duplicate key entries but on find you may get + * any of the duplicate entries returned. + */ +template class GrTHashTable { +public: + GrTHashTable() { this->clearHash(); } + ~GrTHashTable() {} + + int count() const { return fSorted.count(); } + + struct Any { + // Return the first resource that matches the key. + bool operator()(const T*) const { return true; } + }; + + T* find(const Key& key) const { return this->find(key, Any()); } + template T* find(const Key&, Filter filter) const; + + // return true if key was unique when inserted. + bool insert(const Key&, T*); + void remove(const Key&, const T*); + + void deleteAll(); + +#ifdef SK_DEBUG + void validate() const; + bool contains(T*) const; +#endif + + // testing + const SkTDArray& getArray() const { return fSorted; } + SkTDArray& getArray() { return fSorted; } +private: + void clearHash() { sk_bzero(fHash, sizeof(fHash)); } + + enum { + kHashCount = 1 << kHashBits, + kHashMask = kHashCount - 1 + }; + static unsigned hash2Index(uint32_t hash) { + hash ^= hash >> 16; + if (kHashBits <= 8) { + hash ^= hash >> 8; + } + return hash & kHashMask; + } + + mutable T* fHash[kHashCount]; + SkTDArray fSorted; + + // search fSorted, and return the found index, or ~index of where it + // should be inserted + int searchArray(const Key&) const; +}; + +/////////////////////////////////////////////////////////////////////////////// + +template +int GrTHashTable::searchArray(const Key& key) const { + int count = fSorted.count(); + if (0 == count) { + // we should insert it at 0 + return ~0; + } + + const T* const* array = fSorted.begin(); + int high = count - 1; + int low = 0; + while (high > low) { + int index = (low + high) >> 1; + if (Key::LessThan(*array[index], key)) { + low = index + 1; + } else { + high = index; + } + } + + // check if we found it + if (Key::Equals(*array[high], key)) { + // above search should have found the first occurrence if there + // are multiple. + SkASSERT(0 == high || Key::LessThan(*array[high - 1], key)); + return high; + } + + // now return the ~ of where we should insert it + if (Key::LessThan(*array[high], key)) { + high += 1; + } + return ~high; +} + +template +template +T* GrTHashTable::find(const Key& key, Filter filter) const { + + int hashIndex = hash2Index(key.getHash()); + T* elem = fHash[hashIndex]; + + if (NULL != elem && Key::Equals(*elem, key) && filter(elem)) { + return elem; + } + + // bsearch for the key in our sorted array + int index = this->searchArray(key); + if (index < 0) { + return NULL; + } + + const T* const* array = fSorted.begin(); + + // above search should have found the first occurrence if there + // are multiple. + SkASSERT(0 == index || Key::LessThan(*array[index - 1], key)); + + for ( ; index < count() && Key::Equals(*array[index], key); ++index) { + if (filter(fSorted[index])) { + // update the hash + fHash[hashIndex] = fSorted[index]; + return fSorted[index]; + } + } + + return NULL; +} + +template +bool GrTHashTable::insert(const Key& key, T* elem) { + int index = this->searchArray(key); + bool first = index < 0; + if (first) { + // turn it into the actual index + index = ~index; + } + // add it to our array + *fSorted.insert(index) = elem; + // update our hash table (overwrites any dupe's position in the hash) + fHash[hash2Index(key.getHash())] = elem; + return first; +} + +template +void GrTHashTable::remove(const Key& key, const T* elem) { + int index = hash2Index(key.getHash()); + if (fHash[index] == elem) { + fHash[index] = NULL; + } + + // remove from our sorted array + index = this->searchArray(key); + SkASSERT(index >= 0); + // if there are multiple matches searchArray will give us the first match + // march forward until we find elem. + while (elem != fSorted[index]) { + ++index; + SkASSERT(index < fSorted.count()); + } + SkASSERT(elem == fSorted[index]); + fSorted.remove(index); +} + +template +void GrTHashTable::deleteAll() { + fSorted.deleteAll(); + this->clearHash(); +} + +#ifdef SK_DEBUG +template +void GrTHashTable::validate() const { + int count = fSorted.count(); + for (int i = 1; i < count; i++) { + SkASSERT(Key::LessThan(*fSorted[i - 1], *fSorted[i]) || + Key::Equals(*fSorted[i - 1], *fSorted[i])); + } +} + +template +bool GrTHashTable::contains(T* elem) const { + int index = fSorted.find(elem); + return index >= 0; +} + +#endif + +#endif