RTI Connext Traditional C++ API Version 7.3.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 // fixed-size non-primitive members may have a dheader or not; when they
188 // do the LC code is 5, otherwise it is 4.
189 if (!begin_emheader(
190 id,
191 detail::is_fixed_type_w_dheader<OffsetType>::value() ? 5 : 4)) {
192 return OffsetType();
193 }
194
195 OffsetType result = AbstractBuilder::add_element<OffsetType>();
196 finish_emheader();
197
198 stream_memento.discard(); // success - do not restore the previous state
199 return result;
200 }
201
202 template <typename NestedBuilder>
203 NestedBuilder build_member(member_id_t id)
204 {
205 RTI_FLAT_BUILDER_CHECK_VALID(return NestedBuilder());
206
207 // save state in case of error
208 rti::xcdr::Stream::Memento stream_memento(stream());
209 return build_member<NestedBuilder>(id, stream_memento);
210 }
211
212 template <typename NestedBuilder>
213 NestedBuilder build_member(
214 member_id_t id,
215 rti::xcdr::Stream::Memento& stream_memento)
216 {
217 if (!begin_emheader(id, detail::lc_code<NestedBuilder>::value())) {
218 return NestedBuilder();
219 }
220
221 return AbstractBuilder::build_element_no_align<NestedBuilder>(
222 stream_memento);
223 }
224
225 unsigned char* finish_sample_impl()
226 {
227 RTI_FLAT_BUILDER_CHECK_VALID(return NULL);
228 RTI_FLAT_BUILDER_CHECK_NOT_BOUND(return NULL);
229 RTI_FLAT_BUILDER_CHECK_CAN_FINISH_SAMPLE(return NULL);
230
231 if (!stream().finish_dheader(dheader_position_)) {
232 RTI_FLAT_BUILDER_OUT_OF_RESOURCES_ERROR(return NULL);
233 }
234
235 unsigned char *return_sample = stream().buffer();
236 invalidate();
237
238 return return_sample;
239 }
240
241 // Same as finish_impl() but it doesn't throw exceptions or return an Offset
242 void finish_untyped_impl()
243 {
244 if (is_valid() && is_nested()) {
245 stream().finish_dheader(dheader_position_);
246 AbstractBuilder::finish_untyped_impl();
247 }
248 }
249
250 template <typename OffsetType>
251 OffsetType finish_impl()
252 {
253 RTI_FLAT_BUILDER_CHECK_VALID(return OffsetType());
254 RTI_FLAT_BUILDER_CHECK_CAN_FINISH(return OffsetType());
255
256 stream().finish_dheader(dheader_position_);
257 return AbstractBuilder::finish_impl<OffsetType>();
258 }
259
260public:
261 // For internal use; need to use rti::flat::discard_sample(writer, builder)
262 unsigned char * discard_sample_impl()
263 {
264 RTI_FLAT_BUILDER_CHECK_VALID(return NULL);
265 RTI_FLAT_BUILDER_CHECK_NOT_BOUND(return NULL);
266 RTI_FLAT_BUILDER_CHECK_CAN_FINISH_SAMPLE(return NULL);
267
268 unsigned char *buffer = this->buffer();
269 invalidate();
270 return buffer;
271 }
272
273private:
274 void finish_member() // override noexcept
275 {
276 if (!is_valid()) {
277 return;
278 }
279
280 finish_emheader();
281 AbstractBuilder::finish_member();
282 }
283
284private:
285
286 bool begin_emheader(member_id_t id, RTIXCdrUnsignedLong lc)
287 {
288 RTI_FLAT_BUILDER_CHECK_NOT_BOUND(return false);
289
290 if (!stream().serialize_emheader(emheader_position_, id, lc)) {
291 RTI_FLAT_BUILDER_OUT_OF_RESOURCES_ERROR(return false);
292 }
293
294 return true;
295 }
296
297 void finish_emheader() // noexcept
298 {
299 if (emheader_position_ != NULL) {
300 stream().finish_emheader(emheader_position_);
301 emheader_position_ = NULL;
302 }
303 }
304
305protected:
306 // Create a nested builder
307 AggregationBuilder(nested_tag_t, AbstractBuilder& parent, unsigned int alignment)
308 : AbstractBuilder(nested_tag_t(), parent, alignment),
309 dheader_position_(NULL),
310 emheader_position_(NULL)
311 {
312 dheader_position_ = stream().serialize_dheader();
313 if (dheader_position_ == NULL) {
314 RTI_FLAT_BUILDER_OUT_OF_RESOURCES_ERROR(invalidate());
315 }
316 }
317
318private:
319 char * dheader_position_;
320 char * emheader_position_;
321};
322
323// Specializes an AggregationBuilder to enforce that only one member can
324// be set at a time
334template <typename Discriminator>
336protected:
338 {
339 }
340
341 // Create a new top-level builder
343 unsigned char *initial_buffer,
344 offset_t size,
345 bool initialize_members) :
346 AggregationBuilder(initial_buffer, size, initialize_members)
347 {
348 }
349
350 template <typename T>
351 bool add_primitive_member(member_id_t id, Discriminator disc, T value)
352 {
353 RTI_FLAT_BUILDER_CHECK_VALID(return false);
354
355 // Always start at the beginning and override any member or discriminator
356 // that may have been set
357 move_to_discriminator();
358 rti::xcdr::Stream::Memento stream_memento(stream());
359
360 if (!add_discriminator(disc)) {
361 return false;
362 }
363
364 if (!AggregationBuilder::add_primitive_member(id, value)) {
365 return false;
366 }
367
368 stream_memento.discard(); // success: do not restore the current position
369 return true;
370 }
371
372 template <typename OffsetType>
373 OffsetType add_member(member_id_t id, Discriminator disc)
374 {
375 RTI_FLAT_BUILDER_CHECK_VALID(return OffsetType());
376
377 move_to_discriminator();
378 rti::xcdr::Stream::Memento stream_memento(stream());
379 if (!add_discriminator(disc)) {
380 RTI_FLAT_BUILDER_OUT_OF_RESOURCES_ERROR(return OffsetType());
381 }
382
383 return AggregationBuilder::add_member<OffsetType>(id, stream_memento);
384 }
385
386 template <typename NestedBuilder>
387 NestedBuilder build_member(member_id_t id, Discriminator disc)
388 {
389 RTI_FLAT_BUILDER_CHECK_VALID(return NestedBuilder());
390
391 move_to_discriminator();
392 rti::xcdr::Stream::Memento stream_memento(stream());
393 add_discriminator(disc);
394
395 return AggregationBuilder::build_member<NestedBuilder>(id, stream_memento);
396 }
397
398 // Create a nested builder
399 UnionBuilder(nested_tag_t, AbstractBuilder& parent, unsigned int alignment)
400 : AggregationBuilder(nested_tag_t(), parent, alignment)
401 {
402 }
403
404private:
405 void move_to_discriminator()
406 {
407 stream().current_position(begin_position() + RTI_XCDR_DHEADER_SIZE);
408 }
409
410 bool add_discriminator(Discriminator disc)
411 {
412 return AggregationBuilder::add_primitive_member(0, disc);
413 }
414};
415
416
417} }
418
419#endif // RTI_DDS_FLAT_AGGREGATIONBUILDERS_HPP_
420
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 struct and union builders.
Definition: AggregationBuilders.hpp:37
Base class of builders for user-defined mutable unions.
Definition: AggregationBuilders.hpp:335
The RTI namespace.
Definition: AggregationBuilders.hpp:17