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  static void* operator new(std::size_t size)
188  {
189  void* p = ::malloc(size);
190  if (!p) throw std::bad_alloc();
191  return p;
192  }
193  static void operator delete(void *p) noexcept
194  {
195  ::free(p);
196  }
197  static void* operator new(std::size_t /*size*/, void* mem) noexcept
198  {
199  return mem;
200  }
201  static void operator delete(void * /*p*/, void* /*mem*/) noexcept
202  {
203  }
204 
205  template <typename T, typename... Args>
206  T* allocate(Args... args);
207 
208  zone(zone&&) = default;
209  zone& operator=(zone&&) = default;
210  zone(const zone&) = delete;
211  zone& operator=(const zone&) = delete;
212 
213 private:
214  void undo_allocate(size_t size);
215 
216  template <typename T>
217  static void object_destruct(void* obj);
218 
219  template <typename T>
220  static void object_delete(void* obj);
221 
222  static char* get_aligned(char* ptr, size_t align);
223 
224  char* allocate_expand(size_t size);
225 };
226 
227 inline zone::zone(size_t chunk_size) noexcept:m_chunk_size(chunk_size), m_chunk_list(m_chunk_size)
228 {
229 }
230 
231 inline char* zone::get_aligned(char* ptr, size_t align)
232 {
233  return
234  reinterpret_cast<char*>(
235  reinterpret_cast<size_t>(
236  (ptr + (align - 1))) / align * align);
237 }
238 
239 inline void* zone::allocate_align(size_t size, size_t align)
240 {
241  char* aligned = get_aligned(m_chunk_list.m_ptr, align);
242  size_t adjusted_size = size + (aligned - m_chunk_list.m_ptr);
243  if (m_chunk_list.m_free < adjusted_size) {
244  size_t enough_size = size + align - 1;
245  char* ptr = allocate_expand(enough_size);
246  aligned = get_aligned(ptr, align);
247  adjusted_size = size + (aligned - m_chunk_list.m_ptr);
248  }
249  m_chunk_list.m_free -= adjusted_size;
250  m_chunk_list.m_ptr += adjusted_size;
251  return aligned;
252 }
253 
254 inline void* zone::allocate_no_align(size_t size)
255 {
256  char* ptr = m_chunk_list.m_ptr;
257  if(m_chunk_list.m_free < size) {
258  ptr = allocate_expand(size);
259  }
260  m_chunk_list.m_free -= size;
261  m_chunk_list.m_ptr += size;
262 
263  return ptr;
264 }
265 
266 inline char* zone::allocate_expand(size_t size)
267 {
268  chunk_list* const cl = &m_chunk_list;
269 
270  size_t sz = m_chunk_size;
271 
272  while(sz < size) {
273  size_t tmp_sz = sz * 2;
274  if (tmp_sz <= sz) {
275  sz = size;
276  break;
277  }
278  sz = tmp_sz;
279  }
280 
281  chunk* c = static_cast<chunk*>(::malloc(sizeof(chunk) + sz));
282  if (!c) throw std::bad_alloc();
283 
284  char* ptr = reinterpret_cast<char*>(c) + sizeof(chunk);
285 
286  c->m_next = cl->m_head;
287  cl->m_head = c;
288  cl->m_free = sz;
289  cl->m_ptr = ptr;
290 
291  return ptr;
292 }
293 
294 inline void zone::push_finalizer(void (*func)(void*), void* data)
295 {
296  m_finalizer_array.push(func, data);
297 }
298 
299 template <typename T>
301 {
302  m_finalizer_array.push(&zone::object_delete<T>, obj.release());
303 }
304 
305 inline void zone::clear()
306 {
307  m_finalizer_array.clear();
308  m_chunk_list.clear(m_chunk_size);
309 }
310 
311 inline void zone::swap(zone& o)
312 {
313  std::swap(*this, o);
314 }
315 
316 template <typename T>
317 void zone::object_delete(void* obj)
318 {
319  delete static_cast<T*>(obj);
320 }
321 
322 template <typename T>
323 void zone::object_destruct(void* obj)
324 {
325  static_cast<T*>(obj)->~T();
326 }
327 
328 inline void zone::undo_allocate(size_t size)
329 {
330  m_chunk_list.m_ptr -= size;
331  m_chunk_list.m_free += size;
332 }
333 
334 
335 template <typename T, typename... Args>
336 T* zone::allocate(Args... args)
337 {
338  void* x = allocate_align(sizeof(T), MSGPACK_ZONE_ALIGNOF(T));
339  try {
340  m_finalizer_array.push(&zone::object_destruct<T>, x);
341  } catch (...) {
342  undo_allocate(sizeof(T));
343  throw;
344  }
345  try {
346  return new (x) T(args...);
347  } catch (...) {
348  --m_finalizer_array.m_tail;
349  undo_allocate(sizeof(T));
350  throw;
351  }
352 }
353 
354 inline std::size_t aligned_size(
355  std::size_t size,
356  std::size_t align) {
357  return (size + align - 1) / align * align;
358 }
359 
361 } // MSGPACK_API_VERSION_NAMESPACE(v1)
363 
364 } // namespace msgpack
365 
366 #endif // MSGPACK_CPP11_ZONE_HPP
MSGPACK_ZONE_CHUNK_SIZE
#define MSGPACK_ZONE_CHUNK_SIZE
Definition: cpp03_zone_decl.hpp:20
msgpack::zone::allocate_align
void * allocate_align(size_t size, size_t align=MSGPACK_ZONE_ALIGN)
Definition: cpp03_zone.hpp:246
msgpack
Definition: adaptor_base.hpp:15
MSGPACK_ZONE_ALIGNOF
#define MSGPACK_ZONE_ALIGNOF(type)
Definition: cpp03_zone_decl.hpp:30
msgpack::zone::push_finalizer
void push_finalizer(void(*func)(void *), void *data)
Definition: cpp03_zone.hpp:301
msgpack::zone::clear
void clear()
Definition: cpp03_zone.hpp:312
MSGPACK_API_VERSION_NAMESPACE
#define MSGPACK_API_VERSION_NAMESPACE(ns)
Definition: versioning.hpp:58
msgpack::zone::swap
void swap(zone &o)
Definition: cpp03_zone.hpp:318
msgpack::zone
Definition: cpp03_zone.hpp:22
msgpack::zone::allocate
T * allocate(Args... args)
Definition: cpp11_zone.hpp:336
msgpack::aligned_size
std::size_t aligned_size(std::size_t size, std::size_t align)
Definition: cpp03_zone.hpp:344
versioning.hpp
msgpack::type::size
std::size_t size(T const &t)
Definition: size_equal_only.hpp:24
MSGPACK_NULLPTR
#define MSGPACK_NULLPTR
Definition: cpp_config_decl.hpp:35
zone_decl.hpp
msgpack::unique_ptr
Definition: cpp_config_decl.hpp:47
msgpack::move
T & move(T &t)
cpp_config.hpp
MSGPACK_ZONE_ALIGN
#define MSGPACK_ZONE_ALIGN
Definition: cpp03_zone_decl.hpp:24
msgpack::zone::zone
zone(size_t chunk_size=MSGPACK_ZONE_CHUNK_SIZE)
Definition: cpp03_zone.hpp:234
msgpack::zone::allocate_no_align
void * allocate_no_align(size_t size)
Definition: cpp03_zone.hpp:261