// This file is part of Eigen, a lightweight C++ template library // for linear algebra. // // Copyright (C) 2021 The Eigen Team // // This Source Code Form is subject to the terms of the Mozilla // Public License v. 2.0. If a copy of the MPL was not distributed // with this file, You can obtain one at http://mozilla.org/MPL/2.0/. #ifndef EIGEN_SERIALIZER_H #define EIGEN_SERIALIZER_H #include // The Serializer class encodes data into a memory buffer so it can be later // reconstructed. This is mainly used to send objects back-and-forth between // the CPU and GPU. namespace Eigen { /** * Serializes an object to a memory buffer. * * Useful for transferring data (e.g. back-and-forth to a device). */ template class Serializer; // Specialization for POD types. template class Serializer::value && std::is_standard_layout::value>> { public: /** * Determines the required size of the serialization buffer for a value. * * \param value the value to serialize. * \return the required size. */ EIGEN_DEVICE_FUNC size_t size(const T& value) const { return sizeof(value); } /** * Serializes a value to a byte buffer. * \param dest the destination buffer; if this is nullptr, does nothing. * \param end the end of the destination buffer. * \param value the value to serialize. * \return the next memory address past the end of the serialized data. */ EIGEN_DEVICE_FUNC uint8_t* serialize(uint8_t* dest, uint8_t* end, const T& value) { if (EIGEN_PREDICT_FALSE(dest == nullptr)) return nullptr; if (EIGEN_PREDICT_FALSE(dest + sizeof(value) > end)) return nullptr; EIGEN_USING_STD(memcpy) memcpy(dest, &value, sizeof(value)); return dest + sizeof(value); } /** * Deserializes a value from a byte buffer. * \param src the source buffer; if this is nullptr, does nothing. * \param end the end of the source buffer. * \param value the value to populate. * \return the next unprocessed memory address; nullptr if parsing errors are detected. */ EIGEN_DEVICE_FUNC const uint8_t* deserialize(const uint8_t* src, const uint8_t* end, T& value) const { if (EIGEN_PREDICT_FALSE(src == nullptr)) return nullptr; if (EIGEN_PREDICT_FALSE(src + sizeof(value) > end)) return nullptr; EIGEN_USING_STD(memcpy) memcpy(&value, src, sizeof(value)); return src + sizeof(value); } }; // Specialization for DenseBase. // Serializes [rows, cols, data...]. template class Serializer, void> { public: typedef typename Derived::Scalar Scalar; struct Header { typename Derived::Index rows; typename Derived::Index cols; }; EIGEN_DEVICE_FUNC size_t size(const Derived& value) const { return sizeof(Header) + sizeof(Scalar) * value.size(); } EIGEN_DEVICE_FUNC uint8_t* serialize(uint8_t* dest, uint8_t* end, const Derived& value) { if (EIGEN_PREDICT_FALSE(dest == nullptr)) return nullptr; if (EIGEN_PREDICT_FALSE(dest + size(value) > end)) return nullptr; const size_t header_bytes = sizeof(Header); const size_t data_bytes = sizeof(Scalar) * value.size(); Header header = {value.rows(), value.cols()}; EIGEN_USING_STD(memcpy) memcpy(dest, &header, header_bytes); dest += header_bytes; memcpy(dest, value.data(), data_bytes); return dest + data_bytes; } EIGEN_DEVICE_FUNC const uint8_t* deserialize(const uint8_t* src, const uint8_t* end, Derived& value) const { if (EIGEN_PREDICT_FALSE(src == nullptr)) return nullptr; if (EIGEN_PREDICT_FALSE(src + sizeof(Header) > end)) return nullptr; const size_t header_bytes = sizeof(Header); Header header; EIGEN_USING_STD(memcpy) memcpy(&header, src, header_bytes); src += header_bytes; const size_t data_bytes = sizeof(Scalar) * header.rows * header.cols; if (EIGEN_PREDICT_FALSE(src + data_bytes > end)) return nullptr; value.resize(header.rows, header.cols); memcpy(value.data(), src, data_bytes); return src + data_bytes; } }; template class Serializer > : public Serializer > > {}; template class Serializer > : public Serializer > > {}; namespace internal { // Recursive serialization implementation helper. template struct serialize_impl; template struct serialize_impl { using Serializer = Eigen::Serializer::type>; static EIGEN_DEVICE_FUNC EIGEN_STRONG_INLINE size_t serialize_size(const T1& value, const Ts&... args) { Serializer serializer; size_t size = serializer.size(value); return size + serialize_impl::serialize_size(args...); } static EIGEN_DEVICE_FUNC EIGEN_STRONG_INLINE uint8_t* serialize(uint8_t* dest, uint8_t* end, const T1& value, const Ts&... args) { Serializer serializer; dest = serializer.serialize(dest, end, value); return serialize_impl::serialize(dest, end, args...); } static EIGEN_DEVICE_FUNC EIGEN_STRONG_INLINE const uint8_t* deserialize(const uint8_t* src, const uint8_t* end, T1& value, Ts&... args) { Serializer serializer; src = serializer.deserialize(src, end, value); return serialize_impl::deserialize(src, end, args...); } }; // Base case. template<> struct serialize_impl<0> { static EIGEN_DEVICE_FUNC EIGEN_STRONG_INLINE size_t serialize_size() { return 0; } static EIGEN_DEVICE_FUNC EIGEN_STRONG_INLINE uint8_t* serialize(uint8_t* dest, uint8_t* /*end*/) { return dest; } static EIGEN_DEVICE_FUNC EIGEN_STRONG_INLINE const uint8_t* deserialize(const uint8_t* src, const uint8_t* /*end*/) { return src; } }; } // namespace internal /** * Determine the buffer size required to serialize a set of values. * * \param args ... arguments to serialize in sequence. * \return the total size of the required buffer. */ template EIGEN_DEVICE_FUNC EIGEN_STRONG_INLINE size_t serialize_size(const Args&... args) { return internal::serialize_impl::serialize_size(args...); } /** * Serialize a set of values to the byte buffer. * * \param dest output byte buffer; if this is nullptr, does nothing. * \param end the end of the output byte buffer. * \param args ... arguments to serialize in sequence. * \return the next address after all serialized values. */ template EIGEN_DEVICE_FUNC EIGEN_STRONG_INLINE uint8_t* serialize(uint8_t* dest, uint8_t* end, const Args&... args) { return internal::serialize_impl::serialize(dest, end, args...); } /** * Deserialize a set of values from the byte buffer. * * \param src input byte buffer; if this is nullptr, does nothing. * \param end the end of input byte buffer. * \param args ... arguments to deserialize in sequence. * \return the next address after all parsed values; nullptr if parsing errors are detected. */ template EIGEN_DEVICE_FUNC EIGEN_STRONG_INLINE const uint8_t* deserialize(const uint8_t* src, const uint8_t* end, Args&... args) { return internal::serialize_impl::deserialize(src, end, args...); } } // namespace Eigen #endif // EIGEN_SERIALIZER_H