RTI Connext Traditional C++ API Version 7.1.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_ASSERT(PrimitiveSequenceOffset<char>::element_count() > 0, return 0);
310
312 }
313};
314
315struct StringOffsetHelper {
316 static offset_t calculate_serialized_size(
317 rti::flat::SampleBase *sample,
318 offset_t absolute_offset,
319 offset_t max_size)
320 {
321 StringOffset tmp(sample, absolute_offset, max_size);
322 return tmp.element_count()
323 + 1 // null terminator
324 + (unsigned int) sizeof(rti::xcdr::length_t); // length header
325 }
326};
327
328// Wide strings are treated as a sequence of octets
329typedef PrimitiveSequenceOffset<unsigned char> WStringOffset;
330
331// The base class of SequenceOffset, and FinalAlignedArrayOffset
332//
333// This encapsulates the functionality that allows iterating through a list
334// of elements (a sequence or an array). The list must be always aligned to 4
335// (that excludes FinalArrayOffset)
336//
343template <typename ElementOffset>
345public:
346
352
353protected:
355 {
356 }
357
359 rti::flat::SampleBase *sample,
360 offset_t offset,
361 offset_t sequence_size)
362 : OffsetBase(
363 sample,
364 offset,
365 sequence_size)
366 {
367 }
368
369public:
370 bool is_cpp_compatible() const // override
371 {
372 RTI_FLAT_OFFSET_CHECK_NOT_NULL(return false);
373 return !stream_.needs_byte_swap()
374 && rti::xcdr::has_cpp_friendly_cdr_layout_collection<
376 }
377
378 ElementOffset get_element(unsigned int i)
379 {
380 RTI_FLAT_OFFSET_CHECK_NOT_NULL(return ElementOffset());
381
382 return get_element_impl<ElementOffset>(
383 i,
384 typename ElementOffset::offset_kind());
385 }
386
400 {
401 RTI_FLAT_OFFSET_CHECK_NOT_NULL(return iterator(NULL, 0, 0));
402
403 return iterator(
404 sample_,
405 absolute_offset_,
406 absolute_offset_ + get_buffer_size());
407 }
408
413 {
414 RTI_FLAT_OFFSET_CHECK_NOT_NULL(return iterator(NULL, 0, 0));
415
416 return iterator(
417 sample_,
418 absolute_offset_ + get_buffer_size(),
419 absolute_offset_ + get_buffer_size());
420 }
421
422private:
423 // for variable size types we skip element by element
424 template <typename E>
425 E get_element_impl(unsigned int i, variable_size_type_tag_t)
426 {
427 iterator it = begin();
428 while (it != end() && i > 0) {
429 if (!it.advance()) {
430 return E();
431 }
432 i--;
433 }
434
435 return *it;
436 }
437
438 // for fixed-size types we support random access
439 template <typename E>
440 E get_element_impl(unsigned int i, fixed_size_type_tag_t)
441 {
442 offset_t size = i * E::serialized_size_w_padding();
443
444 // Ensure that the stream has space for i + 1 elements
445 if (!stream_.check_size(size + E::serialized_size(0))) {
446 return E();
447 }
448
449 return E(this->sample_, this->absolute_offset_ + size);
450 }
451};
452
453template <typename ElementOffset>
454struct SequenceOffsetHelper;
455
470template <typename ElementOffset>
471class SequenceOffset : public AbstractAlignedList<ElementOffset> {
472public:
473 typedef variable_size_type_tag_t offset_kind;
474 typedef SequenceOffsetHelper<ElementOffset> Helper;
475
476 SequenceOffset() : element_count_(0)
477 {
478 }
479
481 rti::flat::SampleBase *sample,
482 offset_t offset,
483 offset_t sequence_size)
485 // Member size in bytes must be > 4, otherwise let base ctor fail
486 sequence_size >= sizeof(rti::xcdr::length_t) ? sample: NULL,
487 // The offset begins after any padding to align to 4; padding
488 // may be needed for example for an array of sequence of final
489 // types; the end position of the previous sequence may not be
490 // aligned
491 RTIXCdrAlignment_alignSizeUp(offset, RTI_XCDR_SEQ_LENGTH_ALIGNMENT)
492 + static_cast<offset_t>(sizeof(rti::xcdr::length_t)),
493 sequence_size - static_cast<offset_t>(sizeof(rti::xcdr::length_t))),
494 element_count_(0)
495 {
496#ifdef RTI_FLAT_DATA_NO_EXCEPTIONS
497 if (!this->is_null()) { // without exceptions, we need to check if the base ctor failed
498#endif
499 rti::xcdr::Stream::Memento stream_memento(this->stream_);
500 this->stream_.skip_back(sizeof(rti::xcdr::length_t));
501 element_count_ = this->stream_.template deserialize_fast<rti::xcdr::length_t>();
502#ifdef RTI_FLAT_DATA_NO_EXCEPTIONS
503 }
504#endif
505 }
506
513 ElementOffset get_element(unsigned int i)
514 {
515 RTI_FLAT_OFFSET_CHECK_NOT_NULL(return ElementOffset());
516
517 if (i >= element_count_) {
518 return ElementOffset();
519 }
521 }
522
526 unsigned int element_count() const
527 {
528 RTI_FLAT_OFFSET_CHECK_NOT_NULL(return 0);
529
530 return element_count_;
531 }
532
533private:
534 unsigned int element_count_;
535};
536
537template <typename E>
538struct SequenceOffsetHelper {
539 // Calculates the serialized size of a Sequence by skipping each element
540 static offset_t calculate_serialized_size(
541 rti::flat::SampleBase *sample,
542 offset_t absolute_offset,
543 offset_t max_offset)
544 {
545 // Create a SequenceOffset beginning at sample + absolute_offset,
546 // with a size we don't know, but no greater than
547 // max_offset - absolute_offset
548 SequenceOffset<E> tmp(
549 sample,
550 absolute_offset,
551 max_offset - absolute_offset);
552 unsigned int count = tmp.element_count();
553 typename SequenceOffset<E>::iterator it = tmp.begin();
554 for (unsigned int i = 0; i < count; i++) {
555 if (!it.advance()) {
556 return 0; // error
557 }
558 }
559
560 return detail::ptrdiff(it.get_position(), sample->get_buffer())
561 - absolute_offset;
562 }
563};
564
579template <typename ElementOffset, unsigned int N>
580class MutableArrayOffset : public AbstractAlignedList<ElementOffset> {
581public:
582 typedef variable_size_type_tag_t offset_kind;
583
585 {
586 }
587
589 rti::flat::SampleBase *sample,
590 offset_t offset,
591 offset_t sequence_size)
593 sample,
594 offset,
595 sequence_size)
596 {
597 }
598
605 ElementOffset get_element(unsigned int i)
606 {
607 if (i >= N) {
608 return ElementOffset();
609 }
610
612 }
613};
614
634template <typename ElementOffset, unsigned int N>
636public:
637 typedef fixed_size_type_tag_t offset_kind;
638
640 {
641 }
642
643 // Constructor used when this array is part of a fixed-size type, and
644 // therefore it's initial alignment is not known ahead of time
646 rti::flat::SampleBase *sample,
647 offset_t absolute_offset,
648 offset_t first_element_size,
649 offset_t element_size)
650 : OffsetBase(
651 sample,
652 absolute_offset,
653 first_element_size + element_size * (N - 1)),
654 first_element_size_(first_element_size),
655 element_size_(element_size)
656 {
657 }
658
665 ElementOffset get_element(unsigned int i)
666 {
667 RTI_FLAT_OFFSET_CHECK_NOT_NULL(return ElementOffset());
668
669 if (i >= N) {
670 return ElementOffset(); // null offset
671 }
672
673 offset_t element_offset = this->absolute_offset_;
674 if (i > 0) {
675 element_offset += this->first_element_size_
676 + (i - 1) * this->element_size_;
677 }
678
679 return ElementOffset(this->sample_, element_offset);
680 }
681
682private:
683 offset_t first_element_size_;
684 offset_t element_size_;
685};
686
727template <typename ElementOffset, unsigned int N>
728class FinalAlignedArrayOffset : public AbstractAlignedList<ElementOffset> {
729public:
730 typedef fixed_size_type_tag_t offset_kind;
731
733 {
734 }
735
736 // Constructor used when this array is part of a mutable type, and
737 // therefore it's aligned to 4 always
739 rti::flat::SampleBase *sample,
740 offset_t absolute_offset)
742 sample,
743 absolute_offset,
744 serialized_size(0))
745 {
746 }
747
748 // serialized_size() only works when this array is part of a mutable type
749 // and we know it's aligned to 4
750 static offset_t serialized_size(offset_t)
751 {
752 // [element1][pad][element2][pad]...[elementN]
753 return ElementOffset::serialized_size_w_padding() * (N - 1)
754 + ElementOffset::serialized_size(0);
755 }
756
766 ElementOffset get_element(unsigned int i)
767 {
768 RTI_FLAT_OFFSET_CHECK_NOT_NULL(return ElementOffset());
769
770 if (i >= N) {
771 return ElementOffset();
772 }
773
775 }
776};
777
778} }
779
780#endif // RTI_DDS_FLAT_SEQUENCEOFFSETS_HPP_
781
Base class of Offsets to sequences and arrays of non-primitive members.
Definition: SequenceOffsets.hpp:344
iterator end()
Gets an iterator to the past-the-end element.
Definition: SequenceOffsets.hpp:412
iterator begin()
Gets an iterator to the first Offset.
Definition: SequenceOffsets.hpp:399
SequenceIterator< ElementOffset, typename ElementOffset::offset_kind > iterator
The iterator type, SequenceIterator.
Definition: SequenceOffsets.hpp:351
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:728
ElementOffset get_element(unsigned int i)
Gets the Offset to an element.
Definition: SequenceOffsets.hpp:766
Offset to an array of final elements.
Definition: SequenceOffsets.hpp:635
ElementOffset get_element(unsigned int i)
Gets the Offset to an element.
Definition: SequenceOffsets.hpp:665
Offset to an array of variable-size elements.
Definition: SequenceOffsets.hpp:580
ElementOffset get_element(unsigned int i)
Gets the Offset to an element.
Definition: SequenceOffsets.hpp:605
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:471
ElementOffset get_element(unsigned int i)
Gets the Offset to an element.
Definition: SequenceOffsets.hpp:513
unsigned int element_count() const
The number of elements.
Definition: SequenceOffsets.hpp:526
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