|
|
@@ -20,29 +20,29 @@ namespace crown
|
|
|
namespace hash_map
|
|
|
{
|
|
|
/// Returns the number of items in the map @a m.
|
|
|
- template <typename TKey, typename TValue, typename Hash> u32 size(const HashMap<TKey, TValue, Hash>& m);
|
|
|
+ template <typename TKey, typename TValue, typename Hash, typename KeyEqual > u32 size(const HashMap<TKey, TValue, Hash, KeyEqual>& m);
|
|
|
|
|
|
/// Returns the maximum number of items the map @a m can hold.
|
|
|
- template <typename TKey, typename TValue, typename Hash> u32 capacity(const HashMap<TKey, TValue, Hash>& m);
|
|
|
+ template <typename TKey, typename TValue, typename Hash, typename KeyEqual > u32 capacity(const HashMap<TKey, TValue, Hash, KeyEqual>& m);
|
|
|
|
|
|
/// Returns whether the given @a key exists in the map @a m.
|
|
|
- template <typename TKey, typename TValue, typename Hash> bool has(const HashMap<TKey, TValue, Hash>& m, const TKey& key);
|
|
|
+ template <typename TKey, typename TValue, typename Hash, typename KeyEqual > bool has(const HashMap<TKey, TValue, Hash, KeyEqual>& m, const TKey& key);
|
|
|
|
|
|
/// Returns the value for the given @a key or @a deffault if
|
|
|
/// the key does not exist in the map.
|
|
|
- template <typename TKey, typename TValue, typename Hash> const TValue& get(const HashMap<TKey, TValue, Hash>& m, const TKey& key, const TValue& deffault);
|
|
|
+ template <typename TKey, typename TValue, typename Hash, typename KeyEqual > const TValue& get(const HashMap<TKey, TValue, Hash, KeyEqual>& m, const TKey& key, const TValue& deffault);
|
|
|
|
|
|
/// Sets the @a value for the @a key in the map.
|
|
|
- template <typename TKey, typename TValue, typename Hash> void set(HashMap<TKey, TValue, Hash>& m, const TKey& key, const TValue& value);
|
|
|
+ template <typename TKey, typename TValue, typename Hash, typename KeyEqual > void set(HashMap<TKey, TValue, Hash, KeyEqual>& m, const TKey& key, const TValue& value);
|
|
|
|
|
|
/// Removes the @a key from the map if it exists.
|
|
|
- template <typename TKey, typename TValue, typename Hash> void remove(HashMap<TKey, TValue, Hash>& m, const TKey& key);
|
|
|
+ template <typename TKey, typename TValue, typename Hash, typename KeyEqual > void remove(HashMap<TKey, TValue, Hash, KeyEqual>& m, const TKey& key);
|
|
|
|
|
|
/// Removes all the items in the map.
|
|
|
///
|
|
|
/// @note
|
|
|
/// Calls destructor on the items.
|
|
|
- template <typename TKey, typename TValue, typename Hash> void clear(HashMap<TKey, TValue, Hash>& m);
|
|
|
+ template <typename TKey, typename TValue, typename Hash, typename KeyEqual > void clear(HashMap<TKey, TValue, Hash, KeyEqual>& m);
|
|
|
|
|
|
} // namespace hash_map
|
|
|
|
|
|
@@ -53,32 +53,39 @@ namespace hash_map_internal
|
|
|
const u32 FREE = 0x00000000u;
|
|
|
|
|
|
template <typename TKey, typename Hash>
|
|
|
- inline u32 hash_key(const TKey& key)
|
|
|
+ inline u32 key_hash(const TKey& key)
|
|
|
{
|
|
|
const Hash hash;
|
|
|
return hash(key);
|
|
|
}
|
|
|
|
|
|
+ template <typename TKey, typename KeyEqual>
|
|
|
+ inline bool key_equals(const TKey& key_a, const TKey& key_b)
|
|
|
+ {
|
|
|
+ const KeyEqual equal;
|
|
|
+ return equal(key_a, key_b);
|
|
|
+ }
|
|
|
+
|
|
|
inline bool is_deleted(u32 index)
|
|
|
{
|
|
|
// MSB set indicates that this hash is a "tombstone"
|
|
|
return (index >> 31) != 0;
|
|
|
}
|
|
|
|
|
|
- template <typename TKey, typename TValue, typename Hash>
|
|
|
- inline u32 probe_distance(const HashMap<TKey, TValue, Hash>& m, u32 hash, u32 slot_index)
|
|
|
+ template <typename TKey, typename TValue, typename Hash, typename KeyEqual >
|
|
|
+ inline u32 probe_distance(const HashMap<TKey, TValue, Hash, KeyEqual>& m, u32 hash, u32 slot_index)
|
|
|
{
|
|
|
const u32 hash_i = hash & m._mask;
|
|
|
return (slot_index + m._capacity - hash_i) & m._mask;
|
|
|
}
|
|
|
|
|
|
- template <typename TKey, typename TValue, typename Hash>
|
|
|
- u32 find(const HashMap<TKey, TValue, Hash>& m, const TKey& key)
|
|
|
+ template <typename TKey, typename TValue, typename Hash, typename KeyEqual >
|
|
|
+ u32 find(const HashMap<TKey, TValue, Hash, KeyEqual>& m, const TKey& key)
|
|
|
{
|
|
|
if (m._size == 0)
|
|
|
return END_OF_LIST;
|
|
|
|
|
|
- const u32 hash = hash_key<TKey, Hash>(key);
|
|
|
+ const u32 hash = key_hash<TKey, Hash>(key);
|
|
|
u32 hash_i = hash & m._mask;
|
|
|
u32 dist = 0;
|
|
|
for(;;)
|
|
|
@@ -87,7 +94,7 @@ namespace hash_map_internal
|
|
|
return END_OF_LIST;
|
|
|
else if (dist > probe_distance(m, m._index[hash_i].hash, hash_i))
|
|
|
return END_OF_LIST;
|
|
|
- else if (!is_deleted(m._index[hash_i].index) && m._index[hash_i].hash == hash && m._data[hash_i].first == key)
|
|
|
+ else if (!is_deleted(m._index[hash_i].index) && m._index[hash_i].hash == hash && key_equals<TKey, KeyEqual>(m._data[hash_i].first, key))
|
|
|
return hash_i;
|
|
|
|
|
|
hash_i = (hash_i + 1) & m._mask;
|
|
|
@@ -95,8 +102,8 @@ namespace hash_map_internal
|
|
|
}
|
|
|
}
|
|
|
|
|
|
- template <typename TKey, typename TValue, typename Hash>
|
|
|
- void insert(HashMap<TKey, TValue, Hash>& m, u32 hash, const TKey& key, const TValue& value)
|
|
|
+ template <typename TKey, typename TValue, typename Hash, typename KeyEqual >
|
|
|
+ void insert(HashMap<TKey, TValue, Hash, KeyEqual>& m, u32 hash, const TKey& key, const TValue& value)
|
|
|
{
|
|
|
PAIR(TKey, TValue) new_item(*m._allocator);
|
|
|
new_item.first = key;
|
|
|
@@ -129,7 +136,7 @@ namespace hash_map_internal
|
|
|
}
|
|
|
|
|
|
INSERT_AND_RETURN:
|
|
|
- new (m._data + hash_i) typename HashMap<TKey, TValue, Hash>::Entry(*m._allocator);
|
|
|
+ new (m._data + hash_i) typename HashMap<TKey, TValue, Hash, KeyEqual>::Entry(*m._allocator);
|
|
|
memcpy((void*)(m._data + hash_i), &new_item, sizeof(new_item));
|
|
|
m._index[hash_i].hash = hash;
|
|
|
m._index[hash_i].index = 0x0123abcd;
|
|
|
@@ -137,13 +144,13 @@ namespace hash_map_internal
|
|
|
memcpy((void*)&new_item, &empty, sizeof(new_item));
|
|
|
}
|
|
|
|
|
|
- template <typename TKey, typename TValue, typename Hash>
|
|
|
- void rehash(HashMap<TKey, TValue, Hash>& m, u32 new_capacity)
|
|
|
+ template <typename TKey, typename TValue, typename Hash, typename KeyEqual >
|
|
|
+ void rehash(HashMap<TKey, TValue, Hash, KeyEqual>& m, u32 new_capacity)
|
|
|
{
|
|
|
- typedef typename HashMap<TKey, TValue, Hash>::Entry Entry;
|
|
|
- typedef typename HashMap<TKey, TValue, Hash>::Index Index;
|
|
|
+ typedef typename HashMap<TKey, TValue, Hash, KeyEqual>::Entry Entry;
|
|
|
+ typedef typename HashMap<TKey, TValue, Hash, KeyEqual>::Index Index;
|
|
|
|
|
|
- HashMap<TKey, TValue, Hash> nm(*m._allocator);
|
|
|
+ HashMap<TKey, TValue, Hash, KeyEqual> nm(*m._allocator);
|
|
|
nm._index = (Index*)nm._allocator->allocate(new_capacity*sizeof(Index), alignof(Index));
|
|
|
nm._data = (Entry*)nm._allocator->allocate(new_capacity*sizeof(Entry), alignof(Entry));
|
|
|
|
|
|
@@ -160,7 +167,7 @@ namespace hash_map_internal
|
|
|
|
|
|
for (u32 i = 0; i < m._capacity; ++i)
|
|
|
{
|
|
|
- typename HashMap<TKey, TValue, Hash>::Entry& e = m._data[i];
|
|
|
+ typename HashMap<TKey, TValue, Hash, KeyEqual>::Entry& e = m._data[i];
|
|
|
const u32 hash = m._index[i].hash;
|
|
|
const u32 index = m._index[i].index;
|
|
|
|
|
|
@@ -168,21 +175,21 @@ namespace hash_map_internal
|
|
|
hash_map_internal::insert(nm, hash, e.first, e.second);
|
|
|
}
|
|
|
|
|
|
- HashMap<TKey, TValue, Hash> empty(*m._allocator);
|
|
|
- m.~HashMap<TKey, TValue, Hash>();
|
|
|
- memcpy((void*)&m, (void*)&nm, sizeof(HashMap<TKey, TValue, Hash>));
|
|
|
- memcpy((void*)&nm, (void*)&empty, sizeof(HashMap<TKey, TValue, Hash>));
|
|
|
+ HashMap<TKey, TValue, Hash, KeyEqual> empty(*m._allocator);
|
|
|
+ m.~HashMap<TKey, TValue, Hash, KeyEqual>();
|
|
|
+ memcpy((void*)&m, (void*)&nm, sizeof(HashMap<TKey, TValue, Hash, KeyEqual>));
|
|
|
+ memcpy((void*)&nm, (void*)&empty, sizeof(HashMap<TKey, TValue, Hash, KeyEqual>));
|
|
|
}
|
|
|
|
|
|
- template <typename TKey, typename TValue, typename Hash>
|
|
|
- void grow(HashMap<TKey, TValue, Hash>& m)
|
|
|
+ template <typename TKey, typename TValue, typename Hash, typename KeyEqual >
|
|
|
+ void grow(HashMap<TKey, TValue, Hash, KeyEqual>& m)
|
|
|
{
|
|
|
const u32 new_capacity = (m._capacity == 0 ? 16 : m._capacity * 2);
|
|
|
rehash(m, new_capacity);
|
|
|
}
|
|
|
|
|
|
- template <typename TKey, typename TValue, typename Hash>
|
|
|
- bool full(const HashMap<TKey, TValue, Hash>& m)
|
|
|
+ template <typename TKey, typename TValue, typename Hash, typename KeyEqual >
|
|
|
+ bool full(const HashMap<TKey, TValue, Hash, KeyEqual>& m)
|
|
|
{
|
|
|
return m._size >= m._capacity * 0.9f;
|
|
|
}
|
|
|
@@ -191,26 +198,26 @@ namespace hash_map_internal
|
|
|
|
|
|
namespace hash_map
|
|
|
{
|
|
|
- template <typename TKey, typename TValue, typename Hash>
|
|
|
- u32 size(const HashMap<TKey, TValue, Hash>& m)
|
|
|
+ template <typename TKey, typename TValue, typename Hash, typename KeyEqual >
|
|
|
+ u32 size(const HashMap<TKey, TValue, Hash, KeyEqual>& m)
|
|
|
{
|
|
|
return m._size;
|
|
|
}
|
|
|
|
|
|
- template <typename TKey, typename TValue, typename Hash>
|
|
|
- u32 capacity(const HashMap<TKey, TValue, Hash>& m)
|
|
|
+ template <typename TKey, typename TValue, typename Hash, typename KeyEqual >
|
|
|
+ u32 capacity(const HashMap<TKey, TValue, Hash, KeyEqual>& m)
|
|
|
{
|
|
|
return m._capacity;
|
|
|
}
|
|
|
|
|
|
- template <typename TKey, typename TValue, typename Hash>
|
|
|
- bool has(const HashMap<TKey, TValue, Hash>& m, const TKey& key)
|
|
|
+ template <typename TKey, typename TValue, typename Hash, typename KeyEqual >
|
|
|
+ bool has(const HashMap<TKey, TValue, Hash, KeyEqual>& m, const TKey& key)
|
|
|
{
|
|
|
return hash_map_internal::find(m, key) != hash_map_internal::END_OF_LIST;
|
|
|
}
|
|
|
|
|
|
- template <typename TKey, typename TValue, typename Hash>
|
|
|
- const TValue& get(const HashMap<TKey, TValue, Hash>& m, const TKey& key, const TValue& deffault)
|
|
|
+ template <typename TKey, typename TValue, typename Hash, typename KeyEqual >
|
|
|
+ const TValue& get(const HashMap<TKey, TValue, Hash, KeyEqual>& m, const TKey& key, const TValue& deffault)
|
|
|
{
|
|
|
const u32 i = hash_map_internal::find(m, key);
|
|
|
if (i == hash_map_internal::END_OF_LIST)
|
|
|
@@ -219,8 +226,8 @@ namespace hash_map
|
|
|
return m._data[i].second;
|
|
|
}
|
|
|
|
|
|
- template <typename TKey, typename TValue, typename Hash>
|
|
|
- void set(HashMap<TKey, TValue, Hash>& m, const TKey& key, const TValue& value)
|
|
|
+ template <typename TKey, typename TValue, typename Hash, typename KeyEqual >
|
|
|
+ void set(HashMap<TKey, TValue, Hash, KeyEqual>& m, const TKey& key, const TValue& value)
|
|
|
{
|
|
|
if (m._capacity == 0)
|
|
|
hash_map_internal::grow(m);
|
|
|
@@ -229,7 +236,7 @@ namespace hash_map
|
|
|
const u32 i = hash_map_internal::find(m, key);
|
|
|
if (i == hash_map_internal::END_OF_LIST)
|
|
|
{
|
|
|
- hash_map_internal::insert(m, hash_map_internal::hash_key<TKey, Hash>(key), key, value);
|
|
|
+ hash_map_internal::insert(m, hash_map_internal::key_hash<TKey, Hash>(key), key, value);
|
|
|
++m._size;
|
|
|
}
|
|
|
else
|
|
|
@@ -240,8 +247,8 @@ namespace hash_map
|
|
|
hash_map_internal::grow(m);
|
|
|
}
|
|
|
|
|
|
- template <typename TKey, typename TValue, typename Hash>
|
|
|
- void remove(HashMap<TKey, TValue, Hash>& m, const TKey& key)
|
|
|
+ template <typename TKey, typename TValue, typename Hash, typename KeyEqual >
|
|
|
+ void remove(HashMap<TKey, TValue, Hash, KeyEqual>& m, const TKey& key)
|
|
|
{
|
|
|
const u32 i = hash_map_internal::find(m, key);
|
|
|
if (i == hash_map_internal::END_OF_LIST)
|
|
|
@@ -252,8 +259,8 @@ namespace hash_map
|
|
|
--m._size;
|
|
|
}
|
|
|
|
|
|
- template <typename TKey, typename TValue, typename Hash>
|
|
|
- void clear(HashMap<TKey, TValue, Hash>& m)
|
|
|
+ template <typename TKey, typename TValue, typename Hash, typename KeyEqual >
|
|
|
+ void clear(HashMap<TKey, TValue, Hash, KeyEqual>& m)
|
|
|
{
|
|
|
for (u32 i = 0; i < m._capacity; ++i)
|
|
|
{
|
|
|
@@ -267,8 +274,8 @@ namespace hash_map
|
|
|
|
|
|
} // namespace hash_map
|
|
|
|
|
|
-template <typename TKey, typename TValue, typename Hash>
|
|
|
-HashMap<TKey, TValue, Hash>::HashMap(Allocator& a)
|
|
|
+template <typename TKey, typename TValue, typename Hash, typename KeyEqual >
|
|
|
+HashMap<TKey, TValue, Hash, KeyEqual>::HashMap(Allocator& a)
|
|
|
: _allocator(&a)
|
|
|
, _capacity(0)
|
|
|
, _size(0)
|
|
|
@@ -278,8 +285,8 @@ HashMap<TKey, TValue, Hash>::HashMap(Allocator& a)
|
|
|
{
|
|
|
}
|
|
|
|
|
|
-template <typename TKey, typename TValue, typename Hash>
|
|
|
-HashMap<TKey, TValue, Hash>::~HashMap()
|
|
|
+template <typename TKey, typename TValue, typename Hash, typename KeyEqual >
|
|
|
+HashMap<TKey, TValue, Hash, KeyEqual>::~HashMap()
|
|
|
{
|
|
|
for (u32 i = 0; i < _capacity; ++i)
|
|
|
{
|
|
|
@@ -291,10 +298,4 @@ HashMap<TKey, TValue, Hash>::~HashMap()
|
|
|
_allocator->deallocate(_data);
|
|
|
}
|
|
|
|
|
|
-template <typename TKey, typename TValue, typename Hash>
|
|
|
-const TValue& HashMap<TKey, TValue, Hash>::operator[](const TKey& key) const
|
|
|
-{
|
|
|
- return hash_map::get(*this, key, TValue());
|
|
|
-}
|
|
|
-
|
|
|
} // namespace crown
|