cpp03_zone.hpp.erb 8.2 KB

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