RefleX
Build DDS Applications in Modern C++ without IDL
 All Classes Namespaces Files Functions Variables Typedefs Enumerator Friends Macros Pages
dd_manip.h
Go to the documentation of this file.
1 /*********************************************************************************************
2 (c) 2005-2014 Copyright, Real-Time Innovations, Inc. All rights reserved.
3 RTI grants Licensee a license to use, modify, compile, and create derivative works
4 of the Software. Licensee has the right to distribute object form only for use with RTI
5 products. The Software is provided "as is", with no warranty of any type, including
6 any warranty for fitness for any purpose. RTI is under no obligation to maintain or
7 support the Software. RTI shall not be liable for any incidental or consequential
8 damages arising out of the use or inability to use the software.
9 **********************************************************************************************/
10 
11 #ifndef RTIREFLEX_DD_MANIP_H
12 #define RTIREFLEX_DD_MANIP_H
13 
14 #include <string>
15 #include <vector>
16 #include <tuple>
17 #include <iostream>
18 #include <algorithm>
19 #include <cassert>
20 
21 #include "ndds/ndds_cpp.h"
22 
23 #include "reflex/tuple_iterator.h"
24 #include "reflex/dd_traits.h"
25 #include "reflex/enable_if.h"
26 #include "reflex/dd_extra.h"
27 #include "reflex/bounded.h"
28 
29 #include <boost/fusion/support/is_sequence.hpp>
30 #include <boost/fusion/include/is_sequence.hpp>
31 
32 #define SET_MEMBER_VALUE_DECL(TYPE) \
33  REFLEX_DLL_EXPORT static void set_member_value( \
34  DDS_DynamicData & instance, \
35  const MemberAccess &ma, \
36  const TYPE & val)
37 
38 
39 #define GET_MEMBER_VALUE_DECL(TYPE) \
40  REFLEX_DLL_EXPORT static void get_member_value( \
41  const DDS_DynamicData & instance, \
42  const MemberAccess &ma, \
43  TYPE & val)
44 
45 
46 namespace reflex {
47 
48  template <class T>
49  void write_dynamicdata(DDS_DynamicData &dest, const T & src);
50 
51  template <class T>
52  void read_dynamicdata(T & dest, const DDS_DynamicData & src);
53 
54  namespace detail {
55 
56  REFLEX_DLL_EXPORT DDS_LongDouble to_LongDouble(long double);
57  REFLEX_DLL_EXPORT long double from_LongDouble(DDS_LongDouble);
58 
59  struct RawStorage
60  {
61  static const unsigned int size = 128;
62  char buf[size];
63  };
64 
65  // This signed char overload is needed because DDS does not natively
66  // support signed char. It supports char and octet, which in C++
67  // are char and unsigned char but signed char is a third kind of char
68  // and is separate from first two. It must be explicitly casted
69  // to char. Hence the overload.
70  REFLEX_DLL_EXPORT DDS_Char * primitive_ptr_cast(signed char * ptr);
71 
72  template <class T>
73  T * primitive_ptr_cast(T * t,
74  typename
76  !std::is_same<signed char, T>::value>::type * = 0)
77  {
78  // see the signed char overload.
79  return t;
80  }
81 
82 
83  template <class T>
84  bool do_serialize(T &)
85  {
86  return true;
87  }
88 
89  template <class T>
90  uint32_t array_length(const T &)
91  {
93  }
94 
95  struct set_member_overload_resolution_helper
96  {
97  public:
98 
99  SET_MEMBER_VALUE_DECL(match::octet_t); // also uint8_t
100  SET_MEMBER_VALUE_DECL(bool);
101  SET_MEMBER_VALUE_DECL(char);
102  SET_MEMBER_VALUE_DECL(int8_t);
103  SET_MEMBER_VALUE_DECL(int16_t);
104  SET_MEMBER_VALUE_DECL(uint16_t);
105  SET_MEMBER_VALUE_DECL(int32_t);
106  SET_MEMBER_VALUE_DECL(uint32_t);
107  SET_MEMBER_VALUE_DECL(int64_t);
108  SET_MEMBER_VALUE_DECL(uint64_t);
109  SET_MEMBER_VALUE_DECL(float);
110  SET_MEMBER_VALUE_DECL(double);
111  SET_MEMBER_VALUE_DECL(long double);
112 #ifndef RTI_WIN32
113  SET_MEMBER_VALUE_DECL(char32_t);
114 #endif
115 #ifdef __x86_64__
116  SET_MEMBER_VALUE_DECL(long long int);
117 #endif
118 
119  template <class Str>
120  static void set_member_value(
121  DDS_DynamicData & instance,
122  const MemberAccess &ma,
123  const Str & val,
125  {
126  DDS_ReturnCode_t rc;
127  if (ma.access_by_id()) {
128  rc = instance.set_string(NULL, ma.get_id(), val.c_str());
129  }
130  else {
131  rc = instance.set_string(ma.get_name(),
132  DDS_DYNAMIC_DATA_MEMBER_ID_UNSPECIFIED,
133  val.c_str());
134  }
135  detail::check_retcode("DDS_DynamicData::set_string error = ", rc);
136  }
137 
138  template <class T> // When T is an enum
139  static void set_member_value(
140  DDS_DynamicData & instance,
141  const MemberAccess &ma,
142  const T & val,
144  {
145  DDS_ReturnCode_t rc;
146 
147  if (ma.access_by_id())
148  rc = instance.set_long(NULL, ma.get_id(), val);
149  else
150  rc = instance.set_long(
151  ma.get_name(),
152  DDS_DYNAMIC_DATA_MEMBER_ID_UNSPECIFIED,
153  val);
154 
155  detail::check_retcode("set_member_value: set_long (for enums) error = ", rc);
156  }
157 
158  // Typelist could be
159  // 1. A user-defined struct adapted as a Fusion Sequence
160  // 2. std::tuple
161  // 3. std::pair
162  template <class Typelist>
163  static void set_member_value(
164  DDS_DynamicData & instance,
165  const MemberAccess & ma,
166  const Typelist & val,
171  >::type * = 0)
172  {
173  DDS_DynamicData inner(NULL, DDS_DYNAMIC_DATA_PROPERTY_DEFAULT);
174  SafeBinder binder(instance, inner, ma);
175 
176  reflex::write_dynamicdata(inner, val);
177  }
178 
179  template <class C>
180  // When C is a container of primitives
181  // but not vector<primitives except (bool and enums)>
182  static void set_member_value(
183  DDS_DynamicData & instance,
184  const MemberAccess &ma,
185  const C & val,
186  typename reflex::meta::enable_if<
192  >::type * = 0)
193  {
194  if (do_serialize(val))
195  {
196  typename DynamicDataSeqTraits<typename reflex::type_traits::container_traits<C>::value_type>::type seq;
197  seq.ensure_length(val.size(), val.size());
198 
199  size_t i = 0;
200  for (auto const &elem : val) {
201  seq[i] = elem;
202  ++i;
203  }
204 
205  DDS_ReturnCode_t rc = set_sequence(instance, ma, seq);
206  detail::check_retcode("set_member_value: Error setting (bool/enum) seq, error = ", rc);
207  }
208  }
209 
210  template <class C>
211  // When C is a container of user-defined types
212  static void set_member_value(
213  DDS_DynamicData & instance,
214  const MemberAccess &ma,
215  const C & val,
216  typename reflex::meta::disable_if<
221  >::type * = 0)
222  {
223  if (do_serialize(val))
224  {
225  DDS_DynamicData seq_member(NULL, DDS_DYNAMIC_DATA_PROPERTY_DEFAULT);
226  SafeBinder binder(instance, seq_member, ma);
227 
228  // set_seq_length seems to avoid the following weird behavior:
229  // If you have an outer sequence of size N and each element of
230  // the sequence is an empty sequence, the outer sequence in
231  // the dynamic data instance is off by 1. This function seems
232  // to handle nested empty sequences.
233  // BTW, sequence of strings seem to work fine without magic.
234  set_seq_length(
235  seq_member,
236  val.size(),
238 
239  size_t i = 0;
240  for (auto const &elem : val)
241  {
242  set_member_value(seq_member, MemberAccess::BY_ID(i + 1), elem);
243  ++i;
244  }
245  }
246  }
247 
248  REFLEX_DLL_EXPORT static void set_member_value(
249  DDS_DynamicData & instance,
250  const MemberAccess &ma,
251  const std::vector<long double> & val,
252  void * = 0);
253 
254  template <class T>
255  static void set_member_value(
256  DDS_DynamicData & instance,
257  const MemberAccess &ma,
258  const std::vector<T> & val,
260  {
261  // Sequences of primitive types are loaned and unloaned as an optimization.
262  // bools and enums don't use this optimization because vector<bool> storage is
263  // 8 bools-per-byte and sizeof enums is not standarized and it is compiler dependent.
264 
265  if (!val.empty())
266  {
267  typename DynamicDataSeqTraits<T>::type seq;
268  std::vector<T> & nc_val = const_cast<std::vector<T> &>(val);
269  if (seq.loan_contiguous(primitive_ptr_cast(&nc_val[0]), val.size(), val.capacity()) != true)
270  {
271  throw std::runtime_error("set_member_value: sequence loaning failed");
272  }
273 
274  DDS_ReturnCode_t rc = set_sequence(instance, ma, seq);
275  seq.unloan();
276  detail::check_retcode("set_member_value: Error setting sequence, error = ", rc);
277  }
278  }
279 
280  private:
281  template <class T>
282  static void set_member_value_range(
283  DDS_DynamicData & instance,
284  const MemberAccess &ma,
285  const reflex::match::Range<T> & range,
287  {
288  typename DynamicDataSeqTraits<T>::type seq;
289 
290  size_t size = boost::distance(range);
291  seq.ensure_length(size, size);
292 
293  size_t i = 0;
294  for (auto const &elem : range)
295  {
296  seq[i] = elem;
297  ++i;
298  }
299 
300  DDS_ReturnCode_t rc = set_sequence(instance, ma, seq);
301  detail::check_retcode("set_member_value: Error setting sequence, error = ", rc);
302  }
303 
304  template <class T>
305  static void set_member_value_range(
306  DDS_DynamicData & instance,
307  const MemberAccess &ma,
308  const reflex::match::Range<T> & range,
310  {
311  DDS_DynamicData seq_member(NULL, DDS_DYNAMIC_DATA_PROPERTY_DEFAULT);
312  SafeBinder binder(instance, seq_member, ma);
313 
314  size_t size = boost::distance(range);
315 
316  // set_seq_length seems to avoid the following weird behavior:
317  // If you have an outer sequence of size N and each element of
318  // the sequence is an empty sequence, the outser sequence in
319  // the dynamic data instance is off by 1. This function seems
320  // to handle nested empty sequences.
321  // BTW, sequence of strings seem to work fine without magic.
322  set_seq_length(seq_member, size, reflex::type_traits::is_string<T>::value);
323 
324  size_t i = 0;
325  for (typename match::Range<T>::const_iterator iter = boost::begin(range);
326  iter != boost::end(range);
327  ++iter, ++i)
328  {
329  set_member_value
330  (seq_member, MemberAccess::BY_ID(i + 1), *iter);
331  }
332  }
333 
334  public:
335 
336  template <class T>
337  static void set_member_value(
338  DDS_DynamicData & instance,
339  const MemberAccess &ma,
340  const reflex::match::Range<T> & range)
341  {
342  set_member_value_range(instance, ma, range);
343  }
344 
345  template <class T, size_t Bound>
346  static void set_member_value(
347  DDS_DynamicData & instance,
348  const MemberAccess &ma,
350  {
351  set_member_value_range(instance, ma, range);
352  }
353 
354  template <class... Args>
355  static void set_member_value(
356  DDS_DynamicData & instance,
357  const MemberAccess & ma,
358  const reflex::match::Sparse<Args...> & val)
359  {
360  DDS_DynamicData inner(NULL, DDS_DYNAMIC_DATA_PROPERTY_DEFAULT);
361  SafeBinder binder(instance, inner, ma);
362 
364  }
365 
366  template <class TagType, class... Cases>
367  static void set_member_value(
368  DDS_DynamicData & instance,
369  const MemberAccess & ma,
371  {
372  DDS_DynamicData inner(NULL, DDS_DYNAMIC_DATA_PROPERTY_DEFAULT);
373  SafeBinder binder(instance, inner, ma);
374 
375  typedef typename
376  match::Union<TagType, Cases...>::case_tuple_type CaseTuple;
377 
378  typedef TypelistIterator<
379  CaseTuple,
380  0,
382 
383  if (!val.empty())
384  {
385  TIter::set_union(
386  inner,
387  MemberAccess::BY_ID(-999),// id unimportant due to discriminator
388  val);
389  }
390  }
391 
392  template <class T, size_t Dim>
393  static void set_member_value(
394  DDS_DynamicData & instance,
395  const MemberAccess & ma,
396  const T(&val)[Dim],
397  typename reflex::meta::disable_if<
400  >::type * = 0)
401  {
402  DDS_DynamicData arr_member(NULL, DDS_DYNAMIC_DATA_PROPERTY_DEFAULT);
403  SafeBinder binder(instance, arr_member, ma);
404 
405  typename reflex::meta::remove_all_extents<T>::type const * arr =
406  reinterpret_cast<typename reflex::meta::remove_all_extents<T>::type const *>(&val[0]);
407 
408  DDS_UnsignedLong length = array_length(val);
409  for (DDS_UnsignedLong i = 0; i < length; ++i)
410  {
411  set_member_value(arr_member, MemberAccess::BY_ID(i + 1), arr[i]);
412  }
413  }
414 
415  template <class T, size_t Dim>
416  static void set_member_value(
417  DDS_DynamicData & instance,
418  const MemberAccess &ma,
419  const T(&val)[Dim],
420  typename reflex::meta::enable_if<
423  >::type * = 0)
424  {
425  typename reflex::meta::remove_all_extents<T>::type const * arr =
426  reinterpret_cast<typename reflex::meta::remove_all_extents<T>::type const *>(&val[0]);
427 
428  DDS_ReturnCode_t rc =
429  detail::set_array(instance, ma, array_length(val), arr);
430 
431  detail::check_retcode("set_member_value: Error setting array, error = ", rc);
432  }
433 
434  template <class T, size_t Dim>
435  static void set_member_value(
436  DDS_DynamicData & instance,
437  const MemberAccess & ma,
438  const std::array<T, Dim> & val,
439  typename reflex::meta::disable_if<
442  >::type * = 0)
443  {
444  DDS_DynamicData arr_member(NULL, DDS_DYNAMIC_DATA_PROPERTY_DEFAULT);
445  SafeBinder binder(instance, arr_member, ma);
446 
447  typename reflex::meta::remove_all_extents<T>::type const * arr =
448  reinterpret_cast<typename reflex::meta::remove_all_extents<T>::type const *>(&val[0]);
449 
450  DDS_UnsignedLong length = array_length(val);
451  for (DDS_UnsignedLong i = 0; i < length; ++i)
452  {
453  set_member_value(arr_member, MemberAccess::BY_ID(i + 1), arr[i]);
454  }
455  }
456 
457  template <class T, size_t Dim>
458  static void set_member_value(
459  DDS_DynamicData & instance,
460  const MemberAccess &ma,
461  const std::array<T, Dim> & val,
462  typename reflex::meta::enable_if<
465  >::type * = 0)
466  {
467  typename reflex::meta::remove_all_extents<T>::type const * arr =
468  reinterpret_cast<typename reflex::meta::remove_all_extents<T>::type const *>(&val[0]);
469 
470  DDS_ReturnCode_t rc =
471  detail::set_array(instance, ma, array_length(val), arr);
472 
473  detail::check_retcode("set_member_value: Error setting array, error = ", rc);
474  }
475 /*
476 #ifdef RTI_WIN32
477  template <typename... T>
478  static void set_member_value(
479  DDS_DynamicData & instance,
480  const MemberAccess &ma,
481  const boost::optional<T...> & opt)
482 #else
483  template <typename T>
484  static void set_member_value(
485  DDS_DynamicData & instance,
486  const MemberAccess &ma,
487  const boost::optional<T> & opt)
488 #endif
489  {
490  if (opt.is_initialized())
491  {
492  set_member_value(instance, ma, *opt.get_ptr());
493  }
494  }
495 */
496  template <typename Opt>
497  static void set_member_value(
498  DDS_DynamicData & instance,
499  const MemberAccess &ma,
500  const Opt & opt,
502  {
503  if (opt)
504  {
505  set_member_value(instance, ma, *opt);
506  }
507  }
508 
509  template <class T, size_t Bound>
510  static void set_member_value(
511  DDS_DynamicData & instance,
512  const MemberAccess &ma,
514  {
515  set_member_value(instance, ma, static_cast<const T &>(val));
516  }
517  }; // struct set_member_overload_resolution_helper
518 
519  template <class T>
520  void set_member_forward(
521  DDS_DynamicData & instance,
522  const MemberAccess &ma,
523  const T & val)
524  {
525  set_member_overload_resolution_helper::
526  set_member_value(instance, ma, val);
527  }
528 
529 
530  /***************************************************/
531 
532  struct get_member_overload_resolution_helper
533  {
534  public:
535  GET_MEMBER_VALUE_DECL(match::octet_t); // also uint8_t
536  GET_MEMBER_VALUE_DECL(bool);
537  GET_MEMBER_VALUE_DECL(char);
538  GET_MEMBER_VALUE_DECL(int8_t);
539  GET_MEMBER_VALUE_DECL(int16_t);
540  GET_MEMBER_VALUE_DECL(uint16_t);
541  GET_MEMBER_VALUE_DECL(int32_t);
542  GET_MEMBER_VALUE_DECL(uint32_t);
543  GET_MEMBER_VALUE_DECL(int64_t);
544  GET_MEMBER_VALUE_DECL(uint64_t);
545  GET_MEMBER_VALUE_DECL(float);
546  GET_MEMBER_VALUE_DECL(double);
547  GET_MEMBER_VALUE_DECL(long double);
548 #ifndef RTI_WIN32
549  GET_MEMBER_VALUE_DECL(char32_t);
550 #endif
551 #ifdef __x86_64__
552  GET_MEMBER_VALUE_DECL(long long int);
553 #endif
554  //GET_MEMBER_VALUE_DECL(std::string);
555 
556  template <class Str>
557  static void get_member_value(
558  const DDS_DynamicData & instance,
559  const MemberAccess &ma,
560  Str & val,
562  {
563  RawStorage raw;
564  char * buf = raw.buf;
565  DDS_UnsignedLong size = RawStorage::size;
566 
567  const char * member_name =
568  ma.access_by_id() ? NULL : ma.get_name();
569  int id = ma.access_by_id() ?
570  ma.get_id() : DDS_DYNAMIC_DATA_MEMBER_ID_UNSPECIFIED;
571 
572  // Try to get the string into a preallocated buffer
573  DDS_ReturnCode_t rc =
574  instance.get_string(buf, &size, member_name, id);
575 
576  if (rc == DDS_RETCODE_OK)
577  {
578  val.assign(buf);
579  }
580  else if (rc == DDS_RETCODE_OUT_OF_RESOURCES)
581  {
582  // Raw buffer is insufficient. Have the m/w provide it.
583  buf = 0; // TODO: null or empty?
584  size = 0;
585  rc = instance.get_string(buf, &size, member_name, id);
586  detail::check_retcode("DDS_DynamicData::get_string failed. error = ", rc);
587  val.assign(buf);
588  DDS_String_free(buf);
589  }
590  else
591  detail::check_retcode("DDS_DynamicData::get_string failed. error = ", rc);
592  }
593 
594  public:
595 
596  template <class T> // When T is an enum
597  static void get_member_value(
598  const DDS_DynamicData & instance,
599  const MemberAccess &ma,
600  T & val,
602  {
603  DDS_ReturnCode_t rc;
604  DDS_Long out;
605 
606  const char * member_name =
607  ma.access_by_id() ? NULL : ma.get_name();
608 
609  int id = ma.access_by_id() ?
610  ma.get_id() : DDS_DYNAMIC_DATA_MEMBER_ID_UNSPECIFIED;
611 
612  rc = instance.get_long(out, member_name, id);
613  detail::check_retcode("get_member_value: get_long (for enums) failed, error = ", rc);
614 
615  // Do not qualify this function call.
616  // Argument dependent lookup must happen here.
617  // A more specialized enum_cast could be defined
618  // in the namespace of T otherwise fallback to codegen.
619  using namespace reflex::codegen;
620  enum_cast(val, out); // cast required for enums
621  }
622 
623  template <class Typelist>
624  // Typelist could be
625  // 1. A user-defined struct adapted as a Fusion Sequence
626  // 2. std::tuple
627  // 3. std::pair
628  // The overload is disbaled for user-defined enums.
629  static void get_member_value(
630  const DDS_DynamicData & instance,
631  const MemberAccess &ma,
632  Typelist & val,
637  >::type * = 0)
638  {
639  DDS_DynamicData inner(NULL, DDS_DYNAMIC_DATA_PROPERTY_DEFAULT);
640  SafeBinder binder(instance, inner, ma);
641 
642  reflex::read_dynamicdata(val, inner);
643  }
644 
645  private:
646  template <class C>
647  static void right_size(C &c, size_t size)
648  {
650  c = temp;
651  }
652 
653  template <class T, class Alloc>
654  static void right_size(std::vector<T, Alloc> & v, size_t size)
655  {
656  v.resize(size);
657  }
658 
659  template <class T, class Alloc>
660  static void right_size(std::list<T, Alloc> & l, size_t size)
661  {
662  l.resize(size);
663  }
664 
665  template <class T, class Comp, class Alloc>
666  static void right_size(std::set<T, Comp, Alloc> & s, size_t)
667  {
668  // sets have no resize function.
669  // You have clear it and then insert from scratch.
670  s.clear();
671  }
672 
673  template <class Key, class T, class Comp, class Alloc>
674  static void right_size(std::map<Key, T, Comp, Alloc> & m, size_t)
675  {
676  // maps have no resize function.
677  // You have clear it and then insert from scratch.
678  m.clear();
679  }
680 
681  template <class Iter, class U>
682  static void primitive_assign(Iter dest, U src)
683  {
684  *dest = static_cast<typename std::iterator_traits<Iter>::value_type>(src);
685  }
686 
687  template <class U>
688  static void primitive_assign(std::vector<bool>::iterator dest,
689  U src)
690  {
691  *dest = src ? true : false;
692  }
693 
694  template <class C>
696  static begin(C & c, typename reflex::meta::enable_if<reflex::type_traits::is_container<C>::value>::type * = 0)
697  {
698  return c.begin();
699  }
700 
701  template <class Seq, class C>
702  static void copy_primitive_seq(
703  const Seq & seq,
704  size_t count,
705  C & c,
707  {
709  for (size_t i = 0; i < count; ++i, ++iter)
710  {
711  // Cast required for enums
712  // Possible extra copy of primitives due
713  // to cast to value (as opposed to a reference)
714  primitive_assign(iter, seq[i]);
715  }
716  }
717 
718  template <class Seq, class T, class Key, class Alloc>
719  static void copy_primitive_seq(
720  const Seq & seq,
721  size_t count,
722  std::set<T, Key, Alloc> & s)
723  {
724  for (size_t i = 0; i < count; ++i)
725  {
726  // Cast required for enums
727  // Possible extra copy of primitives due
728  // to cast to value (as opposed to reference)
729  s.insert(static_cast<
730  typename std::set<T, Key, Alloc>::value_type>(seq[i]));
731  }
732  }
733 
734  public:
735  template <class C>
736  // When C is a std container of primitives
737  // but not vector<primitives except (bool and enums)>
738  static void get_member_value(
739  const DDS_DynamicData & instance,
740  const MemberAccess &ma,
741  C & val,
742  typename reflex::meta::enable_if <
748  > ::type * = 0)
749  {
750  DDS_DynamicDataMemberInfo seq_info;
751 
752  const char * member_name =
753  ma.access_by_id() ? NULL : ma.get_name();
754  int id = ma.access_by_id() ?
755  ma.get_id() : DDS_DYNAMIC_DATA_MEMBER_ID_UNSPECIFIED;
756 
757  instance.get_member_info(seq_info, member_name, id);
758  right_size(val, seq_info.element_count); // shrink/grow as needed.
759 
760  if (seq_info.element_count > 0)
761  {
762  typename DynamicDataSeqTraits<typename reflex::type_traits::container_traits<C>::value_type>::type seq;
763  seq.ensure_length(seq_info.element_count,
764  seq_info.element_count);
765 
766  DDS_ReturnCode_t rc = detail::get_sequence(instance, seq, ma);
767  detail::check_retcode("get_member_value: get_sequence error = ", rc);
768  copy_primitive_seq(seq, seq_info.element_count, val);
769  }
770  }
771 
772  private:
773  template <class Seq, class C>
774  // When C is a container of user-defined type (a.k.a. fusion sequence)
775  static void copy_complex_seq(
776  const Seq & seq,
777  size_t count,
778  C & c,
781  >::type * = 0)
782  {
783  if (count > 0)
784  {
785 #ifdef _DEBUG
786  assert(c.size() == count); // size() is O(1) even for std::list in C++11
787 #endif
788  size_t i = 0;
789  for (auto &elem : c) // runs from 0 to count-1
790  {
791  get_member_value(seq, MemberAccess::BY_ID(i + 1), elem);
792  ++i;
793  }
794  }
795  }
796 
797  template <class Seq, class Key, class T, class Comp, class Alloc>
798  // When C is a map (each value_type is a std::pair<const Key, T>)
799  static void copy_complex_seq(
800  const Seq & seq,
801  size_t count,
802  std::map<Key, T, Comp, Alloc> & map)
803  {
804  if (count > 0)
805  {
806  for (size_t i = 0; i < count; ++i)
807  {
808  typedef typename std::map<Key, T, Comp, Alloc>::value_type PairType;
809  std::pair<typename reflex::meta::remove_const<typename PairType::first_type>::type,
810  typename PairType::second_type> temp;
811  get_member_value(seq, MemberAccess::BY_ID(i + 1), temp);
812  map.insert(std::move(temp));
813  }
814  }
815  }
816 
817  template <class Seq, class T, class Key, class Alloc>
818  // When set is a container of user-defined type (a.k.a. fusion sequence)
819  static void copy_complex_seq(
820  const Seq & seq,
821  size_t count,
822  std::set<T, Key, Alloc> & s)
823  {
824  if (count > 0)
825  {
826  for (size_t i = 0; i < count; ++i)
827  {
828  // set iterator refer to const elements only
829  // Therefore, you have to create a temporary, fill it in,
830  // and insert in the set.
831  T temp{}; // default-initialize
832  get_member_value(seq, MemberAccess::BY_ID(i + 1), temp);
833  s.insert(std::move(temp));
834  }
835  }
836  }
837 
838  public:
839  template <class C>
840  // When C is a container of user-defined type (a.k.a. fusion sequence)
841  static void get_member_value(
842  const DDS_DynamicData & instance,
843  const MemberAccess &ma,
844  C & val,
849  >::type * = 0)
850  {
851  DDS_DynamicData seq_member(NULL, DDS_DYNAMIC_DATA_PROPERTY_DEFAULT);
852  SafeBinder binder(instance, seq_member, ma);
853 
854  DDS_DynamicDataInfo seq_info;
855  seq_member.get_info(seq_info);
856 
857  right_size(val, seq_info.member_count);
858  copy_complex_seq(seq_member, seq_info.member_count, val);
859  }
860 
861 
862  REFLEX_DLL_EXPORT static void get_member_value(
863  const DDS_DynamicData & instance,
864  const MemberAccess &ma,
865  std::vector<long double> & val,
866  void * = 0);
867 
868  template <class T>
869  static void get_member_value(
870  const DDS_DynamicData & instance,
871  const MemberAccess &ma,
872  std::vector<T> & val,
874  {
875  // Sequences of primitive types are loaned and unloaned as an optimization.
876  // bools and enums don;t use this optimization because vector<bool> storage is
877  // 8 bools-per-byte and sizeof enums is not standarized and it is compiler dependent.
878 
879  DDS_DynamicDataMemberInfo seq_info;
880 
881  const char * member_name =
882  ma.access_by_id() ? NULL : ma.get_name();
883  int id = ma.access_by_id() ?
884  ma.get_id() : DDS_DYNAMIC_DATA_MEMBER_ID_UNSPECIFIED;
885 
886  instance.get_member_info(seq_info, member_name, id);
887  right_size(val, seq_info.element_count);
888 
889  if (seq_info.element_count > 0)
890  {
891  typename DynamicDataSeqTraits<T>::type seq;
892  if (seq.loan_contiguous(primitive_ptr_cast(&val[0]), val.size(), val.capacity()) != true)
893  {
894  throw std::runtime_error("get_member_value: sequence loaning failed");
895  }
896 
897  DDS_ReturnCode_t rc = detail::get_sequence(instance, seq, ma);
898  seq.unloan();
899  detail::check_retcode("get_member_value: get_sequence error = ", rc);
900  }
901  }
902 
903  template <class T, size_t Bound>
904  static void get_member_value(
905  const DDS_DynamicData & instance,
906  const MemberAccess &ma,
908  {
909  get_member_value(instance, ma, static_cast<T &>(val));
910  }
911 
912  private:
913  template <class T>
914  // If you are populating a range it must be sufficient in capacity
915  // You probably also need to "mark" the range to be erased to
916  // separate the old elements from the new one.
917  static void get_member_value_range(
918  const DDS_DynamicData & instance,
919  const MemberAccess &ma,
920  reflex::match::Range<T> & range,
921  typename reflex::meta::enable_if<
923  >::type * = 0)
924  {
925  typename DynamicDataSeqTraits<T>::type seq;
926  DDS_DynamicDataMemberInfo seq_info;
927 
928  const char * member_name =
929  ma.access_by_id() ? NULL : ma.get_name();
930  int id = ma.access_by_id() ?
931  ma.get_id() : DDS_DYNAMIC_DATA_MEMBER_ID_UNSPECIFIED;
932 
933  instance.get_member_info(seq_info, member_name, id);
934  seq.ensure_length(seq_info.element_count,
935  seq_info.element_count);
936 
937  if (seq_info.element_count > 0)
938  {
939  DDS_ReturnCode_t rc = detail::get_sequence(instance, seq, ma);
940  detail::check_retcode("get_member_value: get_sequence error = ", rc);
941 
942  if (boost::distance(range) < seq_info.element_count) {
943  throw std::runtime_error("get_member_value: Insufficient range");
944  }
945 
946  typename match::Range<T>::iterator iter = boost::begin(range);
947  for (size_t i = 0; i < seq_info.element_count; ++i, ++iter)
948  {
949  // Possible extra copy of the primitives
950  *iter = static_cast<T>(seq[i]); // cast required for enums
951  }
952  }
953  }
954 
955  template <class T>
956  static void get_member_value_range(
957  const DDS_DynamicData & instance,
958  const MemberAccess &ma,
959  reflex::match::Range<T> & range,
960  typename reflex::meta::disable_if<
962  >::type * = 0)
963  {
964  DDS_DynamicData seq_member(NULL, DDS_DYNAMIC_DATA_PROPERTY_DEFAULT);
965  SafeBinder binder(instance, seq_member, ma);
966 
967  DDS_DynamicDataInfo seq_info;
968  seq_member.get_info(seq_info);
969 
970  if (boost::distance(range) < seq_info.member_count) {
971  throw std::runtime_error("get_member_value: Insufficient range");
972  }
973 
974  typename match::Range<T>::iterator iter = boost::begin(range);
975  for (int i = 0; i < seq_info.member_count; ++i, ++iter)
976  {
977  get_member_value(seq_member, MemberAccess::BY_ID(i + 1), *iter);
978  }
979  }
980 
981  public:
982  template <class T>
983  static void get_member_value(
984  const DDS_DynamicData & instance,
985  const MemberAccess &ma,
986  reflex::match::Range<T> & range)
987  {
988  get_member_value_range(instance, ma, range);
989  }
990 
991  template <class T, size_t Bound>
992  static void get_member_value(
993  const DDS_DynamicData & instance,
994  const MemberAccess &ma,
996  {
997  get_member_value_range(instance, ma, range);
998  }
999 
1000  template <class... Args>
1001  static void get_member_value(
1002  const DDS_DynamicData & instance,
1003  const MemberAccess &ma,
1005  {
1006  DDS_DynamicData inner(NULL, DDS_DYNAMIC_DATA_PROPERTY_DEFAULT);
1007  SafeBinder binder(instance, inner, ma);
1008 
1010  }
1011 
1012  template <class T, size_t Dim>
1013  static void get_member_value(
1014  const DDS_DynamicData & instance,
1015  const MemberAccess & ma,
1016  T(&val)[Dim],
1017  typename reflex::meta::disable_if<
1020  >::value
1021  >::type * = 0)
1022  {
1023  DDS_DynamicData arr_member(NULL, DDS_DYNAMIC_DATA_PROPERTY_DEFAULT);
1024  SafeBinder binder(instance, arr_member, ma);
1025 
1026  DDS_UnsignedLong length = array_length(val);
1027 
1029  reinterpret_cast<typename reflex::meta::remove_all_extents<T>::type *>(&val[0]);
1030 
1031  for (DDS_UnsignedLong i = 0; i < length; ++i)
1032  {
1033  get_member_value(arr_member, MemberAccess::BY_ID(i + 1), arr[i]);
1034  }
1035  }
1036 
1037  template <class T, size_t Dim>
1038  static void get_member_value(
1039  const DDS_DynamicData & instance,
1040  const MemberAccess & ma,
1041  T(&val)[Dim],
1042  typename reflex::meta::enable_if<
1045  >::value
1046  >::type * = 0)
1047  {
1048  DDS_UnsignedLong length = array_length(val);
1049 
1051  reinterpret_cast<typename reflex::meta::remove_all_extents<T>::type *>(&val[0]);
1052 
1053  DDS_ReturnCode_t rc = detail::get_array(instance, arr, &length, ma);
1054  detail::check_retcode("get_member_value: get_array error = ", rc);
1055  }
1056 
1057  template <class T, size_t Dim>
1058  static void get_member_value(
1059  const DDS_DynamicData & instance,
1060  const MemberAccess & ma,
1061  std::array<T, Dim> &val,
1062  typename reflex::meta::disable_if<
1065  >::value
1066  >::type * = 0)
1067  {
1068  DDS_DynamicData arr_member(NULL, DDS_DYNAMIC_DATA_PROPERTY_DEFAULT);
1069  SafeBinder binder(instance, arr_member, ma);
1070 
1071  DDS_UnsignedLong length = array_length(val);
1072 
1074  reinterpret_cast<typename reflex::meta::remove_all_extents<T>::type *>(&val[0]);
1075 
1076  for (DDS_UnsignedLong i = 0; i < length; ++i)
1077  {
1078  get_member_value(
1079  arr_member,
1080  MemberAccess::BY_ID(i + 1),
1081  arr[i]);
1082  }
1083  }
1084 
1085  template <class T, size_t Dim>
1086  static void get_member_value(
1087  const DDS_DynamicData & instance,
1088  const MemberAccess & ma,
1089  std::array<T, Dim> & val,
1090  typename reflex::meta::enable_if<
1093  >::value
1094  >::type * = 0)
1095  {
1096  DDS_UnsignedLong length = array_length(val);
1097 
1099  reinterpret_cast<typename reflex::meta::remove_all_extents<T>::type *>(&val[0]);
1100 
1101  DDS_ReturnCode_t rc = detail::get_array(instance, arr, &length, ma);
1102  detail::check_retcode("get_member_value: get_array error = ", rc);
1103  }
1104 
1105  template <class TagType, class... Cases>
1106  static void get_member_value(
1107  const DDS_DynamicData & instance,
1108  const MemberAccess & ma,
1110  {
1111  DDS_DynamicData inner(NULL, DDS_DYNAMIC_DATA_PROPERTY_DEFAULT);
1112  SafeBinder binder(instance, inner, ma);
1113 
1114  typedef typename match::Union<TagType, Cases...>::case_tuple_type CaseTuple;
1115  typedef TypelistIterator<
1116  CaseTuple,
1117  0,
1119 
1120  DDS_DynamicDataMemberInfo member_info;
1121  inner.get_member_info_by_index(member_info, 0 /* discriminator id */);
1122 
1123  // member_info.member_id is a DDS_Long. It seems when the discriminator
1124  // typecode is DDS_TK_SHORT or DDS_TK_CHAR, i.e., anything smaller than
1125  // DDS_Long and it is default = -1, a conversion error occurs making
1126  // the member_id = 255 or 65535 instead of -1. Hence the static_cast.
1127 
1128  int discriminator_value = static_cast<TagType>(member_info.member_id);
1129 
1130  TIter::get_union(
1131  inner,
1132  MemberAccess::BY_ID(discriminator_value),
1133  discriminator_value,
1134  val);
1135  }
1136 
1137  private :
1138  template <class Opt>
1139  static void initialize_optional(Opt & opt)
1140  {
1142  opt = temp;
1143  }
1144 
1145 #ifdef RTI_WIN32
1146  template <class... T>
1147  static void initialize_optional(boost::optional<T...> & opt)
1148  {
1149  opt = boost::in_place<T...>();
1150  }
1151 #else
1152  template <class T>
1153  static void initialize_optional(boost::optional<T> & opt)
1154  {
1155  opt = boost::in_place<T>();
1156  }
1157 #endif
1158  public:
1159 
1160  template <typename Opt>
1161  static void get_member_value(
1162  const DDS_DynamicData & instance,
1163  const MemberAccess &ma,
1164  Opt & opt,
1166  {
1167  const char * member_name
1168  = ma.access_by_id() ? NULL : ma.get_name();
1169 
1170  int id = ma.access_by_id() ?
1171  ma.get_id() : DDS_DYNAMIC_DATA_MEMBER_ID_UNSPECIFIED;
1172 
1173  if (instance.member_exists(member_name, id))
1174  {
1175  if (!opt) {
1176  initialize_optional(opt);
1177  }
1178 
1179  if(opt)
1180  get_member_value(instance, ma, *opt);
1181  }
1182  }
1183  }; // struct get_member_overload_resolution_helper
1184 
1185  template <class T>
1186  void get_member_forward(
1187  const DDS_DynamicData & instance,
1188  const MemberAccess &ma,
1189  T & val)
1190  {
1191  get_member_overload_resolution_helper::
1192  get_member_value(instance, ma, val);
1193  }
1194 
1195  } // namespace detail
1196 
1197  namespace match {
1198 
1199  template <class T>
1201  {
1203  }
1204 
1205  template <class Iter>
1207  {
1208  // iterators are always pass-by-value.
1209  return boost::make_iterator_range(begin, end);
1210  }
1211 
1212  template <size_t Bound, class Iter>
1214  make_bounded_range(Iter begin, Iter end)
1215  {
1216  // iterators are always pass-by-value.
1217  return boost::make_iterator_range(
1218  match::make_bounded_view_iterator<Bound>(begin),
1219  match::make_bounded_view_iterator<Bound>(end));
1220  }
1221 
1222  template <size_t Bound, class T>
1224  {
1225  return make_bounded_range<Bound>(t.begin(), t.end());
1226  }
1227 
1228  } // namespace match
1229 } // namespace reflex
1230 
1231 #ifndef REFLEX_NO_HEADER_ONLY
1232 #include "reflex/../../src/dd_manip.cxx"
1233 #endif
1234 
1235 #endif // RTIREFLEX_DD_MANIP_H
1236 
Definition: enable_if.h:413
Definition: disc_union.h:139
T type
Definition: enable_if.h:591
void write_dynamicdata(DDS_DynamicData &dest, const T &src)
Copies source data into the destination DDS_DynamicData instance.
Definition: reflex.h:157
Definition: disc_union.h:27
match::Range< typename Iter::reference > make_range(Iter begin, Iter end)
Definition: dd_manip.h:1206
boost::any_range< T, boost::forward_traversal_tag, T, std::ptrdiff_t > Range
Definition: enable_if.h:95
Definition: enable_if.h:679
Definition: enable_if.h:263
Definition: enable_if.h:502
void enum_cast(T &dst, DDS_Long src)
Casts integers to user-defined enumeration types.
Definition: enable_if.h:155
Definition: enable_if.h:275
const tuple_type & get_opt_tuple() const
Definition: disc_union.h:32
Definition: enable_if.h:311
#define REFLEX_DLL_EXPORT
Definition: dllexport.h:35
match::BoundedRange< typename T::reference, Bound > make_bounded_range(T &t)
Definition: dd_manip.h:1223
void read_dynamicdata(T &dest, const DDS_DynamicData &src)
Extracts data out from the source DDS_DynamicData instance and copies into the destination object of ...
Definition: reflex.h:186
#define SET_MEMBER_VALUE_DECL(TYPE)
Definition: dd_manip.h:32
#define GET_MEMBER_VALUE_DECL(TYPE)
Definition: dd_manip.h:39
Definition: enable_if.h:284
Definition: enable_if.h:631
Definition: bounded.h:24
Definition: enable_if.h:251
Definition: enable_if.h:493
Definition: enable_if.h:215
bool empty() const
Definition: disc_union.h:256
Definition: enable_if.h:353
Definition: enable_if.h:457
unsigned char octet_t
Definition: dd_extra.h:48
container_traits_impl< C, is_container< C >::value >::iterator iterator
Definition: enable_if.h:453
container_traits_impl< C, is_container< C >::value >::value_type value_type
Definition: enable_if.h:447
Definition: enable_if.h:320
Definition: bounded.h:21