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