Blender  V2.59
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