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>)
266 constexpr bool max_rounds_up =
267 std::is_floating_point_v<SRC> &&
268 std::numeric_limits<TO>::digits > std::numeric_limits<SRC>::digits;
269 const SRC max_limit =
static_cast<SRC>(std::numeric_limits<TO>::max());
270 const bool over = max_rounds_up ? (val >= max_limit) : (val > max_limit);
271 if(over || val <
static_cast<SRC>(std::numeric_limits<TO>::lowest()))
278 TO as_target =
static_cast<TO>(val);
279 SRC back_to_source =
static_cast<SRC>(as_target);
280 return val == back_to_source;
284inline bool isCastingSafe(
const std::type_index& type,
const T& val)
286 if(type ==
typeid(T))
291 if(std::type_index(
typeid(uint8_t)) == type)
293 return ValidCast<T, uint8_t>(val);
295 if(std::type_index(
typeid(uint16_t)) == type)
297 return ValidCast<T, uint16_t>(val);
299 if(std::type_index(
typeid(uint32_t)) == type)
301 return ValidCast<T, uint32_t>(val);
303 if(std::type_index(
typeid(uint64_t)) == type)
305 return ValidCast<T, uint64_t>(val);
308 if(std::type_index(
typeid(int8_t)) == type)
310 return ValidCast<T, int8_t>(val);
312 if(std::type_index(
typeid(int16_t)) == type)
314 return ValidCast<T, int16_t>(val);
316 if(std::type_index(
typeid(int32_t)) == type)
318 return ValidCast<T, int32_t>(val);
320 if(std::type_index(
typeid(int64_t)) == type)
322 return ValidCast<T, int64_t>(val);
325 if(std::type_index(
typeid(
float)) == type)
327 return ValidCast<T,
float>(val);
329 if(std::type_index(
typeid(
double)) == type)
331 return ValidCast<T,
double>(val);
336inline Any&
Any::operator=(
const Any& other)
340 this->_any = other._any;
341 this->_original_type = other._original_type;
346inline Any&
Any::operator=(
Any&& other)
noexcept
348 this->_any = std::move(other._any);
349 this->_original_type = other._original_type;
353inline bool Any::isNumber()
const
355 return _any.type() ==
typeid(int64_t) || _any.type() ==
typeid(uint64_t) ||
356 _any.type() ==
typeid(
double);
359inline bool Any::isIntegral()
const
361 return _any.type() ==
typeid(int64_t) || _any.type() ==
typeid(uint64_t);
364inline void Any::copyInto(
Any& dst)
const
372 const auto& dst_type = dst.castedType();
374 if((castedType() == dst_type) || (isString() && dst.isString()))
378 else if(isNumber() && dst.isNumber())
380 if(dst_type ==
typeid(int64_t))
382 dst._any = cast<int64_t>();
384 else if(dst_type ==
typeid(uint64_t))
386 dst._any = cast<uint64_t>();
388 else if(dst_type ==
typeid(
double))
390 dst._any = cast<
double>();
394 throw std::runtime_error(
"Any::copyInto fails");
399 throw std::runtime_error(
"Any::copyInto fails");
403template <
typename DST>
404inline nonstd::expected<DST, std::string>
Any::convert(EnableString<DST>)
const
406 const auto& type = _any.type();
410 return linb::any_cast<SafeAny::
SimpleString>(_any).toStdString();
412 else if(type ==
typeid(int64_t))
414 return std::to_string(linb::any_cast<int64_t>(_any));
416 else if(type ==
typeid(uint64_t))
418 return std::to_string(linb::any_cast<uint64_t>(_any));
420 else if(type ==
typeid(
double))
422 return std::to_string(linb::any_cast<
double>(_any));
425 return nonstd::make_unexpected(errorMsg<DST>());
429inline nonstd::expected<T, std::string>
Any::stringToNumber()
const
431 static_assert(std::is_arithmetic_v<T> && !std::is_same_v<T,
bool>,
"Expecting a "
434 const auto str = linb::any_cast<SafeAny::
SimpleString>(_any);
435#if __cpp_lib_to_chars
>= 201611L
437 auto [ptr, err] = std::from_chars(str.data(), str.data() + str.size(), out);
438 if(err == std::errc())
444 return nonstd::make_unexpected(
"Any failed string to number conversion");
449 if constexpr(std::is_same_v<T, uint16_t>)
451 return std::stoul(str.toStdString());
453 if constexpr(std::is_integral_v<T>)
455 const int64_t val = std::stol(str.toStdString());
457 return temp_any.convert<T>();
459 if constexpr(std::is_floating_point_v<T>)
461 return std::stod(str.toStdString());
466 return nonstd::make_unexpected(
"Any failed string to number conversion");
469 return nonstd::make_unexpected(
"Any conversion from string failed");
472template <
typename DST>
473inline nonstd::expected<DST, std::string>
Any::convert(EnableEnum<DST>)
const
475 using SafeAny::details::convertNumber;
477 const auto& type = _any.type();
479 if(type ==
typeid(int64_t))
481 auto out = linb::any_cast<int64_t>(_any);
482 return static_cast<DST>(out);
484 else if(type ==
typeid(uint64_t))
486 auto out = linb::any_cast<uint64_t>(_any);
487 return static_cast<DST>(out);
490 return nonstd::make_unexpected(errorMsg<DST>());
493template <
typename DST>
494inline nonstd::expected<DST, std::string>
Any::convert(EnableArithmetic<DST>)
const
496 using SafeAny::details::convertNumber;
499 const auto& type = _any.type();
501 if(type ==
typeid(int64_t))
503 convertNumber<int64_t, DST>(linb::any_cast<int64_t>(_any), out);
505 else if(type ==
typeid(uint64_t))
507 convertNumber<uint64_t, DST>(linb::any_cast<uint64_t>(_any), out);
509 else if(type ==
typeid(
double))
511 convertNumber<
double, DST>(linb::any_cast<
double>(_any), out);
515 return nonstd::make_unexpected(errorMsg<DST>());
521inline nonstd::expected<T, std::string>
Any::tryCast()
const
523 static_assert(!std::is_reference<T>::value,
"Any::cast uses value semantic, "
524 "can not cast to reference");
528 throw std::runtime_error(
"Any::cast failed because it is empty");
531 if(castedType() ==
typeid(T))
533 return linb::any_cast<T>(_any);
538 if constexpr(std::is_enum_v<T>)
542 return static_cast<T>(convert<
int>().value());
546 if(
auto out = stringToNumber<int64_t>())
548 return static_cast<T>(out.value());
551 return nonstd::make_unexpected(
"Any::cast failed to cast to enum type");
556 if constexpr(std::is_arithmetic_v<T> && !std::is_same_v<T,
bool>)
558 if(
auto out = stringToNumber<T>())
569 if(
auto res = convert<T>())
571 return std::move(res.value());
580inline nonstd::expected<T, std::string>
583 static_assert(
is_shared_ptr<T>::value,
"tryCastWithRegistry only works with shared_ptr "
588 return nonstd::make_unexpected(
"Any::tryCastWithRegistry failed: empty value");
592 auto result = registry.tryCast(_any, _original_type,
typeid(T));
597 return linb::any_cast<T>(result.value());
599 catch(
const std::exception& e)
601 return nonstd::make_unexpected(StrCat(
"Polymorphic cast failed: ", e.what()));
605 return nonstd::make_unexpected(StrCat(
"[Any::tryCastWithRegistry]: ", result.error(),
606 " (from [", demangle(_original_type),
"] to [",
607 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