RTI Connext Traditional C++ API Version 7.1.0
AggregationBuilders.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_AGGREGATIONBUILDERS_HPP_
12#define RTI_DDS_FLAT_AGGREGATIONBUILDERS_HPP_
13
14#include "rti/flat/BuilderHelper.hpp"
15#include "rti/flat/Builder.hpp"
16
17namespace rti { namespace flat {
18
19/*
20 * Provides the common functionality for builders of aggregated types
21 *
22 * Extends and specializes AbstractBuilder to add or override the functionality
23 * required to build an aggregated type:
24 *
25 * - Add or build members, prepending the member header
26 * - Add dheader at the beginning
27 * - Add parameter-list-end header at the end
28 */
38protected:
40 dheader_position_(NULL),
41 emheader_position_(NULL)
42 {
43 }
44
45 // Create a new top-level builder
47 unsigned char *initial_buffer,
48 offset_t size,
49 bool initialize_members) :
50 AbstractBuilder(initial_buffer, size, initialize_members),
51 dheader_position_(NULL),
52 emheader_position_(NULL)
53 {
54 dheader_position_ = stream().serialize_dheader();
55 if (dheader_position_ == NULL) {
56 RTI_FLAT_BUILDER_OUT_OF_RESOURCES_ERROR(invalidate());
57 }
58 }
59
60public:
61 // For internal use and testing
62 //
63 // Modifies the encapsulation set in the constructor with a custom value.
64 // This function can only be called after the construction of a non-nested
65 // Builder, before any member is built or added.
66 //
67 void set_encapsulation_impl(RTIXCdrEncapsulationId encapsulation_id)
68 {
69 // Only a top-level Builder can change the encapsulation
70 RTI_FLAT_CHECK_PRECONDITION(!is_nested(), return);
71
72 char *current_position = (char *) owned_stream_.current_position();
73 // This operation is only valid right after construction, when no
74 // member has been added yet
75 RTI_FLAT_CHECK_PRECONDITION(
76 current_position == dheader_position_ + RTI_XCDR_DHEADER_SIZE,
77 return);
78
79 owned_stream_.skip_back(
80 RTI_XCDR_DHEADER_SIZE + RTI_XCDR_ENCAPSULATION_HEADER_SIZE);
81
82 if (!RTIXCdrFlatSample_initializeEncapsulationAndStream(
83 (char *) owned_stream_.buffer(),
84 &owned_stream_.c_stream(),
85 encapsulation_id,
86 owned_stream_.total_size())) {
87 RTI_FLAT_BUILDER_OUT_OF_RESOURCES_ERROR(return);
88 }
89
90 stream().serialize_dheader();
91 }
92
93protected:
94
95#if defined(RTI_FLAT_DATA_CXX11_RVALUE_REFERENCES)
96 AggregationBuilder(AggregationBuilder&& other) = default;
97
98 AggregationBuilder& operator=(AggregationBuilder&& other)
99 {
100 if (this == &other) {
101 return *this;
102 }
103
104 finish_untyped_impl();
105
106 AbstractBuilder::operator=(static_cast<AbstractBuilder&&>(other));
107
108 dheader_position_ = other.dheader_position_;
109 emheader_position_ = other.emheader_position_;
110
111 return *this;
112 }
113#else
114public:
115 // Enable the safe-move-constructor idiom without C++11 move constructors
116 struct UntypedAggregationBuilderMoveProxy : AbstractBuilderMoveProxy {
117 char * dheader_position_;
118 char * emheader_position_;
119 };
120
121 operator UntypedAggregationBuilderMoveProxy () throw() // move-constructor idiom
122 {
123 UntypedAggregationBuilderMoveProxy other;
124 move_to(other);
125 return other;
126 }
127
128protected:
129 void move_from(UntypedAggregationBuilderMoveProxy& other)
130 {
131 AbstractBuilder::move_from(other);
132 dheader_position_ = other.dheader_position_;
133 emheader_position_ = other.emheader_position_;
134 }
135
136 void move_to(UntypedAggregationBuilderMoveProxy& other)
137 {
138 AbstractBuilder::move_to(other);
139 other.dheader_position_ = dheader_position_;
140 other.emheader_position_ = emheader_position_;
141 }
142#endif
143
144protected:
145 virtual ~AggregationBuilder()
146 {
147 // AggregationBuilder::finish_untyped_impl() is specialized
148 // with respect to AbstractBuilder::finish_untyped_impl()
149 finish_untyped_impl();
150 }
151
152 template <typename T>
153 bool add_primitive_member(member_id_t id, T value)
154 {
155 RTI_FLAT_BUILDER_CHECK_VALID(return false);
156
157 rti::xcdr::Stream::Memento stream_memento(stream());
158
159 if (!begin_emheader(id, detail::primitive_lc_code<T>::value)) {
160 RTI_FLAT_BUILDER_OUT_OF_RESOURCES_ERROR(return false);
161 }
162 // no need to call finish_emheader()
163
164 if (!stream().serialize_no_align(value)) {
165 RTI_FLAT_BUILDER_OUT_OF_RESOURCES_ERROR(return false);
166 }
167
168 stream_memento.discard(); // success: do not restore the current position
169 return true;
170 }
171
172 template <typename OffsetType>
173 OffsetType add_member(member_id_t id)
174 {
175 RTI_FLAT_BUILDER_CHECK_VALID(return OffsetType());
176
177 // save state in case of error
178 rti::xcdr::Stream::Memento stream_memento(stream());
179 return add_member<OffsetType>(id, stream_memento);
180 }
181
182 template <typename OffsetType>
183 OffsetType add_member(
184 member_id_t id,
185 rti::xcdr::Stream::Memento& stream_memento)
186 {
187 // EMHeader with LC = 4; any fixed-size non-primitive member will have
188 // LC = 4 since they don't encode a length
189 if (!begin_emheader(id, 4)) {
190 return OffsetType();
191 }
192
193 OffsetType result = AbstractBuilder::add_element<OffsetType>();
194 finish_emheader();
195
196 stream_memento.discard(); // success - do not restore the previous state
197 return result;
198 }
199
200 template <typename NestedBuilder>
201 NestedBuilder build_member(member_id_t id)
202 {
203 RTI_FLAT_BUILDER_CHECK_VALID(return NestedBuilder());
204
205 // save state in case of error
206 rti::xcdr::Stream::Memento stream_memento(stream());
207 return build_member<NestedBuilder>(id, stream_memento);
208 }
209
210 template <typename NestedBuilder>
211 NestedBuilder build_member(
212 member_id_t id,
213 rti::xcdr::Stream::Memento& stream_memento)
214 {
215 if (!begin_emheader(id, detail::lc_code<NestedBuilder>::value)) {
216 return NestedBuilder();
217 }
218
219 return AbstractBuilder::build_element_no_align<NestedBuilder>(
220 stream_memento);
221 }
222
223 unsigned char* finish_sample_impl()
224 {
225 RTI_FLAT_BUILDER_CHECK_VALID(return NULL);
226 RTI_FLAT_BUILDER_CHECK_NOT_BOUND(return NULL);
227 RTI_FLAT_BUILDER_CHECK_CAN_FINISH_SAMPLE(return NULL);
228
229 if (!stream().finish_dheader(dheader_position_)) {
230 RTI_FLAT_BUILDER_OUT_OF_RESOURCES_ERROR(return NULL);
231 }
232
233 unsigned char *return_sample = stream().buffer();
234 invalidate();
235
236 return return_sample;
237 }
238
239 // Same as finish_impl() but it doesn't throw exceptions or return an Offset
240 void finish_untyped_impl()
241 {
242 if (is_valid() && is_nested()) {
243 stream().finish_dheader(dheader_position_);
244 AbstractBuilder::finish_untyped_impl();
245 }
246 }
247
248 template <typename OffsetType>
249 OffsetType finish_impl()
250 {
251 RTI_FLAT_BUILDER_CHECK_VALID(return OffsetType());
252 RTI_FLAT_BUILDER_CHECK_CAN_FINISH(return OffsetType());
253
254 stream().finish_dheader(dheader_position_);
255 return AbstractBuilder::finish_impl<OffsetType>();
256 }
257
258public:
259 // For internal use; need to use rti::flat::discard_sample(writer, builder)
260 unsigned char * discard_sample_impl()
261 {
262 RTI_FLAT_BUILDER_CHECK_VALID(return NULL);
263 RTI_FLAT_BUILDER_CHECK_NOT_BOUND(return NULL);
264 RTI_FLAT_BUILDER_CHECK_CAN_FINISH_SAMPLE(return NULL);
265
266 unsigned char *buffer = this->buffer();
267 invalidate();
268 return buffer;
269 }
270
271private:
272 void finish_member() // override noexcept
273 {
274 if (!is_valid()) {
275 return;
276 }
277
278 finish_emheader();
279 AbstractBuilder::finish_member();
280 }
281
282private:
283
284 bool begin_emheader(member_id_t id, RTIXCdrUnsignedLong lc)
285 {
286 RTI_FLAT_BUILDER_CHECK_NOT_BOUND(return false);
287
288 if (!stream().serialize_emheader(emheader_position_, id, lc)) {
289 RTI_FLAT_BUILDER_OUT_OF_RESOURCES_ERROR(return false);
290 }
291
292 return true;
293 }
294
295 void finish_emheader() // noexcept
296 {
297 if (emheader_position_ != NULL) {
298 stream().finish_emheader(emheader_position_);
299 emheader_position_ = NULL;
300 }
301 }
302
303protected:
304 // Create a nested builder
305 AggregationBuilder(nested_tag_t, AbstractBuilder& parent, unsigned int alignment)
306 : AbstractBuilder(nested_tag_t(), parent, alignment),
307 dheader_position_(NULL),
308 emheader_position_(NULL)
309 {
310 dheader_position_ = stream().serialize_dheader();
311 if (dheader_position_ == NULL) {
312 RTI_FLAT_BUILDER_OUT_OF_RESOURCES_ERROR(invalidate());
313 }
314 }
315
316private:
317 char * dheader_position_;
318 char * emheader_position_;
319};
320
321// Specializes an AggregationBuilder to enforce that only one member can
322// be set at a time
332template <typename Discriminator>
334protected:
336 {
337 }
338
339 // Create a new top-level builder
341 unsigned char *initial_buffer,
342 offset_t size,
343 bool initialize_members) :
344 AggregationBuilder(initial_buffer, size, initialize_members)
345 {
346 }
347
348 template <typename T>
349 bool add_primitive_member(member_id_t id, Discriminator disc, T value)
350 {
351 RTI_FLAT_BUILDER_CHECK_VALID(return false);
352
353 // Always start at the beginning and override any member or discriminator
354 // that may have been set
355 move_to_discriminator();
356 rti::xcdr::Stream::Memento stream_memento(stream());
357
358 if (!add_discriminator(disc)) {
359 return false;
360 }
361
362 if (!AggregationBuilder::add_primitive_member(id, value)) {
363 return false;
364 }
365
366 stream_memento.discard(); // success: do not restore the current position
367 return true;
368 }
369
370 template <typename OffsetType>
371 OffsetType add_member(member_id_t id, Discriminator disc)
372 {
373 RTI_FLAT_BUILDER_CHECK_VALID(return OffsetType());
374
375 move_to_discriminator();
376 rti::xcdr::Stream::Memento stream_memento(stream());
377 if (!add_discriminator(disc)) {
378 RTI_FLAT_BUILDER_OUT_OF_RESOURCES_ERROR(return OffsetType());
379 }
380
381 return AggregationBuilder::add_member<OffsetType>(id, stream_memento);
382 }
383
384 template <typename NestedBuilder>
385 NestedBuilder build_member(member_id_t id, Discriminator disc)
386 {
387 RTI_FLAT_BUILDER_CHECK_VALID(return NestedBuilder());
388
389 move_to_discriminator();
390 rti::xcdr::Stream::Memento stream_memento(stream());
391 add_discriminator(disc);
392
393 return AggregationBuilder::build_member<NestedBuilder>(id, stream_memento);
394 }
395
396 // Create a nested builder
397 UnionBuilder(nested_tag_t, AbstractBuilder& parent, unsigned int alignment)
398 : AggregationBuilder(nested_tag_t(), parent, alignment)
399 {
400 }
401
402private:
403 void move_to_discriminator()
404 {
405 stream().current_position(begin_position() + RTI_XCDR_DHEADER_SIZE);
406 }
407
408 bool add_discriminator(Discriminator disc)
409 {
410 return AggregationBuilder::add_primitive_member(0, disc);
411 }
412};
413
414
415} }
416
417#endif // RTI_DDS_FLAT_AGGREGATIONBUILDERS_HPP_
418
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 struct and union builders.
Definition: AggregationBuilders.hpp:37
Base class of builders for user-defined mutable unions.
Definition: AggregationBuilders.hpp:333
The RTI namespace.
Definition: AggregationBuilders.hpp:17