Coverage Report

Created: 2026-01-09 06:11

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