Sane C++ Libraries
C++ Platform Abstraction Libraries
SC::SerializationBinary Struct Reference

Loads or writes binary data with its associated reflection schema from or into a C++ object. More...

#include <SerializationBinary.h>

Static Public Member Functions

template<typename T >
static bool write (T &value, Vector< uint8_t > &buffer, size_t *numberOfWrites=nullptr)
 Writes object T to a binary buffer. More...
 
template<typename T >
static bool loadExact (T &value, Span< const uint8_t > buffer, size_t *numberOfReads=nullptr)
 Loads object T from binary buffer as written by SerializationBinary::write. More...
 
template<typename T >
static bool loadVersioned (T &value, Span< const uint8_t > buffer, Span< const Reflection::TypeInfo > schema, SerializationBinaryOptions options={}, size_t *numberOfReads=nullptr)
 Deserialize object T from a Binary buffer with a reflection schema not matching T schema. More...
 
template<typename T >
static bool writeWithSchema (T &value, Vector< uint8_t > &buffer, size_t *numberOfWrites=nullptr)
 Writes the reflection schema of object T followed by contents of object T to a binary buffer. More...
 
template<typename T >
static bool loadVersionedWithSchema (T &value, Span< const uint8_t > buffer, SerializationBinaryOptions options={}, size_t *numberOfReads=nullptr)
 Loads object T using the schema information that has been prepended by SerializationBinary::writeWithSchema. More...
 

Detailed Description

Loads or writes binary data with its associated reflection schema from or into a C++ object.

Member Function Documentation

◆ loadExact()

template<typename T >
static bool SC::SerializationBinary::loadExact ( T &  value,
Span< const uint8_t buffer,
size_t numberOfReads = nullptr 
)
inlinestatic

Loads object T from binary buffer as written by SerializationBinary::write.

SC::SerializationBinary::loadExact can deserialize binary data into a struct whose schema has not changed from when SerializationBinary::write has been used to generate that same binary data. In other words if the schema of the type passed to SerializationBinary::write must match the one of current type being deserialized. If the two schemas hash match then it's possible to use this fast path, that skips all versioning checks.

Template Parameters
TType of object to be deserialized (must be described by Reflection)
Parameters
valueThe object to be deserialized
bufferThe buffer holding actual bytes for deserialization
numberOfReadsIf provided, will return the number deserialization operations
Returns
true if deserialization succeeded

Assuming the following structs:

struct SC::SerializationSuiteTest::PrimitiveStruct
{
uint8_t arrayValue[4] = {0, 1, 2, 3};
float floatValue = 1.5f;
int64_t int64Value = -13;
bool operator!=(const PrimitiveStruct& other) const
{
for (size_t i = 0; i < TypeTraits::SizeOfArray(arrayValue); ++i)
{
if (arrayValue[i] != other.arrayValue[i])
return true;
}
if (floatValue != other.floatValue)
return true;
if (int64Value != other.int64Value)
return true;
return false;
}
};
SC_REFLECT_STRUCT_VISIT(SC::SerializationSuiteTest::PrimitiveStruct)
SC_REFLECT_STRUCT_FIELD(0, arrayValue)
SC_REFLECT_STRUCT_FIELD(1, floatValue)
SC_REFLECT_STRUCT_FIELD(2, int64Value)
SC_REFLECT_STRUCT_LEAVE()
struct SC::SerializationSuiteTest::NestedStruct
{
int16_t int16Value = 244;
PrimitiveStruct structsArray[2];
double doubleVal = -1.24;
Array<int, 7> arrayInt = {1, 2, 3, 4, 5, 6};
bool operator!=(const NestedStruct& other) const
{
if (int16Value != other.int16Value)
return true;
for (size_t i = 0; i < TypeTraits::SizeOfArray(structsArray); ++i)
if (structsArray[i] != other.structsArray[i])
return true;
if (doubleVal != other.doubleVal)
return true;
return false;
}
};
SC_REFLECT_STRUCT_VISIT(SC::SerializationSuiteTest::NestedStruct)
SC_REFLECT_STRUCT_FIELD(0, int16Value)
SC_REFLECT_STRUCT_FIELD(1, structsArray)
SC_REFLECT_STRUCT_FIELD(2, doubleVal)
SC_REFLECT_STRUCT_LEAVE()
struct SC::SerializationSuiteTest::TopLevelStruct
{
NestedStruct nestedStruct;
bool operator!=(const TopLevelStruct& other) const { return nestedStruct != other.nestedStruct; }
};
SC_REFLECT_STRUCT_VISIT(SC::SerializationSuiteTest::TopLevelStruct)
SC_REFLECT_STRUCT_FIELD(0, nestedStruct)
SC_REFLECT_STRUCT_LEAVE()
constexpr auto SizeOfArray(const T(&)[N])
SizeOfArray is a constexpr function that returns the compile-time size N of a plain C array.
Definition: TypeTraits.h:76
unsigned char uint8_t
Platform independent (1) byte unsigned int.
Definition: PrimitiveTypes.h:36
long long int64_t
Platform independent (8) bytes signed int.
Definition: PrimitiveTypes.h:50
short int16_t
Platform independent (2) bytes signed int.
Definition: PrimitiveTypes.h:45

