RTI Connext Traditional C++ API Version 7.7.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#include "xcdr/xcdr_interpreter.h"
17
18namespace rti { namespace flat {
19
20/*
21 * Parameters describing a member to be added or built.
22 *
23 * The information encoded by this structure is used to set the appropriate
24 * bits in the header that precedes each member of a mutable type.
25 */
26struct MemberParams {
27 /*
28 * Indicates whether the member is part of the key.
29 */
30 bool key;
31 /*
32 * Indicates whether the member is the discriminator of a union.
33 */
34 bool discriminator;
35 /*
36 * Indicates whether the member has been marked as "must understand".
37 */
38 bool must_understand;
39
40 MemberParams() : key(false), discriminator(false), must_understand(false)
41 { }
42
43 /*
44 * Check whether the current XCDR2 compliance mask allows the
45 * specified features.
46 *
47 * This function will cache the value of the compliance mask to avoid
48 * repeated nested function calls at runtime.
49 *
50 * @param check_mask The feature bits to check in the compliance mask.
51 * @param reload_mask If true, force reloading of the compliance mask
52 * from the global configuration.
53 * @return true if all the bits in check_mask are set in the compliance
54 * mask.
55 */
56 static bool xcdr2_compliant(
57 const RTIXCdrXTypesComplianceMask check_mask,
58 const bool reload_mask)
59 {
60 static bool g_compliance_mask_set = false;
61 static RTIXCdrXTypesComplianceMask g_compliance_mask = 0;
62
63 // Initialize the compliance mask on first use
64 // There could be a data race here but the worst that can happen is
65 // that the compliance mask is read more than once.
66 // The goal is to avoid nested function calls on each and every call.
67 if (reload_mask || !g_compliance_mask_set) {
68 g_compliance_mask =
69 RTIXCdrInterpreter_getGlobalXtypeComplianceMask();
70 g_compliance_mask_set = true;
71 }
72
73 return (g_compliance_mask & check_mask);
74 }
75
76 /*
77 * Check if the must_understand bit should be set in the header for this
78 * member.
79 *
80 * The bit will always be set if the must_understand attribute is true.
81 * Additionally, if the current XCDR2 compliance mask allows it, the bit
82 * will also be set for key members and discriminators.
83 *
84 * @return true if the must_understand bit should be set.
85 */
86 bool has_must_understand_bit() const
87 {
88 return must_understand
89 || (xcdr2_compliant(
90 RTI_XCDR_XTYPES_MUST_UNDERSTAND_IN_KEY_AND_DISCRIMINATOR_BIT,
91 false)
92 && (key || discriminator));
93 }
94};
95
96/*
97 * Provides the common functionality for builders of aggregated types
98 *
99 * Extends and specializes AbstractBuilder to add or override the functionality
100 * required to build an aggregated type:
101 *
102 * - Add or build members, prepending the member header
103 * - Add dheader at the beginning
104 * - Add parameter-list-end header at the end
105 */
115protected:
117 dheader_position_(NULL),
118 emheader_position_(NULL)
119 {
120 }
121
122 // Create a new top-level builder
124 unsigned char *initial_buffer,
125 offset_t size,
126 bool initialize_members) :
127 AbstractBuilder(initial_buffer, size, initialize_members),
128 dheader_position_(NULL),
129 emheader_position_(NULL)
130 {
131 dheader_position_ = stream().serialize_dheader();
132 if (dheader_position_ == NULL) {
133 RTI_FLAT_BUILDER_OUT_OF_RESOURCES_ERROR(invalidate());
134 }
135 }
136
137public:
138 // For internal use and testing
139 //
140 // Modifies the encapsulation set in the constructor with a custom value.
141 // This function can only be called after the construction of a non-nested
142 // Builder, before any member is built or added.
143 //
144 void set_encapsulation_impl(RTIXCdrEncapsulationId encapsulation_id)
145 {
146 // Only a top-level Builder can change the encapsulation
147 RTI_FLAT_CHECK_PRECONDITION(!is_nested(), return);
148
149 char *current_position = (char *) owned_stream_.current_position();
150 // This operation is only valid right after construction, when no
151 // member has been added yet
152 RTI_FLAT_CHECK_PRECONDITION(
153 current_position == dheader_position_ + RTI_XCDR_DHEADER_SIZE,
154 return);
155
156 owned_stream_.skip_back(
157 RTI_XCDR_DHEADER_SIZE + RTI_XCDR_ENCAPSULATION_HEADER_SIZE);
158
159 if (!RTIXCdrFlatSample_initializeEncapsulationAndStream(
160 (char *) owned_stream_.buffer(),
161 &owned_stream_.c_stream(),
162 encapsulation_id,
163 owned_stream_.total_size())) {
164 RTI_FLAT_BUILDER_OUT_OF_RESOURCES_ERROR(return);
165 }
166
167 stream().serialize_dheader();
168 }
169
170protected:
171
172#if defined(RTI_FLAT_DATA_CXX11_RVALUE_REFERENCES)
173 AggregationBuilder(AggregationBuilder&& other) = default;
174
175 AggregationBuilder& operator=(AggregationBuilder&& other)
176 {
177 if (this == &other) {
178 return *this;
179 }
180
181 finish_untyped_impl();
182
183 AbstractBuilder::operator=(static_cast<AbstractBuilder&&>(other));
184
185 dheader_position_ = other.dheader_position_;
186 emheader_position_ = other.emheader_position_;
187
188 return *this;
189 }
190#else
191public:
192 // Enable the safe-move-constructor idiom without C++11 move constructors
193 struct UntypedAggregationBuilderMoveProxy : AbstractBuilderMoveProxy {
194 char * dheader_position_;
195 char * emheader_position_;
196 };
197
198 operator UntypedAggregationBuilderMoveProxy () throw() // move-constructor idiom
199 {
200 UntypedAggregationBuilderMoveProxy other;
201 move_to(other);
202 return other;
203 }
204
205protected:
206 void move_from(UntypedAggregationBuilderMoveProxy& other)
207 {
208 AbstractBuilder::move_from(other);
209 dheader_position_ = other.dheader_position_;
210 emheader_position_ = other.emheader_position_;
211 }
212
213 void move_to(UntypedAggregationBuilderMoveProxy& other)
214 {
215 AbstractBuilder::move_to(other);
216 other.dheader_position_ = dheader_position_;
217 other.emheader_position_ = emheader_position_;
218 }
219#endif
220
221protected:
222 virtual ~AggregationBuilder()
223 {
224 // AggregationBuilder::finish_untyped_impl() is specialized
225 // with respect to AbstractBuilder::finish_untyped_impl()
226 finish_untyped_impl();
227 }
228
229 template <typename T>
230 bool add_primitive_member(
231 member_id_t id,
232 T value,
233 const MemberParams& params)
234 {
235 RTI_FLAT_BUILDER_CHECK_VALID(return false);
236
237 rti::xcdr::Stream::Memento stream_memento(stream());
238
239 if (!begin_emheader(id, detail::primitive_lc_code<T>::value, params)) {
240 RTI_FLAT_BUILDER_OUT_OF_RESOURCES_ERROR(return false);
241 }
242 // no need to call finish_emheader()
243
244 if (!stream().serialize_no_align(value)) {
245 RTI_FLAT_BUILDER_OUT_OF_RESOURCES_ERROR(return false);
246 }
247
248 stream_memento.discard(); // success: do not restore the current position
249 return true;
250 }
251
252 template <typename T>
253 bool add_primitive_member(member_id_t id, T value)
254 {
255 static const MemberParams default_params;
256 return add_primitive_member(id, value, default_params);
257 }
258
259 template <typename OffsetType>
260 OffsetType add_member(member_id_t id, const MemberParams& params)
261 {
262 RTI_FLAT_BUILDER_CHECK_VALID(return OffsetType());
263
264 // save state in case of error
265 rti::xcdr::Stream::Memento stream_memento(stream());
266 return add_member<OffsetType>(id, stream_memento, params);
267 }
268
269 template <typename OffsetType>
270 OffsetType add_member(member_id_t id)
271 {
272 RTI_FLAT_BUILDER_CHECK_VALID(return OffsetType());
273
274 // save state in case of error
275 rti::xcdr::Stream::Memento stream_memento(stream());
276 static const MemberParams default_params;
277 return add_member<OffsetType>(id, stream_memento, default_params);
278 }
279
280 template <typename OffsetType>
281 OffsetType add_member(
282 member_id_t id,
283 rti::xcdr::Stream::Memento& stream_memento)
284 {
285 static const MemberParams default_params;
286 return add_member<OffsetType>(id, stream_memento, default_params);
287 }
288
289 template <typename OffsetType>
290 OffsetType add_member(
291 member_id_t id,
292 rti::xcdr::Stream::Memento& stream_memento,
293 const MemberParams& params)
294 {
295 // fixed-size non-primitive members may have a dheader or not; when they
296 // do the LC code is 5, otherwise it is 4.
297 if (!begin_emheader(
298 id,
299 detail::is_fixed_type_w_dheader<OffsetType>::value() ? 5
300 : 4,
301 params)) {
302 return OffsetType();
303 }
304
305 OffsetType result = AbstractBuilder::add_element<OffsetType>();
306 finish_emheader();
307
308 stream_memento.discard(); // success - do not restore the previous state
309 return result;
310 }
311
312 template <typename NestedBuilder>
313 NestedBuilder build_member(member_id_t id, const MemberParams& params)
314 {
315 RTI_FLAT_BUILDER_CHECK_VALID(return NestedBuilder());
316
317 // save state in case of error
318 rti::xcdr::Stream::Memento stream_memento(stream());
319 return build_member<NestedBuilder>(id, stream_memento, params);
320 }
321
322 template <typename NestedBuilder>
323 NestedBuilder build_member(member_id_t id)
324 {
325 static const MemberParams default_params;
326 return build_member<NestedBuilder>(id, default_params);
327 }
328
329 template <typename NestedBuilder>
330 NestedBuilder build_member(
331 member_id_t id,
332 rti::xcdr::Stream::Memento& stream_memento)
333 {
334 static const MemberParams default_params;
335 return build_member<NestedBuilder>(id, stream_memento, default_params);
336 }
337
338 template <typename NestedBuilder>
339 NestedBuilder build_member(
340 member_id_t id,
341 rti::xcdr::Stream::Memento& stream_memento,
342 const MemberParams& params)
343 {
344 if (!begin_emheader(
345 id,
346 static_cast<RTIXCdrUnsignedLong>(
347 detail::lc_code<NestedBuilder>::value()),
348 params)) {
349 return NestedBuilder();
350 }
351
352 return AbstractBuilder::build_element_no_align<NestedBuilder>(
353 stream_memento);
354 }
355
356 unsigned char* finish_sample_impl()
357 {
358 RTI_FLAT_BUILDER_CHECK_VALID(return NULL);
359 RTI_FLAT_BUILDER_CHECK_NOT_BOUND(return NULL);
360 RTI_FLAT_BUILDER_CHECK_CAN_FINISH_SAMPLE(return NULL);
361
362 if (!stream().finish_dheader(dheader_position_)) {
363 RTI_FLAT_BUILDER_OUT_OF_RESOURCES_ERROR(return NULL);
364 }
365
366 unsigned char *return_sample = stream().buffer();
367 invalidate();
368
369 return return_sample;
370 }
371
372 // Same as finish_impl() but it doesn't throw exceptions or return an Offset
373 void finish_untyped_impl()
374 {
375 if (is_valid() && is_nested()) {
376 stream().finish_dheader(dheader_position_);
377 AbstractBuilder::finish_untyped_impl();
378 }
379 }
380
381 template <typename OffsetType>
382 OffsetType finish_impl()
383 {
384 RTI_FLAT_BUILDER_CHECK_VALID(return OffsetType());
385 RTI_FLAT_BUILDER_CHECK_CAN_FINISH(return OffsetType());
386
387 stream().finish_dheader(dheader_position_);
388 return AbstractBuilder::finish_impl<OffsetType>();
389 }
390
391public:
392 // For internal use; need to use rti::flat::discard_sample(writer, builder)
393 unsigned char * discard_sample_impl()
394 {
395 RTI_FLAT_BUILDER_CHECK_VALID(return NULL);
396 RTI_FLAT_BUILDER_CHECK_NOT_BOUND(return NULL);
397 RTI_FLAT_BUILDER_CHECK_CAN_FINISH_SAMPLE(return NULL);
398
399 unsigned char *buffer = this->buffer();
400 invalidate();
401 return buffer;
402 }
403
404private:
405 void finish_member() // override noexcept
406 {
407 if (!is_valid()) {
408 return;
409 }
410
411 finish_emheader();
412 AbstractBuilder::finish_member();
413 }
414
415private:
416 bool begin_emheader(
417 member_id_t id,
418 RTIXCdrUnsignedLong lc,
419 const MemberParams& params)
420 {
421 RTI_FLAT_BUILDER_CHECK_NOT_BOUND(return false);
422
423 if (!stream().serialize_emheader(
424 emheader_position_,
425 id,
426 lc,
427 params.has_must_understand_bit())) {
428 RTI_FLAT_BUILDER_OUT_OF_RESOURCES_ERROR(return false);
429 }
430
431 return true;
432 }
433
434 void finish_emheader() // noexcept
435 {
436 if (emheader_position_ != NULL) {
437 stream().finish_emheader(emheader_position_);
438 emheader_position_ = NULL;
439 }
440 }
441
442protected:
443 // Create a nested builder
444 AggregationBuilder(nested_tag_t, AbstractBuilder& parent, unsigned int alignment)
445 : AbstractBuilder(nested_tag_t(), parent, alignment),
446 dheader_position_(NULL),
447 emheader_position_(NULL)
448 {
449 dheader_position_ = stream().serialize_dheader();
450 if (dheader_position_ == NULL) {
451 RTI_FLAT_BUILDER_OUT_OF_RESOURCES_ERROR(invalidate());
452 }
453 }
454
455private:
456 char * dheader_position_;
457 char * emheader_position_;
458};
459
460// Specializes an AggregationBuilder to enforce that only one member can
461// be set at a time
471template <typename Discriminator>
473protected:
475 {
476 }
477
478 // Create a new top-level builder
480 unsigned char *initial_buffer,
481 offset_t size,
482 bool initialize_members) :
483 AggregationBuilder(initial_buffer, size, initialize_members)
484 {
485 }
486
487 template <typename T>
488 bool add_primitive_member(member_id_t id, Discriminator disc, T value)
489 {
490 RTI_FLAT_BUILDER_CHECK_VALID(return false);
491
492 // Always start at the beginning and override any member or discriminator
493 // that may have been set
494 move_to_discriminator();
495 rti::xcdr::Stream::Memento stream_memento(stream());
496
497 if (!add_discriminator(disc)) {
498 return false;
499 }
500
501 if (!AggregationBuilder::add_primitive_member(id, value)) {
502 return false;
503 }
504
505 stream_memento.discard(); // success: do not restore the current position
506 return true;
507 }
508
509 template <typename OffsetType>
510 OffsetType add_member(member_id_t id, Discriminator disc)
511 {
512 RTI_FLAT_BUILDER_CHECK_VALID(return OffsetType());
513
514 move_to_discriminator();
515 rti::xcdr::Stream::Memento stream_memento(stream());
516 if (!add_discriminator(disc)) {
517 RTI_FLAT_BUILDER_OUT_OF_RESOURCES_ERROR(return OffsetType());
518 }
519
520 return AggregationBuilder::add_member<OffsetType>(id, stream_memento);
521 }
522
523 template <typename NestedBuilder>
524 NestedBuilder build_member(member_id_t id, Discriminator disc)
525 {
526 RTI_FLAT_BUILDER_CHECK_VALID(return NestedBuilder());
527
528 move_to_discriminator();
529 rti::xcdr::Stream::Memento stream_memento(stream());
530 add_discriminator(disc);
531
532 return AggregationBuilder::build_member<NestedBuilder>(id, stream_memento);
533 }
534
535 // Create a nested builder
536 UnionBuilder(nested_tag_t, AbstractBuilder& parent, unsigned int alignment)
537 : AggregationBuilder(nested_tag_t(), parent, alignment)
538 {
539 }
540
541private:
542 void move_to_discriminator()
543 {
544 stream().current_position(begin_position() + RTI_XCDR_DHEADER_SIZE);
545 }
546
547 bool add_discriminator(Discriminator disc)
548 {
549 MemberParams params;
550 params.discriminator = true;
551 return AggregationBuilder::add_primitive_member(0, disc, params);
552 }
553};
554
555
556} }
557
558#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:114
Base class of builders for user-defined mutable unions.
Definition: AggregationBuilders.hpp:472
The RTI namespace.
Definition: AggregationBuilders.hpp:18