RTI Connext Traditional C++ API  Version 6.1.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  return RTI_FLAT_MOVE_BUILDER(nested_builder);
739  }
740 
741  template <typename NestedBuilder>
742  NestedBuilder build_element_no_align(rti::xcdr::Stream::Memento& stream_memento)
743  {
744  RTI_FLAT_BUILDER_CHECK_VALID(return NestedBuilder());
745  RTI_FLAT_BUILDER_CHECK_NOT_BOUND(return NestedBuilder());
746 
747  // By passing '0' to the builder constructor we override its default
748  // argument which indicates its required alignment
749  NestedBuilder nested_builder(nested_tag_t(), *this, 0);
750  RTI_FLAT_BUILDER_CHECK_CREATE_BUILDER(
751  nested_builder,
752  return NestedBuilder());
753 
754  bind_position_ = stream_memento.discard();
755  return RTI_FLAT_MOVE_BUILDER(nested_builder);
756  }
757 
758  /*i
759  * @brief Returns the currently used number of bytes
760  *
761  * The current size is the number of bytes that have been used to create
762  * this sample by adding or building members.
763  *
764  * When current_size() reaches capacity(), the Builder will fail to add
765  * or build any additional member.
766  *
767  * @see capacity().
768  */
769  unsigned int current_size()
770  {
771  return detail::ptrdiff(stream().current_position(), begin_position_);
772  }
773 
774 
775  friend class AggregationBuilder; // to access finish_member()
776 
777  // Finishes this nested builder, updating the parent builder.
778  //
779  // This function doesn't throw exceptions and doesn't return a typed Offset
780  // This function can be used in destructors to "silently" finish the builder
781  void finish_untyped_impl()
782  {
783  if (!is_valid() || !is_nested()) {
784  return;
785  }
786 
787  parent_builder_->finish_member();
788  invalidate();
789  }
790 
791 protected:
792  /*i
793  * @brief Complete the building of a nested member
794  *
795  * Concrete Builders must implement a finish() function with the following body:
796  *
797  * RTI_FLAT_BUILDER_CHECK_CAN_FINISH(...);
798  * // optionally, additonal work
799  * return finish_impl<OffsetType>();
800  *
801  * Destructors can directly call finish_untyped_impl();
802  *
803  * When this is a nested Builder, this function indicates that this element
804  * or member is complete.
805  *
806  * This function is automatically called by the Builder destructor.
807  *
808  * Concrete builders must override this function to return a typed Offset to
809  * the element that was built.
810  *
811  * @post This Builder is in an empty state and cannot be used further
812  *
813  * @return The position in the buffer where this element ended.
814  */
815  template <typename OffsetType>
816  OffsetType finish_impl()
817  {
818  RTI_FLAT_BUILDER_CHECK_VALID(return OffsetType());
819 
820  unsigned char *begin_pos = this->begin_position_;
821  unsigned char *sample_base = stream().buffer();
822  unsigned char *current_pos = stream().current_position();
823  finish_untyped_impl();
824 
825  return OffsetType(
826  reinterpret_cast<SampleBase *>(sample_base), // start of the top-level sample
827  detail::ptrdiff(begin_pos, sample_base), // absoute offset to the member
828  detail::ptrdiff(current_pos, begin_pos)); // size of the member
829  }
830 
831 public:
845  void discard()
846  {
847  RTI_FLAT_BUILDER_CHECK_VALID(return);
848  RTI_FLAT_BUILDER_CHECK_CAN_FINISH(return);
849 
850  parent_builder_->discard_member();
851  invalidate();
852  }
853 
864  bool is_nested() const
865  {
866  return parent_builder_ != NULL;
867  }
868 
881  bool is_valid() const
882  {
883  return begin_position_ != NULL;
884  }
885 
894  rti::xcdr::length_t capacity() const
895  {
896  return stream().total_size();
897  }
898 
899 protected:
900  // Makes this Builder invalid after finish(); discard(); finish_sample();
901  // and, when exceptions are not enabled (traditional C++ API), after an
902  // error during construction
903  void invalidate()
904  {
905  parent_stream_ = NULL;
906  parent_builder_ = NULL;
907  bind_position_ = NULL;
908  begin_position_ = NULL;
909  }
910 
911  // This function is called by a nested Builder when it has finished building
912  // an element
913  virtual void finish_member() // noexcept
914  {
915  if (!is_valid()) {
916  return;
917  }
918 
919  bind_position_ = NULL;
920  }
921 
922  void discard_member()
923  {
924  RTI_FLAT_BUILDER_CHECK_VALID(return);
925 
926  stream().current_position(bind_position_);
927  bind_position_ = NULL;
928  }
929 
930  rti::xcdr::Stream& stream()
931  {
932  if (parent_stream_ != NULL) {
933  return *parent_stream_;
934  } else {
935  return owned_stream_;
936  }
937  }
938 
939  const rti::xcdr::Stream& stream() const
940  {
941  if (parent_stream_ != NULL) {
942  return *parent_stream_;
943  } else {
944  return owned_stream_;
945  }
946  }
947 
948 private:
949  rti::xcdr::Stream owned_stream_;
950  rti::xcdr::Stream *parent_stream_;
951  AbstractBuilder *parent_builder_;
952  unsigned char *begin_position_;
953  unsigned char *bind_position_;
954  bool initialize_on_add_;
955 
956 #ifdef RTI_FLAT_DATA_NO_EXCEPTIONS
957 public:
969  {
970  bool failure = failure_;
971  failure_ = false;
972  return failure;
973  }
974 protected:
975  void set_failure()
976  {
977  failure_ = true;
978  }
979 private:
980  bool failure_;
981 #endif
982 
983 
984 };
985 
986 } }
987 
988 #endif // RTI_DDS_FLAT_BUILDER_HPP_
989 
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:845
bool is_valid() const
Whether this Builder is valid.
Definition: Builder.hpp:881
Offset to an array of primitive elements.
Definition: SequenceOffsets.hpp:208
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:864
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:715
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:894
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:968
Builds a string.
Definition: SequenceBuilders.hpp:709
virtual ~AbstractBuilder()
If this is a member Builder, it calls finish().
Definition: Builder.hpp:620