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_free = 0;
154 other.m_ptr = MSGPACK_NULLPTR;
155 other.m_head = MSGPACK_NULLPTR;
156 }
157 chunk_list& operator=(chunk_list&& other) noexcept
158 {
159 this->~chunk_list();
160 new (this) chunk_list(std::move(other));
161 return *this;
162 }
163
164 size_t m_free;
165 char* m_ptr;
166 chunk* m_head;
167 private:
168 chunk_list(const chunk_list&);
169 chunk_list& operator=(const chunk_list&);
170 };
171 size_t m_chunk_size;
172 chunk_list m_chunk_list;
173 finalizer_array m_finalizer_array;
174
175public:
176 zone(size_t chunk_size = MSGPACK_ZONE_CHUNK_SIZE);
177
178public:
179 void* allocate_align(size_t size, size_t align = MSGPACK_ZONE_ALIGN);
180 void* allocate_no_align(size_t size);
181
182 void push_finalizer(void (*func)(void*), void* data);
183
184 template <typename T>
185 void push_finalizer(msgpack::unique_ptr<T> obj);
186
187 void clear();
188
189 void swap(zone& o);
190
191 static void* operator new(std::size_t size)
192 {
193 void* p = ::malloc(size);
194 if (!p) throw std::bad_alloc();
195 return p;
196 }
197 static void operator delete(void *p) noexcept
198 {
199 ::free(p);
200 }
201 static void* operator new(std::size_t /*size*/, void* mem) noexcept
202 {
203 return mem;
204 }
205 static void operator delete(void * /*p*/, void* /*mem*/) noexcept
206 {
207 }
208
209 template <typename T, typename... Args>
210 T* allocate(Args... args);
211
212 zone(zone&&) = default;
213 zone& operator=(zone&& other) {
214 if (this != &other) {
215 // Destroy in the correct order: run finalizers first (while our
216 // chunks are still alive), then release our chunks. A defaulted
217 // move-assignment would free the chunks before the finalizers run,
218 // causing use-after-free of zone-allocated objects.
219 m_finalizer_array = std::move(other.m_finalizer_array);
220 m_chunk_list = std::move(other.m_chunk_list);
221 m_chunk_size = other.m_chunk_size;
222 }
223 return *this;
224 }
225 zone(const zone&) = delete;
226 zone& operator=(const zone&) = delete;
227
228private:
229 void undo_allocate(size_t size);
230
231 template <typename T>
232 static void object_destruct(void* obj);
233
234 template <typename T>
235 static void object_delete(void* obj);
236
237 static char* get_aligned(char* ptr, size_t align);
238
239 char* allocate_expand(size_t size);
240};
241
242inline zone::zone(size_t chunk_size):m_chunk_size(chunk_size), m_chunk_list(m_chunk_size)
243{
244}
245
246inline char* zone::get_aligned(char* ptr, size_t align)
247{
248 MSGPACK_ASSERT(align != 0 && (align & (align - 1)) == 0); // align must be 2^n (n >= 0)
249 return
250 reinterpret_cast<char*>(
251 reinterpret_cast<uintptr_t>(ptr + (align - 1)) & ~static_cast<uintptr_t>(align - 1)
252 );
253}
254
255inline void* zone::allocate_align(size_t size, size_t align)
256{
257 char* aligned = get_aligned(m_chunk_list.m_ptr, align);
258 size_t adjusted_size = size + static_cast<size_t>(aligned - m_chunk_list.m_ptr);
259 if (m_chunk_list.m_free < adjusted_size) {
260 size_t enough_size = size + align - 1;
261 char* ptr = allocate_expand(enough_size);
262 aligned = get_aligned(ptr, align);
263 adjusted_size = size + static_cast<size_t>(aligned - m_chunk_list.m_ptr);
264 }
265 m_chunk_list.m_free -= adjusted_size;
266 m_chunk_list.m_ptr += adjusted_size;
267 return aligned;
268}
269
270inline void* zone::allocate_no_align(size_t size)
271{
272 char* ptr = m_chunk_list.m_ptr;
273 if(m_chunk_list.m_free < size) {
274 ptr = allocate_expand(size);
275 }
276 m_chunk_list.m_free -= size;
277 m_chunk_list.m_ptr += size;
278
279 return ptr;
280}
281
282inline char* zone::allocate_expand(size_t size)
283{
284 chunk_list* const cl = &m_chunk_list;
285
286 size_t sz = m_chunk_size;
287
288 while(sz < size) {
289 size_t tmp_sz = sz * 2;
290 if (tmp_sz <= sz) {
291 sz = size;
292 break;
293 }
294 sz = tmp_sz;
295 }
296
297 if((sizeof(chunk) + sz) < sz) {
298 throw std::bad_alloc();
299 }
300
301 chunk* c = static_cast<chunk*>(::malloc(sizeof(chunk) + sz));
302 if (!c) throw std::bad_alloc();
303
304 char* ptr = reinterpret_cast<char*>(c) + sizeof(chunk);
305
306 c->m_next = cl->m_head;
307 cl->m_head = c;
308 cl->m_free = sz;
309 cl->m_ptr = ptr;
310
311 return ptr;
312}
313
314inline void zone::push_finalizer(void (*func)(void*), void* data)
315{
316 m_finalizer_array.push(func, data);
317}
318
319template <typename T>
320inline void zone::push_finalizer(msgpack::unique_ptr<T> obj)
321{
322 m_finalizer_array.push(&zone::object_delete<T>, obj.release());
323}
324
325inline void zone::clear()
326{
327 m_finalizer_array.clear();
328 m_chunk_list.clear(m_chunk_size);
329}
330
331inline void zone::swap(zone& o)
332{
333 std::swap(*this, o);
334}
335
336template <typename T>
337void zone::object_delete(void* obj)
338{
339 delete static_cast<T*>(obj);
340}
341
342template <typename T>
343void zone::object_destruct(void* obj)
344{
345 static_cast<T*>(obj)->~T();
346}
347
348inline void zone::undo_allocate(size_t size)
349{
350 m_chunk_list.m_ptr -= size;
351 m_chunk_list.m_free += size;
352}
353
354
355template <typename T, typename... Args>
356T* zone::allocate(Args... args)
357{
358 void* x = allocate_align(sizeof(T), MSGPACK_ZONE_ALIGNOF(T));
359 try {
360 m_finalizer_array.push(&zone::object_destruct<T>, x);
361 } catch (...) {
362 undo_allocate(sizeof(T));
363 throw;
364 }
365 try {
366 return new (x) T(args...);
367 } catch (...) {
368 --m_finalizer_array.m_tail;
369 undo_allocate(sizeof(T));
370 throw;
371 }
372}
373
374inline std::size_t aligned_size(
375 std::size_t size,
376 std::size_t align) {
377 return (size + align - 1) / align * align;
378}
379
381} // MSGPACK_API_VERSION_NAMESPACE(v1)
383
384} // namespace msgpack
385
386#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 &&other)
Definition cpp11_zone.hpp:213
T * allocate(Args... args)
Definition cpp11_zone.hpp:356
void * allocate_no_align(size_t size)
void push_finalizer(msgpack::unique_ptr< T > obj)
void clear()
Definition cpp03_zone.hpp:325
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:365
#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