tag/Pool: use class IntrusiveForwardList

This commit is contained in:
Max Kellermann 2023-09-06 15:06:21 +02:00
parent b35e8a588f
commit 76bdfabcc5
1 changed files with 40 additions and 34 deletions

View File

@ -4,6 +4,7 @@
#include "Pool.hxx" #include "Pool.hxx"
#include "Item.hxx" #include "Item.hxx"
#include "util/Cast.hxx" #include "util/Cast.hxx"
#include "util/IntrusiveForwardList.hxx"
#include "util/VarSize.hxx" #include "util/VarSize.hxx"
#include <array> #include <array>
@ -17,35 +18,36 @@
Mutex tag_pool_lock; Mutex tag_pool_lock;
struct TagPoolSlot { struct TagPoolSlot {
TagPoolSlot *next; IntrusiveForwardListHook list_hook;
uint8_t ref = 1; uint8_t ref = 1;
TagItem item; TagItem item;
static constexpr unsigned MAX_REF = std::numeric_limits<decltype(ref)>::max(); static constexpr unsigned MAX_REF = std::numeric_limits<decltype(ref)>::max();
TagPoolSlot(TagPoolSlot *_next, TagType type, TagPoolSlot(TagType type,
std::string_view value) noexcept std::string_view value) noexcept {
:next(_next) {
item.type = type; item.type = type;
*std::copy(value.begin(), value.end(), item.value) = 0; *std::copy(value.begin(), value.end(), item.value) = 0;
} }
static TagPoolSlot *Create(TagPoolSlot *_next, TagType type, static TagPoolSlot *Create(TagType type,
std::string_view value) noexcept; std::string_view value) noexcept;
}; };
TagPoolSlot * TagPoolSlot *
TagPoolSlot::Create(TagPoolSlot *_next, TagType type, TagPoolSlot::Create(TagType type,
std::string_view value) noexcept std::string_view value) noexcept
{ {
TagPoolSlot *dummy; TagPoolSlot *dummy;
return NewVarSize<TagPoolSlot>(sizeof(dummy->item.value), return NewVarSize<TagPoolSlot>(sizeof(dummy->item.value),
value.size() + 1, value.size() + 1,
_next, type, type,
value); value);
} }
static std::array<TagPoolSlot *, 16127> slots; static std::array<IntrusiveForwardList<TagPoolSlot,
IntrusiveForwardListMemberHookTraits<&TagPoolSlot::list_hook>>,
16127> slots;
static inline unsigned static inline unsigned
calc_hash(TagType type, std::string_view p) noexcept calc_hash(TagType type, std::string_view p) noexcept
@ -77,34 +79,37 @@ tag_item_to_slot(TagItem *item) noexcept
return &ContainerCast(*item, &TagPoolSlot::item); return &ContainerCast(*item, &TagPoolSlot::item);
} }
static inline TagPoolSlot ** static inline auto &
tag_value_slot_p(TagType type, std::string_view value) noexcept tag_value_list(TagType type, std::string_view value) noexcept
{ {
return &slots[calc_hash(type, value) % slots.size()]; return slots[calc_hash(type, value) % slots.size()];
} }
static inline TagPoolSlot ** static inline auto &
tag_value_slot_p(TagType type, const char *value) noexcept tag_value_list(TagType type, const char *value) noexcept
{ {
return &slots[calc_hash(type, value) % slots.size()]; 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 slot_p = tag_value_slot_p(type, value); auto &list = tag_value_list(type, value);
for (auto slot = *slot_p; slot != nullptr; slot = slot->next) {
if (slot->item.type == type && for (auto i = list.before_begin(), n = std::next(i); n != list.end(); i = n) {
value == slot->item.value && auto &slot = *n++;
slot->ref < TagPoolSlot::MAX_REF) {
assert(slot->ref > 0); if (slot.item.type == type &&
++slot->ref; value == slot.item.value &&
return &slot->item; slot.ref < TagPoolSlot::MAX_REF) {
assert(slot.ref > 0);
++slot.ref;
return &slot.item;
} }
} }
auto slot = TagPoolSlot::Create(*slot_p, type, value); auto slot = TagPoolSlot::Create(type, value);
*slot_p = slot; list.push_front(*slot);
return &slot->item; return &slot->item;
} }
@ -129,21 +134,22 @@ tag_pool_dup_item(TagItem *item) noexcept
void void
tag_pool_put_item(TagItem *item) noexcept tag_pool_put_item(TagItem *item) noexcept
{ {
TagPoolSlot **slot_p, *slot; TagPoolSlot *const slot = tag_item_to_slot(item);
slot = tag_item_to_slot(item);
assert(slot->ref > 0); assert(slot->ref > 0);
--slot->ref; --slot->ref;
if (slot->ref > 0) if (slot->ref > 0)
return; return;
for (slot_p = tag_value_slot_p(item->type, item->value); auto &list = tag_value_list(item->type, item->value);
*slot_p != slot; for (auto i = list.before_begin(), n = std::next(i);; i = n) {
slot_p = &(*slot_p)->next) { assert(n != list.end());
assert(*slot_p != nullptr); auto &s = *n++;
}
*slot_p = slot->next; if (&s == slot) {
DeleteVarSize(slot); list.erase_after(i);
DeleteVarSize(slot);
return;
}
}
} }