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