-
Notifications
You must be signed in to change notification settings - Fork 124
Serialization Reference
The following data structures exist in the namespaces cista::offset
and cista::raw
:
-
vector<T>
: serializable version ofstd::vector<T>
-
string
: serializable version ofstd::string
-
unique_ptr<T>
: serializable version ofstd::unique_ptr<T>
-
hash_map<K, V>
: serializable version ofstd::unordered_map
(using Google's Swiss Table) -
ptr<T>
: serializable pointer:cista::raw::ptr<T>
is just aT*
,cista::offset::ptr<T>
is a specialized data structure that behaves mostly like aT*
(overloaded->
,*
, etc. operators).
Currently, they do not provide exactly the same interface as their std::
equivalents.
A cista::ptr<T>
can only point to null
or to a value stored in the serialized buffer. Pointing to a value within the serialized buffer requires that the offset it was written at is known at serialization time.
There are three ways to index an address in order to serialize a pointer to it:
-
cista::unique_ptr<T>
: Everycista::unique_ptr<T>
will be indexed. Thus, pointing to values held by acista::unique_ptr<T>
is possible. -
cista::indexed_vector<T>
: Within acista::indexed_vector<T>
, every value can be referenced. This is more efficient than acista::vector<cista::unique_ptr<T>>
. However,cista::vector<T>
andcista::indexed_vector<T>
do not provide pointer stability after non-const operations such asresize
, oremplace_back
. -
cista::indexed<T>
: To be able to point to the value of member variables, it is possible to usecista::indexed<T>
.cista::indexed<T>
inherits fromT
and thus can be used just like aT
.
An example using cista::indexed_vector<T>
and cista::indexed<T>
:
namespace data = cista::offset;
struct node;
struct edge {
data::ptr<node> from_;
data::ptr<node> to_;
};
struct node {
uint32_tid_{0};
data::vector<data::ptr<edge>> edges_;
cista::indexed<data::string> name_;
};
struct graph {
data::indexed_vector<node> nodes_;
data::indexed_vector<edge> edges_;
data::vector<data::ptr<data::string>> node_names_;
};
Serialization and deserialiazation have to use the same mode. This can be ensured by storing the mode in a constexpr
variable. This variable can then be passed to cista::serialize()
and cista::deserialize()
.
The cista::mode
enum provides the following values:
-
NONE
- default mode (default values are listed below) -
UNCHECKED
- do no bounds checks for types (only affects deserialization) -
WITH_VERSION
- store the data structure version (8 byte), default value: off -
WITH_INTEGRITY
- store a hash sum of the serialized data (8 byte), default value: off -
SERIALIZE_BIG_ENDIAN
- use big endian format when serializing (default: little endian) -
DEEP_CHECK
- apply deep checking for security (only affects deserialization) -
CAST
- casts the buffer pointer (with compile time checks that the buffer stays unmodified: no endian conversion and only offset pointer data structures)
The stored data structure version (cista::mode::WITH_VERSION
) and hash sum (cista::mode::WITH_INTEGRITY
) are checked at deserialization (if available).
Note that you cannot store the integrity checksum and/or data structure version and omit the flag at deserialization because they affect where the actual data starts.
These values work as a bit mask.
Example:
constexpr auto const MODE = cista::mode::WITH_VERSION |
cista::mode::WITH_INTEGRITY |
cista::mode::DEEP_CHECK;
The following methods can be used to serialize either to a std::vector<uint8_t>
(default) or to an arbitrary serialization target.
-
std::vector<uint8_t> cista::serialize<mode Mode = mode::NONE, T>(T const&)
serializes an object of typeT
and returns a buffer containing the serialized object. -
void cista::serialize<mode const Mode = mode::NONE, Target, T>(Target&, T const&)
serializes an object of typeT
to the specified target. Targets are eithercista::buf<Buf>
(whereBuf
can either be a simplestd::vector<uint8_t>
or acista::mmap
) orcista::file
. Custom target structs should providewrite
functions as described here.
The following functions exist in cista::offset
and cista::raw
:
-
T* deserialize<T, cista::mode Mode = cista::mode::NONE, Container>(Container&)
deserializes an object from astd::vector<uint8_t>
or similar data structure. This function throws astd::runtimer_error
if the data is not well-formed. -
T* deserialize<T, cista::mode Mode = cista::mode::NONE>(uint8_t* from, uint8_t* to)
deserializes an object from a pointer range. This function throws astd::runtimer_error
if the data is not well-formed. -
reinterpret_cast<T>(ptr)
: If you are using offset mode and the machine endian format is the same as the serialized one, you may as well just call callreinterpret_cast<T>(ptr)
.