// This file is originally from Trantor - MsgBuffer.h // Copyright (c) 2016-2021, Tao An. All rights reserved. // Redistribution and use in source and binary forms, with or without // modification, are permitted provided that the following conditions // are met: // // * Redistributions of source code must retain the above copyright // notice, this list of conditions and the following disclaimer. // * Redistributions in binary form must reproduce the above copyright // notice, this list of conditions and the following disclaimer in the // documentation and/or other materials provided with the distribution. // * Neither the name of Tao An nor the names of other contributors // may be used to endorse or promote products derived from this software // without specific prior written permission. // // THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS // "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT // LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR // A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT // OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, // SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT // LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, // DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY // THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT // (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE // OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. #pragma once #include #include #include #include #include #include #ifdef _WIN32 using ssize_t = long long; #endif static constexpr size_t kBufferDefaultLength{2048}; static constexpr char CRLF[]{"\r\n"}; /** * @brief This class represents a memory buffer used for sending and receiving * data. * */ class MsgBuffer { public: /** * @brief Construct a new message buffer instance. * * @param len The initial size of the buffer. */ MsgBuffer(size_t len = kBufferDefaultLength); /** * @brief Get the beginning of the buffer. * * @return const char* */ const char *peek() const { return begin() + head_; } /** * @brief Get the end of the buffer where new data can be written. * * @return const char* */ const char *beginWrite() const { return begin() + tail_; } char *beginWrite() { return begin() + tail_; } /** * @brief Get a byte value from the buffer. * * @return uint8_t */ uint8_t peekInt8() const { assert(readableBytes() >= 1); return *(static_cast((void *)peek())); } /** * @brief Get a unsigned short value from the buffer. * * @return uint16_t */ uint16_t peekInt16() const; /** * @brief Get a unsigned int value from the buffer. * * @return uint32_t */ uint32_t peekInt32() const; /** * @brief Get a unsigned int64 value from the buffer. * * @return uint64_t */ uint64_t peekInt64() const; /** * @brief Get and remove some bytes from the buffer. * * @param len * @return std::string */ std::string read(size_t len); /** * @brief Get the remove a byte value from the buffer. * * @return uint8_t */ uint8_t readInt8(); /** * @brief Get and remove a unsigned short value from the buffer. * * @return uint16_t */ uint16_t readInt16(); /** * @brief Get and remove a unsigned int value from the buffer. * * @return uint32_t */ uint32_t readInt32(); /** * @brief Get and remove a unsigned int64 value from the buffer. * * @return uint64_t */ uint64_t readInt64(); /** * @brief swap the buffer with another. * * @param buf */ void swap(MsgBuffer &buf) noexcept; /** * @brief Return the size of the data in the buffer. * * @return size_t */ size_t readableBytes() const { return tail_ - head_; } /** * @brief Return the size of the empty part in the buffer * * @return size_t */ size_t writableBytes() const { return buffer_.size() - tail_; } /** * @brief Append new data to the buffer. * */ void append(const MsgBuffer &buf); template void append(const char (&buf)[N]) { assert(strnlen(buf, N) == N - 1); append(buf, N - 1); } void append(const char *buf, size_t len); void append(const std::string &buf) { append(buf.c_str(), buf.length()); } /** * @brief Append a byte value to the end of the buffer. * * @param b */ void appendInt8(const uint8_t b) { append(static_cast((void *)&b), 1); } /** * @brief Append a unsigned short value to the end of the buffer. * * @param s */ void appendInt16(const uint16_t s); /** * @brief Append a unsigned int value to the end of the buffer. * * @param i */ void appendInt32(const uint32_t i); /** * @brief Appaend a unsigned int64 value to the end of the buffer. * * @param l */ void appendInt64(const uint64_t l); /** * @brief Put new data to the beginning of the buffer. * * @param buf * @param len */ void addInFront(const char *buf, size_t len); /** * @brief Put a byte value to the beginning of the buffer. * * @param b */ void addInFrontInt8(const uint8_t b) { addInFront(static_cast((void *)&b), 1); } /** * @brief Put a unsigned short value to the beginning of the buffer. * * @param s */ void addInFrontInt16(const uint16_t s); /** * @brief Put a unsigned int value to the beginning of the buffer. * * @param i */ void addInFrontInt32(const uint32_t i); /** * @brief Put a unsigned int64 value to the beginning of the buffer. * * @param l */ void addInFrontInt64(const uint64_t l); /** * @brief Remove all data in the buffer. * */ void retrieveAll(); /** * @brief Remove some bytes in the buffer. * * @param len */ void retrieve(size_t len); /** * @brief Read data from a file descriptor and put it into the buffer.˝ * * @param fd The file descriptor. It is usually a socket. * @param retErrno The error code when reading. * @return ssize_t The number of bytes read from the file descriptor. -1 is * returned when an error occurs. */ ssize_t readFd(int fd, int *retErrno); /** * @brief Remove the data before a certain position from the buffer. * * @param end The position. */ void retrieveUntil(const char *end) { assert(peek() <= end); assert(end <= beginWrite()); retrieve(end - peek()); } /** * @brief Find the position of the buffer where the CRLF is found. * * @return const char* */ const char *findCRLF() const { const char *crlf = std::search(peek(), beginWrite(), CRLF, CRLF + 2); return crlf == beginWrite() ? NULL : crlf; } /** * @brief Make sure the buffer has enough spaces to write data. * * @param len */ void ensureWritableBytes(size_t len); /** * @brief Move the write pointer forward when the new data has been written * to the buffer. * * @param len */ void hasWritten(size_t len) { assert(len <= writableBytes()); tail_ += len; } /** * @brief Move the write pointer backward to remove data in the end of the * buffer. * * @param offset */ void unwrite(size_t offset) { assert(readableBytes() >= offset); tail_ -= offset; } /** * @brief Access a byte in the buffer. * * @param offset * @return const char& */ const char &operator[](size_t offset) const { assert(readableBytes() >= offset); return peek()[offset]; } char &operator[](size_t offset) { assert(readableBytes() >= offset); return begin()[head_ + offset]; } private: size_t head_; size_t initCap_; std::vector buffer_; size_t tail_; const char *begin() const { return &buffer_[0]; } char *begin() { return &buffer_[0]; } }; inline void swap(MsgBuffer &one, MsgBuffer &two) noexcept { one.swap(two); } namespace std { template <> inline void swap(MsgBuffer &one, MsgBuffer &two) noexcept { one.swap(two); } } // namespace std