From 7d026497c7af244d4999380b749edaeb302e9f0f Mon Sep 17 00:00:00 2001 From: Steven Le Rouzic Date: Tue, 17 Jun 2025 00:23:38 +0200 Subject: WIP: Add IndexPool --- asl/handle_pool/index_pool.hpp | 111 ++++++++++++++++++++++++++++++++++- asl/handle_pool/index_pool_tests.cpp | 7 +++ 2 files changed, 117 insertions(+), 1 deletion(-) diff --git a/asl/handle_pool/index_pool.hpp b/asl/handle_pool/index_pool.hpp index 1d359d5..ece61c3 100644 --- a/asl/handle_pool/index_pool.hpp +++ b/asl/handle_pool/index_pool.hpp @@ -11,6 +11,7 @@ namespace asl { // @Todo Uniquely represented for the handle? +// @Todo niche for handles template< int kIndexBits_, @@ -27,6 +28,7 @@ struct index_pool_config using PrimitiveUserType = smallest_unsigned_integer_type_for_width * 8>; static_assert(trivially_copy_constructible); + static_assert(trivially_destructible); static_assert(size_of == size_of, "UserType should be of size 1, 2 or 4"); static constexpr int kUserBits = []() static -> int { @@ -60,9 +62,10 @@ template< > class index_pool_handle { - // using config = index_pool_config<5, 5>; +public: using config = index_pool_config; +private: config::HandleType m_handle{}; public: @@ -116,5 +119,111 @@ public: constexpr bool operator==(this index_pool_handle self, index_pool_handle other) = default; }; +template< + int kIndexBits_, + int kGenBits_, + typename UserType_ = empty, + int kUserBits_ = 0, + typename Payload = empty, + allocator Allocator = DefaultAllocator +> +class IndexPool +{ +public: + using handle = index_pool_handle; + +private: + using config = handle::config; + + static constexpr bool kHasPayload = !same_as; + + // @Todo Remove need for default constructible & trivially destructible for payload + // Use union in slot to store the variants + + // @Todo Use dummy user type with inactive handle type -> no need to set user data when allocating handle + + static_assert(default_constructible); + static_assert(copy_constructible); + static_assert(trivially_destructible); + + struct Slot + { + bool is_end_of_list : 1; + bool is_active : 1; + + handle handle; + + ASL_NO_UNIQUE_ADDRESS Payload payload; + }; + + chunked_buffer m_slots; + + // We only use the index, this is essentially the head of the linked + // list to the first available slot. + // Then the index of each slot points to the next available one. + handle m_first_available; + + static constexpr handle make_handle(uint64_t index, uint64_t gen, [[maybe_unused]] config::UserType user_data) + { + if constexpr (config::kHasUser) + { + return handle(index, gen, user_data); + } + else + { + return handle(index, gen); + } + }; + + void allocate_new_slot(config::UserType user) + { + // @Todo Check that we don't go past capacity. + + const auto new_index = static_cast(m_slots.size()); + const handle new_handle = make_handle(new_index, 0, user); + + m_slots.push(Slot{ + .is_end_of_list = true, + .is_active = false, + .handle = new_handle, + .payload = Payload{} + }); + + m_first_available = new_handle; + } + + handle acquire_handle(const Payload& payload, config::UserType user) + { + if (!m_first_available.is_valid()) + { + allocate_new_slot(user); + } + + ASL_ASSERT(m_first_available.is_valid()); + + auto index = static_cast(m_first_available.index()); + + Slot& slot = m_slots[index]; + ASL_ASSERT(!slot.is_active); + + m_first_available = slot.is_end_of_line ? handle{} : slot.handle; + + slot.is_active = true; + slot.payload = payload; + + return make_handle(index, slot.handle.gen(), user); + } + +public: + IndexPool() requires default_constructible = default; + + explicit IndexPool(Allocator allocator) : m_slots{std::move(allocator)} {} + + handle acquire(const Payload& payload) + { + return acquire_handle(payload); + } +}; + } // namespace asl diff --git a/asl/handle_pool/index_pool_tests.cpp b/asl/handle_pool/index_pool_tests.cpp index 3156320..d690878 100644 --- a/asl/handle_pool/index_pool_tests.cpp +++ b/asl/handle_pool/index_pool_tests.cpp @@ -108,3 +108,10 @@ ASL_TEST(compare) // NOLINT ASL_TEST_EXPECT(idx4 != idx5); } + +ASL_TEST(pool) +{ + using Pool = asl::IndexPool<8, 8>; + Pool pool; + auto a = pool.acquire({}); +} -- cgit