safe_any.hpp
Go to the documentation of this file.
1 #ifndef SAFE_ANY_VARNUMBER_H
2 #define SAFE_ANY_VARNUMBER_H
3 
4 #include <exception>
5 #include <algorithm>
6 #include <iostream>
7 #include <chrono>
8 #include <string>
9 #include <cstring>
10 #include <type_traits>
11 #include "any.hpp"
12 #include "demangle_util.h"
13 #include "convert_impl.hpp"
14 #include "expected.hpp"
15 #include "strcat.hpp"
16 #include "strcat.hpp"
17 
18 namespace BT
19 {
20 // Rational: since type erased numbers will always use at least 8 bytes
21 // it is faster to cast everything to either double, uint64_t or int64_t.
22 class Any
23 {
24  template <typename T>
25  using EnableIntegral =
26  typename std::enable_if<std::is_integral<T>::value || std::is_enum<T>::value>::type*;
27 
28  template <typename T>
29  using EnableNonIntegral =
30  typename std::enable_if<!std::is_integral<T>::value && !std::is_enum<T>::value>::type*;
31 
32  template <typename T>
33  using EnableString = typename std::enable_if<std::is_same<T, std::string>::value>::type*;
34 
35  template <typename T>
36  using EnableArithmetic = typename std::enable_if<std::is_arithmetic<T>::value>::type*;
37 
38  template <typename T>
39  using EnableEnum = typename std::enable_if<std::is_enum<T>::value>::type*;
40 
41  template <typename T>
42  using EnableUnknownType =
43  typename std::enable_if<!std::is_arithmetic<T>::value && !std::is_enum<T>::value &&
44  !std::is_same<T, std::string>::value>::type*;
45 
46  public:
47  Any(): _original_type(nullptr)
48  {
49  }
50 
51  ~Any() = default;
52 
53  Any(const Any& other) : _any(other._any), _original_type( other._original_type )
54  {
55  }
56 
57  Any(Any&& other) : _any( std::move(other._any) ), _original_type( other._original_type )
58  {
59  }
60 
61  explicit Any(const double& value) : _any(value), _original_type( &typeid(double) )
62  {
63  }
64 
65  explicit Any(const uint64_t& value) : _any(value), _original_type( &typeid(uint64_t) )
66  {
67  }
68 
69  explicit Any(const float& value) : _any(double(value)), _original_type( &typeid(float) )
70  {
71  }
72 
73  explicit Any(const std::string& str) : _any(SafeAny::SimpleString(str)), _original_type( &typeid(std::string) )
74  {
75  }
76 
77  explicit Any(const char* str) : _any(SafeAny::SimpleString(str)), _original_type( &typeid(std::string) )
78  {
79  }
80 
81  explicit Any(const SafeAny::SimpleString& str) : _any(str), _original_type( &typeid(std::string) )
82  {
83  }
84 
85  // all the other integrals are casted to int64_t
86  template <typename T>
87  explicit Any(const T& value, EnableIntegral<T> = 0) : _any(int64_t(value)), _original_type( &typeid(T) )
88  {
89  }
90 
91  // default for other custom types
92  template <typename T>
93  explicit Any(const T& value, EnableNonIntegral<T> = 0) : _any(value), _original_type( &typeid(T) )
94  {
95  }
96 
97  Any& operator = (const Any& other)
98  {
99  this->_any = other._any;
100  this->_original_type = other._original_type;
101  return *this;
102  }
103 
104  bool isNumber() const
105  {
106  return _any.type() == typeid(int64_t) ||
107  _any.type() == typeid(uint64_t) ||
108  _any.type() == typeid(double);
109  }
110 
111  bool isString() const
112  {
113  return _any.type() == typeid(SafeAny::SimpleString);
114  }
115 
116  // this is different from any_cast, because if allows safe
117  // conversions between arithmetic values.
118  template <typename T>
119  T cast() const
120  {
121  if( _any.empty() )
122  {
123  throw std::runtime_error("Any::cast failed because it is empty");
124  }
125  if (_any.type() == typeid(T))
126  {
127  return linb::any_cast<T>(_any);
128  }
129  else
130  {
131  auto res = convert<T>();
132  if( !res )
133  {
134  throw std::runtime_error( res.error() );
135  }
136  return res.value();
137  }
138  }
139 
140  const std::type_info& type() const noexcept
141  {
142  return *_original_type;
143  }
144 
145  const std::type_info& castedType() const noexcept
146  {
147  return _any.type();
148  }
149 
150  bool empty() const noexcept
151  {
152  return _any.empty();
153  }
154 
155  private:
157  const std::type_info* _original_type;
158 
159  //----------------------------
160 
161  template <typename DST>
162  nonstd::expected<DST,std::string> convert(EnableString<DST> = 0) const
163  {
164  const auto& type = _any.type();
165 
166  if (type == typeid(SafeAny::SimpleString))
167  {
168  return linb::any_cast<SafeAny::SimpleString>(_any).toStdString();
169  }
170  else if (type == typeid(int64_t))
171  {
172  return std::to_string(linb::any_cast<int64_t>(_any));
173  }
174  else if (type == typeid(uint64_t))
175  {
176  return std::to_string(linb::any_cast<uint64_t>(_any));
177  }
178  else if (type == typeid(double))
179  {
180  return std::to_string(linb::any_cast<double>(_any));
181  }
182 
183  return nonstd::make_unexpected( errorMsg<DST>() );
184  }
185 
186  template <typename DST>
187  nonstd::expected<DST,std::string> convert(EnableArithmetic<DST> = 0) const
188  {
189  using SafeAny::details::convertNumber;
190  DST out;
191 
192  const auto& type = _any.type();
193 
194  if (type == typeid(int64_t))
195  {
196  convertNumber<int64_t, DST>(linb::any_cast<int64_t>(_any), out);
197  }
198  else if (type == typeid(uint64_t))
199  {
200  convertNumber<uint64_t, DST>(linb::any_cast<uint64_t>(_any), out);
201  }
202  else if (type == typeid(double))
203  {
204  convertNumber<double, DST>(linb::any_cast<double>(_any), out);
205  }
206  else{
207  return nonstd::make_unexpected( errorMsg<DST>() );
208  }
209  return out;
210  }
211 
212  template <typename DST>
213  nonstd::expected<DST,std::string> convert(EnableEnum<DST> = 0) const
214  {
215  using SafeAny::details::convertNumber;
216 
217  const auto& type = _any.type();
218 
219  if (type == typeid(int64_t))
220  {
221  uint64_t out = linb::any_cast<int64_t>(_any);
222  return static_cast<DST>(out);
223  }
224  else if (type == typeid(uint64_t))
225  {
226  uint64_t out = linb::any_cast<uint64_t>(_any);
227  return static_cast<DST>(out);
228  }
229 
230  return nonstd::make_unexpected( errorMsg<DST>() );
231  }
232 
233  template <typename DST>
234  nonstd::expected<DST,std::string> convert(EnableUnknownType<DST> = 0) const
235  {
236  return nonstd::make_unexpected( errorMsg<DST>() );
237  }
238 
239  template <typename T>
240  std::string errorMsg() const
241  {
242  return StrCat("[Any::convert]: no known safe conversion between [",
243  demangle( _any.type() ), "] and [", demangle( typeid(T) ),"]");
244  }
245 };
246 
247 } // end namespace BT
248 
249 #endif // VARNUMBER_H
T cast() const
Definition: safe_any.hpp:119
bool empty() const noexcept
Returns true if *this has no contained object, otherwise false.
Definition: any.hpp:123
const std::type_info & type() const noexcept
Definition: safe_any.hpp:140
Any(const SafeAny::SimpleString &str)
Definition: safe_any.hpp:81
Any(const float &value)
Definition: safe_any.hpp:69
typename std::enable_if< std::is_enum< T >::value >::type * EnableEnum
Definition: safe_any.hpp:39
Any(Any &&other)
Definition: safe_any.hpp:57
Any(const T &value, EnableNonIntegral< T >=0)
Definition: safe_any.hpp:93
Definition: any.hpp:455
ValueType any_cast(const any &operand)
Performs *any_cast<add_const_t<remove_reference_t<ValueType>>>(&operand), or throws bad_any_cast on f...
Definition: any.hpp:386
Any(const double &value)
Definition: safe_any.hpp:61
~Any()=default
linb::any _any
Definition: safe_any.hpp:156
nonstd::expected< DST, std::string > convert(EnableEnum< DST >=0) const
Definition: safe_any.hpp:213
std::string demangle(char const *name)
Definition: demangle_util.h:78
const std::type_info & castedType() const noexcept
Definition: safe_any.hpp:145
Any & operator=(const Any &other)
Definition: safe_any.hpp:97
bool empty() const noexcept
Definition: safe_any.hpp:150
Any(const uint64_t &value)
Definition: safe_any.hpp:65
std::string StrCat()
Definition: strcat.hpp:47
nonstd::expected< DST, std::string > convert(EnableUnknownType< DST >=0) const
Definition: safe_any.hpp:234
bool isNumber() const
Definition: safe_any.hpp:104
typename std::enable_if< std::is_integral< T >::value||std::is_enum< T >::value >::type * EnableIntegral
Definition: safe_any.hpp:26
const char * str
Definition: util.h:257
typename std::enable_if< std::is_same< T, std::string >::value >::type * EnableString
Definition: safe_any.hpp:33
const std::type_info * _original_type
Definition: safe_any.hpp:157
nonstd::expected< DST, std::string > convert(EnableArithmetic< DST >=0) const
Definition: safe_any.hpp:187
const std::type_info & type() const noexcept
If *this has a contained object of type T, typeid(T); otherwise typeid(void).
Definition: any.hpp:129
Any(const T &value, EnableIntegral< T >=0)
Definition: safe_any.hpp:87
bool isString() const
Definition: safe_any.hpp:111
Any(const Any &other)
Definition: safe_any.hpp:53
nonstd::expected< DST, std::string > convert(EnableString< DST >=0) const
Definition: safe_any.hpp:162
std::basic_string< CharT, Traits > to_string(basic_string_view< CharT, Traits > v)
Any(const char *str)
Definition: safe_any.hpp:77
typename std::enable_if<!std::is_arithmetic< T >::value &&!std::is_enum< T >::value &&!std::is_same< T, std::string >::value >::type * EnableUnknownType
Definition: safe_any.hpp:44
std::string errorMsg() const
Definition: safe_any.hpp:240
typename std::enable_if<!std::is_integral< T >::value &&!std::is_enum< T >::value >::type * EnableNonIntegral
Definition: safe_any.hpp:30
Any(const std::string &str)
Definition: safe_any.hpp:73
typename std::enable_if< std::is_arithmetic< T >::value >::type * EnableArithmetic
Definition: safe_any.hpp:36


behaviortree_cpp
Author(s): Michele Colledanchise, Davide Faconti
autogenerated on Sat Jun 8 2019 18:04:05