MessagePack for C++
Loading...
Searching...
No Matches
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
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
23namespace msgpack {
24
28
29class zone {
30private:
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
173public:
174 zone(size_t chunk_size = MSGPACK_ZONE_CHUNK_SIZE);
175
176public:
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
215private:
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
229inline zone::zone(size_t chunk_size):m_chunk_size(chunk_size), m_chunk_list(m_chunk_size)
230{
231}
232
233inline 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
242inline 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
257inline 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
269inline 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
297inline void zone::push_finalizer(void (*func)(void*), void* data)
298{
299 m_finalizer_array.push(func, data);
300}
301
302template <typename T>
303inline void zone::push_finalizer(msgpack::unique_ptr<T> obj)
304{
305 m_finalizer_array.push(&zone::object_delete<T>, obj.release());
306}
307
308inline void zone::clear()
309{
310 m_finalizer_array.clear();
311 m_chunk_list.clear(m_chunk_size);
312}
313
314inline void zone::swap(zone& o)
315{
316 std::swap(*this, o);
317}
318
319template <typename T>
320void zone::object_delete(void* obj)
321{
322 delete static_cast<T*>(obj);
323}
324
325template <typename T>
326void zone::object_destruct(void* obj)
327{
328 static_cast<T*>(obj)->~T();
329}
330
331inline 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
338template <typename T, typename... Args>
339T* 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
357inline 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(const zone &)=delete
zone & operator=(zone &&)=default
T * allocate(Args... args)
Definition cpp11_zone.hpp:339
void * allocate_no_align(size_t size)
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)
zone & operator=(const zone &)=delete
void push_finalizer(void(*func)(void *), void *data)
zone(size_t chunk_size=MSGPACK_ZONE_CHUNK_SIZE)
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