/src/msgpack-c/include/msgpack/v1/detail/cpp11_zone.hpp
Line | Count | Source (jump to first uncovered line) |
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 | | #include "msgpack/assert.hpp" |
17 | | |
18 | | #include <cstdint> |
19 | | #include <cstdlib> |
20 | | #include <memory> |
21 | | #include <vector> |
22 | | |
23 | | namespace msgpack { |
24 | | |
25 | | /// @cond |
26 | | MSGPACK_API_VERSION_NAMESPACE(v1) { |
27 | | /// @endcond |
28 | | |
29 | | class zone { |
30 | | private: |
31 | | struct finalizer { |
32 | 0 | finalizer(void (*func)(void*), void* data):m_func(func), m_data(data) {} |
33 | 0 | void operator()() { m_func(m_data); } |
34 | | void (*m_func)(void*); |
35 | | void* m_data; |
36 | | }; |
37 | | struct finalizer_array { |
38 | 2.25k | finalizer_array():m_tail(MSGPACK_NULLPTR), m_end(MSGPACK_NULLPTR), m_array(MSGPACK_NULLPTR) {} |
39 | 2.25k | void call() { |
40 | 2.25k | finalizer* fin = m_tail; |
41 | 2.25k | for(; fin != m_array; --fin) (*(fin-1))(); |
42 | 2.25k | } |
43 | 2.25k | ~finalizer_array() { |
44 | 2.25k | call(); |
45 | 2.25k | ::free(m_array); |
46 | 2.25k | } |
47 | 0 | void clear() { |
48 | 0 | call(); |
49 | 0 | m_tail = m_array; |
50 | 0 | } |
51 | | void push(void (*func)(void* data), void* data) |
52 | 0 | { |
53 | 0 | finalizer* fin = m_tail; |
54 | 0 |
|
55 | 0 | if(fin == m_end) { |
56 | 0 | push_expand(func, data); |
57 | 0 | return; |
58 | 0 | } |
59 | 0 |
|
60 | 0 | fin->m_func = func; |
61 | 0 | fin->m_data = data; |
62 | 0 |
|
63 | 0 | ++m_tail; |
64 | 0 | } |
65 | 0 | void push_expand(void (*func)(void*), void* data) { |
66 | 0 | const size_t nused = static_cast<size_t>(m_end - m_array); |
67 | 0 | size_t nnext; |
68 | 0 | if(nused == 0) { |
69 | 0 | nnext = (sizeof(finalizer) < 72/2) ? |
70 | 0 | 72 / sizeof(finalizer) : 8; |
71 | 0 | } else { |
72 | 0 | nnext = nused * 2; |
73 | 0 | } |
74 | 0 | finalizer* tmp = |
75 | 0 | static_cast<finalizer*>(::realloc(m_array, sizeof(finalizer) * nnext)); |
76 | 0 | if(!tmp) { |
77 | 0 | throw std::bad_alloc(); |
78 | 0 | } |
79 | 0 | m_array = tmp; |
80 | 0 | m_end = tmp + nnext; |
81 | 0 | m_tail = tmp + nused; |
82 | 0 | new (m_tail) finalizer(func, data); |
83 | 0 |
|
84 | 0 | ++m_tail; |
85 | 0 | } |
86 | | finalizer_array(finalizer_array&& other) noexcept |
87 | | :m_tail(other.m_tail), m_end(other.m_end), m_array(other.m_array) |
88 | 0 | { |
89 | 0 | other.m_tail = MSGPACK_NULLPTR; |
90 | 0 | other.m_end = MSGPACK_NULLPTR; |
91 | 0 | other.m_array = MSGPACK_NULLPTR; |
92 | 0 | } |
93 | | finalizer_array& operator=(finalizer_array&& other) noexcept |
94 | 0 | { |
95 | 0 | this->~finalizer_array(); |
96 | 0 | new (this) finalizer_array(std::move(other)); |
97 | 0 | return *this; |
98 | 0 | } |
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 | 2.25k | { |
114 | 2.25k | chunk* c = static_cast<chunk*>(::malloc(sizeof(chunk) + chunk_size)); |
115 | 2.25k | if(!c) { |
116 | 0 | throw std::bad_alloc(); |
117 | 0 | } |
118 | | |
119 | 2.25k | m_head = c; |
120 | 2.25k | m_free = chunk_size; |
121 | 2.25k | m_ptr = reinterpret_cast<char*>(c) + sizeof(chunk); |
122 | 2.25k | c->m_next = MSGPACK_NULLPTR; |
123 | 2.25k | } |
124 | | ~chunk_list() |
125 | 2.25k | { |
126 | 2.25k | chunk* c = m_head; |
127 | 13.6k | while(c) { |
128 | 11.3k | chunk* n = c->m_next; |
129 | 11.3k | ::free(c); |
130 | 11.3k | c = n; |
131 | 11.3k | } |
132 | 2.25k | } |
133 | | void clear(size_t chunk_size) |
134 | 0 | { |
135 | 0 | chunk* c = m_head; |
136 | 0 | while(true) { |
137 | 0 | chunk* n = c->m_next; |
138 | 0 | if(n) { |
139 | 0 | ::free(c); |
140 | 0 | c = n; |
141 | 0 | } else { |
142 | 0 | m_head = c; |
143 | 0 | break; |
144 | 0 | } |
145 | 0 | } |
146 | 0 | m_head->m_next = MSGPACK_NULLPTR; |
147 | 0 | m_free = chunk_size; |
148 | 0 | m_ptr = reinterpret_cast<char*>(m_head) + sizeof(chunk); |
149 | 0 | } |
150 | | chunk_list(chunk_list&& other) noexcept |
151 | | :m_free(other.m_free), m_ptr(other.m_ptr), m_head(other.m_head) |
152 | 0 | { |
153 | 0 | other.m_head = MSGPACK_NULLPTR; |
154 | 0 | } |
155 | | chunk_list& operator=(chunk_list&& other) noexcept |
156 | 0 | { |
157 | 0 | this->~chunk_list(); |
158 | 0 | new (this) chunk_list(std::move(other)); |
159 | 0 | return *this; |
160 | 0 | } |
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 | | |
173 | | public: |
174 | | zone(size_t chunk_size = MSGPACK_ZONE_CHUNK_SIZE); |
175 | | |
176 | | public: |
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 | 2.25k | { |
191 | 2.25k | void* p = ::malloc(size); |
192 | 2.25k | if (!p) throw std::bad_alloc(); |
193 | 2.25k | return p; |
194 | 2.25k | } |
195 | | static void operator delete(void *p) noexcept |
196 | 2.25k | { |
197 | 2.25k | ::free(p); |
198 | 2.25k | } |
199 | | static void* operator new(std::size_t /*size*/, void* mem) noexcept |
200 | 0 | { |
201 | 0 | return mem; |
202 | 0 | } |
203 | | static void operator delete(void * /*p*/, void* /*mem*/) noexcept |
204 | 0 | { |
205 | 0 | } |
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 | | |
215 | | private: |
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 | | |
229 | | inline zone::zone(size_t chunk_size):m_chunk_size(chunk_size), m_chunk_list(m_chunk_size) |
230 | 2.25k | { |
231 | 2.25k | } |
232 | | |
233 | | inline char* zone::get_aligned(char* ptr, size_t align) |
234 | 442k | { |
235 | 442k | MSGPACK_ASSERT(align != 0 && (align & (align - 1)) == 0); // align must be 2^n (n >= 0) |
236 | 0 | return |
237 | 442k | reinterpret_cast<char*>( |
238 | 442k | reinterpret_cast<uintptr_t>(ptr + (align - 1)) & ~static_cast<uintptr_t>(align - 1) |
239 | 442k | ); |
240 | 442k | } |
241 | | |
242 | | inline void* zone::allocate_align(size_t size, size_t align) |
243 | 432k | { |
244 | 432k | char* aligned = get_aligned(m_chunk_list.m_ptr, align); |
245 | 432k | size_t adjusted_size = size + static_cast<size_t>(aligned - m_chunk_list.m_ptr); |
246 | 432k | if (m_chunk_list.m_free < adjusted_size) { |
247 | 9.11k | size_t enough_size = size + align - 1; |
248 | 9.11k | char* ptr = allocate_expand(enough_size); |
249 | 9.11k | aligned = get_aligned(ptr, align); |
250 | 9.11k | adjusted_size = size + static_cast<size_t>(aligned - m_chunk_list.m_ptr); |
251 | 9.11k | } |
252 | 432k | m_chunk_list.m_free -= adjusted_size; |
253 | 432k | m_chunk_list.m_ptr += adjusted_size; |
254 | 432k | return aligned; |
255 | 432k | } |
256 | | |
257 | | inline void* zone::allocate_no_align(size_t size) |
258 | 0 | { |
259 | 0 | char* ptr = m_chunk_list.m_ptr; |
260 | 0 | if(m_chunk_list.m_free < size) { |
261 | 0 | ptr = allocate_expand(size); |
262 | 0 | } |
263 | 0 | m_chunk_list.m_free -= size; |
264 | 0 | m_chunk_list.m_ptr += size; |
265 | 0 |
|
266 | 0 | return ptr; |
267 | 0 | } |
268 | | |
269 | | inline char* zone::allocate_expand(size_t size) |
270 | 9.11k | { |
271 | 9.11k | chunk_list* const cl = &m_chunk_list; |
272 | | |
273 | 9.11k | size_t sz = m_chunk_size; |
274 | | |
275 | 12.3k | while(sz < size) { |
276 | 3.19k | size_t tmp_sz = sz * 2; |
277 | 3.19k | if (tmp_sz <= sz) { |
278 | 0 | sz = size; |
279 | 0 | break; |
280 | 0 | } |
281 | 3.19k | sz = tmp_sz; |
282 | 3.19k | } |
283 | | |
284 | 9.11k | chunk* c = static_cast<chunk*>(::malloc(sizeof(chunk) + sz)); |
285 | 9.11k | if (!c) throw std::bad_alloc(); |
286 | | |
287 | 9.11k | char* ptr = reinterpret_cast<char*>(c) + sizeof(chunk); |
288 | | |
289 | 9.11k | c->m_next = cl->m_head; |
290 | 9.11k | cl->m_head = c; |
291 | 9.11k | cl->m_free = sz; |
292 | 9.11k | cl->m_ptr = ptr; |
293 | | |
294 | 9.11k | return ptr; |
295 | 9.11k | } |
296 | | |
297 | | inline void zone::push_finalizer(void (*func)(void*), void* data) |
298 | 0 | { |
299 | 0 | m_finalizer_array.push(func, data); |
300 | 0 | } |
301 | | |
302 | | template <typename T> |
303 | | inline void zone::push_finalizer(msgpack::unique_ptr<T> obj) |
304 | | { |
305 | | m_finalizer_array.push(&zone::object_delete<T>, obj.release()); |
306 | | } |
307 | | |
308 | | inline void zone::clear() |
309 | 0 | { |
310 | 0 | m_finalizer_array.clear(); |
311 | 0 | m_chunk_list.clear(m_chunk_size); |
312 | 0 | } |
313 | | |
314 | | inline void zone::swap(zone& o) |
315 | 0 | { |
316 | 0 | std::swap(*this, o); |
317 | 0 | } |
318 | | |
319 | | template <typename T> |
320 | | void zone::object_delete(void* obj) |
321 | | { |
322 | | delete static_cast<T*>(obj); |
323 | | } |
324 | | |
325 | | template <typename T> |
326 | | void zone::object_destruct(void* obj) |
327 | | { |
328 | | static_cast<T*>(obj)->~T(); |
329 | | } |
330 | | |
331 | | inline void zone::undo_allocate(size_t size) |
332 | 0 | { |
333 | 0 | m_chunk_list.m_ptr -= size; |
334 | 0 | m_chunk_list.m_free += size; |
335 | 0 | } |
336 | | |
337 | | |
338 | | template <typename T, typename... Args> |
339 | | T* 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 | | |
357 | | inline std::size_t aligned_size( |
358 | | std::size_t size, |
359 | 0 | std::size_t align) { |
360 | 0 | return (size + align - 1) / align * align; |
361 | 0 | } |
362 | | |
363 | | /// @cond |
364 | | } // MSGPACK_API_VERSION_NAMESPACE(v1) |
365 | | /// @endcond |
366 | | |
367 | | } // namespace msgpack |
368 | | |
369 | | #endif // MSGPACK_CPP11_ZONE_HPP |