// *********************************************************************** // Filename : ByteBuffer.h // Author : LIZHENG // Created : 2014-11-04 // Description : // // Copyright (c) lizhenghn@gmail.com. All rights reserved. // *********************************************************************** #ifndef ZL_NETBUFFER_H #define ZL_NETBUFFER_H //#include "Define.h" //#include "zlreactor/NetUtil.h" #include #include #include #include namespace zl { namespace net{ /// A buffer class modeled after org.jboss.netty.buffer.ChannelBuffer /// see http://blog.csdn.net/solstice/article/details/6329080 /// @code /// +-------------------+------------------+------------------+ /// | prependable bytes | readable bytes | writable bytes | /// | | (CONTENT) | | /// +-------------------+------------------+------------------+ /// | | | | /// 0 <= readerIndex <= writerIndex <= size /// @endcode class ByteBuffer { public: static const size_t kCheapPrepend = 8; static const size_t kInitialSize = 1024; public: ByteBuffer() : readerIndex_(kCheapPrepend) , writerIndex_(kCheapPrepend) , buffer_(kCheapPrepend + kInitialSize) { assert(readableBytes() == 0); assert(writableBytes() == kInitialSize); assert(prependableBytes() == kCheapPrepend); } size_t readableBytes() const { return writerIndex_ - readerIndex_; } size_t writableBytes() const { return buffer_.size() - writerIndex_; } size_t prependableBytes() const { return readerIndex_; } std::string toString() const { return std::string(peek(), static_cast(readableBytes())); } public: // Data Write & Read void write(const std::string& str) { write(str.data(), str.size()); } void write(const char* data) { write(data, strlen(data)); } void write(const char* data, size_t len) { ensureWritableBytes(len); char* begin = beginWrite(); for (size_t i = 0; i < len; i++) begin[i] = data[i]; //std::copy(data, data+len, beginWrite()); hasWritten(len); } void write(const void* data, size_t len) { write(static_cast(data), len); } /// write Number using network endian /// Number == bool\int8_t\int16_t\int32_t\int64_t\float\double\.... template void write(Number num) { Number nnum = NetUtil::host2Net(num); write(&nnum, sizeof(nnum)); } /// return Number using host endian /// Number == bool\int8_t\int16_t\int32_t\int64_t\float\double\.... /// Require: readableBytes() >= sizeof(Number) template Number read() { Number nnum = peek(); retrieve(sizeof(nnum)); return nnum; } /// peek number using host endian /// Number == bool\int8_t\int16_t\int32_t\int64_t\float\double\.... /// Require: readableBytes() >= sizeof(Number) template Number peek() const { assert(readableBytes() >= sizeof(Number)); Number nnum = 0; ::memcpy(&nnum, peek(), sizeof(nnum)); return NetUtil::net2Host(nnum); } /// prepend number using network endian /// Number = int8_t\int16_t\int32_t\int64_t\... template void prepend(Number num) { Number nnum = NetUtil::host2Net(num); prepend(&nnum, sizeof(nnum)); } //void prepend(const void* data, size_t len) //{ // assert(len <= prependableBytes()); // readerIndex_ -= len; // const char* d = static_cast(data); // std::copy(d, d+len, begin()+readerIndex_); //} void retrieve(size_t len) { assert(len <= readableBytes()); if (len < readableBytes()) { readerIndex_ += len; } else { retrieveAll(); } } template void retrieve() { retrieve(sizeof(Number)); } void retrieveUntil(const char* end) { assert(peek() <= end); assert(end <= beginWrite()); retrieve(end - peek()); } void retrieveAll() { readerIndex_ = kCheapPrepend; writerIndex_ = kCheapPrepend; } std::string retrieveAllAsString() { return retrieveAsString(readableBytes());; } std::string retrieveAsString(size_t len) { assert(len <= readableBytes()); std::string result(peek(), len); retrieve(len); return result; } public: // search const char* peek() const { return begin() + readerIndex_; } const char* findCRLF() const { const char* crlf = std::search(peek(), beginWrite(), kCRLF, kCRLF + 2); return crlf == beginWrite() ? NULL : crlf; } const char* findCRLF(const char* start) const { assert(peek() <= start); assert(start <= beginWrite()); const char* crlf = std::search(start, beginWrite(), kCRLF, kCRLF + 2); return crlf == beginWrite() ? NULL : crlf; } const char* findDoubleCRLF() const { const char* crlf = std::search(peek(), beginWrite(), kDoubleCRLF, kDoubleCRLF + 4); return crlf == beginWrite() ? NULL : crlf; } const char* findEOL() const { const void* eol = memchr(peek(), '\n', readableBytes()); return static_cast(eol); } const char* findEOL(const char* start) const { assert(peek() <= start); assert(start <= beginWrite()); const void* eol = memchr(start, '\n', beginWrite() - start); return static_cast(eol); } public: 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) { assert(len <= writableBytes()); writerIndex_ += len; } void unwrite(size_t len) { assert(len <= readableBytes()); writerIndex_ -= len; } void shrink(size_t reserve) { ByteBuffer other; other.ensureWritableBytes(readableBytes() + reserve); other.write(toString()); swap(other); } size_t capacity() const { return buffer_.capacity(); } void swap(ByteBuffer& rhs) { buffer_.swap(rhs.buffer_); std::swap(readerIndex_, rhs.readerIndex_); std::swap(writerIndex_, rhs.writerIndex_); } private: char* begin() { return &*buffer_.begin(); } const char* begin() const { return &*buffer_.begin(); } void makeSpace(size_t len) { if (writableBytes() + prependableBytes() < len + kCheapPrepend) { // FIXME: move readable data buffer_.resize(writerIndex_ + len); } else { // move readable data to the front, make space inside buffer assert(kCheapPrepend < readerIndex_); size_t readable = readableBytes(); for (size_t i = 0; i < writerIndex_ - readerIndex_; i++) { (begin() + kCheapPrepend)[i] = (begin() + readerIndex_)[i]; } //std::copy(begin() + readerIndex_, begin() + writerIndex_, begin() + kCheapPrepend); readerIndex_ = kCheapPrepend; writerIndex_ = readerIndex_ + readable; assert(readable == readableBytes()); } } private: size_t readerIndex_; size_t writerIndex_; std::vector buffer_; // save buffer of network endian static const char kCRLF[]; static const char kDoubleCRLF[]; }; } } #endif /* ZL_BYTEBUFFER_H */