/* (c) Copyright, Real-Time Innovations, 2018. All rights reserved. No duplications, whole or partial, manual or electronic, may be made without express written permission. Any such copies, or revisions thereof, must display this notice unaltered. This code contains trade secrets of Real-Time Innovations, Inc. */ #ifndef RTI_DDS_FLAT_FLATOFFSETS_HPP_ #define RTI_DDS_FLAT_FLATOFFSETS_HPP_ #include "xcdr/xcdr_stream.h" #include "xcdr/xcdr_stream_impl.h" #include "xcdr/xcdr_interpreter.h" #include "rti/xcdr/Stream.hpp" /** * @defgroup RTIFlatOffsetsModule FlatData Offsets * @ingroup RTIFlatDataModule * @brief Offsets provide access to the members of a FlatData Sample * * An Offset represents a position within a * \ref RTIFlatSampleModule "FlatData Sample" that allows accessing a member * of that Sample, or the Sample's \ref rti::flat::Sample::root "root". * * Offsets can be described as iterators. They represent a position in a * buffer, not the value itself. As such, they're lightweight objects that can * be copied to point to the same data. * * There are the following Offset types to access the different IDL types: * * * * * * * * * * * * * * * * * * * * * * *
CategoryOffset type
User types For example:
    *
  • MyFlatFinalOffset, an Offset to a final struct
  • *
  • MyFlatMutableOffset, an Offset to a mutable struct
  • *
  • MyFlatUnionOffset, an Offset to a union
  • *
Arrays
    *
  • rti::flat::PrimitiveArrayOffset
  • *
  • rti::flat::FinalArrayOffset (array of final elements in a final type)
  • *
  • rti::flat::FinalAlignedArrayOffset (array of final elements in a mutable type)
  • *
  • rti::flat::MutableArrayOffset
  • *
Sequences
    *
  • rti::flat::PrimitiveSequenceOffset
  • *
  • rti::flat::SequenceOffset
  • *
Primitive types
    *
  • The type itself, such as \p double
  • *
  • rti::flat::PrimitiveOffset (when the member is optional)
  • *
