// excerpts from http://code.google.com/p/muduo/ // // Use of this source code is governed by a BSD-style license // that can be found in the License file. // // Author: Shuo Chen (chenshuo at chenshuo dot com) #ifndef MUDUO_NET_BUFFER_H #define MUDUO_NET_BUFFER_H #include "datetime/copyable.h" #include #include #include #include //#include // ssize_t namespace muduo { /// A buffer class modeled after org.jboss.netty.buffer.ChannelBuffer /// /// @code /// +-------------------+------------------+------------------+ /// | prependable bytes | readable bytes | writable bytes | /// | | (CONTENT) | | /// +-------------------+------------------+------------------+ /// | | | | /// 0 <= readerIndex <= writerIndex <= size /// @endcode class Buffer : public muduo::copyable { public: static const size_t kCheapPrepend = 8; static const size_t kInitialSize = 1024; Buffer() : buffer_(kCheapPrepend + kInitialSize), readerIndex_(kCheapPrepend), writerIndex_(kCheapPrepend) { assert(readableBytes() == 0); assert(writableBytes() == kInitialSize); assert(prependableBytes() == kCheapPrepend); } // default copy-ctor, dtor and assignment are fine void swap(Buffer& rhs) { buffer_.swap(rhs.buffer_); std::swap(readerIndex_, rhs.readerIndex_); std::swap(writerIndex_, rhs.writerIndex_); } size_t readableBytes() const { return writerIndex_ - readerIndex_; } size_t writableBytes() const { return buffer_.size() - writerIndex_; } size_t prependableBytes() const { return readerIndex_; } const char* peek() const { return begin() + readerIndex_; } // retrieve returns void, to prevent // string str(retrieve(readableBytes()), readableBytes()); // the evaluation of two functions are unspecified void retrieve(size_t len) { assert(len <= readableBytes()); readerIndex_ += len; } void retrieveUntil(const char* end) { assert(peek() <= end); assert(end <= beginWrite()); retrieve(end - peek()); } void retrieveAll() { readerIndex_ = kCheapPrepend; writerIndex_ = kCheapPrepend; } std::string retrieveAsString() { std::string str(peek(), readableBytes()); readerIndex_ = kCheapPrepend; writerIndex_ = kCheapPrepend; return str; } void append(const std::string& str) { append(str.data(), str.length()); } void append(const char* /*restrict*/ data, size_t len) { ensureWritableBytes(len); std::copy(data, data+len, beginWrite()); hasWritten(len); } void append(const void* /*restrict*/ data, size_t len) { append(static_cast(data), len); } void ensureWritableBytes(size_t len) { if (writableBytes() < len) { makeSpace(len); } assert(writableBytes() >= len); } char* beginWrite() { return begin() + writerIndex_; } const char* beginWrite() const { return begin() + writerIndex_; } void hasWritten(size_t len) { writerIndex_ += len; } void prepend(const void* /*restrict*/ data, size_t len) { assert(len <= prependableBytes()); readerIndex_ -= len; const char* d = static_cast(data); std::copy(d, d+len, begin()+readerIndex_); } void shrink(size_t reserve) { std::vector buf(kCheapPrepend+readableBytes()+reserve); std::copy(peek(), peek()+readableBytes(), buf.begin()+kCheapPrepend); buf.swap(buffer_); } /// Read data directly into buffer. /// /// It may implement with readv(2) /// @return result of read(2), @c errno is saved ssize_t readFd(int fd, int* savedErrno); private: char* begin() { return &*buffer_.begin(); } const char* begin() const { return &*buffer_.begin(); } void makeSpace(size_t len) { if (writableBytes() + prependableBytes() < len + kCheapPrepend) { buffer_.resize(writerIndex_+len); } else { // move readable data to the front, make space inside buffer assert(kCheapPrepend < readerIndex_); size_t readable = readableBytes(); std::copy(begin()+readerIndex_, begin()+writerIndex_, begin()+kCheapPrepend); readerIndex_ = kCheapPrepend; writerIndex_ = readerIndex_ + readable; assert(readable == readableBytes()); } } private: std::vector buffer_; size_t readerIndex_; size_t writerIndex_; }; } #endif // MUDUO_NET_BUFFER_H