Thanks to visit codestin.com
Credit goes to github.com

Skip to content

Commit 49355fd

Browse files
committed
Add optional metadata to TreeNodeManifest
1 parent db5789e commit 49355fd

File tree

6 files changed

+132
-12
lines changed

6 files changed

+132
-12
lines changed

include/behaviortree_cpp/basic_types.h

Lines changed: 39 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -10,7 +10,9 @@
1010
#include <chrono>
1111
#include <memory>
1212
#include <string_view>
13+
#include <utility>
1314
#include <variant>
15+
#include <vector>
1416
#include <optional>
1517

1618
#include "behaviortree_cpp/utils/safe_any.hpp"
@@ -450,6 +452,43 @@ struct has_static_method_description<
450452
{
451453
};
452454

455+
/// Optional metadata for a TreeNodeManifest.
456+
/// The metadata can represent an xml element with text:
457+
/// <metadata_name>Descriptive text</metadata_name>
458+
/// Or an xml element with an attribute:
459+
/// <metadata_name attribute="value"/>
460+
struct ManifestMetadata
461+
{
462+
/// A pair containing the <name, value> of a metadata's XML attribute.
463+
using Attribute = std::pair<std::string, std::string>;
464+
465+
[[nodiscard]] bool representsText() const
466+
{
467+
return std::holds_alternative<std::string>(text_or_attribute);
468+
}
469+
470+
[[nodiscard]] bool representsAttribute() const
471+
{
472+
return std::holds_alternative<Attribute>(text_or_attribute);
473+
}
474+
475+
std::string name;
476+
std::variant<std::string, Attribute> text_or_attribute;
477+
};
478+
479+
template <typename T, typename = void>
480+
struct has_static_method_metadata : std::false_type
481+
{
482+
};
483+
484+
template <typename T>
485+
struct has_static_method_metadata<
486+
T, typename std::enable_if<
487+
std::is_same<decltype(T::metadata()), std::vector<ManifestMetadata>>::value>::type>
488+
: std::true_type
489+
{
490+
};
491+
453492
template <typename T> [[nodiscard]]
454493
inline PortsList getProvidedPorts(enable_if<has_static_method_providedPorts<T>> = nullptr)
455494
{
@@ -467,4 +506,3 @@ using TimePoint = std::chrono::high_resolution_clock::time_point;
467506
using Duration = std::chrono::high_resolution_clock::duration;
468507

469508
} // namespace BT
470-

include/behaviortree_cpp/bt_factory.h

Lines changed: 11 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -44,13 +44,20 @@ template <typename T>
4444
inline TreeNodeManifest CreateManifest(const std::string& ID,
4545
PortsList portlist = getProvidedPorts<T>())
4646
{
47-
if constexpr( has_static_method_description<T>::value)
47+
if constexpr( has_static_method_description<T>::value && has_static_method_metadata<T>::value )
4848
{
49-
return {getType<T>(), ID, portlist, T::description()};
49+
return {getType<T>(), ID, portlist, T::description(), T::metadata()};
5050
}
51-
else {
52-
return {getType<T>(), ID, portlist, {}};
51+
else if constexpr( has_static_method_description<T>::value && !has_static_method_metadata<T>::value )
52+
{
53+
return {getType<T>(), ID, portlist, T::description(), {}};
54+
}
55+
else if constexpr( !has_static_method_description<T>::value && has_static_method_metadata<T>::value )
56+
{
57+
return {getType<T>(), ID, portlist, {}, T::metadata()};
5358
}
59+
60+
return {getType<T>(), ID, portlist, {}, {}};
5461
}
5562

5663
#ifdef BT_PLUGIN_EXPORT

include/behaviortree_cpp/tree_node.h

Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -17,6 +17,7 @@
1717
#include <exception>
1818
#include <mutex>
1919
#include <map>
20+
#include <vector>
2021

2122
#include "behaviortree_cpp/utils/signal.h"
2223
#include "behaviortree_cpp/basic_types.h"
@@ -39,6 +40,7 @@ struct TreeNodeManifest
3940
std::string registration_ID;
4041
PortsList ports;
4142
std::string description;
43+
std::vector<ManifestMetadata> metadata;
4244
};
4345

