MT Core (C++)
Core library for replacing C++ standard in project usage
Loading...
Searching...
No Matches
core/mtcore/alloc.hpp
Go to the documentation of this file.
1/*
2
3Copyright 2025 Matthew Tolman
4
5Licensed under the Apache License, Version 2.0 (the "License");
6you may not use this file except in compliance with the License.
7You may obtain a copy of the License at
8
9 http://www.apache.org/licenses/LICENSE-2.0
10
11Unless required by applicable law or agreed to in writing, software
12distributed under the License is distributed on an "AS IS" BASIS,
13WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
14See the License for the specific language governing permissions and
15limitations under the License.
16
17*/
18
23
28
29#pragma once
30
31#ifndef MTCORE_ALLOC_HPP
32#define MTCORE_ALLOC_HPP
33
34#include <algorithm>
35#include <unordered_map>
36
39#include "mtcore/core.hpp"
40#include "mtcore/traits.hpp"
41
45namespace mtcore {
46
52
60
61 namespace impl::alloc {
62 template<typename T>
63 struct Deiniter;
64 }
65
72 struct Allocator {
111 struct VTable {
115 void *(*alloc)(void *state, size_t bytes);
116
121 void *(*realloc)(void *state, void *ptr, size_t bytes);
122
127 void (*free)(void *state, void *ptr);
128
134 };
135
137 const VTable *vtable = nullptr;
138
140 void *state = nullptr;
141
151
159 [[nodiscard]] Result<void *, AllocationError> alloc(size_t bytes);
160
170 template<typename T>
171 [[nodiscard]] Result<Slice<T>, AllocationError> create_many(size_t count = 1) {
172 ensure(count, "CANNOT ALLOC 0 ELEMENTS!");
173 ensure(vtable, "DEREFERENCING NULL VTABLE! ENSURE ALLOCATOR HAS NOT BEEN "
174 "DEINITIALIZED!");
175 ensure(vtable->alloc, "VTABLE CORRUPTED, MISSING ALLOC");
176 auto s = Slice<T>{static_cast<T *>(vtable->alloc(state, sizeof(T) * count)), count};
177 if (s.head) {
178 for (size_t i = 0; i < count; ++i) {
179 s[i] = T{};
180 }
181 return success(s);
182 }
184 }
185
195 template<typename T, typename... Args>
196 [[nodiscard]] Result<T *, AllocationError> create(Args... args) {
197 ensure(vtable, "DEREFERENCING NULL VTABLE! ENSURE ALLOCATOR HAS NOT BEEN "
198 "DEINITIALIZED!");
199 ensure(vtable->alloc, "VTABLE CORRUPTED, MISSING ALLOC");
200 auto res = static_cast<T *>(vtable->alloc(state, sizeof(T)));
201 if (res) {
202 if constexpr (std::is_copy_assignable<T>::value) {
203 *res = T{args...};
204 }
205 else if constexpr (std::is_move_assignable<T>::value) {
206 *res = std::move(T{args...});
207 }
208 else if constexpr (std::is_trivially_constructible_v<T> && is_initable<T, Args...>) {
209 *res = T{};
210 res->init(args...);
211 }
212 else {
213 new (res) T(args...);
214 }
215 return success(res);
216 }
218 }
219
238 [[nodiscard]] Result<void *, AllocationError> realloc(void *ptr, size_t newBytes);
239
248 template<typename T>
249 void free(T *&ptr) {
250 ensure(vtable, "DEREFERENCING NULL VTABLE! ENSURE ALLOCATOR HAS NOT BEEN "
251 "DEINITIALIZED!");
252
253 // no need to free nullptr
254 if (ptr == nullptr) {
255 return;
256 }
257
258 if (!vtable->free) {
259 mtcore_warn("NO FREE ON ALLOCATOR! FREE IS A NO-OP!");
260 return;
261 }
262 vtable->free(state, ptr);
263
264 ptr = nullptr;
265 }
266
273 template<typename T>
274 void destroy(T *&ptr);
275
282 template<typename T>
283 void destroy_many(Slice<T> s);
284 };
285
295 };
296
306
313 size_t allocatedBytes = 0;
315#ifndef MTCORE_NO_STACKTRACE
316 std::unordered_map<i64, cpptrace::stacktrace> trace = {};
317#endif
318
323 };
324
341
355
369
384
400
408 Allocator *root = nullptr;
409 size_t arenaSizeHint = 0;
410 size_t arenaCountHint = 0;
411 size_t offset = 0;
412
417 };
418
438 size_t elementCountHint) noexcept;
439
440 namespace impl::alloc {
441 template<typename T>
442 struct Deiniter;
443
444 template<AllocatorDeinit T>
445 struct Deiniter<T> {
446 void operator()(Allocator &alloc, T &t) { t.deinit(alloc); }
447 };
448
449 template<DefaultDeinit T>
450 struct Deiniter<T> {
451 void operator()(Allocator &, T &t) { t.deinit(); }
452 };
453
454 template<typename T>
455 struct Deiniter {
456 void operator()(Allocator &, T &) {}
457 };
458
459 template<typename T>
460 void deinit(Allocator &alloc, T &t) {
461 (Deiniter<T>{})(alloc, t);
462 }
463 } // namespace impl::alloc
464
465 template<typename T>
466 void Allocator::destroy(T *&ptr) {
467 if (ptr == nullptr) {
468 return;
469 }
470
471 // call deinit if it's there
472 impl::alloc::deinit(*this, *ptr);
473
474 // call destructor
475 ptr->~T();
476 this->free(ptr);
477 }
478
479 template<typename T>
481 if (s.head == nullptr || s.len == 0) {
482 return;
483 }
484
485 // call destructors & deinit
486 for (size_t i = 0; i < s.len; ++i) {
487 impl::alloc::deinit(*this, s[i]);
488 s[i].~T();
489 }
490 this->free(s.head);
491 }
492} // namespace mtcore
493
494#endif
#define mtcore_warn(...)
Prints a warning message and stacktrace in debug builds Does nothing in release builds`.
ThreadLocalFixedBufferAllocator fixed_buff_thread_local(Slice< u8 > bytes) noexcept
NOT THREAD SAFE!
ThreadLocalFixedArenaAllocator fixed_arena_thread_local(Slice< u8 > bytes) noexcept
NOT THREAD SAFE!
MallocAllocator malloc_alloc() noexcept
Creates a memory allocator using the standard's malloc under the hood Does no memory tracking Ideal f...
ThreadLocalDebugAllocator debug_alloc_thread_local() noexcept
NOT THREAD SAFE!
ThreadLocalDynamicArenaAllocator dynamic_arena_thread_local(Allocator *root, size_t elementSizeHint, size_t elementCountHint) noexcept
NOT THREAD SAFE!
AllocatorError
Error indicating allocator internal state failed (e.g.
AllocationError
Error indicating failed allocation.
#define ensure(check,...)
Ensures that a check holds true, aborts the program if not true Will print error if the condition is ...
Success< void > success()
Creates a successful void Result object.
Definition result.hpp:398
Error< Underlying > error(Underlying err)
Creates an error.
Definition result.hpp:425
constexpr bool is_initable
Checks if a type has an init with the param types.
int64_t i64
Alias for 64-bit ints.
uint8_t u8
Alias for 8-bit unsigned ints.
Core library for C++ with Zig-related functionality.
V-Table for implementing your own allocator Each allocator has state, some of which is standardized (...
Result< void, AllocatorError >(* deinit)(void *state)
Function pointer to deinit method (Optional, if not provided will default to a no-op)
void(* free)(void *state, void *ptr)
Function pointer to free method (Optional, if not provided will default to no-op)
Represents a memory allocator Exact behavior depends on the underlying VTable used Should use the a_*...
void free(T *&ptr)
Marks a block of memory as "free-able" May or may not immediately deallocate memory,...
const VTable * vtable
VTable to allocation-related methods.
void * state
Internal state for the allocator.
void destroy_many(Slice< T > s)
Destroys objects allocated by this allocator by calling the destructors and freeing memory.
Result< void *, AllocationError > realloc(void *ptr, size_t newBytes)
Attempts to reallocate a block of memory to either shrink it or grow it.
Result< void, AllocatorError > deinit()
De-initializes a memory allocator.
Result< T *, AllocationError > create(Args... args)
Allocates some block of memory with an allocator with a known type Will pass arguments to the constru...
Result< void *, AllocationError > alloc(size_t bytes)
Allocates some block of memory with an allocator May fail.
Result< Slice< T >, AllocationError > create_many(size_t count=1)
Allocates some block of memory with an allocator with a known type Will call default constructor on t...
void destroy(T *&ptr)
Destroys an object allocated by this allocator by calling the destructor and freeing memory.
State variable for malloc-based allocator.
Allocator allocator() noexcept
Represents a Result that may have an error (error code) or a success value A type of "void" means the...
Definition result.hpp:170
A Slice which is just a pointer + length Accessing elements through the array operator will do bounds...
State variable for thread local debug allocator Must live longer (and at the same memory address) tha...
Allocator allocator() noexcept
std::unordered_map< i64, cpptrace::stacktrace > trace
State variable for thread local dynamic arena allocator Must live longer (and at the same memory addr...
State variable for thread local fixed arena allocator Must live longer (and at the same memory addres...
State variable for thread local fixed buffer allocator Must live longer (and at the same memory addre...