RTI Connext Traditional C++ API  Version 6.0.0
 All Classes Functions Variables Typedefs Enumerations Enumerator Friends Groups Pages
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  return sizeof(T) == 1 || !stream_.needs_byte_swap();
49  }
50 
51 
52  /*@private
53  * @brief Gets direct access to the elements
54  *
55  * Returns a pointer to the elements of this sequence.
56  *
57  * @note If the Sample that contains this PrimitiveSequenceOffset has an endianess
58  * different from the native one, the element bytes may be swapped. This can
59  * happen if this Sample was published by a DataWriter running on a platform
60  * with a different endianess and received by a DataReader running locally.
61  *
62  * This function is not for public use. See rti::flat::plain_cast() instead.
63  */
64  T * get_elements()
65  {
66  return reinterpret_cast<T*>(this->get_buffer());
67  }
68 
69  /*@private
70  * @brief Gets direct access to the array elements
71  *
72  * (Const overload)
73  */
74  const T * get_elements() const
75  {
76  return reinterpret_cast<const T*>(this->get_buffer());
77  }
78 
87  T get_element(unsigned int i) const
88  {
89  // OffsetBase::serialize only checks this as a debug assertion; in
90  // a sequence or array we need to do it in release mode too
91  if (!stream_.check_size((i + 1) * ((unsigned int) sizeof(T)))) {
92  return T();
93  }
94 
95  return OffsetBase::template deserialize<T>(i * (unsigned int) sizeof(T));
96  }
97 
110  bool set_element(unsigned int i, T value)
111  {
112  // OffsetBase::serialize only checks this as a debug assertion; in
113  // a sequence or array we need to do it in release mode too
114  if (!stream_.check_size((i + 1) * static_cast<unsigned int>(sizeof(T)))) {
115  return false;
116  }
117 
118  return OffsetBase::serialize(i * static_cast<unsigned int>(sizeof(T)), value);
119  }
120 };
121 
122 template <typename T>
123 struct PrimitiveSequenceOffsetHelper;
124 
132 template <typename T>
134 public:
135  typedef variable_size_type_tag_t offset_kind;
136  typedef PrimitiveSequenceOffsetHelper<T> Helper;
137 
139  {
140  }
141 
143  rti::flat::SampleBase *sample,
144  offset_t offset,
145  offset_t serialized_size)
147  // passing NULL causes the base constructors to fail
148  serialized_size >= static_cast<offset_t>(sizeof(rti::xcdr::length_t)) ? sample : NULL,
149  offset + static_cast<offset_t>(sizeof(rti::xcdr::length_t)),
150  serialized_size - static_cast<offset_t>(sizeof(rti::xcdr::length_t)))
151  {
152 #ifdef RTI_FLAT_DATA_NO_EXCEPTIONS
153  if (!this->is_null()) { // without exceptions, we need to check if the base ctor failed
154 #endif
155  rti::xcdr::Stream::Memento stream_memento(this->stream_);
156  this->stream_.skip_back(sizeof(rti::xcdr::length_t));
157  element_count_ = this->stream_.template deserialize_fast<rti::xcdr::length_t>();
158 #ifdef RTI_FLAT_DATA_NO_EXCEPTIONS
159  }
160 #endif
161 
162  }
163 
167  unsigned int element_count() const
168  {
169  RTI_FLAT_OFFSET_CHECK_NOT_NULL(return 0);
170 
171  return element_count_;
172  }
173 
174 private:
175  unsigned int element_count_;
176 
177 };
178 
179 template <typename T>
180 struct PrimitiveSequenceOffsetHelper {
181  static offset_t calculate_serialized_size(
182  rti::flat::SampleBase *sample,
183  offset_t absolute_offset,
184  offset_t max_size)
185  {
186  RTI_FLAT_ASSERT(sample != NULL, return 0);
187  RTI_FLAT_ASSERT(max_size > sizeof(rti::xcdr::length_t), return 0);
188 
189  PrimitiveSequenceOffset<T> tmp(sample, absolute_offset, max_size);
190  // elements + header
191  return (tmp.element_count() * sizeof(T)) + sizeof(rti::xcdr::length_t);
192  }
193 };
194 
206 template <typename T, unsigned int N>
208 public:
209  typedef fixed_size_type_tag_t offset_kind;
210 
212  {
213  }
214 
215  PrimitiveArrayOffset(rti::flat::SampleBase *sample, offset_t offset)
217  sample,
218  offset,
219  serialized_size(0))
220  {
221  }
222 
223 public:
224 
229  unsigned int element_count() const
230  {
231  return N;
232  }
233 
234  static offset_t serialized_size(offset_t)
235  {
236  return sizeof(T) * N;
237  }
238 };
239 
240 // Note: the modern C++ API defines a PrimitiveArrayOffset specializations for
241 // safe_enum and wchar_t
242 
243 struct StringOffsetHelper;
244 
250 class StringOffset : public PrimitiveSequenceOffset<char> {
251 public:
252  typedef variable_size_type_tag_t offset_kind;
253  typedef StringOffsetHelper Helper;
254 
255  StringOffset()
256  {
257  }
258 
259  StringOffset(
260  SampleBase *sample,
261  offset_t absolute_offset,
262  offset_t serialized_size)
264  sample,
265  absolute_offset,
266  serialized_size)
267  {
268  }
269 
275  char * get_string()
276  {
277  return reinterpret_cast<char*>(this->get_buffer());
278  }
279 
284  const char * get_string() const
285  {
286  return reinterpret_cast<const char*>(this->get_buffer());
287  }
288 
294  unsigned int element_count() const
295  {
296  RTI_FLAT_ASSERT(PrimitiveSequenceOffset<char>::element_count() > 0, return 0);
297 
299  }
300 };
301 
302 struct StringOffsetHelper {
303  static offset_t calculate_serialized_size(
304  rti::flat::SampleBase *sample,
305  offset_t absolute_offset,
306  offset_t max_size)
307  {
308  StringOffset tmp(sample, absolute_offset, max_size);
309  return tmp.element_count()
310  + 1 // null terminator
311  + (unsigned int) sizeof(rti::xcdr::length_t); // length header
312  }
313 };
314 
315 // Wide strings are treated as a sequence of octets
316 typedef PrimitiveSequenceOffset<unsigned char> WStringOffset;
317 
318 // The base class of SequenceOffset, and FinalAlignedArrayOffset
319 //
320 // This encapsulates the functionality that allows iterating through a list
321 // of elements (a sequence or an array). The list must be always aligned to 4
322 // (that excludes FinalArrayOffset)
323 //
330 template <typename ElementOffset>
332 public:
333 
339 
340 protected:
342  {
343  }
344 
346  rti::flat::SampleBase *sample,
347  offset_t offset,
348  offset_t sequence_size)
349  : OffsetBase(
350  sample,
351  offset,
352  sequence_size)
353  {
354  }
355 
356 public:
357  bool is_cpp_compatible() const // override
358  {
359  return !stream_.needs_byte_swap()
360  && rti::xcdr::has_cpp_friendly_cdr_layout<
361  typename rti::flat::flat_type_traits<ElementOffset>::flat_type>();
362  }
363 
364  ElementOffset get_element(unsigned int i)
365  {
366  RTI_FLAT_OFFSET_CHECK_NOT_NULL(return ElementOffset());
367 
368  return get_element_impl<ElementOffset>(
369  i,
370  typename ElementOffset::offset_kind());
371  }
372 
386  {
387  RTI_FLAT_OFFSET_CHECK_NOT_NULL(return iterator(NULL, 0, 0));
388 
389  return iterator(
390  sample_,
391  absolute_offset_,
392  absolute_offset_ + get_buffer_size());
393  }
394 
399  {
400  RTI_FLAT_OFFSET_CHECK_NOT_NULL(return iterator(NULL, 0, 0));
401 
402  return iterator(
403  sample_,
404  absolute_offset_ + get_buffer_size(),
405  absolute_offset_ + get_buffer_size());
406  }
407 
408 private:
409  // for variable size types we skip element by element
410  template <typename E>
411  E get_element_impl(unsigned int i, variable_size_type_tag_t)
412  {
413  iterator it = begin();
414  while (it != end() && i > 0) {
415  if (!it.advance()) {
416  return E();
417  }
418  i--;
419  }
420 
421  return *it;
422  }
423 
424  // for fixed-size types we support random access
425  template <typename E>
426  E get_element_impl(unsigned int i, fixed_size_type_tag_t)
427  {
428  offset_t size = i * E::serialized_size_w_padding();
429 
430  // Ensure that the stream has space for i + 1 elements
431  if (!stream_.check_size(size + E::serialized_size(0))) {
432  return E();
433  }
434 
435  return E(this->sample_, this->absolute_offset_ + size);
436  }
437 };
438 
439 template <typename ElementOffset>
440 struct SequenceOffsetHelper;
441 
456 template <typename ElementOffset>
457 class SequenceOffset : public AbstractAlignedList<ElementOffset> {
458 public:
459  typedef variable_size_type_tag_t offset_kind;
460  typedef SequenceOffsetHelper<ElementOffset> Helper;
461 
463  {
464  }
465 
467  rti::flat::SampleBase *sample,
468  offset_t offset,
469  offset_t sequence_size)
471  // Member size in bytes must be > 4, otherwise let base ctor fail
472  sequence_size >= sizeof(rti::xcdr::length_t) ? sample: NULL,
473  // The offset begins after any padding to align to 4; padding
474  // may be needed for example for an array of sequence of final
475  // types; the end position of the previous sequence may not be
476  // aligned
477  RTIXCdrAlignment_alignSizeUp(offset, RTI_XCDR_SEQ_LENGTH_ALIGNMENT)
478  + static_cast<offset_t>(sizeof(rti::xcdr::length_t)),
479  sequence_size - static_cast<offset_t>(sizeof(rti::xcdr::length_t)))
480  {
481 #ifdef RTI_FLAT_DATA_NO_EXCEPTIONS
482  if (!this->is_null()) { // without exceptions, we need to check if the base ctor failed
483 #endif
484  rti::xcdr::Stream::Memento stream_memento(this->stream_);
485  this->stream_.skip_back(sizeof(rti::xcdr::length_t));
486  element_count_ = this->stream_.template deserialize_fast<rti::xcdr::length_t>();
487 #ifdef RTI_FLAT_DATA_NO_EXCEPTIONS
488  }
489 #endif
490  }
491 
498  ElementOffset get_element(unsigned int i)
499  {
500  RTI_FLAT_OFFSET_CHECK_NOT_NULL(return ElementOffset());
501 
502  if (i >= element_count_) {
503  return ElementOffset();
504  }
506  }
507 
511  unsigned int element_count() const
512  {
513  RTI_FLAT_OFFSET_CHECK_NOT_NULL(return 0);
514 
515  return element_count_;
516  }
517 
518 private:
519  unsigned int element_count_;
520 };
521 
522 template <typename E>
523 struct SequenceOffsetHelper {
524  // Calculates the serialized size of a Sequence by skipping each element
525  static offset_t calculate_serialized_size(
526  rti::flat::SampleBase *sample,
527  offset_t absolute_offset,
528  offset_t max_offset)
529  {
530  // Create a SequenceOffset beginning at sample + absolute_offset,
531  // with a size we don't know, but no greater than
532  // max_offset - absolute_offset
533  SequenceOffset<E> tmp(
534  sample,
535  absolute_offset,
536  max_offset - absolute_offset);
537  unsigned int count = tmp.element_count();
538  typename SequenceOffset<E>::iterator it = tmp.begin();
539  for (unsigned int i = 0; i < count; i++) {
540  if (!it.advance()) {
541  return 0; // error
542  }
543  }
544 
545  return detail::ptrdiff(it.get_position(), sample->get_buffer())
546  - absolute_offset;
547  }
548 };
549 
564 template <typename ElementOffset, unsigned int N>
565 class MutableArrayOffset : public AbstractAlignedList<ElementOffset> {
566 public:
567  typedef variable_size_type_tag_t offset_kind;
568 
570  {
571  }
572 
574  rti::flat::SampleBase *sample,
575  offset_t offset,
576  offset_t sequence_size)
578  sample,
579  offset,
580  sequence_size)
581  {
582  }
583 
590  ElementOffset get_element(unsigned int i)
591  {
592  if (i >= N) {
593  return ElementOffset();
594  }
595 
597  }
598 };
599 
619 template <typename ElementOffset, unsigned int N>
620 class FinalArrayOffset : public OffsetBase {
621 public:
622  typedef fixed_size_type_tag_t offset_kind;
623 
625  {
626  }
627 
628  // Constructor used when this array is part of a fixed-size type, and
629  // therefore it's initial alignment is not known ahead of time
631  rti::flat::SampleBase *sample,
632  offset_t absolute_offset,
633  offset_t first_element_size,
634  offset_t element_size)
635  : OffsetBase(
636  sample,
637  absolute_offset,
638  first_element_size + element_size * (N - 1)),
639  first_element_size_(first_element_size),
640  element_size_(element_size)
641  {
642  }
643 
650  ElementOffset get_element(unsigned int i)
651  {
652  RTI_FLAT_OFFSET_CHECK_NOT_NULL(return ElementOffset());
653 
654  if (i >= N) {
655  return ElementOffset(); // null offset
656  }
657 
658  offset_t element_offset = this->absolute_offset_;
659  if (i > 0) {
660  element_offset += this->first_element_size_
661  + (i - 1) * this->element_size_;
662  }
663 
664  return ElementOffset(this->sample_, element_offset);
665  }
666 
667 private:
668  offset_t first_element_size_;
669  offset_t element_size_;
670 };
671 
712 template <typename ElementOffset, unsigned int N>
713 class FinalAlignedArrayOffset : public AbstractAlignedList<ElementOffset> {
714 public:
715  typedef fixed_size_type_tag_t offset_kind;
716 
718  {
719  }
720 
721  // Constructor used when this array is part of a mutable type, and
722  // therefore it's aligned to 4 always
724  rti::flat::SampleBase *sample,
725  offset_t absolute_offset)
727  sample,
728  absolute_offset,
729  serialized_size(0))
730  {
731  }
732 
733  // serialized_size() only works when this array is part of a mutable type
734  // and we know it's aligned to 4
735  static offset_t serialized_size(offset_t)
736  {
737  // [element1][pad][element2][pad]...[elementN]
738  return ElementOffset::serialized_size_w_padding() * (N - 1)
739  + ElementOffset::serialized_size(0);
740  }
741 
751  ElementOffset get_element(unsigned int i)
752  {
753  RTI_FLAT_OFFSET_CHECK_NOT_NULL(return ElementOffset());
754 
755  if (i >= N) {
756  return ElementOffset();
757  }
758 
760  }
761 };
762 
763 } }
764 
765 #endif // RTI_DDS_FLAT_SEQUENCEOFFSETS_HPP_
766 

RTI Connext Traditional C++ API Version 6.0.0 Copyright © Sun Mar 3 2019 Real-Time Innovations, Inc