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

Skip to content

Commit a92b7bd

Browse files
committed
allow Input/Output ports with type Any
1 parent b401974 commit a92b7bd

File tree

4 files changed

+111
-4
lines changed

4 files changed

+111
-4
lines changed

include/behaviortree_cpp/basic_types.h

Lines changed: 2 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -297,7 +297,8 @@ class TypeInfo
297297

298298
[[nodiscard]] bool isStronglyTyped() const
299299
{
300-
return type_info_ != typeid(AnyTypeAllowed);
300+
return type_info_ != typeid(AnyTypeAllowed) &&
301+
type_info_ != typeid(BT::Any);
301302
}
302303

303304
[[nodiscard]] const StringConverter& converter() const

include/behaviortree_cpp/blackboard.h

Lines changed: 9 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -196,7 +196,15 @@ class Blackboard
196196
throw LogicError(msg);
197197
}
198198
}
199-
new_value.copyInto(previous_any);
199+
// if doing set<BT::Any>, skip type check
200+
if constexpr(std::is_same_v<Any, T>)
201+
{
202+
previous_any = new_value;
203+
}
204+
else {
205+
// copy only if the type is compatible
206+
new_value.copyInto(previous_any);
207+
}
200208
}
201209
}
202210

include/behaviortree_cpp/tree_node.h

Lines changed: 17 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -441,10 +441,16 @@ inline Result TreeNode::getInput(const std::string& key, T& destination) const
441441
if (auto any_ref = config().blackboard->getAnyLocked(std::string(remapped_key)))
442442
{
443443
auto val = any_ref.get();
444+
// support getInput<Any>()
445+
if constexpr (std::is_same_v<T, Any>)
446+
{
447+
destination = *val;
448+
return {};
449+
}
450+
444451
if(!val->empty())
445452
{
446-
if (!std::is_same_v<T, std::string> &&
447-
val->type() == typeid(std::string))
453+
if (!std::is_same_v<T, std::string> && val->isString())
448454
{
449455
destination = ParseString(val->cast<std::string>());
450456
}
@@ -495,6 +501,15 @@ inline Result TreeNode::setOutput(const std::string& key, const T& value)
495501
return nonstd::make_unexpected("setOutput requires a blackboard pointer. Use {}");
496502
}
497503

504+
if constexpr(std::is_same_v<BT::Any, T>)
505+
{
506+
if(config().manifest->ports.at(key).type() != typeid(BT::Any))
507+
{
508+
throw LogicError("setOutput<Any> is not allowed, unless the port "
509+
"was declared using OutputPort<Any>");
510+
}
511+
}
512+
498513
remapped_key = stripBlackboardPointer(remapped_key);
499514
config().blackboard->set(static_cast<std::string>(remapped_key), value);
500515

tests/gtest_ports.cpp

Lines changed: 83 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -289,3 +289,86 @@ TEST(PortTest, DefaultInput)
289289
}
290290

291291

292+
class GetAny : public SyncActionNode
293+
{
294+
public:
295+
GetAny(const std::string& name, const NodeConfig& config) :
296+
SyncActionNode(name, config)
297+
{}
298+
299+
NodeStatus tick() override
300+
{
301+
// case 1: the port is Any, but we can cast dirrectly to string
302+
auto res_str = getInput<std::string>("val_str");
303+
// case 2: the port is Any, and we retrieve an Any (to be casted later)
304+
auto res_int = getInput<BT::Any>("val_int");
305+
306+
// case 3: port is double and we get a double
307+
auto res_real_A = getInput<double>("val_real");
308+
// case 4: port is double and we get an Any
309+
auto res_real_B = getInput<BT::Any>("val_real");
310+
311+
bool expected = res_str.value() == "hello" &&
312+
res_int->cast<int>() == 42 &&
313+
res_real_A.value() == 3.14 &&
314+
res_real_B->cast<double>() == 3.14;
315+
316+
return expected ? NodeStatus::SUCCESS : NodeStatus::FAILURE;
317+
}
318+
319+
static PortsList providedPorts()
320+
{
321+
return {BT::InputPort<BT::Any>("val_str"),
322+
BT::InputPort<BT::Any>("val_int"),
323+
BT::InputPort<double>("val_real")};
324+
}
325+
};
326+
327+
class SetAny : public SyncActionNode
328+
{
329+
public:
330+
SetAny(const std::string& name, const NodeConfig& config) :
331+
SyncActionNode(name, config)
332+
{}
333+
334+
NodeStatus tick() override
335+
{
336+
// check that the port can contain different types
337+
setOutput("val_str", BT::Any(1.0));
338+
setOutput("val_str", BT::Any(1));
339+
setOutput("val_str", BT::Any("hello"));
340+
341+
setOutput("val_int", 42);
342+
setOutput("val_real", 3.14);
343+
return NodeStatus::SUCCESS;
344+
}
345+
346+
static PortsList providedPorts()
347+
{
348+
return {BT::OutputPort<BT::Any>("val_str"),
349+
BT::OutputPort<int>("val_int"),
350+
BT::OutputPort<BT::Any>("val_real")};
351+
}
352+
};
353+
354+
TEST(PortTest, AnyPort)
355+
{
356+
std::string xml_txt = R"(
357+
<root BTCPP_format="4" >
358+
<BehaviorTree>
359+
<Sequence>
360+
<SetAny val_str="{val_str}" val_int="{val_int}" val_real="{val_real}"/>
361+
<GetAny val_str="{val_str}" val_int="{val_int}" val_real="{val_real}"/>
362+
</Sequence>
363+
</BehaviorTree>
364+
</root>)";
365+
366+
BehaviorTreeFactory factory;
367+
factory.registerNodeType<SetAny>("SetAny");
368+
factory.registerNodeType<GetAny>("GetAny");
369+
auto tree = factory.createTreeFromText(xml_txt);
370+
auto status = tree.tickOnce();
371+
ASSERT_EQ(status, NodeStatus::SUCCESS);
372+
}
373+
374+

0 commit comments

Comments
 (0)