From 2cd5f4cd3ea196a40f4456ea8dbeb142d9cb31a0 Mon Sep 17 00:00:00 2001 From: Max Kellermann Date: Wed, 2 Aug 2023 22:11:57 +0200 Subject: [PATCH] util/IntrusiveHashSet: replace template parameters Hash/Equal with a single one Preparing to add a key extraction function. Without this "Operators" template parameter, we'd have even more template parameters, and that parameter list would grow too complex. Better wrap it in one single template that contains all operators. This is an API change which all callers need to adjust to, but it will be worth it. --- src/RemoteTagCache.hxx | 9 +++--- src/input/cache/Manager.hxx | 6 ++-- src/util/IntrusiveHashSet.hxx | 48 +++++++++++++++++++----------- test/util/TestIntrusiveHashSet.cxx | 4 ++- 4 files changed, 39 insertions(+), 28 deletions(-) diff --git a/src/RemoteTagCache.hxx b/src/RemoteTagCache.hxx index 9774d3382..5295f46d9 100644 --- a/src/RemoteTagCache.hxx +++ b/src/RemoteTagCache.hxx @@ -100,11 +100,10 @@ class RemoteTagCache final { */ ItemList invoke_list; - using KeyMap = IntrusiveHashSet, - true>; - - KeyMap map; + IntrusiveHashSet, + IntrusiveHashSetBaseHookTraits, + true> map; public: RemoteTagCache(EventLoop &event_loop, diff --git a/src/input/cache/Manager.hxx b/src/input/cache/Manager.hxx index f487a1420..26cba09af 100644 --- a/src/input/cache/Manager.hxx +++ b/src/input/cache/Manager.hxx @@ -48,10 +48,8 @@ class InputCacheManager { IntrusiveList items_by_time; - using UriMap = - IntrusiveHashSet; - - UriMap items_by_uri; + IntrusiveHashSet> items_by_uri; public: explicit InputCacheManager(const InputCacheConfig &config) noexcept; diff --git a/src/util/IntrusiveHashSet.hxx b/src/util/IntrusiveHashSet.hxx index 4f4d2f5fb..ab2f433d5 100644 --- a/src/util/IntrusiveHashSet.hxx +++ b/src/util/IntrusiveHashSet.hxx @@ -75,13 +75,28 @@ struct IntrusiveHashSetMemberHookTraits { } }; +template +struct IntrusiveHashSetOperators { + using hasher = Hash; + using key_equal = Equal; + + [[no_unique_address]] + Hash hash; + + [[no_unique_address]] + Equal equal; +}; + /** * A hash table implementation which stores pointers to items which * have an embedded #IntrusiveHashSetHook. The actual table is * embedded with a compile-time fixed size in this object. + * + * @param Operators a class which contains functions `hash` and + * `equal` */ template, bool constant_time_size=false> class IntrusiveHashSet { @@ -89,10 +104,7 @@ class IntrusiveHashSet { OptionalCounter counter; [[no_unique_address]] - Hash hash; - - [[no_unique_address]] - Equal equal; + Operators ops; struct BucketHookTraits { template @@ -129,20 +141,20 @@ public: using const_pointer = const T *; using size_type = std::size_t; - using hasher = Hash; - using key_equal = Equal; + using hasher = typename Operators::hasher; + using key_equal = typename Operators::key_equal; [[nodiscard]] IntrusiveHashSet() noexcept = default; [[nodiscard]] constexpr const hasher &hash_function() const noexcept { - return hash; + return ops.hash; } [[nodiscard]] constexpr const key_equal &key_eq() const noexcept { - return equal; + return ops.equal; } [[nodiscard]] @@ -192,7 +204,7 @@ public: Disposer auto disposer) noexcept { auto &bucket = GetBucket(key); counter -= bucket.remove_and_dispose_if([this, &key](const auto &item){ - return equal(key, item); + return ops.equal(key, item); }, disposer); } @@ -201,7 +213,7 @@ public: Disposer auto disposer) noexcept { auto &bucket = GetBucket(key); counter -= bucket.remove_and_dispose_if([this, &key, &pred](const auto &item){ - return equal(key, item) && pred(item); + return ops.equal(key, item) && pred(item); }, disposer); } @@ -221,7 +233,7 @@ public: constexpr std::pair insert_check(const auto &key) noexcept { auto &bucket = GetBucket(key); for (auto &i : bucket) - if (equal(key, i)) + if (ops.equal(key, i)) return {bucket.iterator_to(i), false}; /* bucket.end() is a pointer to the bucket's list @@ -269,7 +281,7 @@ public: constexpr bucket_iterator find(const auto &key) noexcept { auto &bucket = GetBucket(key); for (auto &i : bucket) - if (equal(key, i)) + if (ops.equal(key, i)) return bucket.iterator_to(i); return end(); @@ -279,7 +291,7 @@ public: constexpr const_bucket_iterator find(const auto &key) const noexcept { auto &bucket = GetBucket(key); for (auto &i : bucket) - if (equal(key, i)) + if (ops.equal(key, i)) return bucket.iterator_to(i); return end(); @@ -296,7 +308,7 @@ public: std::predicate auto pred) noexcept { auto &bucket = GetBucket(key); for (auto &i : bucket) - if (equal(key, i) && pred(i)) + if (ops.equal(key, i) && pred(i)) return bucket.iterator_to(i); return end(); @@ -323,7 +335,7 @@ public: auto &bucket = GetBucket(key); for (auto i = bucket.begin(), e = bucket.end(); i != e;) { - if (!equal(key, *i)) + if (!ops.equal(key, *i)) ++i; else if (expired_pred(*i)) i = erase_and_dispose(i, disposer); @@ -361,7 +373,7 @@ private: [[gnu::pure]] [[nodiscard]] constexpr auto &GetBucket(K &&key) noexcept { - const auto h = hash(std::forward(key)); + const auto h = ops.hash(std::forward(key)); return table[h % table_size]; } @@ -369,7 +381,7 @@ private: [[gnu::pure]] [[nodiscard]] constexpr const auto &GetBucket(K &&key) const noexcept { - const auto h = hash(std::forward(key)); + const auto h = ops.hash(std::forward(key)); return table[h % table_size]; } }; diff --git a/test/util/TestIntrusiveHashSet.cxx b/test/util/TestIntrusiveHashSet.cxx index bb3b2fc7e..8a66d651a 100644 --- a/test/util/TestIntrusiveHashSet.cxx +++ b/test/util/TestIntrusiveHashSet.cxx @@ -38,7 +38,9 @@ TEST(IntrusiveHashSet, Basic) { IntItem a{1}, b{2}, c{3}, d{4}, e{5}, f{1}; - IntrusiveHashSet set; + IntrusiveHashSet> set; { auto [position, inserted] = set.insert_check(2);