From 3326553e2afa844854e3f8b47cbc194ef1a8a0c2 Mon Sep 17 00:00:00 2001 From: Davide Faconti Date: Sat, 10 Feb 2024 15:55:20 +0100 Subject: [PATCH 001/146] fix compilation error and warning messages --- include/behaviortree_cpp/basic_types.h | 64 ++------------------------ 1 file changed, 3 insertions(+), 61 deletions(-) diff --git a/include/behaviortree_cpp/basic_types.h b/include/behaviortree_cpp/basic_types.h index cdb60d8b5..e0763c49a 100644 --- a/include/behaviortree_cpp/basic_types.h +++ b/include/behaviortree_cpp/basic_types.h @@ -167,7 +167,7 @@ std::string toStr(const T& value) { if constexpr (IsConvertibleToString()) { - return value; + return static_cast(value); } else if constexpr(!std::is_arithmetic_v) { @@ -440,7 +440,7 @@ inline std::pair InputPort(StringView name, static_assert(std::is_same_v || IsConvertibleToString() || std::is_convertible_v, - "The default value must be either the same of the port or BlackboardKey"); + "The default value must be either the same of the port or a string"); auto out = CreatePort(PortDirection::INPUT, name, description); out.second.setDefaultValue(default_value); @@ -462,7 +462,7 @@ inline std::pair BidirectionalPort(StringView name, static_assert(std::is_same_v || IsConvertibleToString() || std::is_convertible_v, - "The default value must be either the same of the port or BlackboardKey"); + "The default value must be either the same of the port or a string"); auto out = CreatePort(PortDirection::INOUT, name, description); out.second.setDefaultValue(default_value); @@ -492,64 +492,6 @@ inline std::pair OutputPort(StringView name, //---------- -// /** Syntactic sugar to invoke CreatePort(PortDirection::INPUT,...) -// * It also sets the default value to the blackboard entry specified -// * in "default_key" -// * -// * @param name the name of the port -// * @param default_key the key of an entry in the blackbard -// * @param description optional human-readable description -// */ -// template [[nodiscard]] -// inline std::pair InputPort( -// StringView name, -// BlackboardKey default_key, -// StringView description) -// { -// auto out = CreatePort(PortDirection::INPUT, name, description); -// out.second.setDefaultValue(default_key); -// return out; -// } - -// /** Syntactic sugar to invoke CreatePort(PortDirection::INOUT,...) -// * It also sets the default value to the blackboard entry specified -// * in "default_key" -// * -// * @param name the name of the port -// * @param default_key the key of an entry in the blackbard -// * @param description optional human-readable description -// */ -// template [[nodiscard]] -// inline std::pair BidirectionalPort( -// StringView name, -// BlackboardKey default_key, -// StringView description) -// { -// auto out = CreatePort(PortDirection::INOUT, name, description); -// out.second.setDefaultValue(default_key); -// return out; -// } - -// /** Syntactic sugar to invoke CreatePort(PortDirection::OUTPUT,...) -// * It also sets the default value to the blackboard entry specified -// * in "default_key" -// * -// * @param name the name of the port -// * @param default_key the key of an entry in the blackbard -// * @param description optional human-readable description -// */ -// template [[nodiscard]] -// inline std::pair OutputPort( -// StringView name, -// BlackboardKey default_key, -// StringView description) -// { -// auto out = CreatePort(PortDirection::OUTPUT, name, description); -// out.second.setDefaultValue(default_key); -// return out; -// } -//---------- - using PortsList = std::unordered_map; template From 83fce13a38efe81f2dd5713328f94942f32f8c9a Mon Sep 17 00:00:00 2001 From: Davide Faconti Date: Tue, 13 Feb 2024 11:28:57 +0100 Subject: [PATCH 002/146] Fix issue #767 and #768 --- include/behaviortree_cpp/basic_types.h | 58 +++++++++++++++++--------- tests/gtest_ports.cpp | 13 ++++++ 2 files changed, 52 insertions(+), 19 deletions(-) diff --git a/include/behaviortree_cpp/basic_types.h b/include/behaviortree_cpp/basic_types.h index e0763c49a..4c179e34e 100644 --- a/include/behaviortree_cpp/basic_types.h +++ b/include/behaviortree_cpp/basic_types.h @@ -425,6 +425,39 @@ inline std::pair BidirectionalPort(StringView name, return CreatePort(PortDirection::INOUT, name, description); } //---------- + +namespace details { + +template [[nodiscard]] +inline std::pair PortWithDefault( + PortDirection direction, + StringView name, + const DefaultT& default_value, + StringView description) +{ + static_assert(IsConvertibleToString() || + std::is_convertible_v || + std::is_constructible_v, + "The default value must be either the same of the port or string"); + + auto out = CreatePort(direction, name, description); + + if constexpr(std::is_constructible_v) + { + out.second.setDefaultValue(T(default_value)); + } + else if constexpr(IsConvertibleToString()) + { + out.second.setDefaultValue(std::string(default_value)); + } + else { + out.second.setDefaultValue(default_value); + } + return out; +} + +} // end namespace details + /** Syntactic sugar to invoke CreatePort(PortDirection::INPUT,...) * It also sets the PortInfo::defaultValue() * @@ -437,14 +470,7 @@ inline std::pair InputPort(StringView name, const DefaultT& default_value, StringView description) { - static_assert(std::is_same_v || - IsConvertibleToString() || - std::is_convertible_v, - "The default value must be either the same of the port or a string"); - - auto out = CreatePort(PortDirection::INPUT, name, description); - out.second.setDefaultValue(default_value); - return out; + return details::PortWithDefault(PortDirection::INPUT, name, default_value, description); } /** Syntactic sugar to invoke CreatePort(PortDirection::INOUT,...) @@ -459,14 +485,7 @@ inline std::pair BidirectionalPort(StringView name, const DefaultT& default_value, StringView description) { - static_assert(std::is_same_v || - IsConvertibleToString() || - std::is_convertible_v, - "The default value must be either the same of the port or a string"); - - auto out = CreatePort(PortDirection::INOUT, name, description); - out.second.setDefaultValue(default_value); - return out; + return details::PortWithDefault(PortDirection::INOUT, name, default_value, description); } /** Syntactic sugar to invoke CreatePort(PortDirection::OUTPUT,...) @@ -477,9 +496,10 @@ inline std::pair BidirectionalPort(StringView name, * @param description optional human-readable description */ template [[nodiscard]] -inline std::pair OutputPort(StringView name, - StringView default_value, - StringView description) +inline std::pair OutputPort( + StringView name, + StringView default_value, + StringView description) { if(default_value.empty() || default_value.front() != '{' || default_value.back() != '}') { diff --git a/tests/gtest_ports.cpp b/tests/gtest_ports.cpp index 9b829ff26..0efbb4cc8 100644 --- a/tests/gtest_ports.cpp +++ b/tests/gtest_ports.cpp @@ -533,3 +533,16 @@ TEST(PortTest, DefaultInputStrings) ASSERT_EQ(status, NodeStatus::SUCCESS); } + +TEST(PortTest, Default_Issues_767_768) +{ + using namespace BT; + + ASSERT_NO_THROW(auto p = InputPort>("opt_A", std::nullopt, "default nullopt")); + ASSERT_NO_THROW(auto p = InputPort>("opt_B", std::nullopt, "default nullopt")); + + ASSERT_NO_THROW(auto p = InputPort>("ptr_A", nullptr, "default nullptr")); + ASSERT_NO_THROW(auto p = InputPort>("ptr_B", nullptr, "default nullptr")); +} + + From 8f9e52aa8f84d1756fad39c4850c677c8864ef50 Mon Sep 17 00:00:00 2001 From: Davide Faconti Date: Tue, 13 Feb 2024 16:28:20 +0100 Subject: [PATCH 003/146] keep back compatibility between "=" and "{=}" --- include/behaviortree_cpp/tree_node.h | 2 +- src/tree_node.cpp | 2 +- 2 files changed, 2 insertions(+), 2 deletions(-) diff --git a/include/behaviortree_cpp/tree_node.h b/include/behaviortree_cpp/tree_node.h index 0de86ddc3..dc86f76b0 100644 --- a/include/behaviortree_cpp/tree_node.h +++ b/include/behaviortree_cpp/tree_node.h @@ -502,7 +502,7 @@ inline Result TreeNode::setOutput(const std::string& key, const T& value) key, "]")); } StringView remapped_key = remap_it->second; - if (remapped_key == "{=}") + if (remapped_key == "{=}" || remapped_key == "=") { config().blackboard->set(static_cast(key), value); return {}; diff --git a/src/tree_node.cpp b/src/tree_node.cpp index ebcb89700..59f46fe2f 100644 --- a/src/tree_node.cpp +++ b/src/tree_node.cpp @@ -394,7 +394,7 @@ StringView TreeNode::stripBlackboardPointer(StringView str) Expected TreeNode::getRemappedKey(StringView port_name, StringView remapped_port) { - if (remapped_port == "{=}") + if (remapped_port == "{=}" || remapped_port == "=") { return {port_name}; } From 21ab495156b6b15d224370803f5cb2cc016a0aa2 Mon Sep 17 00:00:00 2001 From: Marq Rasmussen Date: Tue, 13 Feb 2024 16:18:19 -0700 Subject: [PATCH 004/146] Initialize std::atomic_bool (#772) --- examples/broken_sequence.cpp | 2 +- include/behaviortree_cpp/action_node.h | 4 ++-- include/behaviortree_cpp/actions/sleep_node.h | 2 +- include/behaviortree_cpp/actions/test_node.h | 2 +- include/behaviortree_cpp/decorators/delay_node.h | 8 ++++---- include/behaviortree_cpp/decorators/timeout_node.h | 2 +- src/loggers/groot2_publisher.cpp | 2 +- 7 files changed, 11 insertions(+), 11 deletions(-) diff --git a/examples/broken_sequence.cpp b/examples/broken_sequence.cpp index 032d242f9..51927f1bf 100644 --- a/examples/broken_sequence.cpp +++ b/examples/broken_sequence.cpp @@ -35,7 +35,7 @@ class ActionTestNode : public ActionNode private: int time_; - std::atomic_bool stop_loop_; + std::atomic_bool stop_loop_ = false; }; int main() diff --git a/include/behaviortree_cpp/action_node.h b/include/behaviortree_cpp/action_node.h index 5f332917c..93a4a996f 100644 --- a/include/behaviortree_cpp/action_node.h +++ b/include/behaviortree_cpp/action_node.h @@ -132,7 +132,7 @@ class ThreadedAction : public ActionNodeBase private: std::exception_ptr exptr_; - std::atomic_bool halt_requested_; + std::atomic_bool halt_requested_ = false; std::future thread_handle_; std::mutex mutex_; }; @@ -183,7 +183,7 @@ class StatefulActionNode : public ActionNodeBase void halt() override final; private: - std::atomic_bool halt_requested_; + std::atomic_bool halt_requested_ = false; }; /** diff --git a/include/behaviortree_cpp/actions/sleep_node.h b/include/behaviortree_cpp/actions/sleep_node.h index 553116a92..b97e3cdaa 100644 --- a/include/behaviortree_cpp/actions/sleep_node.h +++ b/include/behaviortree_cpp/actions/sleep_node.h @@ -38,7 +38,7 @@ class SleepNode : public StatefulActionNode TimerQueue<> timer_; uint64_t timer_id_; - std::atomic_bool timer_waiting_; + std::atomic_bool timer_waiting_ = false; std::mutex delay_mutex_; }; diff --git a/include/behaviortree_cpp/actions/test_node.h b/include/behaviortree_cpp/actions/test_node.h index f410a27a6..e56c6a978 100644 --- a/include/behaviortree_cpp/actions/test_node.h +++ b/include/behaviortree_cpp/actions/test_node.h @@ -88,7 +88,7 @@ class TestNode : public BT::StatefulActionNode TestNodeConfig _test_config; ScriptFunction _executor; TimerQueue<> _timer; - std::atomic_bool _completed; + std::atomic_bool _completed = false; }; } // namespace BT diff --git a/include/behaviortree_cpp/decorators/delay_node.h b/include/behaviortree_cpp/decorators/delay_node.h index de09866d4..52f9596d8 100644 --- a/include/behaviortree_cpp/decorators/delay_node.h +++ b/include/behaviortree_cpp/decorators/delay_node.h @@ -56,11 +56,11 @@ class DelayNode : public DecoratorNode virtual BT::NodeStatus tick() override; - bool delay_started_; - std::atomic_bool delay_complete_; - bool delay_aborted_; + bool delay_started_ = false; + std::atomic_bool delay_complete_ = false; + bool delay_aborted_ = false; unsigned msec_; - bool read_parameter_from_ports_; + bool read_parameter_from_ports_ = false; std::mutex delay_mutex_; }; diff --git a/include/behaviortree_cpp/decorators/timeout_node.h b/include/behaviortree_cpp/decorators/timeout_node.h index e71a1e936..dc2cb54a0 100644 --- a/include/behaviortree_cpp/decorators/timeout_node.h +++ b/include/behaviortree_cpp/decorators/timeout_node.h @@ -73,7 +73,7 @@ class TimeoutNode : public DecoratorNode void halt() override; TimerQueue<> timer_; - std::atomic_bool child_halted_; + std::atomic_bool child_halted_ = false; uint64_t timer_id_; unsigned msec_; diff --git a/src/loggers/groot2_publisher.cpp b/src/loggers/groot2_publisher.cpp index 7682e3daf..f40ae1c66 100644 --- a/src/loggers/groot2_publisher.cpp +++ b/src/loggers/groot2_publisher.cpp @@ -73,7 +73,7 @@ struct Groot2Publisher::PImpl std::string tree_xml; - std::atomic_bool active_server; + std::atomic_bool active_server = false; std::thread server_thread; std::mutex status_mutex; From 6c9929c99e0546fcb51d9a0e2dc1febe5c7a624b Mon Sep 17 00:00:00 2001 From: Davide Faconti Date: Wed, 14 Feb 2024 09:31:29 +0100 Subject: [PATCH 005/146] fixes and checks in default values, based on PR #773 --- .../behaviortree_cpp/actions/script_node.h | 2 +- include/behaviortree_cpp/basic_types.h | 13 +++-- src/xml_parsing.cpp | 38 ++++++++++++-- tests/gtest_ports.cpp | 51 ++++++++++++++++++- 4 files changed, 96 insertions(+), 8 deletions(-) diff --git a/include/behaviortree_cpp/actions/script_node.h b/include/behaviortree_cpp/actions/script_node.h index 3ab0fe0f6..a313a424a 100644 --- a/include/behaviortree_cpp/actions/script_node.h +++ b/include/behaviortree_cpp/actions/script_node.h @@ -31,7 +31,7 @@ class ScriptNode : public SyncActionNode static PortsList providedPorts() { - return {InputPort("code", "Piece of code that can be parsed")}; + return {InputPort("code", "Piece of code that can be parsed")}; } private: diff --git a/include/behaviortree_cpp/basic_types.h b/include/behaviortree_cpp/basic_types.h index 4c179e34e..4243c39c2 100644 --- a/include/behaviortree_cpp/basic_types.h +++ b/include/behaviortree_cpp/basic_types.h @@ -61,6 +61,11 @@ using StringView = std::string_view; // vector of key/value pairs using KeyValueVector = std::vector>; + +struct AnyTypeAllowed +{}; + + /** * convertFromString is used to convert a string into a custom type. * @@ -142,6 +147,11 @@ inline StringConverter GetAnyFromStringFunctor() { return [](StringView str) { return Any(str); }; } + else if constexpr(std::is_same_v || + std::is_enum_v) + { + return {}; + } else { return [](StringView str) { return Any(convertFromString(str)); }; } @@ -265,9 +275,6 @@ using Result = Expected; [[nodiscard]] bool IsAllowedPortName(StringView str); -struct AnyTypeAllowed -{}; - class TypeInfo { public: diff --git a/src/xml_parsing.cpp b/src/xml_parsing.cpp index 3bc73f2ba..8067ae595 100644 --- a/src/xml_parsing.cpp +++ b/src/xml_parsing.cpp @@ -636,7 +636,7 @@ TreeNode::Ptr XMLParser::PImpl::createNodeFromXML(const XMLElement* element, const TreeNodeManifest* manifest = nullptr; - auto manifest_it = factory.manifests().find(type_ID); + auto manifest_it = factory.manifests().find(type_ID); if(manifest_it != factory.manifests().end()) { manifest = &manifest_it->second; @@ -647,8 +647,40 @@ TreeNode::Ptr XMLParser::PImpl::createNodeFromXML(const XMLElement* element, { if (IsAllowedPortName(att->Name())) { - const std::string attribute_name = att->Name(); - port_remap[attribute_name] = att->Value(); + const std::string port_name = att->Name(); + const std::string port_value = att->Value(); + + if(manifest) + { + auto port_model_it = manifest->ports.find(port_name); + if(port_model_it == manifest->ports.end()) + { + throw RuntimeError(StrCat("a port with name [", port_name, + "] is found in the XML, but not in the providedPorts()")); + } + else { + const auto& port_model = port_model_it->second; + bool is_blacbkboard = port_value.size() >= 3 && + port_value.front() == '{' && + port_value.back() == '}'; + // let's test already if conversion is possible + if(!is_blacbkboard && port_model.converter() && port_model.isStronglyTyped()) + { + // This may throw + try { + port_model.converter()(port_value); + } + catch(std::exception& ex) + { + auto msg = StrCat("The port with name \"", port_name, "\" and value \"", port_value, + "\" can not be converted to ", port_model.typeName()); + throw LogicError(msg); + } + } + } + } + + port_remap[port_name] = port_value; } } diff --git a/tests/gtest_ports.cpp b/tests/gtest_ports.cpp index 0efbb4cc8..7a8a14f8a 100644 --- a/tests/gtest_ports.cpp +++ b/tests/gtest_ports.cpp @@ -533,8 +533,32 @@ TEST(PortTest, DefaultInputStrings) ASSERT_EQ(status, NodeStatus::SUCCESS); } +struct TestStruct +{ + int a; + double b; + std::string c; +}; -TEST(PortTest, Default_Issues_767_768) +class NodeWithDefaultNullptr : public SyncActionNode +{ +public: + NodeWithDefaultNullptr(const std::string& name, const NodeConfig& config) : + SyncActionNode(name, config) {} + + NodeStatus tick() override + { + return NodeStatus::SUCCESS; + } + + static PortsList providedPorts() + { + return {BT::InputPort< std::shared_ptr >("input", nullptr, "default value is nullptr")}; + } +}; + + +TEST(PortTest, Default_Issues_767) { using namespace BT; @@ -545,4 +569,29 @@ TEST(PortTest, Default_Issues_767_768) ASSERT_NO_THROW(auto p = InputPort>("ptr_B", nullptr, "default nullptr")); } +TEST(PortTest, DefaultWronglyOverriden) +{ + BT::BehaviorTreeFactory factory; + factory.registerNodeType("NodeWithDefaultNullptr"); + + std::string xml_txt_wrong = R"( + + + + + )"; + + std::string xml_txt_correct = R"( + + + + + )"; + // this should throw, because we are NOT using the default, + // but overriding it with an empty string instead. + // See issue 768 for reference + ASSERT_ANY_THROW( auto tree = factory.createTreeFromText(xml_txt_wrong)); + // This is correct + ASSERT_NO_THROW( auto tree = factory.createTreeFromText(xml_txt_correct)); +} From 3073f2904921fa248185f293f046358c97a42eed Mon Sep 17 00:00:00 2001 From: Davide Faconti Date: Mon, 19 Feb 2024 13:20:52 +0100 Subject: [PATCH 006/146] added more pretty-prints to demangler --- .../behaviortree_cpp/utils/demangle_util.h | 32 ++++++++----------- 1 file changed, 14 insertions(+), 18 deletions(-) diff --git a/include/behaviortree_cpp/utils/demangle_util.h b/include/behaviortree_cpp/utils/demangle_util.h index 1b986084a..93c90d2ad 100644 --- a/include/behaviortree_cpp/utils/demangle_util.h +++ b/include/behaviortree_cpp/utils/demangle_util.h @@ -1,6 +1,7 @@ #ifndef DEMANGLE_UTIL_H #define DEMANGLE_UTIL_H +#include #include #include @@ -83,30 +84,24 @@ inline std::string demangle(const std::type_index& index) { return "std::string"; } - - scoped_demangled_name demangled_name(index.name()); - char const* const p = demangled_name.get(); - if (p) + if (index == typeid(std::string_view)) { - return p; + return "std::string_view"; } - else + if (index == typeid(std::chrono::seconds)) { - return index.name(); + return "std::chrono::seconds"; } -} - -inline std::string demangle(const std::type_info* info) -{ - if (!info) + if (index == typeid(std::chrono::milliseconds)) { - return "void"; + return "std::chrono::milliseconds"; } - if (info == &typeid(std::string)) + if (index == typeid(std::chrono::microseconds)) { - return "std::string"; + return "std::chrono::microseconds"; } - scoped_demangled_name demangled_name(info->name()); + + scoped_demangled_name demangled_name(index.name()); char const* const p = demangled_name.get(); if (p) { @@ -114,13 +109,14 @@ inline std::string demangle(const std::type_info* info) } else { - return info->name(); + return index.name(); } } + inline std::string demangle(const std::type_info& info) { - return demangle(&info); + return demangle(std::type_index(info)); } } // namespace BT From f3a65563c1a1a48f24891260f09891b908752e2a Mon Sep 17 00:00:00 2001 From: Davide Faconti Date: Fri, 1 Mar 2024 14:05:08 +0100 Subject: [PATCH 007/146] add unit test --- tests/gtest_preconditions.cpp | 38 +++++++++++++++++++++++++++++++++++ 1 file changed, 38 insertions(+) diff --git a/tests/gtest_preconditions.cpp b/tests/gtest_preconditions.cpp index 26d55cba8..bce8a9486 100644 --- a/tests/gtest_preconditions.cpp +++ b/tests/gtest_preconditions.cpp @@ -298,3 +298,41 @@ TEST(Preconditions, Issue615_NoSkipWhenRunning_B) tree.rootBlackboard()->set("check", false); ASSERT_EQ( tree.tickOnce(), NodeStatus::RUNNING ); } + + + +TEST(Preconditions, Remapping) +{ + static constexpr auto xml_text = R"( + + + + +