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 <string.h>
39 #include <type_traits>
40 #include <limits>
41 #include <string_view>
45 
46 namespace RosMsgParser
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  // Direct access to raw data. Undefined behavior if this variant holds a STRING
122  const uint8_t* getRawStorage() const;
123 
124 private:
125 
126  union {
127  std::array<uint8_t,8> raw_data;
128  char* raw_string;
129  }_storage;
130 
131  void clearStringIfNecessary();
132 
134 };
135 
136 
137 //----------------------- Implementation ----------------------------------------------
138 
139 
140 template<typename T>
141 inline Variant::Variant(const T& value):
142  _type(OTHER)
143 {
144  static_assert (std::numeric_limits<T>::is_specialized ||
145  std::is_same<T, RosMsgParser::Time>::value ||
146  std::is_same<T, std::string_view>::value ||
147  std::is_same<T, std::string>::value
148  , "not a valid type");
149 
150  _storage.raw_string = (nullptr);
151  assign(value);
152 }
153 
154 inline Variant::Variant(const char* buffer, size_t length):_type(OTHER)
155 {
156  _storage.raw_string = (nullptr);
157  assign(buffer,length);
158 }
159 
161 {
163 }
164 
165 //-------------------------------------
166 
168  return _type;
169 }
170 
171 inline const uint8_t* Variant::getRawStorage() const {
172  return _storage.raw_data.data();
173 }
174 
175 template<typename T> inline T Variant::extract( ) const
176 {
177  static_assert (std::numeric_limits<T>::is_specialized ||
178  std::is_same<T, RosMsgParser::Time>::value
179  , "not a valid type");
180 
181  if( _type != RosMsgParser::getType<T>() )
182  {
183  throw TypeException("Variant::extract -> wrong type");
184  }
185  return * reinterpret_cast<const T*>( &_storage.raw_data[0] );
186 }
187 
188 template<> inline std::string_view Variant::extract( ) const
189 {
190 
191  if( _type != STRING )
192  {
193  throw TypeException("Variant::extract -> wrong type");
194  }
195  const uint32_t size = *(reinterpret_cast<const uint32_t*>( &_storage.raw_string[0] ));
196  char* data = static_cast<char*>(&_storage.raw_string[4]);
197  return std::string_view(data, size);
198 }
199 
200 template<> inline std::string Variant::extract( ) const
201 {
202  if( _type != STRING )
203  {
204  throw TypeException("Variant::extract -> wrong type");
205  }
206  const uint32_t size = *(reinterpret_cast<const uint32_t*>( &_storage.raw_string[0] ));
207  char* data = static_cast<char*>(&_storage.raw_string[4]);
208  return std::string(data, size);
209 }
210 
211 //-------------------------------------
212 
213 template <typename T> inline void Variant::assign(const T& value)
214 {
215  static_assert (std::numeric_limits<T>::is_specialized ||
216  std::is_same<T, RosMsgParser::Time>::value
217  , "not a valid type");
218 
220  _type = RosMsgParser::getType<T>() ;
221  *reinterpret_cast<T *>( &_storage.raw_data[0] ) = value;
222 }
223 
225 {
226  if( _storage.raw_string && _type == STRING)
227  {
228  delete [] _storage.raw_string;
229  _storage.raw_string = nullptr;
230  }
231 }
232 
233 inline void Variant::assign(const char* buffer, size_t size)
234 {
236  _type = STRING;
237 
238  _storage.raw_string = new char[size+5];
239  *reinterpret_cast<uint32_t *>( &_storage.raw_string[0] ) = size;
240  memcpy(&_storage.raw_string[4] , buffer, size );
241  _storage.raw_string[size+4] = '\0';
242 }
243 
244 
245 
246 template <> inline void Variant::assign(const std::string_view& value)
247 {
248  assign( value.data(), value.size() );
249 }
250 
251 template <> inline void Variant::assign(const std::string& value)
252 {
253  assign( value.data(), value.size() );
254 }
255 
256 //-------------------------------------
257 
258 template<typename DST> inline DST Variant::convert() const
259 {
260  static_assert (std::numeric_limits<DST>::is_specialized ||
261  std::is_same<DST, RosMsgParser::Time>::value
262  , "not a valid type");
263 
264  using namespace RosMsgParser::details;
265  DST target;
266 
267  const auto& raw_data = &_storage.raw_data[0];
268  //----------
269  switch( _type )
270  {
271  case CHAR:
272  case INT8: convert_impl<int8_t, DST>(*reinterpret_cast<const int8_t*>( raw_data), target ); break;
273 
274  case INT16: convert_impl<int16_t, DST>(*reinterpret_cast<const int16_t*>( raw_data), target ); break;
275  case INT32: convert_impl<int32_t, DST>(*reinterpret_cast<const int32_t*>( raw_data), target ); break;
276  case INT64: convert_impl<int64_t, DST>(*reinterpret_cast<const int64_t*>( raw_data), target ); break;
277 
278  case BOOL:
279  case BYTE:
280  case UINT8: convert_impl<uint8_t, DST>(*reinterpret_cast<const uint8_t*>( raw_data), target ); break;
281 
282  case UINT16: convert_impl<uint16_t, DST>(*reinterpret_cast<const uint16_t*>( raw_data), target ); break;
283  case UINT32: convert_impl<uint32_t, DST>(*reinterpret_cast<const uint32_t*>( raw_data), target ); break;
284  case UINT64: convert_impl<uint64_t, DST>(*reinterpret_cast<const uint64_t*>( raw_data), target ); break;
285 
286  case FLOAT32: convert_impl<float, DST>(*reinterpret_cast<const float*>( raw_data), target ); break;
287  case FLOAT64: convert_impl<double, DST>(*reinterpret_cast<const double*>( raw_data), target ); break;
288 
289  case STRING: {
290  throw TypeException("String will not be converted to a numerical value implicitly");
291  } break;
292 
293  case DURATION:
294  case TIME: {
295  throw TypeException("ros::Duration and ros::Time can be converted only to double (will be seconds)");
296  } break;
297 
298  default: throw TypeException("Variant::convert -> cannot convert type" + std::to_string(_type)); break;
299 
300  }
301  return target;
302 }
303 
304 template<> inline double Variant::convert() const
305 {
306  using namespace RosMsgParser::details;
307  double target = 0;
308  const auto& raw_data = &_storage.raw_data[0];
309  //----------
310  switch( _type )
311  {
312  case CHAR:
313  case INT8: convert_impl<int8_t, double>(*reinterpret_cast<const int8_t*>( raw_data), target ); break;
314 
315  case INT16: convert_impl<int16_t, double>(*reinterpret_cast<const int16_t*>( raw_data), target ); break;
316  case INT32: convert_impl<int32_t, double>(*reinterpret_cast<const int32_t*>( raw_data), target ); break;
317  case INT64: convert_impl<int64_t, double>(*reinterpret_cast<const int64_t*>( raw_data), target ); break;
318 
319  case BOOL:
320  case BYTE:
321  case UINT8: convert_impl<uint8_t, double>(*reinterpret_cast<const uint8_t*>( raw_data), target ); break;
322 
323  case UINT16: convert_impl<uint16_t, double>(*reinterpret_cast<const uint16_t*>( raw_data), target ); break;
324  case UINT32: convert_impl<uint32_t, double>(*reinterpret_cast<const uint32_t*>( raw_data), target ); break;
325  case UINT64: convert_impl<uint64_t, double>(*reinterpret_cast<const uint64_t*>( raw_data), target ); break;
326 
327  case FLOAT32: convert_impl<float, double>(*reinterpret_cast<const float*>( raw_data), target ); break;
328  case FLOAT64: return extract<double>();
329 
330  case STRING: {
331  throw TypeException("String will not be converted to a double implicitly");
332  }break;
333 
334  case DURATION:
335  case TIME: {
336  RosMsgParser::Time tmp = extract<RosMsgParser::Time>();
337  target = tmp.toSec();
338  }break;
339 
340  default: throw TypeException("Variant::convert -> cannot convert type" + std::to_string(_type));
341 
342  }
343  return target;
344 }
345 
346 template<> inline RosMsgParser::Time Variant::convert() const
347 {
348  if( _type != TIME )
349  {
350  throw TypeException("Variant::convert -> cannot convert RosMsgParser::Time");
351  }
352  return extract<RosMsgParser::Time>();
353 }
354 
355 
356 template<> inline std::string Variant::convert() const
357 {
358  if( _type != STRING )
359  {
360  throw TypeException("Variant::convert -> cannot convert to std::string");
361  }
362  return extract<std::string>();
363 }
364 
365 } //end namespace
366 
367 
368 #endif // VARIANT_H
const uint8_t * getRawStorage() const
Definition: variant.hpp:171
Variant(Variant &&other)
Definition: variant.hpp:76
void assign(const T &value)
Definition: variant.hpp:213
std::array< uint8_t, 8 > raw_data
Definition: variant.hpp:127
BuiltinType _type
Definition: variant.hpp:133
basic_string_view< char > string_view
Definition: core.h:522
Definition: core.h:760
union RosMsgParser::Variant::@55 _storage
NLOHMANN_BASIC_JSON_TPL_DECLARATION void swap(nlohmann::NLOHMANN_BASIC_JSON_TPL &j1, nlohmann::NLOHMANN_BASIC_JSON_TPL &j2) noexcept(//NOLINT(readability-inconsistent-declaration-parameter-name) is_nothrow_move_constructible< nlohmann::NLOHMANN_BASIC_JSON_TPL >::value &&//NOLINT(misc-redundant-expression) is_nothrow_move_assignable< nlohmann::NLOHMANN_BASIC_JSON_TPL >::value)
exchanges the values of two JSON objects
Definition: json.hpp:21884
Variant(const Variant &other)
Definition: variant.hpp:61
Variant & operator=(const Variant &other)
Definition: variant.hpp:90
void clearStringIfNecessary()
Definition: variant.hpp:224
BuiltinType getTypeID() const
Definition: variant.hpp:167
span_constexpr std::size_t size(span< T, Extent > const &spn)
Definition: span.hpp:1485
Definition: core.h:1131
Definition: format.h:895


plotjuggler
Author(s): Davide Faconti
autogenerated on Mon Jun 19 2023 03:12:53