Coverage Report

Created: 2026-04-12 06:36

next uncovered line (L), next uncovered region (R), next uncovered branch (B)
/src/muduo/muduo/net/Buffer.h
Line
Count
Source
1
// Copyright 2010, Shuo Chen.  All rights reserved.
2
// http://code.google.com/p/muduo/
3
//
4
// Use of this source code is governed by a BSD-style license
5
// that can be found in the License file.
6
7
// Author: Shuo Chen (chenshuo at chenshuo dot com)
8
//
9
// This is a public header file, it must only include public header files.
10
11
#ifndef MUDUO_NET_BUFFER_H
12
#define MUDUO_NET_BUFFER_H
13
14
#include "muduo/base/copyable.h"
15
#include "muduo/base/StringPiece.h"
16
#include "muduo/base/Types.h"
17
18
#include "muduo/net/Endian.h"
19
20
#include <algorithm>
21
#include <vector>
22
23
#include <assert.h>
24
#include <string.h>
25
//#include <unistd.h>  // ssize_t
26
27
namespace muduo
28
{
29
namespace net
30
{
31
32
/// A buffer class modeled after org.jboss.netty.buffer.ChannelBuffer
33
///
34
/// @code
35
/// +-------------------+------------------+------------------+
36
/// | prependable bytes |  readable bytes  |  writable bytes  |
37
/// |                   |     (CONTENT)    |                  |
38
/// +-------------------+------------------+------------------+
39
/// |                   |                  |                  |
40
/// 0      <=      readerIndex   <=   writerIndex    <=     size
41
/// @endcode
42
class Buffer : public muduo::copyable
43
{
44
 public:
45
  static const size_t kCheapPrepend = 8;
46
  static const size_t kInitialSize = 1024;
47
48
  explicit Buffer(size_t initialSize = kInitialSize)
49
1.57k
    : buffer_(kCheapPrepend + initialSize),
50
1.57k
      readerIndex_(kCheapPrepend),
51
1.57k
      writerIndex_(kCheapPrepend)
52
1.57k
  {
53
1.57k
    assert(readableBytes() == 0);
54
1.57k
    assert(writableBytes() == initialSize);
55
1.57k
    assert(prependableBytes() == kCheapPrepend);
56
1.57k
  }
57
58
  // implicit copy-ctor, move-ctor, dtor and assignment are fine
59
  // NOTE: implicit move-ctor is added in g++ 4.6
60
61
  void swap(Buffer& rhs)
62
0
  {
63
0
    buffer_.swap(rhs.buffer_);
64
0
    std::swap(readerIndex_, rhs.readerIndex_);
65
0
    std::swap(writerIndex_, rhs.writerIndex_);
66
0
  }
67
68
  size_t readableBytes() const
69
22.8k
  { return writerIndex_ - readerIndex_; }
70
71
  size_t writableBytes() const
72
6.84k
  { return buffer_.size() - writerIndex_; }
73
74
  size_t prependableBytes() const
75
2.11k
  { return readerIndex_; }
76
77
  const char* peek() const
78
86.6k
  { return begin() + readerIndex_; }
79
80
  const char* findCRLF() const
81
22.8k
  {
82
    // FIXME: replace with memmem()?
83
22.8k
    const char* crlf = std::search(peek(), beginWrite(), kCRLF, kCRLF+2);
84
22.8k
    return crlf == beginWrite() ? NULL : crlf;
85
22.8k
  }
86
87
  const char* findCRLF(const char* start) const
88
0
  {
89
0
    assert(peek() <= start);
90
0
    assert(start <= beginWrite());
91
0
    // FIXME: replace with memmem()?
92
0
    const char* crlf = std::search(start, beginWrite(), kCRLF, kCRLF+2);
93
0
    return crlf == beginWrite() ? NULL : crlf;
94
0
  }
95
96
  const char* findEOL() const
97
0
  {
98
0
    const void* eol = memchr(peek(), '\n', readableBytes());
99
0
    return static_cast<const char*>(eol);
100
0
  }
101
102
  const char* findEOL(const char* start) const
103
0
  {
104
0
    assert(peek() <= start);
105
0
    assert(start <= beginWrite());
106
0
    const void* eol = memchr(start, '\n', beginWrite() - start);
107
0
    return static_cast<const char*>(eol);
108
0
  }
109
110
  // retrieve returns void, to prevent
111
  // string str(retrieve(readableBytes()), readableBytes());
112
  // the evaluation of two functions are unspecified
113
  void retrieve(size_t len)
114
21.2k
  {
115
21.2k
    assert(len <= readableBytes());
116
21.2k
    if (len < readableBytes())
117
20.6k
    {
118
20.6k
      readerIndex_ += len;
119
20.6k
    }
120
659
    else
121
659
    {
122
659
      retrieveAll();
123
659
    }
124
21.2k
  }
125
126
  void retrieveUntil(const char* end)
127
21.2k
  {
128
21.2k
    assert(peek() <= end);
129
21.2k
    assert(end <= beginWrite());
130
21.2k
    retrieve(end - peek());
131
21.2k
  }
132
133
  void retrieveInt64()
134
0
  {
135
0
    retrieve(sizeof(int64_t));
136
0
  }
137
138
  void retrieveInt32()
139
0
  {
140
0
    retrieve(sizeof(int32_t));
141
0
  }
142
143
  void retrieveInt16()
144
0
  {
145
0
    retrieve(sizeof(int16_t));
146
0
  }
147
148
  void retrieveInt8()
149
0
  {
150
0
    retrieve(sizeof(int8_t));
151
0
  }
152
153
  void retrieveAll()
154
659
  {
155
659
    readerIndex_ = kCheapPrepend;
156
659
    writerIndex_ = kCheapPrepend;
157
659
  }
158
159
  string retrieveAllAsString()
160
0
  {
161
0
    return retrieveAsString(readableBytes());
162
0
  }
163
164
  string retrieveAsString(size_t len)
165
0
  {
166
0
    assert(len <= readableBytes());
167
0
    string result(peek(), len);
168
0
    retrieve(len);
169
0
    return result;
170
0
  }
171
172
  StringPiece toStringPiece() const
173
0
  {
174
0
    return StringPiece(peek(), static_cast<int>(readableBytes()));
175
0
  }
176
177
  void append(const StringPiece& str)
178
1.57k
  {
179
1.57k
    append(str.data(), str.size());
180
1.57k
  }
181
182
  void append(const char* /*restrict*/ data, size_t len)
183
1.57k
  {
184
1.57k
    ensureWritableBytes(len);
185
1.57k
    std::copy(data, data+len, beginWrite());
186
1.57k
    hasWritten(len);
187
1.57k
  }
188
189
  void append(const void* /*restrict*/ data, size_t len)
190
0
  {
191
0
    append(static_cast<const char*>(data), len);
192
0
  }
193
194
  void ensureWritableBytes(size_t len)
195
1.57k
  {
196
1.57k
    if (writableBytes() < len)
197
532
    {
198
532
      makeSpace(len);
199
532
    }
200
1.57k
    assert(writableBytes() >= len);
201
1.57k
  }
202
203
  char* beginWrite()
204
1.57k
  { return begin() + writerIndex_; }
205
206
  const char* beginWrite() const
207
45.6k
  { return begin() + writerIndex_; }
208
209
  void hasWritten(size_t len)
210
1.57k
  {
211
1.57k
    assert(len <= writableBytes());
212
1.57k
    writerIndex_ += len;
213
1.57k
  }
214
215
  void unwrite(size_t len)
216
0
  {
217
0
    assert(len <= readableBytes());
218
0
    writerIndex_ -= len;
219
0
  }
220
221
  ///
222
  /// Append int64_t using network endian
223
  ///
224
  void appendInt64(int64_t x)
225
0
  {
226
0
    int64_t be64 = sockets::hostToNetwork64(x);
227
0
    append(&be64, sizeof be64);
228
0
  }
229
230
  ///
231
  /// Append int32_t using network endian
232
  ///
233
  void appendInt32(int32_t x)
234
0
  {
235
0
    int32_t be32 = sockets::hostToNetwork32(x);
236
0
    append(&be32, sizeof be32);
237
0
  }
238
239
  void appendInt16(int16_t x)
240
0
  {
241
0
    int16_t be16 = sockets::hostToNetwork16(x);
242
0
    append(&be16, sizeof be16);
243
0
  }
244
245
  void appendInt8(int8_t x)
246
0
  {
247
0
    append(&x, sizeof x);
248
0
  }
249
250
  ///
251
  /// Read int64_t from network endian
252
  ///
253
  /// Require: buf->readableBytes() >= sizeof(int32_t)
254
  int64_t readInt64()
255
0
  {
256
0
    int64_t result = peekInt64();
257
0
    retrieveInt64();
258
0
    return result;
259
0
  }
260
261
  ///
262
  /// Read int32_t from network endian
263
  ///
264
  /// Require: buf->readableBytes() >= sizeof(int32_t)
265
  int32_t readInt32()
266
0
  {
267
0
    int32_t result = peekInt32();
268
0
    retrieveInt32();
269
0
    return result;
270
0
  }
271
272
  int16_t readInt16()
273
0
  {
274
0
    int16_t result = peekInt16();
275
0
    retrieveInt16();
276
0
    return result;
277
0
  }
278
279
  int8_t readInt8()
280
0
  {
281
0
    int8_t result = peekInt8();
282
0
    retrieveInt8();
283
0
    return result;
284
0
  }
285
286
  ///
287
  /// Peek int64_t from network endian
288
  ///
289
  /// Require: buf->readableBytes() >= sizeof(int64_t)
290
  int64_t peekInt64() const
291
0
  {
292
0
    assert(readableBytes() >= sizeof(int64_t));
293
0
    int64_t be64 = 0;
294
0
    ::memcpy(&be64, peek(), sizeof be64);
295
0
    return sockets::networkToHost64(be64);
296
0
  }
297
298
  ///
299
  /// Peek int32_t from network endian
300
  ///
301
  /// Require: buf->readableBytes() >= sizeof(int32_t)
302
  int32_t peekInt32() const
303
0
  {
304
0
    assert(readableBytes() >= sizeof(int32_t));
305
0
    int32_t be32 = 0;
306
0
    ::memcpy(&be32, peek(), sizeof be32);
307
0
    return sockets::networkToHost32(be32);
308
0
  }
309
310
  int16_t peekInt16() const
311
0
  {
312
0
    assert(readableBytes() >= sizeof(int16_t));
313
0
    int16_t be16 = 0;
314
0
    ::memcpy(&be16, peek(), sizeof be16);
315
0
    return sockets::networkToHost16(be16);
316
0
  }
317
318
  int8_t peekInt8() const
319
0
  {
320
0
    assert(readableBytes() >= sizeof(int8_t));
321
0
    int8_t x = *peek();
322
0
    return x;
323
0
  }
324
325
  ///
326
  /// Prepend int64_t using network endian
327
  ///
328
  void prependInt64(int64_t x)
329
0
  {
330
0
    int64_t be64 = sockets::hostToNetwork64(x);
331
0
    prepend(&be64, sizeof be64);
332
0
  }
333
334
  ///
335
  /// Prepend int32_t using network endian
336
  ///
337
  void prependInt32(int32_t x)
338
0
  {
339
0
    int32_t be32 = sockets::hostToNetwork32(x);
340
0
    prepend(&be32, sizeof be32);
341
0
  }
342
343
  void prependInt16(int16_t x)
344
0
  {
345
0
    int16_t be16 = sockets::hostToNetwork16(x);
346
0
    prepend(&be16, sizeof be16);
347
0
  }
348
349
  void prependInt8(int8_t x)
350
0
  {
351
0
    prepend(&x, sizeof x);
352
0
  }
353
354
  void prepend(const void* /*restrict*/ data, size_t len)
355
0
  {
356
0
    assert(len <= prependableBytes());
357
0
    readerIndex_ -= len;
358
0
    const char* d = static_cast<const char*>(data);
359
0
    std::copy(d, d+len, begin()+readerIndex_);
360
0
  }
361
362
  void shrink(size_t reserve)
363
0
  {
364
0
    // FIXME: use vector::shrink_to_fit() in C++ 11 if possible.
365
0
    Buffer other;
366
0
    other.ensureWritableBytes(readableBytes()+reserve);
367
0
    other.append(toStringPiece());
368
0
    swap(other);
369
0
  }
370
371
  size_t internalCapacity() const
372
0
  {
373
0
    return buffer_.capacity();
374
0
  }
375
376
  /// Read data directly into buffer.
377
  ///
378
  /// It may implement with readv(2)
379
  /// @return result of read(2), @c errno is saved
380
  ssize_t readFd(int fd, int* savedErrno);
381
382
 private:
383
384
  char* begin()
385
1.57k
  { return &*buffer_.begin(); }
386
387
  const char* begin() const
388
132k
  { return &*buffer_.begin(); }
389
390
  void makeSpace(size_t len)
391
532
  {
392
532
    if (writableBytes() + prependableBytes() < len + kCheapPrepend)
393
532
    {
394
      // FIXME: move readable data
395
532
      buffer_.resize(writerIndex_+len);
396
532
    }
397
0
    else
398
0
    {
399
      // move readable data to the front, make space inside buffer
400
0
      assert(kCheapPrepend < readerIndex_);
401
0
      size_t readable = readableBytes();
402
0
      std::copy(begin()+readerIndex_,
403
0
                begin()+writerIndex_,
404
0
                begin()+kCheapPrepend);
405
0
      readerIndex_ = kCheapPrepend;
406
0
      writerIndex_ = readerIndex_ + readable;
407
      assert(readable == readableBytes());
408
0
    }
409
532
  }
410
411
 private:
412
  std::vector<char> buffer_;
413
  size_t readerIndex_;
414
  size_t writerIndex_;
415
416
  static const char kCRLF[];
417
};
418
419
}  // namespace net
420
}  // namespace muduo
421
422
#endif  // MUDUO_NET_BUFFER_H