Implement StaticBlockAllocator

This commit is contained in:
Nazarii 2024-09-09 00:36:12 +03:00
parent 72cff2ed59
commit 60bd85b713
9 changed files with 509 additions and 20 deletions

126
core/os/block_allocator.cpp Normal file
View File

@ -0,0 +1,126 @@
/**************************************************************************/
/* block_allocator.cpp */
/**************************************************************************/
/* This file is part of: */
/* GODOT ENGINE */
/* https://godotengine.org */
/**************************************************************************/
/* Copyright (c) 2014-present Godot Engine contributors (see AUTHORS.md). */
/* Copyright (c) 2007-2014 Juan Linietsky, Ariel Manzur. */
/* */
/* Permission is hereby granted, free of charge, to any person obtaining */
/* a copy of this software and associated documentation files (the */
/* "Software"), to deal in the Software without restriction, including */
/* without limitation the rights to use, copy, modify, merge, publish, */
/* distribute, sublicense, and/or sell copies of the Software, and to */
/* permit persons to whom the Software is furnished to do so, subject to */
/* the following conditions: */
/* */
/* The above copyright notice and this permission notice shall be */
/* included in all copies or substantial portions of the Software. */
/* */
/* THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, */
/* EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF */
/* MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. */
/* IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY */
/* CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, */
/* TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE */
/* SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. */
/**************************************************************************/
#include "block_allocator.h"
#include "core/os/thread.h"
#include "core/string/print_string.h"
uint32_t BlockAllocator::get_total_blocks() {
return blocks_count;
}
void BlockAllocator::init(uint32_t p_structure_size, uint32_t p_start_size) {
ERR_FAIL_COND_MSG(is_initialized(), "Allocator is in use!!!");
if (p_structure_size < sizeof(FreeListElement)) {
structure_size = sizeof(FreeListElement);
} else {
structure_size = p_structure_size;
}
cur_block_size = p_start_size;
allocate_new_block();
}
void BlockAllocator::init(uint32_t p_start_size) {
CRASH_COND(structure_size == 0 || is_initialized());
init(structure_size, p_start_size);
}
void *BlockAllocator::alloc() {
void *pointer = 0;
uint8_t *block = blocks[blocks_count - 1];
size_t left = current_pointer - block;
total_elements++;
if (free_list != nullptr) {
pointer = free_list;
free_list = free_list->next;
return pointer;
}
if (unlikely(left >= cur_block_size * (size_t)structure_size)) {
allocate_new_block();
}
pointer = current_pointer;
current_pointer += structure_size;
return pointer;
}
uint32_t BlockAllocator::get_blocks_capacity(uint32_t p_blocks_size) {
return next_power_of_2(p_blocks_size);
}
void BlockAllocator::allocate_new_block() {
uint32_t blocks_capacity = get_blocks_capacity(blocks_count);
blocks_count++;
if (blocks_count > blocks_capacity) {
blocks = reinterpret_cast<uint8_t **>(memrealloc(blocks, get_blocks_capacity(blocks_count) * sizeof(uint8_t *)));
}
cur_block_size *= 2;
blocks[blocks_count - 1] = reinterpret_cast<uint8_t *>(memalloc(cur_block_size * (size_t)structure_size));
current_pointer = blocks[blocks_count - 1];
}
size_t BlockAllocator::get_total_elements() {
return total_elements;
}
uint32_t BlockAllocator::get_structure_size() {
return structure_size;
}
void BlockAllocator::free(void *p_ptr) {
FreeListElement *new_head = (FreeListElement *)p_ptr;
new_head->next = free_list;
free_list = new_head;
total_elements--;
}
void BlockAllocator::set_structure_size(uint32_t p_structure_size) {
CRASH_COND(is_initialized());
structure_size = p_structure_size;
}
void BlockAllocator::reset() {
if (blocks == nullptr) {
return;
}
for (uint32_t i = 0; i < blocks_count; i++) {
memfree(blocks[i]);
}
memfree(blocks);
blocks_count = 0;
blocks = nullptr;
free_list = nullptr;
}
BlockAllocator::~BlockAllocator() {
reset();
}

76
core/os/block_allocator.h Normal file
View File

