cpp11_zone.hpp 9.2 KB

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