/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 |