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