MessagePack for C++
cpp11_zone.hpp
Go to the documentation of this file.
1 //
2 // MessagePack for C++ memory pool
3 //
4 // Copyright (C) 2008-2013 FURUHASHI Sadayuki and KONDO Takatoshi
5 //
6 // Distributed under the Boost Software License, Version 1.0.
7 // (See accompanying file LICENSE_1_0.txt or copy at
8 // http://www.boost.org/LICENSE_1_0.txt)
9 //
10 #ifndef MSGPACK_CPP11_ZONE_HPP
11 #define MSGPACK_CPP11_ZONE_HPP
12 
13 #include "msgpack/versioning.hpp"
14 #include "msgpack/cpp_config.hpp"
15 #include "msgpack/zone_decl.hpp"
16 #include "msgpack/assert.hpp"
17 
18 #include <cstdint>
19 #include <cstdlib>
20 #include <memory>
21 #include <vector>
22 
23 namespace msgpack {
24 
28 
29 class zone {
30 private:
31  struct finalizer {
32  finalizer(void (*func)(void*), void* data):m_func(func), m_data(data) {}
33  void operator()() { m_func(m_data); }
34  void (*m_func)(void*);
35  void* m_data;
36  };
37  struct finalizer_array {
38  finalizer_array():m_tail(MSGPACK_NULLPTR), m_end(MSGPACK_NULLPTR), m_array(MSGPACK_NULLPTR) {}
39  void call() {
40  finalizer* fin = m_tail;
41  for(; fin != m_array; --fin) (*(fin-1))();
42  }
43  ~finalizer_array() {
44  call();
45  ::free(m_array);
46  }
47  void clear() {
48  call();
49  m_tail = m_array;
50  }
51  void push(void (*func)(void* data), void* data)
52  {
53  finalizer* fin = m_tail;
54 
55  if(fin == m_end) {
56  push_expand(func, data);
57  return;
58  }
59 
60  fin->m_func = func;
61  fin->m_data = data;
62 
63  ++m_tail;
64  }
65  void push_expand(void (*func)(void*), void* data) {
66  const size_t nused = static_cast<size_t>(m_end - m_array);
67  size_t nnext;
68  if(nused == 0) {
69  nnext = (sizeof(finalizer) < 72/2) ?
70  72 / sizeof(finalizer) : 8;
71  } else {
72  nnext = nused * 2;
73  }
74  finalizer* tmp =
75  static_cast<finalizer*>(::realloc(m_array, sizeof(finalizer) * nnext));
76  if(!tmp) {
77  throw std::bad_alloc();
78  }
79  m_array = tmp;
80  m_end = tmp + nnext;
81  m_tail = tmp + nused;
82  new (m_tail) finalizer(func, data);
83 
84  ++m_tail;
85  }
86  finalizer_array(finalizer_array&& other) noexcept
87  :m_tail(other.m_tail), m_end(other.m_end), m_array(other.m_array)
88  {
89  other.m_tail = MSGPACK_NULLPTR;
90  other.m_end = MSGPACK_NULLPTR;
91  other.m_array = MSGPACK_NULLPTR;
92  }
93  finalizer_array& operator=(finalizer_array&& other) noexcept
94  {
95  this->~finalizer_array();
96  new (this) finalizer_array(std::move(other));
97  return *this;
98  }
99 
100  finalizer* m_tail;
101  finalizer* m_end;
102  finalizer* m_array;
103 
104  private:
105  finalizer_array(const finalizer_array&);
106  finalizer_array& operator=(const finalizer_array&);
107  };
108  struct chunk {
109  chunk* m_next;
110  };
111  struct chunk_list {
112  chunk_list(size_t chunk_size)
113  {
114  chunk* c = static_cast<chunk*>(::malloc(sizeof(chunk) + chunk_size));
115  if(!c) {
116  throw std::bad_alloc();
117  }
118 
119  m_head = c;
120  m_free = chunk_size;
121  m_ptr = reinterpret_cast<char*>(c) + sizeof(chunk);
122  c->m_next = MSGPACK_NULLPTR;
123  }
124  ~chunk_list()
125  {
126  chunk* c = m_head;
127  while(c) {
128  chunk* n = c->m_next;
129  ::free(c);
130  c = n;
131  }
132  }
133  void clear(size_t chunk_size)
134  {
135  chunk* c = m_head;
136  while(true) {
137  chunk* n = c->m_next;
138  if(n) {
139  ::free(c);
140  c = n;
141  } else {
142  m_head = c;
143  break;
144  }
145  }
146  m_head->m_next = MSGPACK_NULLPTR;
147  m_free = chunk_size;
148  m_ptr = reinterpret_cast<char*>(m_head) + sizeof(chunk);
149  }
150  chunk_list(chunk_list&& other) noexcept
151  :m_free(other.m_free), m_ptr(other.m_ptr), m_head(other.m_head)
152  {
153  other.m_head = MSGPACK_NULLPTR;
154  }
155  chunk_list& operator=(chunk_list&& other) noexcept
156  {
157  this->~chunk_list();
158  new (this) chunk_list(std::move(other));
159  return *this;
160  }
161 
162  size_t m_free;
163  char* m_ptr;
164  chunk* m_head;
165  private:
166  chunk_list(const chunk_list&);
167  chunk_list& operator=(const chunk_list&);
168  };
169  size_t m_chunk_size;
170  chunk_list m_chunk_list;
171  finalizer_array m_finalizer_array;
172 
173 public:
174  zone(size_t chunk_size = MSGPACK_ZONE_CHUNK_SIZE);
175 
176 public:
177  void* allocate_align(size_t size, size_t align = MSGPACK_ZONE_ALIGN);
178  void* allocate_no_align(size_t size);
179 
180  void push_finalizer(void (*func)(void*), void* data);
181 
182  template <typename T>
183  void push_finalizer(msgpack::unique_ptr<T> obj);
184 
185  void clear();
186 
187  void swap(zone& o);
188 
189  static void* operator new(std::size_t size)
190  {
191  void* p = ::malloc(size);
192  if (!p) throw std::bad_alloc();
193  return p;
194  }
195  static void operator delete(void *p) noexcept
196  {
197  ::free(p);
198  }
199  static void* operator new(std::size_t /*size*/, void* mem) noexcept
200  {
201  return mem;
202  }
203  static void operator delete(void * /*p*/, void* /*mem*/) noexcept
204  {
205  }
206 
207  template <typename T, typename... Args>
208  T* allocate(Args... args);
209 
210  zone(zone&&) = default;
211  zone& operator=(zone&&) = default;
212  zone(const zone&) = delete;
213  zone& operator=(const zone&) = delete;
214 
215 private:
216  void undo_allocate(size_t size);
217 
218  template <typename T>
219  static void object_destruct(void* obj);
220 
221  template <typename T>
222  static void object_delete(void* obj);
223 
224  static char* get_aligned(char* ptr, size_t align);
225 
226  char* allocate_expand(size_t size);
227 };
228 
229 inline zone::zone(size_t chunk_size):m_chunk_size(chunk_size), m_chunk_list(m_chunk_size)
230 {
231 }
232 
233 inline char* zone::get_aligned(char* ptr, size_t align)
234 {
235  MSGPACK_ASSERT(align != 0 && (align & (align - 1)) == 0); // align must be 2^n (n >= 0)
236  return
237  reinterpret_cast<char*>(
238  reinterpret_cast<uintptr_t>(ptr + (align - 1)) & ~static_cast<uintptr_t>(align - 1)
239  );
240 }
241 
242 inline void* zone::allocate_align(size_t size, size_t align)
243 {
244  char* aligned = get_aligned(m_chunk_list.m_ptr, align);
245  size_t adjusted_size = size + static_cast<size_t>(aligned - m_chunk_list.m_ptr);
246  if (m_chunk_list.m_free < adjusted_size) {
247  size_t enough_size = size + align - 1;
248  char* ptr = allocate_expand(enough_size);
249  aligned = get_aligned(ptr, align);
250  adjusted_size = size + static_cast<size_t>(aligned - m_chunk_list.m_ptr);
251  }
252  m_chunk_list.m_free -= adjusted_size;
253  m_chunk_list.m_ptr += adjusted_size;
254  return aligned;
255 }
256 
257 inline void* zone::allocate_no_align(size_t size)
258 {
259  char* ptr = m_chunk_list.m_ptr;
260  if(m_chunk_list.m_free < size) {
261  ptr = allocate_expand(size);
262  }
263  m_chunk_list.m_free -= size;
264  m_chunk_list.m_ptr += size;
265 
266  return ptr;
267 }
268 
269 inline char* zone::allocate_expand(size_t size)
270 {
271  chunk_list* const cl = &m_chunk_list;
272 
273  size_t sz = m_chunk_size;
274 
275  while(sz < size) {
276  size_t tmp_sz = sz * 2;
277  if (tmp_sz <= sz) {
278  sz = size;
279  break;
280  }
281  sz = tmp_sz;
282  }
283 
284  chunk* c = static_cast<chunk*>(::malloc(sizeof(chunk) + sz));
285  if (!c) throw std::bad_alloc();
286 
287  char* ptr = reinterpret_cast<char*>(c) + sizeof(chunk);
288 
289  c->m_next = cl->m_head;
290  cl->m_head = c;
291  cl->m_free = sz;
292  cl->m_ptr = ptr;
293 
294  return ptr;
295 }
296 
297 inline void zone::push_finalizer(void (*func)(void*), void* data)
298 {
299  m_finalizer_array.push(func, data);
300 }
301 
302 template <typename T>
303 inline void zone::push_finalizer(msgpack::unique_ptr<T> obj)
304 {
305  m_finalizer_array.push(&zone::object_delete<T>, obj.release());
306 }
307 
308 inline void zone::clear()
309 {
310  m_finalizer_array.clear();
311  m_chunk_list.clear(m_chunk_size);
312 }
313 
314 inline void zone::swap(zone& o)
315 {
316  std::swap(*this, o);
317 }
318 
319 template <typename T>
320 void zone::object_delete(void* obj)
321 {
322  delete static_cast<T*>(obj);
323 }
324 
325 template <typename T>
326 void zone::object_destruct(void* obj)
327 {
328  static_cast<T*>(obj)->~T();
329 }
330 
331 inline void zone::undo_allocate(size_t size)
332 {
333  m_chunk_list.m_ptr -= size;
334  m_chunk_list.m_free += size;
335 }
336 
337 
338 template <typename T, typename... Args>
339 T* zone::allocate(Args... args)
340 {
341  void* x = allocate_align(sizeof(T), MSGPACK_ZONE_ALIGNOF(T));
342  try {
343  m_finalizer_array.push(&zone::object_destruct<T>, x);
344  } catch (...) {
345  undo_allocate(sizeof(T));
346  throw;
347  }
348  try {
349  return new (x) T(args...);
350  } catch (...) {
351  --m_finalizer_array.m_tail;
352  undo_allocate(sizeof(T));
353  throw;
354  }
355 }
356 
357 inline std::size_t aligned_size(
358  std::size_t size,
359  std::size_t align) {
360  return (size + align - 1) / align * align;
361 }
362 
364 } // MSGPACK_API_VERSION_NAMESPACE(v1)
366 
367 } // namespace msgpack
368 
369 #endif // MSGPACK_CPP11_ZONE_HPP
#define MSGPACK_ASSERT
Definition: assert.hpp:22
Definition: cpp03_zone.hpp:30
void swap(zone &o)
zone(zone &&)=default
zone & operator=(const zone &)=delete
void * allocate_align(size_t size, size_t align=MSGPACK_ZONE_ALIGN)
zone(const zone &)=delete
T * allocate(Args... args)
Definition: cpp11_zone.hpp:339
void * allocate_no_align(size_t size)
Definition: cpp03_zone.hpp:270
void push_finalizer(msgpack::unique_ptr< T > obj)
void clear()
Definition: cpp03_zone.hpp:321
void * allocate_align(size_t size, size_t align=MSGPACK_ZONE_ALIGN)
Definition: cpp03_zone.hpp:255
void push_finalizer(void(*func)(void *), void *data)
void * allocate_no_align(size_t size)
zone(size_t chunk_size=MSGPACK_ZONE_CHUNK_SIZE)
zone & operator=(zone &&)=default
std::size_t size(T const &t)
Definition: size_equal_only.hpp:24
Definition: adaptor_base.hpp:15
std::size_t aligned_size(std::size_t size, std::size_t align)
Definition: cpp03_zone.hpp:353
#define MSGPACK_NULLPTR
Definition: cpp_config_decl.hpp:85
#define MSGPACK_ZONE_ALIGNOF(type)
Definition: cpp03_zone_decl.hpp:30
#define MSGPACK_ZONE_ALIGN
Definition: cpp03_zone_decl.hpp:24
#define MSGPACK_ZONE_CHUNK_SIZE
Definition: cpp03_zone_decl.hpp:20
#define MSGPACK_API_VERSION_NAMESPACE(ns)
Definition: versioning.hpp:66