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"
35static std::type_index UndefinedAnyType =
typeid(
nullptr);
41 bool require_full_consumption);
82 nonstd::expected<T, std::string> stringToNumber()
const;
85 Any() : _original_type(UndefinedAnyType)
90 Any(
const Any& other) : _any(other._any), _original_type(other._original_type)
93 Any(
Any&& other)
noexcept
94 : _any(std::move(other._any)), _original_type(other._original_type)
97 explicit Any(
const double& value) : _any(value), _original_type(
typeid(
double))
100 explicit Any(
const uint64_t& value) : _any(value), _original_type(
typeid(uint64_t))
103 explicit Any(
const float& value) : _any(
double(value)), _original_type(
typeid(
float))
106 explicit Any(
const std::string& str)
107 : _any(SafeAny::SimpleString(str)), _original_type(
typeid(std::string))
110 explicit Any(
const char* str)
111 : _any(SafeAny::SimpleString(str)), _original_type(
typeid(std::string))
115 : _any(str), _original_type(
typeid(std::string))
118 explicit Any(
const std::string_view& str)
119 : _any(SafeAny::SimpleString(str)), _original_type(
typeid(std::string))
123 template <
typename T>
124 explicit Any(
const T& value, EnableIntegral<T> = 0)
125 : _any(int64_t(value)), _original_type(
typeid(T))
128 Any(
const std::type_index& type) : _original_type(type)
132 template <
typename T>
133 explicit Any(
const T& value, EnableNonIntegral<T> = 0)
134 : _any(value), _original_type(
typeid(T))
136 static_assert(!std::is_reference<T>::value,
"Any can not contain references");
139 Any& operator=(
const Any& other);
141 Any& operator=(
Any&& other)
noexcept;
153 template <
typename T>
154 [[nodiscard]]
bool isType()
const
156 return _original_type ==
typeid(T);
160 void copyInto(
Any& dst)
const;
164 template <
typename T>
165 nonstd::expected<T, std::string> tryCast()
const;
169 template <
typename T>
170 nonstd::expected<T, std::string>
174 template <
typename T>
175 [[nodiscard]] T cast()
const
177 if(
auto res = tryCast<T>())
183 throw std::runtime_error(res.error());
190 template <
typename T>
191 [[nodiscard]] T* castPtr()
193 static_assert(!std::is_same_v<T,
float>,
"The value has been casted internally to "
194 "[double]. Use that instead");
196 return _any.empty() ?
nullptr : linb::any_cast<T>(&_any);
200 [[
nodiscard]]
const std::type_index& type()
const noexcept
202 return _original_type;
206 [[
nodiscard]]
const std::type_info& castedType()
const noexcept
211 [[
nodiscard]]
bool empty()
const noexcept
218 std::type_index _original_type;
222 template <
typename DST>
223 nonstd::expected<DST, std::string> convert(EnableString<DST> = 0)
const;
225 template <
typename DST>
226 nonstd::expected<DST, std::string> convert(EnableArithmetic<DST> =
nullptr)
const;
228 template <
typename DST>
229 nonstd::expected<DST, std::string> convert(EnableEnum<DST> = 0)
const;
231 template <
typename DST>
232 nonstd::expected<DST, std::string> convert(EnableUnknownType<DST> = 0)
const
234 return nonstd::make_unexpected(errorMsg<DST>());
237 template <
typename T>
238 std::string errorMsg()
const
240 return StrCat(
"[Any::convert]: no known safe conversion between [", demangle(type()),
241 "] and [", demangle(
typeid(T)),
"]");
249template <
typename SRC,
typename TO>
250inline bool ValidCast(
const SRC& val)
253 if constexpr(std::is_arithmetic_v<SRC> && std::is_arithmetic_v<TO>)
256 if constexpr(std::is_floating_point_v<TO>)
258 if constexpr(std::is_integral_v<SRC>)
261 TO as_float =
static_cast<TO>(val);
262 SRC back_conv =
static_cast<SRC>(as_float);
263 return back_conv == val;
267 else if constexpr(std::is_integral_v<TO>)
273 constexpr bool max_rounds_up =
274 std::is_floating_point_v<SRC> &&
275 std::numeric_limits<TO>::digits > std::numeric_limits<SRC>::digits;
276 const SRC max_limit =
static_cast<SRC>(std::numeric_limits<TO>::max());
277 const bool over = max_rounds_up ? (val >= max_limit) : (val > max_limit);
278 if(over || val <
static_cast<SRC>(std::numeric_limits<TO>::lowest()))
285 TO as_target =
static_cast<TO>(val);
286 SRC back_to_source =
static_cast<SRC>(as_target);
287 return val == back_to_source;
291inline bool isCastingSafe(
const std::type_index& type,
const T& val)
293 if(type ==
typeid(T))
298 if(std::type_index(
typeid(uint8_t)) == type)
300 return ValidCast<T, uint8_t>(val);
302 if(std::type_index(
typeid(uint16_t)) == type)
304 return ValidCast<T, uint16_t>(val);
306 if(std::type_index(
typeid(uint32_t)) == type)
308 return ValidCast<T, uint32_t>(val);
310 if(std::type_index(
typeid(uint64_t)) == type)
312 return ValidCast<T, uint64_t>(val);
315 if(std::type_index(
typeid(int8_t)) == type)
317 return ValidCast<T, int8_t>(val);
319 if(std::type_index(
typeid(int16_t)) == type)
321 return ValidCast<T, int16_t>(val);
323 if(std::type_index(
typeid(int32_t)) == type)
325 return ValidCast<T, int32_t>(val);
327 if(std::type_index(
typeid(int64_t)) == type)
329 return ValidCast<T, int64_t>(val);
332 if(std::type_index(
typeid(
float)) == type)
334 return ValidCast<T,
float>(val);
336 if(std::type_index(
typeid(
double)) == type)
338 return ValidCast<T,
double>(val);
343inline Any&
Any::operator=(
const Any& other)
347 this->_any = other._any;
348 this->_original_type = other._original_type;
353inline Any&
Any::operator=(
Any&& other)
noexcept
355 this->_any = std::move(other._any);
356 this->_original_type = other._original_type;
360inline bool Any::isNumber()
const
362 return _any.type() ==
typeid(int64_t) || _any.type() ==
typeid(uint64_t) ||
363 _any.type() ==
typeid(
double);
366inline bool Any::isIntegral()
const
368 return _any.type() ==
typeid(int64_t) || _any.type() ==
typeid(uint64_t);
371inline void Any::copyInto(
Any& dst)
const
379 const auto& dst_type = dst.castedType();
381 if((castedType() == dst_type) || (isString() && dst.isString()))
385 else if(isNumber() && dst.isNumber())
387 if(dst_type ==
typeid(int64_t))
389 dst._any = cast<int64_t>();
391 else if(dst_type ==
typeid(uint64_t))
393 dst._any = cast<uint64_t>();
395 else if(dst_type ==
typeid(
double))
397 dst._any = cast<
double>();
401 throw std::runtime_error(
"Any::copyInto fails");
406 throw std::runtime_error(
"Any::copyInto fails");
410template <
typename DST>
411inline nonstd::expected<DST, std::string>
Any::convert(EnableString<DST>)
const
413 const auto& type = _any.type();
417 return linb::any_cast<SafeAny::
SimpleString>(_any).toStdString();
419 else if(type ==
typeid(int64_t))
421 return std::to_string(linb::any_cast<int64_t>(_any));
423 else if(type ==
typeid(uint64_t))
425 return std::to_string(linb::any_cast<uint64_t>(_any));
427 else if(type ==
typeid(
double))
429 return std::to_string(linb::any_cast<
double>(_any));
432 return nonstd::make_unexpected(errorMsg<DST>());
436inline nonstd::expected<T, std::string>
Any::stringToNumber()
const
438 static_assert(std::is_arithmetic_v<T> && !std::is_same_v<T,
bool>,
"Expecting a "
441 const auto str = linb::any_cast<SafeAny::
SimpleString>(_any);
442#if __cpp_lib_to_chars
>= 201611L
444 auto [ptr, err] = std::from_chars(str.data(), str.data() + str.size(), out);
445 if(err == std::errc())
451 return nonstd::make_unexpected(
"Any failed string to number conversion");
456 if constexpr(std::is_same_v<T, uint16_t>)
458 return std::stoul(str.toStdString());
460 if constexpr(std::is_integral_v<T>)
462 const int64_t val = std::stol(str.toStdString());
464 return temp_any.convert<T>();
466 if constexpr(std::is_floating_point_v<T>)
472 if(parseDouble(str.toStdStringView(), value,
false))
474 return static_cast<T>(value);
476 return nonstd::make_unexpected(
"Any failed string to number conversion");
481 return nonstd::make_unexpected(
"Any failed string to number conversion");
484 return nonstd::make_unexpected(
"Any conversion from string failed");
487template <
typename DST>
488inline nonstd::expected<DST, std::string>
Any::convert(EnableEnum<DST>)
const
490 using SafeAny::details::convertNumber;
492 const auto& type = _any.type();
494 if(type ==
typeid(int64_t))
496 auto out = linb::any_cast<int64_t>(_any);
497 return static_cast<DST>(out);
499 else if(type ==
typeid(uint64_t))
501 auto out = linb::any_cast<uint64_t>(_any);
502 return static_cast<DST>(out);
505 return nonstd::make_unexpected(errorMsg<DST>());
508template <
typename DST>
509inline nonstd::expected<DST, std::string>
Any::convert(EnableArithmetic<DST>)
const
511 using SafeAny::details::convertNumber;
514 const auto& type = _any.type();
516 if(type ==
typeid(int64_t))
518 convertNumber<int64_t, DST>(linb::any_cast<int64_t>(_any), out);
520 else if(type ==
typeid(uint64_t))
522 convertNumber<uint64_t, DST>(linb::any_cast<uint64_t>(_any), out);
524 else if(type ==
typeid(
double))
526 convertNumber<
double, DST>(linb::any_cast<
double>(_any), out);
530 return nonstd::make_unexpected(errorMsg<DST>());
536inline nonstd::expected<T, std::string>
Any::tryCast()
const
538 static_assert(!std::is_reference<T>::value,
"Any::cast uses value semantic, "
539 "can not cast to reference");
543 throw std::runtime_error(
"Any::cast failed because it is empty");
546 if(castedType() ==
typeid(T))
548 return linb::any_cast<T>(_any);
553 if constexpr(std::is_enum_v<T>)
557 return static_cast<T>(convert<
int>().value());
561 if(
auto out = stringToNumber<int64_t>())
563 return static_cast<T>(out.value());
566 return nonstd::make_unexpected(
"Any::cast failed to cast to enum type");
571 if constexpr(std::is_arithmetic_v<T> && !std::is_same_v<T,
bool>)
573 if(
auto out = stringToNumber<T>())
584 if(
auto res = convert<T>())
586 return std::move(res.value());
595inline nonstd::expected<T, std::string>
598 static_assert(
is_shared_ptr<T>::value,
"tryCastWithRegistry only works with shared_ptr "
603 return nonstd::make_unexpected(
"Any::tryCastWithRegistry failed: empty value");
607 auto result = registry.tryCast(_any, _original_type,
typeid(T));
612 return linb::any_cast<T>(result.value());
614 catch(
const std::exception& e)
616 return nonstd::make_unexpected(StrCat(
"Polymorphic cast failed: ", e.what()));
620 return nonstd::make_unexpected(StrCat(
"[Any::tryCastWithRegistry]: ", result.error(),
621 " (from [", demangle(_original_type),
"] to [",
622 demangle(
typeid(T)),
"])"));
Definition: safe_any.hpp:57
Registry for polymorphic shared_ptr cast relationships.
Definition: polymorphic_cast_registry.hpp:47
Definition: simple_string.hpp:19
Definition: action_node.h:24
bool parseDouble(StringView str, double &out, bool require_full_consumption)
Parse a double from a string using the semantics of std::from_chars(std::chars_format::general): loca...
Definition: safe_any.hpp:46