SPH
Allocators.h
Go to the documentation of this file.
1 #pragma once
2 
7 
8 #include "common/Assert.h"
9 #include <memory>
10 #include <mm_malloc.h>
11 
13 
14 struct MemoryBlock {
15  void* ptr;
16  std::size_t size;
17 
18  MemoryBlock() = default;
19  MemoryBlock(void* ptr, const std::size_t size)
20  : ptr(ptr)
21  , size(size) {}
22 
24  return { nullptr, 0 };
25  }
26 };
27 
29 class Mallocator {
30 public:
31  INLINE MemoryBlock allocate(const std::size_t size, const std::size_t align) noexcept {
32  MemoryBlock block;
33  block.ptr = _mm_malloc(size, align);
34  if (block.ptr) {
35  block.size = size;
36  } else {
37  block.size = 0;
38  }
39  return block;
40  }
41 
42  INLINE void deallocate(MemoryBlock& block) noexcept {
43  _mm_free(block.ptr);
44  block.ptr = nullptr;
45  }
46 };
47 
51 template <std::size_t TSize, Size TAlign = 16>
52 class StackAllocator : public Immovable, Local {
53 private:
54  alignas(TAlign) uint8_t data[TSize];
55 
57  uint8_t* pos = data;
58 
59 public:
60  INLINE MemoryBlock allocate(const std::size_t size, const std::size_t UNUSED(align)) noexcept {
61  SPH_ASSERT(size > 0);
62 
63  const std::size_t actSize = roundToAlignment(size);
64  if (pos - data + actSize > TSize) {
65  return MemoryBlock::EMPTY();
66  }
67 
68  void* ptr = pos;
69  pos += size;
70  return { ptr, size };
71  }
72 
73  INLINE void deallocate(MemoryBlock& block) noexcept {
74  if (!block.ptr) {
75  return;
76  }
77  if ((uint8_t*)block.ptr + block.size == pos) {
78  pos = static_cast<uint8_t*>(block.ptr);
79  }
80  block = MemoryBlock::EMPTY();
81  }
82 
83  INLINE bool owns(const MemoryBlock& block) const noexcept {
84  return block.ptr >= data && block.ptr < data + TSize;
85  }
86 
87 private:
88  INLINE constexpr static std::size_t roundToAlignment(const std::size_t value) noexcept {
89  const std::size_t remainder = value % TAlign;
90  return value + ((remainder == 0) ? 0 : (TAlign - remainder));
91  }
92 };
93 
100 template <typename TPrimary, typename TFallback>
101 class FallbackAllocator : private TPrimary, private TFallback {
102 public:
103  INLINE MemoryBlock allocate(const std::size_t size, const std::size_t align) noexcept {
104  MemoryBlock block = TPrimary::allocate(size, align);
105  if (block.ptr) {
106  return block;
107  } else {
108  return TFallback::allocate(size, align);
109  }
110  }
111 
112  INLINE void deallocate(MemoryBlock& block) noexcept {
113  if (TPrimary::owns(block)) {
114  TPrimary::deallocate(block);
115  } else {
116  TFallback::deallocate(block);
117  }
118  }
119 
120  INLINE const TPrimary& primary() const {
121  return *this;
122  }
123 
124  INLINE const TFallback& fallback() const {
125  return *this;
126  }
127 };
128 
131 template <std::size_t TLimit, typename TSmall, typename TLarge>
132 class Segregator : private TSmall, private TLarge {
133 public:
134  INLINE MemoryBlock allocate(const std::size_t size, const std::size_t align) noexcept {
135  if (size <= TLimit) {
136  return TSmall::allocate(size, align);
137  } else {
138  return TLarge::allocate(size, align);
139  }
140  }
141 
142  INLINE void deallocate(MemoryBlock& block) noexcept {
143  if (block.size <= TLimit) {
144  TSmall::deallocate(block);
145  } else {
146  TLarge::deallocate(block);
147  }
148  }
149 
150  INLINE bool owns(const MemoryBlock& block) const noexcept {
151  if (block.size <= TLimit) {
152  return TSmall::owns(block);
153  } else {
154  return TLarge::owns(block);
155  }
156  }
157 
158  INLINE const TSmall& small() const {
159  return *this;
160  }
161 
162  INLINE const TLarge& large() const {
163  return *this;
164  }
165 };
166 
168 template <typename TAllocator>
169 class TrackingAllocator : private TAllocator {
170 private:
171  std::size_t memory = 0;
172 
173 public:
174  INLINE MemoryBlock allocate(const std::size_t size, const std::size_t align) noexcept {
175  MemoryBlock block = TAllocator::allocate(size, align);
176  if (block.ptr) {
177  memory += size;
178  }
179  return block;
180  }
181 
182  INLINE void deallocate(MemoryBlock& block) noexcept {
183  if (block.ptr) {
184  memory -= block.size;
185  }
186  TAllocator::deallocate(block);
187  }
188 
189  INLINE bool owns(const MemoryBlock& block) const noexcept {
190  return TAllocator::owns(block);
191  }
192 
193  INLINE std::size_t allocated() const {
194  return memory;
195  }
196 
197  INLINE const TAllocator& underlying() const {
198  return *this;
199  }
200 };
201 
206 template <typename TResource>
208 private:
209  TResource* resource = nullptr;
210 
211 public:
212  INLINE void bind(TResource& other) {
213  resource = std::addressof(other);
214  }
215 
216  INLINE MemoryBlock allocate(const std::size_t size, const Size align) noexcept {
217  if (resource) {
218  return resource->allocate(size, align);
219  } else {
220  return MemoryBlock::EMPTY();
221  }
222  }
223 
224  INLINE void deallocate(MemoryBlock& UNUSED(block)) noexcept {}
225 
226  INLINE bool owns(const MemoryBlock& block) const noexcept {
227  if (resource) {
228  return resource->owns(block);
229  } else {
230  return false;
231  }
232  }
233 };
234 
236 template <typename TAllocator>
237 class MonotonicMemoryResource : public TAllocator {
238  MemoryBlock resource;
239  std::size_t position = 0;
240 
241 public:
242  MonotonicMemoryResource(const std::size_t size, const std::size_t align) {
243  resource = TAllocator::allocate(size, align);
244  }
245 
247  TAllocator::deallocate(resource);
248  }
249 
250  INLINE MemoryBlock allocate(const std::size_t size, const std::size_t UNUSED(align)) noexcept {
251  if (position + size <= resource.size) {
252  MemoryBlock block;
253  block.ptr = (uint8_t*)resource.ptr + position;
254  block.size = size;
255  position += size;
256  return block;
257  } else {
258  return MemoryBlock::EMPTY();
259  }
260  }
261 
262  INLINE bool owns(const MemoryBlock& block) const noexcept {
263  return block.ptr >= resource.ptr && block.ptr < (uint8_t*)resource.ptr + resource.size;
264  }
265 };
266 
Custom assertions.
#define SPH_ASSERT(x,...)
Definition: Assert.h:94
NAMESPACE_SPH_BEGIN
Definition: BarnesHut.cpp:13
uint32_t Size
Integral type used to index arrays (by default).
Definition: Globals.h:16
#define INLINE
Macros for conditional compilation based on selected compiler.
Definition: Object.h:31
#define UNUSED(x)
Definition: Object.h:37
#define NAMESPACE_SPH_END
Definition: Object.h:12
Allocator that attemps to allocate using given primary allocator, and if the allocation fails,...
Definition: Allocators.h:101
INLINE const TFallback & fallback() const
Definition: Allocators.h:124
INLINE void deallocate(MemoryBlock &block) noexcept
Definition: Allocators.h:112
INLINE const TPrimary & primary() const
Definition: Allocators.h:120
INLINE MemoryBlock allocate(const std::size_t size, const std::size_t align) noexcept
Definition: Allocators.h:103
Object intended to only be constructed on stack.
Definition: Object.h:80
Default allocator, simply wrapping _mm_malloc and _mm_free calls.
Definition: Allocators.h:29
INLINE void deallocate(MemoryBlock &block) noexcept
Definition: Allocators.h:42
INLINE MemoryBlock allocate(const std::size_t size, const std::size_t align) noexcept
Definition: Allocators.h:31
Allocator that obtains memory blocks from given memory resource.
Definition: Allocators.h:207
INLINE MemoryBlock allocate(const std::size_t size, const Size align) noexcept
Definition: Allocators.h:216
INLINE void deallocate(MemoryBlock &UNUSED(block)) noexcept
Definition: Allocators.h:224
INLINE bool owns(const MemoryBlock &block) const noexcept
Definition: Allocators.h:226
INLINE void bind(TResource &other)
Definition: Allocators.h:212
Simple memory resource with pre-allocated contiguous memory buffer.
Definition: Allocators.h:237
INLINE bool owns(const MemoryBlock &block) const noexcept
Definition: Allocators.h:262
INLINE MemoryBlock allocate(const std::size_t size, const std::size_t UNUSED(align)) noexcept
Definition: Allocators.h:250
MonotonicMemoryResource(const std::size_t size, const std::size_t align)
Definition: Allocators.h:242
Compositor that uses one allocator for small allocations and another allocator for large allocations.
Definition: Allocators.h:132
INLINE void deallocate(MemoryBlock &block) noexcept
Definition: Allocators.h:142
INLINE const TSmall & small() const
Definition: Allocators.h:158
INLINE const TLarge & large() const
Definition: Allocators.h:162
INLINE MemoryBlock allocate(const std::size_t size, const std::size_t align) noexcept
Definition: Allocators.h:134
INLINE bool owns(const MemoryBlock &block) const noexcept
Definition: Allocators.h:150
Allocator used pre-allocated fixed-size buffer on stack.
Definition: Allocators.h:52
INLINE MemoryBlock allocate(const std::size_t size, const std::size_t UNUSED(align)) noexcept
Definition: Allocators.h:60
INLINE void deallocate(MemoryBlock &block) noexcept
Definition: Allocators.h:73
INLINE bool owns(const MemoryBlock &block) const noexcept
Definition: Allocators.h:83
Helper allocator that keeps track on allocated memory.
Definition: Allocators.h:169
INLINE void deallocate(MemoryBlock &block) noexcept
Definition: Allocators.h:182
INLINE std::size_t allocated() const
Definition: Allocators.h:193
INLINE MemoryBlock allocate(const std::size_t size, const std::size_t align) noexcept
Definition: Allocators.h:174
INLINE bool owns(const MemoryBlock &block) const noexcept
Definition: Allocators.h:189
INLINE const TAllocator & underlying() const
Definition: Allocators.h:197
Object with deleted copy and move constructor and copy and move operator.
Definition: Object.h:64
void * ptr
Definition: Allocators.h:15
std::size_t size
Definition: Allocators.h:16
MemoryBlock()=default
MemoryBlock(void *ptr, const std::size_t size)
Definition: Allocators.h:19
static INLINE MemoryBlock EMPTY()
Definition: Allocators.h:23