RTI Connext Traditional C++ API Version 7.1.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 move_from(other); \
446 } \
447 TYPE& operator=(PROXY other) throw() \
448 { \
449 finish_untyped_impl(); \
450 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
689 if (!stream().skip(member_size)) {
690 RTI_FLAT_BUILDER_OUT_OF_RESOURCES_ERROR(return OffsetType());
691 }
692
693 if (initialize_on_add_) {
694 OffsetType offset(
695 (SampleBase *) stream().buffer(),
696 detail::ptrdiff(pos, stream().buffer()));
697
698 detail::final_offset_initializer<OffsetType>::initialize(offset);
699
700 return offset;
701 } else {
702 return OffsetType(
703 (SampleBase *) stream().buffer(),
704 detail::ptrdiff(pos, stream().buffer()));
705 }
706 }
707
708 /*i
709 * @brief Creates a nested Builder to build a variable-size member or element
710 *
711 * @param stream_memento Subclasses using build_element() to implement
712 * their own build method are required to provide a stream memento that
713 * contains the position in the stream before any bytes related to this
714 * member were added. Any error before the nested Builder is created will
715 * cause the memento's destructor to roll back the Builder to its state
716 * before this member was added. If the Builder can be created without errors
717 * stream_mement.discard() is called, and its position is kept in case
718 * the nested Builder is discarded (instead of finished), which also rolls
719 * back the parent Builder to its previous state.
720 *
721 * @post This Builder becomes "bound" until the returned Builder is finished.
722 * While bound, this Builder can't be used to add or build more elements.
723 *
724 * @return The Builder that allows building this member or element
725 */
726 template <typename NestedBuilder>
727 NestedBuilder build_element(rti::xcdr::Stream::Memento& stream_memento)
728 {
729 RTI_FLAT_BUILDER_CHECK_VALID(return NestedBuilder());
730 RTI_FLAT_BUILDER_CHECK_NOT_BOUND(return NestedBuilder());
731
732 NestedBuilder nested_builder(nested_tag_t(), *this);
733 RTI_FLAT_BUILDER_CHECK_CREATE_BUILDER(
734 nested_builder,
735 return NestedBuilder());
736
737 bind_position_ = stream_memento.discard();
738
739 // uninit_use_in_call is not possible given how the constructor for
740 // the NestedBuilder type is generated by rtiddsgen. The warning is
741 // suppressed for performance reasons.
742 // coverity[uninit_use_in_call : FALSE]
743 return RTI_FLAT_MOVE_BUILDER(nested_builder);
744 }
745
746 template <typename NestedBuilder>
747 NestedBuilder build_element_no_align(rti::xcdr::Stream::Memento& stream_memento)
748 {
749 RTI_FLAT_BUILDER_CHECK_VALID(return NestedBuilder());
750 RTI_FLAT_BUILDER_CHECK_NOT_BOUND(return NestedBuilder());
751
752 // By passing '0' to the builder constructor we override its default
753 // argument which indicates its required alignment
754 NestedBuilder nested_builder(nested_tag_t(), *this, 0);
755 RTI_FLAT_BUILDER_CHECK_CREATE_BUILDER(
756 nested_builder,
757 return NestedBuilder());
758
759 bind_position_ = stream_memento.discard();
760
761 // uninit_use_in_call is not possible given how the constructor for
762 // the NestedBuilder type is generated by rtiddsgen. The warning is
763 // suppressed for performance reasons.
764 // coverity[uninit_use_in_call : FALSE]
765 return RTI_FLAT_MOVE_BUILDER(nested_builder);
766 }
767
768 /*i
769 * @brief Returns the currently used number of bytes
770 *
771 * The current size is the number of bytes that have been used to create
772 * this sample by adding or building members.
773 *
774 * When current_size() reaches capacity(), the Builder will fail to add
775 * or build any additional member.
776 *
777 * @see capacity().
778 */
779 unsigned int current_size()
780 {
781 return detail::ptrdiff(stream().current_position(), begin_position_);
782 }
783
784
785 friend class AggregationBuilder; // to access finish_member()
786
787 // Finishes this nested builder, updating the parent builder.
788 //
789 // This function doesn't throw exceptions and doesn't return a typed Offset
790 // This function can be used in destructors to "silently" finish the builder
791 void finish_untyped_impl()
792 {
793 if (!is_valid() || !is_nested()) {
794 return;
795 }
796
797 parent_builder_->finish_member();
798 invalidate();
799 }
800
801protected:
802 /*i
803 * @brief Complete the building of a nested member
804 *
805 * Concrete Builders must implement a finish() function with the following body:
806 *
807 * RTI_FLAT_BUILDER_CHECK_CAN_FINISH(...);
808 * // optionally, additonal work
809 * return finish_impl<OffsetType>();
810 *
811 * Destructors can directly call finish_untyped_impl();
812 *
813 * When this is a nested Builder, this function indicates that this element
814 * or member is complete.
815 *
816 * This function is automatically called by the Builder destructor.
817 *
818 * Concrete builders must override this function to return a typed Offset to
819 * the element that was built.
820 *
821 * @post This Builder is in an empty state and cannot be used further
822 *
823 * @return The position in the buffer where this element ended.
824 */
825 template <typename OffsetType>
826 OffsetType finish_impl()
827 {
828 RTI_FLAT_BUILDER_CHECK_VALID(return OffsetType());
829
830 unsigned char *begin_pos = this->begin_position_;
831 unsigned char *sample_base = stream().buffer();
832 unsigned char *current_pos = stream().current_position();
833 finish_untyped_impl();
834
835 return OffsetType(
836 reinterpret_cast<SampleBase *>(sample_base), // start of the top-level sample
837 detail::ptrdiff(begin_pos, sample_base), // absoute offset to the member
838 detail::ptrdiff(current_pos, begin_pos)); // size of the member
839 }
840
841public:
855 void discard()
856 {
857 RTI_FLAT_BUILDER_CHECK_VALID(return);
858 RTI_FLAT_BUILDER_CHECK_CAN_FINISH(return);
859
860 parent_builder_->discard_member();
861 invalidate();
862 }
863
874 bool is_nested() const
875 {
876 return parent_builder_ != NULL;
877 }
878
891 bool is_valid() const
892 {
893 return begin_position_ != NULL;
894 }
895
904 rti::xcdr::length_t capacity() const
905 {
906 return stream().total_size();
907 }
908
909protected:
910 // Makes this Builder invalid after finish(); discard(); finish_sample();
911 // and, when exceptions are not enabled (traditional C++ API), after an
912 // error during construction
913 void invalidate()
914 {
915 parent_stream_ = NULL;
916 parent_builder_ = NULL;
917 bind_position_ = NULL;
918 begin_position_ = NULL;
919 }
920
921 // This function is called by a nested Builder when it has finished building
922 // an element
923 virtual void finish_member() // noexcept
924 {
925 if (!is_valid()) {
926 return;
927 }
928
929 bind_position_ = NULL;
930 }
931
932 void discard_member()
933 {
934 RTI_FLAT_BUILDER_CHECK_VALID(return);
935
936 stream().current_position(bind_position_);
937 bind_position_ = NULL;
938 }
939
940 rti::xcdr::Stream& stream()
941 {
942 if (parent_stream_ != NULL) {
943 return *parent_stream_;
944 } else {
945 return owned_stream_;
946 }
947 }
948
949 const rti::xcdr::Stream& stream() const
950 {
951 if (parent_stream_ != NULL) {
952 return *parent_stream_;
953 } else {
954 return owned_stream_;
955 }
956 }
957
958private:
959 rti::xcdr::Stream owned_stream_;
960 rti::xcdr::Stream *parent_stream_;
961 AbstractBuilder *parent_builder_;
962 unsigned char *begin_position_;
963 unsigned char *bind_position_;
964 bool initialize_on_add_;
965
966#ifdef RTI_FLAT_DATA_NO_EXCEPTIONS
967public:
979 {
980 bool failure = failure_;
981 failure_ = false;
982 return failure;
983 }
984protected:
985 void set_failure()
986 {
987 failure_ = true;
988 }
989private:
990 bool failure_;
991#endif
992
993
994};
995
996} }
997
998#endif // RTI_DDS_FLAT_BUILDER_HPP_
999
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:891
bool is_nested() const
Returns whether this is a member Builder.
Definition: Builder.hpp:874
rti::xcdr::length_t capacity() const
Returns the total capacity in bytes.
Definition: Builder.hpp:904
bool check_failure()
Checks if the previous operation failed and resets the failure flag.
Definition: Builder.hpp:978
void discard()
Discards a member in process of being built.
Definition: Builder.hpp:855
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:728
Builds a sequence member of fixed-size elements.
Definition: SequenceBuilders.hpp:487
Builds an array member of variable-size elements.
Definition: SequenceBuilders.hpp:228
Builds a sequence member of variable-size elements.
Definition: SequenceBuilders.hpp:404
Offset to an array of primitive elements.
Definition: SequenceOffsets.hpp:220
Builds a sequence of primitive members.
Definition: SequenceBuilders.hpp:554
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:724
Base class of builders for user-defined mutable unions.
Definition: AggregationBuilders.hpp:333
The RTI namespace.
Definition: AggregationBuilders.hpp:17