rcpp_framework/libs/brynet/base/Packet.hpp
2021-05-14 18:13:02 +02:00

355 lines
7.3 KiB
C++

#pragma once
#include <brynet/base/NonCopyable.hpp>
#include <brynet/base/endian/Endian.hpp>
#include <cstdint>
#include <cstring>
#include <stdexcept>
#include <string>
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 <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 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 <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>;