BAN: Cleanup HashSet
Add a concept for HashSetFindable instead of manually specifying the requries expression everywhere. Allow HashSetFindable also for `remove` and `contains`. Remove non-const return values from iterator; you should never modify the hashed value in place. Don't require key to be move assignable, move construction is enough.
This commit is contained in:
@@ -13,7 +13,7 @@ namespace BAN
|
||||
|
||||
Entry& operator*()
|
||||
{
|
||||
return m_iterator.operator*();
|
||||
return const_cast<Entry&>(m_iterator.operator*());
|
||||
}
|
||||
const Entry& operator*() const
|
||||
{
|
||||
@@ -22,7 +22,7 @@ namespace BAN
|
||||
|
||||
Entry* operator->()
|
||||
{
|
||||
return m_iterator.operator->();
|
||||
return const_cast<Entry*>(m_iterator.operator->());
|
||||
}
|
||||
const Entry* operator->() const
|
||||
{
|
||||
@@ -153,7 +153,7 @@ namespace BAN
|
||||
{
|
||||
if (auto it = m_hash_set.find(key); it != m_hash_set.end())
|
||||
{
|
||||
it->value = T(BAN::forward<Args>(args)...);
|
||||
const_cast<T&>(it->value) = T(BAN::forward<Args>(args)...);
|
||||
return iterator(it);
|
||||
}
|
||||
|
||||
|
||||
@@ -15,22 +15,12 @@ namespace BAN
|
||||
public:
|
||||
HashSetIterator() = default;
|
||||
|
||||
T& operator*()
|
||||
{
|
||||
ASSERT(m_bucket);
|
||||
return *m_bucket->element();
|
||||
}
|
||||
const T& operator*() const
|
||||
{
|
||||
ASSERT(m_bucket);
|
||||
return *m_bucket->element();
|
||||
}
|
||||
|
||||
T* operator->()
|
||||
{
|
||||
ASSERT(m_bucket);
|
||||
return m_bucket->element();
|
||||
}
|
||||
const T* operator->() const
|
||||
{
|
||||
ASSERT(m_bucket);
|
||||
@@ -81,6 +71,12 @@ namespace BAN
|
||||
friend HashSet;
|
||||
};
|
||||
|
||||
namespace detail
|
||||
{
|
||||
template<typename T, typename U, typename HASH, typename COMP>
|
||||
concept HashSetFindable = requires(const U& a, const T& b) { COMP()(a, b); HASH()(b); };
|
||||
}
|
||||
|
||||
template<typename T, typename HASH = BAN::hash<T>, typename COMP = BAN::equal<T>>
|
||||
class HashSet
|
||||
{
|
||||
@@ -166,7 +162,8 @@ namespace BAN
|
||||
{
|
||||
if (!COMP()(*bucket.element(), value))
|
||||
continue;
|
||||
*bucket.element() = BAN::move(value);
|
||||
bucket.element()->~T();
|
||||
new (bucket.element()) T(BAN::move(value));
|
||||
}
|
||||
else
|
||||
{
|
||||
@@ -185,7 +182,8 @@ namespace BAN
|
||||
}
|
||||
}
|
||||
|
||||
void remove(const T& value)
|
||||
template<detail::HashSetFindable<T, HASH, COMP> U>
|
||||
void remove(const U& value)
|
||||
{
|
||||
if (auto it = find(value); it != end())
|
||||
remove(it);
|
||||
@@ -202,13 +200,13 @@ namespace BAN
|
||||
return iterator(&bucket);
|
||||
}
|
||||
|
||||
template<typename U>
|
||||
template<detail::HashSetFindable<T, HASH, COMP> U>
|
||||
iterator find(const U& value)
|
||||
{
|
||||
return iterator(const_cast<Bucket*>(find_impl(value).m_bucket));
|
||||
}
|
||||
|
||||
template<typename U>
|
||||
template<detail::HashSetFindable<T, HASH, COMP> U>
|
||||
const_iterator find(const U& value) const
|
||||
{
|
||||
return find_impl(value);
|
||||
@@ -240,7 +238,8 @@ namespace BAN
|
||||
return {};
|
||||
}
|
||||
|
||||
bool contains(const T& value) const
|
||||
template<detail::HashSetFindable<T, HASH, COMP> U>
|
||||
bool contains(const U& value) const
|
||||
{
|
||||
return find(value) != end();
|
||||
}
|
||||
@@ -295,7 +294,7 @@ namespace BAN
|
||||
return {};
|
||||
}
|
||||
|
||||
template<typename U> requires requires(const T& a, const U& b) { COMP()(a, b); HASH()(b); }
|
||||
template<detail::HashSetFindable<T, HASH, COMP> U>
|
||||
const_iterator find_impl(const U& value) const
|
||||
{
|
||||
if (m_capacity == 0)
|
||||
|
||||
Reference in New Issue
Block a user