mirror of
https://github.com/LadybirdBrowser/ladybird.git
synced 2024-11-21 23:20:20 +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<>
|
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()); }
|
||||||
};
|
};
|
||||||
|
|
|
@ -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();
|
||||||
|
|
|
@ -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=");
|
||||||
|
|
|
@ -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();
|
||||||
|
|
|
@ -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()); }
|
||||||
};
|
};
|
||||||
|
|
|
@ -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(); }
|
||||||
};
|
};
|
||||||
|
|
||||||
}
|
}
|
||||||
|
|
|
@ -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());
|
||||||
|
|
18
AK/Traits.h
18
AK/Traits.h
|
@ -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; }
|
||||||
};
|
};
|
||||||
|
|
||||||
}
|
}
|
||||||
|
|
10
AK/Vector.h
10
AK/Vector.h
|
@ -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;
|
||||||
|
|
|
@ -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()); }
|
||||||
};
|
};
|
||||||
|
|
|
@ -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); }
|
||||||
};
|
};
|
||||||
|
|
|
@ -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()); }
|
||||||
};
|
};
|
||||||
|
|
|
@ -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()); }
|
||||||
};
|
};
|
||||||
|
|
|
@ -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());
|
||||||
|
|
Loading…
Reference in a new issue