1// 2// MessagePack for C++ memory pool 3// 4// Copyright (C) 2008-2010 FURUHASHI Sadayuki 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_CPP03_ZONE_HPP 11#define MSGPACK_CPP03_ZONE_HPP 12 13#include <cstdlib> 14#include <memory> 15#include <vector> 16 17#include "msgpack/versioning.hpp" 18 19#ifndef MSGPACK_ZONE_CHUNK_SIZE 20#define MSGPACK_ZONE_CHUNK_SIZE 8192 21#endif 22 23#ifndef MSGPACK_ZONE_ALIGN 24#define MSGPACK_ZONE_ALIGN sizeof(void*) 25#endif 26 27 28namespace msgpack { 29 30/// @cond 31MSGPACK_API_VERSION_NAMESPACE(v1) { 32/// @endcond 33 34class zone { 35 struct finalizer { 36 finalizer(void (*func)(void*), void* data):m_func(func), m_data(data) {} 37 void operator()() { m_func(m_data); } 38 void (*m_func)(void*); 39 void* m_data; 40 }; 41 struct finalizer_array { 42 finalizer_array():m_tail(nullptr), m_end(nullptr), m_array(nullptr) {} 43 void call() { 44 finalizer* fin = m_tail; 45 for(; fin != m_array; --fin) (*(fin-1))(); 46 } 47 ~finalizer_array() { 48 call(); 49 ::free(m_array); 50 } 51 void clear() { 52 call(); 53 m_tail = m_array; 54 } 55 void push(void (*func)(void* data), void* data) 56 { 57 finalizer* fin = m_tail; 58 59 if(fin == m_end) { 60 push_expand(func, data); 61 return; 62 } 63 64 fin->m_func = func; 65 fin->m_data = data; 66 67 ++m_tail; 68 } 69 void push_expand(void (*func)(void*), void* data) { 70 const size_t nused = m_end - m_array; 71 size_t nnext; 72 if(nused == 0) { 73 nnext = (sizeof(finalizer) < 72/2) ? 74 72 / sizeof(finalizer) : 8; 75 } else { 76 nnext = nused * 2; 77 } 78 finalizer* tmp = 79 static_cast<finalizer*>(::realloc(m_array, sizeof(finalizer) * nnext)); 80 if(!tmp) { 81 throw std::bad_alloc(); 82 } 83 m_array = tmp; 84 m_end = tmp + nnext; 85 m_tail = tmp + nused; 86 new (m_tail) finalizer(func, data); 87 88 ++m_tail; 89 } 90 finalizer* m_tail; 91 finalizer* m_end; 92 finalizer* m_array; 93 }; 94 struct chunk { 95 chunk* m_next; 96 }; 97 struct chunk_list { 98 chunk_list(size_t chunk_size) 99 { 100 chunk* c = static_cast<chunk*>(::malloc(sizeof(chunk) + chunk_size)); 101 if(!c) { 102 throw std::bad_alloc(); 103 } 104 105 m_head = c; 106 m_free = chunk_size; 107 m_ptr = reinterpret_cast<char*>(c) + sizeof(chunk); 108 c->m_next = nullptr; 109 } 110 ~chunk_list() 111 { 112 chunk* c = m_head; 113 while(c) { 114 chunk* n = c->m_next; 115 ::free(c); 116 c = n; 117 } 118 } 119 void clear(size_t chunk_size) 120 { 121 chunk* c = m_head; 122 while(true) { 123 chunk* n = c->m_next; 124 if(n) { 125 ::free(c); 126 c = n; 127 } else { 128 break; 129 } 130 } 131 m_head->m_next = nullptr; 132 m_free = chunk_size; 133 m_ptr = reinterpret_cast<char*>(m_head) + sizeof(chunk); 134 } 135 size_t m_free; 136 char* m_ptr; 137 chunk* m_head; 138 }; 139 size_t m_chunk_size; 140 chunk_list m_chunk_list; 141 finalizer_array m_finalizer_array; 142 143public: 144 zone(size_t chunk_size = MSGPACK_ZONE_CHUNK_SIZE) /* throw() */; 145 146public: 147 void* allocate_align(size_t size, size_t align = MSGPACK_ZONE_ALIGN); 148 void* allocate_no_align(size_t size); 149 150 void push_finalizer(void (*func)(void*), void* data); 151 152 template <typename T> 153 void push_finalizer(msgpack::unique_ptr<T> obj); 154 155 void clear(); 156 157 void swap(zone& o); 158 static void* operator new(std::size_t size) 159 { 160 void* p = ::malloc(size); 161 if (!p) throw std::bad_alloc(); 162 return p; 163 } 164 static void operator delete(void *p) /* throw() */ 165 { 166 ::free(p); 167 } 168 static void* operator new(std::size_t size, void* place) /* throw() */ 169 { 170 return ::operator new(size, place); 171 } 172 static void operator delete(void* p, void* place) /* throw() */ 173 { 174 ::operator delete(p, place); 175 } 176 /// @cond 177 178 template <typename T> 179 T* allocate(); 180 181 template <typename T, typename A1> 182 T* allocate(A1 a1); 183 184 template <typename T, typename A1, typename A2> 185 T* allocate(A1 a1, A2 a2); 186 187 template <typename T, typename A1, typename A2, typename A3> 188 T* allocate(A1 a1, A2 a2, A3 a3); 189 190 template <typename T, typename A1, typename A2, typename A3, typename A4> 191 T* allocate(A1 a1, A2 a2, A3 a3, A4 a4); 192 193 template <typename T, typename A1, typename A2, typename A3, typename A4, typename A5> 194 T* allocate(A1 a1, A2 a2, A3 a3, A4 a4, A5 a5); 195 196 template <typename T, typename A1, typename A2, typename A3, typename A4, typename A5, typename A6> 197 T* allocate(A1 a1, A2 a2, A3 a3, A4 a4, A5 a5, A6 a6); 198 199 template <typename T, typename A1, typename A2, typename A3, typename A4, typename A5, typename A6, typename A7> 200 T* allocate(A1 a1, A2 a2, A3 a3, A4 a4, A5 a5, A6 a6, A7 a7); 201 202 template <typename T, typename A1, typename A2, typename A3, typename A4, typename A5, typename A6, typename A7, typename A8> 203 T* allocate(A1 a1, A2 a2, A3 a3, A4 a4, A5 a5, A6 a6, A7 a7, A8 a8); 204 205 template <typename T, typename A1, typename A2, typename A3, typename A4, typename A5, typename A6, typename A7, typename A8, typename A9> 206 T* allocate(A1 a1, A2 a2, A3 a3, A4 a4, A5 a5, A6 a6, A7 a7, A8 a8, A9 a9); 207 208 template <typename T, typename A1, typename A2, typename A3, typename A4, typename A5, typename A6, typename A7, typename A8, typename A9, typename A10> 209 T* allocate(A1 a1, A2 a2, A3 a3, A4 a4, A5 a5, A6 a6, A7 a7, A8 a8, A9 a9, A10 a10); 210 211 template <typename T, typename A1, typename A2, typename A3, typename A4, typename A5, typename A6, typename A7, typename A8, typename A9, typename A10, typename A11> 212 T* allocate(A1 a1, A2 a2, A3 a3, A4 a4, A5 a5, A6 a6, A7 a7, A8 a8, A9 a9, A10 a10, A11 a11); 213 214 template <typename T, typename A1, typename A2, typename A3, typename A4, typename A5, typename A6, typename A7, typename A8, typename A9, typename A10, typename A11, typename A12> 215 T* allocate(A1 a1, A2 a2, A3 a3, A4 a4, A5 a5, A6 a6, A7 a7, A8 a8, A9 a9, A10 a10, A11 a11, A12 a12); 216 217 template <typename T, typename A1, typename A2, typename A3, typename A4, typename A5, typename A6, typename A7, typename A8, typename A9, typename A10, typename A11, typename A12, typename A13> 218 T* allocate(A1 a1, A2 a2, A3 a3, A4 a4, A5 a5, A6 a6, A7 a7, A8 a8, A9 a9, A10 a10, A11 a11, A12 a12, A13 a13); 219 220 template <typename T, typename A1, typename A2, typename A3, typename A4, typename A5, typename A6, typename A7, typename A8, typename A9, typename A10, typename A11, typename A12, typename A13, typename A14> 221 T* allocate(A1 a1, A2 a2, A3 a3, A4 a4, A5 a5, A6 a6, A7 a7, A8 a8, A9 a9, A10 a10, A11 a11, A12 a12, A13 a13, A14 a14); 222 223 template <typename T, typename A1, typename A2, typename A3, typename A4, typename A5, typename A6, typename A7, typename A8, typename A9, typename A10, typename A11, typename A12, typename A13, typename A14, typename A15> 224 T* allocate(A1 a1, A2 a2, A3 a3, A4 a4, A5 a5, A6 a6, A7 a7, A8 a8, A9 a9, A10 a10, A11 a11, A12 a12, A13 a13, A14 a14, A15 a15); 225 226 /// @endcond 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 void* allocate_expand(size_t size); 238private: 239 zone(const zone&); 240 zone& operator=(const zone&); 241}; 242 243inline zone::zone(size_t chunk_size) /* throw() */ :m_chunk_size(chunk_size), m_chunk_list(m_chunk_size) 244{ 245} 246 247inline void* zone::allocate_align(size_t size, size_t align) 248{ 249 char* aligned = 250 reinterpret_cast<char*>( 251 reinterpret_cast<size_t>( 252 (m_chunk_list.m_ptr + (align - 1))) / align * align); 253 size_t adjusted_size = size + (aligned - m_chunk_list.m_ptr); 254 if(m_chunk_list.m_free >= adjusted_size) { 255 m_chunk_list.m_free -= adjusted_size; 256 m_chunk_list.m_ptr += adjusted_size; 257 return aligned; 258 } 259 return reinterpret_cast<char*>( 260 reinterpret_cast<size_t>( 261 allocate_expand(size + (align - 1))) / align * align); 262} 263 264inline void* zone::allocate_no_align(size_t size) 265{ 266 if(m_chunk_list.m_free < size) { 267 return allocate_expand(size); 268 } 269 270 char* ptr = m_chunk_list.m_ptr; 271 m_chunk_list.m_free -= size; 272 m_chunk_list.m_ptr += size; 273 274 return ptr; 275} 276 277inline void* zone::allocate_expand(size_t size) 278{ 279 chunk_list* const cl = &m_chunk_list; 280 281 size_t sz = m_chunk_size; 282 283 while(sz < size) { 284 size_t tmp_sz = sz * 2; 285 if (tmp_sz <= sz) { 286 sz = size; 287 break; 288 } 289 sz = tmp_sz; 290 } 291 292 chunk* c = static_cast<chunk*>(::malloc(sizeof(chunk) + sz)); 293 if (!c) throw std::bad_alloc(); 294 295 char* ptr = reinterpret_cast<char*>(c) + sizeof(chunk); 296 297 c->m_next = cl->m_head; 298 cl->m_head = c; 299 cl->m_free = sz - size; 300 cl->m_ptr = ptr + size; 301 302 return ptr; 303} 304 305inline void zone::push_finalizer(void (*func)(void*), void* data) 306{ 307 m_finalizer_array.push(func, data); 308} 309 310template <typename T> 311inline void zone::push_finalizer(msgpack::unique_ptr<T> obj) 312{ 313 m_finalizer_array.push(&zone::object_delete<T>, obj.release()); 314} 315 316inline void zone::clear() 317{ 318 m_finalizer_array.clear(); 319 m_chunk_list.clear(m_chunk_size); 320} 321 322inline void zone::swap(zone& o) 323{ 324 using std::swap; 325 swap(m_chunk_size, o.m_chunk_size); 326 swap(m_chunk_list, o.m_chunk_list); 327 swap(m_finalizer_array, o.m_finalizer_array); 328} 329 330template <typename T> 331void zone::object_destruct(void* obj) 332{ 333 static_cast<T*>(obj)->~T(); 334} 335 336template <typename T> 337void zone::object_delete(void* obj) 338{ 339 delete static_cast<T*>(obj); 340} 341 342inline void zone::undo_allocate(size_t size) 343{ 344 m_chunk_list.m_ptr -= size; 345 m_chunk_list.m_free += size; 346} 347 348inline std::size_t aligned_size( 349 std::size_t size, 350 std::size_t align = MSGPACK_ZONE_ALIGN) { 351 return (size + align - 1) / align * align; 352} 353 354/// @cond 355 356template <typename T> 357T* zone::allocate() 358{ 359 void* x = allocate_align(sizeof(T)); 360 try { 361 m_finalizer_array.push(&zone::object_destruct<T>, x); 362 } catch (...) { 363 undo_allocate(sizeof(T)); 364 throw; 365 } 366 try { 367 return new (x) T(); 368 } catch (...) { 369 --m_finalizer_array.m_tail; 370 undo_allocate(sizeof(T)); 371 throw; 372 } 373} 374 375template <typename T, typename A1> 376T* zone::allocate(A1 a1) 377{ 378 void* x = allocate_align(sizeof(T)); 379 try { 380 m_finalizer_array.push(&zone::object_destruct<T>, x); 381 } catch (...) { 382 undo_allocate(sizeof(T)); 383 throw; 384 } 385 try { 386 return new (x) T(a1); 387 } catch (...) { 388 --m_finalizer_array.m_tail; 389 undo_allocate(sizeof(T)); 390 throw; 391 } 392} 393 394template <typename T, typename A1, typename A2> 395T* zone::allocate(A1 a1, A2 a2) 396{ 397 void* x = allocate_align(sizeof(T)); 398 try { 399 m_finalizer_array.push(&zone::object_destruct<T>, x); 400 } catch (...) { 401 undo_allocate(sizeof(T)); 402 throw; 403 } 404 try { 405 return new (x) T(a1, a2); 406 } catch (...) { 407 --m_finalizer_array.m_tail; 408 undo_allocate(sizeof(T)); 409 throw; 410 } 411} 412 413template <typename T, typename A1, typename A2, typename A3> 414T* zone::allocate(A1 a1, A2 a2, A3 a3) 415{ 416 void* x = allocate_align(sizeof(T)); 417 try { 418 m_finalizer_array.push(&zone::object_destruct<T>, x); 419 } catch (...) { 420 undo_allocate(sizeof(T)); 421 throw; 422 } 423 try { 424 return new (x) T(a1, a2, a3); 425 } catch (...) { 426 --m_finalizer_array.m_tail; 427 undo_allocate(sizeof(T)); 428 throw; 429 } 430} 431 432template <typename T, typename A1, typename A2, typename A3, typename A4> 433T* zone::allocate(A1 a1, A2 a2, A3 a3, A4 a4) 434{ 435 void* x = allocate_align(sizeof(T)); 436 try { 437 m_finalizer_array.push(&zone::object_destruct<T>, x); 438 } catch (...) { 439 undo_allocate(sizeof(T)); 440 throw; 441 } 442 try { 443 return new (x) T(a1, a2, a3, a4); 444 } catch (...) { 445 --m_finalizer_array.m_tail; 446 undo_allocate(sizeof(T)); 447 throw; 448 } 449} 450 451template <typename T, typename A1, typename A2, typename A3, typename A4, typename A5> 452T* zone::allocate(A1 a1, A2 a2, A3 a3, A4 a4, A5 a5) 453{ 454 void* x = allocate_align(sizeof(T)); 455 try { 456 m_finalizer_array.push(&zone::object_destruct<T>, x); 457 } catch (...) { 458 undo_allocate(sizeof(T)); 459 throw; 460 } 461 try { 462 return new (x) T(a1, a2, a3, a4, a5); 463 } catch (...) { 464 --m_finalizer_array.m_tail; 465 undo_allocate(sizeof(T)); 466 throw; 467 } 468} 469 470template <typename T, typename A1, typename A2, typename A3, typename A4, typename A5, typename A6> 471T* zone::allocate(A1 a1, A2 a2, A3 a3, A4 a4, A5 a5, A6 a6) 472{ 473 void* x = allocate_align(sizeof(T)); 474 try { 475 m_finalizer_array.push(&zone::object_destruct<T>, x); 476 } catch (...) { 477 undo_allocate(sizeof(T)); 478 throw; 479 } 480 try { 481 return new (x) T(a1, a2, a3, a4, a5, a6); 482 } catch (...) { 483 --m_finalizer_array.m_tail; 484 undo_allocate(sizeof(T)); 485 throw; 486 } 487} 488 489template <typename T, typename A1, typename A2, typename A3, typename A4, typename A5, typename A6, typename A7> 490T* zone::allocate(A1 a1, A2 a2, A3 a3, A4 a4, A5 a5, A6 a6, A7 a7) 491{ 492 void* x = allocate_align(sizeof(T)); 493 try { 494 m_finalizer_array.push(&zone::object_destruct<T>, x); 495 } catch (...) { 496 undo_allocate(sizeof(T)); 497 throw; 498 } 499 try { 500 return new (x) T(a1, a2, a3, a4, a5, a6, a7); 501 } catch (...) { 502 --m_finalizer_array.m_tail; 503 undo_allocate(sizeof(T)); 504 throw; 505 } 506} 507 508template <typename T, typename A1, typename A2, typename A3, typename A4, typename A5, typename A6, typename A7, typename A8> 509T* zone::allocate(A1 a1, A2 a2, A3 a3, A4 a4, A5 a5, A6 a6, A7 a7, A8 a8) 510{ 511 void* x = allocate_align(sizeof(T)); 512 try { 513 m_finalizer_array.push(&zone::object_destruct<T>, x); 514 } catch (...) { 515 undo_allocate(sizeof(T)); 516 throw; 517 } 518 try { 519 return new (x) T(a1, a2, a3, a4, a5, a6, a7, a8); 520 } catch (...) { 521 --m_finalizer_array.m_tail; 522 undo_allocate(sizeof(T)); 523 throw; 524 } 525} 526 527template <typename T, typename A1, typename A2, typename A3, typename A4, typename A5, typename A6, typename A7, typename A8, typename A9> 528T* zone::allocate(A1 a1, A2 a2, A3 a3, A4 a4, A5 a5, A6 a6, A7 a7, A8 a8, A9 a9) 529{ 530 void* x = allocate_align(sizeof(T)); 531 try { 532 m_finalizer_array.push(&zone::object_destruct<T>, x); 533 } catch (...) { 534 undo_allocate(sizeof(T)); 535 throw; 536 } 537 try { 538 return new (x) T(a1, a2, a3, a4, a5, a6, a7, a8, a9); 539 } catch (...) { 540 --m_finalizer_array.m_tail; 541 undo_allocate(sizeof(T)); 542 throw; 543 } 544} 545 546template <typename T, typename A1, typename A2, typename A3, typename A4, typename A5, typename A6, typename A7, typename A8, typename A9, typename A10> 547T* zone::allocate(A1 a1, A2 a2, A3 a3, A4 a4, A5 a5, A6 a6, A7 a7, A8 a8, A9 a9, A10 a10) 548{ 549 void* x = allocate_align(sizeof(T)); 550 try { 551 m_finalizer_array.push(&zone::object_destruct<T>, x); 552 } catch (...) { 553 undo_allocate(sizeof(T)); 554 throw; 555 } 556 try { 557 return new (x) T(a1, a2, a3, a4, a5, a6, a7, a8, a9, a10); 558 } catch (...) { 559 --m_finalizer_array.m_tail; 560 undo_allocate(sizeof(T)); 561 throw; 562 } 563} 564 565template <typename T, typename A1, typename A2, typename A3, typename A4, typename A5, typename A6, typename A7, typename A8, typename A9, typename A10, typename A11> 566T* zone::allocate(A1 a1, A2 a2, A3 a3, A4 a4, A5 a5, A6 a6, A7 a7, A8 a8, A9 a9, A10 a10, A11 a11) 567{ 568 void* x = allocate_align(sizeof(T)); 569 try { 570 m_finalizer_array.push(&zone::object_destruct<T>, x); 571 } catch (...) { 572 undo_allocate(sizeof(T)); 573 throw; 574 } 575 try { 576 return new (x) T(a1, a2, a3, a4, a5, a6, a7, a8, a9, a10, a11); 577 } catch (...) { 578 --m_finalizer_array.m_tail; 579 undo_allocate(sizeof(T)); 580 throw; 581 } 582} 583 584template <typename T, typename A1, typename A2, typename A3, typename A4, typename A5, typename A6, typename A7, typename A8, typename A9, typename A10, typename A11, typename A12> 585T* zone::allocate(A1 a1, A2 a2, A3 a3, A4 a4, A5 a5, A6 a6, A7 a7, A8 a8, A9 a9, A10 a10, A11 a11, A12 a12) 586{ 587 void* x = allocate_align(sizeof(T)); 588 try { 589 m_finalizer_array.push(&zone::object_destruct<T>, x); 590 } catch (...) { 591 undo_allocate(sizeof(T)); 592 throw; 593 } 594 try { 595 return new (x) T(a1, a2, a3, a4, a5, a6, a7, a8, a9, a10, a11, a12); 596 } catch (...) { 597 --m_finalizer_array.m_tail; 598 undo_allocate(sizeof(T)); 599 throw; 600 } 601} 602 603template <typename T, typename A1, typename A2, typename A3, typename A4, typename A5, typename A6, typename A7, typename A8, typename A9, typename A10, typename A11, typename A12, typename A13> 604T* zone::allocate(A1 a1, A2 a2, A3 a3, A4 a4, A5 a5, A6 a6, A7 a7, A8 a8, A9 a9, A10 a10, A11 a11, A12 a12, A13 a13) 605{ 606 void* x = allocate_align(sizeof(T)); 607 try { 608 m_finalizer_array.push(&zone::object_destruct<T>, x); 609 } catch (...) { 610 undo_allocate(sizeof(T)); 611 throw; 612 } 613 try { 614 return new (x) T(a1, a2, a3, a4, a5, a6, a7, a8, a9, a10, a11, a12, a13); 615 } catch (...) { 616 --m_finalizer_array.m_tail; 617 undo_allocate(sizeof(T)); 618 throw; 619 } 620} 621 622template <typename T, typename A1, typename A2, typename A3, typename A4, typename A5, typename A6, typename A7, typename A8, typename A9, typename A10, typename A11, typename A12, typename A13, typename A14> 623T* zone::allocate(A1 a1, A2 a2, A3 a3, A4 a4, A5 a5, A6 a6, A7 a7, A8 a8, A9 a9, A10 a10, A11 a11, A12 a12, A13 a13, A14 a14) 624{ 625 void* x = allocate_align(sizeof(T)); 626 try { 627 m_finalizer_array.push(&zone::object_destruct<T>, x); 628 } catch (...) { 629 undo_allocate(sizeof(T)); 630 throw; 631 } 632 try { 633 return new (x) T(a1, a2, a3, a4, a5, a6, a7, a8, a9, a10, a11, a12, a13, a14); 634 } catch (...) { 635 --m_finalizer_array.m_tail; 636 undo_allocate(sizeof(T)); 637 throw; 638 } 639} 640 641template <typename T, typename A1, typename A2, typename A3, typename A4, typename A5, typename A6, typename A7, typename A8, typename A9, typename A10, typename A11, typename A12, typename A13, typename A14, typename A15> 642T* zone::allocate(A1 a1, A2 a2, A3 a3, A4 a4, A5 a5, A6 a6, A7 a7, A8 a8, A9 a9, A10 a10, A11 a11, A12 a12, A13 a13, A14 a14, A15 a15) 643{ 644 void* x = allocate_align(sizeof(T)); 645 try { 646 m_finalizer_array.push(&zone::object_destruct<T>, x); 647 } catch (...) { 648 undo_allocate(sizeof(T)); 649 throw; 650 } 651 try { 652 return new (x) T(a1, a2, a3, a4, a5, a6, a7, a8, a9, a10, a11, a12, a13, a14, a15); 653 } catch (...) { 654 --m_finalizer_array.m_tail; 655 undo_allocate(sizeof(T)); 656 throw; 657 } 658} 659 660/// @endcond 661 662/// @cond 663} // MSGPACK_API_VERSION_NAMESPACE(v1) 664/// @endcond 665 666} // namespace msgpack 667 668#endif // MSGPACK_CPP03_ZONE_HPP 669