RTI Connext Traditional C++ API  Version 7.0.0
Builder.hpp
1 /*
2 (c) Copyright, Real-Time Innovations, 2018.
3 All rights reserved.
4 
5 No duplications, whole or partial, manual or electronic, may be made
6 without express written permission. Any such copies, or
7 revisions thereof, must display this notice unaltered.
8 This 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 
206 class 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 
257  Offset finish();
258 
274  MyFlatMutable * finish_sample();
275 
279  bool add_my_primitive(int32_t value);
280 
284  bool add_my_optional_primitive(int32_t value);
285 
291  rti::flat::PrimitiveArrayOffset<int32_t, 10> add_my_primitive_array();
292 
296  rti::flat::PrimitiveSequenceBuilder<int32_t> build_my_primitive_seq();
297 
303  MyFlatFinalOffset add_my_final();
304 
311 
316 
322  FlatMutableBarBuilder build_my_mutable();
323 
328 
333 
337  rti::flat::StringBuilder build_my_string();
338 
343 };
344 
362 public:
367 
368 
379  {
380  }
381 
387  Offset finish();
388 
389 
395  MyFlatUnion * finish_sample();
396 
403  bool add_my_primitive(int32_t value);
404 
414  MyFlatMutableBuilder build_my_mutable(int32_t discriminator = 1);
415 
424  MyFlatFinal::Offset add_my_final();
425 };
426 
427 #endif
428 
429 namespace 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) \
442 public: \
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  } \
457 private: \
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 
469 namespace 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  */
513 protected:
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 
551 protected:
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  }
603 private:
605  AbstractBuilder& operator=(AbstractBuilder& other);
606 #endif
607 
608 protected:
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  */
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 
801 protected:
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 
841 public:
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 
909 protected:
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 
958 private:
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
967 public:
979  {
980  bool failure = failure_;
981  failure_ = false;
982  return failure;
983  }
984 protected:
985  void set_failure()
986  {
987  failure_ = true;
988  }
989 private:
990  bool failure_;
991 #endif
992 
993 
994 };
995 
996 } }
997 
998 #endif // RTI_DDS_FLAT_BUILDER_HPP_
999 
The generic definition of FlatData topic-types.
Definition: FlatSample.hpp:148
Represents the Offset to an arbitrary user-defined FlatData mutable IDL struct.
Definition: Offset.hpp:203
Represents the Offset to an arbitrary user-defined FlatData mutable IDL union.
Definition: Offset.hpp:375
void discard()
Discards a member in process of being built.
Definition: Builder.hpp:855
bool is_valid() const
Whether this Builder is valid.
Definition: Builder.hpp:891
Offset to an array of primitive elements.
Definition: SequenceOffsets.hpp:220
Base class of all Builders.
Definition: Builder.hpp:512
MyFlatMutableBuilder()
Creates an invalid Builder.
Definition: Builder.hpp:222
MyFlatUnionOffset Offset
The related offset type.
Definition: Builder.hpp:366
MyFlatMutableOffset Offset
The related offset type.
Definition: Builder.hpp:211
bool is_nested() const
Returns whether this is a member Builder.
Definition: Builder.hpp:874
OffsetType Offset
The related Offset type.
Definition: FlatSample.hpp:155
Base class of builders for user-defined mutable unions.
Definition: AggregationBuilders.hpp:333
Represents the Builder for an arbitrary user-defined mutable type.
Definition: Builder.hpp:206
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 IDL union.
Definition: Builder.hpp:361
Offset to an array of final elements.
Definition: SequenceOffsets.hpp:728
Base class of struct and union builders.
Definition: AggregationBuilders.hpp:37
rti::xcdr::length_t capacity() const
Returns the total capacity in bytes.
Definition: Builder.hpp:904
Builds a sequence member of variable-size elements.
Definition: BuilderHelper.hpp:20
MyFlatMutableBuilder(unsigned char *buffer, int32_t size, bool initialize_members=false)
Construct a Builder with an arbitrary buffer.
Definition: Builder.hpp:242
Builds an array member of variable-size elements.
Definition: BuilderHelper.hpp:26
Definition: AggregationBuilders.hpp:17
Builds a sequence member of fixed-size elements.
Definition: BuilderHelper.hpp:23
Builds a sequence of primitive members.
Definition: BuilderHelper.hpp:17
MyFlatUnionBuilder()
Creates an invalid Builder.
Definition: Builder.hpp:378
bool check_failure()
Checks if the previous operation failed and resets the failure flag.
Definition: Builder.hpp:978
Builds a string.
Definition: SequenceBuilders.hpp:724
virtual ~AbstractBuilder()
If this is a member Builder, it calls finish().
Definition: Builder.hpp:620