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