@ -0,0 +1,76 @@
/**************************************************************************/
/* block_allocator.h */
/**************************************************************************/
/* This file is part of: */
/* GODOT ENGINE */
/* https://godotengine.org */
/**************************************************************************/
/* Copyright (c) 2014-present Godot Engine contributors (see AUTHORS.md). */
/* Copyright (c) 2007-2014 Juan Linietsky, Ariel Manzur. */
/* */
/* Permission is hereby granted, free of charge, to any person obtaining */
/* a copy of this software and associated documentation files (the */
/* "Software"), to deal in the Software without restriction, including */
/* without limitation the rights to use, copy, modify, merge, publish, */
/* distribute, sublicense, and/or sell copies of the Software, and to */
/* permit persons to whom the Software is furnished to do so, subject to */
/* the following conditions: */
/* */
/* The above copyright notice and this permission notice shall be */
/* included in all copies or substantial portions of the Software. */
/* */
/* THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, */
/* EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF */
/* MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. */
/* IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY */
/* CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, */
/* TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE */
/* SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. */
/**************************************************************************/
#ifndef BLOCK_ALLOCATOR_H
#define BLOCK_ALLOCATOR_H
#include "core/templates/local_vector.h"
/**
*
* [ 1 2 3 4 ]
* | | | |
* 1 2 3 4 5 6 7
* | * || * * || * * * * | | ... |
*
*/
class BlockAllocator {
struct FreeListElement {
FreeListElement *next = nullptr;
};
size_t cur_block_size = 1;
uint8_t *current_pointer = nullptr;
uint8_t **blocks = nullptr;
FreeListElement *free_list = nullptr;
size_t total_elements = 0;
uint32_t structure_size = 0;
uint32_t blocks_count = 0;
void allocate_new_block();
static uint32_t get_blocks_capacity(uint32_t p_blocks_size);
public:
_FORCE_INLINE_ bool is_initialized() { return blocks != nullptr; }
size_t get_total_elements();
uint32_t get_structure_size();
uint32_t get_total_blocks();
void init(uint32_t p_structure_size, uint32_t p_start_size);
void init(uint32_t p_start_size);
void set_structure_size(uint32_t p_structure_size);
void *alloc();
void free(void *p_ptr);
void reset();
~BlockAllocator();
};
#endif // BLOCK_ALLOCATOR_H

View File

