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