RTI Connext Traditional C++ API  Version 6.1.1
SequenceOffsets.hpp
1 /*
2 (c) Copyright, Real-Time Innovations, 2018.
3 All rights reserved.
4 
5 No duplications, whole or partial, manual or electronic, may be made
6 without express written permission. Any such copies, or
7 revisions thereof, must display this notice unaltered.
8 This 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 
17 namespace rti { namespace flat {
18 
26 template <typename T>
28 public:
29  typedef T value_type;
30 
31 protected:
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 
44 public:
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 
123 template <typename T>
124 struct PrimitiveSequenceOffsetHelper;
125 
133 template <typename T>
135 public:
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  {
153 #ifdef RTI_FLAT_DATA_NO_EXCEPTIONS
154  if (!this->is_null()) { // without exceptions, we need to check if the base ctor failed
155 #endif
156  rti::xcdr::Stream::Memento stream_memento(this->stream_);
157  this->stream_.skip_back(sizeof(rti::xcdr::length_t));
158  element_count_ = this->stream_.template deserialize_fast<rti::xcdr::length_t>();
159 #ifdef RTI_FLAT_DATA_NO_EXCEPTIONS
160  }
161 #endif
162 
163  }
164 
168  unsigned int element_count() const
169  {
170  RTI_FLAT_OFFSET_CHECK_NOT_NULL(return 0);
171 
172  return element_count_;
173  }
174 
175 private:
176  unsigned int element_count_;
177 
178 };
179 
180 template <typename T>
181 struct PrimitiveSequenceOffsetHelper {
182  static offset_t calculate_serialized_size(
183  rti::flat::SampleBase *sample,
184  offset_t absolute_offset,
185  offset_t max_size)
186  {
187  RTI_FLAT_ASSERT(sample != NULL, return 0);
188  RTI_FLAT_ASSERT(max_size > sizeof(rti::xcdr::length_t), return 0);
189 
190  PrimitiveSequenceOffset<T> tmp(sample, absolute_offset, max_size);
191  // elements + header
192  return (tmp.element_count() * sizeof(T)) + sizeof(rti::xcdr::length_t);
193  }
194 };
195 
207 template <typename T, unsigned int N>
209 public:
210  typedef fixed_size_type_tag_t offset_kind;
211 
213  {
214  }
215 
216  PrimitiveArrayOffset(rti::flat::SampleBase *sample, offset_t offset)
218  sample,
219  offset,
220  serialized_size(0))
221  {
222  }
223 
224 public:
225 
230  unsigned int element_count() const
231  {
232  return N;
233  }
234 
235  static offset_t serialized_size(offset_t)
236  {
237  return sizeof(T) * N;
238  }
239 };
240 
241 // Note: the modern C++ API defines a PrimitiveArrayOffset specializations for
242 // safe_enum and wchar_t
243 
244 struct StringOffsetHelper;
245 
251 class StringOffset : public PrimitiveSequenceOffset<char> {
252 public:
253  typedef variable_size_type_tag_t offset_kind;
254  typedef StringOffsetHelper Helper;
255 
256  StringOffset()
257  {
258  }
259 
260  StringOffset(
261  SampleBase *sample,
262  offset_t absolute_offset,
263  offset_t serialized_size)
265  sample,
266  absolute_offset,
267  serialized_size)
268  {
269  }
270 
276  char * get_string()
277  {
278  return reinterpret_cast<char*>(this->get_buffer());
279  }
280 
285  const char * get_string() const
286  {
287  return reinterpret_cast<const char*>(this->get_buffer());
288  }
289 
295  unsigned int element_count() const
296  {
297  RTI_FLAT_ASSERT(PrimitiveSequenceOffset<char>::element_count() > 0, return 0);
298 
300  }
301 };
302 
303 struct StringOffsetHelper {
304  static offset_t calculate_serialized_size(
305  rti::flat::SampleBase *sample,
306  offset_t absolute_offset,
307  offset_t max_size)
308  {
309  StringOffset tmp(sample, absolute_offset, max_size);
310  return tmp.element_count()
311  + 1 // null terminator
312  + (unsigned int) sizeof(rti::xcdr::length_t); // length header
313  }
314 };
315 
316 // Wide strings are treated as a sequence of octets
318 
319 // The base class of SequenceOffset, and FinalAlignedArrayOffset
320 //
321 // This encapsulates the functionality that allows iterating through a list
322 // of elements (a sequence or an array). The list must be always aligned to 4
323 // (that excludes FinalArrayOffset)
324 //
331 template <typename ElementOffset>
333 public:
334 
340 
341 protected:
343  {
344  }
345 
347  rti::flat::SampleBase *sample,
348  offset_t offset,
349  offset_t sequence_size)
350  : OffsetBase(
351  sample,
352  offset,
353  sequence_size)
354  {
355  }
356 
357 public:
358  bool is_cpp_compatible() const // override
359  {
360  RTI_FLAT_OFFSET_CHECK_NOT_NULL(return false);
361  return !stream_.needs_byte_swap()
362  && rti::xcdr::has_cpp_friendly_cdr_layout_collection<
364  }
365 
366  ElementOffset get_element(unsigned int i)
367  {
368  RTI_FLAT_OFFSET_CHECK_NOT_NULL(return ElementOffset());
369 
370  return get_element_impl<ElementOffset>(
371  i,
372  typename ElementOffset::offset_kind());
373  }
374 
388  {
389  RTI_FLAT_OFFSET_CHECK_NOT_NULL(return iterator(NULL, 0, 0));
390 
391  return iterator(
392  sample_,
393  absolute_offset_,
394  absolute_offset_ + get_buffer_size());
395  }
396 
401  {
402  RTI_FLAT_OFFSET_CHECK_NOT_NULL(return iterator(NULL, 0, 0));
403 
404  return iterator(
405  sample_,
406  absolute_offset_ + get_buffer_size(),
407  absolute_offset_ + get_buffer_size());
408  }
409 
410 private:
411  // for variable size types we skip element by element
412  template <typename E>
413  E get_element_impl(unsigned int i, variable_size_type_tag_t)
414  {
415  iterator it = begin();
416  while (it != end() && i > 0) {
417  if (!it.advance()) {
418  return E();
419  }
420  i--;
421  }
422 
423  return *it;
424  }
425 
426  // for fixed-size types we support random access
427  template <typename E>
428  E get_element_impl(unsigned int i, fixed_size_type_tag_t)
429  {
430  offset_t size = i * E::serialized_size_w_padding();
431 
432  // Ensure that the stream has space for i + 1 elements
433  if (!stream_.check_size(size + E::serialized_size(0))) {
434  return E();
435  }
436 
437  return E(this->sample_, this->absolute_offset_ + size);
438  }
439 };
440 
441 template <typename ElementOffset>
442 struct SequenceOffsetHelper;
443 
458 template <typename ElementOffset>
459 class SequenceOffset : public AbstractAlignedList<ElementOffset> {
460 public:
461  typedef variable_size_type_tag_t offset_kind;
462  typedef SequenceOffsetHelper<ElementOffset> Helper;
463 
464  SequenceOffset() : element_count_(0)
465  {
466  }
467 
469  rti::flat::SampleBase *sample,
470  offset_t offset,
471  offset_t sequence_size)
473  // Member size in bytes must be > 4, otherwise let base ctor fail
474  sequence_size >= sizeof(rti::xcdr::length_t) ? sample: NULL,
475  // The offset begins after any padding to align to 4; padding
476  // may be needed for example for an array of sequence of final
477  // types; the end position of the previous sequence may not be
478  // aligned
479  RTIXCdrAlignment_alignSizeUp(offset, RTI_XCDR_SEQ_LENGTH_ALIGNMENT)
480  + static_cast<offset_t>(sizeof(rti::xcdr::length_t)),
481  sequence_size - static_cast<offset_t>(sizeof(rti::xcdr::length_t)))
482  {
483 #ifdef RTI_FLAT_DATA_NO_EXCEPTIONS
484  if (!this->is_null()) { // without exceptions, we need to check if the base ctor failed
485 #endif
486  rti::xcdr::Stream::Memento stream_memento(this->stream_);
487  this->stream_.skip_back(sizeof(rti::xcdr::length_t));
488  element_count_ = this->stream_.template deserialize_fast<rti::xcdr::length_t>();
489 #ifdef RTI_FLAT_DATA_NO_EXCEPTIONS
490  }
491 #endif
492  }
493 
500  ElementOffset get_element(unsigned int i)
501  {
502  RTI_FLAT_OFFSET_CHECK_NOT_NULL(return ElementOffset());
503 
504  if (i >= element_count_) {
505  return ElementOffset();
506  }
508  }
509 
513  unsigned int element_count() const
514  {
515  RTI_FLAT_OFFSET_CHECK_NOT_NULL(return 0);
516 
517  return element_count_;
518  }
519 
520 private:
521  unsigned int element_count_;
522 };
523 
524 template <typename E>
525 struct SequenceOffsetHelper {
526  // Calculates the serialized size of a Sequence by skipping each element
527  static offset_t calculate_serialized_size(
528  rti::flat::SampleBase *sample,
529  offset_t absolute_offset,
530  offset_t max_offset)
531  {
532  // Create a SequenceOffset beginning at sample + absolute_offset,
533  // with a size we don't know, but no greater than
534  // max_offset - absolute_offset
535  SequenceOffset<E> tmp(
536  sample,
537  absolute_offset,
538  max_offset - absolute_offset);
539  unsigned int count = tmp.element_count();
540  typename SequenceOffset<E>::iterator it = tmp.begin();
541  for (unsigned int i = 0; i < count; i++) {
542  if (!it.advance()) {
543  return 0; // error
544  }
545  }
546 
547  return detail::ptrdiff(it.get_position(), sample->get_buffer())
548  - absolute_offset;
549  }
550 };
551 
566 template <typename ElementOffset, unsigned int N>
567 class MutableArrayOffset : public AbstractAlignedList<ElementOffset> {
568 public:
569  typedef variable_size_type_tag_t offset_kind;
570 
572  {
573  }
574 
576  rti::flat::SampleBase *sample,
577  offset_t offset,
578  offset_t sequence_size)
580  sample,
581  offset,
582  sequence_size)
583  {
584  }
585 
592  ElementOffset get_element(unsigned int i)
593  {
594  if (i >= N) {
595  return ElementOffset();
596  }
597 
599  }
600 };
601 
621 template <typename ElementOffset, unsigned int N>
622 class FinalArrayOffset : public OffsetBase {
623 public:
624  typedef fixed_size_type_tag_t offset_kind;
625 
627  {
628  }
629 
630  // Constructor used when this array is part of a fixed-size type, and
631  // therefore it's initial alignment is not known ahead of time
633  rti::flat::SampleBase *sample,
634  offset_t absolute_offset,
635  offset_t first_element_size,
636  offset_t element_size)
637  : OffsetBase(
638  sample,
639  absolute_offset,
640  first_element_size + element_size * (N - 1)),
641  first_element_size_(first_element_size),
642  element_size_(element_size)
643  {
644  }
645 
652  ElementOffset get_element(unsigned int i)
653  {
654  RTI_FLAT_OFFSET_CHECK_NOT_NULL(return ElementOffset());
655 
656  if (i >= N) {
657  return ElementOffset(); // null offset
658  }
659 
660  offset_t element_offset = this->absolute_offset_;
661  if (i > 0) {
662  element_offset += this->first_element_size_
663  + (i - 1) * this->element_size_;
664  }
665 
666  return ElementOffset(this->sample_, element_offset);
667  }
668 
669 private:
670  offset_t first_element_size_;
671  offset_t element_size_;
672 };
673 
714 template <typename ElementOffset, unsigned int N>
715 class FinalAlignedArrayOffset : public AbstractAlignedList<ElementOffset> {
716 public:
717  typedef fixed_size_type_tag_t offset_kind;
718 
720  {
721  }
722 
723  // Constructor used when this array is part of a mutable type, and
724  // therefore it's aligned to 4 always
726  rti::flat::SampleBase *sample,
727  offset_t absolute_offset)
729  sample,
730  absolute_offset,
731  serialized_size(0))
732  {
733  }
734 
735  // serialized_size() only works when this array is part of a mutable type
736  // and we know it's aligned to 4
737  static offset_t serialized_size(offset_t)
738  {
739  // [element1][pad][element2][pad]...[elementN]
740  return ElementOffset::serialized_size_w_padding() * (N - 1)
741  + ElementOffset::serialized_size(0);
742  }
743 
753  ElementOffset get_element(unsigned int i)
754  {
755  RTI_FLAT_OFFSET_CHECK_NOT_NULL(return ElementOffset());
756 
757  if (i >= N) {
758  return ElementOffset();
759  }
760 
762  }
763 };
764 
765 } }
766 
767 #endif // RTI_DDS_FLAT_SEQUENCEOFFSETS_HPP_
768 
unsigned int element_count() const
Returns the number of characters.
Definition: SequenceOffsets.hpp:295
Base class of Offsets to sequences and arrays of non-primitive members.
Definition: SequenceOffsets.hpp:332
unsigned int element_count() const
Returns the number of elements, N.
Definition: SequenceOffsets.hpp:230
SequenceIterator< ElementOffset, typename ElementOffset::offset_kind > iterator
The iterator type, SequenceIterator.
Definition: SequenceOffsets.hpp:339
Offset to a sequence of primitive elements.
Definition: SequenceOffsets.hpp:134
const unsigned char * get_buffer() const
Gets this member&#39;s position in the buffer.
Definition: Offset.hpp:554
Given a Sample, an Offset or a Builder, it allows obtaining the other types.
Definition: FlatSample.hpp:340
Offset to an array of primitive elements.
Definition: SequenceOffsets.hpp:208
Offset to an array of variable-size elements.
Definition: SequenceOffsets.hpp:567
Base class of all Offset types.
Definition: Offset.hpp:489
ElementOffset get_element(unsigned int i)
Gets the Offset to an element.
Definition: SequenceOffsets.hpp:753
T get_element(unsigned int i) const
Returns an element by index.
Definition: SequenceOffsets.hpp:88
iterator begin()
Gets an iterator to the first Offset.
Definition: SequenceOffsets.hpp:387
bool set_element(unsigned int i, T value)
Sets an element by index.
Definition: SequenceOffsets.hpp:111
char * get_string()
Gets the string.
Definition: SequenceOffsets.hpp:276
Offset to a string.
Definition: SequenceOffsets.hpp:251
Offset to an array of final elements.
Definition: Offset.hpp:481
bool advance()
Advances to the next element, reporting any errors by returning false.
Definition: SequenceIterator.hpp:132
Offset to an array of final elements.
Definition: SequenceOffsets.hpp:715
bool is_null() const
Indicates whether this Offset doesn&#39;t point to a valid element.
Definition: Offset.hpp:509
const char * get_string() const
Gets the string (const)
Definition: SequenceOffsets.hpp:285
ElementOffset get_element(unsigned int i)
Gets the Offset to an element.
Definition: SequenceOffsets.hpp:500
ElementOffset get_element(unsigned int i)
Gets the Offset to an element.
Definition: SequenceOffsets.hpp:592
offset_t get_buffer_size() const
Gets the size, in bytes, of this member in the buffer.
Definition: Offset.hpp:568
Definition: AggregationBuilders.hpp:17
Base class for Offsets to sequences and arrays of primitive types.
Definition: SequenceOffsets.hpp:27
Iterator for collections of Offsets.
Definition: SequenceIterator.hpp:44
Offset to a sequence of non-primitive elements.
Definition: SequenceOffsets.hpp:459
unsigned int element_count() const
Returns the number of elements.
Definition: SequenceOffsets.hpp:168
unsigned int element_count() const
The number of elements.
Definition: SequenceOffsets.hpp:513
iterator end()
Gets an iterator to the past-the-end element.
Definition: SequenceOffsets.hpp:400
ElementOffset get_element(unsigned int i)
Gets the Offset to an element.
Definition: SequenceOffsets.hpp:652