RTI Connext Traditional C++ API Version 7.3.0
Builder.hpp
1/*
2(c) Copyright, Real-Time Innovations, 2018.
3All rights reserved.
4
5No duplications, whole or partial, manual or electronic, may be made
6without express written permission. Any such copies, or
7revisions thereof, must display this notice unaltered.
8This code contains trade secrets of Real-Time Innovations, Inc.
9*/
10
11#ifndef RTI_DDS_FLAT_BUILDER_HPP_
12#define RTI_DDS_FLAT_BUILDER_HPP_
13
14#include "xcdr/xcdr_stream.h"
15#include "xcdr/xcdr_stream_impl.h"
16#include "xcdr/xcdr_interpreter.h"
17#include "xcdr/xcdr_interpreter.h"
18
19#include "rti/xcdr/Stream.hpp"
20#include "rti/flat/ExceptionHelper.hpp"
21#include "rti/flat/SequenceOffsets.hpp"
22
124#ifdef DOXYGEN_DOCUMENTATION_ONLY
125
206class NDDSUSERDllExport MyFlatMutableBuilder : public rti::flat::AggregationBuilder {
207 public:
212
223 {
224 }
225
243 unsigned char *buffer,
244 int32_t size,
245 bool initialize_members = false)
246 {
247 }
248
258
275
279 bool add_my_primitive(int32_t value);
280
284 bool add_my_optional_primitive(int32_t value);
285
292
297
304
311
316
322 FlatMutableBarBuilder build_my_mutable();
323
328
333
338
343};
344
362public:
367
368
379 {
380 }
381
388
389
396
403 bool add_my_primitive(int32_t value);
404
414 MyFlatMutableBuilder build_my_mutable(int32_t discriminator = 1);
415
425};
426
427#endif
428
429namespace rti { namespace flat {
430
431// Support for move constructor and assignment operator in C++98
432//
433// All concrete subclasses of AbstractBuilder must use this macro to implement
434// move semantics
435//
436#if defined(RTI_FLAT_DATA_CXX11_RVALUE_REFERENCES)
437#define RTI_FLAT_BUILDER_DEFINE_MOVE_OPERATIONS_IMPL(TYPE, BASE, PROXY)
438#define RTI_FLAT_BUILDER_DEFINE_MOVE_OPERATIONS(TYPE, BASE)
439#define RTI_FLAT_MOVE_BUILDER(BUILDER) BUILDER
440#else
441#define RTI_FLAT_BUILDER_DEFINE_MOVE_OPERATIONS_IMPL(TYPE, BASE, PROXY) \
442public: \
443 TYPE(PROXY other) throw() \
444 { \
445 this->move_from(other); \
446 } \
447 TYPE& operator=(PROXY other) throw() \
448 { \
449 this->finish_untyped_impl(); \
450 this->move_from(other); \
451 return *this; \
452 } \
453 TYPE move() \
454 { \
455 return TYPE(PROXY(*this)); \
456 } \
457private: \
458 TYPE(TYPE&); \
459 TYPE& operator=(TYPE&);
460
461// Shortcut for generated IDL types
462#define RTI_FLAT_BUILDER_DEFINE_MOVE_OPERATIONS(TYPE, BASE) \
463 RTI_FLAT_BUILDER_DEFINE_MOVE_OPERATIONS_IMPL( \
464 TYPE, BASE, UntypedAggregationBuilderMoveProxy)
465
466#define RTI_FLAT_MOVE_BUILDER(BUILDER) (BUILDER).move()
467#endif
468
469namespace detail {
470 // Template parameters can be AbstractBuilder or AbstractBuilderMoveProxy
471 template <typename Builder1, typename Builder2>
472 void move_abstract_builder(Builder1& to, Builder2& from)
473 {
474 if (from.parent_builder_ == NULL) {
475 to.owned_stream_ = from.owned_stream_;
476 }
477
478 to.parent_stream_ = from.parent_stream_;
479 to.parent_builder_ = from.parent_builder_;
480 to.begin_position_ = from.begin_position_;
481 to.bind_position_ = from.bind_position_;
482 to.initialize_on_add_ = from.initialize_on_add_;
483#ifdef RTI_FLAT_DATA_NO_EXCEPTIONS
484 to.failure_ = from.failure_;
485#endif
486
487 from.parent_stream_ = NULL;
488 from.parent_builder_ = NULL;
489 from.bind_position_ = NULL;
490 from.begin_position_ = NULL;
491 }
492}
493
494/*
495 * @brief Provides the functionality common to all builders
496 *
497 * This class is the base of all builders and provides the following
498 * functionality:
499 *
500 * - Get the buffer and its size
501 * - Add final elements (base case)
502 * - Build operations--create nested builders, binding (base case)
503 * - Finish operation--unbind (base case)
504 * - Discard operation--throw away a nested Builder and roll back the parent
505 * - Error management when exceptions are not supported (traditional C++)
506 * - Move semantics (base case)
507 */
513protected:
515 : parent_stream_(NULL),
516 parent_builder_(NULL),
517 begin_position_(NULL),
518 bind_position_(NULL),
519 initialize_on_add_(false)
520#ifdef RTI_FLAT_DATA_NO_EXCEPTIONS
521 , failure_(false)
522#endif
523 {
524 }
525
526 /*i
527 * @brief Create a new top-level Builder
528 */
529 AbstractBuilder(unsigned char *buffer, offset_t size, bool initialize_members)
530 : parent_stream_(NULL),
531 parent_builder_(NULL),
532 bind_position_(NULL),
533 initialize_on_add_(initialize_members)
534#ifdef RTI_FLAT_DATA_NO_EXCEPTIONS
535 , failure_(false)
536#endif
537 {
538 // Serializes the encapsulation into the buffer and initializes the
539 // stream with that buffer and that encapsulation
540 if (!RTIXCdrFlatSample_initializeEncapsulationAndStream(
541 (char *) buffer,
542 &owned_stream_.c_stream(),
543 RTIXCdrEncapsulationId_getNativePlCdr2(),
544 size)) {
545 RTI_FLAT_BUILDER_OUT_OF_RESOURCES_ERROR(return);
546 }
547
548 begin_position_ = owned_stream_.current_position();
549 }
550
551protected:
552 template <typename Builder1, typename Builder2>
553 friend void detail::move_abstract_builder(Builder1& to, Builder2& from);
554
555#if defined(RTI_FLAT_DATA_CXX11_RVALUE_REFERENCES)
557 {
558 detail::move_abstract_builder(*this, other);
559 }
560
561 AbstractBuilder& operator=(AbstractBuilder&& other)
562 {
563 if (this == &other) {
564 return *this;
565 }
566
567 finish_untyped_impl();
568
569 detail::move_abstract_builder(*this, other);
570
571 return *this;
572 }
573#else
574 // Enables the safe-move-constructor idiom without C++11 move constructors
575 struct AbstractBuilderMoveProxy {
576 rti::xcdr::Stream owned_stream_;
577 rti::xcdr::Stream *parent_stream_;
578 AbstractBuilder *parent_builder_;
579 unsigned char *begin_position_;
580 unsigned char *bind_position_;
581 bool initialize_on_add_;
582#ifdef RTI_FLAT_DATA_NO_EXCEPTIONS
583 bool failure_;
584#endif
585 };
586
587 void move_from(AbstractBuilderMoveProxy& other)
588 {
589 detail::move_abstract_builder(*this, other);
590 }
591
592 void move_to(AbstractBuilderMoveProxy& other)
593 {
594 detail::move_abstract_builder(other, *this);
595 }
596
597 operator AbstractBuilderMoveProxy () throw() // move-constructor idiom
598 {
599 AbstractBuilderMoveProxy other;
600 move_to(other);
601 return other;
602 }
603private:
605 AbstractBuilder& operator=(AbstractBuilder& other);
606#endif
607
608protected:
621 {
622 finish_untyped_impl();
623 }
624
625 struct nested_tag_t {}; // disambiguate copy constructor
626
627 /*i
628 * @brief Creates a nested Builder to build a member or element
629 *
630 * @param parent The Builder for the type that contains the member or element
631 * this Builder builds.
632 *
633 * @param alignment Specifies the alignment required by the concrete Builder.
634 * Namely, aggregation and sequence builders require alignment of 4 for the
635 * DHeader and the sequence length, respectively. This alignment doesn't
636 * reflect the alignment requirement of the elements, that's why arrays do
637 * not require an alignment here. If no alignment is required, this parameter
638 * must be zero. Concrete classes must provide a default value for alignment,
639 * that indicates their requirement. This parameter can be overridden by
640 * build_element_no_align to when we know we don't need to align.
641 */
642 AbstractBuilder(
643 nested_tag_t,
644 AbstractBuilder& parent,
645 unsigned int alignment)
646 : /* owned_stream_ empty and unused */
647 parent_stream_(&parent.stream()), /* work on the parent's stream */
648 parent_builder_(&parent),
649 begin_position_(NULL),
650 bind_position_(NULL),
651 initialize_on_add_(parent.initialize_on_add_)
652#ifdef RTI_FLAT_DATA_NO_EXCEPTIONS
653 , failure_(false)
654#endif
655 {
656 if (alignment != 0) {
657 if (!stream().align(alignment)) {
658 RTI_FLAT_BUILDER_OUT_OF_RESOURCES_ERROR(return);
659 }
660 }
661 begin_position_ = stream().current_position();
662 }
663
664 unsigned char * buffer()
665 {
666 return stream().buffer();
667 }
668
669 unsigned char * begin_position()
670 {
671 return begin_position_;
672 }
673
674 /*i
675 * @brief Adds a fixed-size member or element
676 *
677 * @return The offset to the member or element that was added. This offset
678 * can be used to initialize it.
679 */
680 template <typename OffsetType>
681 OffsetType add_element()
682 {
683 RTI_FLAT_BUILDER_CHECK_VALID(return OffsetType());
684 RTI_FLAT_BUILDER_CHECK_NOT_BOUND(return OffsetType());
685
686 offset_t member_size = OffsetType::serialized_size(0);
687 unsigned char *pos = stream().current_position();
688 if (detail::is_fixed_type_w_dheader<OffsetType>::value()) {
689 pos = (unsigned char *) stream().serialize_dheader();
690 if (pos == NULL) {
691 RTI_FLAT_BUILDER_OUT_OF_RESOURCES_ERROR(return OffsetType());
692 }
693 }
694 if (!stream().skip(member_size)) {
695 RTI_FLAT_BUILDER_OUT_OF_RESOURCES_ERROR(return OffsetType());
696 }
697 if (detail::is_fixed_type_w_dheader<OffsetType>::value()) {
698 stream().finish_dheader((char *) pos);
699 }
700
701 if (initialize_on_add_) {
702 OffsetType offset(
703 (SampleBase *) stream().buffer(),
704 detail::ptrdiff(pos, stream().buffer()));
705
706 detail::final_offset_initializer<OffsetType>::initialize(offset);
707
708 return offset;
709 } else {
710 return OffsetType(
711 (SampleBase *) stream().buffer(),
712 detail::ptrdiff(pos, stream().buffer()));
713 }
714 }
715
716 /*i
717 * @brief Creates a nested Builder to build a variable-size member or element
718 *
719 * @param stream_memento Subclasses using build_element() to implement
720 * their own build method are required to provide a stream memento that
721 * contains the position in the stream before any bytes related to this
722 * member were added. Any error before the nested Builder is created will
723 * cause the memento's destructor to roll back the Builder to its state
724 * before this member was added. If the Builder can be created without errors
725 * stream_mement.discard() is called, and its position is kept in case
726 * the nested Builder is discarded (instead of finished), which also rolls
727 * back the parent Builder to its previous state.
728 *
729 * @post This Builder becomes "bound" until the returned Builder is finished.
730 * While bound, this Builder can't be used to add or build more elements.
731 *
732 * @return The Builder that allows building this member or element
733 */
734 template <typename NestedBuilder>
735 NestedBuilder build_element(rti::xcdr::Stream::Memento& stream_memento)
736 {
737 RTI_FLAT_BUILDER_CHECK_VALID(return NestedBuilder());
738 RTI_FLAT_BUILDER_CHECK_NOT_BOUND(return NestedBuilder());
739
740 NestedBuilder nested_builder(nested_tag_t(), *this);
741 RTI_FLAT_BUILDER_CHECK_CREATE_BUILDER(
742 nested_builder,
743 return NestedBuilder());
744
745 bind_position_ = stream_memento.discard();
746
747 // uninit_use_in_call is not possible given how the constructor for
748 // the NestedBuilder type is generated by rtiddsgen. The warning is
749 // suppressed for performance reasons.
750 /* coverity[uninit_use_in_call : FALSE] */
751 return RTI_FLAT_MOVE_BUILDER(nested_builder);
752 }
753
754 template <typename NestedBuilder>
755 NestedBuilder build_element_no_align(rti::xcdr::Stream::Memento& stream_memento)
756 {
757 RTI_FLAT_BUILDER_CHECK_VALID(return NestedBuilder());
758 RTI_FLAT_BUILDER_CHECK_NOT_BOUND(return NestedBuilder());
759
760 // By passing '0' to the builder constructor we override its default
761 // argument which indicates its required alignment
762 NestedBuilder nested_builder(nested_tag_t(), *this, 0);
763 RTI_FLAT_BUILDER_CHECK_CREATE_BUILDER(
764 nested_builder,
765 return NestedBuilder());
766
767 bind_position_ = stream_memento.discard();
768
769 // uninit_use_in_call is not possible given how the constructor for
770 // the NestedBuilder type is generated by rtiddsgen. The warning is
771 // suppressed for performance reasons.
772 /* coverity[uninit_use_in_call : FALSE] */
773 return RTI_FLAT_MOVE_BUILDER(nested_builder);
774 }
775
776 /*i
777 * @brief Returns the currently used number of bytes
778 *
779 * The current size is the number of bytes that have been used to create
780 * this sample by adding or building members.
781 *
782 * When current_size() reaches capacity(), the Builder will fail to add
783 * or build any additional member.
784 *
785 * @see capacity().
786 */
787 unsigned int current_size()
788 {
789 return detail::ptrdiff(stream().current_position(), begin_position_);
790 }
791
792
793 friend class AggregationBuilder; // to access finish_member()
794
795 // Finishes this nested builder, updating the parent builder.
796 //
797 // This function doesn't throw exceptions and doesn't return a typed Offset
798 // This function can be used in destructors to "silently" finish the builder
799 void finish_untyped_impl()
800 {
801 if (!is_valid() || !is_nested()) {
802 return;
803 }
804
805 parent_builder_->finish_member();
806 invalidate();
807 }
808
809protected:
810 /*i
811 * @brief Complete the building of a nested member
812 *
813 * Concrete Builders must implement a finish() function with the following body:
814 *
815 * RTI_FLAT_BUILDER_CHECK_CAN_FINISH(...);
816 * // optionally, additonal work
817 * return finish_impl<OffsetType>();
818 *
819 * Destructors can directly call finish_untyped_impl();
820 *
821 * When this is a nested Builder, this function indicates that this element
822 * or member is complete.
823 *
824 * This function is automatically called by the Builder destructor.
825 *
826 * Concrete builders must override this function to return a typed Offset to
827 * the element that was built.
828 *
829 * @post This Builder is in an empty state and cannot be used further
830 *
831 * @return The position in the buffer where this element ended.
832 */
833 template <typename OffsetType>
834 OffsetType finish_impl()
835 {
836 RTI_FLAT_BUILDER_CHECK_VALID(return OffsetType());
837
838 unsigned char *begin_pos = this->begin_position_;
839 unsigned char *sample_base = stream().buffer();
840 unsigned char *current_pos = stream().current_position();
841 finish_untyped_impl();
842
843 return OffsetType(
844 reinterpret_cast<SampleBase *>(sample_base), // start of the top-level sample
845 detail::ptrdiff(begin_pos, sample_base), // absoute offset to the member
846 detail::ptrdiff(current_pos, begin_pos)); // size of the member
847 }
848
849public:
863 void discard()
864 {
865 RTI_FLAT_BUILDER_CHECK_VALID(return);
866 RTI_FLAT_BUILDER_CHECK_CAN_FINISH(return);
867
868 parent_builder_->discard_member();
869 invalidate();
870 }
871
882 bool is_nested() const
883 {
884 return parent_builder_ != NULL;
885 }
886
899 bool is_valid() const
900 {
901 return begin_position_ != NULL;
902 }
903
912 rti::xcdr::length_t capacity() const
913 {
914 return stream().total_size();
915 }
916
917protected:
918 // Makes this Builder invalid after finish(); discard(); finish_sample();
919 // and, when exceptions are not enabled (traditional C++ API), after an
920 // error during construction
921 void invalidate()
922 {
923 parent_stream_ = NULL;
924 parent_builder_ = NULL;
925 bind_position_ = NULL;
926 begin_position_ = NULL;
927 }
928
929 // This function is called by a nested Builder when it has finished building
930 // an element
931 virtual void finish_member() // noexcept
932 {
933 if (!is_valid()) {
934 return;
935 }
936
937 bind_position_ = NULL;
938 }
939
940 void discard_member()
941 {
942 RTI_FLAT_BUILDER_CHECK_VALID(return);
943
944 stream().current_position(bind_position_);
945 bind_position_ = NULL;
946 }
947
948 rti::xcdr::Stream& stream()
949 {
950 if (parent_stream_ != NULL) {
951 return *parent_stream_;
952 } else {
953 return owned_stream_;
954 }
955 }
956
957 const rti::xcdr::Stream& stream() const
958 {
959 if (parent_stream_ != NULL) {
960 return *parent_stream_;
961 } else {
962 return owned_stream_;
963 }
964 }
965
966private:
967 rti::xcdr::Stream owned_stream_;
968 rti::xcdr::Stream *parent_stream_;
969 AbstractBuilder *parent_builder_;
970 unsigned char *begin_position_;
971 unsigned char *bind_position_;
972 bool initialize_on_add_;
973
974#ifdef RTI_FLAT_DATA_NO_EXCEPTIONS
975public:
987 {
988 bool failure = failure_;
989 failure_ = false;
990 return failure;
991 }
992protected:
993 void set_failure()
994 {
995 failure_ = true;
996 }
997private:
998 bool failure_;
999#endif
1000
1001
1002};
1003
1004} }
1005
1006#endif // RTI_DDS_FLAT_BUILDER_HPP_
1007
Represents the Offset to an arbitrary user-defined FlatData final IDL struct.
Definition: Offset.hpp:125
Represents the Builder for an arbitrary user-defined mutable type.
Definition: Builder.hpp:206
Offset finish()
Finishes building a member.
MyFlatMutableBuilder(unsigned char *buffer, int32_t size, bool initialize_members=false)
Construct a Builder with an arbitrary buffer.
Definition: Builder.hpp:242
rti::flat::FinalAlignedArrayOffset< MyFlatFinalOffset, 10 > add_my_final_array()
Adds an array member of final complex elements.
rti::flat::StringBuilder build_my_string()
Begins building a string member.
MyFlatMutable * finish_sample()
Finishes building a sample.
rti::flat::MutableArrayBuilder< FlatMutableBarBuilder, 10 > build_my_mutable_array()
Begins building an array member of mutable complex elements.
MyFlatMutableBuilder()
Creates an invalid Builder.
Definition: Builder.hpp:222
rti::flat::MutableSequenceBuilder< FlatMutableBarBuilder > build_my_mutable_seq()
Begins building a sequence member of mutable complex elements.
FlatMutableBarBuilder build_my_mutable()
Begins building a mutable complex member.
rti::flat::MutableSequenceBuilder< rti::flat::StringBuilder > build_my_string_seq()
Begins building a sequence member of string elements.
rti::flat::PrimitiveArrayOffset< int32_t, 10 > add_my_primitive_array()
Adds a primitive array member.
MyFlatFinalOffset add_my_final()
Adds a final complex member.
rti::flat::PrimitiveSequenceBuilder< int32_t > build_my_primitive_seq()
Begins building a primitive-sequence member.
bool add_my_optional_primitive(int32_t value)
Adds a primitive member.
MyFlatMutableOffset Offset
The related offset type.
Definition: Builder.hpp:211
bool add_my_primitive(int32_t value)
Adds a primitive member.
rti::flat::FinalSequenceBuilder< MyFlatFinalOffset > build_my_final_seq()
Begins building a sequence member of final complex elements.
Represents the Offset to an arbitrary user-defined FlatData mutable IDL struct.
Definition: Offset.hpp:203
Represents the Builder for an arbitrary user-defined mutable IDL union.
Definition: Builder.hpp:361
MyFlatMutableBuilder build_my_mutable(int32_t discriminator=1)
Builds a mutable-struct member.
Offset finish()
Finishes building a member.
MyFlatUnion * finish_sample()
Finishes building a sample.
MyFlatUnionBuilder()
Creates an invalid Builder.
Definition: Builder.hpp:378
MyFlatFinal::Offset add_my_final()
Adds a final-struct member.
bool add_my_primitive(int32_t value)
Adds a primitive member.
MyFlatUnionOffset Offset
The related offset type.
Definition: Builder.hpp:366
Represents the Offset to an arbitrary user-defined FlatData mutable IDL union.
Definition: Offset.hpp:376
Base class of all Builders.
Definition: Builder.hpp:512
bool is_valid() const
Whether this Builder is valid.
Definition: Builder.hpp:899
bool is_nested() const
Returns whether this is a member Builder.
Definition: Builder.hpp:882
rti::xcdr::length_t capacity() const
Returns the total capacity in bytes.
Definition: Builder.hpp:912
bool check_failure()
Checks if the previous operation failed and resets the failure flag.
Definition: Builder.hpp:986
void discard()
Discards a member in process of being built.
Definition: Builder.hpp:863
virtual ~AbstractBuilder()
If this is a member Builder, it calls finish().
Definition: Builder.hpp:620
Base class of struct and union builders.
Definition: AggregationBuilders.hpp:37
Offset to an array of final elements.
Definition: SequenceOffsets.hpp:776
Builds a sequence member of fixed-size elements.
Definition: SequenceBuilders.hpp:623
Builds an array member of variable-size elements.
Definition: SequenceBuilders.hpp:305
Builds a sequence member of variable-size elements.
Definition: SequenceBuilders.hpp:535
Offset to an array of primitive elements.
Definition: SequenceOffsets.hpp:241
Builds a sequence of primitive members.
Definition: SequenceBuilders.hpp:692
The generic definition of FlatData topic-types.
Definition: FlatSample.hpp:148
OffsetType Offset
The related Offset type.
Definition: FlatSample.hpp:155
Builds a string.
Definition: SequenceBuilders.hpp:872
Base class of builders for user-defined mutable unions.
Definition: AggregationBuilders.hpp:335
The RTI namespace.
Definition: AggregationBuilders.hpp:17