RedCore
Loading...
Searching...
No Matches
ObjectPool.h
Go to the documentation of this file.
1#pragma once
2
3#include <concepts>
4
5#include <basis/seadAssert.h>
6#include <math/seadMathCalcCommon.h>
7
8#include <utility/Bitfield.h>
9
10namespace red {
11
12 template <typename T>
14 { t.acquire() } -> std::same_as<void>;
15 { t.release() } -> std::same_as<void>;
16 };
17
18 /**
19 * @brief A fixed-capacity, allocation-free container holding a pool of objects which get reused on acquire/release without destruction.
20 * Useful for handling recyclable objects which should only be initialized once but can be marked inactive and reused without re-creation.
21 * @tparam T The type of object to hold.
22 * @tparam N Maximum capacity of the pool.
23 * @details Insertion: O(1), Removal: O(1).
24 */
25 template <PoolObject T, u32 N>
27 static_assert(N > 0, "FixedObjectPool requires N > 0");
28
29 public:
31 : mFreeCount(N)
32 {
33 for (u32 i = 0; i < N; i++) {
34 mFreeIndices[i] = (N-1) - i;
35 }
36 }
37
39 if (mFreeCount == 0) {
40 return nullptr;
41 }
42
43 u32 i = mFreeIndices[--mFreeCount];
44 mWork[i].acquire();
45 mUsed.setBit(i);
46 return &mWork[i];
47 }
48
49 void release(T* obj) {
50 if (obj == nullptr) [[unlikely]]
51 return;
52
53 SEAD_ASSERT(contains(obj));
54 u32 i = obj - mWork;
55 SEAD_ASSERT(isUsed(i));
56
57 mWork[i].release();
58 mUsed.resetBit(i);
59 mFreeIndices[mFreeCount++] = i;
60 }
61
62 u32 size() const {
63 return N - mFreeCount;
64 }
65
66 u32 capacity() const {
67 return N;
68 }
69
70 bool isUsed(u32 i) const {
71 return mUsed.isOnBit(i);
72 }
73
74 bool contains(const T* obj) const {
75 return obj >= mWork && obj < mWork + N;
76 }
77
78 template <typename F>
79 void forEach(F fn, bool ignoreActivity = false) {
80 forEach_(this, fn, ignoreActivity);
81 }
82
83 template <typename F>
84 void forEach(F fn, bool ignoreActivity = false) const {
85 forEach_(this, fn, ignoreActivity);
86 }
87
88 private:
89 template <typename F, typename U>
90 static void forEach_(U* self, F fn, bool ignoreActivity = false) {
91 for (u32 i = 0; i < N; i++) {
92 if (ignoreActivity || self->isUsed(i)) {
93 if constexpr (std::is_void_v<std::invoke_result_t<F&, T&>>) {
94 fn(self->mWork[i]);
95 } else {
96 const bool shouldContinue = fn(self->mWork[i]);
97 if (!shouldContinue) {
98 break;
99 }
100 }
101 }
102 }
103 }
104
105 private:
106 T mWork[N];
107 Bitfield<sead::Mathi::roundUpN(N, 32)> mUsed;
108 u32 mFreeIndices[N];
109 u32 mFreeCount;
110 };
111
112} // namespace red
A fixed-capacity, allocation-free container holding a pool of objects which get reused on acquire/rel...
Definition ObjectPool.h:26
void release(T *obj)
Definition ObjectPool.h:49
void forEach(F fn, bool ignoreActivity=false)
Definition ObjectPool.h:79
T * acquire()
Definition ObjectPool.h:38
u32 capacity() const
Definition ObjectPool.h:66
FixedObjectPool()
Definition ObjectPool.h:30
u32 size() const
Definition ObjectPool.h:62
bool isUsed(u32 i) const
Definition ObjectPool.h:70
void forEach(F fn, bool ignoreActivity=false) const
Definition ObjectPool.h:84
bool contains(const T *obj) const
Definition ObjectPool.h:74
Definition ObjectPool.h:13
Definition ActorDonutBlock.h:5