// // Created by tqcq on 2023/11/14. // #ifndef TEXTADV_SERIALIZABLE_H #define TEXTADV_SERIALIZABLE_H #include #include #include #include class Serializable { public: virtual ~Serializable() = default; virtual std::string ToString() const = 0; virtual void FromString(const std::string &str) = 0; virtual void serialize(std::ostream &os) const; virtual void deserialize(std::istream &is); friend std::ostream &operator<<(std::ostream &os, const Serializable &obj) { obj.serialize(os); return os; } friend std::istream &operator>>(std::istream &is, Serializable &obj) { obj.deserialize(is); return is; } }; class Packer { public: enum Type { CHAR = 0, INT, LONG, SIZE_T, DOUBLE, FLOAT, STRING, VECTOR, MAP, }; struct PacketHeader { Type type; size_t size; }; struct Packet { union { PacketHeader header; struct { Type type; size_t size; }; }; std::string data; }; Packer& pack(char c) { data.push_back({CHAR, sizeof(char), std::string(sizeof(char), c)}); return *this; } Packer& pack(int i) { data.push_back({INT, sizeof(int), std::string((char*)&i, sizeof(int))}); return *this; } Packer& pack(long l) { data.push_back({LONG, sizeof(long), std::string((char*)&l, sizeof(long))}); return *this; } Packer& pack(size_t s) { data.push_back({SIZE_T, sizeof(size_t), std::string((char*)&s, sizeof(size_t))}); return *this; } Packer& pack(double d) { data.push_back({DOUBLE, sizeof(double), std::string((char*)&d, sizeof(double))}); return *this; } Packer& pack(float f) { data.push_back({FLOAT, sizeof(float), std::string((char*)&f, sizeof(float))}); return *this; } Packer& pack(const std::string &str) { data.push_back({STRING, str.size(), str}); return *this; } Packer& pack(const Serializable &obj) { pack(obj.ToString()); return *this; } Packer& pack(const Serializable* obj) { pack(obj->ToString()); return *this; } Packer& unpack(char &c) { Packet &d = data.back(); if (d.type != CHAR) throw std::runtime_error("Type mismatch"); c = d.data[0]; data.pop_back(); return *this; } Packer& unpack(int &i) { Packet &d = data.back(); if (d.type != INT) throw std::runtime_error("Type mismatch"); i = *(int*)d.data.data(); data.pop_back(); return *this; } Packer& unpack(long &l) { Packet &d = data.back(); if (d.type != LONG) throw std::runtime_error("Type mismatch"); l = *(long*)d.data.data(); data.pop_back(); return *this; } Packer& unpack(size_t& s) { Packet &d = data.back(); if (d.type != SIZE_T) throw std::runtime_error("Type mismatch"); s = *(size_t*)d.data.data(); data.pop_back(); return *this; } Packer& unpack(double &d) { Packet &packet = this->data.back(); if (packet.type != DOUBLE) throw std::runtime_error("Type mismatch"); d = *(double*)packet.data.data(); this->data.pop_back(); return *this; } Packer& unpack(float &f) { Packet &packet = this->data.back(); if (packet.type != FLOAT) throw std::runtime_error("Type mismatch"); f = *(float*)packet.data.data(); this->data.pop_back(); return *this; } Packer& unpack(std::string &str) { Packet &packet= this->data.back(); if (packet.type != STRING) throw std::runtime_error("Type mismatch"); str = packet.data; this->data.pop_back(); return *this; } Packer& unpack(Serializable &obj) { std::string str; unpack(str); obj.FromString(str); return *this; } Packer& unpack(Serializable* obj) { std::string str; unpack(str); obj->FromString(str); return *this; } std::string ToHexStr() const { static const std::string hex_str = "0123456789ABCDEF"; std::string str; for (const auto& d : data) { // convert header to hex auto* ptr = (unsigned char*)&d.header; auto* end = ptr + sizeof(d.header); for (; ptr != end; ++ptr) { str.push_back(hex_str[*ptr >> 4]); str.push_back(hex_str[*ptr & 0x0F]); } // convert data to hex ptr = (unsigned char*)d.data.data(); end = ptr + d.data.size(); for (; ptr != end; ++ptr) { str.push_back(hex_str[*ptr >> 4]); str.push_back(hex_str[*ptr & 0x0F]); } } return str; } void FromHexStr(const std::string& str) { static const std::string hex_str = "0123456789ABCDEF"; data.clear(); int idx = 0; for (;idx < str.size();) { Packet packet; // convert header from hex auto* ptr = (unsigned char*)&packet.header; auto* end = ptr + sizeof(packet.header); for (; ptr != end; ++ptr) { auto hi = hex_str.find(str[idx++]); auto lo = hex_str.find(str[idx++]); if (hi == std::string::npos || lo == std::string::npos) throw std::runtime_error("Invalid hex string"); *ptr = (hi << 4) | lo; } packet.data.resize(packet.header.size); for (size_t i = 0; i < packet.header.size; ++i) { auto hi = hex_str.find(str[idx++]); auto lo = hex_str.find(str[idx++]); if (hi == std::string::npos || lo == std::string::npos) throw std::runtime_error("Invalid hex string"); packet.data[i] = (hi << 4) | lo; } data.emplace_back(packet); } } private: std::vector data; }; #endif //TEXTADV_SERIALIZABLE_H