diff options
Diffstat (limited to 'thirdparty/bullet/Bullet3Common/b3HashMap.h')
-rw-r--r-- | thirdparty/bullet/Bullet3Common/b3HashMap.h | 466 |
1 files changed, 466 insertions, 0 deletions
diff --git a/thirdparty/bullet/Bullet3Common/b3HashMap.h b/thirdparty/bullet/Bullet3Common/b3HashMap.h new file mode 100644 index 0000000000..24a59d9baa --- /dev/null +++ b/thirdparty/bullet/Bullet3Common/b3HashMap.h @@ -0,0 +1,466 @@ +/* +Bullet Continuous Collision Detection and Physics Library +Copyright (c) 2003-2013 Erwin Coumans http://bulletphysics.org + +This software is provided 'as-is', without any express or implied warranty. +In no event will the authors be held liable for any damages arising from the use of this software. +Permission is granted to anyone to use this software for any purpose, +including commercial applications, and to alter it and redistribute it freely, +subject to the following restrictions: + +1. The origin of this software must not be misrepresented; you must not claim that you wrote the original software. If you use this software in a product, an acknowledgment in the product documentation would be appreciated but is not required. +2. Altered source versions must be plainly marked as such, and must not be misrepresented as being the original software. +3. This notice may not be removed or altered from any source distribution. +*/ + + +#ifndef B3_HASH_MAP_H +#define B3_HASH_MAP_H + +#include "b3AlignedObjectArray.h" + + +#include <string> + +///very basic hashable string implementation, compatible with b3HashMap +struct b3HashString +{ + std::string m_string; + unsigned int m_hash; + + B3_FORCE_INLINE unsigned int getHash()const + { + return m_hash; + } + + + b3HashString(const char* name) + :m_string(name) + { + + /* magic numbers from http://www.isthe.com/chongo/tech/comp/fnv/ */ + static const unsigned int InitialFNV = 2166136261u; + static const unsigned int FNVMultiple = 16777619u; + + /* Fowler / Noll / Vo (FNV) Hash */ + unsigned int hash = InitialFNV; + int len = m_string.length(); + for(int i = 0; i<len; i++) + { + hash = hash ^ (m_string[i]); /* xor the low 8 bits */ + hash = hash * FNVMultiple; /* multiply by the magic number */ + } + m_hash = hash; + } + + int portableStringCompare(const char* src, const char* dst) const + { + int ret = 0 ; + + while( ! (ret = *(unsigned char *)src - *(unsigned char *)dst) && *dst) + ++src, ++dst; + + if ( ret < 0 ) + ret = -1 ; + else if ( ret > 0 ) + ret = 1 ; + + return( ret ); + } + + bool equals(const b3HashString& other) const + { + return (m_string == other.m_string); + } + +}; + + +const int B3_HASH_NULL=0xffffffff; + + +class b3HashInt +{ + int m_uid; +public: + b3HashInt(int uid) :m_uid(uid) + { + } + + int getUid1() const + { + return m_uid; + } + + void setUid1(int uid) + { + m_uid = uid; + } + + bool equals(const b3HashInt& other) const + { + return getUid1() == other.getUid1(); + } + //to our success + B3_FORCE_INLINE unsigned int getHash()const + { + int key = m_uid; + // Thomas Wang's hash + key += ~(key << 15); key ^= (key >> 10); key += (key << 3); key ^= (key >> 6); key += ~(key << 11); key ^= (key >> 16); + return key; + } +}; + + + +class b3HashPtr +{ + + union + { + const void* m_pointer; + int m_hashValues[2]; + }; + +public: + + b3HashPtr(const void* ptr) + :m_pointer(ptr) + { + } + + const void* getPointer() const + { + return m_pointer; + } + + bool equals(const b3HashPtr& other) const + { + return getPointer() == other.getPointer(); + } + + //to our success + B3_FORCE_INLINE unsigned int getHash()const + { + const bool VOID_IS_8 = ((sizeof(void*)==8)); + + int key = VOID_IS_8? m_hashValues[0]+m_hashValues[1] : m_hashValues[0]; + + // Thomas Wang's hash + key += ~(key << 15); key ^= (key >> 10); key += (key << 3); key ^= (key >> 6); key += ~(key << 11); key ^= (key >> 16); + return key; + } + + +}; + + +template <class Value> +class b3HashKeyPtr +{ + int m_uid; +public: + + b3HashKeyPtr(int uid) :m_uid(uid) + { + } + + int getUid1() const + { + return m_uid; + } + + bool equals(const b3HashKeyPtr<Value>& other) const + { + return getUid1() == other.getUid1(); + } + + //to our success + B3_FORCE_INLINE unsigned int getHash()const + { + int key = m_uid; + // Thomas Wang's hash + key += ~(key << 15); key ^= (key >> 10); key += (key << 3); key ^= (key >> 6); key += ~(key << 11); key ^= (key >> 16); + return key; + } + + +}; + + +template <class Value> +class b3HashKey +{ + int m_uid; +public: + + b3HashKey(int uid) :m_uid(uid) + { + } + + int getUid1() const + { + return m_uid; + } + + bool equals(const b3HashKey<Value>& other) const + { + return getUid1() == other.getUid1(); + } + //to our success + B3_FORCE_INLINE unsigned int getHash()const + { + int key = m_uid; + // Thomas Wang's hash + key += ~(key << 15); key ^= (key >> 10); key += (key << 3); key ^= (key >> 6); key += ~(key << 11); key ^= (key >> 16); + return key; + } +}; + + +///The b3HashMap template class implements a generic and lightweight hashmap. +///A basic sample of how to use b3HashMap is located in Demos\BasicDemo\main.cpp +template <class Key, class Value> +class b3HashMap +{ + +protected: + b3AlignedObjectArray<int> m_hashTable; + b3AlignedObjectArray<int> m_next; + + b3AlignedObjectArray<Value> m_valueArray; + b3AlignedObjectArray<Key> m_keyArray; + + void growTables(const Key& /*key*/) + { + int newCapacity = m_valueArray.capacity(); + + if (m_hashTable.size() < newCapacity) + { + //grow hashtable and next table + int curHashtableSize = m_hashTable.size(); + + m_hashTable.resize(newCapacity); + m_next.resize(newCapacity); + + int i; + + for (i= 0; i < newCapacity; ++i) + { + m_hashTable[i] = B3_HASH_NULL; + } + for (i = 0; i < newCapacity; ++i) + { + m_next[i] = B3_HASH_NULL; + } + + for(i=0;i<curHashtableSize;i++) + { + //const Value& value = m_valueArray[i]; + //const Key& key = m_keyArray[i]; + + int hashValue = m_keyArray[i].getHash() & (m_valueArray.capacity()-1); // New hash value with new mask + m_next[i] = m_hashTable[hashValue]; + m_hashTable[hashValue] = i; + } + + + } + } + + public: + + void insert(const Key& key, const Value& value) { + int hash = key.getHash() & (m_valueArray.capacity()-1); + + //replace value if the key is already there + int index = findIndex(key); + if (index != B3_HASH_NULL) + { + m_valueArray[index]=value; + return; + } + + int count = m_valueArray.size(); + int oldCapacity = m_valueArray.capacity(); + m_valueArray.push_back(value); + m_keyArray.push_back(key); + + int newCapacity = m_valueArray.capacity(); + if (oldCapacity < newCapacity) + { + growTables(key); + //hash with new capacity + hash = key.getHash() & (m_valueArray.capacity()-1); + } + m_next[count] = m_hashTable[hash]; + m_hashTable[hash] = count; + } + + void remove(const Key& key) { + + int hash = key.getHash() & (m_valueArray.capacity()-1); + + int pairIndex = findIndex(key); + + if (pairIndex ==B3_HASH_NULL) + { + return; + } + + // Remove the pair from the hash table. + int index = m_hashTable[hash]; + b3Assert(index != B3_HASH_NULL); + + int previous = B3_HASH_NULL; + while (index != pairIndex) + { + previous = index; + index = m_next[index]; + } + + if (previous != B3_HASH_NULL) + { + b3Assert(m_next[previous] == pairIndex); + m_next[previous] = m_next[pairIndex]; + } + else + { + m_hashTable[hash] = m_next[pairIndex]; + } + + // We now move the last pair into spot of the + // pair being removed. We need to fix the hash + // table indices to support the move. + + int lastPairIndex = m_valueArray.size() - 1; + + // If the removed pair is the last pair, we are done. + if (lastPairIndex == pairIndex) + { + m_valueArray.pop_back(); + m_keyArray.pop_back(); + return; + } + + // Remove the last pair from the hash table. + int lastHash = m_keyArray[lastPairIndex].getHash() & (m_valueArray.capacity()-1); + + index = m_hashTable[lastHash]; + b3Assert(index != B3_HASH_NULL); + + previous = B3_HASH_NULL; + while (index != lastPairIndex) + { + previous = index; + index = m_next[index]; + } + + if (previous != B3_HASH_NULL) + { + b3Assert(m_next[previous] == lastPairIndex); + m_next[previous] = m_next[lastPairIndex]; + } + else + { + m_hashTable[lastHash] = m_next[lastPairIndex]; + } + + // Copy the last pair into the remove pair's spot. + m_valueArray[pairIndex] = m_valueArray[lastPairIndex]; + m_keyArray[pairIndex] = m_keyArray[lastPairIndex]; + + // Insert the last pair into the hash table + m_next[pairIndex] = m_hashTable[lastHash]; + m_hashTable[lastHash] = pairIndex; + + m_valueArray.pop_back(); + m_keyArray.pop_back(); + + } + + + int size() const + { + return m_valueArray.size(); + } + + const Value* getAtIndex(int index) const + { + b3Assert(index < m_valueArray.size()); + + return &m_valueArray[index]; + } + + Value* getAtIndex(int index) + { + b3Assert(index < m_valueArray.size()); + + return &m_valueArray[index]; + } + + Key getKeyAtIndex(int index) + { + b3Assert(index < m_keyArray.size()); + return m_keyArray[index]; + } + + const Key getKeyAtIndex(int index) const + { + b3Assert(index < m_keyArray.size()); + return m_keyArray[index]; + } + + Value* operator[](const Key& key) { + return find(key); + } + + const Value* find(const Key& key) const + { + int index = findIndex(key); + if (index == B3_HASH_NULL) + { + return NULL; + } + return &m_valueArray[index]; + } + + Value* find(const Key& key) + { + int index = findIndex(key); + if (index == B3_HASH_NULL) + { + return NULL; + } + return &m_valueArray[index]; + } + + + int findIndex(const Key& key) const + { + unsigned int hash = key.getHash() & (m_valueArray.capacity()-1); + + if (hash >= (unsigned int)m_hashTable.size()) + { + return B3_HASH_NULL; + } + + int index = m_hashTable[hash]; + while ((index != B3_HASH_NULL) && key.equals(m_keyArray[index]) == false) + { + index = m_next[index]; + } + return index; + } + + void clear() + { + m_hashTable.clear(); + m_next.clear(); + m_valueArray.clear(); + m_keyArray.clear(); + } + +}; + +#endif //B3_HASH_MAP_H |