RTI Connext Traditional C++ API  Version 6.0.0
 All Classes Functions Variables Typedefs Enumerations Enumerator Friends Groups Pages
SequenceBuilders.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_SEQUENCEBUILDERS_HPP_
12 #define RTI_DDS_FLAT_SEQUENCEBUILDERS_HPP_
13 
14 #include "rti/flat/Builder.hpp"
15 
16 //
17 // Builders for sequences, strings, and arrays.
18 //
19 // Type hierarchy (- indicates an abstract builder; * a concrete, usable builder)
20 //
21 // - AbstractListBuilder
22 // * MutableArrayBuilder
23 // - AbstractSequenceBuilder
24 // * MutableSequenceBuilder
25 // * FinalSequenceBuilder
26 // * PrimitiveSequenceBuilder
27 // * StringBuilder
28 //
29 // Notes:
30 // - there's no "FinalArrayBuilder" because that's a fixed-size type and
31 // doesn't need a builder (it's constructed via an "add" operation, not a "build"
32 // operation).
33 // - MutableSequenceBuilder "builds" its elements
34 // - FinalSequenceBuilder "adds" its elements
35 //
36 
37 namespace rti { namespace flat {
38 
39 /*i
40  * Extends and specializes AbstractBuilder to add or override the functionality
41  * required to build a collection of consecutive elements (sequence or array):
42  *
43  * - Add or build elements
44  * - Keep track of the element count
45  * - Handle element alignment
46  *
47  */
53 protected:
54  AbstractListBuilder() : element_count_(0)
55  {
56  }
57 
59  nested_tag_t,
60  AbstractBuilder& parent,
61  unsigned int alignment)
62  : AbstractBuilder(nested_tag_t(), parent, alignment), element_count_(0)
63  {
64  }
65 
66  template <typename ElementBuilder>
67  ElementBuilder build_next()
68  {
69  rti::xcdr::Stream::Memento stream_memento(stream());
70  return build_element<ElementBuilder>(stream_memento);
71  }
72 
73  template <typename ElementOffset>
74  ElementOffset add_next()
75  {
76  RTI_FLAT_BUILDER_CHECK_VALID(return ElementOffset());
77 
78  // save state in case of error
79  rti::xcdr::Stream::Memento stream_memento(stream());
80 
81  if (!stream().align(ElementOffset::required_alignment)) {
82  RTI_FLAT_BUILDER_OUT_OF_RESOURCES_ERROR(return ElementOffset());
83  }
84 
85  ElementOffset element = add_element<ElementOffset>();
86  if (element.is_null()) {
87  return ElementOffset();
88  }
89 
90  // Success: clear memento, increment element count
91  stream_memento.discard();
92  element_count_++;
93 
94  return element;
95  }
96 
97  template <typename ElementOffset>
98  void add_n(unsigned int count)
99  {
100  RTI_FLAT_BUILDER_CHECK_VALID(return ElementOffset());
101 
102  if (count == 0) {
103  return;
104  }
105 
106  if (!stream().align(ElementOffset::required_alignment)) {
107  RTI_FLAT_BUILDER_OUT_OF_RESOURCES_ERROR(return ElementOffset());
108  }
109 
110  offset_t elements_size = ElementOffset::serialized_size(0)
111  + ElementOffset::serialized_size_w_padding() * (count - 1);
112  if (!stream().skip(elements_size)) {
113  RTI_FLAT_BUILDER_OUT_OF_RESOURCES_ERROR(return);
114  }
115 
116  element_count_ += count;
117  }
118 
122  unsigned int element_count() const
123  {
124  return element_count_;
125  }
126 
127 #if defined(RTI_FLAT_DATA_CXX11_RVALUE_REFERENCES)
128  AbstractListBuilder(AbstractListBuilder&& other) = default;
129  AbstractListBuilder& operator=(AbstractListBuilder&& other)
130  {
131  if (this == &other) {
132  return *this;
133  }
134 
135  finish_untyped_impl();
136 
137  AbstractBuilder::operator=(static_cast<AbstractBuilder&&>(other));
138 
139  element_count_ = other.element_count_;
140  other.element_count_ = 0;
141 
142  return *this;
143  }
144 #else
145 public:
146  // Enables the safe-move-constructor idiom without C++11 move constructors
147  struct AbstractListBuilderMoveProxy : AbstractBuilderMoveProxy {
148  unsigned int element_count_;
149  };
150 
151  operator AbstractListBuilderMoveProxy () throw() // move-constructor idiom
152  {
153  AbstractListBuilderMoveProxy other;
154  move_to(other);
155  return other;
156  }
157 
158 protected:
159  void move_from(AbstractListBuilderMoveProxy& other)
160  {
161  AbstractBuilder::move_from(other);
162  element_count_ = other.element_count_;
163  }
164 
165  void move_to(AbstractListBuilderMoveProxy& other)
166  {
167  AbstractBuilder::move_to(other);
168  other.element_count_ = element_count_;
169  }
170 
171 #endif
172 
173 private:
174  friend class AbstractBuilder;
175 
176  virtual void finish_member()
177  {
178  RTI_FLAT_BUILDER_CHECK_VALID(return);
179 
180  // Increment element count after the nested element builder finishes,
181  // instead of on build_next(). This makes it easier to roll back the
182  // state if the element building doesn't complete.
183  element_count_++;
184  AbstractBuilder::finish_member();
185  }
186 
187 protected:
188  unsigned int element_count_;
189 };
190 
191 // --- Array: -----------------------------------------------------------------
192 //
193 // (Note: there is no FinalArrayBuilder, because a final array's size is fixed,
194 // and is handled directly returning its offset with add_*; on the other hand,
195 // sequences are never fixed-size.)
196 
227 template <typename ElementBuilder, unsigned int N>
229 public:
234 
236  {
237  }
238 
239 private:
240  friend class AbstractBuilder; // to allow access to the constructor
241 
243  nested_tag_t,
244  AbstractBuilder& parent,
245  unsigned int alignment = 0)
246  : AbstractListBuilder(nested_tag_t(), parent, alignment)
247  {
248  }
249 
250 public:
257  ElementBuilder build_next()
258  {
259  if (element_count() == N) {
260  RTI_FLAT_BUILDER_PRECONDITION_ERROR(
261  "Array builder build_next: too many elements",
262  return ElementBuilder());
263  }
264 
265  return AbstractListBuilder::build_next<ElementBuilder>();
266  }
267 
276  {
277  RTI_FLAT_BUILDER_CHECK_CAN_FINISH(return Offset());
278 
279  if (element_count() != N) {
280  RTI_FLAT_BUILDER_PRECONDITION_ERROR(
281  "Cannot finish array builder: too few elements",
282  return Offset());
283  }
284 
285  return finish_impl<Offset>();
286  }
287 
288  RTI_FLAT_BUILDER_DEFINE_MOVE_OPERATIONS_IMPL(\
289  MutableArrayBuilder, AbstractListBuilder, AbstractListBuilderMoveProxy)
290 
291 };
292 
293 // --- Sequences: -------------------------------------------------------------
294 
295 // Specializes AbstractListBuilder to handle the length header serialization
296 // common to all sequences (which arrays don't have)
305 protected:
307  {
308  }
309 
311  nested_tag_t,
312  AbstractBuilder& parent,
313  unsigned int alignment)
314  : AbstractListBuilder(nested_tag_t(), parent, alignment)
315  {
316  // leave space for sequence length
317  if (!stream().check_size(sizeof(rti::xcdr::length_t))) {
318  RTI_FLAT_BUILDER_OUT_OF_RESOURCES_ERROR(invalidate());
319  } else {
320  // No need to align; the base constructor already aligned to 4 the
321  // begin_position
322  stream().serialize_fast<rti::xcdr::length_t>(0);
323  }
324  }
325 
326  // The destructor does the same as finish_impl() but doesn't need to return
327  // an Offset
329  {
330  finish_untyped_impl();
331  }
332 
333 #if defined(RTI_FLAT_DATA_CXX11_RVALUE_REFERENCES)
336  {
337  finish_untyped_impl();
338  AbstractListBuilder::operator=(static_cast<AbstractListBuilder&&>(other));
339 
340  return *this;
341  }
342 #endif
343 
344  void finish_untyped_impl()
345  {
346  if (!is_valid() || !is_nested()) {
347  return;
348  }
349 
350  finish_length();
351  AbstractListBuilder::finish_untyped_impl();
352  }
353 
354  // Concrete sequences must call this method in their own finish() function
355  template <typename Offset>
356  Offset finish_impl()
357  {
358  RTI_FLAT_BUILDER_CHECK_VALID(return Offset());
359  RTI_FLAT_BUILDER_CHECK_CAN_FINISH(return Offset());
360 
361  finish_length(); // serialize the length header
362  return AbstractListBuilder::finish_impl<Offset>();
363  }
364 
365 private:
366  // Serializes the sequence length when finishing the builder.
367  void finish_length()
368  {
369  rti::xcdr::Stream::Memento stream_memento(stream());
370  stream().current_position(begin_position());
371  stream().serialize_fast<rti::xcdr::length_t>(element_count());
372  }
373 };
374 
403 template <typename ElementBuilder>
405 public:
410 
412  {
413  }
414 
415 private:
416  friend class AbstractBuilder; // to allow access to the constructor
417 
419  nested_tag_t,
420  AbstractBuilder& parent,
421  unsigned int alignment = RTI_XCDR_DHEADER_ALIGNMENT)
422  : AbstractSequenceBuilder(nested_tag_t(), parent, alignment)
423  {
424  }
425 
426 public:
433  ElementBuilder build_next()
434  {
435  return AbstractListBuilder::build_next<ElementBuilder>();
436  }
437 
446  {
447  return finish_impl<Offset>();
448  }
449 
450  RTI_FLAT_BUILDER_DEFINE_MOVE_OPERATIONS_IMPL(\
451  MutableSequenceBuilder, AbstractSequenceBuilder, AbstractListBuilderMoveProxy)
452 };
453 
486 template <typename ElementOffset>
488 public:
490 
492  {
493  }
494 
495 private:
496  friend class AbstractBuilder; // to allow access to the constructor
497 
499  nested_tag_t,
500  AbstractBuilder& parent,
501  unsigned int alignment = RTI_XCDR_SEQ_LENGTH_ALIGNMENT)
502  : AbstractSequenceBuilder(nested_tag_t(), parent, alignment)
503  {
504  }
505 
506 public:
512  ElementOffset add_next()
513  {
514  return AbstractListBuilder::add_next<ElementOffset>();
515  }
516 
525  FinalSequenceBuilder& add_n(unsigned int count)
526  {
527  AbstractListBuilder::add_n<ElementOffset>(count);
528  return *this;
529  }
530 
538  {
539  return finish_impl<Offset>();
540  }
541 
542  RTI_FLAT_BUILDER_DEFINE_MOVE_OPERATIONS_IMPL(\
543  FinalSequenceBuilder, AbstractSequenceBuilder, AbstractListBuilderMoveProxy)
544 };
545 
553 template <typename T>
555 public:
557 
559  {
560  }
561 
562 protected:
563  friend class AbstractBuilder; // to allow access to the constructor
564 
566  nested_tag_t,
567  AbstractBuilder& parent,
568  unsigned int alignment = RTI_XCDR_SEQ_LENGTH_ALIGNMENT)
569  : AbstractSequenceBuilder(nested_tag_t(), parent, alignment)
570  {
571  }
572 
573 public:
579  PrimitiveSequenceBuilder& add_next(T value)
580  {
581  RTI_FLAT_BUILDER_CHECK_VALID(return *this);
582 
583  if (!stream().template serialize<T>(value)) {
584  RTI_FLAT_BUILDER_OUT_OF_RESOURCES_ERROR(return *this);
585  }
586 
587  element_count_++;
588  return *this;
589  }
590 
597  PrimitiveSequenceBuilder& add_n(const T *array, unsigned int count)
598  {
599  RTI_FLAT_BUILDER_CHECK_VALID(return *this);
600 
601  if (!stream().check_size(static_cast<unsigned int>(sizeof(T)) * count)) {
602  RTI_FLAT_BUILDER_OUT_OF_RESOURCES_ERROR(return *this);
603  }
604 
605  if (stream().needs_byte_swap() && sizeof(T) > 1) {
606  for (unsigned int i = 0; i < count; i++) {
607  stream().template serialize_fast<T>(array[i]);
608  }
609  } else {
610  stream().serialize_fast((void *) array, count * static_cast<unsigned int>(sizeof(T)));
611  }
612 
613  element_count_ += count;
614  return *this;
615  }
616 
623  PrimitiveSequenceBuilder& add_n(unsigned int count, T value = T())
624  {
625  RTI_FLAT_BUILDER_CHECK_VALID(return *this);
626 
627  if (!stream().check_size(sizeof(T) * count)) {
628  RTI_FLAT_BUILDER_OUT_OF_RESOURCES_ERROR(return *this);
629  }
630 
631  for (unsigned int i = 0; i < count; i++) {
632  stream().template serialize_fast<T>(value);
633  }
634  element_count_ += count;
635  return *this;
636  }
637 
645  {
646  return finish_impl<Offset>();
647  }
648 
649 private:
650  RTI_FLAT_BUILDER_DEFINE_MOVE_OPERATIONS_IMPL(\
651  PrimitiveSequenceBuilder, AbstractSequenceBuilder, AbstractListBuilderMoveProxy)
652 };
653 
670 public:
671  typedef StringOffset Offset;
672 
673  StringBuilder()
674  {
675  }
676 
677 private:
678  friend class AbstractBuilder; // to allow access to the constructor
679 
681  nested_tag_t,
682  AbstractBuilder& parent,
683  unsigned int alignment = RTI_XCDR_SEQ_LENGTH_ALIGNMENT)
684  : PrimitiveSequenceBuilder<char>(nested_tag_t(), parent, alignment)
685  {
686  }
687 
688 public:
692  StringBuilder& set_string(const char *value)
693  {
694  RTI_FLAT_BUILDER_CHECK_VALID(return *this);
695 
696  // if set_string is called more than once we override the string
697  // that was set before
698  if (element_count_ != 0) {
699  stream().current_position(begin_position());
700  stream().serialize_fast<rti::xcdr::length_t>(0);
701  element_count_ = 0;
702  }
703 
704  unsigned int length = static_cast<unsigned int>(strlen(value)) + 1;
705  add_n(value, length); // if this fail, error has been reported
706  return *this;
707  }
708 
716  {
717  RTI_FLAT_BUILDER_CHECK_VALID(return Offset());
718 
719  if (element_count_ == 0) {
720  add_next('\0'); // build empty string if no string was built
721  }
722  return finish_impl<Offset>();
723  }
724 
725  typedef PrimitiveSequenceBuilder<char> Base;
726 
727  RTI_FLAT_BUILDER_DEFINE_MOVE_OPERATIONS_IMPL(\
728  StringBuilder, Base, AbstractListBuilderMoveProxy)
729 };
730 
731 // Wide strings are treated as a sequence of octets
732 typedef PrimitiveSequenceBuilder<unsigned char> WStringBuilder;
733 
734 } }
735 
736 #endif // RTI_DDS_FLAT_SEQUENCEBUILDERS_HPP_
737 

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