From 83a6cb804bca0ef1954fb10552666e28f1f9f9c4 Mon Sep 17 00:00:00 2001 From: Max Kellermann Date: Wed, 2 Aug 2023 22:04:00 +0200 Subject: [PATCH] util/IntrusiveHashSet: add template argument `GetKey` This is a big simplification of all IntrusiveHashSet users: instead of having to implement multiple overloads of Hash and Equal, the IntrusiveHashSet class can first extract the effective key from an item and then pass it to the Hash/Equal functions. --- src/RemoteTagCache.hxx | 26 ++++++-------------------- src/input/cache/Manager.cxx | 33 +++------------------------------ src/input/cache/Manager.hxx | 25 +++++-------------------- src/util/IntrusiveHashSet.hxx | 30 +++++++++++++++++++----------- 4 files changed, 33 insertions(+), 81 deletions(-) diff --git a/src/RemoteTagCache.hxx b/src/RemoteTagCache.hxx index 5295f46d9..96e59c0f2 100644 --- a/src/RemoteTagCache.hxx +++ b/src/RemoteTagCache.hxx @@ -52,26 +52,10 @@ class RemoteTagCache final { void OnRemoteTag(Tag &&tag) noexcept override; void OnRemoteTagError(std::exception_ptr e) noexcept override; - struct Hash : std::hash { - using std::hash::operator(); - + struct GetUri { [[gnu::pure]] - std::size_t operator()(const Item &item) const noexcept { - return std::hash::operator()(item.uri); - } - }; - - struct Equal { - [[gnu::pure]] - bool operator()(const Item &a, - const Item &b) const noexcept { - return a.uri == b.uri; - } - - [[gnu::pure]] - bool operator()(const std::string &a, - const Item &b) const noexcept { - return a == b.uri; + std::string_view operator()(const Item &item) const noexcept { + return item.uri; } }; }; @@ -101,7 +85,9 @@ class RemoteTagCache final { ItemList invoke_list; IntrusiveHashSet, + IntrusiveHashSetOperators, + std::equal_to, + Item::GetUri>, IntrusiveHashSetBaseHookTraits, true> map; diff --git a/src/input/cache/Manager.cxx b/src/input/cache/Manager.cxx index 9ac0ae5d5..9b0356159 100644 --- a/src/input/cache/Manager.cxx +++ b/src/input/cache/Manager.cxx @@ -11,37 +11,10 @@ #include -inline std::size_t -InputCacheManager::ItemHash::operator()(std::string_view uri) const noexcept +inline std::string_view +InputCacheManager::ItemGetUri::operator()(const InputCacheItem &item) const noexcept { - return std::hash{}(uri); -} - -inline std::size_t -InputCacheManager::ItemHash::operator()(const InputCacheItem &item) const noexcept -{ - return std::hash{}(item.GetUri()); -} - -inline bool -InputCacheManager::ItemEqual::operator()(const InputCacheItem &a, - std::string_view b) const noexcept -{ - return a.GetUri() == b; -} - -inline bool -InputCacheManager::ItemEqual::operator()(std::string_view a, - const InputCacheItem &b) const noexcept -{ - return a == b.GetUri(); -} - -inline bool -InputCacheManager::ItemEqual::operator()(const InputCacheItem &a, - const InputCacheItem &b) const noexcept -{ - return a.GetUri() == b.GetUri(); + return item.GetUri(); } InputCacheManager::InputCacheManager(const InputCacheConfig &config) noexcept diff --git a/src/input/cache/Manager.hxx b/src/input/cache/Manager.hxx index 26cba09af..bf160bb12 100644 --- a/src/input/cache/Manager.hxx +++ b/src/input/cache/Manager.hxx @@ -24,32 +24,17 @@ class InputCacheManager { size_t total_size = 0; - struct ItemHash { + struct ItemGetUri { [[gnu::pure]] - std::size_t operator()(std::string_view uri) const noexcept; - - [[gnu::pure]] - std::size_t operator()(const InputCacheItem &item) const noexcept; - }; - - struct ItemEqual { - [[gnu::pure]] - bool operator()(const InputCacheItem &a, - std::string_view b) const noexcept; - - [[gnu::pure]] - bool operator()(std::string_view a, - const InputCacheItem &b) const noexcept; - - [[gnu::pure]] - bool operator()(const InputCacheItem &a, - const InputCacheItem &b) const noexcept; + std::string_view operator()(const InputCacheItem &item) const noexcept; }; IntrusiveList items_by_time; IntrusiveHashSet> items_by_uri; + IntrusiveHashSetOperators, + std::equal_to, + ItemGetUri>> items_by_uri; public: explicit InputCacheManager(const InputCacheConfig &config) noexcept; diff --git a/src/util/IntrusiveHashSet.hxx b/src/util/IntrusiveHashSet.hxx index 5b2520a86..a1a252352 100644 --- a/src/util/IntrusiveHashSet.hxx +++ b/src/util/IntrusiveHashSet.hxx @@ -75,7 +75,12 @@ struct IntrusiveHashSetMemberHookTraits { } }; -template +/** + * @param GetKey a function object which extracts the "key" part of an + * item + */ +template struct IntrusiveHashSetOperators { using hasher = Hash; using key_equal = Equal; @@ -85,6 +90,9 @@ struct IntrusiveHashSetOperators { [[no_unique_address]] Equal equal; + + [[no_unique_address]] + GetKey get_key; }; /** @@ -214,7 +222,7 @@ public: Disposer auto disposer) noexcept { auto &bucket = GetBucket(key); std::size_t n = bucket.remove_and_dispose_if([this, &key](const auto &item){ - return ops.equal(key, item); + return ops.equal(key, ops.get_key(item)); }, disposer); counter -= n; return n; @@ -225,7 +233,7 @@ public: Disposer auto disposer) noexcept { auto &bucket = GetBucket(key); std::size_t n = bucket.remove_and_dispose_if([this, &key, &pred](const auto &item){ - return ops.equal(key, item) && pred(item); + return ops.equal(key, ops.get_key(item)) && pred(item); }, disposer); counter -= n; return n; @@ -247,7 +255,7 @@ public: constexpr std::pair insert_check(const auto &key) noexcept { auto &bucket = GetBucket(key); for (auto &i : bucket) - if (ops.equal(key, i)) + if (ops.equal(key, ops.get_key(i))) return {bucket.iterator_to(i), false}; /* bucket.end() is a pointer to the bucket's list @@ -267,7 +275,7 @@ public: /* using insert_after() so the new item gets inserted at the front of the bucket list */ - GetBucket(item).insert_after(bucket, item); + GetBucket(ops.get_key(item)).insert_after(bucket, item); } /** @@ -276,12 +284,12 @@ public: */ constexpr void insert(reference item) noexcept { ++counter; - GetBucket(item).push_front(item); + GetBucket(ops.get_key(item)).push_front(item); } constexpr bucket_iterator erase(bucket_iterator i) noexcept { --counter; - return GetBucket(*i).erase(i); + return GetBucket(ops.get_key(*i)).erase(i); } constexpr bucket_iterator erase_and_dispose(bucket_iterator i, @@ -295,7 +303,7 @@ public: constexpr bucket_iterator find(const auto &key) noexcept { auto &bucket = GetBucket(key); for (auto &i : bucket) - if (ops.equal(key, i)) + if (ops.equal(key, ops.get_key(i))) return bucket.iterator_to(i); return end(); @@ -305,7 +313,7 @@ public: constexpr const_bucket_iterator find(const auto &key) const noexcept { auto &bucket = GetBucket(key); for (auto &i : bucket) - if (ops.equal(key, i)) + if (ops.equal(key, ops.get_key(i))) return bucket.iterator_to(i); return end(); @@ -322,7 +330,7 @@ public: std::predicate auto pred) noexcept { auto &bucket = GetBucket(key); for (auto &i : bucket) - if (ops.equal(key, i) && pred(i)) + if (ops.equal(key, ops.get_key(i)) && pred(i)) return bucket.iterator_to(i); return end(); @@ -349,7 +357,7 @@ public: auto &bucket = GetBucket(key); for (auto i = bucket.begin(), e = bucket.end(); i != e;) { - if (!ops.equal(key, *i)) + if (!ops.equal(key, ops.get_key(*i))) ++i; else if (expired_pred(*i)) i = erase_and_dispose(i, disposer);