TopLevelStruct can be serialized and de-serialized with the following code:

TopLevelStruct objectToSerialize;
TopLevelStruct deserializedObject;
// Change a field just as a test
objectToSerialize.nestedStruct.doubleVal = 44.4;
// Serialization
Vector buffer;
SC_TRY(SerializerWriter::write(objectToSerialize, buffer));
// Deserialization
SC_TRY(SerializerReader::loadExact(deserializedObject, buffer.toSpanConst()));
SC_ASSERT_RELEASE(objectToSerialize.nestedStruct.doubleVal == deserializedObject.nestedStruct.doubleVal);
#define SC_ASSERT_RELEASE(e)
Assert expression e to be true.
Definition: Assert.h:66
#define SC_TRY(expression)
Checks the value of the given expression and if failed, returns this value to caller.
Definition: Result.h:47

◆ loadVersioned()

template<typename T >
static bool SC::SerializationBinary::loadVersioned ( T &  value,
Span< const uint8_t buffer,
Span< const Reflection::TypeInfo schema,
SerializationBinaryOptions  options = {},
size_t numberOfReads = nullptr 
)
inlinestatic

Deserialize object T from a Binary buffer with a reflection schema not matching T schema.

The versioned read serializer SC::SerializationBinary::loadVersioned must be used when source and destination schemas do not match. Compatibility flags can be customized through SC::SerializationBinaryOptions object, allowing to remap data coming from an older (or just different) version of the schema to the current one. SerializationBinary::loadVersioned will try to match the memberTag field specified in [Reflection](Reflection) to match fields between source and destination schemas. When the types of the fields are different, a few options allow controlling the behaviour.

Template Parameters
TType of object to be deserialized (must be described by Reflection)
Parameters
valueThe object to deserialize
bufferThe buffer holding the bytes to be used for deserialization
schemaThe schema used to serialize data in the buffer
numberOfReadsIf provided, will return the number deserialization operations
optionsOptions for data conversion (allow dropping fields, array items etc)
Returns
true if deserialization succeeded


Assuming the following structs:

struct SC::SerializationSuiteTest::VersionedStruct1
{
float floatValue = 1.5f;
int64_t fieldToRemove = 12;
Vector<String> field2ToRemove = {"ASD1", "ASD2", "ASD3"};
int64_t int64Value = -13;
};
SC_REFLECT_STRUCT_VISIT(SC::SerializationSuiteTest::VersionedStruct1)
SC_REFLECT_STRUCT_FIELD(2, field2ToRemove)
SC_REFLECT_STRUCT_FIELD(0, floatValue)
SC_REFLECT_STRUCT_FIELD(1, fieldToRemove)
SC_REFLECT_STRUCT_FIELD(3, int64Value)
SC_REFLECT_STRUCT_LEAVE()
struct SC::SerializationSuiteTest::VersionedStruct2
{
int64_t int64Value = 55;
float floatValue = -2.9f;
bool operator!=(const VersionedStruct1& other) const
{
if (floatValue != other.floatValue)
return true;
if (int64Value != other.int64Value)
return true;
return false;
}
};
SC_REFLECT_STRUCT_VISIT(SC::SerializationSuiteTest::VersionedStruct2)
SC_REFLECT_STRUCT_FIELD(3, int64Value)
SC_REFLECT_STRUCT_FIELD(0, floatValue)
SC_REFLECT_STRUCT_LEAVE()

