|
- // ***********************************************************************
- // 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 <assert.h>
- #include <string>
- #include <vector>
- #include <algorithm>
- 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<int>(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<const char*>(data), len);
- }
-
- /// write Number using network endian
- /// Number == bool\int8_t\int16_t\int32_t\int64_t\float\double\....
- template <typename Number>
- 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 <typename Number>
- Number read()
- {
- Number nnum = peek<Number>();
- 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 <typename Number>
- 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 <typename Number>
- 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<const char*>(data);
- // std::copy(d, d+len, begin()+readerIndex_);
- //}
-
- void retrieve(size_t len)
- {
- assert(len <= readableBytes());
- if (len < readableBytes())
- {
- readerIndex_ += len;
- }
- else
- {
- retrieveAll();
- }
- }
-
- template <typename Number>
- 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<const char*>(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<const char*>(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<char> buffer_; // save buffer of network endian
-
- static const char kCRLF[];
- static const char kDoubleCRLF[];
- };
-
- }
- }
-
- #endif /* ZL_BYTEBUFFER_H */
|