K3Serializer is a fast, clean and small serializer based on modern c++17. It has some advantages:
- Reflection-Based Serialization/Deserialization.
- Less Memory Occupation.
- High Performance.
- Compatible And No Extra Dependency.
- STL-Container And Inherited-Class Serialization Support.
- Flexiable Extendablity.
Head-Only. Just copy k3serializer.h and k3serializer.cpp to your project.
Run Test:
mkdir build
cd build
cmake ..
cmake --build .
ctest
I use this library to do performance comparison. Here is the result on my computer:
Protocol | Message size | Serialization time | Deserialization time |
---|---|---|---|
Cap'n'Proto | 208 bytes | 280 ns | 276 ns |
FastBinaryEncoding | 234 bytes | 47 ns | 90 ns |
FlatBuffers | 280 bytes | 345 ns | 105 ns |
Protobuf | 120 bytes | 372 ns | 488 ns |
SimpleBinaryEncoding | 138 bytes | 30 ns | 73 ns |
RapidJson | 297 bytes | 713 ns | 352 ns |
K3Serializer | 97 bytes | 146 ns | 255 ns |
enum class ECountry
{
US,
CN,
JP,
};
//add template specialization for enum class Type
template<>
class K3Serializer<ECountry> : public K3SerializerEnum<ECountry> {};
int main() {
char c = 'a';
int n = 0x12345678;
float f = 3.14159f;
ECountry e = ECountry::CN;
std::string str;
K3Serializer<char>::PutValue(str, c);
K3Serializer<int>::PutValue(str, n);
K3Serializer<float>::PutValue(str, f);
K3Serializer<ECountry>::PutValue(str, e);
char oc;
int on;
float of;
ECountry oe;
std::string_view input = str;
assert(K3Serializer<char>::GetValue(input, oc) && oc == c);
assert(K3Serializer<int>::GetValue(input, on) && on == n);
assert(K3Serializer<float>::GetValue(input, of) && of == f);
assert(K3Serializer<ECountry>::GetValue(input, oe) && oe == e);
}
int main() {
std::vector<int> in1 = { 1,2,3,4,-3,-2,-1 };
std::unordered_map<std::string, std::string> in2 = { {"first", "john"}, {"second", "bob"}, {"third", "jane"} };
std::string str;
K3Serializer<decltype(in1)>::PutValue(str, in1);
K3Serializer<decltype(in2)>::PutValue(str, in2);
std::vector<int> out1;
std::unordered_map<std::string, std::string> out2;
std::string_view input = str;
assert(K3Serializer<decltype(out1)>::GetValue(input, out1) && in1 == out1);
assert(K3Serializer<decltype(out2)>::GetValue(input, out2) && in2 == out2);
return 0;
}
class Student
{
public:
std::string name;
std::vector<std::string> bookList;
bool operator==(const Student& rhs)
{
return name == rhs.name && bookList == rhs.bookList;
}
//add annotation for class(like meta-data for refelction system)
//we need to konw class-member and super-class info for serialize.
public:
static constexpr inline auto kMetaClassMember = std::make_tuple(&Student::name, &Student::bookList);
using SuperClass = void;
};
template<>
class K3Serializer<Student> : public K3SerializerClass<Student> {};
int main() {
Student stu1;
stu1.name = "bob";
stu1.bookList = { "chinese", "math", "english", "physic" };
std::string str;
K3Serializer<decltype(stu1)>::PutValue(str, stu1);
Student stu2;
std::string_view input = str;
assert(K3Serializer<decltype(stu2)>::GetValue(input, stu2) && stu1 == stu2);
}
class K3Object
{
public:
virtual ~K3Object() = default;
public:
static constexpr inline auto kMetaClassMember = std::make_tuple();
using SuperClass = void;
};
template<>
class K3Serializer<K3Object> : public K3SerializerClass<K3Object> {};
class Entity : public K3Object
{
public:
int64_t entityId;
public:
static constexpr inline auto kMetaClassMember = std::make_tuple(&Entity::entityId);
using SuperClass = K3Object;
};
template<>
class K3Serializer<Entity> : public K3SerializerClass<Entity> {};
class Character : public Entity
{
public:
std::string name;
double money;
public:
static constexpr inline auto kMetaClassMember = std::make_tuple(&Character::name, &Character::money);
using SuperClass = Entity;
};
template<>
class K3Serializer<Character> : public K3SerializerClass<Character> {};
int main() {
Character c1;
c1.entityId = 0xA00000001;
c1.name = "character_1";
c1.money = 9999.9999;
std::string str;
K3Serializer<decltype(c1)>::PutValue(str, c1);
Character c2;
std::string_view input = str;
bool result = K3Serializer<decltype(c2)>::GetValue(input, c2);
assert(result);
}