mirror of
https://github.com/LadybirdBrowser/ladybird.git
synced 2024-11-25 09:00:22 +00:00
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:
parent
9a7dc06567
commit
d5bb98acbc
Notes:
sideshowbarker
2024-07-19 13:26:56 +09:00
Author: https://github.com/awesomekling Commit: https://github.com/SerenityOS/serenity/commit/d5bb98acbcd
14 changed files with 61 additions and 31 deletions
|
@ -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()); }
|
||||
};
|
||||
|
|
|
@ -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();
|
||||
|
|
|
@ -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=");
|
||||
|
|
|
@ -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();
|
||||
|
|
|
@ -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()); }
|
||||
};
|
||||
|
|
|
@ -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(); }
|
||||
};
|
||||
|
||||
}
|
||||
|
|
|
@ -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());
|
||||
|
|
18
AK/Traits.h
18
AK/Traits.h
|
@ -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; }
|
||||
};
|
||||
|
||||
}
|
||||
|
|
|
@ -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;
|
||||
|
|
|
@ -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()); }
|
||||
};
|
||||
|
|
|
@ -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); }
|
||||
};
|
||||
|
|
|
@ -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()); }
|
||||
};
|
||||
|
|
|
@ -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()); }
|
||||
};
|
||||
|
|
|
@ -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());
|
||||
|
|
Loading…
Reference in a new issue