mirror of
https://github.com/Relintai/rcpp_framework.git
synced 2024-11-14 04:57:21 +01:00
435 lines
11 KiB
C++
435 lines
11 KiB
C++
#pragma once
|
|
|
|
#include <cstdint>
|
|
#include <cassert>
|
|
#include <cstdbool>
|
|
#include <cstring>
|
|
#include <string>
|
|
|
|
#include <brynet/base/NonCopyable.hpp>
|
|
#include <brynet/base/endian/Endian.hpp>
|
|
|
|
namespace brynet { namespace base {
|
|
|
|
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 = 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<typename T>
|
|
BasePacketWriter & operator << (const T& v)
|
|
{
|
|
static_assert(!std::is_pointer<T>::value, "T must is't a pointer");
|
|
static_assert(std::is_class <T>::value, "T must a class or struct type");
|
|
static_assert(std::is_pod <T>::value, "T must a pod type");
|
|
writeBuffer((const char*)&v, sizeof(v));
|
|
return *this;
|
|
}
|
|
|
|
template<typename Arg1, typename... Args>
|
|
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 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<typename T>
|
|
void read(T& value)
|
|
{
|
|
static_assert(std::is_same<T, typename std::remove_pointer<T>::type>::value,
|
|
"T must a normal type");
|
|
static_assert(std::is_pod<T>::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<size_t SIZE>
|
|
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>;
|
|
|
|
} } |