diff --git a/projects/openttd_vs100.vcxproj b/projects/openttd_vs100.vcxproj index c5085bf43f..4af9bff731 100644 --- a/projects/openttd_vs100.vcxproj +++ b/projects/openttd_vs100.vcxproj @@ -694,6 +694,7 @@ + diff --git a/projects/openttd_vs100.vcxproj.filters b/projects/openttd_vs100.vcxproj.filters index 55af52e79b..235415b148 100644 --- a/projects/openttd_vs100.vcxproj.filters +++ b/projects/openttd_vs100.vcxproj.filters @@ -1314,6 +1314,9 @@ Core Source Code + + Core Source Code + Core Source Code diff --git a/projects/openttd_vs140.vcxproj b/projects/openttd_vs140.vcxproj index e9058f08e1..ecce7b0882 100644 --- a/projects/openttd_vs140.vcxproj +++ b/projects/openttd_vs140.vcxproj @@ -711,6 +711,7 @@ + diff --git a/projects/openttd_vs140.vcxproj.filters b/projects/openttd_vs140.vcxproj.filters index 55af52e79b..235415b148 100644 --- a/projects/openttd_vs140.vcxproj.filters +++ b/projects/openttd_vs140.vcxproj.filters @@ -1314,6 +1314,9 @@ Core Source Code + + Core Source Code + Core Source Code diff --git a/projects/openttd_vs80.vcproj b/projects/openttd_vs80.vcproj index 92b59f756e..0fce10a864 100644 --- a/projects/openttd_vs80.vcproj +++ b/projects/openttd_vs80.vcproj @@ -2054,6 +2054,10 @@ RelativePath=".\..\src\core\container_func.hpp" > + + diff --git a/projects/openttd_vs90.vcproj b/projects/openttd_vs90.vcproj index 96ee781382..348dac176c 100644 --- a/projects/openttd_vs90.vcproj +++ b/projects/openttd_vs90.vcproj @@ -2051,6 +2051,10 @@ RelativePath=".\..\src\core\container_func.hpp" > + + diff --git a/source.list b/source.list index 7fcfa28658..55507872b8 100644 --- a/source.list +++ b/source.list @@ -451,6 +451,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; + } +};