Skip to content

Commit b8fd0b2

Browse files
Adding the reserved word "_description" (#394)
1 parent 8a8ec27 commit b8fd0b2

File tree

6 files changed

+91
-15
lines changed

6 files changed

+91
-15
lines changed

include/behaviortree_cpp_v3/basic_types.h

Lines changed: 14 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -209,6 +209,12 @@ template <typename T> using Optional = nonstd::expected<T, std::string>;
209209
* */
210210
using Result = Optional<void>;
211211

212+
213+
const std::unordered_set<std::string> ReservedPortNames =
214+
{
215+
"ID", "name", "_description"
216+
};
217+
212218
class PortInfo
213219
{
214220

@@ -261,15 +267,20 @@ std::pair<std::string,PortInfo> CreatePort(PortDirection direction,
261267
StringView name,
262268
StringView description = {})
263269
{
270+
auto sname = static_cast<std::string>(name);
271+
if( ReservedPortNames.count(sname) != 0 )
272+
{
273+
throw std::runtime_error("A port can not use a reserved name. See ReservedPortNames");
274+
}
275+
264276
std::pair<std::string,PortInfo> out;
265277

266278
if( std::is_same<T, void>::value)
267279
{
268-
out = {static_cast<std::string>(name), PortInfo(direction) };
280+
out = {sname, PortInfo(direction) };
269281
}
270282
else{
271-
out = {static_cast<std::string>(name), PortInfo(direction, typeid(T),
272-
GetAnyFromStringFunctor<T>() ) };
283+
out = {sname, PortInfo(direction, typeid(T), GetAnyFromStringFunctor<T>() ) };
273284
}
274285
if( !description.empty() )
275286
{

include/behaviortree_cpp_v3/bt_factory.h

Lines changed: 4 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -425,6 +425,10 @@ class BehaviorTreeFactory
425425
Tree createTree(const std::string& tree_name,
426426
Blackboard::Ptr blackboard = Blackboard::create());
427427

428+
/// Add a description to a specific manifest. This description will be added
429+
/// to <TreeNodesModel> with the function writeTreeNodesModelXML()
430+
void addDescriptionToManifest(const std::string& node_id, const std::string& description );
431+
428432
private:
429433
std::unordered_map<std::string, NodeBuilder> builders_;
430434
std::unordered_map<std::string, TreeNodeManifest> manifests_;

include/behaviortree_cpp_v3/tree_node.h

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -35,6 +35,7 @@ struct TreeNodeManifest
3535
NodeType type;
3636
std::string registration_ID;
3737
PortsList ports;
38+
std::string description;
3839
};
3940

4041
typedef std::unordered_map<std::string, std::string> PortsRemapping;

src/bt_factory.cpp

Lines changed: 10 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -294,6 +294,16 @@ Tree BehaviorTreeFactory::createTree(const std::string &tree_name, Blackboard::P
294294
return tree;
295295
}
296296

297+
void BehaviorTreeFactory::addDescriptionToManifest(const std::string &node_id, const std::string &description)
298+
{
299+
auto it = manifests_.find(node_id);
300+
if( it == manifests_.end() )
301+
{
302+
throw std::runtime_error("addDescriptionToManifest: wrong ID");
303+
}
304+
it->second.description = description;
305+
}
306+
297307
void Tree::sleep(std::chrono::system_clock::duration timeout)
298308
{
299309
wake_up_->waitFor(timeout);

src/xml_parsing.cpp

Lines changed: 14 additions & 12 deletions
Original file line numberDiff line numberDiff line change
@@ -516,7 +516,7 @@ TreeNode::Ptr XMLParser::Pimpl::createNodeFromXML(const XMLElement *element,
516516
for (const XMLAttribute* att = element->FirstAttribute(); att; att = att->Next())
517517
{
518518
const std::string attribute_name = att->Name();
519-
if (attribute_name != "ID" && attribute_name != "name")
519+
if ( ReservedPortNames.count(attribute_name) == 0 )
520520
{
521521
port_remap[attribute_name] = att->Value();
522522
}
@@ -661,10 +661,10 @@ void BT::XMLParser::Pimpl::recursivelyCreateTree(const std::string& tree_ID,
661661

662662
for (const XMLAttribute* attr = element->FirstAttribute(); attr != nullptr; attr = attr->Next())
663663
{
664-
if( strcmp(attr->Name(), "__shared_blackboard") == 0 &&
665-
convertFromString<bool>(attr->Value()) == true )
664+
if( StrEqual(attr->Name(), "__shared_blackboard") )
666665
{
667-
is_isolated = false;
666+
is_isolated = !convertFromString<bool>(attr->Value());
667+
break;
668668
}
669669
}
670670

@@ -678,11 +678,10 @@ void BT::XMLParser::Pimpl::recursivelyCreateTree(const std::string& tree_ID,
678678

679679
for (const XMLAttribute* attr = element->FirstAttribute(); attr != nullptr; attr = attr->Next())
680680
{
681-
if( strcmp(attr->Name(), "ID") == 0 )
681+
if( ReservedPortNames.count(attr->Name()) == 0 )
682682
{
683-
continue;
683+
new_bb->addSubtreeRemapping( attr->Name(), attr->Value() );
684684
}
685-
new_bb->addSubtreeRemapping( attr->Name(), attr->Value() );
686685
}
687686
output_tree.blackboard_stack.emplace_back(new_bb);
688687
recursivelyCreateTree( node->name(), output_tree, new_bb, node );
@@ -701,7 +700,7 @@ void BT::XMLParser::Pimpl::recursivelyCreateTree(const std::string& tree_ID,
701700
const char* attr_name = attr->Name();
702701
const char* attr_value = attr->Value();
703702

704-
if( StrEqual(attr_name, "ID") )
703+
if( ReservedPortNames.count(attr->Name()) != 0 )
705704
{
706705
continue;
707706
}
@@ -772,9 +771,8 @@ void XMLParser::Pimpl::getPortsRecursively(const XMLElement *element,
772771
{
773772
const char* attr_name = attr->Name();
774773
const char* attr_value = attr->Value();
775-
if( !StrEqual(attr_name, "ID") &&
776-
!StrEqual(attr_name, "name") &&
777-
TreeNode::isBlackboardPointer(attr_value) )
774+
if( ReservedPortNames.count(attr_name) == 0 &&
775+
TreeNode::isBlackboardPointer(attr_value) )
778776
{
779777
auto port_name = TreeNode::stripBlackboardPointer(attr_value);
780778
output_ports.push_back( static_cast<std::string>(port_name) );
@@ -870,10 +868,14 @@ std::string writeTreeNodesModelXML(const BehaviorTreeFactory& factory,
870868
{
871869
port_element->SetText( port_info.description().c_str() );
872870
}
873-
874871
element->InsertEndChild(port_element);
875872
}
876873

874+
if(!model.description.empty())
875+
{
876+
element->SetAttribute("description", model.registration_ID.c_str());
877+
}
878+
877879
model_root->InsertEndChild(element);
878880
}
879881

tests/gtest_ports.cpp

Lines changed: 48 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -50,6 +50,32 @@ TEST(PortTest, DefaultPorts)
5050
ASSERT_EQ( status, NodeStatus::SUCCESS );
5151
}
5252

53+
TEST(PortTest, Descriptions)
54+
{
55+
std::string xml_txt = R"(
56+
<root main_tree_to_execute = "MainTree" >
57+
<BehaviorTree ID="MainTree" _description="this is my tree" >
58+
<Sequence>
59+
<NodeWithPorts name="first" in_port_B="66" _description="this is my action" />
60+
<SubTree ID="SubTree" name="second" _description="this is a subtree"/>
61+
</Sequence>
62+
</BehaviorTree>
63+
64+
<BehaviorTree ID="SubTree" _description="this is a subtre" >
65+
<NodeWithPorts name="third" in_port_B="99" />
66+
</BehaviorTree>
67+
68+
</root>)";
69+
70+
BehaviorTreeFactory factory;
71+
factory.registerNodeType<NodeWithPorts>("NodeWithPorts");
72+
73+
auto tree = factory.createTreeFromText(xml_txt);
74+
75+
NodeStatus status = tree.tickRoot();
76+
ASSERT_EQ( status, NodeStatus::FAILURE ); // failure because in_port_B="99"
77+
}
78+
5379
struct MyType
5480
{
5581
std::string value;
@@ -126,3 +152,25 @@ TEST(PortTest, EmptyPort)
126152
ASSERT_EQ( status, NodeStatus::FAILURE );
127153
}
128154

155+
156+
class IllegalPorts: public SyncActionNode
157+
{
158+
public:
159+
IllegalPorts(const std::string & name, const NodeConfiguration & config)
160+
: SyncActionNode(name, config)
161+
{ }
162+
163+
NodeStatus tick() { return NodeStatus::SUCCESS; }
164+
165+
static PortsList providedPorts()
166+
{
167+
return { BT::InputPort<std::string>("name") };
168+
}
169+
};
170+
171+
TEST(PortTest, IllegalPorts)
172+
{
173+
BehaviorTreeFactory factory;
174+
ASSERT_ANY_THROW(factory.registerNodeType<IllegalPorts>("nope"));
175+
}
176+

0 commit comments

Comments
 (0)