RTI Connext Traditional C++ API Version 7.3.0
SequenceBuilders.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_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
744 PrimitiveSequenceBuilder& add_n(const T *array, unsigned int count)
745 {
746 RTI_FLAT_BUILDER_CHECK_VALID(return *this);
747
748 if (RTIXCdrUnsignedLong_MAX / static_cast<unsigned int>(sizeof(T))
749 < count) {
750 RTI_FLAT_BUILDER_OUT_OF_RESOURCES_ERROR(return *this);
751 }
752
753 if (!stream().check_size(static_cast<unsigned int>(sizeof(T)) * count)) {
754 RTI_FLAT_BUILDER_OUT_OF_RESOURCES_ERROR(return *this);
755 }
756
757 if (stream().needs_byte_swap() && sizeof(T) > 1) {
758 for (unsigned int i = 0; i < count; i++) {
759 stream().template serialize_fast<T>(array[i]);
760 }
761 } else {
762 stream().serialize_fast((void *) array, count * static_cast<unsigned int>(sizeof(T)));
763 }
764
765 Base::element_count_ += count;
766 return *this;
767 }
768
782 PrimitiveSequenceBuilder& add_n(unsigned int count, T value)
783 {
784 RTI_FLAT_BUILDER_CHECK_VALID(return *this);
785
786 if (RTIXCdrUnsignedLong_MAX / static_cast<unsigned int>(sizeof(T))
787 < count) {
788 RTI_FLAT_BUILDER_OUT_OF_RESOURCES_ERROR(return *this);
789 }
790
791 if (!stream().check_size(static_cast<unsigned int>(sizeof(T)) * count)) {
792 RTI_FLAT_BUILDER_OUT_OF_RESOURCES_ERROR(return *this);
793 }
794
795 for (unsigned int i = 0; i < count; i++) {
796 stream().template serialize_fast<T>(value);
797 }
798 Base::element_count_ += count;
799 return *this;
800 }
801
822 PrimitiveSequenceBuilder& add_n(unsigned int count)
823 {
824 RTI_FLAT_BUILDER_CHECK_VALID(return *this);
825
826 if (RTIXCdrUnsignedLong_MAX / static_cast<unsigned int>(sizeof(T))
827 < count) {
828 RTI_FLAT_BUILDER_OUT_OF_RESOURCES_ERROR(return *this);
829 }
830
831 if (!stream().skip(static_cast<unsigned int>(sizeof(T)) * count)) {
832 RTI_FLAT_BUILDER_OUT_OF_RESOURCES_ERROR(return *this);
833 }
834
835 Base::element_count_ += count;
836 return *this;
837 }
838
839
847 {
848 this->finish_dheader();
849 return Base::template finish_impl<Offset>();
850 }
851
852private:
853 RTI_FLAT_BUILDER_DEFINE_MOVE_OPERATIONS_IMPL(\
854 PrimitiveSequenceBuilder, Base, AbstractListBuilderMoveProxy)
855};
856
873public:
874 typedef StringOffset Offset;
876 using Base::is_valid;
877 using Base::stream;
878 using typename Base::nested_tag_t;
879
881 {
882 }
883
884private:
885 friend class AbstractBuilder; // to allow access to the constructor
886
888 nested_tag_t,
889 AbstractBuilder& parent,
890 unsigned int alignment = RTI_XCDR_SEQ_LENGTH_ALIGNMENT)
891 : Base(nested_tag_t(), parent, alignment)
892 {
893 }
894
895public:
899 StringBuilder& set_string(const char *value)
900 {
901 RTI_FLAT_BUILDER_CHECK_VALID(return *this);
902
903 // if set_string is called more than once we override the string
904 // that was set before
905 if (Base::element_count_ != 0) {
906 stream().current_position(begin_position());
907 stream().serialize_fast<rti::xcdr::length_t>(0);
908 Base::element_count_ = 0;
909 }
910
911 unsigned int length = static_cast<unsigned int>(strlen(value)) + 1;
912 add_n(value, length); // if this fail, error has been reported
913 return *this;
914 }
915
923 {
924 RTI_FLAT_BUILDER_CHECK_VALID(return Offset());
925
926 if (element_count_ == 0) {
927 add_next('\0'); // build empty string if no string was built
928 }
929
930 Base::finish_dheader();
931 return finish_impl<Offset>();
932 }
933
934 RTI_FLAT_BUILDER_DEFINE_MOVE_OPERATIONS_IMPL(\
935 StringBuilder, Base, AbstractListBuilderMoveProxy)
936};
937
938// Wide strings are treated as a sequence of octets
939typedef PrimitiveSequenceBuilder<unsigned char> WStringBuilder;
940
941} }
942
943#endif // RTI_DDS_FLAT_SEQUENCEBUILDERS_HPP_
944
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:782
PrimitiveSequenceBuilder & add_n(const T *array, unsigned int count)
Adds all the elements in an array.
Definition: SequenceBuilders.hpp:744
PrimitiveSequenceBuilder & add_n(unsigned int count)
Adds a number of uninitialized elements.
Definition: SequenceBuilders.hpp:822
PrimitiveSequenceBuilder & add_next(T value)
Adds the next element.
Definition: SequenceBuilders.hpp:726
Offset finish()
Finishes building the sequence.
Definition: SequenceBuilders.hpp:846
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:872
Offset finish()
Finishes building the string.
Definition: SequenceBuilders.hpp:922
StringBuilder & set_string(const char *value)
Sets the string value.
Definition: SequenceBuilders.hpp:899
Offset to a string.
Definition: SequenceOffsets.hpp:291
The RTI namespace.
Definition: AggregationBuilders.hpp:17