483 lines
		
	
	
		
			9.8 KiB
		
	
	
	
		
			C++
		
	
	
	
	
	
			
		
		
	
	
			483 lines
		
	
	
		
			9.8 KiB
		
	
	
	
		
			C++
		
	
	
	
	
	
/*
 | 
						|
Bullet Continuous Collision Detection and Physics Library
 | 
						|
Copyright (c) 2003-2009 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 BT_HASH_MAP_H
 | 
						|
#define BT_HASH_MAP_H
 | 
						|
 | 
						|
#include "btAlignedObjectArray.h"
 | 
						|
 | 
						|
///very basic hashable string implementation, compatible with btHashMap
 | 
						|
struct btHashString
 | 
						|
{
 | 
						|
	const char* m_string;
 | 
						|
	unsigned int	m_hash;
 | 
						|
 | 
						|
	SIMD_FORCE_INLINE	unsigned int getHash()const
 | 
						|
	{
 | 
						|
		return m_hash;
 | 
						|
	}
 | 
						|
 | 
						|
	btHashString(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;
 | 
						|
		
 | 
						|
		for(int i = 0; m_string[i]; 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 = *(const unsigned char *)src - *(const unsigned char *)dst) && *dst)
 | 
						|
					++src, ++dst;
 | 
						|
 | 
						|
			if ( ret < 0 )
 | 
						|
					ret = -1 ;
 | 
						|
			else if ( ret > 0 )
 | 
						|
					ret = 1 ;
 | 
						|
 | 
						|
			return( ret );
 | 
						|
	}
 | 
						|
 | 
						|
	bool equals(const btHashString& other) const
 | 
						|
	{
 | 
						|
		return (m_string == other.m_string) ||
 | 
						|
			(0==portableStringCompare(m_string,other.m_string));
 | 
						|
 | 
						|
	}
 | 
						|
 | 
						|
};
 | 
						|
 | 
						|
const int BT_HASH_NULL=0xffffffff;
 | 
						|
 | 
						|
 | 
						|
class btHashInt
 | 
						|
{
 | 
						|
	int	m_uid;
 | 
						|
public:
 | 
						|
 | 
						|
	btHashInt()
 | 
						|
	{
 | 
						|
	}
 | 
						|
 | 
						|
	btHashInt(int uid)	:m_uid(uid)
 | 
						|
	{
 | 
						|
	}
 | 
						|
 | 
						|
	int	getUid1() const
 | 
						|
	{
 | 
						|
		return m_uid;
 | 
						|
	}
 | 
						|
 | 
						|
	void	setUid1(int uid)
 | 
						|
	{
 | 
						|
		m_uid = uid;
 | 
						|
	}
 | 
						|
 | 
						|
	bool equals(const btHashInt& other) const
 | 
						|
	{
 | 
						|
		return getUid1() == other.getUid1();
 | 
						|
	}
 | 
						|
	//to our success
 | 
						|
	SIMD_FORCE_INLINE	unsigned int getHash()const
 | 
						|
	{
 | 
						|
		unsigned 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 btHashPtr
 | 
						|
{
 | 
						|
 | 
						|
	union
 | 
						|
	{
 | 
						|
		const void*	m_pointer;
 | 
						|
		unsigned int	m_hashValues[2];
 | 
						|
	};
 | 
						|
 | 
						|
public:
 | 
						|
 | 
						|
	btHashPtr(const void* ptr)
 | 
						|
		:m_pointer(ptr)
 | 
						|
	{
 | 
						|
	}
 | 
						|
 | 
						|
	const void*	getPointer() const
 | 
						|
	{
 | 
						|
		return m_pointer;
 | 
						|
	}
 | 
						|
 | 
						|
	bool equals(const btHashPtr& other) const
 | 
						|
	{
 | 
						|
		return getPointer() == other.getPointer();
 | 
						|
	}
 | 
						|
 | 
						|
	//to our success
 | 
						|
	SIMD_FORCE_INLINE	unsigned int getHash()const
 | 
						|
	{
 | 
						|
		const bool VOID_IS_8 = ((sizeof(void*)==8));
 | 
						|
		
 | 
						|
		unsigned 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 btHashKeyPtr
 | 
						|
{
 | 
						|
        int     m_uid;
 | 
						|
public:
 | 
						|
 | 
						|
        btHashKeyPtr(int uid)    :m_uid(uid)
 | 
						|
        {
 | 
						|
        }
 | 
						|
 | 
						|
        int     getUid1() const
 | 
						|
        {
 | 
						|
                return m_uid;
 | 
						|
        }
 | 
						|
 | 
						|
        bool equals(const btHashKeyPtr<Value>& other) const
 | 
						|
        {
 | 
						|
                return getUid1() == other.getUid1();
 | 
						|
        }
 | 
						|
 | 
						|
        //to our success
 | 
						|
        SIMD_FORCE_INLINE       unsigned int getHash()const
 | 
						|
        {
 | 
						|
                unsigned 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 btHashKey
 | 
						|
{
 | 
						|
	int	m_uid;
 | 
						|
public:
 | 
						|
 | 
						|
	btHashKey(int uid)	:m_uid(uid)
 | 
						|
	{
 | 
						|
	}
 | 
						|
 | 
						|
	int	getUid1() const
 | 
						|
	{
 | 
						|
		return m_uid;
 | 
						|
	}
 | 
						|
 | 
						|
	bool equals(const btHashKey<Value>& other) const
 | 
						|
	{
 | 
						|
		return getUid1() == other.getUid1();
 | 
						|
	}
 | 
						|
	//to our success
 | 
						|
	SIMD_FORCE_INLINE	unsigned int getHash()const
 | 
						|
	{
 | 
						|
		unsigned 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 btHashMap template class implements a generic and lightweight hashmap.
 | 
						|
///A basic sample of how to use btHashMap is located in Demos\BasicDemo\main.cpp
 | 
						|
template <class Key, class Value>
 | 
						|
class btHashMap
 | 
						|
{
 | 
						|
 | 
						|
protected:
 | 
						|
	btAlignedObjectArray<int>		m_hashTable;
 | 
						|
	btAlignedObjectArray<int>		m_next;
 | 
						|
	
 | 
						|
	btAlignedObjectArray<Value>		m_valueArray;
 | 
						|
	btAlignedObjectArray<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] = BT_HASH_NULL;
 | 
						|
			}
 | 
						|
			for (i = 0; i < newCapacity; ++i)
 | 
						|
			{
 | 
						|
				m_next[i] = BT_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 != BT_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 ==BT_HASH_NULL)
 | 
						|
		{
 | 
						|
			return;
 | 
						|
		}
 | 
						|
 | 
						|
		// Remove the pair from the hash table.
 | 
						|
		int index = m_hashTable[hash];
 | 
						|
		btAssert(index != BT_HASH_NULL);
 | 
						|
 | 
						|
		int previous = BT_HASH_NULL;
 | 
						|
		while (index != pairIndex)
 | 
						|
		{
 | 
						|
			previous = index;
 | 
						|
			index = m_next[index];
 | 
						|
		}
 | 
						|
 | 
						|
		if (previous != BT_HASH_NULL)
 | 
						|
		{
 | 
						|
			btAssert(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];
 | 
						|
		btAssert(index != BT_HASH_NULL);
 | 
						|
 | 
						|
		previous = BT_HASH_NULL;
 | 
						|
		while (index != lastPairIndex)
 | 
						|
		{
 | 
						|
			previous = index;
 | 
						|
			index = m_next[index];
 | 
						|
		}
 | 
						|
 | 
						|
		if (previous != BT_HASH_NULL)
 | 
						|
		{
 | 
						|
			btAssert(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
 | 
						|
	{
 | 
						|
		btAssert(index < m_valueArray.size());
 | 
						|
		btAssert(index>=0);
 | 
						|
		if (index>=0 && index < m_valueArray.size())
 | 
						|
		{
 | 
						|
			return &m_valueArray[index];
 | 
						|
		}
 | 
						|
		return 0;
 | 
						|
	}
 | 
						|
 | 
						|
	Value* getAtIndex(int index)
 | 
						|
	{
 | 
						|
		btAssert(index < m_valueArray.size());
 | 
						|
		btAssert(index>=0);
 | 
						|
		if (index>=0 && index < m_valueArray.size())
 | 
						|
		{
 | 
						|
			return &m_valueArray[index];
 | 
						|
		}
 | 
						|
		return 0;
 | 
						|
	}
 | 
						|
 | 
						|
    Key getKeyAtIndex(int index)
 | 
						|
    {
 | 
						|
        btAssert(index < m_keyArray.size());
 | 
						|
		btAssert(index>=0);
 | 
						|
		return m_keyArray[index];
 | 
						|
    }
 | 
						|
    
 | 
						|
    const Key getKeyAtIndex(int index) const
 | 
						|
    {
 | 
						|
        btAssert(index < m_keyArray.size());
 | 
						|
		btAssert(index>=0);
 | 
						|
		return m_keyArray[index];
 | 
						|
   }
 | 
						|
 | 
						|
 | 
						|
	Value* operator[](const Key& key) {
 | 
						|
		return find(key);
 | 
						|
	}
 | 
						|
 | 
						|
	const Value* operator[](const Key& key) const {
 | 
						|
		return find(key);
 | 
						|
	}
 | 
						|
 | 
						|
	const Value*	find(const Key& key) const
 | 
						|
	{
 | 
						|
		int index = findIndex(key);
 | 
						|
		if (index == BT_HASH_NULL)
 | 
						|
		{
 | 
						|
			return NULL;
 | 
						|
		}
 | 
						|
		return &m_valueArray[index];
 | 
						|
	}
 | 
						|
 | 
						|
	Value*	find(const Key& key)
 | 
						|
	{
 | 
						|
		int index = findIndex(key);
 | 
						|
		if (index == BT_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 BT_HASH_NULL;
 | 
						|
		}
 | 
						|
 | 
						|
		int index = m_hashTable[hash];
 | 
						|
		while ((index != BT_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 //BT_HASH_MAP_H
 |