@ -0,0 +1,171 @@
/**************************************************************************/
/* static_block_allocator.cpp */
/**************************************************************************/
/* This file is part of: */
/* GODOT ENGINE */
/* https://godotengine.org */
/**************************************************************************/
/* Copyright (c) 2014-present Godot Engine contributors (see AUTHORS.md). */
/* Copyright (c) 2007-2014 Juan Linietsky, Ariel Manzur. */
/* */
/* Permission is hereby granted, free of charge, to any person obtaining */
/* a copy of this software and associated documentation files (the */
/* "Software"), to deal in the Software without restriction, including */
/* without limitation the rights to use, copy, modify, merge, publish, */
/* distribute, sublicense, and/or sell copies of the Software, and to */
/* permit persons to whom the Software is furnished to do so, subject to */
/* the following conditions: */
/* */
/* The above copyright notice and this permission notice shall be */
/* included in all copies or substantial portions of the Software. */
/* */
/* THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, */
/* EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF */
/* MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. */
/* IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY */
/* CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, */
/* TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE */
/* SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. */
/**************************************************************************/
#include "static_block_allocator.h"
#include "core/os/block_allocator.h"
#include "core/os/os.h"
#include "core/os/thread.h"
#include "core/templates/oa_hash_map.h"
#include <chrono>
typedef OAHashMap<int64_t, int64_t> SizeToIdMap;
struct ThreadData {
uint8_t _offset[64];
LocalVector<BlockAllocator> allocs;
SizeToIdMap size_to_id = SizeToIdMap(32);
BinaryMutex mtx;
};
uint32_t total_num_allocators;
int physics_threads_count;
ThreadData *threads_data = nullptr;
bool is_set_num_threads_by_OS = false;
int32_t StaticBlockAllocator::_get_thread_id() {
return (Thread::get_caller_id() - Thread::MAIN_ID) % physics_threads_count;
}
int64_t StaticBlockAllocator::_create_id(int32_t p_size_pos, int32_t p_thread_id) {
union {
int64_t id;
struct {
int32_t pos;
int32_t thread_id;
};
} id_data;
id_data.pos = p_size_pos;
id_data.thread_id = p_thread_id;
return id_data.id;
}
void StaticBlockAllocator::_get_from_id(int64_t p_id, int32_t &r_size_pos, int32_t &r_thread_id) {
union {
int64_t id;
struct {
int32_t pos;
int32_t thread_id;
};
} id_data;
id_data.id = p_id;
r_size_pos = id_data.pos;
r_thread_id = id_data.thread_id;
}
void StaticBlockAllocator::_init() {
physics_threads_count = 1;
threads_data = memnew(ThreadData);
}
int64_t StaticBlockAllocator::_get_allocator_id_for_size(size_t p_size) {
if (unlikely(!is_set_num_threads_by_OS)) {
if (threads_data == nullptr) {
_init();
}
if (OS::get_singleton() != nullptr) {
physics_threads_count = OS::get_singleton()->get_processor_count();
if (physics_threads_count > 1) {
threads_data = (ThreadData *)memrealloc(threads_data, physics_threads_count * sizeof(ThreadData));
for (int i = 1; i < physics_threads_count; i++) {
memnew_placement(&threads_data[i], ThreadData);
}
}
is_set_num_threads_by_OS = true;
}
}
int32_t thread_id = _get_thread_id();
ThreadData &t = threads_data[thread_id];
t.mtx.lock();
BlockAllocator *ptr = t.allocs.ptr();
int64_t pos = -1;
t.size_to_id.lookup(p_size, pos);
if (unlikely(pos == -1)) {
((SafeNumeric<uint32_t> *)(&total_num_allocators))->increment();
pos = t.allocs.size();
t.allocs.push_back(BlockAllocator());
t.allocs[pos].init(p_size, 16);
t.size_to_id.insert(p_size, pos);
} else if (!ptr[pos].is_initialized()) {
((SafeNumeric<uint32_t> *)(&total_num_allocators))->increment();
ptr[pos].init(2);
}
int64_t id = _create_id(pos, thread_id);
t.mtx.unlock();
return id;
}
int64_t StaticBlockAllocator::get_allocator_id_for_size(size_t p_size) {
uint64_t pos = _get_allocator_id_for_size(p_size);
return pos;
}
void *StaticBlockAllocator::allocate_by_id(int64_t p_id) {
int32_t pos, thread_id;
_get_from_id(p_id, pos, thread_id);
ThreadData &t = threads_data[thread_id];
BlockAllocator &b_allocator = t.allocs.ptr()[pos];
t.mtx.lock();
if (unlikely(!b_allocator.is_initialized())) {
((SafeNumeric<uint32_t> *)(&total_num_allocators))->increment();
b_allocator.init(2);
}
void *ret = b_allocator.alloc();
t.mtx.unlock();
return ret;
}
void StaticBlockAllocator::free_by_id(int64_t p_id, void *p_ptr) {
int32_t pos, thread_id;
_get_from_id(p_id, pos, thread_id);
ThreadData &t = threads_data[thread_id];
t.mtx.lock();
DEV_ASSERT(!(pos >= (int32_t)t.allocs.size() || !t.allocs.ptr()[pos].is_initialized()));
BlockAllocator &b_allocator = t.allocs.ptr()[pos];
b_allocator.free(p_ptr);
if (likely(b_allocator.get_total_elements() != 0)) {
t.mtx.unlock();
return;
}
b_allocator.reset();
if (unlikely(((SafeNumeric<uint32_t> *)(&total_num_allocators))->decrement() == 0)) {
t.mtx.unlock();
for (int i = 0; i < physics_threads_count; i++) {
threads_data[i].~ThreadData();
}
memfree(threads_data);
threads_data = nullptr;
is_set_num_threads_by_OS = false;
return;
}
t.mtx.unlock();
}

View File

@ -0,0 +1,51 @@
/**************************************************************************/
/* static_block_allocator.h */
/**************************************************************************/
/* This file is part of: */
/* GODOT ENGINE */
/* https://godotengine.org */
/**************************************************************************/
/* Copyright (c) 2014-present Godot Engine contributors (see AUTHORS.md). */
/* Copyright (c) 2007-2014 Juan Linietsky, Ariel Manzur. */
/* */
/* Permission is hereby granted, free of charge, to any person obtaining */
/* a copy of this software and associated documentation files (the */
/* "Software"), to deal in the Software without restriction, including */
/* without limitation the rights to use, copy, modify, merge, publish, */
/* distribute, sublicense, and/or sell copies of the Software, and to */
/* permit persons to whom the Software is furnished to do so, subject to */
/* the following conditions: */
/* */
/* The above copyright notice and this permission notice shall be */
/* included in all copies or substantial portions of the Software. */
/* */
/* THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, */
/* EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF */
/* MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. */
/* IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY */
/* CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, */
/* TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE */
/* SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. */
/**************************************************************************/
#ifndef STATIC_BLOCK_ALLOCATOR_H
#define STATIC_BLOCK_ALLOCATOR_H
#include "core/typedefs.h"
#include <stddef.h>
class StaticBlockAllocator {
static int64_t _get_allocator_id_for_size(size_t p_size);
static int32_t _get_thread_id();
static int64_t _create_id(int32_t p_size_pos, int32_t p_thread_id);
static void _get_from_id(int64_t p_id, int32_t &r_size_pos, int32_t &r_thread_id);
static void _init();
public:
static int64_t get_allocator_id_for_size(size_t p_size);
static void *allocate_by_id(int64_t p_id);
static void free_by_id(int64_t p_id, void *p_ptr);
};
#endif // STATIC_BLOCK_ALLOCATOR_H