VersionedStruct2 can be deserialized from VersionedStruct1 in the following way

constexpr auto schema = SerializerSchemaCompiler::template compile<VersionedStruct1>();
VersionedStruct1 objectToSerialize;
VersionedStruct2 deserializedObject;
// Serialization
Vector buffer;
SC_TRY(SerializerWriter::write(objectToSerialize, buffer));
// Deserialization
SC_TRY(SerializerReader::loadVersioned(deserializedObject, buffer.toSpanConst(), schema.typeInfos));

◆ loadVersionedWithSchema()

template<typename T >
static bool SC::SerializationBinary::loadVersionedWithSchema ( T &  value,
Span< const uint8_t buffer,
SerializationBinaryOptions  options = {},
size_t numberOfReads = nullptr 
)
inlinestatic

Loads object T using the schema information that has been prepended by SerializationBinary::writeWithSchema.

The schema allows a "best effort" de-serialization trying to match fields with corresponding memberTag.

See also
SerializationBinary::loadVersioned
SerializationBinary::writeWithSchema

◆ write()

template<typename T >
static bool SC::SerializationBinary::write ( T &  value,
Vector< uint8_t > &  buffer,
size_t numberOfWrites = nullptr 
)
inlinestatic

Writes object T to a binary buffer.

SC::SerializationBinary::write is used to serialize data. The schema itself is not used at all but it could written along with the binary data so that when reading back the data in a later version of the program, the correct choice can be made between deserializing using SerializationBinary::loadVersioned (slower but allows for missing fields and conversion) or deserializing using SerializationBinary::loadExact (faster, but schema must match 1:1).

Template Parameters
TType of object to be serialized (must be described by Reflection)
Parameters
valueThe object to be serialized
bufferThe buffer that will receive serialized bytes
numberOfWritesIf provided, will return the number of serialization operations
Returns
true if serialization succeeded

Assuming the following struct:

struct SC::SerializationSuiteTest::PrimitiveStruct
{
uint8_t arrayValue[4] = {0, 1, 2, 3};
float floatValue = 1.5f;
int64_t int64Value = -13;
bool operator!=(const PrimitiveStruct& other) const
{
for (size_t i = 0; i < TypeTraits::SizeOfArray(arrayValue); ++i)
{
if (arrayValue[i] != other.arrayValue[i])
return true;
}
if (floatValue != other.floatValue)
return true;
if (int64Value != other.int64Value)
return true;
return false;
}
};
SC_REFLECT_STRUCT_VISIT(SC::SerializationSuiteTest::PrimitiveStruct)
SC_REFLECT_STRUCT_FIELD(0, arrayValue)
SC_REFLECT_STRUCT_FIELD(1, floatValue)
SC_REFLECT_STRUCT_FIELD(2, int64Value)
SC_REFLECT_STRUCT_LEAVE()

PrimitiveStruct can be written to a binary buffer with the following code:

PrimitiveStruct objectToSerialize;
Vector buffer;
SC_TRY(SerializerWriter::write(objectToSerialize, buffer));

◆ writeWithSchema()

template<typename T >
static bool SC::SerializationBinary::writeWithSchema ( T &  value,
Vector< uint8_t > &  buffer,
size_t numberOfWrites = nullptr 
)
inlinestatic

Writes the reflection schema of object T followed by contents of object T to a binary buffer.

The serialized buffer can be used with SerializationBinary::loadVersionedWithSchema to allow a "best effort" de-serialization trying to match fields with corresponding memberTag.

See also
SerializationBinary::write
SerializationBinary::loadVersionedWithSchema

The documentation for this struct was generated from the following file: