2
3
4
5
6
7
8
9
10
11
15#if __has_include
(<charconv>)
19#include "behaviortree_cpp/contrib/any.hpp"
20#include "behaviortree_cpp/contrib/expected.hpp"
21#include "behaviortree_cpp/utils/convert_impl.hpp"
22#include "behaviortree_cpp/utils/demangle_util.h"
23#include "behaviortree_cpp/utils/polymorphic_cast_registry.hpp"
24#include "behaviortree_cpp/utils/strcat.hpp"
34static std::type_index UndefinedAnyType =
typeid(
nullptr);
75 nonstd::expected<T, std::string> stringToNumber()
const;
78 Any() : _original_type(UndefinedAnyType)
83 Any(
const Any& other) : _any(other._any), _original_type(other._original_type)
86 Any(
Any&& other)
noexcept
87 : _any(std::move(other._any)), _original_type(other._original_type)
90 explicit Any(
const double& value) : _any(value), _original_type(
typeid(
double))
93 explicit Any(
const uint64_t& value) : _any(value), _original_type(
typeid(uint64_t))
96 explicit Any(
const float& value) : _any(
double(value)), _original_type(
typeid(
float))
99 explicit Any(
const std::string& str)
100 : _any(SafeAny::SimpleString(str)), _original_type(
typeid(std::string))
103 explicit Any(
const char* str)
104 : _any(SafeAny::SimpleString(str)), _original_type(
typeid(std::string))
108 : _any(str), _original_type(
typeid(std::string))
111 explicit Any(
const std::string_view& str)
112 : _any(SafeAny::SimpleString(str)), _original_type(
typeid(std::string))
116 template <
typename T>
117 explicit Any(
const T& value, EnableIntegral<T> = 0)
118 : _any(int64_t(value)), _original_type(
typeid(T))
121 Any(
const std::type_index& type) : _original_type(type)
125 template <
typename T>
126 explicit Any(
const T& value, EnableNonIntegral<T> = 0)
127 : _any(value), _original_type(
typeid(T))
129 static_assert(!std::is_reference<T>::value,
"Any can not contain references");
132 Any& operator=(
const Any& other);
134 Any& operator=(
Any&& other)
noexcept;
146 template <
typename T>
147 [[nodiscard]]
bool isType()
const
149 return _original_type ==
typeid(T);
153 void copyInto(
Any& dst)
const;
157 template <
typename T>
158 nonstd::expected<T, std::string> tryCast()
const;
162 template <
typename T>
163 nonstd::expected<T, std::string>
167 template <
typename T>
168 [[nodiscard]] T cast()
const
170 if(
auto res = tryCast<T>())
176 throw std::runtime_error(res.error());
183 template <
typename T>
184 [[nodiscard]] T* castPtr()
186 static_assert(!std::is_same_v<T,
float>,
"The value has been casted internally to "
187 "[double]. Use that instead");
189 return _any.empty() ?
nullptr : linb::any_cast<T>(&_any);
193 [[
nodiscard]]
const std::type_index& type()
const noexcept
195 return _original_type;
199 [[
nodiscard]]
const std::type_info& castedType()
const noexcept
204 [[
nodiscard]]
bool empty()
const noexcept
211 std::type_index _original_type;
215 template <
typename DST>
216 nonstd::expected<DST, std::string> convert(EnableString<DST> = 0)
const;
218 template <
typename DST>
219 nonstd::expected<DST, std::string> convert(EnableArithmetic<DST> =
nullptr)
const;
221 template <
typename DST>
222 nonstd::expected<DST, std::string> convert(EnableEnum<DST> = 0)
const;
224 template <
typename DST>
225 nonstd::expected<DST, std::string> convert(EnableUnknownType<DST> = 0)
const
227 return nonstd::make_unexpected(errorMsg<DST>());
230 template <
typename T>
231 std::string errorMsg()
const
233 return StrCat(
"[Any::convert]: no known safe conversion between [", demangle(type()),
234 "] and [", demangle(
typeid(T)),
"]");
242template <
typename SRC,
typename TO>
243inline bool ValidCast(
const SRC& val)
246 if constexpr(std::is_arithmetic_v<SRC> && std::is_arithmetic_v<TO>)
249 if constexpr(std::is_floating_point_v<TO>)
251 if constexpr(std::is_integral_v<SRC>)
254 TO as_float =
static_cast<TO>(val);
255 SRC back_conv =
static_cast<SRC>(as_float);
256 return back_conv == val;
260 else if constexpr(std::is_integral_v<TO>)
262 if(val >
static_cast<SRC>(std::numeric_limits<TO>::max()) ||
263 val <
static_cast<SRC>(std::numeric_limits<TO>::lowest()))
270 TO as_target =
static_cast<TO>(val);
271 SRC back_to_source =
static_cast<SRC>(as_target);
272 return val == back_to_source;
276inline bool isCastingSafe(
const std::type_index& type,
const T& val)
278 if(type ==
typeid(T))
283 if(std::type_index(
typeid(uint8_t)) == type)
285 return ValidCast<T, uint8_t>(val);
287 if(std::type_index(
typeid(uint16_t)) == type)
289 return ValidCast<T, uint16_t>(val);
291 if(std::type_index(
typeid(uint32_t)) == type)
293 return ValidCast<T, uint32_t>(val);
295 if(std::type_index(
typeid(uint64_t)) == type)
297 return ValidCast<T, uint64_t>(val);
300 if(std::type_index(
typeid(int8_t)) == type)
302 return ValidCast<T, int8_t>(val);
304 if(std::type_index(
typeid(int16_t)) == type)
306 return ValidCast<T, int16_t>(val);
308 if(std::type_index(
typeid(int32_t)) == type)
310 return ValidCast<T, int32_t>(val);
312 if(std::type_index(
typeid(int64_t)) == type)
314 return ValidCast<T, int64_t>(val);
317 if(std::type_index(
typeid(
float)) == type)
319 return ValidCast<T,
float>(val);
321 if(std::type_index(
typeid(
double)) == type)
323 return ValidCast<T,
double>(val);
328inline Any&
Any::operator=(
const Any& other)
332 this->_any = other._any;
333 this->_original_type = other._original_type;
338inline Any&
Any::operator=(
Any&& other)
noexcept
340 this->_any = std::move(other._any);
341 this->_original_type = other._original_type;
345inline bool Any::isNumber()
const
347 return _any.type() ==
typeid(int64_t) || _any.type() ==
typeid(uint64_t) ||
348 _any.type() ==
typeid(
double);
351inline bool Any::isIntegral()
const
353 return _any.type() ==
typeid(int64_t) || _any.type() ==
typeid(uint64_t);
356inline void Any::copyInto(
Any& dst)
const
364 const auto& dst_type = dst.castedType();
366 if((castedType() == dst_type) || (isString() && dst.isString()))
370 else if(isNumber() && dst.isNumber())
372 if(dst_type ==
typeid(int64_t))
374 dst._any = cast<int64_t>();
376 else if(dst_type ==
typeid(uint64_t))
378 dst._any = cast<uint64_t>();
380 else if(dst_type ==
typeid(
double))
382 dst._any = cast<
double>();
386 throw std::runtime_error(
"Any::copyInto fails");
391 throw std::runtime_error(
"Any::copyInto fails");
395template <
typename DST>
396inline nonstd::expected<DST, std::string>
Any::convert(EnableString<DST>)
const
398 const auto& type = _any.type();
402 return linb::any_cast<SafeAny::
SimpleString>(_any).toStdString();
404 else if(type ==
typeid(int64_t))
406 return std::to_string(linb::any_cast<int64_t>(_any));
408 else if(type ==
typeid(uint64_t))
410 return std::to_string(linb::any_cast<uint64_t>(_any));
412 else if(type ==
typeid(
double))
414 return std::to_string(linb::any_cast<
double>(_any));
417 return nonstd::make_unexpected(errorMsg<DST>());
421inline nonstd::expected<T, std::string>
Any::stringToNumber()
const
423 static_assert(std::is_arithmetic_v<T> && !std::is_same_v<T,
bool>,
"Expecting a "
426 const auto str = linb::any_cast<SafeAny::
SimpleString>(_any);
427#if __cpp_lib_to_chars
>= 201611L
429 auto [ptr, err] = std::from_chars(str.data(), str.data() + str.size(), out);
430 if(err == std::errc())
436 return nonstd::make_unexpected(
"Any failed string to number conversion");
441 if constexpr(std::is_same_v<T, uint16_t>)
443 return std::stoul(str.toStdString());
445 if constexpr(std::is_integral_v<T>)
447 const int64_t val = std::stol(str.toStdString());
449 return temp_any.convert<T>();
451 if constexpr(std::is_floating_point_v<T>)
453 return std::stod(str.toStdString());
458 return nonstd::make_unexpected(
"Any failed string to number conversion");
461 return nonstd::make_unexpected(
"Any conversion from string failed");
464template <
typename DST>
465inline nonstd::expected<DST, std::string>
Any::convert(EnableEnum<DST>)
const
467 using SafeAny::details::convertNumber;
469 const auto& type = _any.type();
471 if(type ==
typeid(int64_t))
473 auto out = linb::any_cast<int64_t>(_any);
474 return static_cast<DST>(out);
476 else if(type ==
typeid(uint64_t))
478 auto out = linb::any_cast<uint64_t>(_any);
479 return static_cast<DST>(out);
482 return nonstd::make_unexpected(errorMsg<DST>());
485template <
typename DST>
486inline nonstd::expected<DST, std::string>
Any::convert(EnableArithmetic<DST>)
const
488 using SafeAny::details::convertNumber;
491 const auto& type = _any.type();
493 if(type ==
typeid(int64_t))
495 convertNumber<int64_t, DST>(linb::any_cast<int64_t>(_any), out);
497 else if(type ==
typeid(uint64_t))
499 convertNumber<uint64_t, DST>(linb::any_cast<uint64_t>(_any), out);
501 else if(type ==
typeid(
double))
503 convertNumber<
double, DST>(linb::any_cast<
double>(_any), out);
507 return nonstd::make_unexpected(errorMsg<DST>());
513inline nonstd::expected<T, std::string>
Any::tryCast()
const
515 static_assert(!std::is_reference<T>::value,
"Any::cast uses value semantic, "
516 "can not cast to reference");
520 throw std::runtime_error(
"Any::cast failed because it is empty");
523 if(castedType() ==
typeid(T))
525 return linb::any_cast<T>(_any);
530 if constexpr(std::is_enum_v<T>)
534 return static_cast<T>(convert<
int>().value());
538 if(
auto out = stringToNumber<int64_t>())
540 return static_cast<T>(out.value());
543 return nonstd::make_unexpected(
"Any::cast failed to cast to enum type");
548 if constexpr(std::is_arithmetic_v<T> && !std::is_same_v<T,
bool>)
550 if(
auto out = stringToNumber<T>())
561 if(
auto res = convert<T>())
572inline nonstd::expected<T, std::string>
575 static_assert(
is_shared_ptr<T>::value,
"tryCastWithRegistry only works with shared_ptr "
580 return nonstd::make_unexpected(
"Any::tryCastWithRegistry failed: empty value");
584 auto result = registry.tryCast(_any, _original_type,
typeid(T));
589 return linb::any_cast<T>(result.value());
591 catch(
const std::exception& e)
593 return nonstd::make_unexpected(StrCat(
"Polymorphic cast failed: ", e.what()));
597 return nonstd::make_unexpected(StrCat(
"[Any::tryCastWithRegistry]: ", result.error(),
598 " (from [", demangle(_original_type),
"] to [",
599 demangle(
typeid(T)),
"])"));
Definition: safe_any.hpp:50
Registry for polymorphic shared_ptr cast relationships.
Definition: polymorphic_cast_registry.hpp:47
Definition: simple_string.hpp:19
Definition: action_node.h:24
Definition: safe_any.hpp:39