#pragma once #include #include #include #include #include #include #include namespace brynet { namespace base { class BasePacketWriter : public NonCopyable { public: BasePacketWriter(char* buffer, size_t len, bool useBigEndian = true, bool isAutoMalloc = false) : mIsAutoMalloc(isAutoMalloc), mBigEndian(useBigEndian) { mMaxLen = len; mPos = 0; mBuffer = buffer; mMallocBuffer = nullptr; } virtual ~BasePacketWriter() { if (mMallocBuffer != nullptr) { free(mMallocBuffer); mMallocBuffer = nullptr; } } void init() { mPos = 0; } size_t getMaxLen() const { return mMaxLen; } size_t getPos() const { return mPos; } const char* getData() const { return mBuffer; } bool isAutoGrow() const { return mIsAutoMalloc; } bool writeBool(bool value) { static_assert(sizeof(bool) == sizeof(int8_t), ""); return writeBuffer((char*)&value, sizeof(value)); } bool writeINT8(int8_t value) { return writeBuffer((char*)&value, sizeof(value)); } bool writeUINT8(uint8_t value) { return writeBuffer((char*)&value, sizeof(value)); } bool writeINT16(int16_t value) { value = endian::hostToNetwork16(value, mBigEndian); return writeBuffer((char*)&value, sizeof(value)); } bool writeUINT16(uint16_t value) { value = endian::hostToNetwork16(value, mBigEndian); return writeBuffer((char*)&value, sizeof(value)); } bool writeINT32(int32_t value) { value = endian::hostToNetwork32(value, mBigEndian); return writeBuffer((char*)&value, sizeof(value)); } bool writeUINT32(uint32_t value) { value = endian::hostToNetwork32(value, mBigEndian); return writeBuffer((char*)&value, sizeof(value)); } bool writeINT64(int64_t value) { value = endian::hostToNetwork64(value, mBigEndian); return writeBuffer((char*)&value, sizeof(value)); } bool writeUINT64(uint64_t value) { value = endian::hostToNetwork64(value, mBigEndian); return writeBuffer((char*)&value, sizeof(value)); } bool writeBinary(const std::string& binary) { return writeBuffer(binary.c_str(), binary.size()); } bool writeBinary(const char* binary, size_t binaryLen) { return writeBuffer(binary, binaryLen); } bool writeBuffer(const char* buffer, size_t len) { growBuffer(len); if (mMaxLen < (mPos + len)) { return false; } memcpy(mBuffer + mPos, buffer, len); mPos += len; return true; } BasePacketWriter & operator << (const bool &v) { writeBool(v); return *this; } BasePacketWriter & operator << (const uint8_t &v) { writeUINT8(v); return *this; } BasePacketWriter & operator << (const int8_t &v) { writeINT8(v); return *this; } BasePacketWriter & operator << (const int16_t &v) { writeINT16(v); return *this; } BasePacketWriter & operator << (const uint16_t &v) { writeUINT16(v); return *this; } BasePacketWriter & operator << (const int32_t &v) { writeINT32(v); return *this; } BasePacketWriter & operator << (const uint32_t &v) { writeUINT32(v); return *this; } BasePacketWriter & operator << (const int64_t &v) { writeINT64(v); return *this; } BasePacketWriter & operator << (const uint64_t &v) { writeUINT64(v); return *this; } BasePacketWriter & operator << (const char* const &v) { writeBinary(v); return *this; } BasePacketWriter & operator << (const std::string &v) { writeBinary(v); return *this; } private: // 为了避免直接<<导致没有指定字节序导致隐藏BUG,因为此函数设置为私有 template BasePacketWriter & operator << (const T& v) { static_assert(!std::is_pointer::value, "T must is't a pointer"); static_assert(std::is_class ::value, "T must a class or struct type"); static_assert(std::is_pod ::value, "T must a pod type"); writeBuffer((const char*)&v, sizeof(v)); return *this; } template void writev(const Arg1& arg1, const Args&... args) { this->operator<<(arg1); writev(args...); } void writev() { } protected: void growBuffer(size_t len) { if (!mIsAutoMalloc || (mPos + len) <= mMaxLen) { return; } auto newBuffer = (char*)malloc(mMaxLen + len); if (newBuffer == nullptr) { return; } memcpy(newBuffer, mBuffer, mPos); if (mMallocBuffer != nullptr) { free(mMallocBuffer); mMallocBuffer = nullptr; } mMaxLen += len; mMallocBuffer = newBuffer; mBuffer = newBuffer; } protected: const bool mIsAutoMalloc; bool mBigEndian; size_t mPos; size_t mMaxLen; char* mBuffer; char* mMallocBuffer; }; class BasePacketReader { public: BasePacketReader(const char* buffer, size_t len, bool useBigEndian = true) : mBigEndian(useBigEndian), mMaxLen(len) { mPos = 0; mBuffer = buffer; } virtual ~BasePacketReader() = default; size_t getLeft() const { if (mPos > mMaxLen) { throw std::out_of_range("current pos is greater than max len"); } return mMaxLen - mPos; } const char* getBuffer() const { return mBuffer; } void skipAll() { mPos = mMaxLen; } size_t getPos() const { return mPos; } size_t getMaxPos() const { return mMaxLen; } void addPos(size_t diff) { const auto tmpPos = mPos + diff; if (tmpPos > mMaxLen) { throw std::out_of_range("diff is to big"); } mPos = tmpPos; } bool readBool() { static_assert(sizeof(bool) == sizeof(int8_t), ""); bool value = false; read(value); return value; } int8_t readINT8() { int8_t value = 0; read(value); return value; } uint8_t readUINT8() { uint8_t value = 0; read(value); return value; } int16_t readINT16() { int16_t value = 0; read(value); return endian::networkToHost16(value, mBigEndian); } uint16_t readUINT16() { uint16_t value = 0; read(value); return endian::networkToHost16(value, mBigEndian); } int32_t readINT32() { int32_t value = 0; read(value); return endian::networkToHost32(value, mBigEndian); } uint32_t readUINT32() { uint32_t value = 0; read(value); return endian::networkToHost32(value, mBigEndian); } int64_t readINT64() { int64_t value = 0; read(value); return endian::networkToHost64(value, mBigEndian); } uint64_t readUINT64() { uint64_t value = 0; read(value); return endian::networkToHost64(value, mBigEndian); } private: // 为了避免直接read(uintXXX)导致没有指定字节序造成隐患BUG,因为此函数设置为私有 template void read(T& value) { static_assert(std::is_same::type>::value, "T must a nomal type"); static_assert(std::is_pod::value, "T must a pod type"); if ((mPos + sizeof(value)) > mMaxLen) { throw std::out_of_range("T size is to big"); } value = *(T*)(mBuffer + mPos); mPos += sizeof(value); } protected: const bool mBigEndian; const size_t mMaxLen; const char* mBuffer; size_t mPos; }; template class AutoMallocPacket : public BasePacketWriter { public: explicit AutoMallocPacket(bool useBigEndian = true, bool isAutoMalloc = false) : BasePacketWriter(mData, SIZE, useBigEndian, isAutoMalloc) {} private: char mData[SIZE]; }; using BigPacket = AutoMallocPacket<32 * 1024>; } }