Kaynağa Gözat

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.
Andreas Kling 6 yıl önce
ebeveyn
işleme
d5bb98acbc

+ 1 - 1
AK/AKString.h

@@ -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()); }
 };
 };

+ 4 - 3
AK/DoublyLinkedList.h

@@ -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();

+ 1 - 5
AK/HashMap.h

@@ -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=");

+ 5 - 5
AK/HashTable.h

@@ -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();

+ 1 - 1
AK/IPv4Address.h

@@ -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()); }
 };
 };

+ 2 - 1
AK/OwnPtr.h

@@ -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(); }
 };
 };
 
 
 }
 }

+ 24 - 0
AK/SinglyLinkedList.h

@@ -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());

+ 12 - 6
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> {
-    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>
 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; }
 };
 };
 
 
 }
 }

+ 6 - 4
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;

+ 1 - 1
Applications/Taskbar/WindowIdentifier.h

@@ -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()); }
 };
 };

+ 1 - 1
Kernel/FileSystem/DiskBackedFileSystem.cpp

@@ -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); }
 };
 };

+ 1 - 1
Kernel/FileSystem/FileSystem.h

@@ -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()); }
 };
 };

+ 1 - 1
Kernel/Net/MACAddress.h

@@ -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()); }
 };
 };

+ 1 - 1
LibGUI/GShortcut.h

@@ -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());