From d5bb98acbcdbd39fcc8d028517189f44bc78e710 Mon Sep 17 00:00:00 2001 From: Andreas Kling Date: Sat, 29 Jun 2019 19:14:03 +0200 Subject: [PATCH] AK: Defer to Traits for equality comparison in container templates. This is prep work for supporting HashMap with NonnullRefPtr as values. It's currently not possible because many HashTable functions require being able to default-construct the value type. --- AK/AKString.h | 2 +- AK/DoublyLinkedList.h | 7 ++++--- AK/HashMap.h | 6 +----- AK/HashTable.h | 10 ++++----- AK/IPv4Address.h | 2 +- AK/OwnPtr.h | 3 ++- AK/SinglyLinkedList.h | 24 ++++++++++++++++++++++ AK/Traits.h | 18 ++++++++++------ AK/Vector.h | 10 +++++---- Applications/Taskbar/WindowIdentifier.h | 2 +- Kernel/FileSystem/DiskBackedFileSystem.cpp | 2 +- Kernel/FileSystem/FileSystem.h | 2 +- Kernel/Net/MACAddress.h | 2 +- LibGUI/GShortcut.h | 2 +- 14 files changed, 61 insertions(+), 31 deletions(-) diff --git a/AK/AKString.h b/AK/AKString.h index 886819b85e..a7de84b856 100644 --- a/AK/AKString.h +++ b/AK/AKString.h @@ -203,7 +203,7 @@ inline bool StringView::operator==(const String& string) const } template<> -struct Traits { +struct Traits : public GenericTraits { static unsigned hash(const String& s) { return s.impl() ? s.impl()->hash() : 0; } static void dump(const String& s) { kprintf("%s", s.characters()); } }; diff --git a/AK/DoublyLinkedList.h b/AK/DoublyLinkedList.h index 1d30c8a1c7..5fe83b309e 100644 --- a/AK/DoublyLinkedList.h +++ b/AK/DoublyLinkedList.h @@ -1,7 +1,8 @@ #pragma once -#include "StdLibExtras.h" #include +#include +#include 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::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::equals(node->value, value)) return Iterator(node); } return end(); diff --git a/AK/HashMap.h b/AK/HashMap.h index ea85b805a4..d6fed82763 100644 --- a/AK/HashMap.h +++ b/AK/HashMap.h @@ -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::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="); diff --git a/AK/HashTable.h b/AK/HashTable.h index 346d65bfe0..0e10730e6a 100644 --- a/AK/HashTable.h +++ b/AK/HashTable.h @@ -181,7 +181,7 @@ void HashTable::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::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::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::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(value); if (bucket_iterator != bucket.end()) return Iterator(*this, false, bucket_iterator, bucket_index); return end(); @@ -293,7 +293,7 @@ auto HashTable::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(value); if (bucket_iterator != bucket.end()) return ConstIterator(*this, false, bucket_iterator, bucket_index); return end(); diff --git a/AK/IPv4Address.h b/AK/IPv4Address.h index 56dc3d57ce..d3d1bf1dfa 100644 --- a/AK/IPv4Address.h +++ b/AK/IPv4Address.h @@ -52,7 +52,7 @@ private: static_assert(sizeof(IPv4Address) == 4); template<> -struct Traits { +struct Traits : public GenericTraits { 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()); } }; diff --git a/AK/OwnPtr.h b/AK/OwnPtr.h index 64168e8596..c301323553 100644 --- a/AK/OwnPtr.h +++ b/AK/OwnPtr.h @@ -109,9 +109,10 @@ make(Args&&... args) } template -struct Traits> { +struct Traits> : public GenericTraits> { static unsigned hash(const OwnPtr& p) { return (unsigned)p.ptr(); } static void dump(const OwnPtr& p) { kprintf("%p", p.ptr()); } + static bool equals(const OwnPtr& a, const OwnPtr& b) { return a.ptr() == b.ptr(); } }; } diff --git a/AK/SinglyLinkedList.h b/AK/SinglyLinkedList.h index d6d55b5917..59b2f1665a 100644 --- a/AK/SinglyLinkedList.h +++ b/AK/SinglyLinkedList.h @@ -169,6 +169,30 @@ public: return end(); } + template + 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 + 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()); diff --git a/AK/Traits.h b/AK/Traits.h index f0ecb9ae2d..63080b5883 100644 --- a/AK/Traits.h +++ b/AK/Traits.h @@ -6,25 +6,30 @@ namespace AK { template -struct Traits { +struct GenericTraits { + static bool equals(const T& a, const T& b) { return a == b; } +}; + +template +struct Traits : public GenericTraits { }; template<> -struct Traits { +struct Traits : public GenericTraits { static unsigned hash(int i) { return int_hash(i); } static void dump(int i) { kprintf("%d", i); } }; template<> -struct Traits { +struct Traits : public GenericTraits { static unsigned hash(unsigned u) { return int_hash(u); } static void dump(unsigned u) { kprintf("%u", u); } }; template<> -struct Traits { - static unsigned hash(unsigned u) { return int_hash(u); } - static void dump(unsigned u) { kprintf("%u", u); } +struct Traits : public GenericTraits { + static unsigned hash(word u) { return int_hash(u); } + static void dump(word u) { kprintf("%u", u); } }; template @@ -34,6 +39,7 @@ struct Traits { 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; } }; } diff --git a/AK/Vector.h b/AK/Vector.h index 1ae11d6cab..176b05d9ff 100644 --- a/AK/Vector.h +++ b/AK/Vector.h @@ -2,22 +2,24 @@ #include #include +#include #include // NOTE: We can't include during the toolchain bootstrap, // since it's part of libstdc++, and libstdc++ depends on LibC. // For this reason, we don't support Vector(initializer_list) in LibC. #ifndef SERENITY_LIBC_BUILD -#include +# include #endif #ifndef __serenity__ -#include +# include #endif namespace AK { -template class Vector; +template +class Vector; template 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::equals(at(i), value)) return true; } return false; diff --git a/Applications/Taskbar/WindowIdentifier.h b/Applications/Taskbar/WindowIdentifier.h index f5fcd65bfc..7d849d36ec 100644 --- a/Applications/Taskbar/WindowIdentifier.h +++ b/Applications/Taskbar/WindowIdentifier.h @@ -26,7 +26,7 @@ private: namespace AK { template<> -struct Traits { +struct Traits : public GenericTraits { 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()); } }; diff --git a/Kernel/FileSystem/DiskBackedFileSystem.cpp b/Kernel/FileSystem/DiskBackedFileSystem.cpp index d8b66803a1..6a3f8ddc90 100644 --- a/Kernel/FileSystem/DiskBackedFileSystem.cpp +++ b/Kernel/FileSystem/DiskBackedFileSystem.cpp @@ -15,7 +15,7 @@ struct BlockIdentifier { namespace AK { template<> -struct Traits { +struct Traits : public GenericTraits { 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); } }; diff --git a/Kernel/FileSystem/FileSystem.h b/Kernel/FileSystem/FileSystem.h index 58f839faef..55d48a4ff8 100644 --- a/Kernel/FileSystem/FileSystem.h +++ b/Kernel/FileSystem/FileSystem.h @@ -89,7 +89,7 @@ inline bool InodeIdentifier::is_root_inode() const namespace AK { template<> -struct Traits { +struct Traits : public GenericTraits { 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()); } }; diff --git a/Kernel/Net/MACAddress.h b/Kernel/Net/MACAddress.h index 3cf906decb..72069bdaa5 100644 --- a/Kernel/Net/MACAddress.h +++ b/Kernel/Net/MACAddress.h @@ -40,7 +40,7 @@ static_assert(sizeof(MACAddress) == 6); namespace AK { template<> -struct Traits { +struct Traits : public GenericTraits { 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()); } }; diff --git a/LibGUI/GShortcut.h b/LibGUI/GShortcut.h index 20713eb0f5..808fca4136 100644 --- a/LibGUI/GShortcut.h +++ b/LibGUI/GShortcut.h @@ -32,7 +32,7 @@ private: namespace AK { template<> -struct Traits { +struct Traits : public GenericTraits { static unsigned hash(const GShortcut& shortcut) { return pair_int_hash(shortcut.modifiers(), shortcut.key());