StackAllocator.cpp
Go to the documentation of this file.
1 /*
2  * Original work Copyright (c) 2006-2009 Erin Catto http://www.box2d.org
3  * Modified work Copyright (c) 2017 Louis Langholtz https://github.com/louis-langholtz/PlayRho
4  *
5  * This software is provided 'as-is', without any express or implied
6  * warranty. In no event will the authors be held liable for any damages
7  * arising from the use of this software.
8  * Permission is granted to anyone to use this software for any purpose,
9  * including commercial applications, and to alter it and redistribute it
10  * freely, subject to the following restrictions:
11  * 1. The origin of this software must not be misrepresented; you must not
12  * claim that you wrote the original software. If you use this software
13  * in a product, an acknowledgment in the product documentation would be
14  * appreciated but is not required.
15  * 2. Altered source versions must be plainly marked as such, and must not be
16  * misrepresented as being the original software.
17  * 3. This notice may not be removed or altered from any source distribution.
18  */
19 
21 #include <PlayRho/Common/Math.hpp>
23 
24 #include <memory>
25 
26 using namespace playrho;
27 
28 namespace {
29 
30 inline std::size_t alignment_size(std::size_t size)
31 {
32  PLAYRHO_CONSTEXPR const auto one = static_cast<std::size_t>(1u);
33  return (size < one)? one: (size < sizeof(std::max_align_t))?
34  static_cast<std::size_t>(NextPowerOfTwo(size - one)): alignof(std::max_align_t);
35 };
36 
37 } // anonymous namespace
38 
40  m_data{static_cast<decltype(m_data)>(Alloc(config.preallocation_size))},
41  m_entries{static_cast<AllocationRecord*>(Alloc(config.allocation_records * sizeof(AllocationRecord)))},
42  m_size{config.preallocation_size},
43  m_max_entries{config.allocation_records}
44 {
45  // Intentionally empty.
46 }
47 
49 {
50  assert(m_index == 0);
51  assert(m_entryCount == 0);
52  playrho::Free(m_entries);
53  playrho::Free(m_data);
54 }
55 
57 {
58  assert(m_index <= m_size);
59 
60  if (m_entryCount < m_max_entries)
61  {
62  auto entry = m_entries + m_entryCount;
63 
64  const auto available = m_size - m_index;
65  if (size > (available / sizeof(std::max_align_t)) * sizeof(std::max_align_t))
66  {
67  entry->data = static_cast<decltype(entry->data)>(Alloc(size));
68  entry->usedMalloc = true;
69  }
70  else
71  {
72  auto ptr = static_cast<void*>(m_data + m_index);
73  auto space = available;
74  entry->data = std::align(alignment_size(size), size, ptr, space);
75  entry->usedMalloc = false;
76  size += (available - space);
77  m_index += size;
78  }
79 
80  entry->size = size;
81  m_allocation += size;
82  m_maxAllocation = std::max(m_maxAllocation, m_allocation);
83  ++m_entryCount;
84 
85  return entry->data;
86  }
87  return nullptr;
88 }
89 
90 void StackAllocator::Free(void* p) noexcept
91 {
92  if (p)
93  {
94  assert(m_entryCount > 0);
95  const auto entry = m_entries + m_entryCount - 1;
96  assert(p == entry->data);
97  if (entry->usedMalloc)
98  {
99  playrho::Free(p);
100  }
101  else
102  {
103  assert(m_index >= entry->size);
104  m_index -= entry->size;
105  }
106  assert(m_allocation >= entry->size);
107  m_allocation -= entry->size;
108  --m_entryCount;
109  }
110 }