summaryrefslogtreecommitdiffhomepage
diff options
context:
space:
mode:
authorStanislaw Halik <sthalik@misaki.pl>2024-07-12 23:49:45 +0200
committerStanislaw Halik <sthalik@misaki.pl>2024-07-14 13:04:41 +0200
commit7d309c5cdf61ec186046fc7d83e641853c8706ac (patch)
treed8eeadfced1077e1ea2834b6f5bb9b642eea7718
parent2a597bdcfcb6fd685be121d7f52693832c122589 (diff)
w
-rw-r--r--src/handle-page.hpp11
-rw-r--r--src/handle-page.inl34
-rw-r--r--test/handle.cpp13
3 files changed, 49 insertions, 9 deletions
diff --git a/src/handle-page.hpp b/src/handle-page.hpp
index c0397db7..057a512e 100644
--- a/src/handle-page.hpp
+++ b/src/handle-page.hpp
@@ -9,7 +9,7 @@ namespace floormat::impl_handle {
template<typename Obj, uint32_t PageSize>
struct Item
{
- union { Obj object; };
+ union { char empty = {}; Obj object; };
Handle<Obj, PageSize> handle;
uint32_t next;
};
@@ -25,14 +25,21 @@ class Page
uint32_t used_count = 0;
uint32_t first_free = (uint32_t)-1;
+ static void do_deallocate(Item<Obj, PageSize>& item);
+
public:
fm_DECLARE_DELETED_COPY_MOVE_ASSIGNMENTS(Page);
explicit Page(uint32_t start_index);
~Page() noexcept;
- [[nodiscard]] Item<Obj, PageSize>& allocate();
+ template<typename... Xs>
+ requires requires (Xs&&... xs) {
+ Obj{forward<Xs>(xs)...};
+ }
+ [[nodiscard]] Item<Obj, PageSize>& allocate(Xs&&... xs);
void deallocate(Handle<Obj, PageSize> obj);
+ void deallocate_all();
bool is_empty();
bool is_full();
};
diff --git a/src/handle-page.inl b/src/handle-page.inl
index fbd28043..8a8bd489 100644
--- a/src/handle-page.inl
+++ b/src/handle-page.inl
@@ -6,6 +6,12 @@
namespace floormat::impl_handle {
template<typename Obj, uint32_t PageSize>
+void Page<Obj, PageSize>::do_deallocate(Item<Obj, PageSize>& item)
+{
+ item.object.~Obj();
+}
+
+template<typename Obj, uint32_t PageSize>
Page<Obj, PageSize>::~Page() noexcept
{
fm_assert(used_count == 0);
@@ -28,7 +34,11 @@ Page<Obj, PageSize>::Page(uint32_t start_index):
}
template<typename Obj, uint32_t PageSize>
-Item<Obj, PageSize>& Page<Obj, PageSize>::allocate()
+template<typename... Xs>
+requires requires (Xs&&... xs) {
+ Obj{forward<Xs>(xs)...};
+}
+Item<Obj, PageSize>& Page<Obj, PageSize>::allocate(Xs&&... xs)
{
fm_assert(used_count < PageSize);
auto first_freeʹ = first_free - start_index;
@@ -38,6 +48,7 @@ Item<Obj, PageSize>& Page<Obj, PageSize>::allocate()
first_free = item.next;
used_count++;
used_map.set(first_freeʹ, true);
+ new (&item.object) Obj{ forward<Xs>(xs)... };
return item;
}
@@ -55,9 +66,28 @@ void Page<Obj, PageSize>::deallocate(Handle<Obj, PageSize> obj)
Debug{} << "counter" << FM_PRETTY_FUNCTION << "overflowed";
fm_assert(obj.counter == ctr);
item.next = first_free;
+ first_free = obj.index;
used_count--;
used_map.set(index, false);
- first_free = obj.index;
+ do_deallocate(item);
+}
+
+template<typename Obj, uint32_t PageSize>
+void Page<Obj, PageSize>::deallocate_all()
+{
+ for (auto i = 0u; i < PageSize; i++)
+ if (used_map[i])
+ do_deallocate(storage[i]);
+ auto val = start_index;
+ for (auto i = 0u; i < PageSize; i++)
+ {
+ auto& o = storage.data()[i];
+ o.handle = {val++, 0};
+ o.next = val;
+ }
+ first_free = start_index;
+ used_count = 0;
+ used_map = BitArray{ValueInit, PageSize};
}
template<typename Obj, uint32_t PageSize>
diff --git a/test/handle.cpp b/test/handle.cpp
index cbec8cac..2b52b04e 100644
--- a/test/handle.cpp
+++ b/test/handle.cpp
@@ -8,7 +8,7 @@ namespace floormat {
namespace {
constexpr uint32_t start_index = 1024, page_size = 128;
-struct Foo { int value; };
+struct Foo { int value = 0; };
using Page = impl_handle::Page<Foo, page_size>;
using Handle = impl_handle::Handle<Foo, page_size>;
@@ -32,14 +32,17 @@ namespace {
void test_page1()
{
Page page{start_index};
- auto& item0 = page.allocate();
+ auto& item0 = page.allocate(1);
auto handle0 = item0.handle;
fm_assert(item0.handle == Handle{start_index});
+ fm_assert(item0.object.value == 1);
page.deallocate(item0.handle);
- auto& item1 = page.allocate();
- auto& item2 = page.allocate();
- fm_assert(item1.handle.index == start_index || item2.handle.index == start_index);
+ auto& item1 = page.allocate(2);
+ auto& item2 = page.allocate(3);
+ fm_assert(item1.object.value == 2);
+ fm_assert(item2.object.value == 3);
+ fm_assert(item1.handle.index == item0.handle.index || item2.handle.index == item0.handle.index);
fm_assert(item1.handle.index != item2.handle.index);
fm_assert(item1.handle.counter != item2.handle.counter);
fm_assert(int{item1.handle.counter != handle0.counter} + int{item2.handle.counter != handle0.counter} == 1);