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 886819b85e2..a7de84b8564 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 1d30c8a1c7e..5fe83b309ed 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 ea85b805a4b..d6fed82763b 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 346d65bfe02..0e10730e6ac 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 56dc3d57ce0..d3d1bf1dfa0 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 64168e85960..c301323553c 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 d6d55b5917e..59b2f1665a7 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 f0ecb9ae2df..63080b58838 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 1ae11d6cabc..176b05d9ff8 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 f5fcd65bfc1..7d849d36ec1 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 d8b66803a1d..6a3f8ddc908 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 58f839faef2..55d48a4ff8e 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 3cf906decb6..72069bdaa5d 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 20713eb0f50..808fca41368 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());