BAN: Cleanup HashMap

Add a concept for HashMapFindable instead of manually specifying the
requries expression everywhere.

Allow HashMapFindable also for `remove`, `contains`, `operator[]`, `at`

Make Entry have a const Key. This allows iterator's operator* and
operator-> return values have const keys.
This commit is contained in:
2026-04-25 22:04:55 +03:00
parent a63818ec33
commit 0e00b72df6

View File

@@ -60,14 +60,40 @@ namespace BAN
friend HashMap; friend HashMap;
}; };
namespace detail
{
template<typename T, typename Key, typename HASH, typename COMP>
concept HashMapFindable = requires(const Key& a, const T& b) { COMP()(a, b); HASH()(b); };
}
template<typename Key, typename T, typename HASH = BAN::hash<Key>, typename COMP = BAN::equal<Key>> template<typename Key, typename T, typename HASH = BAN::hash<Key>, typename COMP = BAN::equal<Key>>
class HashMap class HashMap
{ {
public: public:
struct Entry struct Entry
{ {
Key key; const Key key;
T value; T value;
Entry() = delete;
Entry& operator=(const Entry&) = delete;
Entry& operator=(Entry&&) = delete;
Entry(const Entry& other)
: key(other.key)
, value(other.value)
{ }
Entry(Entry&& other)
: key(BAN::move(const_cast<Key&>(other.key)))
, value(BAN::move(other.value))
{ }
template<typename... Args>
Entry(Key&& key, Args&&... args)
: key(BAN::move(key))
, value(BAN::forward<Args>(args)...)
{ }
}; };
struct EntryHash struct EntryHash
@@ -105,15 +131,15 @@ namespace BAN
HashMap() = default; HashMap() = default;
~HashMap() { clear(); } ~HashMap() { clear(); }
HashMap(const HashMap<Key, T, HASH>& other) { *this = other; } HashMap(const HashMap& other) { *this = other; }
HashMap<Key, T, HASH>& operator=(const HashMap<Key, T, HASH>& other) HashMap& operator=(const HashMap& other)
{ {
m_hash_set = other.m_hash_set; m_hash_set = other.m_hash_set;
return *this; return *this;
} }
HashMap(HashMap<Key, T, HASH>&& other) { *this = BAN::move(other); } HashMap(HashMap&& other) { *this = BAN::move(other); }
HashMap<Key, T, HASH>& operator=(HashMap<Key, T, HASH>&& other) HashMap& operator=(HashMap&& other)
{ {
m_hash_set = BAN::move(other.m_hash_set); m_hash_set = BAN::move(other.m_hash_set);
return *this; return *this;
@@ -161,7 +187,8 @@ namespace BAN
return iterator(it); return iterator(it);
} }
void remove(const Key& key) template<detail::HashMapFindable<Key, HASH, COMP> U>
void remove(const U& key)
{ {
if (auto it = find(key); it != end()) if (auto it = find(key); it != end())
remove(it); remove(it);
@@ -172,13 +199,13 @@ namespace BAN
return iterator(m_hash_set.remove(it.m_iterator)); return iterator(m_hash_set.remove(it.m_iterator));
} }
template<typename U> requires requires(const Key& a, const U& b) { COMP()(a, b); HASH()(b); } template<detail::HashMapFindable<Key, HASH, COMP> U>
iterator find(const U& key) iterator find(const U& key)
{ {
return iterator(m_hash_set.find(key)); return iterator(m_hash_set.find(key));
} }
template<typename U> requires requires(const Key& a, const U& b) { COMP()(a, b); HASH()(b); } template<detail::HashMapFindable<Key, HASH, COMP> U>
const_iterator find(const U& key) const const_iterator find(const U& key) const
{ {
return const_iterator(m_hash_set.find(key)); return const_iterator(m_hash_set.find(key));
@@ -194,17 +221,20 @@ namespace BAN
return m_hash_set.reserve(size); return m_hash_set.reserve(size);
} }
T& operator[](const Key& key) template<detail::HashMapFindable<Key, HASH, COMP> U>
T& operator[](const U& key)
{ {
return find(key)->value; return find(key)->value;
} }
const T& operator[](const Key& key) const template<detail::HashMapFindable<Key, HASH, COMP> U>
const T& operator[](const U& key) const
{ {
return find(key)->value; return find(key)->value;
} }
bool contains(const Key& key) const template<detail::HashMapFindable<Key, HASH, COMP> U>
bool contains(const U& key) const
{ {
return find(key) != end(); return find(key) != end();
} }