// Copyright (c) OpenMMLab. All rights reserved. #ifndef MMDEPLOY_SRC_CORE_SERIALIZATION_H_ #define MMDEPLOY_SRC_CORE_SERIALIZATION_H_ #include #include #include #include #include "core/macro.h" #include "core/status_code.h" #include "mpl/detected.h" #include "mpl/type_traits.h" namespace mmdeploy { #define MMDEPLOY_ARCHIVE_NVP(archive, ...) archive(MMDEPLOY_PP_MAP(MMDEPLOY_NVP, __VA_ARGS__)) #define MMDEPLOY_ARCHIVE_MEMBERS(...) \ template \ void serialize(Archive &archive) { \ MMDEPLOY_ARCHIVE_NVP(archive, __VA_ARGS__); \ } #define MMDEPLOY_NVP(var) \ ::mmdeploy::NamedValue { std::forward_as_tuple(#var, var) } template class NamedValue { public: explicit NamedValue(std::tuple &&data) : data_(std::move(data)) {} template void serialize(Archive &archive) { archive.named_value(std::forward(std::get<0>(data_)), std::forward(std::get<1>(data_))); } std::tuple &data() { return data_; } private: std::tuple data_; }; template struct array_tag { explicit array_tag(std::size_t size) : size_(size) {} std::size_t size() const { return size_; } std::size_t size_; }; template struct object_tag {}; template using mapped_type_t = typename T::mapped_type; template using has_mapped_type = detail::is_detected; template using get_size_t = decltype(std::declval().size()); template using has_size = detail::is_detected; template using reserve_t = decltype(std::declval().reserve(std::size_t{0})); template using has_reserve = detail::is_detected; namespace detail { template , typename ValueType = typename U::value_type, std::enable_if_t, int> = 0> auto save(Archive &archive, T &&iterable) -> std::void_t { if constexpr (has_size::value) { archive.init(array_tag(iterable.size())); } for (auto &&x : iterable) { archive.item(std::forward(x)); } } template class KeyValue { public: explicit KeyValue(std::tuple &&data) : data_(std::move(data)) {} template void serialize(Archive &archive) { archive.named_value("key", std::forward(std::get<0>(data_))); archive.named_value("value", std::forward(std::get<1>(data_))); } std::tuple &data() { return data_; } private: std::tuple data_; }; template , typename KeyType = typename U::key_type, typename MappedType = typename U::mapped_type, std::enable_if_t, int> = 0> auto save(Archive &archive, T &object) -> std::void_t { if constexpr (has_size::value) { // TODO: provide meaningful type info archive.init(array_tag(object.size())); } for (auto &&[k, v] : object) { archive.item(KeyValue{ std::forward_as_tuple(std::forward(k), std::forward(v))}); } } template , typename KeyType = typename U::key_type, typename MappedType = typename U::mapped_type, std::enable_if_t, int> = 0> auto save(Archive &archive, T &object) -> std::void_t { if constexpr (has_size::value) { archive.init(object_tag()); } for (auto &&[k, v] : object) { archive.named_value(std::forward(k), std::forward(v)); } } template void save_tuple_impl(Archive &archive, T &&tuple, std::index_sequence) { (archive.item(std::get(std::forward(tuple))), ...); } template void save(Archive &archive, const std::tuple &tuple) { save_tuple_impl(archive, tuple, std::index_sequence_for{}); } template void load_tuple_impl(Archive &archive, T &tuple, std::index_sequence) { (archive.item(std::get(tuple)), ...); } template void save(Archive &archive, T (&v)[N]) { archive.init(array_tag(N)); for (std::size_t i = 0; i < N; ++i) { archive.item(v[i]); } } template void load(Archive &archive, std::tuple &tuple) { std::size_t size{}; archive.init(size); if (size != sizeof...(Ts)) { throw_exception(eShapeMismatch); } load_tuple_impl(archive, tuple, std::index_sequence_for{}); } template , typename ValueType = typename U::value_type, std::enable_if_t, int> = 0> auto load(Archive &&archive, T &&vec) -> std::void_t { std::size_t size{}; archive.init(size); vec.clear(); for (std::size_t i = 0; i < size; ++i) { ValueType v{}; archive.item(v); vec.push_back(std::move(v)); } } template void load(Archive &archive, std::array &v) { std::size_t size{}; archive.init(size); for (std::size_t i = 0; i < size; ++i) { archive.item(v[i]); } } template void load(Archive &archive, T (&v)[N]) { std::size_t size{}; archive.init(size); for (std::size_t i = 0; i < size; ++i) { archive.item(v[i]); } } template , typename ValueType = typename U::value_type, std::enable_if_t, std::negation>>, int> = 0> auto load(Archive &&archive, T &&set) -> std::void_t()))> { std::size_t size{}; archive.init(size); for (std::size_t i = 0; i < size; ++i) { ValueType v{}; archive.item(v); set.insert(std::move(v)); } } template < typename Archive, typename T, typename U = uncvref_t, typename KeyType = typename U::key_type, typename MappedType = typename U::mapped_type, std::enable_if_t>, std::is_default_constructible, std::is_default_constructible>, int> = 0> void load(Archive &&archive, T &&object) { std::size_t size{}; archive.init(size); for (std::size_t i = 0; i < size; ++i) { KeyType key; MappedType mapped; archive.item(KeyValue{std::tie(key, mapped)}); object.insert({std::move(key), std::move(mapped)}); }; } template , typename KeyType = typename U::key_type, typename MappedType = typename U::mapped_type, std::enable_if_t, std::is_default_constructible>, int> = 0> void load(Archive &&archive, T &&object) { std::size_t size{}; archive.init(size); for (std::size_t i = 0; i < size; ++i) { std::string name; MappedType value{}; archive.named_value(name, value); object.insert({std::move(name), std::move(value)}); } } struct save_fn { template auto operator()(Archive &&a, T &&v) const -> decltype(save(std::forward(a), std::forward(v))) { return save(std::forward(a), std::forward(v)); } }; struct load_fn { template auto operator()(Archive &&a, T &&v) const -> decltype(load(std::forward(a), std::forward(v))) { return load(std::forward(a), std::forward(v)); } }; struct serialize_fn { template auto operator()(Archive &&a, T &&v) const -> decltype(serialize(std::forward(a), std::forward(v))) { return serialize(std::forward(a), std::forward(v)); } }; } // namespace detail namespace { constexpr inline detail::save_fn save{}; constexpr inline detail::load_fn load{}; constexpr inline detail::serialize_fn serialize{}; } // namespace template struct adl_serializer; template struct adl_serializer { template static auto save(Archive &&a, T &&v) -> decltype(::mmdeploy::save(std::forward(a), std::forward(v))) { ::mmdeploy::save(std::forward(a), std::forward(v)); } template static auto load(Archive &&a, T &&v) -> decltype(::mmdeploy::load(std::forward(a), std::forward(v))) { ::mmdeploy::load(std::forward(a), std::forward(v)); } template static auto serialize(Archive &&a, T &&v) -> decltype(::mmdeploy::serialize(std::forward(a), std::forward(v))) { ::mmdeploy::serialize(std::forward(a), std::forward(v)); } }; }; // namespace mmdeploy #endif // MMDEPLOY_SRC_CORE_SERIALIZATION_H_