1// excerpts from http://code.google.com/p/muduo/
2//
3// Use of this source code is governed by a BSD-style license
4// that can be found in the License file.
5//
6// Author: Shuo Chen (chenshuo at chenshuo dot com)
7
8#ifndef MUDUO_NET_BUFFER_H
9#define MUDUO_NET_BUFFER_H
10
11#include "datetime/copyable.h"
12
13#include <algorithm>
14#include <string>
15#include <vector>
16
17#include <assert.h>
18//#include <unistd.h>  // ssize_t
19
20namespace muduo
21{
22
23/// A buffer class modeled after org.jboss.netty.buffer.ChannelBuffer
24///
25/// @code
26/// +-------------------+------------------+------------------+
27/// | prependable bytes |  readable bytes  |  writable bytes  |
28/// |                   |     (CONTENT)    |                  |
29/// +-------------------+------------------+------------------+
30/// |                   |                  |                  |
31/// 0      <=      readerIndex   <=   writerIndex    <=     size
32/// @endcode
33class Buffer : public muduo::copyable
34{
35 public:
36  static const size_t kCheapPrepend = 8;
37  static const size_t kInitialSize = 1024;
38
39  Buffer()
40    : buffer_(kCheapPrepend + kInitialSize),
41      readerIndex_(kCheapPrepend),
42      writerIndex_(kCheapPrepend)
43  {
44    assert(readableBytes() == 0);
45    assert(writableBytes() == kInitialSize);
46    assert(prependableBytes() == kCheapPrepend);
47  }
48
49  // default copy-ctor, dtor and assignment are fine
50
51  void swap(Buffer& rhs)
52  {
53    buffer_.swap(rhs.buffer_);
54    std::swap(readerIndex_, rhs.readerIndex_);
55    std::swap(writerIndex_, rhs.writerIndex_);
56  }
57
58  size_t readableBytes() const
59  { return writerIndex_ - readerIndex_; }
60
61  size_t writableBytes() const
62  { return buffer_.size() - writerIndex_; }
63
64  size_t prependableBytes() const
65  { return readerIndex_; }
66
67  const char* peek() const
68  { return begin() + readerIndex_; }
69
70  // retrieve returns void, to prevent
71  // string str(retrieve(readableBytes()), readableBytes());
72  // the evaluation of two functions are unspecified
73  void retrieve(size_t len)
74  {
75    assert(len <= readableBytes());
76    readerIndex_ += len;
77  }
78
79  void retrieveUntil(const char* end)
80  {
81    assert(peek() <= end);
82    assert(end <= beginWrite());
83    retrieve(end - peek());
84  }
85
86  void retrieveAll()
87  {
88    readerIndex_ = kCheapPrepend;
89    writerIndex_ = kCheapPrepend;
90  }
91
92  std::string retrieveAsString()
93  {
94    std::string str(peek(), readableBytes());
95    retrieveAll();
96    return str;
97  }
98
99  void append(const std::string& str)
100  {
101    append(str.data(), str.length());
102  }
103
104  void append(const char* /*restrict*/ data, size_t len)
105  {
106    ensureWritableBytes(len);
107    std::copy(data, data+len, beginWrite());
108    hasWritten(len);
109  }
110
111  void append(const void* /*restrict*/ data, size_t len)
112  {
113    append(static_cast<const char*>(data), len);
114  }
115
116  void ensureWritableBytes(size_t len)
117  {
118    if (writableBytes() < len)
119    {
120      makeSpace(len);
121    }
122    assert(writableBytes() >= len);
123  }
124
125  char* beginWrite()
126  { return begin() + writerIndex_; }
127
128  const char* beginWrite() const
129  { return begin() + writerIndex_; }
130
131  void hasWritten(size_t len)
132  { writerIndex_ += len; }
133
134  void prepend(const void* /*restrict*/ data, size_t len)
135  {
136    assert(len <= prependableBytes());
137    readerIndex_ -= len;
138    const char* d = static_cast<const char*>(data);
139    std::copy(d, d+len, begin()+readerIndex_);
140  }
141
142  void shrink(size_t reserve)
143  {
144   std::vector<char> buf(kCheapPrepend+readableBytes()+reserve);
145   std::copy(peek(), peek()+readableBytes(), buf.begin()+kCheapPrepend);
146   buf.swap(buffer_);
147  }
148
149  /// Read data directly into buffer.
150  ///
151  /// It may implement with readv(2)
152  /// @return result of read(2), @c errno is saved
153  ssize_t readFd(int fd, int* savedErrno);
154
155 private:
156
157  char* begin()
158  { return &*buffer_.begin(); }
159
160  const char* begin() const
161  { return &*buffer_.begin(); }
162
163  void makeSpace(size_t len)
164  {
165    if (writableBytes() + prependableBytes() < len + kCheapPrepend)
166    {
167      buffer_.resize(writerIndex_+len);
168    }
169    else
170    {
171      // move readable data to the front, make space inside buffer
172      assert(kCheapPrepend < readerIndex_);
173      size_t readable = readableBytes();
174      std::copy(begin()+readerIndex_,
175                begin()+writerIndex_,
176                begin()+kCheapPrepend);
177      readerIndex_ = kCheapPrepend;
178      writerIndex_ = readerIndex_ + readable;
179      assert(readable == readableBytes());
180    }
181  }
182
183 private:
184  std::vector<char> buffer_;
185  size_t readerIndex_;
186  size_t writerIndex_;
187};
188
189}
190
191#endif  // MUDUO_NET_BUFFER_H
192