RTI Connext Traditional C++ API Version 7.2.0
SequenceOffsets.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_SEQUENCEOFFSETS_HPP_
12#define RTI_DDS_FLAT_SEQUENCEOFFSETS_HPP_
13
14#include "rti/flat/Offset.hpp"
15#include "rti/flat/SequenceIterator.hpp"
16
17namespace rti { namespace flat {
18
26template <typename T>
28public:
29 typedef T value_type;
30
31protected:
33 {
34 }
35
37 rti::flat::SampleBase *sample,
38 offset_t offset,
39 offset_t sequence_size)
40 : OffsetBase(sample, offset, sequence_size)
41 {
42 }
43
44public:
45
46 bool is_cpp_compatible() const
47 {
48 RTI_FLAT_OFFSET_CHECK_NOT_NULL(return false);
49 return sizeof(T) == 1 || !stream_.needs_byte_swap();
50 }
51
52
53 /*@private
54 * @brief Gets direct access to the elements
55 *
56 * Returns a pointer to the elements of this sequence.
57 *
58 * @note If the Sample that contains this PrimitiveSequenceOffset has an endianess
59 * different from the native one, the element bytes may be swapped. This can
60 * happen if this Sample was published by a DataWriter running on a platform
61 * with a different endianess and received by a DataReader running locally.
62 *
63 * This function is not for public use. See rti::flat::plain_cast() instead.
64 */
65 T * get_elements()
66 {
67 return reinterpret_cast<T*>(this->get_buffer());
68 }
69
70 /*@private
71 * @brief Gets direct access to the array elements
72 *
73 * (Const overload)
74 */
75 const T * get_elements() const
76 {
77 return reinterpret_cast<const T*>(this->get_buffer());
78 }
79
88 T get_element(unsigned int i) const
89 {
90 // OffsetBase::serialize only checks this as a debug assertion; in
91 // a sequence or array we need to do it in release mode too
92 if (!stream_.check_size((i + 1) * ((unsigned int) sizeof(T)))) {
93 return T();
94 }
95
96 return OffsetBase::template deserialize<T>(i * (unsigned int) sizeof(T));
97 }
98
111 bool set_element(unsigned int i, T value)
112 {
113 // OffsetBase::serialize only checks this as a debug assertion; in
114 // a sequence or array we need to do it in release mode too
115 if (!stream_.check_size((i + 1) * static_cast<unsigned int>(sizeof(T)))) {
116 return false;
117 }
118
119 return OffsetBase::serialize(i * static_cast<unsigned int>(sizeof(T)), value);
120 }
121};
122
123template <typename T>
124struct PrimitiveSequenceOffsetHelper;
125
133template <typename T>
135public:
136 typedef variable_size_type_tag_t offset_kind;
137 typedef PrimitiveSequenceOffsetHelper<T> Helper;
138
139 PrimitiveSequenceOffset() : element_count_(0)
140 {
141 }
142
144 rti::flat::SampleBase *sample,
145 offset_t offset,
146 offset_t serialized_size)
148 // passing NULL causes the base constructors to fail
149 serialized_size >= static_cast<offset_t>(sizeof(rti::xcdr::length_t)) ? sample : NULL,
150 offset + static_cast<offset_t>(sizeof(rti::xcdr::length_t)),
151 serialized_size - static_cast<offset_t>(sizeof(rti::xcdr::length_t))),
152 element_count_(0)
153 {
154#ifdef RTI_FLAT_DATA_NO_EXCEPTIONS
155 if (!this->is_null()) { // without exceptions, we need to check if the base ctor failed
156#endif
157 rti::xcdr::Stream::Memento stream_memento(this->stream_);
158 this->stream_.skip_back(sizeof(rti::xcdr::length_t));
159 element_count_ = this->stream_.template deserialize_fast<rti::xcdr::length_t>();
160#ifdef RTI_FLAT_DATA_NO_EXCEPTIONS
161 }
162#endif
163
164 }
165
169 unsigned int element_count() const
170 {
171 RTI_FLAT_OFFSET_CHECK_NOT_NULL(return 0);
172
173 return element_count_;
174 }
175
176private:
177 unsigned int element_count_;
178
179};
180
181template <typename T>
182struct PrimitiveSequenceOffsetHelper {
183 static offset_t calculate_serialized_size(
184 rti::flat::SampleBase *sample,
185 offset_t absolute_offset,
186 offset_t max_size)
187 {
188 RTI_FLAT_ASSERT(sample != NULL, return 0);
189 RTI_FLAT_ASSERT(max_size > sizeof(rti::xcdr::length_t), return 0);
190
191 PrimitiveSequenceOffset<T> tmp(sample, absolute_offset, max_size);
192
193 // elements + header
194 if ((RTIXCdrUnsignedLong_MAX
195 - static_cast<unsigned int>(sizeof(rti::xcdr::length_t)))
196 / static_cast<unsigned int>(sizeof(T))
197 < tmp.element_count()) {
198 RTI_FLAT_OFFSET_PRECONDITION_ERROR(
199 "Serialized size of a sequence of primitive elements "
200 "exceeds maximum representable 32-bit unsigned integer.",
201 return 0);
202 }
203 return (tmp.element_count() * static_cast<unsigned int>(sizeof(T)))
204 + static_cast<unsigned int>(sizeof(rti::xcdr::length_t));
205 }
206};
207
219template <typename T, unsigned int N>
221public:
222 typedef fixed_size_type_tag_t offset_kind;
223
225 {
226 }
227
228 PrimitiveArrayOffset(rti::flat::SampleBase *sample, offset_t offset)
230 sample,
231 offset,
232 serialized_size(0))
233 {
234 }
235
236public:
237
242 unsigned int element_count() const
243 {
244 return N;
245 }
246
247 static offset_t serialized_size(offset_t)
248 {
249 return sizeof(T) * N;
250 }
251};
252
253// Note: the modern C++ API defines a PrimitiveArrayOffset specializations for
254// safe_enum and wchar_t
255
256struct StringOffsetHelper;
257
264public:
265 typedef variable_size_type_tag_t offset_kind;
266 typedef StringOffsetHelper Helper;
267
269 {
270 }
271
273 SampleBase *sample,
274 offset_t absolute_offset,
275 offset_t serialized_size)
277 sample,
278 absolute_offset,
279 serialized_size)
280 {
281 }
282
288 char * get_string()
289 {
290 return reinterpret_cast<char*>(this->get_buffer());
291 }
292
297 const char * get_string() const
298 {
299 return reinterpret_cast<const char*>(this->get_buffer());
300 }
301
307 unsigned int element_count() const
308 {
309 RTI_FLAT_CHECK_PRECONDITION(
311 return 0);
312
314 }
315};
316
317struct StringOffsetHelper {
318 static offset_t calculate_serialized_size(
319 rti::flat::SampleBase *sample,
320 offset_t absolute_offset,
321 offset_t max_size)
322 {
323 StringOffset tmp(sample, absolute_offset, max_size);
324 return tmp.element_count()
325 + 1 // null terminator
326 + (unsigned int) sizeof(rti::xcdr::length_t); // length header
327 }
328};
329
330// Wide strings are treated as a sequence of octets
331typedef PrimitiveSequenceOffset<unsigned char> WStringOffset;
332
333// The base class of SequenceOffset, and FinalAlignedArrayOffset
334//
335// This encapsulates the functionality that allows iterating through a list
336// of elements (a sequence or an array). The list must be always aligned to 4
337// (that excludes FinalArrayOffset)
338//
345template <typename ElementOffset>
347public:
348
354
355protected:
357 {
358 }
359
361 rti::flat::SampleBase *sample,
362 offset_t offset,
363 offset_t sequence_size)
364 : OffsetBase(
365 sample,
366 offset,
367 sequence_size)
368 {
369 }
370
371public:
372 bool is_cpp_compatible() const // override
373 {
374 RTI_FLAT_OFFSET_CHECK_NOT_NULL(return false);
375 return !stream_.needs_byte_swap()
376 && rti::xcdr::has_cpp_friendly_cdr_layout_collection<
378 }
379
380 ElementOffset get_element(unsigned int i)
381 {
382 RTI_FLAT_OFFSET_CHECK_NOT_NULL(return ElementOffset());
383
384 return get_element_impl<ElementOffset>(
385 i,
386 typename ElementOffset::offset_kind());
387 }
388
402 {
403 RTI_FLAT_OFFSET_CHECK_NOT_NULL(return iterator(NULL, 0, 0));
404
405 return iterator(
406 sample_,
407 absolute_offset_,
408 absolute_offset_ + get_buffer_size());
409 }
410
415 {
416 RTI_FLAT_OFFSET_CHECK_NOT_NULL(return iterator(NULL, 0, 0));
417
418 return iterator(
419 sample_,
420 absolute_offset_ + get_buffer_size(),
421 absolute_offset_ + get_buffer_size());
422 }
423
424private:
425 // for variable size types we skip element by element
426 template <typename E>
427 E get_element_impl(unsigned int i, variable_size_type_tag_t)
428 {
429 iterator it = begin();
430 while (it != end() && i > 0) {
431 if (!it.advance()) {
432 return E();
433 }
434 i--;
435 }
436
437 return *it;
438 }
439
440 // for fixed-size types we support random access
441 template <typename E>
442 E get_element_impl(unsigned int i, fixed_size_type_tag_t)
443 {
444 offset_t size = i * E::serialized_size_w_padding();
445
446 // Ensure that the stream has space for i + 1 elements
447 if (!stream_.check_size(size + E::serialized_size(0))) {
448 return E();
449 }
450
451 return E(this->sample_, this->absolute_offset_ + size);
452 }
453};
454
455template <typename ElementOffset>
456struct SequenceOffsetHelper;
457
472template <typename ElementOffset>
473class SequenceOffset : public AbstractAlignedList<ElementOffset> {
474public:
475 typedef variable_size_type_tag_t offset_kind;
476 typedef SequenceOffsetHelper<ElementOffset> Helper;
477
478 SequenceOffset() : element_count_(0)
479 {
480 }
481
483 rti::flat::SampleBase *sample,
484 offset_t offset,
485 offset_t sequence_size)
487 // Member size in bytes must be > 4, otherwise let base ctor fail
488 sequence_size >= sizeof(rti::xcdr::length_t) ? sample: NULL,
489 // The offset begins after any padding to align to 4; padding
490 // may be needed for example for an array of sequence of final
491 // types; the end position of the previous sequence may not be
492 // aligned
493 RTIXCdrAlignment_alignSizeUp(offset, RTI_XCDR_SEQ_LENGTH_ALIGNMENT)
494 + static_cast<offset_t>(sizeof(rti::xcdr::length_t)),
495 sequence_size - static_cast<offset_t>(sizeof(rti::xcdr::length_t))),
496 element_count_(0)
497 {
498#ifdef RTI_FLAT_DATA_NO_EXCEPTIONS
499 if (!this->is_null()) { // without exceptions, we need to check if the base ctor failed
500#endif
501 rti::xcdr::Stream::Memento stream_memento(this->stream_);
502 this->stream_.skip_back(sizeof(rti::xcdr::length_t));
503 element_count_ = this->stream_.template deserialize_fast<rti::xcdr::length_t>();
504#ifdef RTI_FLAT_DATA_NO_EXCEPTIONS
505 }
506#endif
507 }
508
515 ElementOffset get_element(unsigned int i)
516 {
517 RTI_FLAT_OFFSET_CHECK_NOT_NULL(return ElementOffset());
518
519 if (i >= element_count_) {
520 return ElementOffset();
521 }
523 }
524
528 unsigned int element_count() const
529 {
530 RTI_FLAT_OFFSET_CHECK_NOT_NULL(return 0);
531
532 return element_count_;
533 }
534
535private:
536 unsigned int element_count_;
537};
538
539template <typename E>
540struct SequenceOffsetHelper {
541 // Calculates the serialized size of a Sequence by skipping each element
542 static offset_t calculate_serialized_size(
543 rti::flat::SampleBase *sample,
544 offset_t absolute_offset,
545 offset_t max_offset)
546 {
547 // Create a SequenceOffset beginning at sample + absolute_offset,
548 // with a size we don't know, but no greater than
549 // max_offset - absolute_offset
550 SequenceOffset<E> tmp(
551 sample,
552 absolute_offset,
553 max_offset - absolute_offset);
554 unsigned int count = tmp.element_count();
555 typename SequenceOffset<E>::iterator it = tmp.begin();
556 for (unsigned int i = 0; i < count; i++) {
557 if (!it.advance()) {
558 return 0; // error
559 }
560 }
561
562 return detail::ptrdiff(it.get_position(), sample->get_buffer())
563 - absolute_offset;
564 }
565};
566
581template <typename ElementOffset, unsigned int N>
582class MutableArrayOffset : public AbstractAlignedList<ElementOffset> {
583public:
584 typedef variable_size_type_tag_t offset_kind;
585
587 {
588 }
589
591 rti::flat::SampleBase *sample,
592 offset_t offset,
593 offset_t sequence_size)
595 sample,
596 offset,
597 sequence_size)
598 {
599 }
600
607 ElementOffset get_element(unsigned int i)
608 {
609 if (i >= N) {
610 return ElementOffset();
611 }
612
614 }
615};
616
636template <typename ElementOffset, unsigned int N>
638public:
639 typedef fixed_size_type_tag_t offset_kind;
640
642 {
643 }
644
645 // Constructor used when this array is part of a fixed-size type, and
646 // therefore it's initial alignment is not known ahead of time
648 rti::flat::SampleBase *sample,
649 offset_t absolute_offset,
650 offset_t first_element_size,
651 offset_t element_size)
652 : OffsetBase(
653 sample,
654 absolute_offset,
655 first_element_size + element_size * (N - 1)),
656 first_element_size_(first_element_size),
657 element_size_(element_size)
658 {
659 }
660
667 ElementOffset get_element(unsigned int i)
668 {
669 RTI_FLAT_OFFSET_CHECK_NOT_NULL(return ElementOffset());
670
671 if (i >= N) {
672 return ElementOffset(); // null offset
673 }
674
675 offset_t element_offset = this->absolute_offset_;
676 if (i > 0) {
677 element_offset += this->first_element_size_
678 + (i - 1) * this->element_size_;
679 }
680
681 return ElementOffset(this->sample_, element_offset);
682 }
683
684private:
685 offset_t first_element_size_;
686 offset_t element_size_;
687};
688
729template <typename ElementOffset, unsigned int N>
730class FinalAlignedArrayOffset : public AbstractAlignedList<ElementOffset> {
731public:
732 typedef fixed_size_type_tag_t offset_kind;
733
735 {
736 }
737
738 // Constructor used when this array is part of a mutable type, and
739 // therefore it's aligned to 4 always
741 rti::flat::SampleBase *sample,
742 offset_t absolute_offset)
744 sample,
745 absolute_offset,
746 serialized_size(0))
747 {
748 }
749
750 // serialized_size() only works when this array is part of a mutable type
751 // and we know it's aligned to 4
752 static offset_t serialized_size(offset_t)
753 {
754 // [element1][pad][element2][pad]...[elementN]
755 return ElementOffset::serialized_size_w_padding() * (N - 1)
756 + ElementOffset::serialized_size(0);
757 }
758
768 ElementOffset get_element(unsigned int i)
769 {
770 RTI_FLAT_OFFSET_CHECK_NOT_NULL(return ElementOffset());
771
772 if (i >= N) {
773 return ElementOffset();
774 }
775
777 }
778};
779
780} }
781
782#endif // RTI_DDS_FLAT_SEQUENCEOFFSETS_HPP_
783
Base class of Offsets to sequences and arrays of non-primitive members.
Definition: SequenceOffsets.hpp:346
iterator end()
Gets an iterator to the past-the-end element.
Definition: SequenceOffsets.hpp:414
iterator begin()
Gets an iterator to the first Offset.
Definition: SequenceOffsets.hpp:401
SequenceIterator< ElementOffset, typename ElementOffset::offset_kind > iterator
The iterator type, SequenceIterator.
Definition: SequenceOffsets.hpp:353
Base class for Offsets to sequences and arrays of primitive types.
Definition: SequenceOffsets.hpp:27
bool set_element(unsigned int i, T value)
Sets an element by index.
Definition: SequenceOffsets.hpp:111
T get_element(unsigned int i) const
Returns an element by index.
Definition: SequenceOffsets.hpp:88
Offset to an array of final elements.
Definition: SequenceOffsets.hpp:730
ElementOffset get_element(unsigned int i)
Gets the Offset to an element.
Definition: SequenceOffsets.hpp:768
Offset to an array of final elements.
Definition: SequenceOffsets.hpp:637
ElementOffset get_element(unsigned int i)
Gets the Offset to an element.
Definition: SequenceOffsets.hpp:667
Offset to an array of variable-size elements.
Definition: SequenceOffsets.hpp:582
ElementOffset get_element(unsigned int i)
Gets the Offset to an element.
Definition: SequenceOffsets.hpp:607
Base class of all Offset types.
Definition: Offset.hpp:489
bool is_null() const
Indicates whether this Offset doesn't point to a valid element.
Definition: Offset.hpp:509
const unsigned char * get_buffer() const
Gets this member's position in the buffer.
Definition: Offset.hpp:554
offset_t get_buffer_size() const
Gets the size, in bytes, of this member in the buffer.
Definition: Offset.hpp:568
Offset to an array of primitive elements.
Definition: SequenceOffsets.hpp:220
unsigned int element_count() const
Returns the number of elements, N.
Definition: SequenceOffsets.hpp:242
Offset to a sequence of primitive elements.
Definition: SequenceOffsets.hpp:134
unsigned int element_count() const
Returns the number of elements.
Definition: SequenceOffsets.hpp:169
Iterator for collections of Offsets.
Definition: SequenceIterator.hpp:44
Offset to a sequence of non-primitive elements.
Definition: SequenceOffsets.hpp:473
ElementOffset get_element(unsigned int i)
Gets the Offset to an element.
Definition: SequenceOffsets.hpp:515
unsigned int element_count() const
The number of elements.
Definition: SequenceOffsets.hpp:528
Offset to a string.
Definition: SequenceOffsets.hpp:263
char * get_string()
Gets the string.
Definition: SequenceOffsets.hpp:288
unsigned int element_count() const
Returns the number of characters.
Definition: SequenceOffsets.hpp:307
const char * get_string() const
Gets the string (const)
Definition: SequenceOffsets.hpp:297
The RTI namespace.
Definition: AggregationBuilders.hpp:17
Given a Sample, an Offset or a Builder, it allows obtaining the other types.
Definition: FlatSample.hpp:340