AK: Allow HashMap to be used with non-default-constructible values.
Solve this by adding find() overloads to HashTable and SinglyLinkedList that take a templated functor for comparing the values. This allows HashMap to call HashTable::find() without having to create a temporary Entry for use as the table key. :^)
This commit is contained in:
parent
d5bb98acbc
commit
6e95b11395
Notes:
sideshowbarker
2024-07-19 13:26:53 +09:00
Author: https://github.com/awesomekling Commit: https://github.com/SerenityOS/serenity/commit/6e95b113957
3 changed files with 67 additions and 51 deletions
11
AK/HashMap.h
11
AK/HashMap.h
|
@ -37,7 +37,12 @@ public:
|
|||
|
||||
void set(const K& key, const V& value) { m_table.set({ key, value }); }
|
||||
void set(const K& key, V&& value) { m_table.set({ key, move(value) }); }
|
||||
void remove(const K& key) { m_table.remove({ key, V() }); }
|
||||
void remove(const K& key)
|
||||
{
|
||||
auto it = find(key);
|
||||
if (it != end())
|
||||
m_table.remove(it);
|
||||
}
|
||||
void remove_one_randomly() { m_table.remove(m_table.begin()); }
|
||||
|
||||
typedef HashTable<Entry, EntryTraits> HashTableType;
|
||||
|
@ -46,11 +51,11 @@ public:
|
|||
|
||||
IteratorType begin() { return m_table.begin(); }
|
||||
IteratorType end() { return m_table.end(); }
|
||||
IteratorType find(const K& key) { return m_table.find({ key, V() }); }
|
||||
IteratorType find(const K& key) { return m_table.find(Traits<K>::hash(key), [&](auto& entry) { return key == entry.key; }); }
|
||||
|
||||
ConstIteratorType begin() const { return m_table.begin(); }
|
||||
ConstIteratorType end() const { return m_table.end(); }
|
||||
ConstIteratorType find(const K& key) const { return m_table.find({ key, V() }); }
|
||||
ConstIteratorType find(const K& key) const { return m_table.find(Traits<K>::hash(key), [&](auto& entry) { return key == entry.key; }); }
|
||||
|
||||
void ensure_capacity(int capacity) { m_table.ensure_capacity(capacity); }
|
||||
|
||||
|
|
|
@ -146,8 +146,42 @@ public:
|
|||
ConstIterator begin() const { return ConstIterator(*this, is_empty()); }
|
||||
ConstIterator end() const { return ConstIterator(*this, true); }
|
||||
|
||||
Iterator find(const T&);
|
||||
ConstIterator find(const T&) const;
|
||||
|
||||
template<typename Finder>
|
||||
Iterator find(unsigned hash, Finder finder)
|
||||
{
|
||||
if (is_empty())
|
||||
return end();
|
||||
int bucket_index;
|
||||
auto& bucket = lookup_with_hash(hash, &bucket_index);
|
||||
auto bucket_iterator = bucket.find(finder);
|
||||
if (bucket_iterator != bucket.end())
|
||||
return Iterator(*this, false, bucket_iterator, bucket_index);
|
||||
return end();
|
||||
}
|
||||
|
||||
template<typename Finder>
|
||||
ConstIterator find(unsigned hash, Finder finder) const
|
||||
{
|
||||
if (is_empty())
|
||||
return end();
|
||||
int bucket_index;
|
||||
auto& bucket = lookup_with_hash(hash, &bucket_index);
|
||||
auto bucket_iterator = bucket.find(finder);
|
||||
if (bucket_iterator != bucket.end())
|
||||
return ConstIterator(*this, false, bucket_iterator, bucket_index);
|
||||
return end();
|
||||
}
|
||||
|
||||
Iterator find(const T& value)
|
||||
{
|
||||
return find(TraitsForT::hash(value), [&](auto& other) { return TraitsForT::equals(value, other); });
|
||||
}
|
||||
|
||||
ConstIterator find(const T& value) const
|
||||
{
|
||||
return find(TraitsForT::hash(value), [&](auto& other) { return TraitsForT::equals(value, other); });
|
||||
}
|
||||
|
||||
void remove(const T& value)
|
||||
{
|
||||
|
@ -161,6 +195,21 @@ public:
|
|||
private:
|
||||
Bucket& lookup(const T&, int* bucket_index = nullptr);
|
||||
const Bucket& lookup(const T&, int* bucket_index = nullptr) const;
|
||||
|
||||
Bucket& lookup_with_hash(unsigned hash, int* bucket_index)
|
||||
{
|
||||
if (bucket_index)
|
||||
*bucket_index = hash % m_capacity;
|
||||
return m_buckets[hash % m_capacity];
|
||||
}
|
||||
|
||||
const Bucket& lookup_with_hash(unsigned hash, int* bucket_index) const
|
||||
{
|
||||
if (bucket_index)
|
||||
*bucket_index = hash % m_capacity;
|
||||
return m_buckets[hash % m_capacity];
|
||||
}
|
||||
|
||||
void rehash(int capacity);
|
||||
void insert(const T&);
|
||||
void insert(T&&);
|
||||
|
@ -273,32 +322,6 @@ bool HashTable<T, TraitsForT>::contains(const T& value) const
|
|||
return false;
|
||||
}
|
||||
|
||||
template<typename T, typename TraitsForT>
|
||||
auto HashTable<T, TraitsForT>::find(const T& value) -> Iterator
|
||||
{
|
||||
if (is_empty())
|
||||
return end();
|
||||
int bucket_index;
|
||||
auto& bucket = lookup(value, &bucket_index);
|
||||
auto bucket_iterator = bucket.template find<TraitsForT>(value);
|
||||
if (bucket_iterator != bucket.end())
|
||||
return Iterator(*this, false, bucket_iterator, bucket_index);
|
||||
return end();
|
||||
}
|
||||
|
||||
template<typename T, typename TraitsForT>
|
||||
auto HashTable<T, TraitsForT>::find(const T& value) const -> ConstIterator
|
||||
{
|
||||
if (is_empty())
|
||||
return end();
|
||||
int bucket_index;
|
||||
const auto& bucket = lookup(value, &bucket_index);
|
||||
auto bucket_iterator = bucket.template find<TraitsForT>(value);
|
||||
if (bucket_iterator != bucket.end())
|
||||
return ConstIterator(*this, false, bucket_iterator, bucket_index);
|
||||
return end();
|
||||
}
|
||||
|
||||
template<typename T, typename TraitsForT>
|
||||
void HashTable<T, TraitsForT>::remove(Iterator it)
|
||||
{
|
||||
|
|
|
@ -147,50 +147,38 @@ public:
|
|||
ConstIterator begin() const { return ConstIterator(m_head); }
|
||||
ConstIterator end() const { return ConstIterator::universal_end(); }
|
||||
|
||||
ConstIterator find(const T& value) const
|
||||
template<typename Finder>
|
||||
ConstIterator find(Finder finder) const
|
||||
{
|
||||
Node* prev = nullptr;
|
||||
for (auto* node = m_head; node; node = node->next) {
|
||||
if (node->value == value)
|
||||
if (finder(node->value))
|
||||
return ConstIterator(node, prev);
|
||||
prev = node;
|
||||
}
|
||||
return end();
|
||||
}
|
||||
|
||||
Iterator find(const T& value)
|
||||
template<typename Finder>
|
||||
Iterator find(Finder finder)
|
||||
{
|
||||
Node* prev = nullptr;
|
||||
for (auto* node = m_head; node; node = node->next) {
|
||||
if (node->value == value)
|
||||
if (finder(node->value))
|
||||
return Iterator(node, prev);
|
||||
prev = node;
|
||||
}
|
||||
return end();
|
||||
}
|
||||
|
||||
template<typename Traits>
|
||||
ConstIterator find(const T& value) const
|
||||
{
|
||||
Node* prev = nullptr;
|
||||
for (auto* node = m_head; node; node = node->next) {
|
||||
if (Traits::equals(node->value, value))
|
||||
return ConstIterator(node, prev);
|
||||
prev = node;
|
||||
}
|
||||
return end();
|
||||
return find([&](auto& other) { return value == other; });
|
||||
}
|
||||
|
||||
template<typename Traits>
|
||||
Iterator find(const T& value)
|
||||
{
|
||||
Node* prev = nullptr;
|
||||
for (auto* node = m_head; node; node = node->next) {
|
||||
if (Traits::equals(node->value, value))
|
||||
return Iterator(node, prev);
|
||||
prev = node;
|
||||
}
|
||||
return end();
|
||||
return find([&](auto& other) { return value == other; });
|
||||
}
|
||||
|
||||
void remove(Iterator iterator)
|
||||
|
|
Loading…
Add table
Reference in a new issue