tag/Pool: use class IntrusiveHashSet intead of rolling a custom hash table
This commit is contained in:
parent
847ae7dd7c
commit
c8dc1e0665
|
@ -5,7 +5,7 @@
|
||||||
#include "Item.hxx"
|
#include "Item.hxx"
|
||||||
#include "util/Cast.hxx"
|
#include "util/Cast.hxx"
|
||||||
#include "util/djb_hash.hxx"
|
#include "util/djb_hash.hxx"
|
||||||
#include "util/IntrusiveList.hxx"
|
#include "util/IntrusiveHashSet.hxx"
|
||||||
#include "util/SpanCast.hxx"
|
#include "util/SpanCast.hxx"
|
||||||
#include "util/VarSize.hxx"
|
#include "util/VarSize.hxx"
|
||||||
|
|
||||||
|
@ -16,8 +16,23 @@
|
||||||
|
|
||||||
Mutex tag_pool_lock;
|
Mutex tag_pool_lock;
|
||||||
|
|
||||||
|
struct TagPoolKey {
|
||||||
|
std::string_view value;
|
||||||
|
TagType type;
|
||||||
|
|
||||||
|
friend constexpr auto operator<=>(const TagPoolKey &,
|
||||||
|
const TagPoolKey &) noexcept = default;
|
||||||
|
|
||||||
|
struct Hash {
|
||||||
|
[[gnu::pure]]
|
||||||
|
std::size_t operator()(const TagPoolKey &key) const noexcept {
|
||||||
|
return djb_hash(AsBytes(key.value)) ^ key.type;
|
||||||
|
}
|
||||||
|
};
|
||||||
|
};
|
||||||
|
|
||||||
struct TagPoolItem {
|
struct TagPoolItem {
|
||||||
IntrusiveListHook<IntrusiveHookMode::NORMAL> list_hook;
|
IntrusiveHashSetHook<IntrusiveHookMode::NORMAL> hash_set_hook;
|
||||||
uint8_t ref = 1;
|
uint8_t ref = 1;
|
||||||
TagItem item;
|
TagItem item;
|
||||||
|
|
||||||
|
@ -31,6 +46,24 @@ struct TagPoolItem {
|
||||||
|
|
||||||
static TagPoolItem *Create(TagType type,
|
static TagPoolItem *Create(TagType type,
|
||||||
std::string_view value) noexcept;
|
std::string_view value) noexcept;
|
||||||
|
|
||||||
|
struct GetKey {
|
||||||
|
[[gnu::pure]]
|
||||||
|
constexpr TagPoolKey operator()(const TagItem &i) const noexcept {
|
||||||
|
return { i.value, i.type };
|
||||||
|
}
|
||||||
|
|
||||||
|
[[gnu::pure]]
|
||||||
|
constexpr TagPoolKey operator()(const TagPoolItem &i) const noexcept {
|
||||||
|
return operator()(i.item);
|
||||||
|
}
|
||||||
|
};
|
||||||
|
|
||||||
|
struct CanIncrementRef {
|
||||||
|
constexpr bool operator()(const TagPoolItem &i) const noexcept {
|
||||||
|
return i.ref < MAX_REF;
|
||||||
|
}
|
||||||
|
};
|
||||||
};
|
};
|
||||||
|
|
||||||
TagPoolItem *
|
TagPoolItem *
|
||||||
|
@ -44,16 +77,12 @@ TagPoolItem::Create(TagType type,
|
||||||
value);
|
value);
|
||||||
}
|
}
|
||||||
|
|
||||||
static std::array<IntrusiveList<TagPoolItem,
|
static IntrusiveHashSet<TagPoolItem, 16127,
|
||||||
IntrusiveListMemberHookTraits<&TagPoolItem::list_hook>,
|
IntrusiveHashSetOperators<TagPoolKey::Hash,
|
||||||
IntrusiveListOptions{.zero_initialized = true}>,
|
std::equal_to<TagPoolKey>,
|
||||||
16127> slots;
|
TagPoolItem::GetKey>,
|
||||||
|
IntrusiveHashSetMemberHookTraits<&TagPoolItem::hash_set_hook>,
|
||||||
static inline std::size_t
|
IntrusiveHashSetOptions{.zero_initialized = true}> tag_pool;
|
||||||
calc_hash(TagType type, std::string_view p) noexcept
|
|
||||||
{
|
|
||||||
return djb_hash(AsBytes(p)) ^ type;
|
|
||||||
}
|
|
||||||
|
|
||||||
static constexpr TagPoolItem *
|
static constexpr TagPoolItem *
|
||||||
TagItemToPoolItem(TagItem *item) noexcept
|
TagItemToPoolItem(TagItem *item) noexcept
|
||||||
|
@ -61,30 +90,21 @@ TagItemToPoolItem(TagItem *item) noexcept
|
||||||
return &ContainerCast(*item, &TagPoolItem::item);
|
return &ContainerCast(*item, &TagPoolItem::item);
|
||||||
}
|
}
|
||||||
|
|
||||||
static inline auto &
|
|
||||||
tag_value_list(TagType type, std::string_view value) noexcept
|
|
||||||
{
|
|
||||||
return slots[calc_hash(type, value) % slots.size()];
|
|
||||||
}
|
|
||||||
|
|
||||||
TagItem *
|
TagItem *
|
||||||
tag_pool_get_item(TagType type, std::string_view value) noexcept
|
tag_pool_get_item(TagType type, std::string_view value) noexcept
|
||||||
{
|
{
|
||||||
auto &list = tag_value_list(type, value);
|
const auto [position, inserted] =
|
||||||
|
tag_pool.insert_check_if(TagPoolKey{value, type},
|
||||||
|
TagPoolItem::CanIncrementRef{});
|
||||||
|
|
||||||
for (auto &i : list) {
|
if (inserted) {
|
||||||
if (i.item.type == type &&
|
auto *pool_item = TagPoolItem::Create(type, value);
|
||||||
value == i.item.value &&
|
tag_pool.insert_commit(position, *pool_item);
|
||||||
i.ref < TagPoolItem::MAX_REF) {
|
return &pool_item->item;
|
||||||
assert(i.ref > 0);
|
} else {
|
||||||
++i.ref;
|
++position->ref;
|
||||||
return &i.item;
|
return &position->item;
|
||||||
}
|
|
||||||
}
|
}
|
||||||
|
|
||||||
auto *pool_item = TagPoolItem::Create(type, value);
|
|
||||||
list.push_front(*pool_item);
|
|
||||||
return &pool_item->item;
|
|
||||||
}
|
}
|
||||||
|
|
||||||
TagItem *
|
TagItem *
|
||||||
|
@ -115,6 +135,6 @@ tag_pool_put_item(TagItem *item) noexcept
|
||||||
if (pool_item->ref > 0)
|
if (pool_item->ref > 0)
|
||||||
return;
|
return;
|
||||||
|
|
||||||
pool_item->list_hook.unlink();
|
tag_pool.erase(tag_pool.iterator_to(*pool_item));
|
||||||
DeleteVarSize(pool_item);
|
DeleteVarSize(pool_item);
|
||||||
}
|
}
|
||||||
|
|
Loading…
Reference in New Issue