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