mesytec-mnode/external/taskflow-3.8.0/sandbox/utility/serializer.hpp
2025-01-04 01:25:05 +01:00

1135 lines
29 KiB
C++

#pragma once
#include <type_traits>
#include <iterator>
#include <iostream>
#include <fstream>
#include <stack>
#include <queue>
#include <vector>
#include <algorithm>
#include <memory>
#include <functional>
#include <map>
#include <set>
#include <unordered_map>
#include <unordered_set>
#include <sstream>
#include <list>
#include <forward_list>
#include <numeric>
#include <iomanip>
#include <cassert>
#include <cmath>
#include <array>
#include <string>
#include <variant>
#include <optional>
namespace tf {
// ----------------------------------------------------------------------------
// Supported C++ STL type
// ----------------------------------------------------------------------------
// std::basic_string
template <typename T>
struct is_std_basic_string : std::false_type {};
template <typename... ArgsT>
struct is_std_basic_string <std::basic_string<ArgsT...>> : std::true_type {};
template <typename T>
constexpr bool is_std_basic_string_v = is_std_basic_string<T>::value;
// std::array
template <typename T>
struct is_std_array : std::false_type {};
template <typename T, size_t N>
struct is_std_array <std::array<T, N>> : std::true_type {};
template <typename T>
constexpr bool is_std_array_v = is_std_array<T>::value;
// std::vector
template <typename T>
struct is_std_vector : std::false_type {};
template <typename... ArgsT>
struct is_std_vector <std::vector<ArgsT...>> : std::true_type {};
template <typename T>
constexpr bool is_std_vector_v = is_std_vector<T>::value;
// std::deque
template <typename T>
struct is_std_deque : std::false_type {};
template <typename... ArgsT>
struct is_std_deque <std::deque<ArgsT...>> : std::true_type {};
template <typename T>
constexpr bool is_std_deque_v = is_std_deque<T>::value;
// std::list
template <typename T>
struct is_std_list : std::false_type {};
template <typename... ArgsT>
struct is_std_list <std::list<ArgsT...>> : std::true_type {};
template <typename T>
constexpr bool is_std_list_v = is_std_list<T>::value;
// std::forward_list
template <typename T>
struct is_std_forward_list : std::false_type {};
template <typename... ArgsT>
struct is_std_forward_list <std::forward_list<ArgsT...>> : std::true_type {};
template <typename T>
constexpr bool is_std_forward_list_v = is_std_forward_list<T>::value;
// std::map
template <typename T>
struct is_std_map : std::false_type {};
template <typename... ArgsT>
struct is_std_map <std::map<ArgsT...>> : std::true_type {};
template <typename T>
constexpr bool is_std_map_v = is_std_map<T>::value;
// std::unordered_map
template <typename T>
struct is_std_unordered_map : std::false_type {};
template <typename... ArgsT>
struct is_std_unordered_map <std::unordered_map<ArgsT...>> : std::true_type {};
template <typename T>
constexpr bool is_std_unordered_map_v = is_std_unordered_map<T>::value;
// std::set
template <typename T>
struct is_std_set : std::false_type {};
template <typename... ArgsT>
struct is_std_set <std::set<ArgsT...>> : std::true_type {};
template <typename T>
constexpr bool is_std_set_v = is_std_set<T>::value;
// std::unordered_set
template <typename T>
struct is_std_unordered_set : std::false_type {};
template <typename... ArgsT>
struct is_std_unordered_set <std::unordered_set<ArgsT...>> : std::true_type {};
template <typename T>
constexpr bool is_std_unordered_set_v = is_std_unordered_set<T>::value;
// std::variant
template <typename T>
struct is_std_variant : std::false_type {};
template <typename... ArgsT>
struct is_std_variant <std::variant<ArgsT...>> : std::true_type {};
template <typename T>
constexpr bool is_std_variant_v = is_std_variant<T>::value;
// std::optional
template <typename T>
struct is_std_optional : std::false_type {};
template <typename... ArgsT>
struct is_std_optional <std::optional<ArgsT...>> : std::true_type {};
template <typename T>
constexpr bool is_std_optional_v = is_std_optional<T>::value;
// std::unique_ptr
template <typename T>
struct is_std_unique_ptr : std::false_type {};
template <typename... ArgsT>
struct is_std_unique_ptr <std::unique_ptr<ArgsT...>> : std::true_type {};
template <typename T>
constexpr bool is_std_unique_ptr_v = is_std_unique_ptr<T>::value;
// std::shared_ptr
template <typename T>
struct is_std_shared_ptr : std::false_type {};
template <typename... ArgsT>
struct is_std_shared_ptr <std::shared_ptr<ArgsT...>> : std::true_type {};
template <typename T>
constexpr bool is_std_shared_ptr_v = is_std_shared_ptr<T>::value;
// std::duration
template <typename T> struct is_std_duration : std::false_type {};
template <typename... ArgsT>
struct is_std_duration<std::chrono::duration<ArgsT...>> : std::true_type {};
template <typename T>
constexpr bool is_std_duration_v = is_std_duration<T>::value;
// std::time_point
template <typename T>
struct is_std_time_point : std::false_type {};
template <typename... ArgsT>
struct is_std_time_point<std::chrono::time_point<ArgsT...>> : std::true_type {};
template <typename T>
constexpr bool is_std_time_point_v = is_std_time_point<T>::value;
// std::tuple
template <typename T>
struct is_std_tuple : std::false_type {};
template <typename... ArgsT>
struct is_std_tuple<std::tuple<ArgsT...>> : std::true_type {};
template <typename T>
constexpr bool is_std_tuple_v = is_std_tuple<T>::value;
//-----------------------------------------------------------------------------
// Type extraction.
//-----------------------------------------------------------------------------
// ExtractType: forward declaration
template <size_t, typename>
struct ExtractType;
// ExtractType_t: alias interface
template <size_t idx, typename C>
using ExtractType_t = typename ExtractType<idx, C>::type;
// ExtractType: base
template <template <typename...> typename C, typename T, typename... RestT>
struct ExtractType <0, C<T, RestT...>> {
using type = T;
};
// ExtractType: base
template <typename T>
struct ExtractType <0, T> {
using type = T;
};
// ExtractType: recursive definition.
template <size_t idx, template <typename...> typename C, typename T, typename... RestT>
struct ExtractType <idx, C<T, RestT...>> : ExtractType<idx-1, C<RestT...>> {
};
// ----------------------------------------------------------------------------
// Size Wrapper
// ----------------------------------------------------------------------------
// Struct: SizeTag
// Class that wraps a given size item which can be customized.
template <typename T>
class SizeTag {
public:
using type = std::conditional_t<std::is_lvalue_reference_v<T>, T, std::decay_t<T>>;
SizeTag(T&& item) : _item(std::forward<T>(item)) {}
SizeTag& operator = (const SizeTag&) = delete;
inline const T& get() const {return _item;}
template <typename ArchiverT>
auto save(ArchiverT & ar) const { return ar(_item); }
template <typename ArchiverT>
auto load(ArchiverT & ar) { return ar(_item); }
private:
type _item;
};
// Function: make_size_tag
template <typename T>
SizeTag<T> make_size_tag(T&& t) {
return { std::forward<T>(t) };
}
// ----------------------------------------------------------------------------
// Size Wrapper
// ----------------------------------------------------------------------------
// Class: MapItem
template <typename KeyT, typename ValueT>
class MapItem {
public:
using KeyType = std::conditional_t <std::is_lvalue_reference_v<KeyT>, KeyT, std::decay_t<KeyT>>;
using ValueType = std::conditional_t <std::is_lvalue_reference_v<ValueT>, ValueT, std::decay_t<ValueT>>;
MapItem(KeyT&& k, ValueT&& v) : _key(std::forward<KeyT>(k)), _value(std::forward<ValueT>(v)) {}
MapItem& operator = (const MapItem&) = delete;
inline const KeyT& key() const { return _key; }
inline const ValueT& value() const { return _value; }
template <typename ArchiverT>
auto save(ArchiverT & ar) const { return ar(_key, _value); }
template <typename ArchiverT>
auto load(ArchiverT & ar) { return ar(_key, _value); }
private:
KeyType _key;
ValueType _value;
};
// Function: make_kv_pair
template <typename KeyT, typename ValueT>
MapItem<KeyT, ValueT> make_kv_pair(KeyT&& k, ValueT&& v) {
return { std::forward<KeyT>(k), std::forward<ValueT>(v) };
}
// ----------------------------------------------------------------------------
// Serializer Definition
// ----------------------------------------------------------------------------
template <typename T>
constexpr auto is_default_serializable_v = (
std::is_arithmetic_v<T> ||
std::is_enum_v<T> ||
is_std_basic_string_v<T> ||
is_std_vector_v<T> ||
is_std_deque_v<T> ||
is_std_list_v<T> ||
is_std_forward_list_v<T> ||
is_std_map_v<T> ||
is_std_unordered_map_v<T> ||
is_std_set_v<T> ||
is_std_unordered_set_v<T> ||
is_std_duration_v<T> ||
is_std_time_point_v<T> ||
is_std_variant_v<T> ||
is_std_optional_v<T> ||
is_std_tuple_v<T> ||
is_std_array_v<T>
);
// Class: Serializer
template <typename Stream, typename SizeType = std::streamsize>
class Serializer {
public:
Serializer(Stream& stream);
template <typename... T>
SizeType operator()(T&&... items);
private:
Stream& _stream;
template <typename T,
std::enable_if_t<!is_default_serializable_v<std::decay_t<T>>, void>* = nullptr
>
SizeType _save(T&&);
template <typename T,
std::enable_if_t<std::is_arithmetic_v<std::decay_t<T>>, void>* = nullptr
>
SizeType _save(T&&);
template <typename T,
std::enable_if_t<is_std_basic_string_v<std::decay_t<T>>, void>* = nullptr
>
SizeType _save(T&&);
template <typename T,
std::enable_if_t<is_std_vector_v<std::decay_t<T>>, void>* = nullptr
>
SizeType _save(T&&);
template <typename T,
std::enable_if_t<
is_std_deque_v<std::decay_t<T>> ||
is_std_list_v<std::decay_t<T>>,
void
>* = nullptr
>
SizeType _save(T&&);
template <typename T,
std::enable_if_t<
is_std_forward_list_v<std::decay_t<T>>,
void
>* = nullptr
>
SizeType _save(T&&);
template <typename T,
std::enable_if_t<
is_std_map_v<std::decay_t<T>> ||
is_std_unordered_map_v<std::decay_t<T>>,
void
>* = nullptr
>
SizeType _save(T&&);
template <typename T,
std::enable_if_t<
is_std_set_v<std::decay_t<T>> ||
is_std_unordered_set_v<std::decay_t<T>>,
void
>* = nullptr
>
SizeType _save(T&&);
template <typename T,
std::enable_if_t<std::is_enum_v<std::decay_t<T>>, void>* = nullptr
>
SizeType _save(T&&);
template <typename T,
std::enable_if_t<is_std_duration_v<std::decay_t<T>>, void>* = nullptr
>
SizeType _save(T&&);
template <typename T,
std::enable_if_t<is_std_time_point_v<std::decay_t<T>>, void>* = nullptr
>
SizeType _save(T&&);
template <typename T,
std::enable_if_t<is_std_optional_v<std::decay_t<T>>, void>* = nullptr
>
SizeType _save(T&&);
template <typename T,
std::enable_if_t<is_std_variant_v<std::decay_t<T>>, void>* = nullptr
>
SizeType _save(T&&);
template <typename T,
std::enable_if_t<is_std_tuple_v<std::decay_t<T>>, void>* = nullptr
>
SizeType _save(T&&);
template <typename T,
std::enable_if_t<is_std_array_v<std::decay_t<T>>, void>* = nullptr
>
SizeType _save(T&&);
};
// Constructor
template <typename Stream, typename SizeType>
Serializer<Stream, SizeType>::Serializer(Stream& stream) : _stream(stream) {
}
// Operator ()
template <typename Stream, typename SizeType>
template <typename... T>
SizeType Serializer<Stream, SizeType>::operator() (T&&... items) {
return (_save(std::forward<T>(items)) + ...);
}
// arithmetic data type
template <typename Stream, typename SizeType>
template <typename T,
std::enable_if_t<std::is_arithmetic_v<std::decay_t<T>>, void>*
>
SizeType Serializer<Stream, SizeType>::_save(T&& t) {
_stream.write(reinterpret_cast<const char*>(std::addressof(t)), sizeof(t));
return sizeof(t);
}
// std::basic_string
template <typename Stream, typename SizeType>
template <typename T,
std::enable_if_t<is_std_basic_string_v<std::decay_t<T>>, void>*
>
SizeType Serializer<Stream, SizeType>::_save(T&& t) {
using U = std::decay_t<T>;
auto sz = _save(make_size_tag(t.size()));
_stream.write(
reinterpret_cast<const char*>(t.data()),
t.size()*sizeof(typename U::value_type)
);
return sz + t.size()*sizeof(typename U::value_type);
}
// std::vector
template <typename Stream, typename SizeType>
template <typename T,
std::enable_if_t<is_std_vector_v<std::decay_t<T>>, void>*
>
SizeType Serializer<Stream, SizeType>::_save(T&& t) {
using U = std::decay_t<T>;
auto sz = _save(make_size_tag(t.size()));
if constexpr (std::is_arithmetic_v<typename U::value_type>) {
_stream.write(
reinterpret_cast<const char*>(t.data()),
t.size() * sizeof(typename U::value_type)
);
sz += t.size() * sizeof(typename U::value_type);
} else {
for(auto&& item : t) {
sz += _save(item);
}
}
return sz;
}
// std::list and std::deque
template <typename Stream, typename SizeType>
template <typename T,
std::enable_if_t<is_std_deque_v<std::decay_t<T>> ||
is_std_list_v<std::decay_t<T>>, void>*
>
SizeType Serializer<Stream, SizeType>::_save(T&& t) {
auto sz = _save(make_size_tag(t.size()));
for(auto&& item : t) {
sz += _save(item);
}
return sz;
}
// std::forward_list
template <typename Stream, typename SizeType>
template <typename T,
std::enable_if_t<is_std_forward_list_v<std::decay_t<T>>, void>*
>
SizeType Serializer<Stream, SizeType>::_save(T&& t) {
auto sz = _save(make_size_tag(std::distance(t.begin(), t.end())));
for(auto&& item : t) {
sz += _save(item);
}
return sz;
}
// std::map and std::unordered_map
template <typename Stream, typename SizeType>
template <typename T, std::enable_if_t<
is_std_map_v<std::decay_t<T>> ||
is_std_unordered_map_v<std::decay_t<T>>,
void
>*>
SizeType Serializer<Stream, SizeType>::_save(T&& t) {
auto sz = _save(make_size_tag(t.size()));
for(auto&& [k, v] : t) {
sz += _save(make_kv_pair(k, v));
}
return sz;
}
// std::set and std::unordered_set
template <typename Stream, typename SizeType>
template <typename T, std::enable_if_t<
is_std_set_v<std::decay_t<T>> ||
is_std_unordered_set_v<std::decay_t<T>>,
void
>*>
SizeType Serializer<Stream, SizeType>::_save(T&& t) {
auto sz = _save(make_size_tag(t.size()));
for(auto&& item : t) {
sz += _save(item);
}
return sz;
}
// enum data type
template <typename Stream, typename SizeType>
template <typename T,
std::enable_if_t<std::is_enum_v<std::decay_t<T>>, void>*
>
SizeType Serializer<Stream, SizeType>::_save(T&& t) {
using U = std::decay_t<T>;
return _save(static_cast<std::underlying_type_t<U>>(t));
}
// duration data type
template <typename Stream, typename SizeType>
template <typename T,
std::enable_if_t<is_std_duration_v<std::decay_t<T>>, void>*
>
SizeType Serializer<Stream, SizeType>::_save(T&& t) {
return _save(t.count());
}
// time point data type
template <typename Stream, typename SizeType>
template <typename T,
std::enable_if_t<is_std_time_point_v<std::decay_t<T>>, void>*
>
SizeType Serializer<Stream, SizeType>::_save(T&& t) {
return _save(t.time_since_epoch());
}
// optional data type
template <typename Stream, typename SizeType>
template <typename T,
std::enable_if_t<is_std_optional_v<std::decay_t<T>>, void>*
>
SizeType Serializer<Stream, SizeType>::_save(T&& t) {
if(bool flag = t.has_value(); flag) {
return _save(flag) + _save(*t);
}
else {
return _save(flag);
}
}
// variant type
template <typename Stream, typename SizeType>
template <typename T,
std::enable_if_t<is_std_variant_v<std::decay_t<T>>, void>*
>
SizeType Serializer<Stream, SizeType>::_save(T&& t) {
return _save(t.index()) +
std::visit([&] (auto&& arg){ return _save(arg);}, t);
}
// tuple type
template <typename Stream, typename SizeType>
template <typename T,
std::enable_if_t<is_std_tuple_v<std::decay_t<T>>, void>*
>
SizeType Serializer<Stream, SizeType>::_save(T&& t) {
return std::apply(
[&] (auto&&... args) {
return (_save(std::forward<decltype(args)>(args)) + ... + 0);
},
std::forward<T>(t)
);
}
// array
template <typename Stream, typename SizeType>
template <typename T,
std::enable_if_t<is_std_array_v<std::decay_t<T>>, void>*
>
SizeType Serializer<Stream, SizeType>::_save(T&& t) {
using U = std::decay_t<T>;
static_assert(std::tuple_size<U>::value > 0, "Array size can't be zero");
SizeType sz;
if constexpr(std::is_arithmetic_v<typename U::value_type>) {
_stream.write(reinterpret_cast<const char*>(t.data()), sizeof(t));
sz = sizeof(t);
}
else {
sz = 0;
for(auto&& item : t) {
sz += _save(item);
}
}
return sz;
}
// custom save method
template <typename Stream, typename SizeType>
template <typename T,
std::enable_if_t<!is_default_serializable_v<std::decay_t<T>>, void>*
>
SizeType Serializer<Stream, SizeType>::_save(T&& t) {
return t.save(*this);
}
// ----------------------------------------------------------------------------
// DeSerializer Definition
// ----------------------------------------------------------------------------
template <typename T>
constexpr auto is_default_deserializable_v =
std::is_arithmetic_v<T> ||
std::is_enum_v<T> ||
is_std_basic_string_v<T> ||
is_std_vector_v<T> ||
is_std_deque_v<T> ||
is_std_list_v<T> ||
is_std_forward_list_v<T> ||
is_std_map_v<T> ||
is_std_unordered_map_v<T> ||
is_std_set_v<T> ||
is_std_unordered_set_v<T> ||
is_std_duration_v<T> ||
is_std_time_point_v<T> ||
is_std_variant_v<T> ||
is_std_optional_v<T> ||
is_std_tuple_v<T> ||
is_std_array_v<T>;
// Class: Deserializer
template <typename Stream, typename SizeType = std::streamsize>
class Deserializer {
public:
Deserializer(Stream& stream);
template <typename... T>
SizeType operator()(T&&... items);
private:
Stream& _stream;
// Function: _variant_helper
template <
size_t I = 0, typename... ArgsT,
std::enable_if_t<I==sizeof...(ArgsT)>* = nullptr
>
SizeType _variant_helper(size_t, std::variant<ArgsT...>&);
// Function: _variant_helper
template <
size_t I = 0, typename... ArgsT,
std::enable_if_t<I<sizeof...(ArgsT)>* = nullptr
>
SizeType _variant_helper(size_t, std::variant<ArgsT...>&);
template <typename T,
std::enable_if_t<std::is_arithmetic_v<std::decay_t<T>>, void>* = nullptr
>
SizeType _load(T&&);
template <typename T,
std::enable_if_t<is_std_basic_string_v<std::decay_t<T>>, void>* = nullptr
>
SizeType _load(T&&);
template <typename T,
std::enable_if_t<is_std_vector_v<std::decay_t<T>>, void>* = nullptr
>
SizeType _load(T&&);
template <typename T,
std::enable_if_t<
is_std_deque_v<std::decay_t<T>> ||
is_std_list_v<std::decay_t<T>> ||
is_std_forward_list_v<std::decay_t<T>>,
void
>* = nullptr
>
SizeType _load(T&&);
template <typename T,
std::enable_if_t<is_std_map_v<std::decay_t<T>>, void>* = nullptr
>
SizeType _load(T&&);
template <typename T,
std::enable_if_t<is_std_unordered_map_v<std::decay_t<T>>, void>* = nullptr
>
SizeType _load(T&&);
template <typename T,
std::enable_if_t<is_std_set_v<std::decay_t<T>>, void>* = nullptr
>
SizeType _load(T&&);
template <typename T,
std::enable_if_t<is_std_unordered_set_v<std::decay_t<T>>, void>* = nullptr
>
SizeType _load(T&&);
template <typename T,
std::enable_if_t<std::is_enum_v<std::decay_t<T>>, void>* = nullptr
>
SizeType _load(T&&);
template <typename T,
std::enable_if_t<is_std_duration_v<std::decay_t<T>>, void>* = nullptr
>
SizeType _load(T&&);
template <typename T,
std::enable_if_t<is_std_time_point_v<std::decay_t<T>>, void>* = nullptr
>
SizeType _load(T&&);
template <typename T,
std::enable_if_t<is_std_optional_v<std::decay_t<T>>, void>* = nullptr
>
SizeType _load(T&&);
template <typename T,
std::enable_if_t<is_std_variant_v<std::decay_t<T>>, void>* = nullptr
>
SizeType _load(T&&);
template <typename T,
std::enable_if_t<is_std_tuple_v<std::decay_t<T>>, void>* = nullptr
>
SizeType _load(T&&);
template <typename T,
std::enable_if_t<is_std_array_v<std::decay_t<T>>, void>* = nullptr
>
SizeType _load(T&&);
template <typename T,
std::enable_if_t<!is_default_deserializable_v<std::decay_t<T>>, void>* = nullptr
>
SizeType _load(T&&);
};
// Constructor
template <typename Stream, typename SizeType>
Deserializer<Stream, SizeType>::Deserializer(Stream& stream) : _stream(stream) {
}
// Operator ()
template <typename Stream, typename SizeType>
template <typename... T>
SizeType Deserializer<Stream, SizeType>::operator() (T&&... items) {
return (_load(std::forward<T>(items)) + ...);
}
// Function: _variant_helper
template <typename Stream, typename SizeType>
template <size_t I, typename... ArgsT, std::enable_if_t<I==sizeof...(ArgsT)>*>
SizeType Deserializer<Stream, SizeType>::_variant_helper(size_t, std::variant<ArgsT...>&) {
return 0;
}
// Function: _variant_helper
template <typename Stream, typename SizeType>
template <size_t I, typename... ArgsT, std::enable_if_t<I<sizeof...(ArgsT)>*>
SizeType Deserializer<Stream, SizeType>::_variant_helper(size_t i, std::variant<ArgsT...>& v) {
if(i == 0) {
using type = ExtractType_t<I, std::variant<ArgsT...>>;
if(v.index() != I) {
static_assert(
std::is_default_constructible<type>::value,
"Failed to archive variant (type should be default constructible T())"
);
v = type();
}
return _load(*std::get_if<type>(&v));
}
return _variant_helper<I+1, ArgsT...>(i-1, v);
}
// arithmetic data type
template <typename Stream, typename SizeType>
template <typename T,
std::enable_if_t<std::is_arithmetic_v<std::decay_t<T>>, void>*
>
SizeType Deserializer<Stream, SizeType>::_load(T&& t) {
_stream.read(reinterpret_cast<char*>(std::addressof(t)), sizeof(t));
return sizeof(t);
}
// std::basic_string
template <typename Stream, typename SizeType>
template <typename T,
std::enable_if_t<is_std_basic_string_v<std::decay_t<T>>, void>*
>
SizeType Deserializer<Stream, SizeType>::_load(T&& t) {
using U = std::decay_t<T>;
typename U::size_type num_chars;
auto sz = _load(make_size_tag(num_chars));
t.resize(num_chars);
_stream.read(reinterpret_cast<char*>(t.data()), num_chars*sizeof(typename U::value_type));
return sz + num_chars*sizeof(typename U::value_type);
}
// std::vector
template <typename Stream, typename SizeType>
template <typename T,
std::enable_if_t<is_std_vector_v<std::decay_t<T>>, void>*
>
SizeType Deserializer<Stream, SizeType>::_load(T&& t) {
using U = std::decay_t<T>;
typename U::size_type num_data;
auto sz = _load(make_size_tag(num_data));
if constexpr(std::is_arithmetic_v<typename U::value_type>) {
t.resize(num_data);
_stream.read(reinterpret_cast<char*>(t.data()), num_data * sizeof(typename U::value_type));
sz += num_data * sizeof(typename U::value_type);
}
else {
t.resize(num_data);
for(auto && v : t) {
sz += _load(v);
}
}
return sz;
}
// std::list and std::deque
template <typename Stream, typename SizeType>
template <typename T,
std::enable_if_t<is_std_deque_v<std::decay_t<T>> ||
is_std_list_v<std::decay_t<T>> ||
is_std_forward_list_v<std::decay_t<T>>, void>*
>
SizeType Deserializer<Stream, SizeType>::_load(T&& t) {
using U = std::decay_t<T>;
typename U::size_type num_data;
auto sz = _load(make_size_tag(num_data));
t.resize(num_data);
for(auto && v : t) {
sz += _load(v);
}
return sz;
}
// std::map
template <typename Stream, typename SizeType>
template <typename T,
std::enable_if_t<is_std_map_v<std::decay_t<T>>, void>*
>
SizeType Deserializer<Stream, SizeType>::_load(T&& t) {
using U = std::decay_t<T>;
typename U::size_type num_data;
auto sz = _load(make_size_tag(num_data));
t.clear();
auto hint = t.begin();
typename U::key_type k;
typename U::mapped_type v;
for(size_t i=0; i<num_data; ++i) {
sz += _load(make_kv_pair(k, v));
hint = t.emplace_hint(hint, std::move(k), std::move(v));
}
return sz;
}
// std::unordered_map
template <typename Stream, typename SizeType>
template <typename T,
std::enable_if_t<is_std_unordered_map_v<std::decay_t<T>>, void>*
>
SizeType Deserializer<Stream, SizeType>::_load(T&& t) {
using U = std::decay_t<T>;
typename U::size_type num_data;
auto sz = _load(make_size_tag(num_data));
t.clear();
t.reserve(num_data);
typename U::key_type k;
typename U::mapped_type v;
for(size_t i=0; i<num_data; ++i) {
sz += _load(make_kv_pair(k, v));
t.emplace(std::move(k), std::move(v));
}
return sz;
}
// std::set
template <typename Stream, typename SizeType>
template <typename T,
std::enable_if_t<is_std_set_v<std::decay_t<T>>, void>*
>
SizeType Deserializer<Stream, SizeType>::_load(T&& t) {
using U = std::decay_t<T>;
typename U::size_type num_data;
auto sz = _load(make_size_tag(num_data));
t.clear();
auto hint = t.begin();
typename U::key_type k;
for(size_t i=0; i<num_data; ++i) {
sz += _load(k);
hint = t.emplace_hint(hint, std::move(k));
}
return sz;
}
// std::unordered_set
template <typename Stream, typename SizeType>
template <typename T,
std::enable_if_t<is_std_unordered_set_v<std::decay_t<T>>, void>*
>
SizeType Deserializer<Stream, SizeType>::_load(T&& t) {
using U = std::decay_t<T>;
typename U::size_type num_data;
auto sz = _load(make_size_tag(num_data));
t.clear();
t.reserve(num_data);
typename U::key_type k;
for(size_t i=0; i<num_data; ++i) {
sz += _load(k);
t.emplace(std::move(k));
}
return sz;
}
// enum data type
template <typename Stream, typename SizeType>
template <typename T,
std::enable_if_t<std::is_enum_v<std::decay_t<T>>, void>*
>
SizeType Deserializer<Stream, SizeType>::_load(T&& t) {
using U = std::decay_t<T>;
std::underlying_type_t<U> k;
auto sz = _load(k);
t = static_cast<U>(k);
return sz;
}
// duration data type
template <typename Stream, typename SizeType>
template <typename T,
std::enable_if_t<is_std_duration_v<std::decay_t<T>>, void>*
>
SizeType Deserializer<Stream, SizeType>::_load(T&& t) {
using U = std::decay_t<T>;
typename U::rep count;
auto s = _load(count);
t = U{count};
return s;
}
// time point data type
template <typename Stream, typename SizeType>
template <typename T,
std::enable_if_t<is_std_time_point_v<std::decay_t<T>>, void>*
>
SizeType Deserializer<Stream, SizeType>::_load(T&& t) {
using U = std::decay_t<T>;
typename U::duration elapsed;
auto s = _load(elapsed);
t = U{elapsed};
return s;
}
// optional data type
template <typename Stream, typename SizeType>
template <typename T,
std::enable_if_t<is_std_optional_v<std::decay_t<T>>, void>*
>
SizeType Deserializer<Stream, SizeType>::_load(T&& t) {
using U = std::decay_t<T>;
bool has_value;
auto s = _load(has_value);
if(has_value) {
if(!t) {
t = typename U::value_type();
}
s += _load(*t);
}
else {
t.reset();
}
return s;
}
// variant type
template <typename Stream, typename SizeType>
template <typename T,
std::enable_if_t<is_std_variant_v<std::decay_t<T>>, void>*
>
SizeType Deserializer<Stream, SizeType>::_load(T&& t) {
std::decay_t<decltype(t.index())> idx;
auto s = _load(idx);
return s + _variant_helper(idx, t);
}
// tuple type
template <typename Stream, typename SizeType>
template <typename T,
std::enable_if_t<is_std_tuple_v<std::decay_t<T>>, void>*
>
SizeType Deserializer<Stream, SizeType>::_load(T&& t) {
return std::apply(
[&] (auto&&... args) {
return (_load(std::forward<decltype(args)>(args)) + ... + 0);
},
std::forward<T>(t)
);
}
// array
template <typename Stream, typename SizeType>
template <typename T,
std::enable_if_t<is_std_array_v<std::decay_t<T>>, void>*
>
SizeType Deserializer<Stream, SizeType>::_load(T&& t) {
using U = std::decay_t<T>;
static_assert(std::tuple_size<U>::value > 0, "Array size can't be zero");
SizeType sz;
if constexpr(std::is_arithmetic_v<typename U::value_type>) {
_stream.read(reinterpret_cast<char*>(t.data()), sizeof(t));
sz = sizeof(t);
}
else {
sz = 0;
for(auto && v : t) {
sz += _load(v);
}
}
return sz;
}
// custom save method
template <typename Stream, typename SizeType>
template <typename T,
std::enable_if_t<!is_default_deserializable_v<std::decay_t<T>>, void>*
>
SizeType Deserializer<Stream, SizeType>::_load(T&& t) {
return t.load(*this);
}
} // end of namespace tf -----------------------------------------------------