RTI Connext Traditional C++ API Version 7.2.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
39/*i
40 * Extends and specializes AbstractBuilder to add or override the functionality
41 * required to build a collection of consecutive elements (sequence or array):
42 *
43 * - Add or build elements
44 * - Keep track of the element count
45 * - Handle element alignment
46 *
47 */
53protected:
54 AbstractListBuilder() : element_count_(0)
55 {
56 }
57
59 nested_tag_t,
60 AbstractBuilder& parent,
61 unsigned int alignment)
62 : AbstractBuilder(nested_tag_t(), parent, alignment), element_count_(0)
63 {
64 }
65
66 template <typename ElementBuilder>
67 ElementBuilder build_next()
68 {
69 rti::xcdr::Stream::Memento stream_memento(stream());
70 return build_element<ElementBuilder>(stream_memento);
71 }
72
73 template <typename ElementOffset>
74 ElementOffset add_next()
75 {
76 RTI_FLAT_BUILDER_CHECK_VALID(return ElementOffset());
77
78 // save state in case of error
79 rti::xcdr::Stream::Memento stream_memento(stream());
80
81 if (!stream().align(ElementOffset::required_alignment)) {
82 RTI_FLAT_BUILDER_OUT_OF_RESOURCES_ERROR(return ElementOffset());
83 }
84
85 ElementOffset element = add_element<ElementOffset>();
86 if (element.is_null()) {
87 return ElementOffset();
88 }
89
90 // Success: clear memento, increment element count
91 stream_memento.discard();
92 element_count_++;
93
94 return element;
95 }
96
97 template <typename ElementOffset>
98 void add_n(unsigned int count)
99 {
100 RTI_FLAT_BUILDER_CHECK_VALID(return);
101
102 if (count == 0) {
103 return;
104 }
105
106 if (!stream().align(ElementOffset::required_alignment)) {
107 RTI_FLAT_BUILDER_OUT_OF_RESOURCES_ERROR(return);
108 }
109
110 offset_t elements_size = ElementOffset::serialized_size(0)
111 + ElementOffset::serialized_size_w_padding() * (count - 1);
112 if (!stream().skip(elements_size)) {
113 RTI_FLAT_BUILDER_OUT_OF_RESOURCES_ERROR(return);
114 }
115
116 element_count_ += count;
117 }
118
122 unsigned int element_count() const
123 {
124 return element_count_;
125 }
126
127#if defined(RTI_FLAT_DATA_CXX11_RVALUE_REFERENCES)
128 AbstractListBuilder(AbstractListBuilder&& other) = default;
129 AbstractListBuilder& operator=(AbstractListBuilder&& other)
130 {
131 if (this == &other) {
132 return *this;
133 }
134
135 finish_untyped_impl();
136
137 AbstractBuilder::operator=(static_cast<AbstractBuilder&&>(other));
138
139 element_count_ = other.element_count_;
140 other.element_count_ = 0;
141
142 return *this;
143 }
144#else
145public:
146 // Enables the safe-move-constructor idiom without C++11 move constructors
147 struct AbstractListBuilderMoveProxy : AbstractBuilderMoveProxy {
148 unsigned int element_count_;
149 };
150
151 operator AbstractListBuilderMoveProxy () throw() // move-constructor idiom
152 {
153 AbstractListBuilderMoveProxy other;
154 move_to(other);
155 return other;
156 }
157
158protected:
159 void move_from(AbstractListBuilderMoveProxy& other)
160 {
161 AbstractBuilder::move_from(other);
162 element_count_ = other.element_count_;
163 }
164
165 void move_to(AbstractListBuilderMoveProxy& other)
166 {
167 AbstractBuilder::move_to(other);
168 other.element_count_ = element_count_;
169 }
170
171#endif
172
173private:
174 friend class AbstractBuilder;
175
176 virtual void finish_member() // override
177 {
178 RTI_FLAT_BUILDER_CHECK_VALID(return);
179
180 // Increment element count after the nested element builder finishes,
181 // instead of on build_next(). This makes it easier to roll back the
182 // state if the element building doesn't complete.
183 element_count_++;
184 AbstractBuilder::finish_member();
185 }
186
187protected:
188 unsigned int element_count_;
189};
190
191// --- Array: -----------------------------------------------------------------
192//
193// (Note: there is no FinalArrayBuilder, because a final array's size is fixed,
194// and is handled directly returning its offset with add_*; on the other hand,
195// sequences are never fixed-size.)
196
227template <typename ElementBuilder, unsigned int N>
229public:
234
236 {
237 }
238
239private:
240 friend class AbstractBuilder; // to allow access to the constructor
241
243 nested_tag_t,
244 AbstractBuilder& parent,
245 unsigned int alignment = 0)
246 : AbstractListBuilder(nested_tag_t(), parent, alignment)
247 {
248 }
249
250public:
257 ElementBuilder build_next()
258 {
259 if (element_count() == N) {
260 RTI_FLAT_BUILDER_PRECONDITION_ERROR(
261 "Array builder build_next: too many elements",
262 return ElementBuilder());
263 }
264
265 return AbstractListBuilder::build_next<ElementBuilder>();
266 }
267
276 {
277 RTI_FLAT_BUILDER_CHECK_CAN_FINISH(return Offset());
278
279 if (element_count() != N) {
280 RTI_FLAT_BUILDER_PRECONDITION_ERROR(
281 "Cannot finish array builder: too few elements",
282 return Offset());
283 }
284
285 return finish_impl<Offset>();
286 }
287
288 RTI_FLAT_BUILDER_DEFINE_MOVE_OPERATIONS_IMPL(\
289 MutableArrayBuilder, AbstractListBuilder, AbstractListBuilderMoveProxy)
290
291};
292
293// --- Sequences: -------------------------------------------------------------
294
295// Specializes AbstractListBuilder to handle the length header serialization
296// common to all sequences (which arrays don't have)
305protected:
307 {
308 }
309
311 nested_tag_t,
312 AbstractBuilder& parent,
313 unsigned int alignment)
314 : AbstractListBuilder(nested_tag_t(), parent, alignment)
315 {
316 // leave space for sequence length
317 if (!stream().check_size(sizeof(rti::xcdr::length_t))) {
318 RTI_FLAT_BUILDER_OUT_OF_RESOURCES_ERROR(invalidate());
319 } else {
320 // No need to align; the base constructor already aligned to 4 the
321 // begin_position
322 stream().serialize_fast<rti::xcdr::length_t>(0);
323 }
324 }
325
326 // The destructor does the same as finish_impl() but doesn't need to return
327 // an Offset
329 {
330 finish_untyped_impl();
331 }
332
333#if defined(RTI_FLAT_DATA_CXX11_RVALUE_REFERENCES)
336 {
337 finish_untyped_impl();
338 AbstractListBuilder::operator=(static_cast<AbstractListBuilder&&>(other));
339
340 return *this;
341 }
342#endif
343
344 void finish_untyped_impl()
345 {
346 if (!is_valid() || !is_nested()) {
347 return;
348 }
349
350 finish_length();
351 AbstractListBuilder::finish_untyped_impl();
352 }
353
354 // Concrete sequences must call this method in their own finish() function
355 template <typename Offset>
356 Offset finish_impl()
357 {
358 RTI_FLAT_BUILDER_CHECK_VALID(return Offset());
359 RTI_FLAT_BUILDER_CHECK_CAN_FINISH(return Offset());
360
361 finish_length(); // serialize the length header
362 return AbstractListBuilder::finish_impl<Offset>();
363 }
364
365private:
366 // Serializes the sequence length when finishing the builder.
367 void finish_length()
368 {
369 rti::xcdr::Stream::Memento stream_memento(stream());
370 stream().current_position(begin_position());
371 stream().serialize_fast<rti::xcdr::length_t>(element_count());
372 }
373};
374
403template <typename ElementBuilder>
405public:
410
412 {
413 }
414
415private:
416 friend class AbstractBuilder; // to allow access to the constructor
417
419 nested_tag_t,
420 AbstractBuilder& parent,
421 unsigned int alignment = RTI_XCDR_DHEADER_ALIGNMENT)
422 : AbstractSequenceBuilder(nested_tag_t(), parent, alignment)
423 {
424 }
425
426public:
433 ElementBuilder build_next()
434 {
435 return AbstractListBuilder::build_next<ElementBuilder>();
436 }
437
446 {
447 return finish_impl<Offset>();
448 }
449
450 RTI_FLAT_BUILDER_DEFINE_MOVE_OPERATIONS_IMPL(\
451 MutableSequenceBuilder, AbstractSequenceBuilder, AbstractListBuilderMoveProxy)
452};
453
486template <typename ElementOffset>
488public:
490
492 {
493 }
494
495private:
496 friend class AbstractBuilder; // to allow access to the constructor
497
499 nested_tag_t,
500 AbstractBuilder& parent,
501 unsigned int alignment = RTI_XCDR_SEQ_LENGTH_ALIGNMENT)
502 : AbstractSequenceBuilder(nested_tag_t(), parent, alignment)
503 {
504 }
505
506public:
512 ElementOffset add_next()
513 {
514 return AbstractListBuilder::add_next<ElementOffset>();
515 }
516
525 FinalSequenceBuilder& add_n(unsigned int count)
526 {
527 AbstractListBuilder::add_n<ElementOffset>(count);
528 return *this;
529 }
530
538 {
539 return finish_impl<Offset>();
540 }
541
542 RTI_FLAT_BUILDER_DEFINE_MOVE_OPERATIONS_IMPL(\
543 FinalSequenceBuilder, AbstractSequenceBuilder, AbstractListBuilderMoveProxy)
544};
545
553template <typename T>
555public:
557
559 {
560 }
561
562protected:
563 friend class AbstractBuilder; // to allow access to the constructor
564
566 nested_tag_t,
567 AbstractBuilder& parent,
568 unsigned int alignment = RTI_XCDR_SEQ_LENGTH_ALIGNMENT)
569 : AbstractSequenceBuilder(nested_tag_t(), parent, alignment)
570 {
571 }
572
573public:
580 {
581 RTI_FLAT_BUILDER_CHECK_VALID(return *this);
582
583 if (!stream().template serialize<T>(value)) {
584 RTI_FLAT_BUILDER_OUT_OF_RESOURCES_ERROR(return *this);
585 }
586
587 element_count_++;
588 return *this;
589 }
590
597 PrimitiveSequenceBuilder& add_n(const T *array, unsigned int count)
598 {
599 RTI_FLAT_BUILDER_CHECK_VALID(return *this);
600
601 if (RTIXCdrUnsignedLong_MAX / static_cast<unsigned int>(sizeof(T))
602 < count) {
603 RTI_FLAT_BUILDER_OUT_OF_RESOURCES_ERROR(return *this);
604 }
605
606 if (!stream().check_size(static_cast<unsigned int>(sizeof(T)) * count)) {
607 RTI_FLAT_BUILDER_OUT_OF_RESOURCES_ERROR(return *this);
608 }
609
610 if (stream().needs_byte_swap() && sizeof(T) > 1) {
611 for (unsigned int i = 0; i < count; i++) {
612 stream().template serialize_fast<T>(array[i]);
613 }
614 } else {
615 stream().serialize_fast((void *) array, count * static_cast<unsigned int>(sizeof(T)));
616 }
617
618 element_count_ += count;
619 return *this;
620 }
621
635 PrimitiveSequenceBuilder& add_n(unsigned int count, T value)
636 {
637 RTI_FLAT_BUILDER_CHECK_VALID(return *this);
638
639 if (RTIXCdrUnsignedLong_MAX / static_cast<unsigned int>(sizeof(T))
640 < count) {
641 RTI_FLAT_BUILDER_OUT_OF_RESOURCES_ERROR(return *this);
642 }
643
644 if (!stream().check_size(static_cast<unsigned int>(sizeof(T)) * count)) {
645 RTI_FLAT_BUILDER_OUT_OF_RESOURCES_ERROR(return *this);
646 }
647
648 for (unsigned int i = 0; i < count; i++) {
649 stream().template serialize_fast<T>(value);
650 }
651 element_count_ += count;
652 return *this;
653 }
654
675 PrimitiveSequenceBuilder& add_n(unsigned int count)
676 {
677 RTI_FLAT_BUILDER_CHECK_VALID(return *this);
678
679 if (RTIXCdrUnsignedLong_MAX / static_cast<unsigned int>(sizeof(T))
680 < count) {
681 RTI_FLAT_BUILDER_OUT_OF_RESOURCES_ERROR(return *this);
682 }
683
684 if (!stream().skip(static_cast<unsigned int>(sizeof(T)) * count)) {
685 RTI_FLAT_BUILDER_OUT_OF_RESOURCES_ERROR(return *this);
686 }
687
688 element_count_ += count;
689 return *this;
690 }
691
692
700 {
701 return finish_impl<Offset>();
702 }
703
704private:
705 RTI_FLAT_BUILDER_DEFINE_MOVE_OPERATIONS_IMPL(\
706 PrimitiveSequenceBuilder, AbstractSequenceBuilder, AbstractListBuilderMoveProxy)
707};
708
725public:
726 typedef StringOffset Offset;
727
729 {
730 }
731
732private:
733 friend class AbstractBuilder; // to allow access to the constructor
734
736 nested_tag_t,
737 AbstractBuilder& parent,
738 unsigned int alignment = RTI_XCDR_SEQ_LENGTH_ALIGNMENT)
739 : PrimitiveSequenceBuilder<char>(nested_tag_t(), parent, alignment)
740 {
741 }
742
743public:
747 StringBuilder& set_string(const char *value)
748 {
749 RTI_FLAT_BUILDER_CHECK_VALID(return *this);
750
751 // if set_string is called more than once we override the string
752 // that was set before
753 if (element_count_ != 0) {
754 stream().current_position(begin_position());
755 stream().serialize_fast<rti::xcdr::length_t>(0);
756 element_count_ = 0;
757 }
758
759 unsigned int length = static_cast<unsigned int>(strlen(value)) + 1;
760 add_n(value, length); // if this fail, error has been reported
761 return *this;
762 }
763
771 {
772 RTI_FLAT_BUILDER_CHECK_VALID(return Offset());
773
774 if (element_count_ == 0) {
775 add_next('\0'); // build empty string if no string was built
776 }
777 return finish_impl<Offset>();
778 }
779
781
782 RTI_FLAT_BUILDER_DEFINE_MOVE_OPERATIONS_IMPL(\
783 StringBuilder, Base, AbstractListBuilderMoveProxy)
784};
785
786// Wide strings are treated as a sequence of octets
787typedef PrimitiveSequenceBuilder<unsigned char> WStringBuilder;
788
789} }
790
791#endif // RTI_DDS_FLAT_SEQUENCEBUILDERS_HPP_
792
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
Base class of all array and sequence builders.
Definition: SequenceBuilders.hpp:52
unsigned int element_count() const
Returns the current number of elements that have been added.
Definition: SequenceBuilders.hpp:122
Base class of Builders for sequence members.
Definition: SequenceBuilders.hpp:304
Builds a sequence member of fixed-size elements.
Definition: SequenceBuilders.hpp:487
Offset finish()
Finishes building the sequence.
Definition: SequenceBuilders.hpp:537
FinalSequenceBuilder & add_n(unsigned int count)
Adds a number of elements at once.
Definition: SequenceBuilders.hpp:525
ElementOffset add_next()
Adds the next element.
Definition: SequenceBuilders.hpp:512
Builds an array member of variable-size elements.
Definition: SequenceBuilders.hpp:228
ElementBuilder build_next()
Begins building the next element.
Definition: SequenceBuilders.hpp:257
Offset finish()
Finishes building the array.
Definition: SequenceBuilders.hpp:275
MutableArrayOffset< typename ElementBuilder::Offset, N > Offset
The related Offset type.
Definition: SequenceBuilders.hpp:233
Offset to an array of variable-size elements.
Definition: SequenceOffsets.hpp:582
Builds a sequence member of variable-size elements.
Definition: SequenceBuilders.hpp:404
SequenceOffset< typename ElementBuilder::Offset > Offset
The related Offset type.
Definition: SequenceBuilders.hpp:409
ElementBuilder build_next()
Begins building the next element.
Definition: SequenceBuilders.hpp:433
Offset finish()
Finishes building the sequence.
Definition: SequenceBuilders.hpp:445
Builds a sequence of primitive members.
Definition: SequenceBuilders.hpp:554
PrimitiveSequenceBuilder & add_n(unsigned int count, T value)
Adds a number of elements with the same value.
Definition: SequenceBuilders.hpp:635
PrimitiveSequenceBuilder & add_n(const T *array, unsigned int count)
Adds all the elements in an array.
Definition: SequenceBuilders.hpp:597
PrimitiveSequenceBuilder & add_n(unsigned int count)
Adds a number of uninitialized elements.
Definition: SequenceBuilders.hpp:675
PrimitiveSequenceBuilder & add_next(T value)
Adds the next element.
Definition: SequenceBuilders.hpp:579
Offset finish()
Finishes building the sequence.
Definition: SequenceBuilders.hpp:699
Offset to a sequence of primitive elements.
Definition: SequenceOffsets.hpp:134
Offset to a sequence of non-primitive elements.
Definition: SequenceOffsets.hpp:473
Builds a string.
Definition: SequenceBuilders.hpp:724
Offset finish()
Finishes building the string.
Definition: SequenceBuilders.hpp:770
StringBuilder & set_string(const char *value)
Sets the string value.
Definition: SequenceBuilders.hpp:747
Offset to a string.
Definition: SequenceOffsets.hpp:263
The RTI namespace.
Definition: AggregationBuilders.hpp:17