/* (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_BUILDER_HPP_ #define RTI_DDS_FLAT_BUILDER_HPP_ #include "xcdr/xcdr_stream.h" #include "xcdr/xcdr_stream_impl.h" #include "xcdr/xcdr_interpreter.h" #include "xcdr/xcdr_interpreter.h" #include "rti/xcdr/Stream.hpp" #include "rti/flat/ExceptionHelper.hpp" #include "rti/flat/SequenceOffsets.hpp" /** * @defgroup RTIFlatBuildersModule FlatData Builders * @ingroup RTIFlatDataModule * @brief A Builder allows creating and initializing variable-size data * * Builders allow creating variable-size \ref RTIFlatSampleModule "FlatData samples", * as described in \ref PublishingFlatData. * * There are the following Builder types: * * * * * * * * * * * * * * * * * * * * * * *
CategoryBuilder type
User types For example:
    *
  • MyFlatMutableBuilder, a mutable struct
  • *
  • MyFlatUnionBuilder, a union
  • *
  • Final structs are fixed-size and do not have a Builder (see for * example MyFlatMutableBuilder::add_my_final()). *
Arrays
    *
  • rti::flat::MutableArrayBuilder
  • *
  • Arrays of final elements are fixed-size and do not have a Builder * (see for example MyFlatMutableBuilder::add_my_final_array()).
  • *
Sequences
    *
  • rti::flat::MutableSequenceBuilder for sequences of mutable elements
  • *
  • rti::flat::FinalSequenceBuilder for sequences of final elements
  • *
  • rti::flat::PrimitiveSequenceBuilder for sequences of primitive elements
  • *
  • rti::flat::StringBuilder
  • *
Primitive types
    *
  • Primitive members are added using one of the member functions of the * Builder of the type that contains them. See for example * MyFlatMutableBuilder::add_my_primitive()
  • < *
* * Builder for user types, such as MyFlatMutableBuilder, can behave as * sample builders, when they build a sample, or member builders * when they build a member for another Builder (such as the Builder returned * by MyFlatMutableBuilder::build_my_mutable()). All the other Builder types * (sequences, arrays) are always member builders (such as the Builder returned * by MyFlatMutableBuilder::build_my_final_seq()). * * Builders are move-only types. They cannot be copied, only moved. When * you assign a Builder as the return value of a function, this happens * automatically. * * \code * // the return value of 'build_data' is moved into 'builder' * MyFlatMutableBuilder builder = rti::flat::build_data(writer); * \endcode * * To explicitly move a Builder variable \if CPP_LANGUAGE_ONLY in * the Traditional C++ API, call its \p move() member function\else use \p std::move() * in C++11 platforms or call the \p move() member function in pre-C++11 platforms. * \endif * * @section BuilderErrorManagement Builder Error Management * \if CPP_LANGUAGE_ONLY * The Traditional C++ API reports Builder errors by setting a flag * that can be checked with the member function \ref rti::flat::AbstractBuilder::check_failure() * "check_failure()". After each Builder operation, \p check_failure() must be * called to check (and clear) the error flag. * * In addition, in case of error, operations that return another Builder, such * as MyFlatMutableBuilder::build_my_mutable(), return an invalid Builder * (\ref rti::flat::AbstractBuilder::is_valid() "is_valid()" is \p false). * Operations that return an * Offset, such as MyFlatMutableBuilder::add_my_final() return a "null" Offset * when they fail (see \ref OffsetErrorManagement). * \endif * \if CPP2_LANGUAGE_ONLY * In the Modern C++ API errors are notified with exceptions. Builder operations * may throw the following exceptions * - dds::core::PreconditionNotMetError, for any precondition failure. * - dds::core::OutOfResourcesError, when the Builder's underlying buffer runs * out of space (this should not happen when the Builder has been created with * rti::flat::build_data()). * * See also \ref OffsetErrorManagement. * \endif * * @see MyFlatMutableBuilder for more information specific to builders for user * types. */ #ifdef DOXYGEN_DOCUMENTATION_ONLY /** * @ingroup RTIFlatBuildersModule * @brief Represents the Builder for an arbitrary user-defined mutable type * * This example type represents the \ref RTIFlatBuildersModule "Builder" type * that \nddsgen would generate for \ref MyFlatMutable and allows creating a * sample or a member of that type. * * The most common way to create a Builder is rti::flat::build_data(), which * obtains a managed sample from a \idref_FooDataWriter as described in * \ref PublishingFlatData. It is also possible to create a Builder with an * arbitrary buffer using the constructor that receives the buffer and its size. * * When a Builder is created, the type is empty--it doesn't contain any members. * The Builder provides functions to create each member. There are two kind of * functions: \p add functions and \p build functions. * * Adding fixed-size members * ------------------------- * Fixed-size members are "added", and the corresponding function is called * \p add_. "Add" functions directly place the member in * the buffer, and return an \ref RTIFlatOffsetsModule "Offset" that allows * setting its values. * * By default, after calling \p add_ the * member values are uninitialized. This behavior can be changed by creating * the writer with * \idref_DataWriterResourceLimitsQosPolicy_initialize_writer_loaned_sample; * this is however not recommended in general because of the performance impact * for large types. * * \code * MyFlatMutableBuilder builder = ...; * MyFinalFooOffset member_offset = builder.add_my_final(); * member_offset.my_primitive(10); * // ... add/build more members * \endcode * * * * Building variable-size members * ------------------------------ * Variable-size members are "built", and the function is called * \p build_. "Build" functions return another * \ref RTIFlatBuildersModule "Builder" to build the member. * * \code * MyFlatMutableBuilder builder = ...; * auto member_builder = builder.build_my_mutable(); * // ... use member_builder * member_builder.finish(); * // ... add/build more members * \endcode * * While a member is being built, the parent Builder is a bound state, * which prevents any changes to it until the member has been finished by calling * \p member_builder.finish(). In particular, the member Builder must be finished * before adding or building any other member, or before finishing \p builder. * * Choosing which members are included * ----------------------------------- * The \p add/build function for each member can be called one or zero times. * That is, all members are optional, even those without the \p \@optional IDL * annotation. However \p \@key member must be added or \idref_FooDataWriter_write * will fail. * * FlatData samples received by \idref_DataReader will not * contain the members that were not added/built--the corresponding member getters * return a null Offset. A \idref_DataReader for an equivalent non-FlatData * (plain) definition of this type will assign default values to any non-optional * members that were not present in the sample when written. * * It is not permitted to add a member more than once, but builders don't enforce * this. Trying to build/add a member more than once may cause the Builder to * overflow (see \ref BuilderErrorManagement). If it doesn't, it may be * possible to write and read the data samples, but the duplicate members will * be ignored. * * @see \ref RTIFlatBuildersModule */ class NDDSUSERDllExport MyFlatMutableBuilder : public rti::flat::AggregationBuilder { public: /** * @brief The related offset type */ typedef MyFlatMutableOffset Offset; /** * @brief Creates an invalid Builder * * @post !is_valid() * * @note Top-level builders are created with rti::flat::build_data(), and * member builders are created with the corresponding \p build_ * function. */ MyFlatMutableBuilder() { } /** * @brief Construct a Builder with an arbitrary buffer * * @note The recommended way to create a Builder is rti::flat::build_data() * as described in \ref PublishingFlatData. This constructor provides an * alternative option to use an arbitrary data buffer. * * @param buffer The buffer that will be used to build the data sample * @param size The size of the buffer * @param initialize_members Whether fixed-size elements added to this * Builder will be initialized to their default values or will be left * uninitialized (more efficient). * * If the sample being built overflows the buffer size, the add/build * operations will fail. See \ref BuilderErrorManagement. */ MyFlatMutableBuilder( unsigned char *buffer, int32_t size, bool initialize_members = false) { } /** * @brief Finishes building a member * * @return The Offset to the member (normally it can be ignored) * * @pre \ref rti::flat::AbstractBuilder::is_nested() "is_nested()". That is, * this object must be a member Builder, not a sample Builder. */ Offset finish(); /** * @brief Finishes building a sample * * @pre \ref rti::flat::AbstractBuilder::is_nested() "!is_nested()". * That is, this object must be a sample Builder, not a member Builder. * @post \ref rti::flat::AbstractBuilder::is_valid "!is_valid()". * That is, this Builder can no longer be used. * * @return The sample, ready to be written. * * This function completes and returns the sample built with this Builder. * * @see rti::flat::build_data(), the function to create a * \idref_FooDataWriter-managed sample Builder. */ MyFlatMutable * finish_sample(); /** * @brief Adds a primitive member */ bool add_my_primitive(int32_t value); /** * @brief Adds a primitive member */ bool add_my_optional_primitive(int32_t value); /** * @brief Adds a primitive array member * * @return The Offset to the array, which can be used to set its values. */ rti::flat::PrimitiveArrayOffset add_my_primitive_array(); /** * @brief Begins building a primitive-sequence member */ rti::flat::PrimitiveSequenceBuilder build_my_primitive_seq(); /** * @brief Adds a final complex member * * @return The Offset to the member, which can be used to set its values. */ MyFlatFinalOffset add_my_final(); /** * @brief Adds an array member of final complex elements * * @return The Offset to the array, which can be used to set its values. */ rti::flat::FinalAlignedArrayOffset add_my_final_array(); /** * @brief Begins building a sequence member of final complex elements */ rti::flat::FinalSequenceBuilder build_my_final_seq(); /** * @brief Begins building a mutable complex member * * FlatMutableBar represents another arbitrary mutable FlatData type. */ FlatMutableBarBuilder build_my_mutable(); /** * @brief Begins building an array member of mutable complex elements */ rti::flat::MutableArrayBuilder build_my_mutable_array(); /** * @brief Begins building a sequence member of mutable complex elements */ rti::flat::MutableSequenceBuilder build_my_mutable_seq(); /** * @brief Begins building a string member */ rti::flat::StringBuilder build_my_string(); /** * @brief Begins building a sequence member of string elements */ rti::flat::MutableSequenceBuilder build_my_string_seq(); }; /** * @ingroup RTIFlatBuildersModule * @brief Represents the Builder for an arbitrary user-defined mutable IDL union * * This example type represents the \ref RTIFlatBuildersModule "Builder" type * that \nddsgen would generate for \ref MyFlatUnion and allows creating a * sample or a member of that type. * * Union builders are similar to struct builders (see MyFlatMutableBuilder), * except that they only allow adding/building one member. * * "Add" and "build" functions automatically set the discriminator value that * in the IDL definition selects that member. If more than one discriminator * value selects a member, the add/build function allows picking one. * */ class MyFlatUnionBuilder : public rti::flat::UnionBuilder { public: /** * @brief The related offset type */ typedef MyFlatUnionOffset Offset; /** * @brief Creates an invalid Builder * * @post !is_valid() * * @note Top-level builders are created with rti::flat::build_data(), and * member builders are created with the corresponding \p build_ * function. */ MyFlatUnionBuilder() { } /** * @brief Finishes building a member * * @see MyMutableBuilder::finish() */ Offset finish(); /** * @brief Finishes building a sample * * @see MyMutableBuilder::finish_sample() */ MyFlatUnion * finish_sample(); /** * @brief Adds a primitive member * * This function automatically selects the discriminator 0, which corresponds * to the member 'my_primitive' (see \ref MyFlatUnion) */ bool add_my_primitive(int32_t value); /** * @brief Builds a mutable-struct member * * @param discriminator Allows selecting one of the possible discriminator * values for this member: 1 or 2. This argument is optional: if not * specified it selects the first 'case' label in the IDL definition (1). * * @return The Builder to build this member */ MyFlatMutableBuilder build_my_mutable(int32_t discriminator = 1); /** * @brief Adds a final-struct member * * @return The Offset to the member, which can be used to set its values. * * This function automatically selects the discriminator value 3, which * corresponds to the member 'my_final' (see \ref MyFlatUnion). */ MyFlatFinal::Offset add_my_final(); }; #endif namespace rti { namespace flat { // Support for move constructor and assignment operator in C++98 // // All concrete subclasses of AbstractBuilder must use this macro to implement // move semantics // #if defined(RTI_FLAT_DATA_CXX11_RVALUE_REFERENCES) #define RTI_FLAT_BUILDER_DEFINE_MOVE_OPERATIONS_IMPL(TYPE, BASE, PROXY) #define RTI_FLAT_BUILDER_DEFINE_MOVE_OPERATIONS(TYPE, BASE) #define RTI_FLAT_MOVE_BUILDER(BUILDER) BUILDER #else #define RTI_FLAT_BUILDER_DEFINE_MOVE_OPERATIONS_IMPL(TYPE, BASE, PROXY) \ public: \ TYPE(PROXY other) throw() \ { \ this->move_from(other); \ } \ TYPE& operator=(PROXY other) throw() \ { \ this->finish_untyped_impl(); \ this->move_from(other); \ return *this; \ } \ TYPE move() \ { \ return TYPE(PROXY(*this)); \ } \ private: \ TYPE(TYPE&); \ TYPE& operator=(TYPE&); // Shortcut for generated IDL types #define RTI_FLAT_BUILDER_DEFINE_MOVE_OPERATIONS(TYPE, BASE) \ RTI_FLAT_BUILDER_DEFINE_MOVE_OPERATIONS_IMPL( \ TYPE, BASE, UntypedAggregationBuilderMoveProxy) #define RTI_FLAT_MOVE_BUILDER(BUILDER) (BUILDER).move() #endif namespace detail { // Template parameters can be AbstractBuilder or AbstractBuilderMoveProxy template void move_abstract_builder(Builder1& to, Builder2& from) { if (from.parent_builder_ == NULL) { to.owned_stream_ = from.owned_stream_; } to.parent_stream_ = from.parent_stream_; to.parent_builder_ = from.parent_builder_; to.begin_position_ = from.begin_position_; to.bind_position_ = from.bind_position_; to.initialize_on_add_ = from.initialize_on_add_; #ifdef RTI_FLAT_DATA_NO_EXCEPTIONS to.failure_ = from.failure_; #endif from.parent_stream_ = NULL; from.parent_builder_ = NULL; from.bind_position_ = NULL; from.begin_position_ = NULL; } } /* * @brief Provides the functionality common to all builders * * This class is the base of all builders and provides the following * functionality: * * - Get the buffer and its size * - Add final elements (base case) * - Build operations--create nested builders, binding (base case) * - Finish operation--unbind (base case) * - Discard operation--throw away a nested Builder and roll back the parent * - Error management when exceptions are not supported (traditional C++) * - Move semantics (base case) */ /** * @ingroup RTIFlatBuildersModule * @brief Base class of all \ref RTIFlatBuildersModule "Builders" */ class AbstractBuilder { protected: AbstractBuilder() : parent_stream_(NULL), parent_builder_(NULL), begin_position_(NULL), bind_position_(NULL), initialize_on_add_(false) #ifdef RTI_FLAT_DATA_NO_EXCEPTIONS , failure_(false) #endif { } /*i * @brief Create a new top-level Builder */ AbstractBuilder(unsigned char *buffer, offset_t size, bool initialize_members) : parent_stream_(NULL), parent_builder_(NULL), bind_position_(NULL), initialize_on_add_(initialize_members) #ifdef RTI_FLAT_DATA_NO_EXCEPTIONS , failure_(false) #endif { // Serializes the encapsulation into the buffer and initializes the // stream with that buffer and that encapsulation if (!RTIXCdrFlatSample_initializeEncapsulationAndStream( (char *) buffer, &owned_stream_.c_stream(), RTIXCdrEncapsulationId_getNativePlCdr2(), size)) { RTI_FLAT_BUILDER_OUT_OF_RESOURCES_ERROR(return); } begin_position_ = owned_stream_.current_position(); } protected: template friend void detail::move_abstract_builder(Builder1& to, Builder2& from); #if defined(RTI_FLAT_DATA_CXX11_RVALUE_REFERENCES) AbstractBuilder(AbstractBuilder&& other) { detail::move_abstract_builder(*this, other); } AbstractBuilder& operator=(AbstractBuilder&& other) { if (this == &other) { return *this; } finish_untyped_impl(); detail::move_abstract_builder(*this, other); return *this; } #else // Enables the safe-move-constructor idiom without C++11 move constructors struct AbstractBuilderMoveProxy { rti::xcdr::Stream owned_stream_; rti::xcdr::Stream *parent_stream_; AbstractBuilder *parent_builder_; unsigned char *begin_position_; unsigned char *bind_position_; bool initialize_on_add_; #ifdef RTI_FLAT_DATA_NO_EXCEPTIONS bool failure_; #endif }; void move_from(AbstractBuilderMoveProxy& other) { detail::move_abstract_builder(*this, other); } void move_to(AbstractBuilderMoveProxy& other) { detail::move_abstract_builder(other, *this); } operator AbstractBuilderMoveProxy () throw() // move-constructor idiom { AbstractBuilderMoveProxy other; move_to(other); return other; } private: AbstractBuilder(AbstractBuilder& other); AbstractBuilder& operator=(AbstractBuilder& other); #endif protected: /** * @brief If this is a member Builder, it calls finish(). * * If this Builder is building a member (that is, is_nested() is true), and * the object goes out of scope before finish() has been called, its * destructor calls finish(). Note, however, that it won't report any error. * * If this Builder is building a sample (!is_nested()), its destructor doesn't * do anything. * */ virtual ~AbstractBuilder() { finish_untyped_impl(); } struct nested_tag_t {}; // disambiguate copy constructor /*i * @brief Creates a nested Builder to build a member or element * * @param parent The Builder for the type that contains the member or element * this Builder builds. * * @param alignment Specifies the alignment required by the concrete Builder. * Namely, aggregation and sequence builders require alignment of 4 for the * DHeader and the sequence length, respectively. This alignment doesn't * reflect the alignment requirement of the elements, that's why arrays do * not require an alignment here. If no alignment is required, this parameter * must be zero. Concrete classes must provide a default value for alignment, * that indicates their requirement. This parameter can be overridden by * build_element_no_align to when we know we don't need to align. */ AbstractBuilder( nested_tag_t, AbstractBuilder& parent, unsigned int alignment) : /* owned_stream_ empty and unused */ parent_stream_(&parent.stream()), /* work on the parent's stream */ parent_builder_(&parent), begin_position_(NULL), bind_position_(NULL), initialize_on_add_(parent.initialize_on_add_) #ifdef RTI_FLAT_DATA_NO_EXCEPTIONS , failure_(false) #endif { if (alignment != 0) { if (!stream().align(alignment)) { RTI_FLAT_BUILDER_OUT_OF_RESOURCES_ERROR(return); } } begin_position_ = stream().current_position(); } unsigned char * buffer() { return stream().buffer(); } unsigned char * begin_position() { return begin_position_; } /*i * @brief Adds a fixed-size member or element * * @return The offset to the member or element that was added. This offset * can be used to initialize it. */ template OffsetType add_element() { RTI_FLAT_BUILDER_CHECK_VALID(return OffsetType()); RTI_FLAT_BUILDER_CHECK_NOT_BOUND(return OffsetType()); offset_t member_size = OffsetType::serialized_size(0); unsigned char *pos = stream().current_position(); if (detail::is_fixed_type_w_dheader::value()) { pos = (unsigned char *) stream().serialize_dheader(); if (pos == NULL) { RTI_FLAT_BUILDER_OUT_OF_RESOURCES_ERROR(return OffsetType()); } } if (!stream().skip(member_size)) { RTI_FLAT_BUILDER_OUT_OF_RESOURCES_ERROR(return OffsetType()); } if (detail::is_fixed_type_w_dheader::value()) { stream().finish_dheader((char *) pos); } if (initialize_on_add_) { OffsetType offset( (SampleBase *) stream().buffer(), detail::ptrdiff(pos, stream().buffer())); detail::final_offset_initializer::initialize(offset); return offset; } else { return OffsetType( (SampleBase *) stream().buffer(), detail::ptrdiff(pos, stream().buffer())); } } /*i * @brief Creates a nested Builder to build a variable-size member or element * * @param stream_memento Subclasses using build_element() to implement * their own build method are required to provide a stream memento that * contains the position in the stream before any bytes related to this * member were added. Any error before the nested Builder is created will * cause the memento's destructor to roll back the Builder to its state * before this member was added. If the Builder can be created without errors * stream_mement.discard() is called, and its position is kept in case * the nested Builder is discarded (instead of finished), which also rolls * back the parent Builder to its previous state. * * @post This Builder becomes "bound" until the returned Builder is finished. * While bound, this Builder can't be used to add or build more elements. * * @return The Builder that allows building this member or element */ template NestedBuilder build_element(rti::xcdr::Stream::Memento& stream_memento) { RTI_FLAT_BUILDER_CHECK_VALID(return NestedBuilder()); RTI_FLAT_BUILDER_CHECK_NOT_BOUND(return NestedBuilder()); NestedBuilder nested_builder(nested_tag_t(), *this); RTI_FLAT_BUILDER_CHECK_CREATE_BUILDER( nested_builder, return NestedBuilder()); bind_position_ = stream_memento.discard(); // uninit_use_in_call is not possible given how the constructor for // the NestedBuilder type is generated by rtiddsgen. The warning is // suppressed for performance reasons. /* coverity[uninit_use_in_call : FALSE] */ return RTI_FLAT_MOVE_BUILDER(nested_builder); } template NestedBuilder build_element_no_align(rti::xcdr::Stream::Memento& stream_memento) { RTI_FLAT_BUILDER_CHECK_VALID(return NestedBuilder()); RTI_FLAT_BUILDER_CHECK_NOT_BOUND(return NestedBuilder()); // By passing '0' to the builder constructor we override its default // argument which indicates its required alignment NestedBuilder nested_builder(nested_tag_t(), *this, 0); RTI_FLAT_BUILDER_CHECK_CREATE_BUILDER( nested_builder, return NestedBuilder()); bind_position_ = stream_memento.discard(); // uninit_use_in_call is not possible given how the constructor for // the NestedBuilder type is generated by rtiddsgen. The warning is // suppressed for performance reasons. /* coverity[uninit_use_in_call : FALSE] */ return RTI_FLAT_MOVE_BUILDER(nested_builder); } /*i * @brief Returns the currently used number of bytes * * The current size is the number of bytes that have been used to create * this sample by adding or building members. * * When current_size() reaches capacity(), the Builder will fail to add * or build any additional member. * * @see capacity(). */ unsigned int current_size() { return detail::ptrdiff(stream().current_position(), begin_position_); } friend class AggregationBuilder; // to access finish_member() // Finishes this nested builder, updating the parent builder. // // This function doesn't throw exceptions and doesn't return a typed Offset // This function can be used in destructors to "silently" finish the builder void finish_untyped_impl() { if (!is_valid() || !is_nested()) { return; } parent_builder_->finish_member(); invalidate(); } protected: /*i * @brief Complete the building of a nested member * * Concrete Builders must implement a finish() function with the following body: * * RTI_FLAT_BUILDER_CHECK_CAN_FINISH(...); * // optionally, additonal work * return finish_impl(); * * Destructors can directly call finish_untyped_impl(); * * When this is a nested Builder, this function indicates that this element * or member is complete. * * This function is automatically called by the Builder destructor. * * Concrete builders must override this function to return a typed Offset to * the element that was built. * * @post This Builder is in an empty state and cannot be used further * * @return The position in the buffer where this element ended. */ template OffsetType finish_impl() { RTI_FLAT_BUILDER_CHECK_VALID(return OffsetType()); unsigned char *begin_pos = this->begin_position_; unsigned char *sample_base = stream().buffer(); unsigned char *current_pos = stream().current_position(); finish_untyped_impl(); return OffsetType( reinterpret_cast(sample_base), // start of the top-level sample detail::ptrdiff(begin_pos, sample_base), // absoute offset to the member detail::ptrdiff(current_pos, begin_pos)); // size of the member } public: /** * @brief Discards a member in process of being built * * This function ends the creation of a member, returning the Builder of * the type that contains the member to its previous state, as if this * member had never been built. * * @pre This object must be a member Builder, not a sample Builder. * * This method is useful when during the building of a member an error * occurs and the application wants to roll back, instead of finishing an * incomplete member. */ void discard() { RTI_FLAT_BUILDER_CHECK_VALID(return); RTI_FLAT_BUILDER_CHECK_CAN_FINISH(return); parent_builder_->discard_member(); invalidate(); } /** * @brief Returns whether this is a member Builder * * A member Builder is a Builder that has been created * by calling a \p "build_" function on another Builder (for * example, MyFlatMutableBuilder::build_my_mutable()). * * @return True if this is a member Builder, or false if this is a sample * Builder. */ bool is_nested() const { return parent_builder_ != NULL; } /** * @brief Whether this Builder is valid * * A Builder is not valid when it is default-constructed, or after any * of these functions is called: finish(), finish_sample(), discard(). * * \if CPP_LANGUAGE_ONLY * Since the Traditional C++ API doesn't use exceptions, certain function * failures due to the Builder running out resources are also reported by * invalidating the Builder. * \endif */ bool is_valid() const { return begin_position_ != NULL; } /** * @brief Returns the total capacity in bytes * * The capacity is the total number of bytes this Builder can contain. For * a sample Builder (that is, one such that is_nested() returns false), * rti::flat::build_data reserves enough bytes to accommodate any sample of * a given type. */ rti::xcdr::length_t capacity() const { return stream().total_size(); } protected: // Makes this Builder invalid after finish(); discard(); finish_sample(); // and, when exceptions are not enabled (traditional C++ API), after an // error during construction void invalidate() { parent_stream_ = NULL; parent_builder_ = NULL; bind_position_ = NULL; begin_position_ = NULL; } // This function is called by a nested Builder when it has finished building // an element virtual void finish_member() // noexcept { if (!is_valid()) { return; } bind_position_ = NULL; } void discard_member() { RTI_FLAT_BUILDER_CHECK_VALID(return); stream().current_position(bind_position_); bind_position_ = NULL; } rti::xcdr::Stream& stream() { if (parent_stream_ != NULL) { return *parent_stream_; } else { return owned_stream_; } } const rti::xcdr::Stream& stream() const { if (parent_stream_ != NULL) { return *parent_stream_; } else { return owned_stream_; } } private: rti::xcdr::Stream owned_stream_; rti::xcdr::Stream *parent_stream_; AbstractBuilder *parent_builder_; unsigned char *begin_position_; unsigned char *bind_position_; bool initialize_on_add_; #ifdef RTI_FLAT_DATA_NO_EXCEPTIONS public: /** * @brief Checks if the previous operation failed and resets the failure flag * * This function must be called after each Builder operation to check if * it succeeded. Note that after calling check_failure() the error flag is * reset, so a subsequent call will always return false. * * @return True if there was a failure in the previous operation, false * if there was no failure since the last call to check_failure. */ bool check_failure() { bool failure = failure_; failure_ = false; return failure; } protected: void set_failure() { failure_ = true; } private: bool failure_; #endif }; } } #endif // RTI_DDS_FLAT_BUILDER_HPP_