Blender V2.61 - r43446

btHashMap.h

Go to the documentation of this file.
00001 #ifndef BT_HASH_MAP_H
00002 #define BT_HASH_MAP_H
00003 
00004 #include "btAlignedObjectArray.h"
00005 
00007 struct btHashString
00008 {
00009     const char* m_string;
00010     unsigned int    m_hash;
00011 
00012     SIMD_FORCE_INLINE   unsigned int getHash()const
00013     {
00014         return m_hash;
00015     }
00016 
00017     btHashString(const char* name)
00018         :m_string(name)
00019     {
00020         /* magic numbers from http://www.isthe.com/chongo/tech/comp/fnv/ */
00021         static const unsigned int  InitialFNV = 2166136261u;
00022         static const unsigned int FNVMultiple = 16777619u;
00023 
00024         /* Fowler / Noll / Vo (FNV) Hash */
00025         unsigned int hash = InitialFNV;
00026         
00027         for(int i = 0; m_string[i]; i++)
00028         {
00029             hash = hash ^ (m_string[i]);       /* xor  the low 8 bits */
00030             hash = hash * FNVMultiple;  /* multiply by the magic number */
00031         }
00032         m_hash = hash;
00033     }
00034 
00035     int portableStringCompare(const char* src,  const char* dst) const
00036     {
00037             int ret = 0 ;
00038 
00039             while( ! (ret = *(unsigned char *)src - *(unsigned char *)dst) && *dst)
00040                     ++src, ++dst;
00041 
00042             if ( ret < 0 )
00043                     ret = -1 ;
00044             else if ( ret > 0 )
00045                     ret = 1 ;
00046 
00047             return( ret );
00048     }
00049 
00050     bool equals(const btHashString& other) const
00051     {
00052         return (m_string == other.m_string) ||
00053             (0==portableStringCompare(m_string,other.m_string));
00054 
00055     }
00056 
00057 };
00058 
00059 const int BT_HASH_NULL=0xffffffff;
00060 
00061 
00062 class btHashInt
00063 {
00064     int m_uid;
00065 public:
00066     btHashInt(int uid)  :m_uid(uid)
00067     {
00068     }
00069 
00070     int getUid1() const
00071     {
00072         return m_uid;
00073     }
00074 
00075     void    setUid1(int uid)
00076     {
00077         m_uid = uid;
00078     }
00079 
00080     bool equals(const btHashInt& other) const
00081     {
00082         return getUid1() == other.getUid1();
00083     }
00084     //to our success
00085     SIMD_FORCE_INLINE   unsigned int getHash()const
00086     {
00087         int key = m_uid;
00088         // Thomas Wang's hash
00089         key += ~(key << 15);    key ^=  (key >> 10);    key +=  (key << 3); key ^=  (key >> 6); key += ~(key << 11);    key ^=  (key >> 16);
00090         return key;
00091     }
00092 };
00093 
00094 
00095 
00096 class btHashPtr
00097 {
00098 
00099     union
00100     {
00101         const void* m_pointer;
00102         int m_hashValues[2];
00103     };
00104 
00105 public:
00106 
00107     btHashPtr(const void* ptr)
00108         :m_pointer(ptr)
00109     {
00110     }
00111 
00112     const void* getPointer() const
00113     {
00114         return m_pointer;
00115     }
00116 
00117     bool equals(const btHashPtr& other) const
00118     {
00119         return getPointer() == other.getPointer();
00120     }
00121 
00122     //to our success
00123     SIMD_FORCE_INLINE   unsigned int getHash()const
00124     {
00125         const bool VOID_IS_8 = ((sizeof(void*)==8));
00126         
00127         int key = VOID_IS_8? m_hashValues[0]+m_hashValues[1] : m_hashValues[0];
00128     
00129         // Thomas Wang's hash
00130         key += ~(key << 15);    key ^=  (key >> 10);    key +=  (key << 3); key ^=  (key >> 6); key += ~(key << 11);    key ^=  (key >> 16);
00131         return key;
00132     }
00133 
00134     
00135 };
00136 
00137 
00138 template <class Value>
00139 class btHashKeyPtr
00140 {
00141         int     m_uid;
00142 public:
00143 
00144         btHashKeyPtr(int uid)    :m_uid(uid)
00145         {
00146         }
00147 
00148         int     getUid1() const
00149         {
00150                 return m_uid;
00151         }
00152 
00153         bool equals(const btHashKeyPtr<Value>& other) const
00154         {
00155                 return getUid1() == other.getUid1();
00156         }
00157 
00158         //to our success
00159         SIMD_FORCE_INLINE       unsigned int getHash()const
00160         {
00161                 int key = m_uid;
00162                 // Thomas Wang's hash
00163                 key += ~(key << 15);    key ^=  (key >> 10);    key +=  (key << 3); key ^=  (key >> 6); key += ~(key << 11);    key ^=  (key >> 16);
00164                 return key;
00165         }
00166 
00167         
00168 };
00169 
00170 
00171 template <class Value>
00172 class btHashKey
00173 {
00174     int m_uid;
00175 public:
00176 
00177     btHashKey(int uid)  :m_uid(uid)
00178     {
00179     }
00180 
00181     int getUid1() const
00182     {
00183         return m_uid;
00184     }
00185 
00186     bool equals(const btHashKey<Value>& other) const
00187     {
00188         return getUid1() == other.getUid1();
00189     }
00190     //to our success
00191     SIMD_FORCE_INLINE   unsigned int getHash()const
00192     {
00193         int key = m_uid;
00194         // Thomas Wang's hash
00195         key += ~(key << 15);    key ^=  (key >> 10);    key +=  (key << 3); key ^=  (key >> 6); key += ~(key << 11);    key ^=  (key >> 16);
00196         return key;
00197     }
00198 };
00199 
00200 
00203 template <class Key, class Value>
00204 class btHashMap
00205 {
00206 
00207 protected:
00208     btAlignedObjectArray<int>       m_hashTable;
00209     btAlignedObjectArray<int>       m_next;
00210     
00211     btAlignedObjectArray<Value>     m_valueArray;
00212     btAlignedObjectArray<Key>       m_keyArray;
00213 
00214     void    growTables(const Key& /*key*/)
00215     {
00216         int newCapacity = m_valueArray.capacity();
00217 
00218         if (m_hashTable.size() < newCapacity)
00219         {
00220             //grow hashtable and next table
00221             int curHashtableSize = m_hashTable.size();
00222 
00223             m_hashTable.resize(newCapacity);
00224             m_next.resize(newCapacity);
00225 
00226             int i;
00227 
00228             for (i= 0; i < newCapacity; ++i)
00229             {
00230                 m_hashTable[i] = BT_HASH_NULL;
00231             }
00232             for (i = 0; i < newCapacity; ++i)
00233             {
00234                 m_next[i] = BT_HASH_NULL;
00235             }
00236 
00237             for(i=0;i<curHashtableSize;i++)
00238             {
00239                 //const Value& value = m_valueArray[i];
00240                 //const Key& key = m_keyArray[i];
00241 
00242                 int hashValue = m_keyArray[i].getHash() & (m_valueArray.capacity()-1);  // New hash value with new mask
00243                 m_next[i] = m_hashTable[hashValue];
00244                 m_hashTable[hashValue] = i;
00245             }
00246 
00247 
00248         }
00249     }
00250 
00251     public:
00252 
00253     void insert(const Key& key, const Value& value) {
00254         int hash = key.getHash() & (m_valueArray.capacity()-1);
00255 
00256         //replace value if the key is already there
00257         int index = findIndex(key);
00258         if (index != BT_HASH_NULL)
00259         {
00260             m_valueArray[index]=value;
00261             return;
00262         }
00263 
00264         int count = m_valueArray.size();
00265         int oldCapacity = m_valueArray.capacity();
00266         m_valueArray.push_back(value);
00267         m_keyArray.push_back(key);
00268 
00269         int newCapacity = m_valueArray.capacity();
00270         if (oldCapacity < newCapacity)
00271         {
00272             growTables(key);
00273             //hash with new capacity
00274             hash = key.getHash() & (m_valueArray.capacity()-1);
00275         }
00276         m_next[count] = m_hashTable[hash];
00277         m_hashTable[hash] = count;
00278     }
00279 
00280     void remove(const Key& key) {
00281 
00282         int hash = key.getHash() & (m_valueArray.capacity()-1);
00283 
00284         int pairIndex = findIndex(key);
00285         
00286         if (pairIndex ==BT_HASH_NULL)
00287         {
00288             return;
00289         }
00290 
00291         // Remove the pair from the hash table.
00292         int index = m_hashTable[hash];
00293         btAssert(index != BT_HASH_NULL);
00294 
00295         int previous = BT_HASH_NULL;
00296         while (index != pairIndex)
00297         {
00298             previous = index;
00299             index = m_next[index];
00300         }
00301 
00302         if (previous != BT_HASH_NULL)
00303         {
00304             btAssert(m_next[previous] == pairIndex);
00305             m_next[previous] = m_next[pairIndex];
00306         }
00307         else
00308         {
00309             m_hashTable[hash] = m_next[pairIndex];
00310         }
00311 
00312         // We now move the last pair into spot of the
00313         // pair being removed. We need to fix the hash
00314         // table indices to support the move.
00315 
00316         int lastPairIndex = m_valueArray.size() - 1;
00317 
00318         // If the removed pair is the last pair, we are done.
00319         if (lastPairIndex == pairIndex)
00320         {
00321             m_valueArray.pop_back();
00322             m_keyArray.pop_back();
00323             return;
00324         }
00325 
00326         // Remove the last pair from the hash table.
00327         int lastHash = m_keyArray[lastPairIndex].getHash() & (m_valueArray.capacity()-1);
00328 
00329         index = m_hashTable[lastHash];
00330         btAssert(index != BT_HASH_NULL);
00331 
00332         previous = BT_HASH_NULL;
00333         while (index != lastPairIndex)
00334         {
00335             previous = index;
00336             index = m_next[index];
00337         }
00338 
00339         if (previous != BT_HASH_NULL)
00340         {
00341             btAssert(m_next[previous] == lastPairIndex);
00342             m_next[previous] = m_next[lastPairIndex];
00343         }
00344         else
00345         {
00346             m_hashTable[lastHash] = m_next[lastPairIndex];
00347         }
00348 
00349         // Copy the last pair into the remove pair's spot.
00350         m_valueArray[pairIndex] = m_valueArray[lastPairIndex];
00351         m_keyArray[pairIndex] = m_keyArray[lastPairIndex];
00352 
00353         // Insert the last pair into the hash table
00354         m_next[pairIndex] = m_hashTable[lastHash];
00355         m_hashTable[lastHash] = pairIndex;
00356 
00357         m_valueArray.pop_back();
00358         m_keyArray.pop_back();
00359 
00360     }
00361 
00362 
00363     int size() const
00364     {
00365         return m_valueArray.size();
00366     }
00367 
00368     const Value* getAtIndex(int index) const
00369     {
00370         btAssert(index < m_valueArray.size());
00371 
00372         return &m_valueArray[index];
00373     }
00374 
00375     Value* getAtIndex(int index)
00376     {
00377         btAssert(index < m_valueArray.size());
00378 
00379         return &m_valueArray[index];
00380     }
00381 
00382     Value* operator[](const Key& key) {
00383         return find(key);
00384     }
00385 
00386     const Value*    find(const Key& key) const
00387     {
00388         int index = findIndex(key);
00389         if (index == BT_HASH_NULL)
00390         {
00391             return NULL;
00392         }
00393         return &m_valueArray[index];
00394     }
00395 
00396     Value*  find(const Key& key)
00397     {
00398         int index = findIndex(key);
00399         if (index == BT_HASH_NULL)
00400         {
00401             return NULL;
00402         }
00403         return &m_valueArray[index];
00404     }
00405 
00406 
00407     int findIndex(const Key& key) const
00408     {
00409         unsigned int hash = key.getHash() & (m_valueArray.capacity()-1);
00410 
00411         if (hash >= (unsigned int)m_hashTable.size())
00412         {
00413             return BT_HASH_NULL;
00414         }
00415 
00416         int index = m_hashTable[hash];
00417         while ((index != BT_HASH_NULL) && key.equals(m_keyArray[index]) == false)
00418         {
00419             index = m_next[index];
00420         }
00421         return index;
00422     }
00423 
00424     void    clear()
00425     {
00426         m_hashTable.clear();
00427         m_next.clear();
00428         m_valueArray.clear();
00429         m_keyArray.clear();
00430     }
00431 
00432 };
00433 
00434 #endif //BT_HASH_MAP_H