vrefbuffer.hpp 7.5 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314
  1. //
  2. // MessagePack for C++ zero-copy buffer implementation
  3. //
  4. // Copyright (C) 2008-2017 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_VREFBUFFER_HPP
  11. #define MSGPACK_V1_VREFBUFFER_HPP
  12. #include "msgpack/v1/vrefbuffer_decl.hpp"
  13. #include "msgpack/assert.hpp"
  14. #include <stdexcept>
  15. #include <algorithm>
  16. #if defined(_MSC_VER)
  17. // avoiding confliction std::max, std::min, and macro in windows.h
  18. #ifndef NOMINMAX
  19. #define NOMINMAX
  20. #endif
  21. #endif // defined(_MSC_VER)
  22. #if defined(unix) || defined(__unix) || defined(__APPLE__) || defined(__OpenBSD__)
  23. #include <sys/uio.h>
  24. namespace msgpack {
  25. typedef ::iovec iovec;
  26. } // namespace msgpack
  27. #else
  28. namespace msgpack {
  29. struct iovec {
  30. void *iov_base;
  31. size_t iov_len;
  32. };
  33. } // namespace msgpack
  34. #endif
  35. namespace msgpack {
  36. /// @cond
  37. MSGPACK_API_VERSION_NAMESPACE(v1) {
  38. /// @endcond
  39. namespace detail {
  40. // int64, uint64, double
  41. std::size_t const packer_max_buffer_size = 9;
  42. } // detail
  43. class vrefbuffer {
  44. private:
  45. struct chunk {
  46. chunk* next;
  47. };
  48. struct inner_buffer {
  49. size_t free;
  50. char* ptr;
  51. chunk* head;
  52. };
  53. public:
  54. vrefbuffer(size_t ref_size = MSGPACK_VREFBUFFER_REF_SIZE,
  55. size_t chunk_size = MSGPACK_VREFBUFFER_CHUNK_SIZE)
  56. :m_ref_size(std::max(ref_size, detail::packer_max_buffer_size + 1)),
  57. m_chunk_size(chunk_size)
  58. {
  59. if((sizeof(chunk) + chunk_size) < chunk_size) {
  60. throw std::bad_alloc();
  61. }
  62. size_t nfirst = (sizeof(iovec) < 72/2) ?
  63. 72 / sizeof(iovec) : 8;
  64. iovec* array = static_cast<iovec*>(::malloc(
  65. sizeof(iovec) * nfirst));
  66. if(!array) {
  67. throw std::bad_alloc();
  68. }
  69. m_tail = array;
  70. m_end = array + nfirst;
  71. m_array = array;
  72. chunk* c = static_cast<chunk*>(::malloc(sizeof(chunk) + chunk_size));
  73. if(!c) {
  74. ::free(array);
  75. throw std::bad_alloc();
  76. }
  77. inner_buffer* const ib = &m_inner_buffer;
  78. ib->free = chunk_size;
  79. ib->ptr = reinterpret_cast<char*>(c) + sizeof(chunk);
  80. ib->head = c;
  81. c->next = MSGPACK_NULLPTR;
  82. }
  83. ~vrefbuffer()
  84. {
  85. chunk* c = m_inner_buffer.head;
  86. while(true) {
  87. chunk* n = c->next;
  88. ::free(c);
  89. if(n != NULL) {
  90. c = n;
  91. } else {
  92. break;
  93. }
  94. }
  95. ::free(m_array);
  96. }
  97. public:
  98. void write(const char* buf, size_t len)
  99. {
  100. MSGPACK_ASSERT(buf || len == 0);
  101. if (!buf) return;
  102. if(len < m_ref_size) {
  103. append_copy(buf, len);
  104. } else {
  105. append_ref(buf, len);
  106. }
  107. }
  108. void append_ref(const char* buf, size_t len)
  109. {
  110. if(m_tail == m_end) {
  111. const size_t nused = static_cast<size_t>(m_tail - m_array);
  112. const size_t nnext = nused * 2;
  113. iovec* nvec = static_cast<iovec*>(::realloc(
  114. m_array, sizeof(iovec)*nnext));
  115. if(!nvec) {
  116. throw std::bad_alloc();
  117. }
  118. m_array = nvec;
  119. m_end = nvec + nnext;
  120. m_tail = nvec + nused;
  121. }
  122. m_tail->iov_base = const_cast<char*>(buf);
  123. m_tail->iov_len = len;
  124. ++m_tail;
  125. }
  126. void append_copy(const char* buf, size_t len)
  127. {
  128. inner_buffer* const ib = &m_inner_buffer;
  129. if(ib->free < len) {
  130. size_t sz = m_chunk_size;
  131. if(sz < len) {
  132. sz = len;
  133. }
  134. if(sizeof(chunk) + sz < sz){
  135. throw std::bad_alloc();
  136. }
  137. chunk* c = static_cast<chunk*>(::malloc(sizeof(chunk) + sz));
  138. if(!c) {
  139. throw std::bad_alloc();
  140. }
  141. c->next = ib->head;
  142. ib->head = c;
  143. ib->free = sz;
  144. ib->ptr = reinterpret_cast<char*>(c) + sizeof(chunk);
  145. }
  146. char* m = ib->ptr;
  147. std::memcpy(m, buf, len);
  148. ib->free -= len;
  149. ib->ptr += len;
  150. if(m_tail != m_array && m ==
  151. static_cast<const char*>(
  152. const_cast<const void *>((m_tail - 1)->iov_base)
  153. ) + (m_tail - 1)->iov_len) {
  154. (m_tail - 1)->iov_len += len;
  155. return;
  156. } else {
  157. append_ref( m, len);
  158. }
  159. }
  160. const iovec* vector() const
  161. {
  162. return m_array;
  163. }
  164. size_t vector_size() const
  165. {
  166. return static_cast<size_t>(m_tail - m_array);
  167. }
  168. void migrate(vrefbuffer* to)
  169. {
  170. size_t sz = m_chunk_size;
  171. if((sizeof(chunk) + sz) < sz){
  172. throw std::bad_alloc();
  173. }
  174. chunk* empty = static_cast<chunk*>(::malloc(sizeof(chunk) + sz));
  175. if(!empty) {
  176. throw std::bad_alloc();
  177. }
  178. empty->next = MSGPACK_NULLPTR;
  179. const size_t nused = static_cast<size_t>(m_tail - m_array);
  180. if(to->m_tail + nused < m_end) {
  181. const size_t tosize = static_cast<size_t>(to->m_tail - to->m_array);
  182. const size_t reqsize = nused + tosize;
  183. size_t nnext = static_cast<size_t>(to->m_end - to->m_array) * 2;
  184. while(nnext < reqsize) {
  185. size_t tmp_nnext = nnext * 2;
  186. if (tmp_nnext <= nnext) {
  187. nnext = reqsize;
  188. break;
  189. }
  190. nnext = tmp_nnext;
  191. }
  192. iovec* nvec = static_cast<iovec*>(::realloc(
  193. to->m_array, sizeof(iovec)*nnext));
  194. if(!nvec) {
  195. ::free(empty);
  196. throw std::bad_alloc();
  197. }
  198. to->m_array = nvec;
  199. to->m_end = nvec + nnext;
  200. to->m_tail = nvec + tosize;
  201. }
  202. std::memcpy(to->m_tail, m_array, sizeof(iovec)*nused);
  203. to->m_tail += nused;
  204. m_tail = m_array;
  205. inner_buffer* const ib = &m_inner_buffer;
  206. inner_buffer* const toib = &to->m_inner_buffer;
  207. chunk* last = ib->head;
  208. while(last->next) {
  209. last = last->next;
  210. }
  211. last->next = toib->head;
  212. toib->head = ib->head;
  213. if(toib->free < ib->free) {
  214. toib->free = ib->free;
  215. toib->ptr = ib->ptr;
  216. }
  217. ib->head = empty;
  218. ib->free = sz;
  219. ib->ptr = reinterpret_cast<char*>(empty) + sizeof(chunk);
  220. }
  221. void clear()
  222. {
  223. chunk* c = m_inner_buffer.head->next;
  224. chunk* n;
  225. while(c) {
  226. n = c->next;
  227. ::free(c);
  228. c = n;
  229. }
  230. inner_buffer* const ib = &m_inner_buffer;
  231. c = ib->head;
  232. c->next = MSGPACK_NULLPTR;
  233. ib->free = m_chunk_size;
  234. ib->ptr = reinterpret_cast<char*>(c) + sizeof(chunk);
  235. m_tail = m_array;
  236. }
  237. #if defined(MSGPACK_USE_CPP03)
  238. private:
  239. vrefbuffer(const vrefbuffer&);
  240. vrefbuffer& operator=(const vrefbuffer&);
  241. #else // defined(MSGPACK_USE_CPP03)
  242. vrefbuffer(const vrefbuffer&) = delete;
  243. vrefbuffer& operator=(const vrefbuffer&) = delete;
  244. #endif // defined(MSGPACK_USE_CPP03)
  245. private:
  246. iovec* m_tail;
  247. iovec* m_end;
  248. iovec* m_array;
  249. size_t m_ref_size;
  250. size_t m_chunk_size;
  251. inner_buffer m_inner_buffer;
  252. };
  253. /// @cond
  254. } // MSGPACK_API_VERSION_NAMESPACE(v1)
  255. /// @endcond
  256. } // namespace msgpack
  257. #endif // MSGPACK_V1_VREFBUFFER_HPP