Grail (C++)  1.4.0
A multi-platform, modular, universal engine for embedding advanced AI in games.
MemoryPool.hh
1 // Copyright QED Software 2023.
2 
3 #ifndef GRAIL_POOL_ALLOCATOR_H
4 #define GRAIL_POOL_ALLOCATOR_H
5 
6 #include "../GrailCore/consts.h"
7 #include "../GrailLogger/LoggerManager.hh"
8 
9 #include <memory>
10 #include <string>
11 #include <type_traits>
12 #include <utility>
13 
14 namespace grail
15 {
16 namespace planner
17 {
18  template <typename T>
19  class Emplacer final
20  {
21  public:
22  Emplacer(typename std::enable_if<std::is_trivially_destructible<T>::value>::type* = 0)
23  {
24  }
25 
26  template <typename... Arguments>
27  T& operator()(void* memoryCell, Arguments&&... arguments)
28  {
29  return *(new(memoryCell) T{std::forward<Arguments>(arguments)...});
30  }
31  };
32 
33  template <>
34  class Emplacer<std::string>
35  {
36  public:
37  template <typename... Arguments>
38  std::string& operator()(void* memoryCell, Arguments&&... arguments)
39  {
40  if(StringLength(std::forward<Arguments>(arguments)...) > consts::MAX_STRING_SIZE)
41  {
42  throw std::bad_alloc{};
43  }
44  return *(new(memoryCell) std::string{std::forward<Arguments>(arguments)...});
45  }
46 
47  private:
48  std::size_t StringLength(const std::string& string) const
49  {
50  return string.size();
51  }
52  };
53 
54  template <>
55  class Emplacer<const std::string>
56  {
57  public:
58  template <typename... Arguments>
59  const std::string& operator()(void* memoryCell, Arguments&&... arguments)
60  {
61  if(StringLength(std::forward<Arguments>(arguments)...) > consts::MAX_STRING_SIZE)
62  {
63  GRAIL_LOG(consts::DEFAULT_GRAIL_LOG_GROUP, logger::Severity::ERRORS, "Planner memory pool out of memory");
64  throw std::bad_alloc{};
65  }
66  return *(new(memoryCell) const std::string{std::forward<Arguments>(arguments)...});
67  }
68 
69  private:
70  std::size_t StringLength(const std::string& string) const
71  {
72  return string.size();
73  }
74  };
75 
79  class MemoryPool final
80  {
81  public:
86  MemoryPool(const std::size_t BYTES = 5242880u)
87  : blocks{new char[BYTES]},
88  currentMemoryCell{&blocks[0]},
89  _size{0},
90  BYTES{BYTES}
91  {
92  }
93 
94  ~MemoryPool()
95  {
96  delete[] blocks;
97  }
98 
99  template <typename T, typename... ConstructorArguments>
100  T& Emplace(ConstructorArguments&&... arguments)
101  {
102  std::size_t memoryRequired = sizeof(T);
103  std::size_t alignment = alignof(T);
104  std::size_t leftoverBytes = _size % alignment;
105 
106  if(leftoverBytes > 0)
107  {
108  std::size_t padding = (alignment - leftoverBytes);
109  _size += padding;
110  if(_size < BYTES)
111  {
112  currentMemoryCell = static_cast<char*>(currentMemoryCell) + padding;
113  }
114  }
115 
116  _size += memoryRequired;
117 
118  if(_size > BYTES)
119  {
120  throw std::bad_alloc{};
121  }
122 
123  Emplacer<T> emplacer;
124  T& result = emplacer(currentMemoryCell, std::forward<ConstructorArguments>(arguments)...);
125  currentMemoryCell = static_cast<char*>(currentMemoryCell) + memoryRequired;
126  return result;
127  }
128 
129  std::size_t Size() const
130  {
131  return _size;
132  }
133 
134  void Reset(std::size_t size = 0)
135  {
136  if(size >= BYTES)
137  {
138  GRAIL_LOG(consts::DEFAULT_GRAIL_LOG_GROUP, logger::Severity::ERRORS, "Pool reset to size exceeding allocated memory");
139  size = BYTES-1;
140  }
141 
142  currentMemoryCell = &blocks[size];
143  _size = size;
144  }
145 
146  private:
147  char* const blocks;
148  void* currentMemoryCell;
149  std::size_t _size;
150  const std::size_t BYTES;
151  };
152 }
153 }
154 
155 #endif // GRAIL_POOL_ALLOCATOR_H
grail::planner::Emplacer
Definition: MemoryPool.hh:19
grail::planner::MemoryPool
The MemoryPool class - preallocated memory container for optimization issues.
Definition: MemoryPool.hh:79
grail::planner::MemoryPool::MemoryPool
MemoryPool(const std::size_t BYTES=5242880u)
MemoryPool.
Definition: MemoryPool.hh:86