From d50360f5dd97505e057c1d0dc92717a745576feb Mon Sep 17 00:00:00 2001 From: Hendiadyoin1 Date: Sun, 7 Nov 2021 14:52:20 +0100 Subject: [PATCH] AK: Allow hash-compatible key types in Hash[Table|Map] lookup This will allow us to avoid some potentially expensive type conversion during lookup, like form String to StringView, which would allocate memory otherwise. --- AK/HashMap.h | 46 ++++++++++++++++++++++++++++++++++++++++++++++ AK/HashTable.h | 33 +++++++++++++++++++++++++++++++++ 2 files changed, 79 insertions(+) diff --git a/AK/HashMap.h b/AK/HashMap.h index 5303bdf32d..78a307e3ee 100644 --- a/AK/HashMap.h +++ b/AK/HashMap.h @@ -91,6 +91,19 @@ public: return m_table.find(hash, predicate); } + // FIXME: Use some sort of Traits to get the comparison operation + template Key> + requires(IsSame>) [[nodiscard]] IteratorType find(Key const& value) + { + return m_table.find(Traits::hash(value), [&](auto& entry) { return value == entry.key; }); + } + + template Key> + requires(IsSame>) [[nodiscard]] ConstIteratorType find(Key const& value) const + { + return m_table.find(Traits::hash(value), [&](auto& entry) { return value == entry.key; }); + } + void ensure_capacity(size_t capacity) { m_table.ensure_capacity(capacity); } ErrorOr try_ensure_capacity(size_t capacity) { return m_table.try_ensure_capacity(capacity); } @@ -118,11 +131,44 @@ public: return (*it).value; } + template Key> + requires(IsSame>) Optional::PeekType> get(const Key& key) const requires(!IsPointer::PeekType>) + { + auto it = find(key); + if (it == end()) + return {}; + return (*it).value; + } + + template Key> + requires(IsSame>) Optional::ConstPeekType> get(const Key& key) const requires(IsPointer::PeekType>) + { + auto it = find(key); + if (it == end()) + return {}; + return (*it).value; + } + + template Key> + requires(IsSame>) Optional::PeekType> get(const Key& key) requires(!IsConst::PeekType>) + { + auto it = find(key); + if (it == end()) + return {}; + return (*it).value; + } + [[nodiscard]] bool contains(const K& key) const { return find(key) != end(); } + template Key> + requires(IsSame>) [[nodiscard]] bool contains(Key const& value) + { + return find(value) != end(); + } + void remove(IteratorType it) { m_table.remove(it); diff --git a/AK/HashTable.h b/AK/HashTable.h index f736d5415b..5be70d5735 100644 --- a/AK/HashTable.h +++ b/AK/HashTable.h @@ -6,6 +6,7 @@ #pragma once +#include #include #include #include @@ -209,6 +210,12 @@ public: return find(value) != end(); } + template K> + requires(IsSame>) [[nodiscard]] bool contains(K const& value) const + { + return find(value) != end(); + } + using Iterator = Conditional, HashTableIterator>; @@ -329,6 +336,32 @@ public: { return find(TraitsForT::hash(value), [&](auto& other) { return TraitsForT::equals(value, other); }); } + // FIXME: Use some Traits to get the comparison operation + // FIXME: Support for predicates, while guaranteeing that the predicate call + // does not call a non trivial constructor each time invoked + template K> + requires(IsSame>) [[nodiscard]] Iterator find(K const& value) + { + return find(Traits::hash(value), [&](auto& other) { return value == other; }); + } + + template K, typename TUnaryPredicate> + requires(IsSame>) [[nodiscard]] Iterator find(K const& value, TUnaryPredicate predicate) + { + return find(Traits::hash(value), move(predicate)); + } + + template K> + requires(IsSame>) [[nodiscard]] ConstIterator find(K const& value) const + { + return find(Traits::hash(value), [&](auto& other) { return value == other; }); + } + + template K, typename TUnaryPredicate> + requires(IsSame>) [[nodiscard]] ConstIterator find(K const& value, TUnaryPredicate predicate) const + { + return find(Traits::hash(value), move(predicate)); + } bool remove(const T& value) {