Implement StaticBlockAllocator
This commit is contained in:
parent
72cff2ed59
commit
60bd85b713
|
@ -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();
|
||||
}
|
|
@ -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
|
|
@ -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();
|
||||
}
|
|
@ -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
|
|
@ -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.
|
||||
|
|
|
@ -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;
|
||||
|
|
|
@ -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) {
|
||||
|
|
|
@ -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) {
|
||||
|
|
|
@ -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
|
Loading…
Reference in New Issue