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  static_assert(!std::is_reference<T>::value, "Any can not contain references");
96  }
97 
98  Any& operator = (const Any& other)
99  {
100  this->_any = other._any;
101  this->_original_type = other._original_type;
102  return *this;
103  }
104 
105  bool isNumber() const
106  {
107  return _any.type() == typeid(int64_t) ||
108  _any.type() == typeid(uint64_t) ||
109  _any.type() == typeid(double);
110  }
111 
112  bool isString() const
113  {
114  return _any.type() == typeid(SafeAny::SimpleString);
115  }
116 
117  // this is different from any_cast, because if allows safe
118  // conversions between arithmetic values.
119  template <typename T>
120  T cast() const
121  {
122  static_assert(!std::is_reference<T>::value, "Any::cast uses value semantic, can not cast to reference");
123 
124  if( _any.empty() )
125  {
126  throw std::runtime_error("Any::cast failed because it is empty");
127  }
128  if (_any.type() == typeid(T))
129  {
130  return linb::any_cast<T>(_any);
131  }
132  else
133  {
134  auto res = convert<T>();
135  if( !res )
136  {
137  throw std::runtime_error( res.error() );
138  }
139  return res.value();
140  }
141  }
142 
143  const std::type_info& type() const noexcept
144  {
145  return *_original_type;
146  }
147 
148  const std::type_info& castedType() const noexcept
149  {
150  return _any.type();
151  }
152 
153  bool empty() const noexcept
154  {
155  return _any.empty();
156  }
157 
158  private:
160  const std::type_info* _original_type;
161 
162  //----------------------------
163 
164  template <typename DST>
165  nonstd::expected<DST,std::string> convert(EnableString<DST> = 0) const
166  {
167  const auto& type = _any.type();
168 
169  if (type == typeid(SafeAny::SimpleString))
170  {
171  return linb::any_cast<SafeAny::SimpleString>(_any).toStdString();
172  }
173  else if (type == typeid(int64_t))
174  {
175  return std::to_string(linb::any_cast<int64_t>(_any));
176  }
177  else if (type == typeid(uint64_t))
178  {
179  return std::to_string(linb::any_cast<uint64_t>(_any));
180  }
181  else if (type == typeid(double))
182  {
183  return std::to_string(linb::any_cast<double>(_any));
184  }
185 
186  return nonstd::make_unexpected( errorMsg<DST>() );
187  }
188 
189  template <typename DST>
190  nonstd::expected<DST,std::string> convert(EnableArithmetic<DST> = 0) const
191  {
192  using SafeAny::details::convertNumber;
193  DST out;
194 
195  const auto& type = _any.type();
196 
197  if (type == typeid(int64_t))
198  {
199  convertNumber<int64_t, DST>(linb::any_cast<int64_t>(_any), out);
200  }
201  else if (type == typeid(uint64_t))
202  {
203  convertNumber<uint64_t, DST>(linb::any_cast<uint64_t>(_any), out);
204  }
205  else if (type == typeid(double))
206  {
207  convertNumber<double, DST>(linb::any_cast<double>(_any), out);
208  }
209  else{
210  return nonstd::make_unexpected( errorMsg<DST>() );
211  }
212  return out;
213  }
214 
215  template <typename DST>
216  nonstd::expected<DST,std::string> convert(EnableEnum<DST> = 0) const
217  {
218  using SafeAny::details::convertNumber;
219 
220  const auto& type = _any.type();
221 
222  if (type == typeid(int64_t))
223  {
224  uint64_t out = linb::any_cast<int64_t>(_any);
225  return static_cast<DST>(out);
226  }
227  else if (type == typeid(uint64_t))
228  {
229  uint64_t out = linb::any_cast<uint64_t>(_any);
230  return static_cast<DST>(out);
231  }
232 
233  return nonstd::make_unexpected( errorMsg<DST>() );
234  }
235 
236  template <typename DST>
237  nonstd::expected<DST,std::string> convert(EnableUnknownType<DST> = 0) const
238  {
239  return nonstd::make_unexpected( errorMsg<DST>() );
240  }
241 
242  template <typename T>
243  std::string errorMsg() const
244  {
245  return StrCat("[Any::convert]: no known safe conversion between [",
246  demangle( _any.type() ), "] and [", demangle( typeid(T) ),"]");
247  }
248 };
249 
250 } // end namespace BT
251 
252 #endif // VARNUMBER_H
nonstd::expected< DST, std::string > convert(EnableArithmetic< DST >=0) const
Definition: safe_any.hpp:190
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:143
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
T cast() const
Definition: safe_any.hpp:120
nonstd::expected< DST, std::string > convert(EnableUnknownType< DST >=0) const
Definition: safe_any.hpp:237
linb::any _any
Definition: safe_any.hpp:159
bool isNumber() const
Definition: safe_any.hpp:105
std::string demangle(char const *name)
Definition: demangle_util.h:72
const std::type_info & castedType() const noexcept
Definition: safe_any.hpp:148
std::string errorMsg() const
Definition: safe_any.hpp:243
bool isString() const
Definition: safe_any.hpp:112
Any & operator=(const Any &other)
Definition: safe_any.hpp:98
bool empty() const noexcept
Definition: safe_any.hpp:153
Any(const uint64_t &value)
Definition: safe_any.hpp:65
std::string StrCat()
Definition: strcat.hpp:47
typename std::enable_if< std::is_integral< T >::value||std::is_enum< T >::value >::type * EnableIntegral
Definition: safe_any.hpp:26
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:160
nonstd::expected< DST, std::string > convert(EnableString< DST >=0) const
Definition: safe_any.hpp:165
nonstd::expected< DST, std::string > convert(EnableEnum< DST >=0) const
Definition: safe_any.hpp:216
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
Any(const Any &other)
Definition: safe_any.hpp:53
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
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_v3
Author(s): Michele Colledanchise, Davide Faconti
autogenerated on Mon Jul 3 2023 02:50:14