Closed MatchPointDarko closed 5 years ago
@MatchPointDarko I didn't forget about it, I just got a little busy with another project, I plan to check the variant recursive vs O(1) implementation and merge when done.
Not needed anymore.. i see this project is abandoned.. i'm using mike-serializer: https://github.com/MatchPointDarko/serializer
@MatchPointDarko Here is my take on similar change, with no recursions:
/**
* Serialize std::optional, operates on loading (input) archives.
*/
template <typename Archive,
typename Type,
typename...,
typename = typename Archive::loading>
void serialize(Archive & archive, std::optional<Type> & optional)
{
// Load whether has value.
bool has_value{};
archive(has_value);
// If does not have a value.
if (!has_value) {
optional = std::nullopt;
return;
}
// If the type is default constructible.
if constexpr (std::is_default_constructible_v<Type>) {
// Create the value if does not exist.
if (!optional) {
optional = Type{};
}
// Load the value.
archive(*optional);
} else {
// The object storage.
std::aligned_storage_t<sizeof(Type), alignof(Type)> storage;
// Create the object at the storage.
std::unique_ptr<Type, void (*)(Type *)> object(
access::placement_new<Type>(std::addressof(storage)),
[](auto pointer) { access::destruct(*pointer); });
// Load the object.
archive(*object);
// Assign the loaded object.
optional = std::move(*object);
}
}
/**
* Serialize std::optional, operates on saving (output) archives.
*/
template <typename Archive,
typename Type,
typename...,
typename = typename Archive::saving>
void serialize(Archive & archive, const std::optional<Type> & optional)
{
// Save has value.
bool has_value = optional.has_value();
// If has value, save it.
if (has_value) {
archive(has_value, *optional);
} else {
archive(has_value);
}
}
/**
* Serialize std::variant, operates on loading (input) archives.
*/
template <typename Archive,
typename... Types,
typename = typename Archive::loading>
void serialize(Archive & archive, std::variant<Types...> & variant)
{
// Test for maximum number of types.
static_assert(sizeof...(Types) < 0xff, "Max variant types reached.");
// The variant index.
unsigned char index{};
// Load the index.
archive(index);
// Check that loaded index is inside bounds.
if (index >= sizeof...(Types)) {
throw variant_index_out_of_range("Variant index out of range");
}
// The variant type.
using variant_type = std::variant<Types...>;
// Loader type.
using loader_type =
void (*)(Archive & archive, variant_type & variant);
// Loaders per variant index.
static constexpr loader_type loaders[] = {[](auto & archive,
auto & variant) {
// If the type is default constructible.
if constexpr (std::is_default_constructible_v<Types>) {
// If does not have the needed type, assign it.
if (!std::get_if<Types>(&variant)) {
variant = Types{};
}
// Load the value.
archive(*std::get_if<Types>(&variant));
} else {
// The object storage.
std::aligned_storage_t<sizeof(Types), alignof(Types)> storage;
// Create the object at the storage.
std::unique_ptr<Types, void (*)(Types *)> object(
access::placement_new<Types>(std::addressof(storage)),
[](auto pointer) { access::destruct(*pointer); });
// Load the object.
archive(*object);
// Assign the loaded object.
variant = std::move(*object);
}
}...};
// Execute the appropriate loader.
loaders[index](archive, variant);
}
/**
* Serialize std::variant, operates on saving (output) archives.
*/
template <typename Archive,
typename... Types,
typename = typename Archive::saving>
void serialize(Archive & archive, const std::variant<Types...> & variant)
{
// Test for maximum number of types.
static_assert(sizeof...(Types) < 0xff, "Max variant types reached.");
// The variant index.
auto variant_index = variant.index();
// Disallow serializations of valueless variant.
if (std::variant_npos == variant_index) {
throw attempt_to_serialize_valueless_variant(
"Cannot serialize a valueless variant.");
}
// The index to save.
auto index = static_cast<unsigned char>(variant_index & 0xff);
// Save the variant object.
std::visit(
[index, &archive](auto & object) { archive(index, object); },
variant);
}
I propose a serialization implementation for std::variant and std::optional here.