Ver Fonte

core: add KeyEqual template parameter to HashMap

Daniele Bartolini há 7 anos atrás
pai
commit
f7247d9eb4
2 ficheiros alterados com 58 adições e 57 exclusões
  1. 57 56
      src/core/containers/hash_map.h
  2. 1 1
      src/core/containers/types.h

+ 57 - 56
src/core/containers/hash_map.h

@@ -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

+ 1 - 1
src/core/containers/types.h

@@ -119,7 +119,7 @@ struct Map
 /// Hash map.
 ///
 /// @ingroup Containers
-template <typename TKey, typename TValue, typename Hash = hash<TKey> >
+template <typename TKey, typename TValue, typename Hash = hash<TKey>, typename KeyEqual = equal_to<TKey> >
 struct HashMap
 {
 	ALLOCATOR_AWARE;