// Copyright (c) OpenMMLab. All rights reserved. #ifndef MMDEPLOY_SRC_CORE_SERIALIZATION_H_ #define MMDEPLOY_SRC_CORE_SERIALIZATION_H_ #include #include #include #include #include "core/status_code.h" #include "mpl/detected.h" #include "mpl/type_traits.h" namespace mmdeploy { #define _MMDEPLOY_NTH_ARG(_1, _2, _3, _4, _5, _6, _7, _8, _9, _10, _11, _12, _13, _14, _15, _16, \ N, ...) \ N #define _MMDEPLOY_ARCHIVE_1(x) MMDEPLOY_NVP(x) #define _MMDEPLOY_ARCHIVE_2(x, ...) MMDEPLOY_NVP(x), _MMDEPLOY_ARCHIVE_1(__VA_ARGS__) #define _MMDEPLOY_ARCHIVE_3(x, ...) MMDEPLOY_NVP(x), _MMDEPLOY_ARCHIVE_2(__VA_ARGS__) #define _MMDEPLOY_ARCHIVE_4(x, ...) MMDEPLOY_NVP(x), _MMDEPLOY_ARCHIVE_3(__VA_ARGS__) #define _MMDEPLOY_ARCHIVE_5(x, ...) MMDEPLOY_NVP(x), _MMDEPLOY_ARCHIVE_4(__VA_ARGS__) #define _MMDEPLOY_ARCHIVE_6(x, ...) MMDEPLOY_NVP(x), _MMDEPLOY_ARCHIVE_5(__VA_ARGS__) #define _MMDEPLOY_ARCHIVE_7(x, ...) MMDEPLOY_NVP(x), _MMDEPLOY_ARCHIVE_6(__VA_ARGS__) #define _MMDEPLOY_ARCHIVE_8(x, ...) MMDEPLOY_NVP(x), _MMDEPLOY_ARCHIVE_7(__VA_ARGS__) #define _MMDEPLOY_ARCHIVE_9(x, ...) MMDEPLOY_NVP(x), _MMDEPLOY_ARCHIVE_8(__VA_ARGS__) #define _MMDEPLOY_ARCHIVE_10(x, ...) MMDEPLOY_NVP(x), _MMDEPLOY_ARCHIVE_9(__VA_ARGS__) #define _MMDEPLOY_ARCHIVE_11(x, ...) MMDEPLOY_NVP(x), _MMDEPLOY_ARCHIVE_10(__VA_ARGS__) #define _MMDEPLOY_ARCHIVE_12(x, ...) MMDEPLOY_NVP(x), _MMDEPLOY_ARCHIVE_11(__VA_ARGS__) #define _MMDEPLOY_ARCHIVE_13(x, ...) MMDEPLOY_NVP(x), _MMDEPLOY_ARCHIVE_12(__VA_ARGS__) #define _MMDEPLOY_ARCHIVE_14(x, ...) MMDEPLOY_NVP(x), _MMDEPLOY_ARCHIVE_13(__VA_ARGS__) #define _MMDEPLOY_ARCHIVE_15(x, ...) MMDEPLOY_NVP(x), _MMDEPLOY_ARCHIVE_14(__VA_ARGS__) #define _MMDEPLOY_ARCHIVE_16(x, ...) MMDEPLOY_NVP(x), _MMDEPLOY_ARCHIVE_15(__VA_ARGS__) #define _MMDEPLOY_ARCHIVE_DISPATCH(...) \ _MMDEPLOY_NTH_ARG(__VA_ARGS__, _MMDEPLOY_ARCHIVE_16(__VA_ARGS__), \ _MMDEPLOY_ARCHIVE_15(__VA_ARGS__), _MMDEPLOY_ARCHIVE_14(__VA_ARGS__), \ _MMDEPLOY_ARCHIVE_13(__VA_ARGS__), _MMDEPLOY_ARCHIVE_12(__VA_ARGS__), \ _MMDEPLOY_ARCHIVE_11(__VA_ARGS__), _MMDEPLOY_ARCHIVE_10(__VA_ARGS__), \ _MMDEPLOY_ARCHIVE_9(__VA_ARGS__), _MMDEPLOY_ARCHIVE_8(__VA_ARGS__), \ _MMDEPLOY_ARCHIVE_7(__VA_ARGS__), _MMDEPLOY_ARCHIVE_6(__VA_ARGS__), \ _MMDEPLOY_ARCHIVE_5(__VA_ARGS__), _MMDEPLOY_ARCHIVE_4(__VA_ARGS__), \ _MMDEPLOY_ARCHIVE_3(__VA_ARGS__), _MMDEPLOY_ARCHIVE_2(__VA_ARGS__), \ _MMDEPLOY_ARCHIVE_1(__VA_ARGS__)) #define MMDEPLOY_ARCHIVE_NVP(archive, ...) archive(_MMDEPLOY_ARCHIVE_DISPATCH(__VA_ARGS__)) #define MMDEPLOY_ARCHIVE(archive, ...) archive(__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)}); } } template using save_t = decltype(save(std::declval(), std::declval())); struct save_fn { template auto operator()(Archive &&a, T &&v) const -> save_t { return save(std::forward(a), std::forward(v)); } }; template using load_t = decltype(load(std::declval(), std::declval())); struct load_fn { template auto operator()(Archive &&a, T &&v) const -> load_t { return load(std::forward(a), std::forward(v)); } }; template using serialize_t = decltype(serialize(std::declval(), std::declval())); struct serialize_fn { template auto operator()(Archive &&a, T &&v) const -> serialize_t { 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) -> detail::save_t { ::mmdeploy::save(std::forward(a), std::forward(v)); } template static auto load(Archive &&a, T &&v) -> detail::load_t { ::mmdeploy::load(std::forward(a), std::forward(v)); } template static auto serialize(Archive &&a, T &&v) -> detail::serialize_t { ::mmdeploy::serialize(std::forward(a), std::forward(v)); } }; }; // namespace mmdeploy #endif // MMDEPLOY_SRC_CORE_SERIALIZATION_H_