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*()
|
Entry& operator*()
|
||||||
{
|
{
|
||||||
return m_iterator.operator*();
|
return const_cast<Entry&>(m_iterator.operator*());
|
||||||
}
|
}
|
||||||
const Entry& operator*() const
|
const Entry& operator*() const
|
||||||
{
|
{
|
||||||
@@ -22,7 +22,7 @@ namespace BAN
|
|||||||
|
|
||||||
Entry* operator->()
|
Entry* operator->()
|
||||||
{
|
{
|
||||||
return m_iterator.operator->();
|
return const_cast<Entry*>(m_iterator.operator->());
|
||||||
}
|
}
|
||||||
const Entry* operator->() const
|
const Entry* operator->() const
|
||||||
{
|
{
|
||||||
@@ -153,7 +153,7 @@ namespace BAN
|
|||||||
{
|
{
|
||||||
if (auto it = m_hash_set.find(key); it != m_hash_set.end())
|
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);
|
return iterator(it);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|||||||
@@ -15,22 +15,12 @@ namespace BAN
|
|||||||
public:
|
public:
|
||||||
HashSetIterator() = default;
|
HashSetIterator() = default;
|
||||||
|
|
||||||
T& operator*()
|
|
||||||
{
|
|
||||||
ASSERT(m_bucket);
|
|
||||||
return *m_bucket->element();
|
|
||||||
}
|
|
||||||
const T& operator*() const
|
const T& operator*() const
|
||||||
{
|
{
|
||||||
ASSERT(m_bucket);
|
ASSERT(m_bucket);
|
||||||
return *m_bucket->element();
|
return *m_bucket->element();
|
||||||
}
|
}
|
||||||
|
|
||||||
T* operator->()
|
|
||||||
{
|
|
||||||
ASSERT(m_bucket);
|
|
||||||
return m_bucket->element();
|
|
||||||
}
|
|
||||||
const T* operator->() const
|
const T* operator->() const
|
||||||
{
|
{
|
||||||
ASSERT(m_bucket);
|
ASSERT(m_bucket);
|
||||||
@@ -81,6 +71,12 @@ namespace BAN
|
|||||||
friend HashSet;
|
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>>
|
template<typename T, typename HASH = BAN::hash<T>, typename COMP = BAN::equal<T>>
|
||||||
class HashSet
|
class HashSet
|
||||||
{
|
{
|
||||||
@@ -166,7 +162,8 @@ namespace BAN
|
|||||||
{
|
{
|
||||||
if (!COMP()(*bucket.element(), value))
|
if (!COMP()(*bucket.element(), value))
|
||||||
continue;
|
continue;
|
||||||
*bucket.element() = BAN::move(value);
|
bucket.element()->~T();
|
||||||
|
new (bucket.element()) T(BAN::move(value));
|
||||||
}
|
}
|
||||||
else
|
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())
|
if (auto it = find(value); it != end())
|
||||||
remove(it);
|
remove(it);
|
||||||
@@ -202,13 +200,13 @@ namespace BAN
|
|||||||
return iterator(&bucket);
|
return iterator(&bucket);
|
||||||
}
|
}
|
||||||
|
|
||||||
template<typename U>
|
template<detail::HashSetFindable<T, HASH, COMP> U>
|
||||||
iterator find(const U& value)
|
iterator find(const U& value)
|
||||||
{
|
{
|
||||||
return iterator(const_cast<Bucket*>(find_impl(value).m_bucket));
|
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
|
const_iterator find(const U& value) const
|
||||||
{
|
{
|
||||||
return find_impl(value);
|
return find_impl(value);
|
||||||
@@ -240,7 +238,8 @@ namespace BAN
|
|||||||
return {};
|
return {};
|
||||||
}
|
}
|
||||||
|
|
||||||
bool contains(const T& value) const
|
template<detail::HashSetFindable<T, HASH, COMP> U>
|
||||||
|
bool contains(const U& value) const
|
||||||
{
|
{
|
||||||
return find(value) != end();
|
return find(value) != end();
|
||||||
}
|
}
|
||||||
@@ -295,7 +294,7 @@ namespace BAN
|
|||||||
return {};
|
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
|
const_iterator find_impl(const U& value) const
|
||||||
{
|
{
|
||||||
if (m_capacity == 0)
|
if (m_capacity == 0)
|
||||||
|
|||||||
Reference in New Issue
Block a user