| 1 | #pragma once |
|---|---|
| 2 | |
| 3 | #include <new> |
| 4 | |
| 5 | #include "basis/seadRawPrint.h" |
| 6 | #include "basis/seadTypes.h" |
| 7 | |
| 8 | namespace sead |
| 9 | { |
| 10 | class FreeList |
| 11 | { |
| 12 | public: |
| 13 | void setWork(void* work, s32 elem_size, s32 num); |
| 14 | void reset(); |
| 15 | |
| 16 | void* alloc(); |
| 17 | void free(void* ptr); |
| 18 | |
| 19 | void* getFree() const { return mFree; } |
| 20 | void* work() const { return mWork; } |
| 21 | |
| 22 | static const size_t cPtrSize = sizeof(void*); |
| 23 | |
| 24 | private: |
| 25 | struct Node |
| 26 | { |
| 27 | Node* nextFree; |
| 28 | }; |
| 29 | |
| 30 | Node* mFree = nullptr; |
| 31 | void* mWork = nullptr; |
| 32 | }; |
| 33 | |
| 34 | inline void FreeList::setWork(void* work, s32 elem_size, s32 num) |
| 35 | { |
| 36 | SEAD_ASSERT(work); |
| 37 | SEAD_ASSERT(elem_size > 0 && elem_size % cPtrSize == 0); |
| 38 | SEAD_ASSERT(num > 0); |
| 39 | |
| 40 | const s32 idx_multiplier = elem_size / cPtrSize; |
| 41 | void** const ptrs = new (work) void*[num * idx_multiplier]; |
| 42 | |
| 43 | mFree = new (work) Node; |
| 44 | |
| 45 | // Create the linked list. |
| 46 | for (s32 i = 0; i < num - 1; ++i) |
| 47 | new (&ptrs[i * idx_multiplier]) Node{.nextFree: new (&ptrs[(i + 1) * idx_multiplier]) Node}; |
| 48 | |
| 49 | new (&ptrs[(num - 1) * idx_multiplier]) Node{.nextFree: nullptr}; |
| 50 | |
| 51 | mWork = work; |
| 52 | } |
| 53 | |
| 54 | inline void FreeList::reset() |
| 55 | { |
| 56 | mFree = nullptr; |
| 57 | mWork = nullptr; |
| 58 | } |
| 59 | |
| 60 | inline void* FreeList::alloc() |
| 61 | { |
| 62 | if (!mFree) |
| 63 | return nullptr; |
| 64 | |
| 65 | void* ptr = mFree; |
| 66 | mFree = mFree->nextFree; |
| 67 | return ptr; |
| 68 | } |
| 69 | |
| 70 | inline void FreeList::free(void* ptr) |
| 71 | { |
| 72 | mFree = new (ptr) Node{.nextFree: mFree}; |
| 73 | } |
| 74 | } // namespace sead |
| 75 |