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.
This commit is contained in:
Max Kellermann 2023-08-02 22:04:00 +02:00 committed by Max Kellermann
parent 78801f303e
commit 83a6cb804b
4 changed files with 33 additions and 81 deletions

View File

@ -52,26 +52,10 @@ class RemoteTagCache final {
void OnRemoteTag(Tag &&tag) noexcept override; void OnRemoteTag(Tag &&tag) noexcept override;
void OnRemoteTagError(std::exception_ptr e) noexcept override; void OnRemoteTagError(std::exception_ptr e) noexcept override;
struct Hash : std::hash<std::string> { struct GetUri {
using std::hash<std::string>::operator();
[[gnu::pure]] [[gnu::pure]]
std::size_t operator()(const Item &item) const noexcept { std::string_view operator()(const Item &item) const noexcept {
return std::hash<std::string>::operator()(item.uri); return 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;
} }
}; };
}; };
@ -101,7 +85,9 @@ class RemoteTagCache final {
ItemList invoke_list; ItemList invoke_list;
IntrusiveHashSet<Item, 127, IntrusiveHashSet<Item, 127,
IntrusiveHashSetOperators<Item::Hash, Item::Equal>, IntrusiveHashSetOperators<std::hash<std::string_view>,
std::equal_to<std::string_view>,
Item::GetUri>,
IntrusiveHashSetBaseHookTraits<Item>, IntrusiveHashSetBaseHookTraits<Item>,
true> map; true> map;

View File

@ -11,37 +11,10 @@
#include <string.h> #include <string.h>
inline std::size_t inline std::string_view
InputCacheManager::ItemHash::operator()(std::string_view uri) const noexcept InputCacheManager::ItemGetUri::operator()(const InputCacheItem &item) const noexcept
{ {
return std::hash<std::string_view>{}(uri); return item.GetUri();
}
inline std::size_t
InputCacheManager::ItemHash::operator()(const InputCacheItem &item) const noexcept
{
return std::hash<std::string_view>{}(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();
} }
InputCacheManager::InputCacheManager(const InputCacheConfig &config) noexcept InputCacheManager::InputCacheManager(const InputCacheConfig &config) noexcept

View File

@ -24,32 +24,17 @@ class InputCacheManager {
size_t total_size = 0; size_t total_size = 0;
struct ItemHash { struct ItemGetUri {
[[gnu::pure]] [[gnu::pure]]
std::size_t operator()(std::string_view uri) const noexcept; std::string_view operator()(const InputCacheItem &item) 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;
}; };
IntrusiveList<InputCacheItem> items_by_time; IntrusiveList<InputCacheItem> items_by_time;
IntrusiveHashSet<InputCacheItem, 127, IntrusiveHashSet<InputCacheItem, 127,
IntrusiveHashSetOperators<ItemHash, ItemEqual>> items_by_uri; IntrusiveHashSetOperators<std::hash<std::string_view>,
std::equal_to<std::string_view>,
ItemGetUri>> items_by_uri;
public: public:
explicit InputCacheManager(const InputCacheConfig &config) noexcept; explicit InputCacheManager(const InputCacheConfig &config) noexcept;

View File

@ -75,7 +75,12 @@ struct IntrusiveHashSetMemberHookTraits {
} }
}; };
template<typename Hash, typename Equal> /**
* @param GetKey a function object which extracts the "key" part of an
* item
*/
template<typename Hash, typename Equal,
typename GetKey=std::identity>
struct IntrusiveHashSetOperators { struct IntrusiveHashSetOperators {
using hasher = Hash; using hasher = Hash;
using key_equal = Equal; using key_equal = Equal;
@ -85,6 +90,9 @@ struct IntrusiveHashSetOperators {
[[no_unique_address]] [[no_unique_address]]
Equal equal; Equal equal;
[[no_unique_address]]
GetKey get_key;
}; };
/** /**
@ -214,7 +222,7 @@ public:
Disposer<value_type> auto disposer) noexcept { Disposer<value_type> auto disposer) noexcept {
auto &bucket = GetBucket(key); auto &bucket = GetBucket(key);
std::size_t n = bucket.remove_and_dispose_if([this, &key](const auto &item){ 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); }, disposer);
counter -= n; counter -= n;
return n; return n;
@ -225,7 +233,7 @@ public:
Disposer<value_type> auto disposer) noexcept { Disposer<value_type> auto disposer) noexcept {
auto &bucket = GetBucket(key); auto &bucket = GetBucket(key);
std::size_t n = bucket.remove_and_dispose_if([this, &key, &pred](const auto &item){ 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); }, disposer);
counter -= n; counter -= n;
return n; return n;
@ -247,7 +255,7 @@ public:
constexpr std::pair<bucket_iterator, bool> insert_check(const auto &key) noexcept { constexpr std::pair<bucket_iterator, bool> insert_check(const auto &key) noexcept {
auto &bucket = GetBucket(key); auto &bucket = GetBucket(key);
for (auto &i : bucket) for (auto &i : bucket)
if (ops.equal(key, i)) if (ops.equal(key, ops.get_key(i)))
return {bucket.iterator_to(i), false}; return {bucket.iterator_to(i), false};
/* bucket.end() is a pointer to the bucket's list /* bucket.end() is a pointer to the bucket's list
@ -267,7 +275,7 @@ public:
/* using insert_after() so the new item gets inserted /* using insert_after() so the new item gets inserted
at the front of the bucket list */ 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 { constexpr void insert(reference item) noexcept {
++counter; ++counter;
GetBucket(item).push_front(item); GetBucket(ops.get_key(item)).push_front(item);
} }
constexpr bucket_iterator erase(bucket_iterator i) noexcept { constexpr bucket_iterator erase(bucket_iterator i) noexcept {
--counter; --counter;
return GetBucket(*i).erase(i); return GetBucket(ops.get_key(*i)).erase(i);
} }
constexpr bucket_iterator erase_and_dispose(bucket_iterator i, constexpr bucket_iterator erase_and_dispose(bucket_iterator i,
@ -295,7 +303,7 @@ public:
constexpr bucket_iterator find(const auto &key) noexcept { constexpr bucket_iterator find(const auto &key) noexcept {
auto &bucket = GetBucket(key); auto &bucket = GetBucket(key);
for (auto &i : bucket) for (auto &i : bucket)
if (ops.equal(key, i)) if (ops.equal(key, ops.get_key(i)))
return bucket.iterator_to(i); return bucket.iterator_to(i);
return end(); return end();
@ -305,7 +313,7 @@ public:
constexpr const_bucket_iterator find(const auto &key) const noexcept { constexpr const_bucket_iterator find(const auto &key) const noexcept {
auto &bucket = GetBucket(key); auto &bucket = GetBucket(key);
for (auto &i : bucket) for (auto &i : bucket)
if (ops.equal(key, i)) if (ops.equal(key, ops.get_key(i)))
return bucket.iterator_to(i); return bucket.iterator_to(i);
return end(); return end();
@ -322,7 +330,7 @@ public:
std::predicate<const_reference> auto pred) noexcept { std::predicate<const_reference> auto pred) noexcept {
auto &bucket = GetBucket(key); auto &bucket = GetBucket(key);
for (auto &i : bucket) 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 bucket.iterator_to(i);
return end(); return end();
@ -349,7 +357,7 @@ public:
auto &bucket = GetBucket(key); auto &bucket = GetBucket(key);
for (auto i = bucket.begin(), e = bucket.end(); i != e;) { for (auto i = bucket.begin(), e = bucket.end(); i != e;) {
if (!ops.equal(key, *i)) if (!ops.equal(key, ops.get_key(*i)))
++i; ++i;
else if (expired_pred(*i)) else if (expired_pred(*i))
i = erase_and_dispose(i, disposer); i = erase_and_dispose(i, disposer);