JASSv2
allocator_pool.h
Go to the documentation of this file.
1 /*
2  ALLOCATOR_POOL.H
3  ----------------
4  Copyright (c) 2016 Andrew Trotman
5  Released under the 2-clause BSD license (See:https://en.wikipedia.org/wiki/BSD_licenses)
6 */
13 #pragma once
14 
15 #include <stdio.h>
16 #include <stdint.h>
17 #include <stdlib.h>
18 #include <assert.h>
19 
20 #include <vector>
21 #include <mutex>
22 
23 #ifdef __APPLE__
24  #include <sys/mman.h>
25  #include <mach/vm_statistics.h>
26 #endif
27 
28 #include "allocator.h"
29 
30 namespace JASS
31  {
32  template <typename TYPE> class dynamic_array; // forward declare as its used in allocator_pool::_unittest()
33  /*
34  CLASS ALLOCATOR_POOL
35  --------------------
36  */
61  class allocator_pool : public allocator
62  {
63  protected:
64  static const size_t default_allocation_size = 1024 * 1024 * 128;
65 
66  protected:
67  size_t block_size;
68 
69 #ifdef USE_CRT_MALLOC
70  std::vector<void *> crt_malloc_list;
71  std::mutex mutex;
72 #endif
73 
74  protected:
75  /*
76  CLASS ALLOCATOR_POOL::CHUNK
77  ---------------------------
78  */
86  class chunk
87  {
88  public:
89  std::atomic<uint8_t *> chunk_at;
90  uint8_t *chunk_end;
92  size_t chunk_size;
93  #ifdef WIN32
94  #pragma warning(push) // Xcode thinks thinks a 0-sized entity in a class is OK, but Visual Studio kicks up a fuss (but does it anyway).
95  #pragma warning(disable : 4200)
96  #endif
97  uint8_t data[];
98  #ifdef WIN32
99  #pragma warning(pop)
100  #endif
101  };
102 
103  protected:
104  std::atomic<chunk *> current_chunk;
105 
106  private:
107  /*
108  ALLOCATOR_POOL::ALLOCATOR_POOL()
109  --------------------------------
110  */
111  allocator_pool(allocator_pool &) = delete;
112 
113  /*
114  ALLOCATOR_POOL::OPERATOR=()
115  ---------------------------
116  */
117  allocator_pool &operator=(const allocator_pool &) = delete;
118 
119  protected:
120  /*
121  ALLOCATOR_POOL::ALLOC()
122  -----------------------
123  */
129  void *alloc(size_t size) const
130  {
131 // #ifdef __APPLE__
132 // /*
133 // If we're on OSX then use large pages (2MB) if we can. If mmap() fails then fall-back to malloc().
134 // mmap() failure can be either out of memory, or not enough pages of that size exist (i.e. fragmenation).
135 // */
136 // size_t block_size = 2 * 1024 * 1024;
137 // size = ((size + block_size - 1) / block_size) * block_size;
138 // auto got = ::mmap(nullptr, size, PROT_READ | PROT_WRITE, MAP_ANON | MAP_PRIVATE, VM_FLAGS_SUPERPAGE_SIZE_2MB, 0);
139 // if (got == MAP_FAILED)
140 // return ::malloc((size_t)size);
141 // else
142 // return got;
143 // #else
144  /*
145  On other operating systems we use malloc()
146  */
147  return ::malloc((size_t)size);
148 // #endif
149  }
150 
151  /*
152  ALLOCATOR_POOL::DEALLOC()
153  -------------------------
154  */
159  void dealloc(void *buffer) const
160  {
161  ::free(buffer);
162  }
163 
164  /*
165  ALLOCATOR_POOL::ADD_CHUNK()
166  ---------------------------
167  */
177  chunk *add_chunk(size_t bytes);
178 
179  public:
180  /*
181  ALLOCATOR_POOL::ALLOCATOR_POOL()
182  --------------------------------
183  */
188  allocator_pool(size_t block_size_for_allocation = default_allocation_size);
189 
190  /*
191  ALLOCATOR_POOL::~ALLOCATOR_POOL()
192  ---------------------------------
193  */
197  virtual ~allocator_pool();
198 
199  /*
200  ALLOCATOR_POOL::OPERATOR==()
201  ----------------------------
202  */
209  virtual bool operator==(const allocator &with)
210  {
211  try
212  {
213  /*
214  Downcast the parameter to an allocator_memory and see if it matches this.
215  */
216  auto other = dynamic_cast<const allocator_pool *>(&with);
217  return (used == other->size()) && (allocated == other->capacity()) && (current_chunk.load() == other->current_chunk.load());
218  }
219  catch (...)
220  {
221  return false;
222  }
223  }
224 
225  /*
226  ALLOCATOR_POOL::OPERATOR!=()
227  ----------------------------
228  */
235  virtual bool operator!=(const allocator &with)
236  {
237  try
238  {
239  /*
240  Downcast the parameter to an allocator_memory and see if it matches this.
241  */
242  auto other = dynamic_cast<const allocator_pool *>(&with);
243  return (used != other->size()) || (allocated != other->capacity()) || (current_chunk.load() != other->current_chunk.load());
244  }
245  catch (...)
246  {
247  return false;
248  }
249  }
250 
251  /*
252  ALLOCATOR_POOL::MALLOC()
253  ------------------------
254  */
261  virtual void *malloc(size_t bytes, size_t alignment = alignment_boundary);
262 
263  /*
264  ALLOCATOR_POOL::REWIND()
265  ------------------------
266  */
272  virtual void rewind(void);
273 
274  /*
275  ALLOCATOR_POOL::UNITTEST_THREAD()
276  ---------------------------------
277  */
284  static void unittest_thread(dynamic_array<uint8_t *> &answer, allocator_pool &memory, uint8_t bytes);
285 
286  /*
287  ALLOCATOR_POOL::UNITTEST()
288  --------------------------
289  */
293  static void unittest(void);
294  };
295 }
virtual bool operator!=(const allocator &with)
Compare for inequlity two objects of this class type.
Definition: allocator_pool.h:235
uint8_t * chunk_end
Pointer to the end of the current chunk&#39;s large allocation (used to check for overflow).
Definition: allocator_pool.h:90
Details of an individual large-allocation unit.
Definition: allocator_pool.h:86
std::atomic< size_t > allocated
The number of bytes this object has allocated.
Definition: allocator.h:43
size_t block_size
The size (in bytes) of the large-allocations this object will make.
Definition: allocator_pool.h:67
chunk * add_chunk(size_t bytes)
Get memory from the C++ free store (or the Operating System) and add it to the linked list of large-a...
Definition: allocator_pool.cpp:49
static const size_t default_allocation_size
Allocations from the C++ free-store are this size.
Definition: allocator_pool.h:64
std::atomic< uint8_t * > chunk_at
Pointer to the next byte that can be allocated (within the current chunk).
Definition: allocator_pool.h:89
virtual void * malloc(size_t bytes, size_t alignment=alignment_boundary)
Allocate a small chunk of memory from the internal block and return a pointer to the caller...
Definition: allocator_pool.cpp:90
static void unittest(void)
Unit test this class.
Definition: allocator_pool.cpp:219
virtual bool operator==(const allocator &with)
Compare for equality two objects of this class type.
Definition: allocator_pool.h:209
chunk * next_chunk
Pointer to the previous large allocation (i.e. chunk).
Definition: allocator_pool.h:91
virtual void rewind(void)
Throw away (without calling delete) all objects allocated in the memory space of this object...
Definition: allocator_pool.cpp:167
virtual ~allocator_pool()
Destructor.
Definition: allocator_pool.cpp:38
std::atomic< chunk * > current_chunk
Pointer to the top of the chunk list (of large allocations).
Definition: allocator_pool.h:104
Simple block-allocator that internally allocates a large chunk then allocates smaller blocks from thi...
Definition: allocator_pool.h:61
Virtual base class for C style allocators.
Definition: allocator.h:33
static void unittest_thread(dynamic_array< uint8_t *> &answer, allocator_pool &memory, uint8_t bytes)
Unit test this class - thread manager.
Definition: allocator_pool.cpp:199
uint8_t data[]
The data in this large allocation that is available for re-distribution.
Definition: allocator_pool.h:97
std::atomic< size_t > used
The number of bytes this object has passed back to the caller.
Definition: allocator.h:42
size_t chunk_size
The size of this chunk.
Definition: allocator_pool.h:92
void dealloc(void *buffer) const
Hand back to the C++ free store (or Operating system) a chunk of memory that has previously been allo...
Definition: allocator_pool.h:159
size_t size(void) const
Return the number of bytes of memory this object has handed back to callers.
Definition: allocator.h:128
Thread-safe grow-only dynamic array using the thread-safe allocator.
Definition: allocator_pool.h:32
void * alloc(size_t size) const
Allocate more memory from the C++ free-store.
Definition: allocator_pool.h:129
Base class for different allocators.
Definition: compress_integer_elias_delta_simd.c:23
static constexpr size_t alignment_boundary
Elsewhere don&#39;t bother with alignment (align on byte boundaries)
Definition: allocator.h:39