Skip to content

Commit

Permalink
allow Input/Output ports with type Any
Browse files Browse the repository at this point in the history
  • Loading branch information
facontidavide committed Jan 10, 2024
1 parent b401974 commit a92b7bd
Show file tree
Hide file tree
Showing 4 changed files with 111 additions and 4 deletions.
3 changes: 2 additions & 1 deletion include/behaviortree_cpp/basic_types.h
Original file line number Diff line number Diff line change
Expand Up @@ -297,7 +297,8 @@ class TypeInfo

[[nodiscard]] bool isStronglyTyped() const
{
return type_info_ != typeid(AnyTypeAllowed);
return type_info_ != typeid(AnyTypeAllowed) &&
type_info_ != typeid(BT::Any);
}

[[nodiscard]] const StringConverter& converter() const
Expand Down
10 changes: 9 additions & 1 deletion include/behaviortree_cpp/blackboard.h
Original file line number Diff line number Diff line change
Expand Up @@ -196,7 +196,15 @@ class Blackboard
throw LogicError(msg);
}
}
new_value.copyInto(previous_any);
// if doing set<BT::Any>, skip type check
if constexpr(std::is_same_v<Any, T>)
{
previous_any = new_value;
}
else {
// copy only if the type is compatible
new_value.copyInto(previous_any);
}
}
}

Expand Down
19 changes: 17 additions & 2 deletions include/behaviortree_cpp/tree_node.h
Original file line number Diff line number Diff line change
Expand Up @@ -441,10 +441,16 @@ inline Result TreeNode::getInput(const std::string& key, T& destination) const
if (auto any_ref = config().blackboard->getAnyLocked(std::string(remapped_key)))
{
auto val = any_ref.get();
// support getInput<Any>()
if constexpr (std::is_same_v<T, Any>)
{
destination = *val;
return {};
}

if(!val->empty())
{
if (!std::is_same_v<T, std::string> &&
val->type() == typeid(std::string))
if (!std::is_same_v<T, std::string> && val->isString())
{
destination = ParseString(val->cast<std::string>());
}
Expand Down Expand Up @@ -495,6 +501,15 @@ inline Result TreeNode::setOutput(const std::string& key, const T& value)
return nonstd::make_unexpected("setOutput requires a blackboard pointer. Use {}");
}

if constexpr(std::is_same_v<BT::Any, T>)
{
if(config().manifest->ports.at(key).type() != typeid(BT::Any))
{
throw LogicError("setOutput<Any> is not allowed, unless the port "
"was declared using OutputPort<Any>");
}
}

remapped_key = stripBlackboardPointer(remapped_key);
config().blackboard->set(static_cast<std::string>(remapped_key), value);

Expand Down
83 changes: 83 additions & 0 deletions tests/gtest_ports.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -289,3 +289,86 @@ TEST(PortTest, DefaultInput)
}


class GetAny : public SyncActionNode
{
public:
GetAny(const std::string& name, const NodeConfig& config) :
SyncActionNode(name, config)
{}

NodeStatus tick() override
{
// case 1: the port is Any, but we can cast dirrectly to string
auto res_str = getInput<std::string>("val_str");
// case 2: the port is Any, and we retrieve an Any (to be casted later)
auto res_int = getInput<BT::Any>("val_int");

// case 3: port is double and we get a double
auto res_real_A = getInput<double>("val_real");
// case 4: port is double and we get an Any
auto res_real_B = getInput<BT::Any>("val_real");

bool expected = res_str.value() == "hello" &&
res_int->cast<int>() == 42 &&
res_real_A.value() == 3.14 &&
res_real_B->cast<double>() == 3.14;

return expected ? NodeStatus::SUCCESS : NodeStatus::FAILURE;
}

static PortsList providedPorts()
{
return {BT::InputPort<BT::Any>("val_str"),
BT::InputPort<BT::Any>("val_int"),
BT::InputPort<double>("val_real")};
}
};

class SetAny : public SyncActionNode
{
public:
SetAny(const std::string& name, const NodeConfig& config) :
SyncActionNode(name, config)
{}

NodeStatus tick() override
{
// check that the port can contain different types
setOutput("val_str", BT::Any(1.0));
setOutput("val_str", BT::Any(1));
setOutput("val_str", BT::Any("hello"));

setOutput("val_int", 42);
setOutput("val_real", 3.14);
return NodeStatus::SUCCESS;
}

static PortsList providedPorts()
{
return {BT::OutputPort<BT::Any>("val_str"),
BT::OutputPort<int>("val_int"),
BT::OutputPort<BT::Any>("val_real")};
}
};

TEST(PortTest, AnyPort)
{
std::string xml_txt = R"(
<root BTCPP_format="4" >
<BehaviorTree>
<Sequence>
<SetAny val_str="{val_str}" val_int="{val_int}" val_real="{val_real}"/>
<GetAny val_str="{val_str}" val_int="{val_int}" val_real="{val_real}"/>
</Sequence>
</BehaviorTree>
</root>)";

BehaviorTreeFactory factory;
factory.registerNodeType<SetAny>("SetAny");
factory.registerNodeType<GetAny>("GetAny");
auto tree = factory.createTreeFromText(xml_txt);
auto status = tree.tickOnce();
ASSERT_EQ(status, NodeStatus::SUCCESS);
}


0 comments on commit a92b7bd

Please sign in to comment.