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