From cd8b30a70aa3da602eb9c17c71650c8261670872 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Ricardo=20Gonz=C3=A1lez=20Moreno?= Date: Tue, 23 Jan 2024 11:05:59 +0100 Subject: [PATCH] Refs #17138. Support serializing a std::vector as an array. MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Signed-off-by: Ricardo González Moreno --- include/fastcdr/Cdr.h | 221 ++++++++++++++++++++++++++++++++++++++++++ src/cpp/Cdr.cpp | 78 +++++++++++++++ 2 files changed, 299 insertions(+) diff --git a/include/fastcdr/Cdr.h b/include/fastcdr/Cdr.h index 33ebadbc..0734b265 100644 --- a/include/fastcdr/Cdr.h +++ b/include/fastcdr/Cdr.h @@ -1271,6 +1271,107 @@ class Cdr return *this; } + /*! + * @brief Encodes an std::vector of primitives as an array. + * @param[in] value Reference to a std::vector. + * @return Reference to the eprosima::fastcdr::Cdr object. + * @exception exception::NotEnoughMemoryException This exception is thrown when trying to encode into a buffer + * position that exceeds the internal memory size. + */ + template::value || + std::is_arithmetic<_T>::value>::type* = nullptr> + Cdr& serialize_array( + const std::vector<_T>& value) + { + serialize_array(value.data(), value.size()); + + return *this; + } + + /*! + * @brief Encodes an std::vector of non-primitives as an array. + * @param[in] value Reference to a std::vector. + * @return Reference to the eprosima::fastcdr::Cdr object. + * @exception exception::NotEnoughMemoryException This exception is thrown when trying to encode into a buffer + * position that exceeds the internal memory size. + */ + template::value && + !std::is_arithmetic<_T>::value>::type* = nullptr> + Cdr& serialize_array( + const std::vector<_T>& value) + { + Cdr::state dheader_state(*this); + + if (CdrVersion::XCDRv2 == cdr_version_) + { + // Serialize DHEADER + uint32_t dheader {0}; + serialize(dheader); + } + + serialize_array(value.data(), value.size()); + + if (CdrVersion::XCDRv2 == cdr_version_) + { + auto offset = offset_; + Cdr::state state_after(*this); + set_state(dheader_state); + size_t dheader = offset - offset_ - (4 + alignment(sizeof(uint32_t)));/* DHEADER */ + serialize(static_cast(dheader)); + set_state(state_after); + serialized_member_size_ = SERIALIZED_MEMBER_SIZE; + } + + return *this; + } + + /*! + * @brief Encodes an std::vector as an array with a different endianness. + * @param[in] value Reference to a std::vector. + * @param[in] endianness Endianness that will be used in the serialization of this value. + * @return Reference to the eprosima::fastcdr::Cdr object. + * @exception exception::NotEnoughMemoryException This exception is thrown when trying to encode into a buffer + * position that exceeds the internal memory size. + */ + template + Cdr& serialize_array( + const std::vector<_T>& value, + Endianness endianness) + { + bool aux_swap = swap_bytes_; + swap_bytes_ = (swap_bytes_ && (static_cast(endianness_) == endianness)) || + (!swap_bytes_ && (static_cast(endianness_) != endianness)); + + try + { + serialize_array(value); + swap_bytes_ = aux_swap; + } + catch (exception::Exception& ex) + { + swap_bytes_ = aux_swap; + ex.raise(); + } + + return *this; + } + + /*! + * @brief Encodes an std::vector of booleans as an array. + * @param[in] value Reference to a std::vector. + * @return Reference to the eprosima::fastcdr::Cdr object. + * @exception exception::NotEnoughMemoryException This exception is thrown when trying to encode into a buffer + * position that exceeds the internal memory size. + */ + TEMPLATE_SPEC + Cdr& serialize_array( + const std::vector& value) + { + serialize_bool_array(value); + + return *this; + } + /*! * @brief This function template serializes a raw sequence of non-primitives * @param sequence_t Pointer to the sequence that will be serialized in the buffer. @@ -2330,6 +2431,120 @@ class Cdr bool* bool_t, size_t num_elements); + /*! + * @brief Decodes an array of primitives on a std::vector. + * + * std::vector must have allocated the number of element of the array. + * + * @param[out] value Reference to the std::vector where the array will be stored after decoding from the buffer. + * @return Reference to the eprosima::fastcdr::Cdr object. + * @exception exception::NotEnoughMemoryException This exception is thrown when trying to decode from a buffer + * position that exceeds the internal memory size. + */ + template::value || + std::is_arithmetic<_T>::value>::type* = nullptr> + Cdr& deserialize_array( + std::vector<_T>& value) + { + deserialize_array(value.data(), value.size()); + + return *this; + } + + /*! + * @brief Decodes an array of non-primitives on a std::vector. + * + * std::vector must have allocated the number of element of the array. + * + * @param[out] value Reference to the std::vector where the array will be stored after decoding from the buffer. + * @return Reference to the eprosima::fastcdr::Cdr object. + * @exception exception::NotEnoughMemoryException This exception is thrown when trying to decode from a buffer + * position that exceeds the internal memory size. + */ + template::value && + !std::is_arithmetic<_T>::value>::type* = nullptr> + Cdr& deserialize_array( + std::vector<_T>& value) + { + if (CdrVersion::XCDRv2 == cdr_version_) + { + uint32_t dheader {0}; + deserialize(dheader); + + uint32_t count {0}; + auto offset = offset_; + while (offset_ - offset < dheader && count < value.size()) + { + deserialize_array(&value.data()[count], 1); + ++count; + } + + if (offset_ - offset != dheader) + { + throw exception::BadParamException("Member size greater than size specified by DHEADER"); + } + } + else + { + return deserialize_array(value.data(), value.size()); + } + + return *this; + } + + /*! + * @brief Decodes an array of non-primitives on a std::vector with a different endianness. + * + * std::vector must have allocated the number of element of the array. + * + * @param[out] value Reference to the std::vector where the array will be stored after decoding from the buffer. + * @param[in] endianness Endianness that will be used in the serialization of this value. + * @return Reference to the eprosima::fastcdr::Cdr object. + * @exception exception::NotEnoughMemoryException This exception is thrown when trying to decode from a buffer + * position that exceeds the internal memory size. + */ + template + Cdr& deserialize_array( + std::vector<_T>& value, + Endianness endianness) + { + bool aux_swap = swap_bytes_; + swap_bytes_ = (swap_bytes_ && (static_cast(endianness_) == endianness)) || + (!swap_bytes_ && (static_cast(endianness_) != endianness)); + + try + { + deserialize_array(value); + swap_bytes_ = aux_swap; + } + catch (exception::Exception& ex) + { + swap_bytes_ = aux_swap; + ex.raise(); + } + + return *this; + } + + /*! + * @brief Decodes an array of booleans on a std::vector. + * + * std::vector must have allocated the number of element of the array. + * + * @param[out] value Reference to the std::vector where the array will be stored after decoding from the buffer. + * @return Reference to the eprosima::fastcdr::Cdr object. + * @exception exception::NotEnoughMemoryException This exception is thrown when trying to encode into a buffer + * position that exceeds the internal memory size. + */ + TEMPLATE_SPEC + Cdr& deserialize_array( + std::vector& value) + { + deserialize_bool_array(value); + + return *this; + } + /*! * @brief This function template deserializes a raw sequence of non-primitives. * This function allocates memory to store the sequence. The user pointer will be set to point this allocated memory. @@ -2805,9 +3020,15 @@ class Cdr Cdr& operator =( const Cdr&) = delete; + Cdr_DllAPI Cdr& serialize_bool_array( + const std::vector& vector_t); + Cdr_DllAPI Cdr& serialize_bool_sequence( const std::vector& vector_t); + Cdr_DllAPI Cdr& deserialize_bool_array( + std::vector& vector_t); + Cdr_DllAPI Cdr& deserialize_bool_sequence( std::vector& vector_t); diff --git a/src/cpp/Cdr.cpp b/src/cpp/Cdr.cpp index 34e2ebe8..960bf868 100644 --- a/src/cpp/Cdr.cpp +++ b/src/cpp/Cdr.cpp @@ -2156,6 +2156,44 @@ Cdr& Cdr::deserialize_array( throw NotEnoughMemoryException(NotEnoughMemoryException::NOT_ENOUGH_MEMORY_MESSAGE_DEFAULT); } +Cdr& Cdr::serialize_bool_array( + const std::vector& vector_t) +{ + state state_before_error(*this); + + size_t total_size = vector_t.size() * sizeof(bool); + + if (((end_ - offset_) >= total_size) || resize(total_size)) + { + // Save last datasize. + last_data_size_ = sizeof(bool); + + for (size_t count = 0; count < vector_t.size(); ++count) + { + uint8_t value = 0; + std::vector::const_reference ref = vector_t[count]; + + if (ref) + { + value = 1; + } + offset_++ << value; + } + } + else + { + set_state(state_before_error); + throw NotEnoughMemoryException(NotEnoughMemoryException::NOT_ENOUGH_MEMORY_MESSAGE_DEFAULT); + } + + if (CdrVersion::XCDRv2 == cdr_version_) + { + serialized_member_size_ = SERIALIZED_MEMBER_SIZE; + } + + return *this; +} + Cdr& Cdr::serialize_bool_sequence( const std::vector& vector_t) { @@ -2196,6 +2234,46 @@ Cdr& Cdr::serialize_bool_sequence( return *this; } +Cdr& Cdr::deserialize_bool_array( + std::vector& vector_t) +{ + state state_before_error(*this); + + size_t total_size = vector_t.size() * sizeof(bool); + + if ((end_ - offset_) >= total_size) + { + // Save last datasize. + last_data_size_ = sizeof(bool); + + for (uint32_t count = 0; count < vector_t.size(); ++count) + { + uint8_t value = 0; + offset_++ >> value; + + if (value == 1) + { + vector_t[count] = true; + } + else if (value == 0) + { + vector_t[count] = false; + } + else + { + throw BadParamException("Unexpected byte value in Cdr::deserialize_bool_sequence, expected 0 or 1"); + } + } + } + else + { + set_state(state_before_error); + throw NotEnoughMemoryException(NotEnoughMemoryException::NOT_ENOUGH_MEMORY_MESSAGE_DEFAULT); + } + + return *this; +} + Cdr& Cdr::deserialize_bool_sequence( std::vector& vector_t) {