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<> template<>
struct Traits<String> { struct Traits<String> : public GenericTraits<String> {
static unsigned hash(const String& s) { return s.impl() ? s.impl()->hash() : 0; } static unsigned hash(const String& s) { return s.impl() ? s.impl()->hash() : 0; }
static void dump(const String& s) { kprintf("%s", s.characters()); } static void dump(const String& s) { kprintf("%s", s.characters()); }
}; };

View file

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

View file

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

View file

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

View file

@ -52,7 +52,7 @@ private:
static_assert(sizeof(IPv4Address) == 4); static_assert(sizeof(IPv4Address) == 4);
template<> 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 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()); } static void dump(const IPv4Address& address) { kprintf("%s", address.to_string().characters()); }
}; };

View file

@ -109,9 +109,10 @@ make(Args&&... args)
} }
template<typename T> 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 unsigned hash(const OwnPtr<T>& p) { return (unsigned)p.ptr(); }
static void dump(const OwnPtr<T>& p) { kprintf("%p", 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(); 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) void remove(Iterator iterator)
{ {
ASSERT(!iterator.is_end()); ASSERT(!iterator.is_end());

View file

@ -6,25 +6,30 @@
namespace AK { namespace AK {
template<typename T> 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<> template<>
struct Traits<int> { struct Traits<int> : public GenericTraits<int> {
static unsigned hash(int i) { return int_hash(i); } static unsigned hash(int i) { return int_hash(i); }
static void dump(int i) { kprintf("%d", i); } static void dump(int i) { kprintf("%d", i); }
}; };
template<> template<>
struct Traits<unsigned> { struct Traits<unsigned> : public GenericTraits<unsigned> {
static unsigned hash(unsigned u) { return int_hash(u); } static unsigned hash(unsigned u) { return int_hash(u); }
static void dump(unsigned u) { kprintf("%u", u); } static void dump(unsigned u) { kprintf("%u", u); }
}; };
template<> template<>
struct Traits<word> { struct Traits<word> : public GenericTraits<word> {
static unsigned hash(unsigned u) { return int_hash(u); } static unsigned hash(word u) { return int_hash(u); }
static void dump(unsigned u) { kprintf("%u", u); } static void dump(word u) { kprintf("%u", u); }
}; };
template<typename T> template<typename T>
@ -34,6 +39,7 @@ struct Traits<T*> {
return int_hash((unsigned)(__PTRDIFF_TYPE__)p); return int_hash((unsigned)(__PTRDIFF_TYPE__)p);
} }
static void dump(const T* p) { kprintf("%p", 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,22 +2,24 @@
#include <AK/Assertions.h> #include <AK/Assertions.h>
#include <AK/StdLibExtras.h> #include <AK/StdLibExtras.h>
#include <AK/Traits.h>
#include <AK/kmalloc.h> #include <AK/kmalloc.h>
// NOTE: We can't include <initializer_list> during the toolchain bootstrap, // NOTE: We can't include <initializer_list> during the toolchain bootstrap,
// since it's part of libstdc++, and libstdc++ depends on LibC. // since it's part of libstdc++, and libstdc++ depends on LibC.
// For this reason, we don't support Vector(initializer_list) in LibC. // For this reason, we don't support Vector(initializer_list) in LibC.
#ifndef SERENITY_LIBC_BUILD #ifndef SERENITY_LIBC_BUILD
#include <initializer_list> # include <initializer_list>
#endif #endif
#ifndef __serenity__ #ifndef __serenity__
#include <new> # include <new>
#endif #endif
namespace AK { namespace AK {
template<typename T, int inline_capacity> class Vector; template<typename T, int inline_capacity>
class Vector;
template<typename VectorType, typename ElementType> template<typename VectorType, typename ElementType>
class VectorIterator { class VectorIterator {
@ -148,7 +150,7 @@ public:
bool contains_slow(const T& value) const bool contains_slow(const T& value) const
{ {
for (int i = 0; i < size(); ++i) { for (int i = 0; i < size(); ++i) {
if (at(i) == value) if (Traits<T>::equals(at(i), value))
return true; return true;
} }
return false; return false;

View file

@ -26,7 +26,7 @@ private:
namespace AK { namespace AK {
template<> 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 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()); } 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 { namespace AK {
template<> 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 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); } 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 { namespace AK {
template<> 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 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()); } 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 { namespace AK {
template<> 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 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()); } static void dump(const MACAddress& address) { kprintf("%s", address.to_string().characters()); }
}; };

View file

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