RTI Connext Traditional C++ API Version 7.7.0
SequenceBuilders.hpp
1/*
2(c) Copyright, Real-Time Innovations, 2018-2024.
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_SEQUENCEBUILDERS_HPP_
12#define RTI_DDS_FLAT_SEQUENCEBUILDERS_HPP_
13
14#include "rti/flat/Builder.hpp"
15
16//
17// Builders for sequences, strings, and arrays.
18//
19// Type hierarchy (- indicates an abstract builder; * a concrete, usable builder)
20//
21// - AbstractListBuilder
22// * MutableArrayBuilder
23// - AbstractSequenceBuilder
24// * MutableSequenceBuilder
25// * FinalSequenceBuilder
26// * PrimitiveSequenceBuilder
27// * StringBuilder
28//
29// Notes:
30// - there's no "FinalArrayBuilder" because that's a fixed-size type and
31// doesn't need a builder (it's constructed via an "add" operation, not a "build"
32// operation).
33// - MutableSequenceBuilder "builds" its elements
34// - FinalSequenceBuilder "adds" its elements
35//
36
37namespace rti { namespace flat {
38
39namespace detail {
40
41template <bool IsForEnum>
42struct DHeaderGeneratorImpl {
43 static bool reserve_dheader(rti::xcdr::Stream& stream)
44 {
45 if (collection_dheader_traits<IsForEnum>::dheader_required()) {
46 return stream.serialize_dheader() != NULL;
47 } else {
48 return true;
49 }
50 }
51
52 static bool finish_dheader(
53 rti::xcdr::Stream& stream,
54 unsigned char *dheader_position)
55 {
56 if (collection_dheader_traits<IsForEnum>::dheader_required()) {
57 return stream.finish_dheader((char *) dheader_position);
58 } else {
59 return true;
60 }
61 }
62
63 static bool move_after_dheader(
64 rti::xcdr::Stream& stream,
65 unsigned char *begin_position)
66 {
67 stream.current_position(begin_position);
68
69 if (collection_dheader_traits<IsForEnum>::dheader_required()) {
70 return stream.skip(RTI_XCDR_DHEADER_SIZE);
71 } else {
72 return true;
73 }
74 }
75};
76
77struct NoDHeaderGenerator {
78 static bool reserve_dheader(rti::xcdr::Stream&)
79 {
80 return true;
81 }
82
83 static bool finish_dheader(rti::xcdr::Stream&, unsigned char *)
84 {
85 return true;
86 }
87
88 static bool move_after_dheader(
89 rti::xcdr::Stream& stream,
90 unsigned char *begin_position)
91 {
92 stream.current_position(begin_position);
93 return true;
94 }
95};
96
97typedef DHeaderGeneratorImpl<false> DHeaderGenerator;
98typedef DHeaderGeneratorImpl<true> DHeaderGeneratorForEnum;
99
100// Maybe specialized for enums to select DHeaderGenerator
101template <typename T, typename Enable = void>
102struct primitive_sequence_dheader_gen {
103 typedef NoDHeaderGenerator type;
104};
105
106} // namespace detail
107
108/*i
109 * Extends and specializes AbstractBuilder to add or override the
110 * functionality required to build a collection of consecutive elements
111 * (sequence or array):
112 *
113 * - Add or build elements
114 * - Keep track of the element count
115 * - Handle element alignment
116 *
117 */
122template <typename DHeaderGen>
124protected:
125 AbstractListBuilder() : element_count_(0)
126 { }
127
129 nested_tag_t,
130 AbstractBuilder& parent,
131 unsigned int alignment)
132 : AbstractBuilder(nested_tag_t(), parent, alignment),
133 element_count_(0)
134 {
135 DHeaderGen::reserve_dheader(stream());
136 }
137
138 template <typename ElementBuilder>
139 ElementBuilder build_next()
140 {
141 rti::xcdr::Stream::Memento stream_memento(stream());
142 return build_element<ElementBuilder>(stream_memento);
143 }
144
145 template <typename ElementOffset>
146 ElementOffset add_next()
147 {
148 RTI_FLAT_BUILDER_CHECK_VALID(return ElementOffset());
149
150 // save state in case of error
151 rti::xcdr::Stream::Memento stream_memento(stream());
152
153 if (!stream().align(ElementOffset::required_alignment)) {
154 RTI_FLAT_BUILDER_OUT_OF_RESOURCES_ERROR(return ElementOffset());
155 }
156
157 ElementOffset element = add_element<ElementOffset>();
158 if (element.is_null()) {
159 return ElementOffset();
160 }
161
162 // Success: clear memento, increment element count
163 stream_memento.discard();
164 element_count_++;
165
166 return element;
167 }
168
169 template <typename ElementOffset>
170 void add_n(unsigned int count)
171 {
172 RTI_FLAT_BUILDER_CHECK_VALID(return);
173
174 if (count == 0) {
175 return;
176 }
177
178 if (!stream().align(ElementOffset::required_alignment)) {
179 RTI_FLAT_BUILDER_OUT_OF_RESOURCES_ERROR(return);
180 }
181
182 offset_t elements_size = ElementOffset::serialized_size(0)
183 + ElementOffset::serialized_size_w_padding() * (count - 1);
184 if (!stream().skip(elements_size)) {
185 RTI_FLAT_BUILDER_OUT_OF_RESOURCES_ERROR(return);
186 }
187
188 element_count_ += count;
189 }
190
194 unsigned int element_count() const
195 {
196 return element_count_;
197 }
198
199#if defined(RTI_FLAT_DATA_CXX11_RVALUE_REFERENCES)
200 AbstractListBuilder(AbstractListBuilder&& other) = default;
201 AbstractListBuilder& operator=(AbstractListBuilder&& other)
202 {
203 if (this == &other) {
204 return *this;
205 }
206
207 finish_untyped_impl();
208
209 AbstractBuilder::operator=(static_cast<AbstractBuilder&&>(other));
210
211 element_count_ = other.element_count_;
212 other.element_count_ = 0;
213
214 return *this;
215 }
216 #else
217public:
218 // Enables the safe-move-constructor idiom without C++11 move constructors
219 struct AbstractListBuilderMoveProxy : AbstractBuilderMoveProxy {
220 unsigned int element_count_;
221 };
222
223 operator AbstractListBuilderMoveProxy () throw() // move-constructor idiom
224 {
225 AbstractListBuilderMoveProxy other;
226 move_to(other);
227 return other;
228 }
229
230protected:
231 void move_from(AbstractListBuilderMoveProxy& other)
232 {
233 AbstractBuilder::move_from(other);
234 element_count_ = other.element_count_;
235 }
236
237 void move_to(AbstractListBuilderMoveProxy& other)
238 {
239 AbstractBuilder::move_to(other);
240 other.element_count_ = element_count_;
241 }
242
243#endif
244
245private:
246 friend class AbstractBuilder;
247
248 virtual void finish_member() // override
249 {
250 RTI_FLAT_BUILDER_CHECK_VALID(return);
251
252 // Increment element count after the nested element builder finishes,
253 // instead of on build_next(). This makes it easier to roll back the
254 // state if the element building doesn't complete.
255 element_count_++;
256 AbstractBuilder::finish_member();
257 }
258
259protected:
260 bool finish_dheader()
261 {
262 return DHeaderGen::finish_dheader(stream(), begin_position());
263 }
264
265 unsigned int element_count_;
266};
267
268// --- Array: -----------------------------------------------------------------
269//
270// (Note: there is no FinalArrayBuilder, because a final array's size is fixed,
271// and is handled directly returning its offset with add_*; on the other hand,
272// sequences are never fixed-size.)
273
304template <typename ElementBuilder, unsigned int N>
305class MutableArrayBuilder : public AbstractListBuilder<detail::DHeaderGenerator> {
306public:
312
314 { }
315
316 // The destructor does the same as finish_impl() but doesn't need to return
317 // an Offset
319 {
320 finish_untyped_impl();
321 }
322
323#if defined(RTI_FLAT_DATA_CXX11_RVALUE_REFERENCES)
324 MutableArrayBuilder(MutableArrayBuilder&& other) = default;
325
326 MutableArrayBuilder& operator=(MutableArrayBuilder&& other)
327 {
328 finish_untyped_impl();
329 Base::operator=(static_cast<Base&&>(other));
330
331 return *this;
332 }
333#endif
334
335 void finish_untyped_impl()
336 {
337 if (!Base::is_valid() || !Base::is_nested()) {
338 return;
339 }
340
341 Base::finish_dheader();
342 Base::finish_untyped_impl();
343 }
344
345private:
346 friend class AbstractBuilder; // to allow access to the constructor
347
348 MutableArrayBuilder(
349 nested_tag_t,
350 AbstractBuilder& parent,
351 unsigned int alignment = 0)
352 : AbstractListBuilder(nested_tag_t(), parent, alignment)
353 {
354 }
355
356public:
363 ElementBuilder build_next()
364 {
365 if (element_count() == N) {
366 RTI_FLAT_BUILDER_PRECONDITION_ERROR(
367 "Array builder build_next: too many elements",
368 return ElementBuilder());
369 }
370
371 return AbstractListBuilder::build_next<ElementBuilder>();
372 }
373
382 {
383 RTI_FLAT_BUILDER_CHECK_CAN_FINISH(return Offset());
384
385 if (element_count() != N) {
386 RTI_FLAT_BUILDER_PRECONDITION_ERROR(
387 "Cannot finish array builder: too few elements",
388 return Offset());
389 }
390
391 if (!finish_dheader()) {
392 RTI_FLAT_BUILDER_OUT_OF_RESOURCES_ERROR(return Offset());
393 }
394
395 return finish_impl<Offset>();
396 }
397
398 RTI_FLAT_BUILDER_DEFINE_MOVE_OPERATIONS_IMPL(\
399 MutableArrayBuilder, AbstractListBuilder, AbstractListBuilderMoveProxy)
400
401};
402
403// --- Sequences: -------------------------------------------------------------
404
405// Specializes AbstractListBuilder to handle the length header serialization
406// common to all sequences (which arrays don't have)
414template <typename DHeaderGen>
416public:
419 using Base::is_nested;
420 using Base::is_valid;
421 using Base::stream;
422 using typename Base::nested_tag_t;
423 #if !defined(RTI_FLAT_DATA_CXX11_RVALUE_REFERENCES)
424 using typename Base::AbstractListBuilderMoveProxy;
425 #endif
426
427protected:
428
430 {
431 }
432
434 nested_tag_t,
435 AbstractBuilder& parent,
436 unsigned int alignment)
437 : Base(nested_tag_t(), parent, alignment)
438 {
439 // leave space for sequence length
440 if (!stream().check_size(sizeof(rti::xcdr::length_t))) {
441 RTI_FLAT_BUILDER_OUT_OF_RESOURCES_ERROR(this->invalidate());
442 } else {
443 // No need to align; the base constructor already aligned to 4 the
444 // begin_position
445 stream().template serialize_fast<rti::xcdr::length_t>(0);
446 }
447 }
448
449 // The destructor does the same as finish_impl() but doesn't need to return
450 // an Offset
451 ~AbstractSequenceBuilder()
452 {
453 finish_untyped_impl();
454 }
455
456#if defined(RTI_FLAT_DATA_CXX11_RVALUE_REFERENCES)
457 AbstractSequenceBuilder(AbstractSequenceBuilder&& other) = default;
458 AbstractSequenceBuilder& operator=(AbstractSequenceBuilder&& other)
459 {
460 finish_untyped_impl();
461 Base::operator=(static_cast<Base&&>(other));
462
463 return *this;
464 }
465#endif
466
467 void finish_untyped_impl()
468 {
469 if (!Base::is_valid() || !Base::is_nested()) {
470 return;
471 }
472
473 Base::finish_dheader();
474 finish_length();
475 Base::finish_untyped_impl();
476 }
477
478 // Concrete sequences must call this method in their own finish() function
479 template <typename Offset>
480 Offset finish_impl()
481 {
482 RTI_FLAT_BUILDER_CHECK_VALID(return Offset());
483 RTI_FLAT_BUILDER_CHECK_CAN_FINISH(return Offset());
484
485 Base::finish_dheader();
486 finish_length(); // serialize the length header
487 return Base::template finish_impl<Offset>();
488 }
489
490private:
491 // Serializes the sequence length when finishing the builder.
492 void finish_length()
493 {
494 rti::xcdr::Stream::Memento stream_memento(stream());
495 DHeaderGen::move_after_dheader(stream(), Base::begin_position());
496
497 // Coverity found examples where element_count() is checked, but
498 // that's only done in Array builders, which are unrelated to this
499 // class, AbstractSequenceBuilder.
500 // coverity[CHECKED_RETURN : FALSE]
501 stream().template serialize_fast<rti::xcdr::length_t>(element_count());
502 }
503};
504
533template <typename ElementBuilder>
535 : public AbstractSequenceBuilder<detail::DHeaderGenerator> {
536public:
541
543 {
544 }
545
546private:
548
549 friend class AbstractBuilder; // to allow access to the constructor
550
552 nested_tag_t,
553 AbstractBuilder& parent,
554 unsigned int alignment = RTI_XCDR_DHEADER_ALIGNMENT)
555 : Base(nested_tag_t(), parent, alignment)
556 {
557 }
558
559public:
566 ElementBuilder build_next()
567 {
568 return AbstractListBuilder::build_next<ElementBuilder>();
569 }
570
579 {
580 return finish_impl<Offset>();
581 }
582
583 RTI_FLAT_BUILDER_DEFINE_MOVE_OPERATIONS_IMPL(
585 Base,
586 AbstractListBuilderMoveProxy)
587};
588
621template <typename ElementOffset>
623 : public AbstractSequenceBuilder<detail::DHeaderGenerator> {
624public:
626
628 {
629 }
630
631private:
632 friend class AbstractBuilder; // to allow access to the constructor
633
635 nested_tag_t,
636 AbstractBuilder& parent,
637 unsigned int alignment = RTI_XCDR_SEQ_LENGTH_ALIGNMENT)
638 : AbstractSequenceBuilder(nested_tag_t(), parent, alignment)
639 {
640 }
641
642public:
648 ElementOffset add_next()
649 {
650 return AbstractListBuilder::add_next<ElementOffset>();
651 }
652
661 FinalSequenceBuilder& add_n(unsigned int count)
662 {
663 AbstractListBuilder::add_n<ElementOffset>(count);
664 return *this;
665 }
666
674 {
675 return finish_impl<Offset>();
676 }
677
678 RTI_FLAT_BUILDER_DEFINE_MOVE_OPERATIONS_IMPL(\
679 FinalSequenceBuilder, AbstractSequenceBuilder, AbstractListBuilderMoveProxy)
680};
681
689template <typename T>
692 typename detail::primitive_sequence_dheader_gen<T>::type> {
693public:
696 typename detail::primitive_sequence_dheader_gen<T>::type>
697 Base;
698 using Base::is_valid;
699 using Base::stream;
700 using typename Base::nested_tag_t;
701#if !defined(RTI_FLAT_DATA_CXX11_RVALUE_REFERENCES)
702 using typename Base::AbstractListBuilderMoveProxy;
703#endif
704
706 {
707 }
708
709protected:
710 friend class AbstractBuilder; // to allow access to the constructor
711
713 nested_tag_t,
714 AbstractBuilder& parent,
715 unsigned int alignment = RTI_XCDR_SEQ_LENGTH_ALIGNMENT)
716 : Base(nested_tag_t(), parent, alignment)
717 {
718 }
719
720public:
727 {
728 RTI_FLAT_BUILDER_CHECK_VALID(return *this);
729
730 if (!stream().template serialize<T>(value)) {
731 RTI_FLAT_BUILDER_OUT_OF_RESOURCES_ERROR(return *this);
732 }
733
734 Base::element_count_++;
735 return *this;
736 }
737
746 PrimitiveSequenceBuilder& add_n(const T *array, unsigned int count)
747 {
748 RTI_FLAT_BUILDER_CHECK_VALID(return *this);
749 RTI_FLAT_ASSERT(array != NULL, return *this);
750
751 if (RTIXCdrUnsignedLong_MAX / static_cast<unsigned int>(sizeof(T))
752 < count) {
753 RTI_FLAT_BUILDER_OUT_OF_RESOURCES_ERROR(return *this);
754 }
755
756 if (!stream().check_size(static_cast<unsigned int>(sizeof(T)) * count)) {
757 RTI_FLAT_BUILDER_OUT_OF_RESOURCES_ERROR(return *this);
758 }
759
760 if (stream().needs_byte_swap() && sizeof(T) > 1) {
761 for (unsigned int i = 0; i < count; i++) {
762 stream().template serialize_fast<T>(array[i]);
763 }
764 } else {
765 stream().serialize_fast((void *) array, count * static_cast<unsigned int>(sizeof(T)));
766 }
767
768 Base::element_count_ += count;
769 return *this;
770 }
771
785 PrimitiveSequenceBuilder& add_n(unsigned int count, T value)
786 {
787 RTI_FLAT_BUILDER_CHECK_VALID(return *this);
788
789 if (RTIXCdrUnsignedLong_MAX / static_cast<unsigned int>(sizeof(T))
790 < count) {
791 RTI_FLAT_BUILDER_OUT_OF_RESOURCES_ERROR(return *this);
792 }
793
794 if (!stream().check_size(static_cast<unsigned int>(sizeof(T)) * count)) {
795 RTI_FLAT_BUILDER_OUT_OF_RESOURCES_ERROR(return *this);
796 }
797
798 for (unsigned int i = 0; i < count; i++) {
799 stream().template serialize_fast<T>(value);
800 }
801 Base::element_count_ += count;
802 return *this;
803 }
804
825 PrimitiveSequenceBuilder& add_n(unsigned int count)
826 {
827 RTI_FLAT_BUILDER_CHECK_VALID(return *this);
828
829 if (RTIXCdrUnsignedLong_MAX / static_cast<unsigned int>(sizeof(T))
830 < count) {
831 RTI_FLAT_BUILDER_OUT_OF_RESOURCES_ERROR(return *this);
832 }
833
834 if (!stream().skip(static_cast<unsigned int>(sizeof(T)) * count)) {
835 RTI_FLAT_BUILDER_OUT_OF_RESOURCES_ERROR(return *this);
836 }
837
838 Base::element_count_ += count;
839 return *this;
840 }
841
842
850 {
851 this->finish_dheader();
852 return Base::template finish_impl<Offset>();
853 }
854
855private:
856 RTI_FLAT_BUILDER_DEFINE_MOVE_OPERATIONS_IMPL(\
857 PrimitiveSequenceBuilder, Base, AbstractListBuilderMoveProxy)
858};
859
876public:
877 typedef StringOffset Offset;
879 using Base::is_valid;
880 using Base::stream;
881 using typename Base::nested_tag_t;
882
884 {
885 }
886
887private:
888 friend class AbstractBuilder; // to allow access to the constructor
889
891 nested_tag_t,
892 AbstractBuilder& parent,
893 unsigned int alignment = RTI_XCDR_SEQ_LENGTH_ALIGNMENT)
894 : Base(nested_tag_t(), parent, alignment)
895 {
896 }
897
898public:
906 StringBuilder& set_string(const char *value)
907 {
908 RTI_FLAT_BUILDER_CHECK_VALID(return *this);
909 RTI_FLAT_ASSERT(value != NULL, return *this);
910
911 // if set_string is called more than once we override the string
912 // that was set before
913 if (Base::element_count_ != 0) {
914 stream().current_position(begin_position());
915 stream().serialize_fast<rti::xcdr::length_t>(0);
916 Base::element_count_ = 0;
917 }
918
919 unsigned int length =
920 static_cast<unsigned int>(RTIXCdrString_getLength(value)) + 1;
921 add_n(value, length); // if this fail, error has been reported
922 return *this;
923 }
924
932 {
933 RTI_FLAT_BUILDER_CHECK_VALID(return Offset());
934
935 if (element_count_ == 0) {
936 add_next('\0'); // build empty string if no string was built
937 }
938
939 Base::finish_dheader();
940 return finish_impl<Offset>();
941 }
942
943 RTI_FLAT_BUILDER_DEFINE_MOVE_OPERATIONS_IMPL(\
944 StringBuilder, Base, AbstractListBuilderMoveProxy)
945};
946
947// Wide strings are treated as a sequence of octets
948typedef PrimitiveSequenceBuilder<unsigned char> WStringBuilder;
949
950} }
951
952#endif // RTI_DDS_FLAT_SEQUENCEBUILDERS_HPP_
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
Base class of all array and sequence builders.
Definition: SequenceBuilders.hpp:123
unsigned int element_count() const
Returns the current number of elements that have been added.
Definition: SequenceBuilders.hpp:194
Base class of Builders for sequence members.
Definition: SequenceBuilders.hpp:415
unsigned int element_count() const
Returns the current number of elements that have been added.
Definition: SequenceBuilders.hpp:194
Builds a sequence member of fixed-size elements.
Definition: SequenceBuilders.hpp:623
Offset finish()
Finishes building the sequence.
Definition: SequenceBuilders.hpp:673
FinalSequenceBuilder & add_n(unsigned int count)
Adds a number of elements at once.
Definition: SequenceBuilders.hpp:661
ElementOffset add_next()
Adds the next element.
Definition: SequenceBuilders.hpp:648
Builds an array member of variable-size elements.
Definition: SequenceBuilders.hpp:305
ElementBuilder build_next()
Begins building the next element.
Definition: SequenceBuilders.hpp:363
Offset finish()
Finishes building the array.
Definition: SequenceBuilders.hpp:381
MutableArrayOffset< typename ElementBuilder::Offset, N > Offset
The related Offset type.
Definition: SequenceBuilders.hpp:310
Offset to an array of variable-size elements.
Definition: SequenceOffsets.hpp:621
Builds a sequence member of variable-size elements.
Definition: SequenceBuilders.hpp:535
SequenceOffset< typename ElementBuilder::Offset > Offset
The related Offset type.
Definition: SequenceBuilders.hpp:540
ElementBuilder build_next()
Begins building the next element.
Definition: SequenceBuilders.hpp:566
Offset finish()
Finishes building the sequence.
Definition: SequenceBuilders.hpp:578
Builds a sequence of primitive members.
Definition: SequenceBuilders.hpp:692
PrimitiveSequenceBuilder & add_n(unsigned int count, T value)
Adds a number of elements with the same value.
Definition: SequenceBuilders.hpp:785
PrimitiveSequenceBuilder & add_n(const T *array, unsigned int count)
Adds all the elements in an array.
Definition: SequenceBuilders.hpp:746
PrimitiveSequenceBuilder & add_n(unsigned int count)
Adds a number of uninitialized elements.
Definition: SequenceBuilders.hpp:825
PrimitiveSequenceBuilder & add_next(T value)
Adds the next element.
Definition: SequenceBuilders.hpp:726
Offset finish()
Finishes building the sequence.
Definition: SequenceBuilders.hpp:849
Offset to a sequence of primitive elements.
Definition: SequenceOffsets.hpp:146
Offset to a sequence of non-primitive elements.
Definition: SequenceOffsets.hpp:501
Builds a string.
Definition: SequenceBuilders.hpp:875
Offset finish()
Finishes building the string.
Definition: SequenceBuilders.hpp:931
StringBuilder & set_string(const char *value)
Sets the string value.
Definition: SequenceBuilders.hpp:906
Offset to a string.
Definition: SequenceOffsets.hpp:291
The RTI namespace.
Definition: AggregationBuilders.hpp:18