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