4446
using PortsRemapping = std::unordered_map<std::string, std::string>;

src/bt_factory.cpp

Lines changed: 4 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -91,7 +91,7 @@ BehaviorTreeFactory::BehaviorTreeFactory():
9191
registerNodeType<SwitchNode<4>>("Switch4");
9292
registerNodeType<SwitchNode<5>>("Switch5");
9393
registerNodeType<SwitchNode<6>>("Switch6");
94-
94+
9595
registerNodeType<LoopNode<int>>("LoopInt");
9696
registerNodeType<LoopNode<bool>>("LoopBool");
9797
registerNodeType<LoopNode<double>>("LoopDouble");
@@ -157,7 +157,7 @@ void BehaviorTreeFactory::registerSimpleCondition(
157157
return std::make_unique<SimpleConditionNode>(name, tick_functor, config);
158158
};
159159

160-
TreeNodeManifest manifest = {NodeType::CONDITION, ID, std::move(ports), {}};
160+
TreeNodeManifest manifest = {NodeType::CONDITION, ID, std::move(ports), {}, {}};
161161
registerBuilder(manifest, builder);
162162
}
163163

@@ -170,7 +170,7 @@ void BehaviorTreeFactory::registerSimpleAction(
170170
return std::make_unique<SimpleActionNode>(name, tick_functor, config);
171171
};
172172

173-
TreeNodeManifest manifest = {NodeType::ACTION, ID, std::move(ports), {}};
173+
TreeNodeManifest manifest = {NodeType::ACTION, ID, std::move(ports), {}, {}};
174174
registerBuilder(manifest, builder);
175175
}
176176

@@ -183,7 +183,7 @@ void BehaviorTreeFactory::registerSimpleDecorator(
183183
return std::make_unique<SimpleDecoratorNode>(name, tick_functor, config);
184184
};
185185

186-
TreeNodeManifest manifest = {NodeType::DECORATOR, ID, std::move(ports), {}};
186+
TreeNodeManifest manifest = {NodeType::DECORATOR, ID, std::move(ports), {}, {}};
187187
registerBuilder(manifest, builder);
188188
}
189189

src/xml_parsing.cpp

Lines changed: 20 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -83,7 +83,7 @@ struct XMLParser::PImpl
8383
std::map<std::string, SubtreeModel> subtree_models;
8484

8585
int suffix_count;
86-
86+
8787
explicit PImpl(const BehaviorTreeFactory& fact) :
8888
factory(fact), current_path(std::filesystem::current_path()), suffix_count(0)
8989
{}
@@ -989,6 +989,24 @@ void addNodeModelToXML(const TreeNodeManifest& model,
989989
element->InsertEndChild(description_element);
990990
}
991991

992+
for (const auto& metadata : model.metadata)
993+
{
994+
auto metadata_element = doc.NewElement(metadata.name.c_str());
995+
996+
if (metadata.representsText())
997+
{
998+
const auto element_text = std::get<std::string>(metadata.text_or_attribute);
999+
metadata_element->SetText(element_text.c_str());
1000+
}
1001+
else
1002+
{
1003+
const auto [attribute_name, attribute_val] = std::get<ManifestMetadata::Attribute>(metadata.text_or_attribute);
1004+
metadata_element->SetAttribute(attribute_name.c_str(), attribute_val.c_str());
1005+
}
1006+
1007+
element->InsertEndChild(metadata_element);
1008+
}
1009+
9921010
model_root->InsertEndChild(element);
9931011
}
9941012

