vrefbuffer.hpp 7.2 KB

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