* * Offsets for user types are generated by \nddsgen and provide methods to * access the type's members by their names. Offsets for arrays and sequences * provide methods to access each element. * * Some offsets allow accessing the data through a pointer to the equivalent plain * C++ type, which generally provides better performance. See rti::flat::plain_cast(). * * @section OffsetErrorManagement Offset Error Management * Functions that return an Offset may return a "null" Offset (one such that * \ref rti::flat::OffsetBase::is_null "is_null()" returns \p true). * * An Offset may be null if a member doesn't exist in the \ref * RTIFlatSampleModule "Sample". For example, if the member 'my_final' in * \ref MyFlatMutable doesn't exist (because it wasn't added while building the * Sample, or because it wasn't received in the subscribing application), * MyFlatMutableOffset::my_final() returns an null Offset. Note that a * member in a final type (for example, MyFlatFinalOffset::my_complex()) * always exists, except in the case of an error. * * \if CPP_LANGUAGE_ONLY * In addition to that, a function may return a null Offset for any error * condition. * \endif * * \if CPP2_LANGUAGE_ONLY * Other than that, any error condition will cause one of the following * exceptions, not a null Offset: * - dds::core::NullReferenceError, when accessing a null Offset * - dds::core::PreconditionNotMetError, for any precondition failure. * - dds::core::OutOfResourcesError, when a \ref RTIFlatBuildersModule "Builder" * runs out of space while adding a member. * \endif * */ #ifdef DOXYGEN_DOCUMENTATION_ONLY /** * @ingroup RTIFlatOffsetsModule * @brief Represents the Offset to an arbitrary user-defined FlatData final * IDL struct * * This example type represents the Offset type that \nddsgen would generate * for \ref MyFlatFinal. * * It provides accessors for each of its members. Accessors can return other * Offsets or primitive values. * * An Offset to a final type may meet the requirements to be cast to its * equivalent plain C++ type (see rti::flat::plain_cast()). * */ class MyFlatFinalOffset : public rti::flat::FinalOffset { public: /** * @brief The equivalent read-only Offset type * * Each Offset for a user type has an equivalent const Offset that doesn't * provide the methods to modify the Sample. \if CPP2_LANGUAGE_ONLY * For example, when reading data from a \idref_DataReader, a const Sample's * Sample::root() function returns a const Offset.\endif */ typedef MyFlatFinalConstOffset ConstOffset; /** * @brief Creates a null Offset * * @post is_null() */ MyFlatFinalOffset() { } /** * @brief Retrieves the value for a primitive member */ int32_t my_primitive() const; /** * @brief Retrieves a const Offset to a complex member * * FlatFinalBar is another arbitrary user-defined final FlatData type. */ FlatFinalBar::ConstOffset my_complex() const; /** * @brief Retrieves a const Offset to a primitive array */ const rti::flat::PrimitiveArrayOffset my_primitive_array() const; /** * @brief Retrieves a const Offset to a complex array */ rti::flat::FinalArrayOffset my_complex_array() const; /** * @brief Sets the value for a primitive member */ bool my_primitive(int32_t value); /** * @brief Retrieves a non-const Offset to a complex member * * FlatFinalBar is another arbitrary user-defined final FlatData type. */ FlatFinalBar::Offset my_complex(); /** * @brief Retrieves a non-const Offset to a primitive array */ rti::flat::PrimitiveArrayOffset my_primitive_array(); /** * @brief Retrieves a non-const Offset to a complex array */ rti::flat::FinalArrayOffset my_complex_array(); }; /** * @ingroup RTIFlatOffsetsModule * @brief Represents the Offset to an arbitrary user-defined FlatData * mutable IDL struct * * This example type represents the Offset type that \nddsgen would generate * for \ref MyFlatMutable. * * It provides accessors for each of its members. Accessors can return other * Offsets or primitive values. * */ class NDDSUSERDllExport MyFlatMutableOffset : public rti::flat::MutableOffset { public: /** * @brief The equivalent read-only Offset type * * Each Offset for a user type has an equivalent const Offset that doesn't * allow modifying the underlying Sample. \if CPP2_LANGUAGE_ONLY * For example, when reading data from a \idref_DataReader, a const Sample's * Sample::root() function returns a const Offset.\endif */ typedef MyFlatMutableConstOffset ConstOffset; /** * @brief Creates a null Offset * * @post is_null() */ MyFlatMutableOffset() { } /** * @brief Retrieves the value for a primitive member * * @return The value of the member or its default value if this member * doesn't exist in this Sample. */ int32_t my_primitive() const; /** * @brief Retrieves a const Offset to an optional primitive * * Unlike the non-optional my_primitive(), which accesses the integer * directly, for an optional primitive it is possible to check whether it * exists or not. If it doesn't exist, the Offset this function returns * will be null (\p is_null()). */ rti::flat::PrimitiveConstOffset my_optional_primitive() const; /** * @brief Retrieves a const Offset to a primitive array */ const rti::flat::PrimitiveArrayOffset my_primitive_array() const; /** * @brief Retrieves a const Offset to a primitive sequence */ const rti::flat::PrimitiveSequenceOffset my_primitive_seq() const; /** * @brief Retrieves a const Offset to a complex member */ MyFlatFinal::ConstOffset my_final() const; /** * @brief Retrieves a const Offset to a complex array */ rti::flat::FinalAlignedArrayOffset my_final_array() const; /** * @brief Retrieves a const Offset to a complex sequence */ rti::flat::SequenceOffset my_final_seq() const; /** * @brief Retrieves a const Offset to a complex member * * FlatMutableBar is another arbitrary user-defined mutable FlatData type. */ FlatMutableBar::ConstOffset my_mutable() const; /** * @brief Retrieves a const Offset to a complex array */ rti::flat::MutableArrayOffset my_mutable_array() const; /** * @brief Retrieves a const Offset to a complex sequence */ rti::flat::SequenceOffset my_mutable_seq() const; /** * @brief Retrieves a const Offset to a string */ const rti::flat::StringOffset my_string() const; /** * @brief Retrieves a const Offset to a sequence of strings */ rti::flat::SequenceOffset my_string_seq() const; /** * @brief Sets the value of a primitive member */ bool my_primitive(int32_t value); /* @brief Retrieves a non-const Offset to an optional primitive * * Unlike the non-optional my_primitive(), which allows accessing the integer * directly, an optional primitive may not exist. If it doesn't, the Offset * this function returns will be null (\p is_null()). */ rti::flat::PrimitiveOffset my_optional_primitive(); /** * @brief Retrieves a non-const Offset to a primitive array */ rti::flat::PrimitiveArrayOffset my_primitive_array(); /** * @brief Retrieves a non-const Offset to a primitive sequence */ rti::flat::PrimitiveSequenceOffset my_primitive_seq(); /** * @brief Retrieves a non-const Offset to a complex member */ MyFlatFinal::Offset my_final(); /** * @brief Retrieves a non-const Offset to a complex array */ rti::flat::FinalAlignedArrayOffset my_final_array(); /** * @brief Retrieves a non-const Offset to a complex sequence */ rti::flat::SequenceOffset my_final_seq(); /** * @brief Retrieves a non-const Offset to a complex member * * FlatMutableBar is another arbitrary user-defined mutable FlatData type. */ FlatMutableBar::Offset my_mutable(); /** * @brief Retrieves a non-const Offset to a complex array */ rti::flat::MutableArrayOffset my_mutable_array(); /** * @brief Retrieves a non-const Offset to a complex sequence */ rti::flat::SequenceOffset my_mutable_seq(); /** * @brief Retrieves a non-const Offset to a string */ rti::flat::StringOffset my_string(); /** * @brief Retrieves a non-const Offset to a sequence of strings */ rti::flat::SequenceOffset my_string_seq(); }; /** * @ingroup RTIFlatOffsetsModule * @brief Represents the Offset to an arbitrary user-defined FlatData * mutable IDL union * * This example type represents the Offset type that \nddsgen would generate * for \ref MyFlatUnion. * * It provides accessors for each of its members, plus the discriminator _d(). * Accessors can return other Offsets or primitive values. * * Given a union, only one member, the one identified by _d(), can exist at a * time. The discriminator cannot be modified. * */ class NDDSUSERDllExport MyFlatUnionOffset : public rti::flat::MutableOffset { public: /** * @brief The equivalent read-only Offset type */ typedef MyFlatUnionConstOffset ConstOffset; /** * @brief Creates a null Offset * * @post is_null() */ MyFlatUnionOffset() { } /** * @brief Retrieves the union discriminator * * @return The union discriminator, which identifies which field this union * contains. * * In this example: * - 0 selects my_primitive() * - 1 and 2 select my_mutable() * - 3 selects my_final * * Any other discriminator value indicates that no member or an unknown * member follows. * * Note that the discriminator cannot be modified, since that would * potentially change the size of this Sample by selecting a different * member. The discriminator is selected during the building of a Sample * (see MyUnionBuilder). */ int32_t _d() const; /** * @brief Retrieves the value for a primitive member * * @return The value of my_primitive if this member is selected by _d() * or its default value otherwise. */ int32_t my_primitive() const; /** * @brief Retrieves a const Offset to a complex member * * @return The Offset to the 'my_mutable' member if selected by _d(), * or a \ref OffsetErrorManagement "null Offset" otherwise */ MyFlatMutable::ConstOffset my_mutable() const; /** * @brief Retrieves a const Offset to a complex member * * @return The Offset to the 'my_final' member if selected by _d(), * or a \ref OffsetErrorManagement "null Offset" otherwise */ MyFlatFinal::ConstOffset my_final() const; /** * @brief Sets the value for a primitive member * * @pre _d() must select 'my_primitive', otherwise this function * returns false. * * @return true if my_primitive was set or false if the operation failed. */ bool my_primitive(int32_t value); /** * @brief Retrieves a non-const Offset to a complex member * * @return The Offset to the 'my_mutable' member if selected by _d(), * or a \ref OffsetErrorManagement "null Offset" otherwise */ MyFlatMutable::Offset my_mutable(); /** * @brief Retrieves a non-const Offset to a complex member * * @return The Offset to the 'my_final' member if selected by _d(), * or a \ref OffsetErrorManagement "null Offset" otherwise */ MyFlatFinal::Offset my_final(); }; #endif namespace rti { namespace flat { namespace detail { inline rti::flat::offset_t ptrdiff(unsigned char *a, unsigned char *b) { RTI_FLAT_ASSERT(a - b < RTI_XCDR_MAX_SERIALIZED_SIZE, return 0); return static_cast(a - b); } // Used to determine which fixed-size types need a DHeader when adding a // fixed-size member or element. OffsetType classes may specialize this template // to indicate if they need a DHeader. template struct is_fixed_type_w_dheader { static bool value() { return false; } }; inline bool is_dheader_required_in_non_primitive_collections() { // Allow setting the behavior at compilation time to gain compiler // optimizations #if defined(RTI_FLATDATA_NO_DHEADER_COLLECTIONS) return false; #elif defined(RTI_FLATDATA_DHEADER_COLLECTIONS) return true; #else // Without any compilation flag, the behavior is configurable at runtime RTIXCdrXTypesComplianceMask xTypesComplianceMask; xTypesComplianceMask = RTIXCdrInterpreter_getGlobalXtypeComplianceMask(); return RTIXCdrXTypesComplianceMask_isBitSet( xTypesComplianceMask, RTI_XCDR_XTYPES_DHEADER_IN_NON_PRIMITIVE_COLLECTIONS_BIT); #endif } inline bool is_dheader_required_in_enum_collections() { #if defined(RTI_FLATDATA_NO_DHEADER_COLLECTIONS) return false; #elif defined(RTI_FLATDATA_DHEADER_COLLECTIONS) return true; #else RTIXCdrXTypesComplianceMask xTypesComplianceMask; xTypesComplianceMask = RTIXCdrInterpreter_getGlobalXtypeComplianceMask(); return RTIXCdrXTypesComplianceMask_isBitSet( xTypesComplianceMask, RTI_XCDR_XTYPES_DHEADER_IN_NON_PRIMITIVE_COLLECTIONS_BIT) && !RTIXCdrXTypesComplianceMask_isBitSet( xTypesComplianceMask, RTI_XCDR_XTYPES_ENUM_AS_PRIMITIVE_IN_COLLECTIONS_BIT); #endif } template struct collection_dheader_traits { static bool dheader_required() { return is_dheader_required_in_non_primitive_collections(); } static unsigned int dheader_size() { return dheader_required() ? RTI_XCDR_DHEADER_SIZE : 0; } }; template <> struct collection_dheader_traits { static bool dheader_required() { return is_dheader_required_in_enum_collections(); } static unsigned int dheader_size() { return dheader_required() ? RTI_XCDR_DHEADER_SIZE : 0; } }; } // namespace detail // Forward declaration template class FinalArrayOffset; /** * @ingroup RTIFlatOffsetsModule * @brief Base class of all Offset types * * @see \ref RTIFlatOffsetsModule */ class OffsetBase { public: /** * @brief Indicates whether this Offset doesn't point to a valid element * * \if CPP2_LANGUAGE_ONLY * Comparing this object with \p nullptr is equivalent to calling is_null(). * For example: * \code * MyFlatMutableOffset my_mutable = ...; * auto my_final_member = my_mutable.my_final(); * if (my_final_member.is_null()) { ...member doesn't exist... } * // alternative syntax: * if (my_final_member == nullptr) {...} * \endcode * \endif * * @see \ref OffsetErrorManagement */ bool is_null() const { return sample_ == NULL; } /** * @brief Indicates whether rti::flat::plain_cast() is possible * * @return True only if the data pointed to by this Offset can be * rti::flat::plain_cast() * * @see rti::flat::plain_cast() for the requirements that a type needs to meet */ bool is_cpp_compatible() const { // Derived classes may indicate whether // a type is cpp-compatible return false; } /** * @private * * For internal use only. See the const overload. */ unsigned char * get_buffer() { if (is_null()) { return NULL; } return stream_.current_position(); } /** * @brief Gets this member's position in the buffer * * @note This function should be used for debugging purposes only. * To access the data in this Offset use the Offset accessor methods or, if * this type allows it, rti::flat::plain_cast(). * * Returns the position within the Sample's buffer that this * Offset points to. * * @see get_buffer_size() */ const unsigned char * get_buffer() const { if (is_null()) { return NULL; } return stream_.current_position(); } /** * @brief Gets the size, in bytes, of this member in the buffer * * Returns the number of bytes that this member comprises * after the position returned by get_buffer(). */ offset_t get_buffer_size() const { RTI_FLAT_OFFSET_CHECK_NOT_NULL(return 0); return stream_.total_size(); } /** * @brief Compares two Offsets * * @return True if s1 points to a position smaller than s2's. */ friend bool operator<( const OffsetBase & s1, const OffsetBase & s2) { return s1.get_buffer() < s2.get_buffer(); } /** * @brief Compares two Offsets * * @return True if s1 points to a position greater than s2's. */ friend bool operator > ( const OffsetBase & s1, const OffsetBase & s2) { return s1.get_buffer() > s2.get_buffer(); } /** * @brief Compares two Offsets * * @return True if s1 points to a position equal to or smaller than s2's. */ friend bool operator <= ( const OffsetBase & s1, const OffsetBase & s2) { return s1.get_buffer() <= s2.get_buffer(); } /** * @brief Compares two Offsets * * @return True if s1 points to a position equal to or greater than s2's. */ friend bool operator >= ( const OffsetBase & s1, const OffsetBase & s2) { return s1.get_buffer() >= s2.get_buffer(); } /** * @brief Determines if two offets point to the same position * * @return True if s1 points to the same position as s2. */ friend bool operator == ( const OffsetBase & s1, const OffsetBase & s2) { return s1.get_buffer() == s2.get_buffer(); } /** * @brief Determines if two offets point to different positions * * @return True if s1 points to a different position than s2. */ friend bool operator != ( const OffsetBase & s1, const OffsetBase & s2) { return !(s1 == s2); } protected: OffsetBase() : sample_(NULL), absolute_offset_(0) { } OffsetBase( SampleBase *sample, offset_t absolute_offset, offset_t serialized_size) : sample_(sample), absolute_offset_(absolute_offset) { // In modern C++ this throws PreconditionNotMetError; in traditional // C++, this ends the constructor leaving the object in a state such // that is_null() is true. RTI_FLAT_CHECK_PRECONDITION(sample != NULL, return); sample_->initialize_stream( stream_.c_stream(), absolute_offset_, serialized_size); } // Gets the value of a primitive member at the specified relative Offset template U deserialize(offset_t member_offset) const { RTI_FLAT_OFFSET_CHECK_NOT_NULL(return U()); RTI_FLAT_ASSERT(stream_.check_size(member_offset + static_cast(sizeof(U))), return U()); rti::xcdr::Stream::Memento stream_memento(stream_); stream_.skip_fast(member_offset); return stream_.deserialize_fast(); } // Sets the value of a primitive member at the specified relative Offset template bool serialize(offset_t member_offset, U value) { RTI_FLAT_OFFSET_CHECK_NOT_NULL(return false); RTI_FLAT_ASSERT(stream_.check_size(member_offset + static_cast(sizeof(U))), return false); rti::xcdr::Stream::Memento stream_memento(stream_); stream_.skip_fast(member_offset); stream_.serialize_fast(value); return true; } // Obtains a member at the specified relative offset // // U is the type of the member. U must be a subclass of Offset. template U get_member(offset_t relative_member_offset) { RTI_FLAT_OFFSET_CHECK_NOT_NULL(return U()); return U( sample_, // the absolute location of the member: absolute_offset_ + relative_member_offset); } template U get_member(offset_t relative_member_offset) const { RTI_FLAT_OFFSET_CHECK_NOT_NULL(return U()); return U( sample_, // the absolute location of the member: absolute_offset_ + relative_member_offset); } protected: SampleBase *sample_; // the actual CDR buffer is in the sample offset_t absolute_offset_; // the position of this Offset in the buffer mutable rti::xcdr::Stream stream_; // a substream that shares the same buffer }; /** * @ingroup RTIFlatOffsetsModule * @brief The base class of all Offsets to a final struct type * * This class contains only implementation details; all the public accessors * are defined in the generated type (MyFlatFinalOffset). */ template class FinalOffset : public OffsetBase { public: typedef fixed_size_type_tag_t offset_kind; static offset_t serialized_size_w_padding() { RTI_FLAT_ASSERT(T::serialized_size(0) > 0, return 0); RTI_FLAT_ASSERT(T::required_alignment > 0, return 0); const offset_t element_size = T::serialized_size(0); if (element_size % T::required_alignment != 0) { return element_size + T::required_alignment - element_size % T::required_alignment; } else { return element_size; } } bool is_cpp_compatible() const // override { RTI_FLAT_OFFSET_CHECK_NOT_NULL(return false); return !stream_.needs_byte_swap() && rti::xcdr::has_cpp_friendly_cdr_layout< typename rti::flat::flat_type_traits::flat_type>(); } protected: FinalOffset() { } // Creates an Offset within the sample's CDR buffer at the specified // absolute offset // // This overload requires T::serialized_size(offset_t) // FinalOffset(SampleBase *sample, offset_t absolute_offset) : OffsetBase( sample, absolute_offset, T::serialized_size(absolute_offset)) { } // Gets the value of a primitive member at the specified relative offset // relative_member_offsets - the 4 possible offsets depending on the this // type's initial alignment template U deserialize(const offset_t *relative_member_offsets) const { RTI_FLAT_ASSERT(relative_member_offsets != NULL, return U()); // In a FinalOffset the stream is guaranteed to have enough space to // contain all its members. There are two possible cases: // // - If the FinalOffset is a member of a mutable type, the member getter // will ensure that the stream has enough space for the whole final // type. // // - If the final offset is a top-level type, the type plugin ensures // that the serialized buffer is large enough to contain the type. return OffsetBase::deserialize( // pick the right offset based on the initial alignment get_value_for_alignment(relative_member_offsets)); } // Sets the value of a primitive member at the specified relative offset template bool serialize(const offset_t *relative_member_offsets, U value) { RTI_FLAT_ASSERT(relative_member_offsets != NULL, return false); return OffsetBase::serialize( // pick the right offset based on the initial alignment get_value_for_alignment(relative_member_offsets), value); } // Obtains a member at the specified relative offset // // U is the type of the member. U must be a subclass of Offset. template U get_member(const offset_t *relative_member_offsets) { RTI_FLAT_ASSERT(relative_member_offsets != NULL, return U()); return OffsetBase::get_member( get_value_for_alignment(relative_member_offsets)); } template U get_member(const offset_t *relative_member_offsets) const { RTI_FLAT_ASSERT(relative_member_offsets != NULL, return U()); return OffsetBase::get_member( get_value_for_alignment(relative_member_offsets)); } // Returns an FinalArrayOffset located within this Offset template FinalArrayOffset get_array_member( const offset_t *relative_member_offsets, const offset_t *first_element_sizes, offset_t element_size) { typedef FinalArrayOffset ArrayType; RTI_FLAT_ASSERT(relative_member_offsets != NULL, return ArrayType()); RTI_FLAT_ASSERT(first_element_sizes != NULL, return ArrayType()); RTI_FLAT_OFFSET_CHECK_NOT_NULL(return ArrayType()); return ArrayType( sample_, // the absolute location of the member: absolute_offset_ + get_value_for_alignment(relative_member_offsets), // the size of the first element, which can differ from the rest get_value_for_alignment(first_element_sizes), // the size of every other element element_size); } template FinalArrayOffset get_array_member( const offset_t *relative_member_offsets, const offset_t *first_element_sizes, offset_t element_size) const { typedef FinalArrayOffset ArrayType; RTI_FLAT_ASSERT(relative_member_offsets != NULL, return ArrayType()); RTI_FLAT_ASSERT(first_element_sizes != NULL, return ArrayType()); RTI_FLAT_OFFSET_CHECK_NOT_NULL(return ArrayType()); return ArrayType( sample_, // the absolute location of the member: absolute_offset_ + get_value_for_alignment(relative_member_offsets), // the size of the first element, which can differ from the rest get_value_for_alignment(first_element_sizes), // the size of every other element element_size); } private: // A member's relative offset or an array's first element size // may be different depending on the alignment of the position in the CDR // buffer of the type that contains them (this). These values are passed // to get_member or get_array_member as an array of 4 possible values. This // function picks the right one based on the alingmenet of absolute_offset_ offset_t get_value_for_alignment(const offset_t *values_per_alignment) const { return values_per_alignment [absolute_offset_ % RTI_XCDR_MAX_XCDR2_ALIGNMENT]; } }; struct MutableOffsetHelper { // Obtains the size of a mutable struct located at the absolute_offset of // a FlatData sample static offset_t calculate_serialized_size( rti::flat::SampleBase *sample, offset_t absolute_offset, offset_t) { RTI_FLAT_ASSERT(sample != NULL, return 0); return RTIXCdrFlatSample_getMutableSampleSize( sample->get_buffer(), absolute_offset); } }; /** * @ingroup RTIFlatOffsetsModule * @brief The base class of all Offsets to a final struct type * * This class contains only implementation details; all the public accessors * are defined in the generated type (MyFlatMutableOffset). */ class MutableOffset : public OffsetBase { public: typedef variable_size_type_tag_t offset_kind; typedef MutableOffsetHelper Helper; protected: MutableOffset() { } MutableOffset( SampleBase *sample, offset_t absolute_offset, offset_t serialized_size) : OffsetBase( sample, absolute_offset, serialized_size) { } template U deserialize(member_id_t member_id, U default_val = U()) const { RTI_FLAT_OFFSET_CHECK_NOT_NULL(return U()); rti::xcdr::Stream::Memento stream_memento(stream_); offset_t member_size = 0; if (!RTIXCdrStream_findV2MutableSampleMember( &stream_.c_stream(), member_id, &member_size)) { return default_val; } return stream_.deserialize_fast(); } // Sets the value of a primitive member at the specified relative offset template bool serialize(member_id_t member_id, U value) { RTI_FLAT_OFFSET_CHECK_NOT_NULL(return false); rti::xcdr::Stream::Memento stream_memento(stream_); offset_t member_size = 0; if (!RTIXCdrStream_findV2MutableSampleMember( &stream_.c_stream(), member_id, &member_size)) { return false; } stream_.serialize_fast(value); return true; } template U get_member(member_id_t member_id) const { RTI_FLAT_OFFSET_CHECK_NOT_NULL(return U()); rti::xcdr::Stream::Memento stream_memento(stream_); offset_t member_size = 0; if (!RTIXCdrStream_findV2MutableSampleMember( &stream_.c_stream(), member_id, &member_size)) { return U(); } return get_member_impl( // absolute offset to the found member detail::ptrdiff(stream_.current_position(), sample_->get_buffer()), member_size, typename U::offset_kind()); } private: template U get_member_impl( offset_t absolute_member_offset, offset_t member_size, variable_size_type_tag_t) const { RTI_FLAT_ASSERT(absolute_member_offset > 0, return U()); // VariableOffsets receive a member_size return U(sample_, absolute_member_offset, member_size); } template U get_member_impl( offset_t absolute_member_offset, offset_t member_size, fixed_size_type_tag_t) const { (void) member_size; // suppress unused-param warning in release mode RTI_FLAT_ASSERT(absolute_member_offset > 0, return U()); // FixedOffsets do not receive a member_size (it's already known) return U(sample_, absolute_member_offset); } }; /** * @ingroup RTIFlatOffsetsModule * @brief A const Offset to an optional primitive member * * Read-only version of PrimitiveOffset. * * If !is_null(), the value can be retrieved with get(). */ template struct PrimitiveConstOffset : public OffsetBase { public: typedef fixed_size_type_tag_t offset_kind; PrimitiveConstOffset() { } PrimitiveConstOffset( SampleBase *sample, offset_t absolute_offset) : OffsetBase( sample, absolute_offset, serialized_size(0)) { } bool is_cpp_compatible() const { RTI_FLAT_OFFSET_CHECK_NOT_NULL(return false); return sizeof(T) == 1 || !stream_.needs_byte_swap(); } /** * @brief Gets the value of this primitive member * * @pre !is_null() */ T get() const { RTI_FLAT_OFFSET_CHECK_NOT_NULL(return T()); RTI_FLAT_ASSERT(stream_.check_size(sizeof(T)), return T()); return stream_.deserialize_fast(); } static offset_t serialized_size(offset_t) { return sizeof(T); } static offset_t serialized_size_w_padding() { return serialized_size(0); } }; /** * @ingroup RTIFlatOffsetsModule * @brief An Offset to an optional primitive member * * @tparam T The primitive type * * Non-optional primitive members are accessed directly using its container * type's methods; however, since an optional member may not exist, this Offset * is returned instead. The only purpose of the type PrimitiveOffset is to * provide a way to check for the member's existence. * * If !is_null(), the value can be retrieved with get() or set with set(). * * @see MyFlatMutableOffset::my_optional_primitive vs. * MyFlatMutableOffset::my_primitive */ template struct PrimitiveOffset : public PrimitiveConstOffset { public: PrimitiveOffset() { } PrimitiveOffset( SampleBase *sample, offset_t absolute_offset) : PrimitiveConstOffset( sample, absolute_offset) { } /** * @brief Sets a value for this primitive member * * @pre !is_null() */ bool set(T value) { RTI_FLAT_OFFSET_CHECK_NOT_NULL(return false); RTI_FLAT_ASSERT(this->stream_.check_size(sizeof(T)), return false); this->stream_.template serialize_fast(value); return true; } }; } } #endif // RTI_DDS_FLAT_FLATOFFSETS_HPP_