AK: Defer to Traits<T> for equality comparison in container templates.

This is prep work for supporting HashMap with NonnullRefPtr<T> as values.
It's currently not possible because many HashTable functions require being
able to default-construct the value type.
This commit is contained in:
Andreas Kling 2019-06-29 19:14:03 +02:00
parent 9a7dc06567
commit d5bb98acbc
Notes: sideshowbarker 2024-07-19 13:26:56 +09:00
14 changed files with 61 additions and 31 deletions

View file

@ -203,7 +203,7 @@ inline bool StringView::operator==(const String& string) const
}
template<>
struct Traits<String> {
struct Traits<String> : public GenericTraits<String> {
static unsigned hash(const String& s) { return s.impl() ? s.impl()->hash() : 0; }
static void dump(const String& s) { kprintf("%s", s.characters()); }
};

View file

@ -1,7 +1,8 @@
#pragma once
#include "StdLibExtras.h"
#include <AK/Assertions.h>
#include <AK/StdLibExtras.h>
#include <AK/Traits.h>
namespace AK {
@ -116,7 +117,7 @@ public:
ConstIterator find(const T& value) const
{
for (auto* node = m_head; node; node = node->next) {
if (node->value == value)
if (Traits<T>::equals(node->value, value))
return ConstIterator(node);
}
return end();
@ -125,7 +126,7 @@ public:
Iterator find(const T& value)
{
for (auto* node = m_head; node; node = node->next) {
if (node->value == value)
if (Traits<T>::equals(node->value, value))
return Iterator(node);
}
return end();

View file

@ -13,15 +13,11 @@ private:
struct Entry {
K key;
V value;
bool operator==(const Entry& other) const
{
return key == other.key;
}
};
struct EntryTraits {
static unsigned hash(const Entry& entry) { return Traits<K>::hash(entry.key); }
static bool equals(const Entry& a, const Entry& b) { return a.key == b.key; }
static void dump(const Entry& entry)
{
kprintf("key=");

View file

@ -181,7 +181,7 @@ void HashTable<T, TraitsForT>::set(T&& value)
rehash(1);
auto& bucket = lookup(value);
for (auto& e : bucket) {
if (e == value) {
if (TraitsForT::equals(e, value)) {
e = move(value);
return;
}
@ -202,7 +202,7 @@ void HashTable<T, TraitsForT>::set(const T& value)
rehash(1);
auto& bucket = lookup(value);
for (auto& e : bucket) {
if (e == value) {
if (TraitsForT::equals(e, value)) {
e = value;
return;
}
@ -267,7 +267,7 @@ bool HashTable<T, TraitsForT>::contains(const T& value) const
return false;
auto& bucket = lookup(value);
for (auto& e : bucket) {
if (e == value)
if (TraitsForT::equals(e, value))
return true;
}
return false;
@ -280,7 +280,7 @@ auto HashTable<T, TraitsForT>::find(const T& value) -> Iterator
return end();
int bucket_index;
auto& bucket = lookup(value, &bucket_index);
auto bucket_iterator = bucket.find(value);
auto bucket_iterator = bucket.template find<TraitsForT>(value);
if (bucket_iterator != bucket.end())
return Iterator(*this, false, bucket_iterator, bucket_index);
return end();
@ -293,7 +293,7 @@ auto HashTable<T, TraitsForT>::find(const T& value) const -> ConstIterator
return end();
int bucket_index;
const auto& bucket = lookup(value, &bucket_index);
auto bucket_iterator = bucket.find(value);
auto bucket_iterator = bucket.template find<TraitsForT>(value);
if (bucket_iterator != bucket.end())
return ConstIterator(*this, false, bucket_iterator, bucket_index);
return end();

View file

@ -52,7 +52,7 @@ private:
static_assert(sizeof(IPv4Address) == 4);
template<>
struct Traits<IPv4Address> {
struct Traits<IPv4Address> : public GenericTraits<IPv4Address> {
static unsigned hash(const IPv4Address& address) { return string_hash((const char*)&address, sizeof(address)); }
static void dump(const IPv4Address& address) { kprintf("%s", address.to_string().characters()); }
};

View file

@ -109,9 +109,10 @@ make(Args&&... args)
}
template<typename T>
struct Traits<OwnPtr<T>> {
struct Traits<OwnPtr<T>> : public GenericTraits<OwnPtr<T>> {
static unsigned hash(const OwnPtr<T>& p) { return (unsigned)p.ptr(); }
static void dump(const OwnPtr<T>& p) { kprintf("%p", p.ptr()); }
static bool equals(const OwnPtr<T>& a, const OwnPtr<T>& b) { return a.ptr() == b.ptr(); }
};
}

View file

@ -169,6 +169,30 @@ public:
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();
}
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();
}
void remove(Iterator iterator)
{
ASSERT(!iterator.is_end());

View file

@ -6,25 +6,30 @@
namespace AK {
template<typename T>
struct Traits {
struct GenericTraits {
static bool equals(const T& a, const T& b) { return a == b; }
};
template<typename T>
struct Traits : public GenericTraits<T> {
};
template<>
struct Traits<int> {
struct Traits<int> : public GenericTraits<int> {
static unsigned hash(int i) { return int_hash(i); }
static void dump(int i) { kprintf("%d", i); }
};
template<>
struct Traits<unsigned> {
struct Traits<unsigned> : public GenericTraits<unsigned> {
static unsigned hash(unsigned u) { return int_hash(u); }
static void dump(unsigned u) { kprintf("%u", u); }
};
template<>
struct Traits<word> {
static unsigned hash(unsigned u) { return int_hash(u); }
static void dump(unsigned u) { kprintf("%u", u); }
struct Traits<word> : public GenericTraits<word> {
static unsigned hash(word u) { return int_hash(u); }
static void dump(word u) { kprintf("%u", u); }
};
template<typename T>
@ -34,6 +39,7 @@ struct Traits<T*> {
return int_hash((unsigned)(__PTRDIFF_TYPE__)p);
}
static void dump(const T* p) { kprintf("%p", p); }
static bool equals(const T* a, const T* b) { return a == b; }
};
}

View file

@ -2,6 +2,7 @@
#include <AK/Assertions.h>
#include <AK/StdLibExtras.h>
#include <AK/Traits.h>
#include <AK/kmalloc.h>
// NOTE: We can't include <initializer_list> during the toolchain bootstrap,
@ -17,7 +18,8 @@
namespace AK {
template<typename T, int inline_capacity> class Vector;
template<typename T, int inline_capacity>
class Vector;
template<typename VectorType, typename ElementType>
class VectorIterator {
@ -148,7 +150,7 @@ public:
bool contains_slow(const T& value) const
{
for (int i = 0; i < size(); ++i) {
if (at(i) == value)
if (Traits<T>::equals(at(i), value))
return true;
}
return false;

View file

@ -26,7 +26,7 @@ private:
namespace AK {
template<>
struct Traits<WindowIdentifier> {
struct Traits<WindowIdentifier> : public GenericTraits<WindowIdentifier> {
static unsigned hash(const WindowIdentifier& w) { return pair_int_hash(w.client_id(), w.window_id()); }
static void dump(const WindowIdentifier& w) { kprintf("WindowIdentifier(%d, %d)", w.client_id(), w.window_id()); }
};

View file

@ -15,7 +15,7 @@ struct BlockIdentifier {
namespace AK {
template<>
struct Traits<BlockIdentifier> {
struct Traits<BlockIdentifier> : public GenericTraits<BlockIdentifier> {
static unsigned hash(const BlockIdentifier& block_id) { return pair_int_hash(block_id.fsid, block_id.index); }
static void dump(const BlockIdentifier& block_id) { kprintf("[block %02u:%08u]", block_id.fsid, block_id.index); }
};

View file

@ -89,7 +89,7 @@ inline bool InodeIdentifier::is_root_inode() const
namespace AK {
template<>
struct Traits<InodeIdentifier> {
struct Traits<InodeIdentifier> : public GenericTraits<InodeIdentifier> {
static unsigned hash(const InodeIdentifier& inode) { return pair_int_hash(inode.fsid(), inode.index()); }
static void dump(const InodeIdentifier& inode) { kprintf("%02u:%08u", inode.fsid(), inode.index()); }
};

View file

@ -40,7 +40,7 @@ static_assert(sizeof(MACAddress) == 6);
namespace AK {
template<>
struct Traits<MACAddress> {
struct Traits<MACAddress> : public GenericTraits<MACAddress> {
static unsigned hash(const MACAddress& address) { return string_hash((const char*)&address, sizeof(address)); }
static void dump(const MACAddress& address) { kprintf("%s", address.to_string().characters()); }
};

View file

@ -32,7 +32,7 @@ private:
namespace AK {
template<>
struct Traits<GShortcut> {
struct Traits<GShortcut> : public GenericTraits<GShortcut> {
static unsigned hash(const GShortcut& shortcut)
{
return pair_int_hash(shortcut.modifiers(), shortcut.key());