variant.hpp
Go to the documentation of this file.
1 /*********************************************************************
2 * Software License Agreement (BSD License)
3 *
4 * Copyright 2016-2017 Davide Faconti
5 * All rights reserved.
6 *
7 * Redistribution and use in source and binary forms, with or without
8 * modification, are permitted provided that the following conditions
9 * are met:
10 *
11 * * Redistributions of source code must retain the above copyright
12 * notice, this list of conditions and the following disclaimer.
13 * * Redistributions in binary form must reproduce the above
14 * copyright notice, this list of conditions and the following
15 * disclaimer in the documentation and/or other materials provided
16 * with the distribution.
17 * * Neither the name of Willow Garage, Inc. nor the names of its
18 * contributors may be used to endorse or promote products derived
19 * from this software without specific prior written permission.
20 *
21 * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
22 * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
23 * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS
24 * FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE
25 * COPYRIGHT OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT,
26 * INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING,
27 * BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES;
28 * LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER
29 * CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
30 * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN
31 * ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE
32 * POSSIBILITY OF SUCH DAMAGE.
33 * *******************************************************************/
34 
35 #ifndef VARIANT_H
36 #define VARIANT_H
37 
38 #include <type_traits>
39 #include <limits>
44 
45 
46 namespace RosIntrospection
47 {
48 
49 class Variant
50 {
51 
52 public:
53 
54  Variant() {
55  _type = OTHER;
56  _storage.raw_string = nullptr;
57  }
58 
59  ~Variant();
60 
61  Variant(const Variant& other): _type(OTHER)
62  {
63  if( other._type == STRING)
64  {
65  const char* raw = other._storage.raw_string;
66  const uint32_t size = *(reinterpret_cast<const uint32_t*>( &raw[0] ));
67  const char* data = (&raw[4]);
68  assign( data, size );
69  }
70  else{
71  _type = other._type;
72  _storage.raw_data = other._storage.raw_data;
73  }
74  }
75 
77  {
78  if( other._type == STRING)
79  {
80  _storage.raw_string = nullptr;
81  std::swap( _storage.raw_string, other._storage.raw_string);
82  std::swap( _type, other._type);
83  }
84  else{
85  _type = other._type;
86  _storage.raw_data = other._storage.raw_data;
87  }
88  }
89 
90  Variant& operator = (const Variant& other)
91  {
92  if( other._type == STRING)
93  {
94  const char* raw = other._storage.raw_string;
95  const uint32_t size = *(reinterpret_cast<const uint32_t*>( &raw[0] ));
96  const char* data = (&raw[4]);
97  assign( data, size );
98  }
99  else{
100  _type = other._type;
101  _storage.raw_data = other._storage.raw_data;
102  }
103  return *this;
104  }
105 
106  template<typename T> Variant(const T& value);
107 
108  // specialization for raw string
109  Variant(const char* buffer, size_t length);
110 
111  BuiltinType getTypeID() const;
112 
113  template<typename T> T convert( ) const;
114 
115  template<typename T> T extract( ) const;
116 
117  template <typename T> void assign(const T& value);
118 
119  void assign(const char* buffer, size_t length);
120 
121 private:
122 
123  union {
124  std::array<uint8_t,8> raw_data;
125  char* raw_string;
126  }_storage;
127 
128  void clearStringIfNecessary();
129 
131 };
132 
133 
134 //----------------------- Implementation ----------------------------------------------
135 
136 
137 template<typename T>
138 inline Variant::Variant(const T& value):
139  _type(OTHER)
140 {
141  static_assert (std::numeric_limits<T>::is_specialized ||
142  std::is_same<T, ros::Time>::value ||
143  std::is_same<T, absl::string_view>::value ||
144  std::is_same<T, std::string>::value ||
145  std::is_same<T, ros::Duration>::value
146  , "not a valid type");
147 
148  _storage.raw_string = (nullptr);
149  assign(value);
150 }
151 
152 inline Variant::Variant(const char* buffer, size_t length):_type(OTHER)
153 {
154  _storage.raw_string = (nullptr);
155  assign(buffer,length);
156 }
157 
159 {
161 }
162 
163 //-------------------------------------
164 
166  return _type;
167 }
168 
169 template<typename T> inline T Variant::extract( ) const
170 {
171  static_assert (std::numeric_limits<T>::is_specialized ||
172  std::is_same<T, ros::Time>::value ||
173  std::is_same<T, ros::Duration>::value
174  , "not a valid type");
175 
176  if( _type != RosIntrospection::getType<T>() )
177  {
178  throw TypeException("Variant::extract -> wrong type");
179  }
180  return * reinterpret_cast<const T*>( &_storage.raw_data[0] );
181 }
182 
183 template<> inline absl::string_view Variant::extract( ) const
184 {
185 
186  if( _type != STRING )
187  {
188  throw TypeException("Variant::extract -> wrong type");
189  }
190  const uint32_t size = *(reinterpret_cast<const uint32_t*>( &_storage.raw_string[0] ));
191  char* data = static_cast<char*>(&_storage.raw_string[4]);
192  return absl::string_view(data, size);
193 }
194 
195 template<> inline std::string Variant::extract( ) const
196 {
197  if( _type != STRING )
198  {
199  throw TypeException("Variant::extract -> wrong type");
200  }
201  const uint32_t size = *(reinterpret_cast<const uint32_t*>( &_storage.raw_string[0] ));
202  char* data = static_cast<char*>(&_storage.raw_string[4]);
203  return std::string(data, size);
204 }
205 
206 //-------------------------------------
207 
208 template <typename T> inline void Variant::assign(const T& value)
209 {
210  static_assert (std::numeric_limits<T>::is_specialized ||
211  std::is_same<T, ros::Time>::value ||
212  std::is_same<T, ros::Duration>::value
213  , "not a valid type");
214 
216  _type = RosIntrospection::getType<T>() ;
217  *reinterpret_cast<T *>( &_storage.raw_data[0] ) = value;
218 }
219 
221 {
222  if( _storage.raw_string && _type == STRING)
223  {
224  delete [] _storage.raw_string;
225  _storage.raw_string = nullptr;
226  }
227 }
228 
229 inline void Variant::assign(const char* buffer, size_t size)
230 {
232  _type = STRING;
233 
234  _storage.raw_string = new char[size+5];
235  *reinterpret_cast<uint32_t *>( &_storage.raw_string[0] ) = size;
236  memcpy(&_storage.raw_string[4] , buffer, size );
237  _storage.raw_string[size+4] = '\0';
238 }
239 
240 
241 
242 template <> inline void Variant::assign(const absl::string_view& value)
243 {
244  assign( value.data(), value.size() );
245 }
246 
247 template <> inline void Variant::assign(const std::string& value)
248 {
249  assign( value.data(), value.size() );
250 }
251 
252 //-------------------------------------
253 
254 template<typename DST> inline DST Variant::convert() const
255 {
256  static_assert (std::numeric_limits<DST>::is_specialized ||
257  std::is_same<DST, ros::Time>::value ||
258  std::is_same<DST, ros::Duration>::value
259  , "not a valid type");
260 
261  using namespace RosIntrospection::details;
262  DST target;
263 
264  const auto& raw_data = &_storage.raw_data[0];
265  //----------
266  switch( _type )
267  {
268  case CHAR:
269  case INT8: convert_impl<int8_t, DST>(*reinterpret_cast<const int8_t*>( raw_data), target ); break;
270 
271  case INT16: convert_impl<int16_t, DST>(*reinterpret_cast<const int16_t*>( raw_data), target ); break;
272  case INT32: convert_impl<int32_t, DST>(*reinterpret_cast<const int32_t*>( raw_data), target ); break;
273  case INT64: convert_impl<int64_t, DST>(*reinterpret_cast<const int64_t*>( raw_data), target ); break;
274 
275  case BOOL:
276  case BYTE:
277  case UINT8: convert_impl<uint8_t, DST>(*reinterpret_cast<const uint8_t*>( raw_data), target ); break;
278 
279  case UINT16: convert_impl<uint16_t, DST>(*reinterpret_cast<const uint16_t*>( raw_data), target ); break;
280  case UINT32: convert_impl<uint32_t, DST>(*reinterpret_cast<const uint32_t*>( raw_data), target ); break;
281  case UINT64: convert_impl<uint64_t, DST>(*reinterpret_cast<const uint64_t*>( raw_data), target ); break;
282 
283  case FLOAT32: convert_impl<float, DST>(*reinterpret_cast<const float*>( raw_data), target ); break;
284  case FLOAT64: convert_impl<double, DST>(*reinterpret_cast<const double*>( raw_data), target ); break;
285 
286  case STRING: {
287  throw TypeException("String will not be converted to a numerical value implicitly");
288  } break;
289 
290  case DURATION:
291  case TIME: {
292  throw TypeException("ros::Duration and ros::Time can be converted only to double (will be seconds)");
293  } break;
294 
295  default: throw TypeException("Variant::convert -> cannot convert type" + std::to_string(_type)); break;
296 
297  }
298  return target;
299 }
300 
301 template<> inline double Variant::convert() const
302 {
303  using namespace RosIntrospection::details;
304  double target = 0;
305  const auto& raw_data = &_storage.raw_data[0];
306  //----------
307  switch( _type )
308  {
309  case CHAR:
310  case INT8: convert_impl<int8_t, double>(*reinterpret_cast<const int8_t*>( raw_data), target ); break;
311 
312  case INT16: convert_impl<int16_t, double>(*reinterpret_cast<const int16_t*>( raw_data), target ); break;
313  case INT32: convert_impl<int32_t, double>(*reinterpret_cast<const int32_t*>( raw_data), target ); break;
314  case INT64: convert_impl<int64_t, double>(*reinterpret_cast<const int64_t*>( raw_data), target ); break;
315 
316  case BOOL:
317  case BYTE:
318  case UINT8: convert_impl<uint8_t, double>(*reinterpret_cast<const uint8_t*>( raw_data), target ); break;
319 
320  case UINT16: convert_impl<uint16_t, double>(*reinterpret_cast<const uint16_t*>( raw_data), target ); break;
321  case UINT32: convert_impl<uint32_t, double>(*reinterpret_cast<const uint32_t*>( raw_data), target ); break;
322  case UINT64: convert_impl<uint64_t, double>(*reinterpret_cast<const uint64_t*>( raw_data), target ); break;
323 
324  case FLOAT32: convert_impl<float, double>(*reinterpret_cast<const float*>( raw_data), target ); break;
325  case FLOAT64: return extract<double>();
326 
327  case STRING: {
328  throw TypeException("String will not be converted to a double implicitly");
329  }break;
330 
331  case DURATION: {
332  ros::Duration tmp = extract<ros::Duration>();
333  target = tmp.toSec();
334  }break;
335 
336  case TIME: {
337  ros::Time tmp = extract<ros::Time>();
338  target = tmp.toSec();
339  }break;
340 
341  default: throw TypeException("Variant::convert -> cannot convert type" + std::to_string(_type));
342 
343  }
344  return target;
345 }
346 
347 template<> inline ros::Time Variant::convert() const
348 {
349  if( _type != TIME )
350  {
351  throw TypeException("Variant::convert -> cannot convert ros::Time");
352  }
353  return extract<ros::Time>();
354 }
355 
356 template<> inline ros::Duration Variant::convert() const
357 {
358  if( _type != DURATION )
359  {
360  throw TypeException("Variant::convert -> cannot convert ros::Duration");
361  }
362  return extract<ros::Duration>();
363 }
364 
365 
366 template<> inline std::string Variant::convert() const
367 {
368  if( _type != STRING )
369  {
370  throw TypeException("Variant::convert -> cannot convert to std::string");
371  }
372  return extract<std::string>();
373 }
374 
375 } //end namespace
376 
377 
378 #endif // VARIANT_H
union RosIntrospection::Variant::@0 _storage
void assign(const T &value)
Definition: variant.hpp:208
constexpr size_type size() const noexcept
T value
BuiltinType getTypeID() const
Definition: variant.hpp:165
Variant & operator=(const Variant &other)
Definition: variant.hpp:90
uintptr_t size
constexpr const_pointer data() const noexcept
Variant(const Variant &other)
Definition: variant.hpp:61
std::array< uint8_t, 8 > raw_data
Definition: variant.hpp:124
empty_struct data[sizeof(T)/sizeof(empty_struct)]
std::size_t length
Variant(Variant &&other)
Definition: variant.hpp:76


ros_type_introspection
Author(s): Davide Faconti
autogenerated on Thu May 16 2019 02:39:09