View File

@ -32,10 +32,10 @@
#define HASH_MAP_H
#include "core/math/math_funcs.h"
#include "core/os/memory.h"
#include "core/templates/hashfuncs.h"
#include "core/templates/paged_allocator.h"
#include "core/templates/pair.h"
#include "core/templates/typed_static_block_allocator.h"
/**
* A HashMap implementation that uses open addressing with Robin Hood hashing.
@ -64,7 +64,7 @@ struct HashMapElement {
template <typename TKey, typename TValue,
typename Hasher = HashMapHasherDefault,
typename Comparator = HashMapComparatorDefault<TKey>,
typename Allocator = DefaultTypedAllocator<HashMapElement<TKey, TValue>>>
typename Allocator = TypedStaticBlockAllocator<HashMapElement<TKey, TValue>>>
class HashMap {
public:
static constexpr uint32_t MIN_CAPACITY_INDEX = 2; // Use a prime.

View File

@ -34,6 +34,7 @@
#include "core/error/error_macros.h"
#include "core/os/memory.h"
#include "core/templates/sort_array.h"
#include "core/templates/typed_static_block_allocator.h"
/**
* Generic Templatized Linked List Implementation.
@ -220,6 +221,7 @@ public:
#endif
private:
struct _Data {
TypedStaticBlockAllocator<Element> a;
Element *first = nullptr;
Element *last = nullptr;
int size_cache = 0;
@ -244,7 +246,7 @@ private:
p_I->next_ptr->prev_ptr = p_I->prev_ptr;
}
memdelete_allocator<Element, A>(const_cast<Element *>(p_I));
a.delete_allocation(const_cast<Element *>(p_I));
size_cache--;
return true;
@ -293,7 +295,7 @@ public:
_data->size_cache = 0;
}
Element *n = memnew_allocator(Element, A);
Element *n = _data->a.new_allocation();
n->value = (T &)value;
n->prev_ptr = _data->last;
@ -332,7 +334,7 @@ public:
_data->size_cache = 0;
}
Element *n = memnew_allocator(Element, A);
Element *n = _data->a.new_allocation();
n->value = (T &)value;
n->prev_ptr = nullptr;
n->next_ptr = _data->first;
@ -366,7 +368,7 @@ public:
return push_back(p_value);
}
Element *n = memnew_allocator(Element, A);
Element *n = _data->a.new_allocation();
n->value = (T &)p_value;
n->prev_ptr = p_element;
n->next_ptr = p_element->next_ptr;
@ -392,7 +394,7 @@ public:
return push_back(p_value);
}
Element *n = memnew_allocator(Element, A);
Element *n = _data->a.new_allocation();
n->value = (T &)p_value;
n->prev_ptr = p_element->prev_ptr;
n->next_ptr = p_element;

View File

@ -32,8 +32,8 @@
#define RB_MAP_H
#include "core/error/error_macros.h"
#include "core/os/memory.h"
#include "core/templates/pair.h"
#include "core/templates/typed_static_block_allocator.h"
// based on the very nice implementation of rb-trees by:
// https://web.archive.org/web/20120507164830/https://web.mit.edu/~emin/www/source_code/red_black_tree/index.html
@ -195,6 +195,7 @@ private:
struct _Data {
Element *_root = nullptr;
Element *_nil = nullptr;
TypedStaticBlockAllocator<Element> element_alloc;
int size_cache = 0;
_FORCE_INLINE_ _Data() {
@ -208,14 +209,14 @@ private:
}
void _create_root() {
_root = memnew_allocator(Element(KeyValue<K, V>(K(), V())), A);
_root = element_alloc.new_allocation(Element(KeyValue<K, V>(K(), V())));
_root->parent = _root->left = _root->right = _nil;
_root->color = BLACK;
}
void _free_root() {
if (_root) {
memdelete_allocator<Element, A>(_root);
element_alloc.delete_allocation(_root);
_root = nullptr;
}
}
@ -424,7 +425,7 @@ private:
}
typedef KeyValue<K, V> KV;
Element *new_node = memnew_allocator(Element(KV(p_key, p_value)), A);
Element *new_node = _data.element_alloc.new_allocation(Element(KV(p_key, p_value)));
new_node->parent = new_parent;
new_node->right = _data._nil;
new_node->left = _data._nil;
@ -560,7 +561,7 @@ private:
p_node->_prev->_next = p_node->_next;
}
memdelete_allocator<Element, A>(p_node);
_data.element_alloc.delete_allocation(p_node);
_data.size_cache--;
ERR_FAIL_COND(_data._nil->color == RED);
}
@ -585,7 +586,7 @@ private:
_cleanup_tree(p_element->left);
_cleanup_tree(p_element->right);
memdelete_allocator<Element, A>(p_element);
_data.element_alloc.delete_allocation(p_element);
}
void _copy_from(const RBMap &p_map) {

View File

@ -31,7 +31,7 @@
#ifndef RB_SET_H
#define RB_SET_H
#include "core/os/memory.h"
#include "core/templates/typed_static_block_allocator.h"
#include "core/typedefs.h"
// based on the very nice implementation of rb-trees by:
@ -166,6 +166,7 @@ private:
struct _Data {
Element *_root = nullptr;
Element *_nil = nullptr;
TypedStaticBlockAllocator<Element> element_alloc;
int size_cache = 0;
_FORCE_INLINE_ _Data() {
@ -179,14 +180,14 @@ private:
}
void _create_root() {
_root = memnew_allocator(Element, A);
_root = element_alloc.new_allocation();
_root->parent = _root->left = _root->right = _nil;
_root->color = BLACK;
}
void _free_root() {
if (_root) {
memdelete_allocator<Element, A>(_root);
element_alloc.delete_allocation(_root);
_root = nullptr;
}
}
@ -393,7 +394,7 @@ private:
}
}
Element *new_node = memnew_allocator(Element, A);
Element *new_node = _data.element_alloc.new_allocation();
new_node->parent = new_parent;
new_node->right = _data._nil;
new_node->left = _data._nil;
@ -528,8 +529,7 @@ private:
if (p_node->_prev) {
p_node->_prev->_next = p_node->_next;
}
memdelete_allocator<Element, A>(p_node);
_data.element_alloc.delete_allocation(p_node);
_data.size_cache--;
ERR_FAIL_COND(_data._nil->color == RED);
}
@ -554,7 +554,7 @@ private:
_cleanup_tree(p_element->left);
_cleanup_tree(p_element->right);
memdelete_allocator<Element, A>(p_element);
_data.element_alloc.delete_allocation(p_element);
}
void _copy_from(const RBSet &p_set) {

View File

@ -0,0 +1,62 @@
/**************************************************************************/
/* typed_static_block_allocator.h */
/**************************************************************************/
/* This file is part of: */
/* GODOT ENGINE */
/* https://godotengine.org */
/**************************************************************************/
/* Copyright (c) 2014-present Godot Engine contributors (see AUTHORS.md). */
/* Copyright (c) 2007-2014 Juan Linietsky, Ariel Manzur. */
/* */
/* Permission is hereby granted, free of charge, to any person obtaining */
/* a copy of this software and associated documentation files (the */
/* "Software"), to deal in the Software without restriction, including */
/* without limitation the rights to use, copy, modify, merge, publish, */
/* distribute, sublicense, and/or sell copies of the Software, and to */
/* permit persons to whom the Software is furnished to do so, subject to */
/* the following conditions: */
/* */
/* The above copyright notice and this permission notice shall be */
/* included in all copies or substantial portions of the Software. */
/* */
/* THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, */
/* EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF */
/* MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. */
/* IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY */
/* CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, */
/* TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE */
/* SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. */
/**************************************************************************/
#ifndef TYPED_STATIC_BLOCK_ALLOCATOR_H
#define TYPED_STATIC_BLOCK_ALLOCATOR_H
#include "core/os/memory.h"
#include "core/os/static_block_allocator.h"
template <typename T>
class TypedStaticBlockAllocator {
int64_t allocator_id = -1;
public:
template <typename... Args>
T *new_allocation(const Args &&...p_args) {
if (unlikely(allocator_id == -1)) {
allocator_id = StaticBlockAllocator::get_allocator_id_for_size(sizeof(T));
}
T *ret = static_cast<T *>(StaticBlockAllocator::allocate_by_id(allocator_id));
memnew_placement(ret, T(p_args...));
return ret;
}
void delete_allocation(T *p_allocation) {
if (!predelete_handler(p_allocation)) {
return; // doesn't want to be deleted
}
if constexpr (!std::is_trivially_destructible_v<T>) {
p_allocation->~T();
}
StaticBlockAllocator::free_by_id(allocator_id, p_allocation);
}
};
#endif // TYPED_STATIC_BLOCK_ALLOCATOR_H