Header only library for serializing C++ structs into MessagePack binary form with minimal boilerplate code. Requires C++17 and MSVC compiler (but should probably work with other compilers as well). Obviously, this is just a fun project, highly experimental, avoid using it during rocket surgeries.
If you need to serialize small non-POD structures (i.e., you can't just use plain memcpy), this library might provide good quick solution. There is no need to manually write serialization and deserialization code for each and every struct you have. There aren't even any message definition files (like .proto files in Google's Protocol Buffers). Everything is resolved during compilation.
struct UserData final
{
int age;
float height;
std::string name;
uint64_t password_hash;
std::vector<int> lucky_numbers;
};
// Fill UserData struct with some random data
UserData ud;
ud.age = 32;
ud.height = 1.75f;
ud.name = "Jeff";
ud.password_hash = 0xDEADBEEFDEADC0DEull;
ud.lucky_numbers = { 69, 420, 1984 };
// Serialize it into a buffer
sbp::buffer buff;
sbp::write(buff, ud);That's it! As long as your structs are simple enough (see limitations below), there is no need to write any extra serialization or deserialization code.
How does serialized UserData instance look like in memory:
'20 ca 00 00 e0 3f a4 4a 65 66 66 cf de c0 ad de ef be ad de 93 45 d1 a4 01 d1 c0 07'
20 : 7-bit positive integer (32)
ca : 32-bit floating point number
00 00 e0 3f : 1.75f
a4 : 4 bytes string
4a 65 66 66 : "Jeff"
cf : 64-bit unsigned integer
de c0 ad de ef be ad de : 0xDEADBEEFDEADC0DE
93 : array of 3 elements
45 : 7-bit positive integer (69)
d1 : 16-bit signed integer
a4 01 : 420
d1 : 16-bit signed integer
c0 07 : 1984
boolint8_t,int16_t,int32_t,int64_tuint8_t,uint16_t,uint32_t,uint64_tfloat,doubleconst char *- to simplify deserialization, raw C-strings are serialized WITH null terminator. This goes against MessagePack rules and might break interoperability with other libraries. If you do not like this behaviour, use
std::stringorstd::string_viewinstead!
- to simplify deserialization, raw C-strings are serialized WITH null terminator. This goes against MessagePack rules and might break interoperability with other libraries. If you do not like this behaviour, use
Unless you are using MSVC compiler, support for individual STL container types must be manually enabled:
std::array- define
SBP_STL_ARRAY
- define
std::string- define
SBP_STL_STRING
- define
std::string_view- define
SBP_STL_STRING_VIEW
- define
std::vector- define
SBP_STL_VECTOR
- define
std::map- define
SBP_STL_MAP
- define
std::unordered_map- define
SBP_STL_UNORDERED_MAP
- define
struct Person final
{
std::string name;
int age;
float weight;
};
namespace sbp::detail {
void write(buffer &b, const Person &value) SBP_NOEXCEPT
{
write_multiple(b, name, age, weight);
}
error read(buffer &b, Person &value) SBP_NOEXCEPT
{
return read_multiple(b, name, age, weight);
}
} // namespace sbp::detail
struct NuclearFamily final
{
std::array<Person, 2> parents;
std::vector<Person> children;
};
NuclearFamily fam = ...;
sbp::buffer buff;
sbp::write(buff, fam);Simple POD types can be stored in ext format, which is basically just a byte type ID followed by binary data. Use SBP_EXTENSION macro to automatically generate code of sbp::detail::write and sbp::detail::read functions for your types:
struct Vector2D final { float x, y; };
struct Vector3D final { float x, y, z; };
struct Vector4D final { float x, y, z, w; };
SBP_EXTENSION(Vector2D, 1)
SBP_EXTENSION(Vector3D, 2)
SBP_EXTENSION(Vector4D, 3)
struct Mesh final
{
std::string name;
Vector4D diffuseColor;
Vector3D aabbMin, aabbMax;
std::vector<Vector3D> vertices;
std::vector<Vector2D> texCoords;
};
Mesh m = ...;
sbp::buffer buff;
sbp::write(buff, m);- library does not care about endianness
- no STL streams or allocators support (but feel free to roll your own
sbp::bufferimplementation) - error reporting is very primitive, no exceptions used
- inheritance does not work, use composition instead
- C-style arrays do not work, use
std::arrayinstead - if you really want to use inheritance (or even C-style arrays), you have to provide template specializations for
std::tuple_size,std::tuple_elementandstd::get
- structured binding code idea originally taken from avakar/destructure
- binary serialization follows MessagePack format (to some extent)