Pyrogenesis HEAD
Pyrogenesis, a RTS Engine
DynamicArena.h
Go to the documentation of this file.
1/* Copyright (C) 2021 Wildfire Games.
2 *
3 * Permission is hereby granted, free of charge, to any person obtaining
4 * a copy of this software and associated documentation files (the
5 * "Software"), to deal in the Software without restriction, including
6 * without limitation the rights to use, copy, modify, merge, publish,
7 * distribute, sublicense, and/or sell copies of the Software, and to
8 * permit persons to whom the Software is furnished to do so, subject to
9 * the following conditions:
10 *
11 * The above copyright notice and this permission notice shall be included
12 * in all copies or substantial portions of the Software.
13 *
14 * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND,
15 * EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF
16 * MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT.
17 * IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY
18 * CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT,
19 * TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE
20 * SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
21 */
22
23#ifndef INCLUDED_ALLOCATORS_DYNAMIC_ARENA
24#define INCLUDED_ALLOCATORS_DYNAMIC_ARENA
25
26#include "lib/bits.h"
27
28#include <cstdlib>
29#include <new> // bad_alloc
30#include <utility>
31#include <vector>
32
33namespace Allocators {
34
35/**
36 * 'Blind' memory allocator. Characteristics:
37 * - grows dynamically, and linearily, by BLOCK_SIZE
38 * - no reallocations, pointers remain valid
39 * - can allocate objects up to BLOCK_SIZE in size
40 * - can handle any aligment (up to BLOCK_SIZE)
41 * - Doesn't de-allocate unless cleared or destroyed.
42 */
43template<size_t BLOCK_SIZE>
45{
46protected:
47 class Block
48 {
49 public:
51 {
52 m_Data = static_cast<uint8_t*>(
53 std::malloc(BLOCK_SIZE * sizeof(uint8_t)));
54 if (!m_Data)
55 {
56 debug_warn("DynamicArena failed to allocate chunk");
57 throw std::bad_alloc();
58 }
59 }
60
62 {
63 std::free(static_cast<void*>(m_Data));
64 }
65
66 Block(const Block& other) = delete;
67 Block& operator=(const Block& other) = delete;
68
69 Block(Block&& other)
70 : m_Size(other.m_Size), m_Data(other.m_Data)
71 {
72 other.m_Size = 0;
73 other.m_Data = nullptr;
74 }
75
77 {
78 if (&other == this)
79 return *this;
80
81 Block tmp(std::move(other));
82 swap(*this, tmp);
83
84 return *this;
85 }
86
87 friend void swap(Block& lhs, Block& rhs)
88 {
89 using std::swap;
90
91 swap(lhs.m_Size, rhs.m_Size);
92 swap(lhs.m_Data, rhs.m_Data);
93 }
94
95 bool Available(size_t n, size_t alignment) const
96 {
97 return n + ROUND_UP(m_Size, alignment) <= BLOCK_SIZE;
98 }
99
100 uint8_t* Allocate(size_t n, size_t alignment)
101 {
102 m_Size = ROUND_UP(m_Size, alignment);
103 uint8_t* ptr = &m_Data[m_Size];
104 m_Size += n;
105 return ptr;
106 }
107
108 private:
109 size_t m_Size = 0;
110 uint8_t* m_Data = nullptr;
111 };
112
114public:
116 {
117 m_Blocks.reserve(16);
119 };
120
122 {
123 m_Blocks.emplace_back();
124 }
125
126 void* allocate(size_t n, const void*, size_t alignment)
127 {
128 // Safely handle zero-sized allocations (happens with GCC STL - see ticket #909).
129 if (n == 0)
130 n = 1;
131
132 if (n > BLOCK_SIZE)
133 {
134 debug_warn("DynamicArena cannot allocate more than chunk size");
135 throw std::bad_alloc();
136 }
137
138 if (!m_Blocks.back().Available(n, alignment))
140
141 return reinterpret_cast<void*>(m_Blocks.back().Allocate(n, alignment));
142 }
143
144 void deallocate(void* UNUSED(p), size_t UNUSED(n))
145 {
146 // ignored
147 }
148
149 void clear()
150 {
151 m_Blocks.clear();
153 }
154
155protected:
156 std::vector<Block> m_Blocks;
157};
158
159} // namespace Allocators
160
161#endif // INCLUDED_ALLOCATORS_DYNAMIC_ARENA
#define swap(a, i, j)
#define ROUND_UP(n, multiple)
Definition: bits.h:284
Definition: DynamicArena.h:48
uint8_t * m_Data
Definition: DynamicArena.h:110
~Block()
Definition: DynamicArena.h:61
Block(const Block &other)=delete
Block()
Definition: DynamicArena.h:50
Block & operator=(const Block &other)=delete
bool Available(size_t n, size_t alignment) const
Definition: DynamicArena.h:95
friend void swap(Block &lhs, Block &rhs)
Definition: DynamicArena.h:87
uint8_t * Allocate(size_t n, size_t alignment)
Definition: DynamicArena.h:100
size_t m_Size
Definition: DynamicArena.h:109
Block(Block &&other)
Definition: DynamicArena.h:69
Block & operator=(Block &&other)
Definition: DynamicArena.h:76
'Blind' memory allocator.
Definition: DynamicArena.h:45
DynamicArena()
Definition: DynamicArena.h:115
void * allocate(size_t n, const void *, size_t alignment)
Definition: DynamicArena.h:126
void clear()
Definition: DynamicArena.h:149
void deallocate(void *p, size_t n)
Definition: DynamicArena.h:144
std::vector< Block > m_Blocks
Definition: DynamicArena.h:156
NONCOPYABLE(DynamicArena)
void AllocateNewBlock()
Definition: DynamicArena.h:121
#define UNUSED(param)
mark a function parameter as unused and avoid the corresponding compiler warning.
Definition: code_annotation.h:40
#define debug_warn(expr)
display the error dialog with the given text.
Definition: debug.h:319
Definition: allocator_policies.h:36
unsigned char uint8_t
Definition: wposix_types.h:51
static const size_t BLOCK_SIZE
Definition: write_buffer.cpp:32