MxEngine
StackAllocator.h
1 // Copyright(c) 2019 - 2020, #Momo
2 // All rights reserved.
3 //
4 // Redistribution and use in source and binary forms, with or without
5 // modification, are permitted provided that the following conditions are met :
6 //
7 // 1. Redistributions of source code must retain the above copyright notice, this
8 // list of conditions and the following disclaimer.
9 //
10 // 2. Redistributions in binary form must reproduce the above copyright notice,
11 // this list of conditions and the following disclaimer in the documentation
12 // and /or other materials provided with the distribution.
13 //
14 // 3. Neither the name of the copyright holder nor the names of its
15 // contributors may be used to endorse or promote products derived from
16 // this software without specific prior written permission.
17 //
18 // THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS"
19 // AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
20 // IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE
21 // DISCLAIMED.IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE LIABLE
22 // FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
23 // DAMAGES(INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR
24 // SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER
25 // CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY,
26 // OR TORT(INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
27 // OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
28 
29 #pragma once
30 
31 #include <cassert>
32 #include <cstdint>
33 #include <ostream>
34 #include <memory>
35 
36 #include "Core/Macro/Macro.h"
37 
38 namespace MxEngine
39 {
40  /*
41  StackAllocator class by #Momo
42  accepts chunk of memory and its size, do NOT allocate or free memory by itself
43  allocates aligned chunk of memory, adjusting `top` pointer.
44  last allocated object can be freed by Free() method (LIFO idiom)
45  object constructor is called automatically, object destructor is called when using StackAlloc()
46  */
48  {
49  public:
50  using DataPointer = uint8_t*;
51  private:
55  DataPointer base = nullptr;
59  DataPointer top = nullptr;
63  size_t size = 0;
64 
71  uintptr_t AlignAddress(uintptr_t address, size_t align)
72  {
73  const size_t mask = align - 1;
74  MX_ASSERT((align & mask) == 0); // check for the power of 2
75  return (address + align) & ~mask;
76  }
77 
84  uint8_t* AlignPointer(uint8_t* ptr, size_t align)
85  {
86  return reinterpret_cast<uint8_t*>(AlignAddress((uintptr_t)ptr, align));
87  }
88 
89  public:
94 
100  void Init(DataPointer data, size_t bytes)
101  {
102  this->base = data;
103  this->top = data;
104  this->size = bytes;
105  }
106 
112  StackAllocator(DataPointer data, size_t bytes)
113  : base(data), top(data), size(bytes)
114  {
115  }
116 
121  DataPointer GetBase()
122  {
123  return this->base;
124  }
125 
132  [[nodiscard]] DataPointer RawAlloc(size_t bytes, size_t align = 1)
133  {
134  MX_ASSERT(this->base != nullptr);
135 
136  DataPointer aligned = AlignPointer(this->top, align);
137  aligned[-1] = (uint8_t)(aligned - this->top);
138  this->top = aligned + bytes;
139 
140  MX_ASSERT(this->top <= this->base + this->size);
141 
142  return aligned;
143  }
144 
151  void RawFree(uint8_t* ptr)
152  {
153  MX_ASSERT(ptr >= this->base && ptr < this->base + this->size);
154  size_t shift = ptr[-1];
155  this->top = ptr - shift;
156  }
157 
163  template<typename T, typename... Args>
164  [[nodiscard]] T* Alloc(Args&&... args)
165  {
166  DataPointer ptr = RawAlloc(sizeof(T), alignof(T));
167  return new (ptr) T(std::forward<Args>(args)...);
168  }
169 
177  template<typename T, typename... Args>
178  [[nodiscard]] auto StackAlloc(Args&&... args)
179  {
180  auto deleter = [this](T* ptr) { this->Free(ptr); };
181  using SmartPtr = std::unique_ptr<T, decltype(deleter)>;
182  return SmartPtr(this->Alloc<T>(std::forward<Args>(args)...), std::move(deleter));
183  }
184 
191  template<typename T>
192  void Free(T* ptr)
193  {
194  ptr->~T();
195  RawFree(reinterpret_cast<uint8_t*>(ptr));
196  }
197 
202  void Dump(std::ostream& out)
203  {
204  for (size_t i = 0; i < this->size; i++)
205  {
206  out << std::hex << (int)this->base[i];
207  }
208  out << std::dec << "\n --- dumped " << size << " bytes --- \n";
209  }
210  };
211 }
void Init(DataPointer data, size_t bytes)
Definition: StackAllocator.h:100
void Dump(std::ostream &out)
Definition: StackAllocator.h:202
void RawFree(uint8_t *ptr)
Definition: StackAllocator.h:151
void Free(T *ptr)
Definition: StackAllocator.h:192
auto StackAlloc(Args &&... args)
Definition: StackAllocator.h:178
StackAllocator()
Definition: StackAllocator.h:93
DataPointer GetBase()
Definition: StackAllocator.h:121
StackAllocator(DataPointer data, size_t bytes)
Definition: StackAllocator.h:112
Definition: StackAllocator.h:47
DataPointer RawAlloc(size_t bytes, size_t align=1)
Definition: StackAllocator.h:132
T * Alloc(Args &&... args)
Definition: StackAllocator.h:164
Definition: Application.cpp:49