From 8f3e0c4fe5e3f0f609eccdbf9451bc381b0abd6b Mon Sep 17 00:00:00 2001 From: Jonathan G Rennison Date: Wed, 8 Feb 2017 21:46:50 +0000 Subject: [PATCH] Add a custom arena allocator utility. --- projects/openttd_vs100.vcxproj | 2 + projects/openttd_vs100.vcxproj.filters | 6 ++ projects/openttd_vs140.vcxproj | 2 + projects/openttd_vs140.vcxproj.filters | 6 ++ projects/openttd_vs80.vcproj | 8 +++ projects/openttd_vs90.vcproj | 8 +++ source.list | 1 + src/core/dyn_arena_alloc.hpp | 97 ++++++++++++++++++++++++++ 8 files changed, 130 insertions(+) create mode 100644 src/core/dyn_arena_alloc.hpp diff --git a/projects/openttd_vs100.vcxproj b/projects/openttd_vs100.vcxproj index a7abe4d1ab..00c6f66811 100644 --- a/projects/openttd_vs100.vcxproj +++ b/projects/openttd_vs100.vcxproj @@ -667,6 +667,8 @@ + + diff --git a/projects/openttd_vs100.vcxproj.filters b/projects/openttd_vs100.vcxproj.filters index d996963c06..54cd94e730 100644 --- a/projects/openttd_vs100.vcxproj.filters +++ b/projects/openttd_vs100.vcxproj.filters @@ -1230,6 +1230,12 @@ Core Source Code + + Core Source Code + + + Core Source Code + Core Source Code diff --git a/projects/openttd_vs140.vcxproj b/projects/openttd_vs140.vcxproj index 67acda0402..19760f468b 100644 --- a/projects/openttd_vs140.vcxproj +++ b/projects/openttd_vs140.vcxproj @@ -684,6 +684,8 @@ + + diff --git a/projects/openttd_vs140.vcxproj.filters b/projects/openttd_vs140.vcxproj.filters index d996963c06..54cd94e730 100644 --- a/projects/openttd_vs140.vcxproj.filters +++ b/projects/openttd_vs140.vcxproj.filters @@ -1230,6 +1230,12 @@ Core Source Code + + Core Source Code + + + Core Source Code + Core Source Code diff --git a/projects/openttd_vs80.vcproj b/projects/openttd_vs80.vcproj index fcd9c0e3a3..afb125acf2 100644 --- a/projects/openttd_vs80.vcproj +++ b/projects/openttd_vs80.vcproj @@ -1946,6 +1946,14 @@ RelativePath=".\..\src\core\bitmath_func.hpp" > + + + + diff --git a/projects/openttd_vs90.vcproj b/projects/openttd_vs90.vcproj index cd5eea9d4e..f35a14ece5 100644 --- a/projects/openttd_vs90.vcproj +++ b/projects/openttd_vs90.vcproj @@ -1943,6 +1943,14 @@ RelativePath=".\..\src\core\bitmath_func.hpp" > + + + + diff --git a/source.list b/source.list index b2c2f4d495..c88f322cd1 100644 --- a/source.list +++ b/source.list @@ -424,6 +424,7 @@ core/backup_type.hpp core/bitmath_func.cpp core/bitmath_func.hpp core/container_func.hpp +core/dyn_arena_alloc.hpp core/endian_func.hpp core/endian_type.hpp core/enum_type.hpp diff --git a/src/core/dyn_arena_alloc.hpp b/src/core/dyn_arena_alloc.hpp new file mode 100644 index 0000000000..2bc4978d14 --- /dev/null +++ b/src/core/dyn_arena_alloc.hpp @@ -0,0 +1,97 @@ +/* $Id$ */ + +/* + * This file is part of OpenTTD. + * OpenTTD is free software; you can redistribute it and/or modify it under the terms of the GNU General Public License as published by the Free Software Foundation, version 2. + * OpenTTD is distributed in the hope that it will be useful, but WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. + * See the GNU General Public License for more details. You should have received a copy of the GNU General Public License along with OpenTTD. If not, see . + */ + +/** @file dyn_arena_alloc.hpp Dynamic chunk-size arena allocator. */ + +#include + +/** + * Custom arena allocator for uniform-size allocations of a variable size. + * The allocation and chunk sizes may only be changed when the arena is empty. + */ +class DynUniformArenaAllocator { + std::vector used_blocks; + + void *current_block = nullptr; + void *last_freed = nullptr; + size_t next_position = 0; + + size_t item_size = 0; + size_t items_per_chunk = 0; + + void NewBlock() + { + current_block = malloc(item_size * items_per_chunk); + assert(current_block != nullptr); + next_position = 0; + used_blocks.push_back(current_block); + } + + public: + DynUniformArenaAllocator() = default; + DynUniformArenaAllocator(const DynUniformArenaAllocator &other) = delete; + DynUniformArenaAllocator& operator=(const DynUniformArenaAllocator &other) = delete; + + ~DynUniformArenaAllocator() + { + EmptyArena(); + } + + void EmptyArena() + { + current_block = nullptr; + last_freed = nullptr; + next_position = 0; + for (void *block : used_blocks) { + free(block); + } + used_blocks.clear(); + } + + void ResetArena() + { + EmptyArena(); + item_size = 0; + items_per_chunk = 0; + } + + void *Allocate() { + assert(item_size != 0); + if (last_freed) { + void *ptr = last_freed; + last_freed = *reinterpret_cast(ptr); + return ptr; + } else { + if (current_block == nullptr || next_position == items_per_chunk) { + NewBlock(); + } + void *out = reinterpret_cast(current_block) + (item_size * next_position); + next_position++; + return out; + } + } + + void Free(void *ptr) { + if (!ptr) return; + assert(current_block != nullptr); + + *reinterpret_cast(ptr) = last_freed; + last_freed = ptr; + } + + void SetParameters(size_t item_size, size_t items_per_chunk) + { + if (item_size < sizeof(void *)) item_size = sizeof(void *); + if (this->item_size == item_size && this->items_per_chunk == items_per_chunk) return; + + assert(current_block == nullptr); + this->item_size = item_size; + this->items_per_chunk = items_per_chunk; + } +};