1 /*
2 Bullet Continuous Collision Detection and Physics Library
3 Copyright (c) 2003-2009 Erwin Coumans  http://bulletphysics.org
4 
5 This software is provided 'as-is', without any express or implied warranty.
6 In no event will the authors be held liable for any damages arising from the use of this software.
7 Permission is granted to anyone to use this software for any purpose,
8 including commercial applications, and to alter it and redistribute it freely,
9 subject to the following restrictions:
10 
11 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.
12 2. Altered source versions must be plainly marked as such, and must not be misrepresented as being the original software.
13 3. This notice may not be removed or altered from any source distribution.
14 */
15 
16 
17 #ifndef BT_HASH_MAP_H
18 #define BT_HASH_MAP_H
19 
20 #include "btAlignedObjectArray.h"
21 
22 ///very basic hashable string implementation, compatible with btHashMap
23 struct btHashString
24 {
25 	const char* m_string;
26 	unsigned int	m_hash;
27 
getHashbtHashString28 	SIMD_FORCE_INLINE	unsigned int getHash()const
29 	{
30 		return m_hash;
31 	}
32 
btHashStringbtHashString33 	btHashString(const char* name)
34 		:m_string(name)
35 	{
36 		/* magic numbers from http://www.isthe.com/chongo/tech/comp/fnv/ */
37 		static const unsigned int  InitialFNV = 2166136261u;
38 		static const unsigned int FNVMultiple = 16777619u;
39 
40 		/* Fowler / Noll / Vo (FNV) Hash */
41 		unsigned int hash = InitialFNV;
42 
43 		for(int i = 0; m_string[i]; i++)
44 		{
45 			hash = hash ^ (m_string[i]);       /* xor  the low 8 bits */
46 			hash = hash * FNVMultiple;  /* multiply by the magic number */
47 		}
48 		m_hash = hash;
49 	}
50 
portableStringComparebtHashString51 	int portableStringCompare(const char* src,	const char* dst) const
52 	{
53 			int ret = 0 ;
54 
55 			while( ! (ret = *(unsigned char *)src - *(unsigned char *)dst) && *dst)
56 					++src, ++dst;
57 
58 			if ( ret < 0 )
59 					ret = -1 ;
60 			else if ( ret > 0 )
61 					ret = 1 ;
62 
63 			return( ret );
64 	}
65 
equalsbtHashString66 	bool equals(const btHashString& other) const
67 	{
68 		return (m_string == other.m_string) ||
69 			(0==portableStringCompare(m_string,other.m_string));
70 
71 	}
72 
73 };
74 
75 const int BT_HASH_NULL=0xffffffff;
76 
77 
78 class btHashInt
79 {
80 	int	m_uid;
81 public:
btHashInt(int uid)82 	btHashInt(int uid)	:m_uid(uid)
83 	{
84 	}
85 
getUid1()86 	int	getUid1() const
87 	{
88 		return m_uid;
89 	}
90 
setUid1(int uid)91 	void	setUid1(int uid)
92 	{
93 		m_uid = uid;
94 	}
95 
equals(const btHashInt & other)96 	bool equals(const btHashInt& other) const
97 	{
98 		return getUid1() == other.getUid1();
99 	}
100 	//to our success
getHash()101 	SIMD_FORCE_INLINE	unsigned int getHash()const
102 	{
103 		int key = m_uid;
104 		// Thomas Wang's hash
105 		key += ~(key << 15);	key ^=  (key >> 10);	key +=  (key << 3);	key ^=  (key >> 6);	key += ~(key << 11);	key ^=  (key >> 16);
106 		return key;
107 	}
108 };
109 
110 
111 
112 class btHashPtr
113 {
114 
115 	union
116 	{
117 		const void*	m_pointer;
118 		int	m_hashValues[2];
119 	};
120 
121 public:
122 
btHashPtr(const void * ptr)123 	btHashPtr(const void* ptr)
124 		:m_pointer(ptr)
125 	{
126 	}
127 
getPointer()128 	const void*	getPointer() const
129 	{
130 		return m_pointer;
131 	}
132 
equals(const btHashPtr & other)133 	bool equals(const btHashPtr& other) const
134 	{
135 		return getPointer() == other.getPointer();
136 	}
137 
138 	//to our success
getHash()139 	SIMD_FORCE_INLINE	unsigned int getHash()const
140 	{
141 		const bool VOID_IS_8 = ((sizeof(void*)==8));
142 
143 		int key = VOID_IS_8? m_hashValues[0]+m_hashValues[1] : m_hashValues[0];
144 
145 		// Thomas Wang's hash
146 		key += ~(key << 15);	key ^=  (key >> 10);	key +=  (key << 3);	key ^=  (key >> 6);	key += ~(key << 11);	key ^=  (key >> 16);
147 		return key;
148 	}
149 
150 
151 };
152 
153 
154 template <class Value>
155 class btHashKeyPtr
156 {
157         int     m_uid;
158 public:
159 
btHashKeyPtr(int uid)160         btHashKeyPtr(int uid)    :m_uid(uid)
161         {
162         }
163 
getUid1()164         int     getUid1() const
165         {
166                 return m_uid;
167         }
168 
equals(const btHashKeyPtr<Value> & other)169         bool equals(const btHashKeyPtr<Value>& other) const
170         {
171                 return getUid1() == other.getUid1();
172         }
173 
174         //to our success
getHash()175         SIMD_FORCE_INLINE       unsigned int getHash()const
176         {
177                 int key = m_uid;
178                 // Thomas Wang's hash
179                 key += ~(key << 15);	key ^=  (key >> 10);	key +=  (key << 3);	key ^=  (key >> 6);	key += ~(key << 11);	key ^=  (key >> 16);
180                 return key;
181         }
182 
183 
184 };
185 
186 
187 template <class Value>
188 class btHashKey
189 {
190 	int	m_uid;
191 public:
192 
btHashKey(int uid)193 	btHashKey(int uid)	:m_uid(uid)
194 	{
195 	}
196 
getUid1()197 	int	getUid1() const
198 	{
199 		return m_uid;
200 	}
201 
equals(const btHashKey<Value> & other)202 	bool equals(const btHashKey<Value>& other) const
203 	{
204 		return getUid1() == other.getUid1();
205 	}
206 	//to our success
getHash()207 	SIMD_FORCE_INLINE	unsigned int getHash()const
208 	{
209 		int key = m_uid;
210 		// Thomas Wang's hash
211 		key += ~(key << 15);	key ^=  (key >> 10);	key +=  (key << 3);	key ^=  (key >> 6);	key += ~(key << 11);	key ^=  (key >> 16);
212 		return key;
213 	}
214 };
215 
216 
217 ///The btHashMap template class implements a generic and lightweight hashmap.
218 ///A basic sample of how to use btHashMap is located in Demos\BasicDemo\main.cpp
219 template <class Key, class Value>
220 class btHashMap
221 {
222 
223 protected:
224 	btAlignedObjectArray<int>		m_hashTable;
225 	btAlignedObjectArray<int>		m_next;
226 
227 	btAlignedObjectArray<Value>		m_valueArray;
228 	btAlignedObjectArray<Key>		m_keyArray;
229 
growTables(const Key &)230 	void	growTables(const Key& /*key*/)
231 	{
232 		int newCapacity = m_valueArray.capacity();
233 
234 		if (m_hashTable.size() < newCapacity)
235 		{
236 			//grow hashtable and next table
237 			int curHashtableSize = m_hashTable.size();
238 
239 			m_hashTable.resize(newCapacity);
240 			m_next.resize(newCapacity);
241 
242 			int i;
243 
244 			for (i= 0; i < newCapacity; ++i)
245 			{
246 				m_hashTable[i] = BT_HASH_NULL;
247 			}
248 			for (i = 0; i < newCapacity; ++i)
249 			{
250 				m_next[i] = BT_HASH_NULL;
251 			}
252 
253 			for(i=0;i<curHashtableSize;i++)
254 			{
255 				//const Value& value = m_valueArray[i];
256 				//const Key& key = m_keyArray[i];
257 
258 				int	hashValue = m_keyArray[i].getHash() & (m_valueArray.capacity()-1);	// New hash value with new mask
259 				m_next[i] = m_hashTable[hashValue];
260 				m_hashTable[hashValue] = i;
261 			}
262 
263 
264 		}
265 	}
266 
267 	public:
268 
insert(const Key & key,const Value & value)269 	void insert(const Key& key, const Value& value) {
270 		int hash = key.getHash() & (m_valueArray.capacity()-1);
271 
272 		//replace value if the key is already there
273 		int index = findIndex(key);
274 		if (index != BT_HASH_NULL)
275 		{
276 			m_valueArray[index]=value;
277 			return;
278 		}
279 
280 		int count = m_valueArray.size();
281 		int oldCapacity = m_valueArray.capacity();
282 		m_valueArray.push_back(value);
283 		m_keyArray.push_back(key);
284 
285 		int newCapacity = m_valueArray.capacity();
286 		if (oldCapacity < newCapacity)
287 		{
288 			growTables(key);
289 			//hash with new capacity
290 			hash = key.getHash() & (m_valueArray.capacity()-1);
291 		}
292 		m_next[count] = m_hashTable[hash];
293 		m_hashTable[hash] = count;
294 	}
295 
remove(const Key & key)296 	void remove(const Key& key) {
297 
298 		int hash = key.getHash() & (m_valueArray.capacity()-1);
299 
300 		int pairIndex = findIndex(key);
301 
302 		if (pairIndex ==BT_HASH_NULL)
303 		{
304 			return;
305 		}
306 
307 		// Remove the pair from the hash table.
308 		int index = m_hashTable[hash];
309 		btAssert(index != BT_HASH_NULL);
310 
311 		int previous = BT_HASH_NULL;
312 		while (index != pairIndex)
313 		{
314 			previous = index;
315 			index = m_next[index];
316 		}
317 
318 		if (previous != BT_HASH_NULL)
319 		{
320 			btAssert(m_next[previous] == pairIndex);
321 			m_next[previous] = m_next[pairIndex];
322 		}
323 		else
324 		{
325 			m_hashTable[hash] = m_next[pairIndex];
326 		}
327 
328 		// We now move the last pair into spot of the
329 		// pair being removed. We need to fix the hash
330 		// table indices to support the move.
331 
332 		int lastPairIndex = m_valueArray.size() - 1;
333 
334 		// If the removed pair is the last pair, we are done.
335 		if (lastPairIndex == pairIndex)
336 		{
337 			m_valueArray.pop_back();
338 			m_keyArray.pop_back();
339 			return;
340 		}
341 
342 		// Remove the last pair from the hash table.
343 		int lastHash = m_keyArray[lastPairIndex].getHash() & (m_valueArray.capacity()-1);
344 
345 		index = m_hashTable[lastHash];
346 		btAssert(index != BT_HASH_NULL);
347 
348 		previous = BT_HASH_NULL;
349 		while (index != lastPairIndex)
350 		{
351 			previous = index;
352 			index = m_next[index];
353 		}
354 
355 		if (previous != BT_HASH_NULL)
356 		{
357 			btAssert(m_next[previous] == lastPairIndex);
358 			m_next[previous] = m_next[lastPairIndex];
359 		}
360 		else
361 		{
362 			m_hashTable[lastHash] = m_next[lastPairIndex];
363 		}
364 
365 		// Copy the last pair into the remove pair's spot.
366 		m_valueArray[pairIndex] = m_valueArray[lastPairIndex];
367 		m_keyArray[pairIndex] = m_keyArray[lastPairIndex];
368 
369 		// Insert the last pair into the hash table
370 		m_next[pairIndex] = m_hashTable[lastHash];
371 		m_hashTable[lastHash] = pairIndex;
372 
373 		m_valueArray.pop_back();
374 		m_keyArray.pop_back();
375 
376 	}
377 
378 
size()379 	int size() const
380 	{
381 		return m_valueArray.size();
382 	}
383 
getAtIndex(int index)384 	const Value* getAtIndex(int index) const
385 	{
386 		btAssert(index < m_valueArray.size());
387 
388 		return &m_valueArray[index];
389 	}
390 
getAtIndex(int index)391 	Value* getAtIndex(int index)
392 	{
393 		btAssert(index < m_valueArray.size());
394 
395 		return &m_valueArray[index];
396 	}
397 
getKeyAtIndex(int index)398     Key getKeyAtIndex(int index)
399     {
400         btAssert(index < m_keyArray.size());
401         return m_keyArray[index];
402     }
403 
getKeyAtIndex(int index)404     const Key getKeyAtIndex(int index) const
405     {
406         btAssert(index < m_keyArray.size());
407         return m_keyArray[index];
408     }
409 
410 
411 	Value* operator[](const Key& key) {
412 		return find(key);
413 	}
414 
415 	const Value* operator[](const Key& key) const {
416 		return find(key);
417 	}
418 
find(const Key & key)419 	const Value*	find(const Key& key) const
420 	{
421 		int index = findIndex(key);
422 		if (index == BT_HASH_NULL)
423 		{
424 			return NULL;
425 		}
426 		return &m_valueArray[index];
427 	}
428 
find(const Key & key)429 	Value*	find(const Key& key)
430 	{
431 		int index = findIndex(key);
432 		if (index == BT_HASH_NULL)
433 		{
434 			return NULL;
435 		}
436 		return &m_valueArray[index];
437 	}
438 
439 
findIndex(const Key & key)440 	int	findIndex(const Key& key) const
441 	{
442 		unsigned int hash = key.getHash() & (m_valueArray.capacity()-1);
443 
444 		if (hash >= (unsigned int)m_hashTable.size())
445 		{
446 			return BT_HASH_NULL;
447 		}
448 
449 		int index = m_hashTable[hash];
450 		while ((index != BT_HASH_NULL) && key.equals(m_keyArray[index]) == false)
451 		{
452 			index = m_next[index];
453 		}
454 		return index;
455 	}
456 
clear()457 	void	clear()
458 	{
459 		m_hashTable.clear();
460 		m_next.clear();
461 		m_valueArray.clear();
462 		m_keyArray.clear();
463 	}
464 
465 };
466 
467 #endif //BT_HASH_MAP_H
468