cpp11_zone.hpp 9.0 KB

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