#pragma once #include #include #include #include #include #include class BasePacketWriter : public NonCopyable { public: BasePacketWriter(char *buffer, size_t len, bool useBigEndian = false, 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 = hostToNetwork16(value, mBigEndian); return writeBuffer((char *)&value, sizeof(value)); } bool writeUINT16(uint16_t value) { value = hostToNetwork16(value, mBigEndian); return writeBuffer((char *)&value, sizeof(value)); } bool writeINT32(int32_t value) { value = hostToNetwork32(value, mBigEndian); return writeBuffer((char *)&value, sizeof(value)); } bool writeUINT32(uint32_t value) { value = hostToNetwork32(value, mBigEndian); return writeBuffer((char *)&value, sizeof(value)); } bool writeINT64(int64_t value) { value = hostToNetwork64(value, mBigEndian); return writeBuffer((char *)&value, sizeof(value)); } bool writeUINT64(uint64_t value) { value = 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 = false) : mBigEndian(useBigEndian), mSize(len) { mPos = 0; mSavedPos = 0; mBuffer = buffer; } virtual ~BasePacketReader() = default; void useBigEndian() { mBigEndian = true; } void useLittleEndian() { mBigEndian = false; } void savePos() { mSavedPos = mPos; } size_t savedPos() const { return mSavedPos; } size_t getLeft() const { if (mPos > mSize) { throw std::out_of_range("current pos is greater than max len"); } return mSize - mPos; } bool enough(size_t len) const { if (mPos > mSize) { return false; } return (mSize - mPos) >= len; } const char *begin() const { return mBuffer; } const char *currentBuffer() const { return mBuffer + mPos; } void consumeAll() { mPos = mSize; savePos(); } size_t currentPos() const { return mPos; } size_t size() const { return mSize; } void addPos(size_t diff) { const auto tmpPos = mPos + diff; if (tmpPos > mSize) { 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 networkToHost16(value, mBigEndian); } uint16_t readUINT16() { uint16_t value = 0; read(value); return networkToHost16(value, mBigEndian); } int32_t readINT32() { int32_t value = 0; read(value); return networkToHost32(value, mBigEndian); } uint32_t readUINT32() { uint32_t value = 0; read(value); return networkToHost32(value, mBigEndian); } int64_t readINT64() { int64_t value = 0; read(value); return networkToHost64(value, mBigEndian); } uint64_t readUINT64() { uint64_t value = 0; read(value); return networkToHost64(value, mBigEndian); } private: // 为了避免直接read(uintXXX)导致没有指定字节序造成隐患BUG,因为此函数设置为私有 template void read(T &value) { static_assert(std::is_same::type>::value, "T must a normal type"); static_assert(std::is_pod::value, "T must a pod type"); if ((mPos + sizeof(value)) > mSize) { throw std::out_of_range("T size is to big"); } value = *(T *)(mBuffer + mPos); mPos += sizeof(value); } protected: bool mBigEndian; const size_t mSize; const char *mBuffer; size_t mPos; size_t mSavedPos; }; template class AutoMallocPacket : public BasePacketWriter { public: explicit AutoMallocPacket(bool useBigEndian = false, bool isAutoMalloc = false) : BasePacketWriter(mData, SIZE, useBigEndian, isAutoMalloc) {} private: char mData[SIZE]; }; using BigPacket = AutoMallocPacket<32 * 1024>;