2 Bullet Continuous Collision Detection and Physics Library
3 Copyright (c) 2003-2013 Erwin Coumans http://bulletphysics.org
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:
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.
19 #include "b3AlignedObjectArray.h"
23 ///very basic hashable string implementation, compatible with b3HashMap
29 B3_FORCE_INLINE unsigned int getHash() const
34 b3HashString(const char* name)
37 /* magic numbers from http://www.isthe.com/chongo/tech/comp/fnv/ */
38 static const unsigned int InitialFNV = 2166136261u;
39 static const unsigned int FNVMultiple = 16777619u;
41 /* Fowler / Noll / Vo (FNV) Hash */
42 unsigned int hash = InitialFNV;
43 int len = m_string.length();
44 for (int i = 0; i < len; i++)
46 hash = hash ^ (m_string[i]); /* xor the low 8 bits */
47 hash = hash * FNVMultiple; /* multiply by the magic number */
52 int portableStringCompare(const char* src, const char* dst) const
56 while (!(ret = *(unsigned char*)src - *(unsigned char*)dst) && *dst)
67 bool equals(const b3HashString& other) const
69 return (m_string == other.m_string);
73 const int B3_HASH_NULL = 0xffffffff;
80 b3HashInt(int uid) : m_uid(uid)
94 bool equals(const b3HashInt& other) const
96 return getUid1() == other.getUid1();
99 B3_FORCE_INLINE unsigned int getHash() const
102 // Thomas Wang's hash
116 const void* m_pointer;
121 b3HashPtr(const void* ptr)
126 const void* getPointer() const
131 bool equals(const b3HashPtr& other) const
133 return getPointer() == other.getPointer();
137 B3_FORCE_INLINE unsigned int getHash() const
139 const bool VOID_IS_8 = ((sizeof(void*) == 8));
141 int key = VOID_IS_8 ? m_hashValues[0] + m_hashValues[1] : m_hashValues[0];
143 // Thomas Wang's hash
154 template <class Value>
160 b3HashKeyPtr(int uid) : m_uid(uid)
169 bool equals(const b3HashKeyPtr<Value>& other) const
171 return getUid1() == other.getUid1();
175 B3_FORCE_INLINE unsigned int getHash() const
178 // Thomas Wang's hash
189 template <class Value>
195 b3HashKey(int uid) : m_uid(uid)
204 bool equals(const b3HashKey<Value>& other) const
206 return getUid1() == other.getUid1();
209 B3_FORCE_INLINE unsigned int getHash() const
212 // Thomas Wang's hash
223 ///The b3HashMap template class implements a generic and lightweight hashmap.
224 ///A basic sample of how to use b3HashMap is located in Demos\BasicDemo\main.cpp
225 template <class Key, class Value>
229 b3AlignedObjectArray<int> m_hashTable;
230 b3AlignedObjectArray<int> m_next;
232 b3AlignedObjectArray<Value> m_valueArray;
233 b3AlignedObjectArray<Key> m_keyArray;
235 void growTables(const Key& /*key*/)
237 int newCapacity = m_valueArray.capacity();
239 if (m_hashTable.size() < newCapacity)
241 //grow hashtable and next table
242 int curHashtableSize = m_hashTable.size();
244 m_hashTable.resize(newCapacity);
245 m_next.resize(newCapacity);
249 for (i = 0; i < newCapacity; ++i)
251 m_hashTable[i] = B3_HASH_NULL;
253 for (i = 0; i < newCapacity; ++i)
255 m_next[i] = B3_HASH_NULL;
258 for (i = 0; i < curHashtableSize; i++)
260 //const Value& value = m_valueArray[i];
261 //const Key& key = m_keyArray[i];
263 int hashValue = m_keyArray[i].getHash() & (m_valueArray.capacity() - 1); // New hash value with new mask
264 m_next[i] = m_hashTable[hashValue];
265 m_hashTable[hashValue] = i;
271 void insert(const Key& key, const Value& value)
273 int hash = key.getHash() & (m_valueArray.capacity() - 1);
275 //replace value if the key is already there
276 int index = findIndex(key);
277 if (index != B3_HASH_NULL)
279 m_valueArray[index] = value;
283 int count = m_valueArray.size();
284 int oldCapacity = m_valueArray.capacity();
285 m_valueArray.push_back(value);
286 m_keyArray.push_back(key);
288 int newCapacity = m_valueArray.capacity();
289 if (oldCapacity < newCapacity)
292 //hash with new capacity
293 hash = key.getHash() & (m_valueArray.capacity() - 1);
295 m_next[count] = m_hashTable[hash];
296 m_hashTable[hash] = count;
299 void remove(const Key& key)
301 int hash = key.getHash() & (m_valueArray.capacity() - 1);
303 int pairIndex = findIndex(key);
305 if (pairIndex == B3_HASH_NULL)
310 // Remove the pair from the hash table.
311 int index = m_hashTable[hash];
312 b3Assert(index != B3_HASH_NULL);
314 int previous = B3_HASH_NULL;
315 while (index != pairIndex)
318 index = m_next[index];
321 if (previous != B3_HASH_NULL)
323 b3Assert(m_next[previous] == pairIndex);
324 m_next[previous] = m_next[pairIndex];
328 m_hashTable[hash] = m_next[pairIndex];
331 // We now move the last pair into spot of the
332 // pair being removed. We need to fix the hash
333 // table indices to support the move.
335 int lastPairIndex = m_valueArray.size() - 1;
337 // If the removed pair is the last pair, we are done.
338 if (lastPairIndex == pairIndex)
340 m_valueArray.pop_back();
341 m_keyArray.pop_back();
345 // Remove the last pair from the hash table.
346 int lastHash = m_keyArray[lastPairIndex].getHash() & (m_valueArray.capacity() - 1);
348 index = m_hashTable[lastHash];
349 b3Assert(index != B3_HASH_NULL);
351 previous = B3_HASH_NULL;
352 while (index != lastPairIndex)
355 index = m_next[index];
358 if (previous != B3_HASH_NULL)
360 b3Assert(m_next[previous] == lastPairIndex);
361 m_next[previous] = m_next[lastPairIndex];
365 m_hashTable[lastHash] = m_next[lastPairIndex];
368 // Copy the last pair into the remove pair's spot.
369 m_valueArray[pairIndex] = m_valueArray[lastPairIndex];
370 m_keyArray[pairIndex] = m_keyArray[lastPairIndex];
372 // Insert the last pair into the hash table
373 m_next[pairIndex] = m_hashTable[lastHash];
374 m_hashTable[lastHash] = pairIndex;
376 m_valueArray.pop_back();
377 m_keyArray.pop_back();
382 return m_valueArray.size();
385 const Value* getAtIndex(int index) const
387 b3Assert(index < m_valueArray.size());
389 return &m_valueArray[index];
392 Value* getAtIndex(int index)
394 b3Assert(index < m_valueArray.size());
396 return &m_valueArray[index];
399 Key getKeyAtIndex(int index)
401 b3Assert(index < m_keyArray.size());
402 return m_keyArray[index];
405 const Key getKeyAtIndex(int index) const
407 b3Assert(index < m_keyArray.size());
408 return m_keyArray[index];
411 Value* operator[](const Key& key)
416 const Value* find(const Key& key) const
418 int index = findIndex(key);
419 if (index == B3_HASH_NULL)
423 return &m_valueArray[index];
426 Value* find(const Key& key)
428 int index = findIndex(key);
429 if (index == B3_HASH_NULL)
433 return &m_valueArray[index];
436 int findIndex(const Key& key) const
438 unsigned int hash = key.getHash() & (m_valueArray.capacity() - 1);
440 if (hash >= (unsigned int)m_hashTable.size())
445 int index = m_hashTable[hash];
446 while ((index != B3_HASH_NULL) && key.equals(m_keyArray[index]) == false)
448 index = m_next[index];
457 m_valueArray.clear();
462 #endif //B3_HASH_MAP_H