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