@@ -997,7 +1015,7 @@ void addTreeToXML(const Tree& tree,
9971015
XMLElement* rootXML,
9981016
bool add_metadata,
9991017
bool add_builtin_models)
1000-
{
1018+
{
10011019
std::function<void(const TreeNode&, XMLElement*)> addNode;
10021020
addNode = [&](const TreeNode& node,
10031021
XMLElement* parent_elem)

tests/gtest_factory.cpp

Lines changed: 56 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -1,5 +1,8 @@
11
#include <gtest/gtest.h>
22
#include <filesystem>
3+
#include <string>
4+
#include <utility>
5+
#include <vector>
36
#include "behaviortree_cpp/xml_parsing.h"
47
#include "../sample_nodes/crossdoor_nodes.h"
58
#include "../sample_nodes/dummy_nodes.h"
@@ -409,7 +412,6 @@ class DescriptiveAction : public SyncActionNode
409412

410413
TEST(BehaviorTreeFactory, DescriptionMethod)
411414
{
412-
413415
BehaviorTreeFactory factory;
414416
factory.registerNodeType<DescriptiveAction>("DescriptiveAction");
415417
const auto& manifest = factory.manifests().at("DescriptiveAction");
@@ -420,3 +422,56 @@ TEST(BehaviorTreeFactory, DescriptionMethod)
420422

421423
ASSERT_NE(xml.find( "<description>THE DESCRIPTION</description>"), std::string::npos);
422424
}
425+
426+
std::vector<ManifestMetadata> makeTestMetadata()
427+
{
428+
ManifestMetadata text_metadata;
429+
text_metadata.name = "text_metadata";
430+
text_metadata.text_or_attribute = "text";
431+
432+
ManifestMetadata attribute_metadata;
433+
attribute_metadata.name = "attribute_metadata";
434+
attribute_metadata.text_or_attribute = std::make_pair<std::string, std::string>("attribute_name", "attribute_value");
435+
436+
return {text_metadata, attribute_metadata};
437+
}
438+
439+
class ActionWithMetadata : public SyncActionNode
440+
{
441+
public:
442+
ActionWithMetadata(const std::string& name, const NodeConfig& config):
443+
SyncActionNode(name, config) {}
444+
445+
BT::NodeStatus tick() override {
446+
return NodeStatus::SUCCESS;
447+
}
448+
449+
static PortsList providedPorts() {
450+
return {};
451+
}
452+
453+
static std::vector<ManifestMetadata> metadata() {
454+
return makeTestMetadata();
455+
}
456+
};
457+
458+
TEST(BehaviorTreeFactory, ManifestMethod)
459+
{
460+
BehaviorTreeFactory factory;
461+
factory.registerNodeType<ActionWithMetadata>("ActionWithMetadata");
462+
const auto& manifest = factory.manifests().at("ActionWithMetadata");
463+
ASSERT_EQ(manifest.metadata.size(), 2u);
464+
auto expected_metadata = makeTestMetadata();
465+
EXPECT_EQ(manifest.metadata[0].name, expected_metadata[0].name);
466+
EXPECT_EQ(manifest.metadata[0].text_or_attribute, expected_metadata[0].text_or_attribute);
467+
EXPECT_TRUE(manifest.metadata[0].representsText());
468+
EXPECT_EQ(manifest.metadata[1].name, expected_metadata[1].name);
469+
EXPECT_EQ(manifest.metadata[1].text_or_attribute, expected_metadata[1].text_or_attribute);
470+
EXPECT_TRUE(manifest.metadata[1].representsAttribute());
471+
472+
auto xml = writeTreeNodesModelXML(factory, false);
473+
std::cout << xml << std::endl;
474+
475+
ASSERT_NE(xml.find("<text_metadata>text</text_metadata>"), std::string::npos);
476+
ASSERT_NE(xml.find("<attribute_metadata attribute_name=\"attribute_value\"/>"), std::string::npos);
477+
}

0 commit comments

Comments
 (0)