RTI Connext Traditional C++ API Version 7.3.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
123namespace detail {
124
125template <typename T>
126struct PrimitiveSequenceOffsetHelper;
127
128template <typename T, typename Enable = void>
129struct primitive_sequence_header_length {
130 static size_t value()
131 {
132 return sizeof(rti::xcdr::length_t);
133 }
134};
135
136} // namespace detail
137
145template <typename T>
147public:
148 typedef variable_size_type_tag_t offset_kind;
149 typedef detail::PrimitiveSequenceOffsetHelper<T> Helper;
150
151 PrimitiveSequenceOffset() : element_count_(0)
152 {
153 }
154
156 rti::flat::SampleBase *sample,
157 offset_t offset,
158 offset_t serialized_size)
160 // passing NULL causes the base constructors to fail
161 serialized_size >= static_cast<offset_t>(header_length()) ? sample : NULL,
162 offset + static_cast<offset_t>(header_length()),
163 serialized_size - static_cast<offset_t>(header_length())),
164 element_count_(0)
165 {
166#ifdef RTI_FLAT_DATA_NO_EXCEPTIONS
167 if (!this->is_null()) { // without exceptions, we need to check if the base ctor failed
168#endif
169 rti::xcdr::Stream::Memento stream_memento(this->stream_);
170 this->stream_.skip_back(sizeof(rti::xcdr::length_t));
171 element_count_ = this->stream_.template deserialize_fast<rti::xcdr::length_t>();
172#ifdef RTI_FLAT_DATA_NO_EXCEPTIONS
173 }
174#endif
175
176 }
177
181 unsigned int element_count() const
182 {
183 RTI_FLAT_OFFSET_CHECK_NOT_NULL(return 0);
184
185 return element_count_;
186 }
187
188private:
189 static size_t header_length()
190 {
191 return detail::primitive_sequence_header_length<T>::value();
192 }
193
194 unsigned int element_count_;
195
196};
197
198namespace detail {
199
200template <typename T>
201struct PrimitiveSequenceOffsetHelper {
202 static offset_t calculate_serialized_size(
203 rti::flat::SampleBase *sample,
204 offset_t absolute_offset,
205 offset_t max_size)
206 {
207 RTI_FLAT_ASSERT(sample != NULL, return 0);
208 RTI_FLAT_ASSERT(max_size > sizeof(rti::xcdr::length_t), return 0);
209
210 PrimitiveSequenceOffset<T> tmp(sample, absolute_offset, max_size);
211
212 // elements + header
213 if ((RTIXCdrUnsignedLong_MAX
214 - static_cast<unsigned int>(sizeof(rti::xcdr::length_t)))
215 / static_cast<unsigned int>(sizeof(T))
216 < tmp.element_count()) {
217 RTI_FLAT_OFFSET_PRECONDITION_ERROR(
218 "Serialized size of a sequence of primitive elements "
219 "exceeds maximum representable 32-bit unsigned integer.",
220 return 0);
221 }
222 return (tmp.element_count() * static_cast<unsigned int>(sizeof(T)))
223 + static_cast<unsigned int>(sizeof(rti::xcdr::length_t));
224 }
225};
226
227} // namespace detail
228
240template <typename T, unsigned int N>
242public:
243 typedef fixed_size_type_tag_t offset_kind;
244
246 {
247 }
248
249 PrimitiveArrayOffset(rti::flat::SampleBase *sample, offset_t offset)
251 sample,
252 offset + static_cast<offset_t>(header_length()),
253 serialized_size(0))
254 {
255 }
256
257public:
258
263 unsigned int element_count() const
264 {
265 return N;
266 }
267
268 static offset_t serialized_size(offset_t)
269 {
270 return sizeof(T) * N;
271 }
272
273private:
274 static size_t header_length()
275 {
276 return detail::primitive_sequence_header_length<T>::value()
277 - sizeof(rti::xcdr::length_t);
278 }
279};
280
281// Note: the modern C++ API defines a PrimitiveArrayOffset specializations for
282// safe_enum and wchar_t
283
284struct StringOffsetHelper;
285
292public:
293 typedef variable_size_type_tag_t offset_kind;
294 typedef StringOffsetHelper Helper;
295
297 {
298 }
299
301 SampleBase *sample,
302 offset_t absolute_offset,
303 offset_t serialized_size)
305 sample,
306 absolute_offset,
307 serialized_size)
308 {
309 }
310
316 char * get_string()
317 {
318 return reinterpret_cast<char*>(this->get_buffer());
319 }
320
325 const char * get_string() const
326 {
327 return reinterpret_cast<const char*>(this->get_buffer());
328 }
329
335 unsigned int element_count() const
336 {
337 RTI_FLAT_CHECK_PRECONDITION(
339 return 0);
340
342 }
343};
344
345struct StringOffsetHelper {
346 static offset_t calculate_serialized_size(
347 rti::flat::SampleBase *sample,
348 offset_t absolute_offset,
349 offset_t max_size)
350 {
351 StringOffset tmp(sample, absolute_offset, max_size);
352 return tmp.element_count()
353 + 1 // null terminator
354 + (unsigned int) sizeof(rti::xcdr::length_t); // length header
355 }
356};
357
358// Wide strings are treated as a sequence of octets
359typedef PrimitiveSequenceOffset<unsigned char> WStringOffset;
360
361// The base class of SequenceOffset, and FinalAlignedArrayOffset
362//
363// This encapsulates the functionality that allows iterating through a list
364// of elements (a sequence or an array). The list must be always aligned to 4
365// (that excludes FinalArrayOffset)
366//
373template <typename ElementOffset>
375public:
376
382
383protected:
385 {
386 }
387
389 rti::flat::SampleBase *sample,
390 offset_t offset,
391 offset_t sequence_size)
392 : OffsetBase(
393 sample,
394 offset,
395 sequence_size)
396 {
397 }
398
399public:
400 bool is_cpp_compatible() const // override
401 {
402 RTI_FLAT_OFFSET_CHECK_NOT_NULL(return false);
403 return !stream_.needs_byte_swap()
404 && rti::xcdr::has_cpp_friendly_cdr_layout_collection<
406 }
407
408 ElementOffset get_element(unsigned int i)
409 {
410 RTI_FLAT_OFFSET_CHECK_NOT_NULL(return ElementOffset());
411
412 return get_element_impl<ElementOffset>(
413 i,
414 typename ElementOffset::offset_kind());
415 }
416
430 {
431 RTI_FLAT_OFFSET_CHECK_NOT_NULL(return iterator(NULL, 0, 0));
432
433 return iterator(
434 sample_,
435 absolute_offset_,
436 absolute_offset_ + get_buffer_size());
437 }
438
443 {
444 RTI_FLAT_OFFSET_CHECK_NOT_NULL(return iterator(NULL, 0, 0));
445
446 return iterator(
447 sample_,
448 absolute_offset_ + get_buffer_size(),
449 absolute_offset_ + get_buffer_size());
450 }
451
452private:
453 // for variable size types we skip element by element
454 template <typename E>
455 E get_element_impl(unsigned int i, variable_size_type_tag_t)
456 {
457 iterator it = begin();
458 while (it != end() && i > 0) {
459 if (!it.advance()) {
460 return E();
461 }
462 i--;
463 }
464
465 return *it;
466 }
467
468 // for fixed-size types we support random access
469 template <typename E>
470 E get_element_impl(unsigned int i, fixed_size_type_tag_t)
471 {
472 offset_t size = i * E::serialized_size_w_padding();
473
474 // Ensure that the stream has space for i + 1 elements
475 if (!stream_.check_size(size + E::serialized_size(0))) {
476 return E();
477 }
478
479 return E(this->sample_, this->absolute_offset_ + size);
480 }
481};
482
483template <typename ElementOffset>
484struct SequenceOffsetHelper;
485
500template <typename ElementOffset>
501class SequenceOffset : public AbstractAlignedList<ElementOffset> {
502public:
503 typedef variable_size_type_tag_t offset_kind;
504 typedef SequenceOffsetHelper<ElementOffset> Helper;
505
506 SequenceOffset() : element_count_(0)
507 {
508 }
509
511 rti::flat::SampleBase *sample,
512 offset_t offset,
513 offset_t sequence_size)
515 // Member size in bytes must be > 4, otherwise let base ctor
516 // fail
517 sequence_size >= header_length() ? sample : NULL,
518 // The offset begins after any padding to align to 4;
519 // padding may be needed for example for an array of
520 // sequence of final types; the end position of the previous
521 // sequence may not be aligned
522 RTIXCdrAlignment_alignSizeUp(
523 offset,
524 RTI_XCDR_SEQ_LENGTH_ALIGNMENT)
525 + header_length(),
526 sequence_size - header_length()),
527 element_count_(0)
528 {
529#ifdef RTI_FLAT_DATA_NO_EXCEPTIONS
530 if (!this->is_null()) { // without exceptions, we need to check if the base ctor failed
531#endif
532 rti::xcdr::Stream::Memento stream_memento(this->stream_);
533 this->stream_.skip_back(sizeof(rti::xcdr::length_t));
534 element_count_ = this->stream_.template deserialize_fast<rti::xcdr::length_t>();
535#ifdef RTI_FLAT_DATA_NO_EXCEPTIONS
536 }
537#endif
538 }
539
546 ElementOffset get_element(unsigned int i)
547 {
548 RTI_FLAT_OFFSET_CHECK_NOT_NULL(return ElementOffset());
549
550 if (i >= element_count_) {
551 return ElementOffset();
552 }
554 }
555
559 unsigned int element_count() const
560 {
561 RTI_FLAT_OFFSET_CHECK_NOT_NULL(return 0);
562
563 return element_count_;
564 }
565
566private:
567 static offset_t header_length()
568 {
569 return static_cast<offset_t>(
570 detail::collection_dheader_traits<false>::dheader_size()
571 + sizeof(rti::xcdr::length_t));
572 }
573
574
575 unsigned int element_count_;
576};
577
578template <typename E>
579struct SequenceOffsetHelper {
580 // Calculates the serialized size of a Sequence by skipping each element
581 static offset_t calculate_serialized_size(
582 rti::flat::SampleBase *sample,
583 offset_t absolute_offset,
584 offset_t max_offset)
585 {
586 // Create a SequenceOffset beginning at sample + absolute_offset,
587 // with a size we don't know, but no greater than
588 // max_offset - absolute_offset
589 SequenceOffset<E> tmp(
590 sample,
591 absolute_offset,
592 max_offset - absolute_offset);
593 unsigned int count = tmp.element_count();
594 typename SequenceOffset<E>::iterator it = tmp.begin();
595 for (unsigned int i = 0; i < count; i++) {
596 if (!it.advance()) {
597 return 0; // error
598 }
599 }
600
601 return detail::ptrdiff(it.get_position(), sample->get_buffer())
602 - absolute_offset;
603 }
604};
605
620template <typename ElementOffset, unsigned int N>
621class MutableArrayOffset : public AbstractAlignedList<ElementOffset> {
622public:
623 typedef variable_size_type_tag_t offset_kind;
624
626 {
627 }
628
630 rti::flat::SampleBase *sample,
631 offset_t offset,
632 offset_t sequence_size)
634 sequence_size >= header_length() ? sample : NULL,
635 offset + header_length(),
636 sequence_size - header_length())
637 {
638 }
639
646 ElementOffset get_element(unsigned int i)
647 {
648 if (i >= N) {
649 return ElementOffset();
650 }
651
653 }
654
655private:
656 static offset_t header_length()
657 {
658 return static_cast<offset_t>(
659 detail::collection_dheader_traits<false>::dheader_size());
660 }
661};
662
682template <typename ElementOffset, unsigned int N>
684public:
685 typedef fixed_size_type_tag_t offset_kind;
686
688 {
689 }
690
691 // Constructor used when this array is part of a fixed-size type, and
692 // therefore it's initial alignment is not known ahead of time
694 rti::flat::SampleBase *sample,
695 offset_t absolute_offset,
696 offset_t first_element_size,
697 offset_t element_size)
698 : OffsetBase(
699 sample,
700 absolute_offset,
701 first_element_size + element_size * (N - 1)),
702 first_element_size_(first_element_size),
703 element_size_(element_size)
704 {
705 }
706
713 ElementOffset get_element(unsigned int i)
714 {
715 RTI_FLAT_OFFSET_CHECK_NOT_NULL(return ElementOffset());
716
717 if (i >= N) {
718 return ElementOffset(); // null offset
719 }
720
721 offset_t element_offset = this->absolute_offset_;
722 if (i > 0) {
723 element_offset += this->first_element_size_
724 + (i - 1) * this->element_size_;
725 }
726
727 return ElementOffset(this->sample_, element_offset);
728 }
729
730private:
731 offset_t first_element_size_;
732 offset_t element_size_;
733};
734
775template <typename ElementOffset, unsigned int N>
776class FinalAlignedArrayOffset : public AbstractAlignedList<ElementOffset> {
777public:
778 typedef fixed_size_type_tag_t offset_kind;
779
781 {
782 }
783
784 // Constructor used when this array is part of a mutable type, and
785 // therefore it's aligned to 4 always
787 rti::flat::SampleBase *sample,
788 offset_t absolute_offset)
790 sample,
791 absolute_offset
792 + detail::collection_dheader_traits<
793 false>::dheader_size(),
794 serialized_size(0))
795 { }
796
797 // serialized_size() only works when this array is part of a mutable type
798 // and we know it's aligned to 4
799 static offset_t serialized_size(offset_t)
800 {
801 // [element1][pad][element2][pad]...[elementN]
802 return ElementOffset::serialized_size_w_padding() * (N - 1)
803 + ElementOffset::serialized_size(0);
804 }
805
815 ElementOffset get_element(unsigned int i)
816 {
817 RTI_FLAT_OFFSET_CHECK_NOT_NULL(return ElementOffset());
818
819 if (i >= N) {
820 return ElementOffset();
821 }
822
824 }
825};
826
827namespace detail {
828
829// Arrays of complex elements may need a DHEADER
830template <typename T, unsigned int N>
831struct is_fixed_type_w_dheader<FinalAlignedArrayOffset<T, N> > {
832 static bool value()
833 {
834 return is_dheader_required_in_non_primitive_collections();
835 }
836};
837
838
839} // namespace detail
840
841}} // namespace rti::flat
842
843#endif // RTI_DDS_FLAT_SEQUENCEOFFSETS_HPP_
844
Base class of Offsets to sequences and arrays of non-primitive members.
Definition: SequenceOffsets.hpp:374
iterator end()
Gets an iterator to the past-the-end element.
Definition: SequenceOffsets.hpp:442
iterator begin()
Gets an iterator to the first Offset.
Definition: SequenceOffsets.hpp:429
SequenceIterator< ElementOffset, typename ElementOffset::offset_kind > iterator
The iterator type, SequenceIterator.
Definition: SequenceOffsets.hpp:381
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:776
ElementOffset get_element(unsigned int i)
Gets the Offset to an element.
Definition: SequenceOffsets.hpp:815
Offset to an array of final elements.
Definition: SequenceOffsets.hpp:683
ElementOffset get_element(unsigned int i)
Gets the Offset to an element.
Definition: SequenceOffsets.hpp:713
Offset to an array of variable-size elements.
Definition: SequenceOffsets.hpp:621
ElementOffset get_element(unsigned int i)
Gets the Offset to an element.
Definition: SequenceOffsets.hpp:646
Base class of all Offset types.
Definition: Offset.hpp:562
bool is_null() const
Indicates whether this Offset doesn't point to a valid element.
Definition: Offset.hpp:582
const unsigned char * get_buffer() const
Gets this member's position in the buffer.
Definition: Offset.hpp:627
offset_t get_buffer_size() const
Gets the size, in bytes, of this member in the buffer.
Definition: Offset.hpp:641
Offset to an array of primitive elements.
Definition: SequenceOffsets.hpp:241
unsigned int element_count() const
Returns the number of elements, N.
Definition: SequenceOffsets.hpp:263
Offset to a sequence of primitive elements.
Definition: SequenceOffsets.hpp:146
unsigned int element_count() const
Returns the number of elements.
Definition: SequenceOffsets.hpp:181
Iterator for collections of Offsets.
Definition: SequenceIterator.hpp:44
Offset to a sequence of non-primitive elements.
Definition: SequenceOffsets.hpp:501
ElementOffset get_element(unsigned int i)
Gets the Offset to an element.
Definition: SequenceOffsets.hpp:546
unsigned int element_count() const
The number of elements.
Definition: SequenceOffsets.hpp:559
Offset to a string.
Definition: SequenceOffsets.hpp:291
char * get_string()
Gets the string.
Definition: SequenceOffsets.hpp:316
unsigned int element_count() const
Returns the number of characters.
Definition: SequenceOffsets.hpp:335
const char * get_string() const
Gets the string (const)
Definition: SequenceOffsets.hpp:325
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