1 /* Copyright (C) 2022 Wildfire Games.
3 * Permission is hereby granted, free of charge, to any person obtaining
4 * a copy of this software and associated documentation files (the
5 * "Software"), to deal in the Software without restriction, including
6 * without limitation the rights to use, copy, modify, merge, publish,
7 * distribute, sublicense, and/or sell copies of the Software, and to
8 * permit persons to whom the Software is furnished to do so, subject to
9 * the following conditions:
11 * The above copyright notice and this permission notice shall be included
12 * in all copies or substantial portions of the Software.
14 * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND,
15 * EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF
16 * MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT.
17 * IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY
18 * CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT,
19 * TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE
20 * SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
24 * pool allocator (fixed-size blocks, freelist).
27 #ifndef INCLUDED_ALLOCATORS_POOL
28 #define INCLUDED_ALLOCATORS_POOL
30 #include "lib/bits.h" // ROUND_UP
31 #include "lib/allocators/allocator_policies.h"
33 namespace Allocators
{
36 * allocator design parameters:
37 * - O(1) allocation and deallocation;
38 * - fixed-size objects;
39 * - support for deallocating all objects;
40 * - consecutive allocations are back-to-back;
41 * - objects are aligned to the pointer size.
43 template<typename T
, class Storage
= Storage_Fixed
<> >
48 // (must round up because freelist stores pointers inside objects)
49 static const size_t objectSize
= ROUND_UP(sizeof(T
), sizeof(intptr_t));
51 Pool(size_t maxObjects
)
52 : storage(maxObjects
*objectSize
)
57 size_t RemainingObjects()
59 return (storage
.MaxCapacity() - end
) / objectSize
;
64 void* p
= mem_freelist_Detach(freelist
);
67 ASSERT(Contains((uintptr_t)p
));
71 return (T
*)StorageAppend(storage
, end
, objectSize
);
76 ASSERT(Contains((uintptr_t)p
));
77 mem_freelist_AddToFront(freelist
, p
);
82 freelist
= mem_freelist_Sentinel();
86 // @return whether the address lies within the previously allocated range.
87 bool Contains(uintptr_t address
) const
89 return (address
- storage
.Address()) < end
;
100 } // namespace Allocators
103 #include "lib/allocators/dynarray.h"
106 * allocator design parameters:
107 * - O(1) alloc and free;
108 * - either fixed- or variable-sized blocks;
109 * - doesn't preallocate the entire pool;
110 * - returns sequential addresses.
112 * opaque! do not read/write any fields!
119 * size of elements. = 0 if pool set up for variable-sized
120 * elements, otherwise rounded up to pool alignment.
125 * pointer to freelist (opaque); see freelist_*.
126 * never used (remains 0) if elements are of variable size.
132 * pass as pool_create's \<el_size\> param to indicate variable-sized allocs
133 * are required (see below).
135 const size_t POOL_VARIABLE_ALLOCS
= ~(size_t)0u;
138 * Ready Pool for use.
141 * @param max_size Max size [bytes] of the Pool; this much
142 * (rounded up to next page multiple) virtual address space is reserved.
143 * no virtual memory is actually committed until calls to pool_alloc.
144 * @param el_size Number of bytes that will be returned by each
145 * pool_alloc (whose size parameter is then ignored). Can be 0 to
146 * allow variable-sized allocations, but pool_free is then unusable.
149 Status
pool_create(Pool
* p
, size_t max_size
, size_t el_size
);
152 * free all memory (address space + physical) that constitutes the
155 * future alloc and free calls on this pool will fail.
156 * continued use of the allocated memory (*) is
157 * impossible because it is marked not-present via MMU.
158 * (* no matter if in freelist or unused or "allocated" to user)
163 Status
pool_destroy(Pool
* p
);
166 * indicate whether a pointer was allocated from the given pool.
168 * this is useful for callers that use several types of allocators.
174 bool pool_contains(const Pool
* p
, void* el
);
177 * Dole out memory from the pool.
178 * exhausts the freelist before returning new entries to improve locality.
181 * @param size bytes to allocate; ignored if pool_create's el_size was not 0.
182 * @return allocated memory, or 0 if the Pool would have to be expanded and
183 * there isn't enough memory to do so.
185 void* pool_alloc(Pool
* p
, size_t size
);
188 * Make a fixed-size element available for reuse in the given Pool.
190 * this is not allowed if the Pool was created for variable-size elements.
191 * rationale: avoids having to pass el_size here and compare with size when
192 * allocating; also prevents fragmentation and leaking memory.
195 * @param el Element returned by pool_alloc.
197 void pool_free(Pool
* p
, void* el
);
200 * "free" all user allocations that ensued from the given Pool.
202 * this resets it as if freshly pool_create-d, but doesn't release the
203 * underlying reserved virtual memory.
207 void pool_free_all(Pool
* p
);
210 * Return the number of bytes committed in the pool's backing array.
212 * This is roughly the number of bytes allocated in this pool plus the
213 * unused freelist entries.
216 * @return number of bytes
218 size_t pool_committed(Pool
* p
);
220 #endif // #ifndef INCLUDED_ALLOCATORS_POOL