diff --git a/include/behaviortree_cpp/contrib/any.hpp b/include/behaviortree_cpp/contrib/any.hpp deleted file mode 100644 index acc1321a2..000000000 --- a/include/behaviortree_cpp/contrib/any.hpp +++ /dev/null @@ -1,557 +0,0 @@ -// -// Implementation of N4562 std::experimental::any (merged into C++17) for C++11 compilers. -// -// See also: -// + http://en.cppreference.com/w/cpp/any -// + http://en.cppreference.com/w/cpp/experimental/any -// + http://www.open-std.org/jtc1/sc22/wg21/docs/papers/2015/n4562.html#any -// + https://cplusplus.github.io/LWG/lwg-active.html#2509 -// -// -// Copyright (c) 2016 Denilson das Mercês Amorim -// -// Distributed under the Boost Software License, Version 1.0. (See accompanying -// file LICENSE_1_0.txt or copy at http://www.boost.org/LICENSE_1_0.txt) -// -#ifndef LINB_ANY_HPP -#define LINB_ANY_HPP -#pragma once -#include -#include -#include -#include -#include - -#if defined(PARTICLE) -#if !defined(__cpp_exceptions) && !defined(ANY_IMPL_NO_EXCEPTIONS) && !defined(ANY_IMPL_EXCEPTIONS) -# define ANY_IMPL_NO_EXCEPTIONS -# endif -#else -// you can opt-out of exceptions by definining ANY_IMPL_NO_EXCEPTIONS, -// but you must ensure not to cast badly when passing an `any' object to any_cast(any) -#endif - -#if defined(PARTICLE) -#if !defined(__cpp_rtti) && !defined(ANY_IMPL_NO_RTTI) && !defined(ANY_IMPL_RTTI) -# define ANY_IMPL_NO_RTTI -# endif -#else -// you can opt-out of RTTI by defining ANY_IMPL_NO_RTTI, -// in order to disable functions working with the typeid of a type -#endif - - -namespace linb -{ -template -struct in_place_type_t -{ - constexpr explicit in_place_type_t() noexcept = default; -}; - -#if defined (__cpp_variable_templates) || defined(_MSC_VER) -template -constexpr in_place_type_t in_place_type{}; -#endif - -class bad_any_cast : public std::bad_cast -{ -public: - const char* what() const noexcept override - { - return "bad any cast"; - } -}; - -class any final -{ -public: - /// Constructs an object of type any with an empty state. - any() noexcept : - vtable(nullptr) - { - } - - /// Constructs an object of type any with an equivalent state as other. - any(const any& rhs) : - vtable(rhs.vtable) - { - if(!rhs.empty()) - { - rhs.vtable->copy(rhs.storage, this->storage); - } - } - - /// Constructs an object of type any with a state equivalent to the original state of other. - /// rhs is left in a valid but otherwise unspecified state. - any(any&& rhs) noexcept : - vtable(rhs.vtable) - { - if(!rhs.empty()) - { - rhs.vtable->move(rhs.storage, this->storage); - rhs.vtable = nullptr; - } - } - - /// Same effect as this->clear(). - ~any() - { - this->clear(); - } - - /// Constructs an object of type any that contains an object of type T direct-initialized with std::forward(value). - /// - /// T shall satisfy the CopyConstructible requirements, otherwise the program is ill-formed. - /// This is because an `any` may be copy constructed into another `any` at any time, so a copy should always be allowed. - template::type, any>::value>::type> - any(ValueType&& value) - { - static_assert(std::is_copy_constructible::type>::value, - "T shall satisfy the CopyConstructible requirements."); - this->construct(std::forward(value)); - } - - template - explicit any(in_place_type_t, Args&&... args) - { - this->emplace_construct(std::forward(args)...); - } - - template - explicit any(in_place_type_t, std::initializer_list il, Args&&... args) - { - this->emplace_construct(il, std::forward(args)...); - } - /// Has the same effect as any(rhs).swap(*this). No effects if an exception is thrown. - any& operator=(const any& rhs) - { - any(rhs).swap(*this); - return *this; - } - - /// Has the same effect as any(std::move(rhs)).swap(*this). - /// - /// The state of *this is equivalent to the original state of rhs and rhs is left in a valid - /// but otherwise unspecified state. - any& operator=(any&& rhs) noexcept - { - std::move(rhs).swap(*this); - return *this; - } - - /// Has the same effect as any(std::forward(value)).swap(*this). No effect if a exception is thrown. - /// - /// T shall satisfy the CopyConstructible requirements, otherwise the program is ill-formed. - /// This is because an `any` may be copy constructed into another `any` at any time, so a copy should always be allowed. - template::type, any>::value>::type> - any& operator=(ValueType&& value) - { - static_assert(std::is_copy_constructible::type>::value, - "T shall satisfy the CopyConstructible requirements."); - any(std::forward(value)).swap(*this); - return *this; - } - - /// If not empty, destroys the contained object. - void clear() noexcept - { - if(!empty()) - { - this->vtable->destroy(storage); - this->vtable = nullptr; - } - } - - /// Returns true if *this has no contained object, otherwise false. - bool empty() const noexcept - { - return this->vtable == nullptr; - } - -#ifndef ANY_IMPL_NO_RTTI - /// If *this has a contained object of type T, typeid(T); otherwise typeid(void). - const std::type_info& type() const noexcept - { - return empty()? typeid(void) : this->vtable->type(); - } -#endif - - /// Exchange the states of *this and rhs. - void swap(any& rhs) noexcept - { - if(this->vtable != rhs.vtable) - { - any tmp(std::move(rhs)); - - // move from *this to rhs. - rhs.vtable = this->vtable; - if(this->vtable != nullptr) - { - this->vtable->move(this->storage, rhs.storage); - //this->vtable = nullptr; -- unneeded, see below - } - - // move from tmp (previously rhs) to *this. - this->vtable = tmp.vtable; - if(tmp.vtable != nullptr) - { - tmp.vtable->move(tmp.storage, this->storage); - tmp.vtable = nullptr; - } - } - else // same types - { - if(this->vtable != nullptr) - this->vtable->swap(this->storage, rhs.storage); - } - } - -private: // Storage and Virtual Method Table - - union storage_union - { - using stack_storage_t = typename std::aligned_storage<2 * sizeof(void*), std::alignment_of::value>::type; - - void* dynamic; - stack_storage_t stack; // 2 words for e.g. shared_ptr - }; - - /// Base VTable specification. - struct vtable_type - { - // Note: The caller is responsible for doing .vtable = nullptr after destructful operations - // such as destroy() and/or move(). - -#ifndef ANY_IMPL_NO_RTTI - /// The type of the object this vtable is for. - const std::type_info& (*type)() noexcept; -#endif - - /// Destroys the object in the union. - /// The state of the union after this call is unspecified, caller must ensure not to use src anymore. - void(*destroy)(storage_union&) noexcept; - - /// Copies the **inner** content of the src union into the yet unitialized dest union. - /// As such, both inner objects will have the same state, but on separate memory locations. - void(*copy)(const storage_union& src, storage_union& dest); - - /// Moves the storage from src to the yet unitialized dest union. - /// The state of src after this call is unspecified, caller must ensure not to use src anymore. - void(*move)(storage_union& src, storage_union& dest) noexcept; - - /// Exchanges the storage between lhs and rhs. - void(*swap)(storage_union& lhs, storage_union& rhs) noexcept; - }; - - /// VTable for dynamically allocated storage. - template - struct vtable_dynamic - { -#ifndef ANY_IMPL_NO_RTTI - static const std::type_info& type() noexcept - { - return typeid(T); - } -#endif - - static void destroy(storage_union& storage) noexcept - { - //assert(reinterpret_cast(storage.dynamic)); - delete reinterpret_cast(storage.dynamic); - } - - static void copy(const storage_union& src, storage_union& dest) - { - dest.dynamic = new T(*reinterpret_cast(src.dynamic)); - } - - static void move(storage_union& src, storage_union& dest) noexcept - { - dest.dynamic = src.dynamic; - src.dynamic = nullptr; - } - - static void swap(storage_union& lhs, storage_union& rhs) noexcept - { - // just exchange the storage pointers. - std::swap(lhs.dynamic, rhs.dynamic); - } - }; - - /// VTable for stack allocated storage. - template - struct vtable_stack - { -#ifndef ANY_IMPL_NO_RTTI - static const std::type_info& type() noexcept - { - return typeid(T); - } -#endif - - static void destroy(storage_union& storage) noexcept - { - reinterpret_cast(&storage.stack)->~T(); - } - - static void copy(const storage_union& src, storage_union& dest) - { - new (&dest.stack) T(reinterpret_cast(src.stack)); - } - - static void move(storage_union& src, storage_union& dest) noexcept - { - // one of the conditions for using vtable_stack is a nothrow move constructor, - // so this move constructor will never throw a exception. - new (&dest.stack) T(std::move(reinterpret_cast(src.stack))); - destroy(src); - } - - static void swap(storage_union& lhs, storage_union& rhs) noexcept - { - storage_union tmp_storage; - move(rhs, tmp_storage); - move(lhs, rhs); - move(tmp_storage, lhs); - } - }; - - /// Whether the type T must be dynamically allocated or can be stored on the stack. - template - struct requires_allocation : - std::integral_constant::value // N4562 §6.3/3 [any.class] - && sizeof(T) <= sizeof(storage_union::stack) - && std::alignment_of::value <= std::alignment_of::value)> - {}; - - /// Returns the pointer to the vtable of the type T. - template - static vtable_type* vtable_for_type() - { - using VTableType = typename std::conditional::value, vtable_dynamic, vtable_stack>::type; - static vtable_type table = { -#ifndef ANY_IMPL_NO_RTTI - VTableType::type, -#endif - VTableType::destroy, - VTableType::copy, VTableType::move, - VTableType::swap, - }; - return &table; - } - -protected: - template - friend const T* any_cast(const any* operand) noexcept; - template - friend T* any_cast(any* operand) noexcept; - -#ifndef ANY_IMPL_NO_RTTI - /// Same effect as is_same(this->type(), t); - bool is_typed(const std::type_info& t) const - { - return is_same(this->type(), t); - } -#endif - -#ifndef ANY_IMPL_NO_RTTI - /// Checks if two type infos are the same. - /// - /// If ANY_IMPL_FAST_TYPE_INFO_COMPARE is defined, checks only the address of the - /// type infos, otherwise does an actual comparision. Checking addresses is - /// only a valid approach when there's no interaction with outside sources - /// (other shared libraries and such). - static bool is_same(const std::type_info& a, const std::type_info& b) - { -#ifdef ANY_IMPL_FAST_TYPE_INFO_COMPARE - return &a == &b; -#else - return a == b; -#endif - } -#endif - - /// Casts (with no type_info checks) the storage pointer as const T*. - template - const T* cast() const noexcept - { - return requires_allocation::type>::value? - reinterpret_cast(storage.dynamic) : - reinterpret_cast(&storage.stack); - } - - /// Casts (with no type_info checks) the storage pointer as T*. - template - T* cast() noexcept - { - return requires_allocation::type>::value? - reinterpret_cast(storage.dynamic) : - reinterpret_cast(&storage.stack); - } - -private: - storage_union storage; // on offset(0) so no padding for align - vtable_type* vtable; - - template - typename std::enable_if::value>::type do_emplace(Args&&... args) - { - storage.dynamic = new T(std::forward(args)...); - } - - template - typename std::enable_if::value>::type do_emplace(Args&&... args) - { - new (&storage.stack) T(std::forward(args)...); - } - - template - void emplace_construct(Args&&... args) - { - using T = typename std::decay::type; - - this->vtable = vtable_for_type(); - - do_emplace(std::forward(args)...); - } - - template - typename std::enable_if::value>::type - do_construct(ValueType&& value) - { - storage.dynamic = new T(std::forward(value)); - } - - template - typename std::enable_if::value>::type - do_construct(ValueType&& value) - { - new (&storage.stack) T(std::forward(value)); - } - - /// Chooses between stack and dynamic allocation for the type decay_t, - /// assigns the correct vtable, and constructs the object on our storage. - template - void construct(ValueType&& value) - { - using T = typename std::decay::type; - - this->vtable = vtable_for_type(); - - do_construct(std::forward(value)); - } -}; - - - -namespace detail -{ - template - inline ValueType any_cast_move_if_true(typename std::remove_reference::type* p, std::true_type) - { - return std::move(*p); - } - - template - inline ValueType any_cast_move_if_true(typename std::remove_reference::type* p, std::false_type) - { - return *p; - } -} - -/// Performs *any_cast>>(&operand), or throws bad_any_cast on failure. -template -inline ValueType any_cast(const any& operand) -{ - auto p = any_cast::type>::type>(&operand); -#ifndef ANY_IMPL_NO_EXCEPTIONS - if(p == nullptr) throw bad_any_cast(); -#endif - return *p; -} - -/// Performs *any_cast>(&operand), or throws bad_any_cast on failure. -template -inline ValueType any_cast(any& operand) -{ - auto p = any_cast::type>(&operand); -#ifndef ANY_IMPL_NO_EXCEPTIONS - if(p == nullptr) throw bad_any_cast(); -#endif - return *p; -} - -/// -/// If ValueType is MoveConstructible and isn't a lvalue reference, performs -/// std::move(*any_cast>(&operand)), otherwise -/// *any_cast>(&operand). Throws bad_any_cast on failure. -/// -template -inline ValueType any_cast(any&& operand) -{ - using can_move = std::integral_constant::value - && !std::is_lvalue_reference::value>; - - auto p = any_cast::type>(&operand); -#ifndef ANY_IMPL_NO_EXCEPTIONS - if(p == nullptr) throw bad_any_cast(); -#endif - return detail::any_cast_move_if_true(p, can_move()); -} - -/// If operand != nullptr && operand->type() == typeid(ValueType), a pointer to the object -/// contained by operand, otherwise nullptr. -template -inline const ValueType* any_cast(const any* operand) noexcept -{ - using T = typename std::decay::type; - -#ifndef ANY_IMPL_NO_RTTI - if (operand && operand->is_typed(typeid(T))) -#else - if (operand && operand->vtable == any::vtable_for_type()) -#endif - return operand->cast(); - else - return nullptr; -} - -/// If operand != nullptr && operand->type() == typeid(ValueType), a pointer to the object -/// contained by operand, otherwise nullptr. -template -inline ValueType* any_cast(any* operand) noexcept -{ - using T = typename std::decay::type; - -#ifndef ANY_IMPL_NO_RTTI - if (operand && operand->is_typed(typeid(T))) -#else - if (operand && operand->vtable == any::vtable_for_type()) -#endif - return operand->cast(); - else - return nullptr; -} - -inline void swap(any& lhs, any& rhs) noexcept -{ - lhs.swap(rhs); -} - -template -any make_any(Args&&... args) -{ - return any(in_place_type_t{}, std::forward(args)...); -} - -template -any make_any(std::initializer_list il, Args&&... args) -{ - return any(in_place_type_t{}, il, std::forward(args)...); -} -} - -#endif diff --git a/include/behaviortree_cpp/utils/safe_any.hpp b/include/behaviortree_cpp/utils/safe_any.hpp index e4d5ef98c..d8123c2f8 100644 --- a/include/behaviortree_cpp/utils/safe_any.hpp +++ b/include/behaviortree_cpp/utils/safe_any.hpp @@ -16,12 +16,12 @@ #include #endif -#include "behaviortree_cpp/contrib/any.hpp" #include "behaviortree_cpp/contrib/expected.hpp" #include "behaviortree_cpp/utils/convert_impl.hpp" #include "behaviortree_cpp/utils/demangle_util.h" #include "behaviortree_cpp/utils/strcat.hpp" +#include #include #include #include @@ -167,7 +167,7 @@ class Any static_assert(!std::is_same_v, "The value has been casted internally to " "[double]. Use that instead"); - return _any.empty() ? nullptr : linb::any_cast(&_any); + return _any.has_value() ? std::any_cast(&_any) : nullptr; } // This is the original type @@ -184,11 +184,11 @@ class Any [[nodiscard]] bool empty() const noexcept { - return _any.empty(); + return !_any.has_value(); } private: - linb::any _any; + std::any _any; std::type_index _original_type; //---------------------------- @@ -380,19 +380,19 @@ inline nonstd::expected Any::convert(EnableString) const if(type == typeid(SafeAny::SimpleString)) { - return linb::any_cast(_any).toStdString(); + return std::any_cast(_any).toStdString(); } else if(type == typeid(int64_t)) { - return std::to_string(linb::any_cast(_any)); + return std::to_string(std::any_cast(_any)); } else if(type == typeid(uint64_t)) { - return std::to_string(linb::any_cast(_any)); + return std::to_string(std::any_cast(_any)); } else if(type == typeid(double)) { - return std::to_string(linb::any_cast(_any)); + return std::to_string(std::any_cast(_any)); } return nonstd::make_unexpected(errorMsg()); @@ -404,7 +404,7 @@ inline nonstd::expected Any::stringToNumber() const static_assert(std::is_arithmetic_v && !std::is_same_v, "Expecting a " "numeric type"); - const auto str = linb::any_cast(_any); + const auto str = std::any_cast(_any); #if __cpp_lib_to_chars >= 201611L T out; auto [ptr, err] = std::from_chars(str.data(), str.data() + str.size(), out); @@ -451,12 +451,12 @@ inline nonstd::expected Any::convert(EnableEnum) const if(type == typeid(int64_t)) { - auto out = linb::any_cast(_any); + auto out = std::any_cast(_any); return static_cast(out); } else if(type == typeid(uint64_t)) { - auto out = linb::any_cast(_any); + auto out = std::any_cast(_any); return static_cast(out); } @@ -473,15 +473,15 @@ inline nonstd::expected Any::convert(EnableArithmetic) co if(type == typeid(int64_t)) { - convertNumber(linb::any_cast(_any), out); + convertNumber(std::any_cast(_any), out); } else if(type == typeid(uint64_t)) { - convertNumber(linb::any_cast(_any), out); + convertNumber(std::any_cast(_any), out); } else if(type == typeid(double)) { - convertNumber(linb::any_cast(_any), out); + convertNumber(std::any_cast(_any), out); } else { @@ -496,14 +496,14 @@ inline nonstd::expected Any::tryCast() const static_assert(!std::is_reference::value, "Any::cast uses value semantic, " "can not cast to reference"); - if(_any.empty()) + if(!_any.has_value()) { throw std::runtime_error("Any::cast failed because it is empty"); } if(castedType() == typeid(T)) { - return linb::any_cast(_any); + return std::any_cast(_any); } // special case when the output is an enum.