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