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#ifndef BUTIL_IOBUF_H
23#define BUTIL_IOBUF_H
24
25#include <sys/uio.h> // iovec
26#include <stdint.h> // uint32_t
27#include <string> // std::string
28#include <ostream> // std::ostream
29#include <google/protobuf/io/zero_copy_stream.h> // ZeroCopyInputStream
30#include "butil/strings/string_piece.h" // butil::StringPiece
31#include "butil/third_party/snappy/snappy-sinksource.h"
32#include "butil/zero_copy_stream_as_streambuf.h"
33#include "butil/macros.h"
34#include "butil/reader_writer.h"
35#include "butil/binary_printer.h"
36
37// For IOBuf::appendv(const const_iovec*, size_t). The only difference of this
38// struct from iovec (defined in sys/uio.h) is that iov_base is `const void*'
39// which is assignable by const pointers w/o any error.
40extern "C" {
41struct const_iovec {
42 const void* iov_base;
43 size_t iov_len;
44};
45#ifndef USE_MESALINK
46struct ssl_st;
47#else
48#define ssl_st MESALINK_SSL
49#endif
50}
51
52namespace butil {
53
54// IOBuf is a non-continuous buffer that can be cut and combined w/o copying
55// payload. It can be read from or flushed into file descriptors as well.
56// IOBuf is [thread-compatible]. Namely using different IOBuf in different
57// threads simultaneously is safe, and reading a static IOBuf from different
58// threads is safe as well.
59// IOBuf is [NOT thread-safe]. Modifying a same IOBuf from different threads
60// simultaneously is unsafe and likely to crash.
61class IOBuf {
62friend class IOBufAsZeroCopyInputStream;
63friend class IOBufAsZeroCopyOutputStream;
64friend class IOBufBytesIterator;
65friend class IOBufCutter;
66public:
67 static const size_t DEFAULT_BLOCK_SIZE = 8192;
68 static const size_t INITIAL_CAP = 32; // must be power of 2
69
70 struct Block;
71
72 // can't directly use `struct iovec' here because we also need to access the
73 // reference counter(nshared) in Block*
74 struct BlockRef {
75 // NOTICE: first bit of `offset' is shared with BigView::start
76 uint32_t offset;
77 uint32_t length;
78 Block* block;
79 };
80
81 // IOBuf is essentially a tiny queue of BlockRefs.
82 struct SmallView {
83 BlockRef refs[2];
84 };
85
86 struct BigView {
87 int32_t magic;
88 uint32_t start;
89 BlockRef* refs;
90 uint32_t nref;
91 uint32_t cap_mask;
92 size_t nbytes;
93
94 const BlockRef& ref_at(uint32_t i) const
95 { return refs[(start + i) & cap_mask]; }
96
97 BlockRef& ref_at(uint32_t i)
98 { return refs[(start + i) & cap_mask]; }
99
100 uint32_t capacity() const { return cap_mask + 1; }
101 };
102
103 struct Movable {
104 explicit Movable(IOBuf& v) : _v(&v) { }
105 IOBuf& value() const { return *_v; }
106 private:
107 IOBuf *_v;
108 };
109
110 typedef uint64_t Area;
111 static const Area INVALID_AREA = 0;
112
113 IOBuf();
114 IOBuf(const IOBuf&);
115 IOBuf(const Movable&);
116 ~IOBuf() { clear(); }
117 void operator=(const IOBuf&);
118 void operator=(const Movable&);
119 void operator=(const char*);
120 void operator=(const std::string&);
121
122 // Exchange internal fields with another IOBuf.
123 void swap(IOBuf&);
124
125 // Pop n bytes from front side
126 // If n == 0, nothing popped; if n >= length(), all bytes are popped
127 // Returns bytes popped.
128 size_t pop_front(size_t n);
129
130 // Pop n bytes from back side
131 // If n == 0, nothing popped; if n >= length(), all bytes are popped
132 // Returns bytes popped.
133 size_t pop_back(size_t n);
134
135 // Cut off n bytes from front side and APPEND to `out'
136 // If n == 0, nothing cut; if n >= length(), all bytes are cut
137 // Returns bytes cut.
138 size_t cutn(IOBuf* out, size_t n);
139 size_t cutn(void* out, size_t n);
140 size_t cutn(std::string* out, size_t n);
141 // Cut off 1 byte from the front side and set to *c
142 // Return true on cut, false otherwise.
143 bool cut1(void* c);
144
145 // Cut from front side until the characters matches `delim', append
146 // data before the matched characters to `out'.
147 // Returns 0 on success, -1 when there's no match (including empty `delim')
148 // or other errors.
149 int cut_until(IOBuf* out, char const* delim);
150
151 // std::string version, `delim' could be binary
152 int cut_until(IOBuf* out, const std::string& delim);
153
154 // Cut at most `size_hint' bytes(approximately) into the writer
155 // Returns bytes cut on success, -1 otherwise and errno is set.
156 ssize_t cut_into_writer(IWriter* writer, size_t size_hint = 1024*1024);
157
158 // Cut at most `size_hint' bytes(approximately) into the file descriptor
159 // Returns bytes cut on success, -1 otherwise and errno is set.
160 ssize_t cut_into_file_descriptor(int fd, size_t size_hint = 1024*1024);
161
162 // Cut at most `size_hint' bytes(approximately) into the file descriptor at
163 // a given offset(from the start of the file). The file offset is not changed.
164 // If `offset' is negative, does exactly what cut_into_file_descriptor does.
165 // Returns bytes cut on success, -1 otherwise and errno is set.
166 //
167 // NOTE: POSIX requires that a file open with the O_APPEND flag should
168 // not affect pwrite(). However, on Linux, if |fd| is open with O_APPEND,
169 // pwrite() appends data to the end of the file, regardless of the value
170 // of |offset|.
171 ssize_t pcut_into_file_descriptor(int fd, off_t offset /*NOTE*/,
172 size_t size_hint = 1024*1024);
173
174 // Cut into SSL channel `ssl'. Returns what `SSL_write' returns
175 // and the ssl error code will be filled into `ssl_error'
176 ssize_t cut_into_SSL_channel(struct ssl_st* ssl, int* ssl_error);
177
178 // Cut `count' number of `pieces' into the writer.
179 // Returns bytes cut on success, -1 otherwise and errno is set.
180 static ssize_t cut_multiple_into_writer(
181 IWriter* writer, IOBuf* const* pieces, size_t count);
182
183 // Cut `count' number of `pieces' into the file descriptor.
184 // Returns bytes cut on success, -1 otherwise and errno is set.
185 static ssize_t cut_multiple_into_file_descriptor(
186 int fd, IOBuf* const* pieces, size_t count);
187
188 // Cut `count' number of `pieces' into file descriptor `fd' at a given
189 // offset. The file offset is not changed.
190 // If `offset' is negative, does exactly what cut_multiple_into_file_descriptor
191 // does.
192 // Read NOTE of pcut_into_file_descriptor.
193 // Returns bytes cut on success, -1 otherwise and errno is set.
194 static ssize_t pcut_multiple_into_file_descriptor(
195 int fd, off_t offset, IOBuf* const* pieces, size_t count);
196
197 // Cut `count' number of `pieces' into SSL channel `ssl'.
198 // Returns bytes cut on success, -1 otherwise and errno is set.
199 static ssize_t cut_multiple_into_SSL_channel(
200 struct ssl_st* ssl, IOBuf* const* pieces, size_t count, int* ssl_error);
201
202 // Append another IOBuf to back side, payload of the IOBuf is shared
203 // rather than copied.
204 void append(const IOBuf& other);
205 // Append content of `other' to self and clear `other'.
206 void append(const Movable& other);
207
208 // ===================================================================
209 // Following push_back()/append() are just implemented for convenience
210 // and occasional usages, they're relatively slow because of the overhead
211 // of frequent BlockRef-management and reference-countings. If you get
212 // a lot of push_back/append to do, you should use IOBufAppender or
213 // IOBufBuilder instead, which reduce overhead by owning IOBuf::Block.
214 // ===================================================================
215
216 // Append a character to back side. (with copying)
217 // Returns 0 on success, -1 otherwise.
218 int push_back(char c);
219
220 // Append `data' with `count' bytes to back side. (with copying)
221 // Returns 0 on success(include count == 0), -1 otherwise.
222 int append(void const* data, size_t count);
223
224 // Append multiple data to back side in one call, faster than appending
225 // one by one separately.
226 // Returns 0 on success, -1 otherwise.
227 // Example:
228 // const_iovec vec[] = { { data1, len1 },
229 // { data2, len2 },
230 // { data3, len3 } };
231 // foo.appendv(vec, arraysize(vec));
232 int appendv(const const_iovec vec[], size_t n);
233 int appendv(const iovec* vec, size_t n)
234 { return appendv((const const_iovec*)vec, n); }
235
236 // Append a c-style string to back side. (with copying)
237 // Returns 0 on success, -1 otherwise.
238 // NOTE: Returns 0 when `s' is empty.
239 int append(char const* s);
240
241 // Append a std::string to back side. (with copying)
242 // Returns 0 on success, -1 otherwise.
243 // NOTE: Returns 0 when `s' is empty.
244 int append(const std::string& s);
245
246 // Append the user-data to back side WITHOUT copying.
247 // The user-data can be split and shared by smaller IOBufs and will be
248 // deleted using the deleter func when no IOBuf references it anymore.
249 int append_user_data(void* data, size_t size, void (*deleter)(void*));
250
251 // Resizes the buf to a length of n characters.
252 // If n is smaller than the current length, all bytes after n will be
253 // truncated.
254 // If n is greater than the current length, the buffer would be append with
255 // as many |c| as needed to reach a size of n. If c is not specified,
256 // null-character would be appended.
257 // Returns 0 on success, -1 otherwise.
258 int resize(size_t n) { return resize(n, '\0'); }
259 int resize(size_t n, char c);
260
261 // Reserve `n' uninitialized bytes at back-side.
262 // Returns an object representing the reserved area, INVALID_AREA on failure.
263 // NOTE: reserve(0) returns INVALID_AREA.
264 Area reserve(size_t n);
265
266 // [EXTREMELY UNSAFE]
267 // Copy `data' to the reserved `area'. `data' must be as long as the
268 // reserved size.
269 // Returns 0 on success, -1 otherwise.
270 // [Rules]
271 // 1. Make sure the IOBuf to be assigned was NOT cut/pop from front side
272 // after reserving, otherwise behavior of this function is undefined,
273 // even if it returns 0.
274 // 2. Make sure the IOBuf to be assigned was NOT copied to/from another
275 // IOBuf after reserving to prevent underlying blocks from being shared,
276 // otherwise the assignment affects all IOBuf sharing the blocks, which
277 // is probably not what we want.
278 int unsafe_assign(Area area, const void* data);
279
280 // Append min(n, length()) bytes starting from `pos' at front side to `buf'.
281 // The real payload is shared rather than copied.
282 // Returns bytes copied.
283 size_t append_to(IOBuf* buf, size_t n = (size_t)-1L, size_t pos = 0) const;
284
285 // Explicitly declare this overload as error to avoid copy_to(butil::IOBuf*)
286 // from being interpreted as copy_to(void*) by the compiler (which causes
287 // undefined behavior).
288 size_t copy_to(IOBuf* buf, size_t n = (size_t)-1L, size_t pos = 0) const
289 // the error attribute in not available in gcc 3.4
290#if defined(__GNUC__) && (__GNUC__ > 4 || (__GNUC__ == 4 && __GNUC_MINOR__ >= 8))
291 __attribute__ (( error("Call append_to(IOBuf*) instead") ))
292#endif
293 ;
294
295 // Copy min(n, length()) bytes starting from `pos' at front side into `buf'.
296 // Returns bytes copied.
297 size_t copy_to(void* buf, size_t n = (size_t)-1L, size_t pos = 0) const;
298
299 // NOTE: first parameter is not std::string& because user may passes
300 // a pointer of std::string by mistake, in which case, compiler would
301 // call the void* version which crashes definitely.
302 size_t copy_to(std::string* s, size_t n = (size_t)-1L, size_t pos = 0) const;
303 size_t append_to(std::string* s, size_t n = (size_t)-1L, size_t pos = 0) const;
304
305 // Copy min(n, length()) bytes staring from `pos' at front side into
306 // `cstr' and end it with '\0'.
307 // `cstr' must be as long as min(n, length())+1.
308 // Returns bytes copied (not including ending '\0')
309 size_t copy_to_cstr(char* cstr, size_t n = (size_t)-1L, size_t pos = 0) const;
310
311 // Convert all data in this buffer to a std::string.
312 std::string to_string() const;
313
314 // Get `n' front-side bytes with minimum copying. Length of `aux_buffer'
315 // must not be less than `n'.
316 // Returns:
317 // NULL - n is greater than length()
318 // aux_buffer - n bytes are copied into aux_buffer
319 // internal buffer - the bytes are stored continuously in the internal
320 // buffer, no copying is needed. This function does not
321 // add additional reference to the underlying block,
322 // so user should not change this IOBuf during using
323 // the internal buffer.
324 // If n == 0 and buffer is empty, return value is undefined.
325 const void* fetch(void* aux_buffer, size_t n) const;
326 // Fetch one character from front side.
327 // Returns pointer to the character, NULL on empty.
328 const void* fetch1() const;
329
330 // Remove all data
331 void clear();
332
333 // True iff there's no data
334 bool empty() const;
335
336 // Number of bytes
337 size_t length() const;
338 size_t size() const { return length(); }
339
340 // Get number of Blocks in use. block_memory = block_count * BLOCK_SIZE
341 static size_t block_count();
342 static size_t block_memory();
343 static size_t new_bigview_count();
344 static size_t block_count_hit_tls_threshold();
345
346 // Equal with a string/IOBuf or not.
347 bool equals(const butil::StringPiece&) const;
348 bool equals(const IOBuf& other) const;
349
350 // Get the number of backing blocks
351 size_t backing_block_num() const { return _ref_num(); }
352
353 // Get #i backing_block, an empty StringPiece is returned if no such block
354 StringPiece backing_block(size_t i) const;
355
356 // Make a movable version of self
357 Movable movable() { return Movable(*this); }
358
359protected:
360 int _cut_by_char(IOBuf* out, char);
361 int _cut_by_delim(IOBuf* out, char const* dbegin, size_t ndelim);
362
363 // Returns: true iff this should be viewed as SmallView
364 bool _small() const;
365
366 template <bool MOVE>
367 void _push_or_move_back_ref_to_smallview(const BlockRef&);
368 template <bool MOVE>
369 void _push_or_move_back_ref_to_bigview(const BlockRef&);
370
371 // Push a BlockRef to back side
372 // NOTICE: All fields of the ref must be initialized or assigned
373 // properly, or it will ruin this queue
374 void _push_back_ref(const BlockRef&);
375 // Move a BlockRef to back side. After calling this function, content of
376 // the BlockRef will be invalid and should never be used again.
377 void _move_back_ref(const BlockRef&);
378
379 // Pop a BlockRef from front side.
380 // Returns: 0 on success and -1 on empty.
381 int _pop_front_ref() { return _pop_or_moveout_front_ref<false>(); }
382
383 // Move a BlockRef out from front side.
384 // Returns: 0 on success and -1 on empty.
385 int _moveout_front_ref() { return _pop_or_moveout_front_ref<true>(); }
386
387 template <bool MOVEOUT>
388 int _pop_or_moveout_front_ref();
389
390 // Pop a BlockRef from back side.
391 // Returns: 0 on success and -1 on empty.
392 int _pop_back_ref();
393
394 // Number of refs in the queue
395 size_t _ref_num() const;
396
397 // Get reference to front/back BlockRef in the queue
398 // should not be called if queue is empty or the behavior is undefined
399 BlockRef& _front_ref();
400 const BlockRef& _front_ref() const;
401 BlockRef& _back_ref();
402 const BlockRef& _back_ref() const;
403
404 // Get reference to n-th BlockRef(counting from front) in the queue
405 // NOTICE: should not be called if queue is empty and the `n' must
406 // be inside [0, _ref_num()-1] or behavior is undefined
407 BlockRef& _ref_at(size_t i);
408 const BlockRef& _ref_at(size_t i) const;
409
410 // Get pointer to n-th BlockRef(counting from front)
411 // If i is out-of-range, NULL is returned.
412 const BlockRef* _pref_at(size_t i) const;
413
414private:
415 union {
416 BigView _bv;
417 SmallView _sv;
418 };
419};
420
421std::ostream& operator<<(std::ostream&, const IOBuf& buf);
422
423inline bool operator==(const butil::IOBuf& b, const butil::StringPiece& s)
424{ return b.equals(s); }
425inline bool operator==(const butil::StringPiece& s, const butil::IOBuf& b)
426{ return b.equals(s); }
427inline bool operator!=(const butil::IOBuf& b, const butil::StringPiece& s)
428{ return !b.equals(s); }
429inline bool operator!=(const butil::StringPiece& s, const butil::IOBuf& b)
430{ return !b.equals(s); }
431inline bool operator==(const butil::IOBuf& b1, const butil::IOBuf& b2)
432{ return b1.equals(b2); }
433inline bool operator!=(const butil::IOBuf& b1, const butil::IOBuf& b2)
434{ return !b1.equals(b2); }
435
436// IOPortal is a subclass of IOBuf that can read from file descriptors.
437// Typically used as the buffer to store bytes from sockets.
438class IOPortal : public IOBuf {
439public:
440 IOPortal() : _block(NULL) { }
441 IOPortal(const IOPortal& rhs) : IOBuf(rhs), _block(NULL) { }
442 ~IOPortal();
443 IOPortal& operator=(const IOPortal& rhs);
444
445 // Read at most `max_count' bytes from the reader and append to self.
446 ssize_t append_from_reader(IReader* reader, size_t max_count);
447
448 // Read at most `max_count' bytes from file descriptor `fd' and
449 // append to self.
450 ssize_t append_from_file_descriptor(int fd, size_t max_count);
451
452 // Read at most `max_count' bytes from file descriptor `fd' at a given
453 // offset and append to self. The file offset is not changed.
454 // If `offset' is negative, does exactly what append_from_file_descriptor does.
455 ssize_t pappend_from_file_descriptor(int fd, off_t offset, size_t max_count);
456
457 // Read as many bytes as possible from SSL channel `ssl', and stop until `max_count'.
458 // Returns total bytes read and the ssl error code will be filled into `ssl_error'
459 ssize_t append_from_SSL_channel(struct ssl_st* ssl, int* ssl_error,
460 size_t max_count = 1024*1024);
461
462 // Remove all data inside and return cached blocks.
463 void clear();
464
465 // Return cached blocks to TLS. This function should be called by users
466 // when this IOPortal are cut into intact messages and becomes empty, to
467 // let continuing code on IOBuf to reuse the blocks. Calling this function
468 // after each call to append_xxx does not make sense and may hurt
469 // performance. Read comments on field `_block' below.
470 void return_cached_blocks();
471
472private:
473 static void return_cached_blocks_impl(Block*);
474
475 // Cached blocks for appending. Notice that the blocks are released
476 // until return_cached_blocks()/clear()/dtor() are called, rather than
477 // released after each append_xxx(), which makes messages read from one
478 // file descriptor more likely to share blocks and have less BlockRefs.
479 Block* _block;
480};
481
482// Specialized utility to cut from IOBuf faster than using corresponding
483// methods in IOBuf.
484// Designed for efficiently parsing data from IOBuf.
485// The cut IOBuf can be appended during cutting.
486class IOBufCutter {
487public:
488 explicit IOBufCutter(butil::IOBuf* buf);
489 ~IOBufCutter();
490
491 // Cut off n bytes and APPEND to `out'
492 // Returns bytes cut.
493 size_t cutn(butil::IOBuf* out, size_t n);
494 size_t cutn(std::string* out, size_t n);
495 size_t cutn(void* out, size_t n);
496
497 // Cut off 1 byte from the front side and set to *c
498 // Return true on cut, false otherwise.
499 bool cut1(void* data);
500
501 // Copy n bytes into `data'
502 // Returns bytes copied.
503 size_t copy_to(void* data, size_t n);
504
505 // Fetch one character.
506 // Returns pointer to the character, NULL on empty
507 const void* fetch1();
508
509 // Pop n bytes from front side
510 // Returns bytes popped.
511 size_t pop_front(size_t n);
512
513 // Uncut bytes
514 size_t remaining_bytes() const;
515
516private:
517 size_t slower_copy_to(void* data, size_t n);
518 bool load_next_ref();
519
520private:
521 void* _data;
522 void* _data_end;
523 IOBuf::Block* _block;
524 IOBuf* _buf;
525};
526
527// Parse protobuf message from IOBuf. Notice that this wrapper does not change
528// source IOBuf, which also should not change during lifetime of the wrapper.
529// Even if a IOBufAsZeroCopyInputStream is created but parsed, the source
530// IOBuf should not be changed as well becuase constructor of the stream
531// saves internal information of the source IOBuf which is assumed to be
532// unchanged.
533// Example:
534// IOBufAsZeroCopyInputStream wrapper(the_iobuf_with_protobuf_format_data);
535// some_pb_message.ParseFromZeroCopyStream(&wrapper);
536class IOBufAsZeroCopyInputStream
537 : public google::protobuf::io::ZeroCopyInputStream {
538public:
539 explicit IOBufAsZeroCopyInputStream(const IOBuf&);
540
541 bool Next(const void** data, int* size) override;
542 void BackUp(int count) override;
543 bool Skip(int count) override;
544 google::protobuf::int64 ByteCount() const override;
545
546private:
547 int _ref_index;
548 int _add_offset;
549 google::protobuf::int64 _byte_count;
550 const IOBuf* _buf;
551};
552
553// Serialize protobuf message into IOBuf. This wrapper does not clear source
554// IOBuf before appending. You can change the source IOBuf when stream is
555// not used(append sth. to the IOBuf, serialize a protobuf message, append
556// sth. again, serialize messages again...). This is different from
557// IOBufAsZeroCopyInputStream which needs the source IOBuf to be unchanged.
558// Example:
559// IOBufAsZeroCopyOutputStream wrapper(&the_iobuf_to_put_data_in);
560// some_pb_message.SerializeToZeroCopyStream(&wrapper);
561//
562// NOTE: Blocks are by default shared among all the ZeroCopyOutputStream in one
563// thread. If there are many manuplated streams at one time, there may be many
564// fragments. You can create a ZeroCopyOutputStream which has its own block by
565// passing a positive `block_size' argument to avoid this problem.
566class IOBufAsZeroCopyOutputStream
567 : public google::protobuf::io::ZeroCopyOutputStream {
568public:
569 explicit IOBufAsZeroCopyOutputStream(IOBuf*);
570 IOBufAsZeroCopyOutputStream(IOBuf*, uint32_t block_size);
571 ~IOBufAsZeroCopyOutputStream();
572
573 bool Next(void** data, int* size) override;
574 void BackUp(int count) override; // `count' can be as long as ByteCount()
575 google::protobuf::int64 ByteCount() const override;
576
577private:
578 void _release_block();
579
580 IOBuf* _buf;
581 uint32_t _block_size;
582 IOBuf::Block *_cur_block;
583 google::protobuf::int64 _byte_count;
584};
585
586// Wrap IOBuf into input of snappy compresson.
587class IOBufAsSnappySource : public butil::snappy::Source {
588public:
589 explicit IOBufAsSnappySource(const butil::IOBuf& buf)
590 : _buf(&buf), _stream(buf) {}
591 virtual ~IOBufAsSnappySource() {}
592
593 // Return the number of bytes left to read from the source
594 size_t Available() const override;
595
596 // Peek at the next flat region of the source.
597 const char* Peek(size_t* len) override;
598
599 // Skip the next n bytes. Invalidates any buffer returned by
600 // a previous call to Peek().
601 void Skip(size_t n) override;
602
603private:
604 const butil::IOBuf* _buf;
605 butil::IOBufAsZeroCopyInputStream _stream;
606};
607
608// Wrap IOBuf into output of snappy compression.
609class IOBufAsSnappySink : public butil::snappy::Sink {
610public:
611 explicit IOBufAsSnappySink(butil::IOBuf& buf);
612 virtual ~IOBufAsSnappySink() {}
613
614 // Append "bytes[0,n-1]" to this.
615 void Append(const char* bytes, size_t n) override;
616
617 // Returns a writable buffer of the specified length for appending.
618 char* GetAppendBuffer(size_t length, char* scratch) override;
619
620private:
621 char* _cur_buf;
622 int _cur_len;
623 butil::IOBuf* _buf;
624 butil::IOBufAsZeroCopyOutputStream _buf_stream;
625};
626
627// A std::ostream to build IOBuf.
628// Example:
629// IOBufBuilder builder;
630// builder << "Anything that can be sent to std::ostream";
631// // You have several methods to fetch the IOBuf.
632// target_iobuf.append(builder.buf()); // builder.buf() was not changed
633// OR
634// builder.move_to(target_iobuf); // builder.buf() was clear()-ed.
635class IOBufBuilder :
636 // Have to use private inheritance to arrange initialization order.
637 virtual private IOBuf,
638 virtual private IOBufAsZeroCopyOutputStream,
639 virtual private ZeroCopyStreamAsStreamBuf,
640 public std::ostream {
641public:
642 explicit IOBufBuilder()
643 : IOBufAsZeroCopyOutputStream(this)
644 , ZeroCopyStreamAsStreamBuf(this)
645 , std::ostream(this)
646 { }
647
648 IOBuf& buf() {
649 this->shrink();
650 return *this;
651 }
652 void buf(const IOBuf& buf) {
653 *static_cast<IOBuf*>(this) = buf;
654 }
655 void move_to(IOBuf& target) {
656 target = Movable(buf());
657 }
658};
659
660// Create IOBuf by appending data *faster*
661class IOBufAppender {
662public:
663 IOBufAppender();
664
665 // Append `n' bytes starting from `data' to back side of the internal buffer
666 // Costs 2/3 time of IOBuf.append for short data/strings on Intel(R) Xeon(R)
667 // CPU E5-2620 @ 2.00GHz. Longer data/strings make differences smaller.
668 // Returns 0 on success, -1 otherwise.
669 int append(const void* data, size_t n);
670 int append(const butil::StringPiece& str);
671
672 // Format integer |d| to back side of the internal buffer, which is much faster
673 // than snprintf(..., "%lu", d).
674 // Returns 0 on success, -1 otherwise.
675 int append_decimal(long d);
676
677 // Push the character to back side of the internal buffer.
678 // Costs ~3ns while IOBuf.push_back costs ~13ns on Intel(R) Xeon(R) CPU
679 // E5-2620 @ 2.00GHz
680 // Returns 0 on success, -1 otherwise.
681 int push_back(char c);
682
683 IOBuf& buf() {
684 shrink();
685 return _buf;
686 }
687 void move_to(IOBuf& target) {
688 target = IOBuf::Movable(buf());
689 }
690
691private:
692 void shrink();
693 int add_block();
694
695 void* _data;
696 // Saving _data_end instead of _size avoid modifying _data and _size
697 // in each push_back() which is probably a hotspot.
698 void* _data_end;
699 IOBuf _buf;
700 IOBufAsZeroCopyOutputStream _zc_stream;
701};
702
703// Iterate bytes of a IOBuf.
704// During iteration, the iobuf should NOT be changed.
705class IOBufBytesIterator {
706public:
707 explicit IOBufBytesIterator(const butil::IOBuf& buf);
708 // Construct from another iterator.
709 IOBufBytesIterator(const IOBufBytesIterator& it);
710 IOBufBytesIterator(const IOBufBytesIterator& it, size_t bytes_left);
711 // Returning unsigned is safer than char which would be more error prone
712 // to bitwise operations. For example: in "uint32_t value = *it", value
713 // is (unexpected) 4294967168 when *it returns (char)128.
714 unsigned char operator*() const { return (unsigned char)*_block_begin; }
715 operator const void*() const { return (const void*)!!_bytes_left; }
716 void operator++();
717 void operator++(int) { return operator++(); }
718 // Copy at most n bytes into buf, forwarding this iterator.
719 // Returns bytes copied.
720 size_t copy_and_forward(void* buf, size_t n);
721 size_t copy_and_forward(std::string* s, size_t n);
722 // Just forward this iterator for at most n bytes.
723 size_t forward(size_t n);
724 // Append at most n bytes into buf, forwarding this iterator. Data are
725 // referenced rather than copied.
726 size_t append_and_forward(butil::IOBuf* buf, size_t n);
727 bool forward_one_block(const void** data, size_t* size);
728 size_t bytes_left() const { return _bytes_left; }
729private:
730 void try_next_block();
731 const char* _block_begin;
732 const char* _block_end;
733 uint32_t _block_count;
734 uint32_t _bytes_left;
735 const butil::IOBuf* _buf;
736};
737
738} // namespace butil
739
740// Specialize std::swap for IOBuf
741#if __cplusplus < 201103L // < C++11
742#include <algorithm> // std::swap until C++11
743#else
744#include <utility> // std::swap since C++11
745#endif // __cplusplus < 201103L
746namespace std {
747template <>
748inline void swap(butil::IOBuf& a, butil::IOBuf& b) {
749 return a.swap(b);
750}
751} // namespace std
752
753#include "butil/iobuf_inl.h"
754
755#endif // BUTIL_IOBUF_H
756