RTI Connext Traditional C++ API  Version 7.0.0
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  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 
176 private:
177  unsigned int element_count_;
178 
179 };
180 
181 template <typename T>
182 struct 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 
219 template <typename T, unsigned int N>
221 public:
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 
236 public:
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 
256 struct StringOffsetHelper;
257 
263 class StringOffset : public PrimitiveSequenceOffset<char> {
264 public:
265  typedef variable_size_type_tag_t offset_kind;
266  typedef StringOffsetHelper Helper;
267 
268  StringOffset()
269  {
270  }
271 
272  StringOffset(
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 
315 struct 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
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 //
343 template <typename ElementOffset>
345 public:
346 
352 
353 protected:
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 
369 public:
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 
422 private:
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 
453 template <typename ElementOffset>
454 struct SequenceOffsetHelper;
455 
470 template <typename ElementOffset>
471 class SequenceOffset : public AbstractAlignedList<ElementOffset> {
472 public:
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 
533 private:
534  unsigned int element_count_;
535 };
536 
537 template <typename E>
538 struct 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 
579 template <typename ElementOffset, unsigned int N>
580 class MutableArrayOffset : public AbstractAlignedList<ElementOffset> {
581 public:
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 
634 template <typename ElementOffset, unsigned int N>
635 class FinalArrayOffset : public OffsetBase {
636 public:
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 
682 private:
683  offset_t first_element_size_;
684  offset_t element_size_;
685 };
686 
727 template <typename ElementOffset, unsigned int N>
728 class FinalAlignedArrayOffset : public AbstractAlignedList<ElementOffset> {
729 public:
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 
unsigned int element_count() const
Returns the number of characters.
Definition: SequenceOffsets.hpp:307
Base class of Offsets to sequences and arrays of non-primitive members.
Definition: SequenceOffsets.hpp:344
unsigned int element_count() const
Returns the number of elements, N.
Definition: SequenceOffsets.hpp:242
SequenceIterator< ElementOffset, typename ElementOffset::offset_kind > iterator
The iterator type, SequenceIterator.
Definition: SequenceOffsets.hpp:351
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:220
Offset to an array of variable-size elements.
Definition: SequenceOffsets.hpp:580
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:766
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:399
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:288
Offset to a string.
Definition: SequenceOffsets.hpp:263
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:728
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:297
ElementOffset get_element(unsigned int i)
Gets the Offset to an element.
Definition: SequenceOffsets.hpp:513
ElementOffset get_element(unsigned int i)
Gets the Offset to an element.
Definition: SequenceOffsets.hpp:605
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:471
unsigned int element_count() const
Returns the number of elements.
Definition: SequenceOffsets.hpp:169
unsigned int element_count() const
The number of elements.
Definition: SequenceOffsets.hpp:526
iterator end()
Gets an iterator to the past-the-end element.
Definition: SequenceOffsets.hpp:412
ElementOffset get_element(unsigned int i)
Gets the Offset to an element.
Definition: SequenceOffsets.hpp:665