1// Licensed to the Apache Software Foundation (ASF) under one
2// or more contributor license agreements. See the NOTICE file
3// distributed with this work for additional information
4// regarding copyright ownership. The ASF licenses this file
5// to you under the Apache License, Version 2.0 (the
6// "License"); you may not use this file except in compliance
7// with the License. You may obtain a copy of the License at
8//
9// http://www.apache.org/licenses/LICENSE-2.0
10//
11// Unless required by applicable law or agreed to in writing,
12// software distributed under the License is distributed on an
13// "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
14// KIND, either express or implied. See the License for the
15// specific language governing permissions and limitations
16// under the License.
17
18// iobuf - A non-continuous zero-copied buffer
19
20// Date: Thu Nov 22 13:57:56 CST 2012
21
22// Inlined implementations of some methods defined in iobuf.h
23
24#ifndef BUTIL_IOBUF_INL_H
25#define BUTIL_IOBUF_INL_H
26
27void* fast_memcpy(void *__restrict dest, const void *__restrict src, size_t n);
28
29namespace butil {
30
31inline ssize_t IOBuf::cut_into_file_descriptor(int fd, size_t size_hint) {
32 return pcut_into_file_descriptor(fd, -1, size_hint);
33}
34
35inline ssize_t IOBuf::cut_multiple_into_file_descriptor(
36 int fd, IOBuf* const* pieces, size_t count) {
37 return pcut_multiple_into_file_descriptor(fd, -1, pieces, count);
38}
39
40inline ssize_t IOPortal::append_from_file_descriptor(int fd, size_t max_count) {
41 return pappend_from_file_descriptor(fd, -1, max_count);
42}
43
44inline void IOPortal::return_cached_blocks() {
45 if (_block) {
46 return_cached_blocks_impl(_block);
47 _block = NULL;
48 }
49}
50
51inline void reset_block_ref(IOBuf::BlockRef& ref) {
52 ref.offset = 0;
53 ref.length = 0;
54 ref.block = NULL;
55}
56
57inline IOBuf::IOBuf() {
58 reset_block_ref(_sv.refs[0]);
59 reset_block_ref(_sv.refs[1]);
60}
61
62inline IOBuf::IOBuf(const Movable& rhs) {
63 _sv = rhs.value()._sv;
64 new (&rhs.value()) IOBuf;
65}
66
67inline void IOBuf::operator=(const Movable& rhs) {
68 clear();
69 _sv = rhs.value()._sv;
70 new (&rhs.value()) IOBuf;
71}
72
73inline void IOBuf::operator=(const char* s) {
74 clear();
75 append(s);
76}
77
78inline void IOBuf::operator=(const std::string& s) {
79 clear();
80 append(s);
81}
82
83inline void IOBuf::swap(IOBuf& other) {
84 const SmallView tmp = other._sv;
85 other._sv = _sv;
86 _sv = tmp;
87}
88
89inline int IOBuf::cut_until(IOBuf* out, char const* delim) {
90 if (*delim) {
91 if (!*(delim+1)) {
92 return _cut_by_char(out, *delim);
93 } else {
94 return _cut_by_delim(out, delim, strlen(delim));
95 }
96 }
97 return -1;
98}
99
100inline int IOBuf::cut_until(IOBuf* out, const std::string& delim) {
101 if (delim.length() == 1UL) {
102 return _cut_by_char(out, delim[0]);
103 } else if (delim.length() > 1UL) {
104 return _cut_by_delim(out, delim.data(), delim.length());
105 } else {
106 return -1;
107 }
108}
109
110inline int IOBuf::append(const std::string& s) {
111 return append(s.data(), s.length());
112}
113
114inline std::string IOBuf::to_string() const {
115 std::string s;
116 copy_to(&s);
117 return s;
118}
119
120inline bool IOBuf::empty() const {
121 return _small() ? !_sv.refs[0].block : !_bv.nbytes;
122}
123
124inline size_t IOBuf::length() const {
125 return _small() ?
126 (_sv.refs[0].length + _sv.refs[1].length) : _bv.nbytes;
127}
128
129inline bool IOBuf::_small() const {
130 return _bv.magic >= 0;
131}
132
133inline size_t IOBuf::_ref_num() const {
134 return _small()
135 ? (!!_sv.refs[0].block + !!_sv.refs[1].block) : _bv.nref;
136}
137
138inline IOBuf::BlockRef& IOBuf::_front_ref() {
139 return _small() ? _sv.refs[0] : _bv.refs[_bv.start];
140}
141
142inline const IOBuf::BlockRef& IOBuf::_front_ref() const {
143 return _small() ? _sv.refs[0] : _bv.refs[_bv.start];
144}
145
146inline IOBuf::BlockRef& IOBuf::_back_ref() {
147 return _small() ? _sv.refs[!!_sv.refs[1].block] : _bv.ref_at(_bv.nref - 1);
148}
149
150inline const IOBuf::BlockRef& IOBuf::_back_ref() const {
151 return _small() ? _sv.refs[!!_sv.refs[1].block] : _bv.ref_at(_bv.nref - 1);
152}
153
154inline IOBuf::BlockRef& IOBuf::_ref_at(size_t i) {
155 return _small() ? _sv.refs[i] : _bv.ref_at(i);
156}
157
158inline const IOBuf::BlockRef& IOBuf::_ref_at(size_t i) const {
159 return _small() ? _sv.refs[i] : _bv.ref_at(i);
160}
161
162inline const IOBuf::BlockRef* IOBuf::_pref_at(size_t i) const {
163 if (_small()) {
164 return i < (size_t)(!!_sv.refs[0].block + !!_sv.refs[1].block) ? &_sv.refs[i] : NULL;
165 } else {
166 return i < _bv.nref ? &_bv.ref_at(i) : NULL;
167 }
168}
169
170inline bool operator==(const IOBuf::BlockRef& r1, const IOBuf::BlockRef& r2) {
171 return r1.offset == r2.offset && r1.length == r2.length &&
172 r1.block == r2.block;
173}
174
175inline bool operator!=(const IOBuf::BlockRef& r1, const IOBuf::BlockRef& r2) {
176 return !(r1 == r2);
177}
178
179inline void IOBuf::_push_back_ref(const BlockRef& r) {
180 if (_small()) {
181 return _push_or_move_back_ref_to_smallview<false>(r);
182 } else {
183 return _push_or_move_back_ref_to_bigview<false>(r);
184 }
185}
186
187inline void IOBuf::_move_back_ref(const BlockRef& r) {
188 if (_small()) {
189 return _push_or_move_back_ref_to_smallview<true>(r);
190 } else {
191 return _push_or_move_back_ref_to_bigview<true>(r);
192 }
193}
194
195//////////////// IOBufCutter ////////////////
196inline size_t IOBufCutter::remaining_bytes() const {
197 if (_block) {
198 return (char*)_data_end - (char*)_data + _buf->size() - _buf->_front_ref().length;
199 } else {
200 return _buf->size();
201 }
202}
203
204inline bool IOBufCutter::cut1(void* c) {
205 if (_data == _data_end) {
206 if (!load_next_ref()) {
207 return false;
208 }
209 }
210 *(char*)c = *(const char*)_data;
211 _data = (char*)_data + 1;
212 return true;
213}
214
215inline const void* IOBufCutter::fetch1() {
216 if (_data == _data_end) {
217 if (!load_next_ref()) {
218 return NULL;
219 }
220 }
221 return _data;
222}
223
224inline size_t IOBufCutter::copy_to(void* out, size_t n) {
225 size_t size = (char*)_data_end - (char*)_data;
226 if (n <= size) {
227 memcpy(out, _data, n);
228 return n;
229 }
230 return slower_copy_to(out, n);
231}
232
233inline size_t IOBufCutter::pop_front(size_t n) {
234 const size_t saved_n = n;
235 do {
236 const size_t size = (char*)_data_end - (char*)_data;
237 if (n <= size) {
238 _data = (char*)_data + n;
239 return saved_n;
240 }
241 if (size != 0) {
242 n -= size;
243 }
244 if (!load_next_ref()) {
245 return saved_n;
246 }
247 } while (true);
248}
249
250inline size_t IOBufCutter::cutn(std::string* out, size_t n) {
251 if (n == 0) {
252 return 0;
253 }
254 const size_t len = remaining_bytes();
255 if (n > len) {
256 n = len;
257 }
258 const size_t old_size = out->size();
259 out->resize(out->size() + n);
260 return cutn(&(*out)[old_size], n);
261}
262
263/////////////// IOBufAppender /////////////////
264inline int IOBufAppender::append(const void* src, size_t n) {
265 do {
266 const size_t size = (char*)_data_end - (char*)_data;
267 if (n <= size) {
268 memcpy(_data, src, n);
269 _data = (char*)_data + n;
270 return 0;
271 }
272 if (size != 0) {
273 memcpy(_data, src, size);
274 src = (const char*)src + size;
275 n -= size;
276 }
277 if (add_block() != 0) {
278 return -1;
279 }
280 } while (true);
281}
282
283inline int IOBufAppender::append(const StringPiece& str) {
284 return append(str.data(), str.size());
285}
286
287inline int IOBufAppender::append_decimal(long d) {
288 char buf[24]; // enough for decimal 64-bit integers
289 size_t n = sizeof(buf);
290 bool negative = false;
291 if (d < 0) {
292 negative = true;
293 d = -d;
294 }
295 do {
296 const long q = d / 10;
297 buf[--n] = d - q * 10 + '0';
298 d = q;
299 } while (d);
300 if (negative) {
301 buf[--n] = '-';
302 }
303 return append(buf + n, sizeof(buf) - n);
304}
305
306inline int IOBufAppender::push_back(char c) {
307 if (_data == _data_end) {
308 if (add_block() != 0) {
309 return -1;
310 }
311 }
312 char* const p = (char*)_data;
313 *p = c;
314 _data = p + 1;
315 return 0;
316}
317
318inline int IOBufAppender::add_block() {
319 int size = 0;
320 if (_zc_stream.Next(&_data, &size)) {
321 _data_end = (char*)_data + size;
322 return 0;
323 }
324 _data = NULL;
325 _data_end = NULL;
326 return -1;
327}
328
329inline void IOBufAppender::shrink() {
330 const size_t size = (char*)_data_end - (char*)_data;
331 if (size != 0) {
332 _zc_stream.BackUp(size);
333 _data = NULL;
334 _data_end = NULL;
335 }
336}
337
338inline IOBufBytesIterator::IOBufBytesIterator(const butil::IOBuf& buf)
339 : _block_begin(NULL), _block_end(NULL), _block_count(0),
340 _bytes_left(buf.length()), _buf(&buf) {
341 try_next_block();
342}
343
344inline IOBufBytesIterator::IOBufBytesIterator(const IOBufBytesIterator& it)
345 : _block_begin(it._block_begin)
346 , _block_end(it._block_end)
347 , _block_count(it._block_count)
348 , _bytes_left(it._bytes_left)
349 , _buf(it._buf) {
350}
351
352inline IOBufBytesIterator::IOBufBytesIterator(
353 const IOBufBytesIterator& it, size_t bytes_left)
354 : _block_begin(it._block_begin)
355 , _block_end(it._block_end)
356 , _block_count(it._block_count)
357 , _bytes_left(bytes_left)
358 , _buf(it._buf) {
359 //CHECK_LE(_bytes_left, it._bytes_left);
360 if (_block_end > _block_begin + _bytes_left) {
361 _block_end = _block_begin + _bytes_left;
362 }
363}
364
365inline void IOBufBytesIterator::try_next_block() {
366 if (_bytes_left == 0) {
367 return;
368 }
369 butil::StringPiece s = _buf->backing_block(_block_count++);
370 _block_begin = s.data();
371 _block_end = s.data() + std::min(s.size(), (size_t)_bytes_left);
372}
373
374inline void IOBufBytesIterator::operator++() {
375 ++_block_begin;
376 --_bytes_left;
377 if (_block_begin == _block_end) {
378 try_next_block();
379 }
380}
381
382inline size_t IOBufBytesIterator::copy_and_forward(void* buf, size_t n) {
383 size_t nc = 0;
384 while (nc < n && _bytes_left != 0) {
385 const size_t block_size = _block_end - _block_begin;
386 const size_t to_copy = std::min(block_size, n - nc);
387 memcpy((char*)buf + nc, _block_begin, to_copy);
388 _block_begin += to_copy;
389 _bytes_left -= to_copy;
390 nc += to_copy;
391 if (_block_begin == _block_end) {
392 try_next_block();
393 }
394 }
395 return nc;
396}
397
398inline size_t IOBufBytesIterator::copy_and_forward(std::string* s, size_t n) {
399 bool resized = false;
400 if (s->size() < n) {
401 resized = true;
402 s->resize(n);
403 }
404 const size_t nc = copy_and_forward(const_cast<char*>(s->data()), n);
405 if (nc < n && resized) {
406 s->resize(nc);
407 }
408 return nc;
409}
410
411inline size_t IOBufBytesIterator::forward(size_t n) {
412 size_t nc = 0;
413 while (nc < n && _bytes_left != 0) {
414 const size_t block_size = _block_end - _block_begin;
415 const size_t to_copy = std::min(block_size, n - nc);
416 _block_begin += to_copy;
417 _bytes_left -= to_copy;
418 nc += to_copy;
419 if (_block_begin == _block_end) {
420 try_next_block();
421 }
422 }
423 return nc;
424}
425
426} // namespace butil
427
428#endif // BUTIL_IOBUF_INL_H
429