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

Skip to content

Commit 789ce6e

Browse files
committed
new default port capability: keys
1 parent c4ad3cd commit 789ce6e

File tree

4 files changed

+247
-43
lines changed

4 files changed

+247
-43
lines changed

include/behaviortree_cpp/basic_types.h

Lines changed: 138 additions & 12 deletions
Original file line numberDiff line numberDiff line change
@@ -1,12 +1,11 @@
11
#pragma once
22

3+
#include <chrono>
34
#include <iostream>
4-
#include <vector>
5-
#include <unordered_map>
6-
#include <typeinfo>
75
#include <functional>
8-
#include <chrono>
96
#include <string_view>
7+
#include <typeinfo>
8+
#include <unordered_map>
109
#include <utility>
1110
#include <variant>
1211
#include <vector>
@@ -156,11 +155,17 @@ inline StringConverter GetAnyFromStringFunctor<void>()
156155

157156
//------------------------------------------------------------------
158157

158+
template <typename T>
159+
constexpr bool IsConvertibleToString()
160+
{
161+
return std::is_convertible_v<T, std::string> ||
162+
std::is_convertible_v<T, std::string_view>;
163+
}
164+
159165
template<typename T> [[nodiscard]]
160166
std::string toStr(const T& value)
161167
{
162-
if constexpr (std::is_convertible_v<T, std::string> ||
163-
std::is_convertible_v<T, std::string_view>)
168+
if constexpr (IsConvertibleToString<T>())
164169
{
165170
return value;
166171
}
@@ -169,8 +174,9 @@ std::string toStr(const T& value)
169174
throw LogicError(
170175
StrCat("Function BT::toStr<T>() not specialized for type [",
171176
BT::demangle(typeid(T)), "]")
172-
);
173-
} else {
177+
);
178+
}
179+
else {
174180
return std::to_string(value);
175181
}
176182
}
@@ -383,45 +389,165 @@ std::pair<std::string, PortInfo> CreatePort(PortDirection direction,
383389
}
384390

385391
//----------
392+
/** Syntactic sugar to invoke CreatePort<T>(PortDirection::INPUT, ...)
393+
*
394+
* @param name the name of the port
395+
* @param description optional human-readable description
396+
*/
386397
template <typename T = AnyTypeAllowed> [[nodiscard]]
387398
inline std::pair<std::string, PortInfo> InputPort(StringView name,
388399
StringView description = {})
389400
{
390401
return CreatePort<T>(PortDirection::INPUT, name, description);
391402
}
392403

404+
/** Syntactic sugar to invoke CreatePort<T>(PortDirection::OUTPUT,...)
405+
*
406+
* @param name the name of the port
407+
* @param description optional human-readable description
408+
*/
393409
template <typename T = AnyTypeAllowed> [[nodiscard]]
394410
inline std::pair<std::string, PortInfo> OutputPort(StringView name,
395411
StringView description = {})
396412
{
397413
return CreatePort<T>(PortDirection::OUTPUT, name, description);
398414
}
399415

416+
/** Syntactic sugar to invoke CreatePort<T>(PortDirection::INOUT,...)
417+
*
418+
* @param name the name of the port
419+
* @param description optional human-readable description
420+
*/
400421
template <typename T = AnyTypeAllowed> [[nodiscard]]
401422
inline std::pair<std::string, PortInfo> BidirectionalPort(StringView name,
402423
StringView description = {})
403424
{
404425
return CreatePort<T>(PortDirection::INOUT, name, description);
405426
}
406427
//----------
407-
template <typename T = AnyTypeAllowed> [[nodiscard]]
408-
inline std::pair<std::string, PortInfo> InputPort(StringView name, const T& default_value,
428+
/** Syntactic sugar to invoke CreatePort<T>(PortDirection::INPUT,...)
429+
* It also sets the PortInfo::defaultValue()
430+
*
431+
* @param name the name of the port
432+
* @param default_value default value of the port, either type T of BlackboardKey
433+
* @param description optional human-readable description
434+
*/
435+
template <typename T = AnyTypeAllowed, typename DefaultT = T> [[nodiscard]]
436+
inline std::pair<std::string, PortInfo> InputPort(StringView name,
437+
const DefaultT& default_value,
409438
StringView description)
410439
{
440+
static_assert(std::is_same_v<T, DefaultT> ||
441+
IsConvertibleToString<DefaultT>() ||
442+
std::is_convertible_v<DefaultT, T>,
443+
"The default value must be either the same of the port or BlackboardKey");
444+
411445
auto out = CreatePort<T>(PortDirection::INPUT, name, description);
412446
out.second.setDefaultValue(default_value);
413447
return out;
414448
}
415449

416-
template <typename T = AnyTypeAllowed> [[nodiscard]]
450+
/** Syntactic sugar to invoke CreatePort<T>(PortDirection::INOUT,...)
451+
* It also sets the PortInfo::defaultValue()
452+
*
453+
* @param name the name of the port
454+
* @param default_value default value of the port, either type T of BlackboardKey
455+
* @param description optional human-readable description
456+
*/
457+
template <typename T = AnyTypeAllowed, typename DefaultT = T> [[nodiscard]]
417458
inline std::pair<std::string, PortInfo> BidirectionalPort(StringView name,
418-
const T& default_value,
459+
const DefaultT& default_value,
419460
StringView description)
420461
{
462+
static_assert(std::is_same_v<T, DefaultT> ||
463+
IsConvertibleToString<DefaultT>() ||
464+
std::is_convertible_v<DefaultT, T>,
465+
"The default value must be either the same of the port or BlackboardKey");
466+
421467
auto out = CreatePort<T>(PortDirection::INOUT, name, description);
422468
out.second.setDefaultValue(default_value);
423469
return out;
424470
}
471+
472+
/** Syntactic sugar to invoke CreatePort<T>(PortDirection::OUTPUT,...)
473+
* It also sets the PortInfo::defaultValue()
474+
*
475+
* @param name the name of the port
476+
* @param default_value default blackboard entry where the output is written
477+
* @param description optional human-readable description
478+
*/
479+
template <typename T = AnyTypeAllowed> [[nodiscard]]
480+
inline std::pair<std::string, PortInfo> OutputPort(StringView name,
481+
StringView default_value,
482+
StringView description)
483+
{
484+
if(default_value.empty() || default_value.front() != '{' || default_value.back() != '}')
485+
{
486+
throw LogicError("Output port can only refer to blackboard entries, i.e. use the syntax '{port_name}'");
487+
}
488+
auto out = CreatePort<T>(PortDirection::OUTPUT, name, description);
489+
out.second.setDefaultValue(default_value);
490+
return out;
491+
}
492+
493+
//----------
494+
495+
// /** Syntactic sugar to invoke CreatePort<T>(PortDirection::INPUT,...)
496+
// * It also sets the default value to the blackboard entry specified
497+
// * in "default_key"
498+
// *
499+
// * @param name the name of the port
500+
// * @param default_key the key of an entry in the blackbard
501+
// * @param description optional human-readable description
502+
// */
503+
// template <typename T> [[nodiscard]]
504+
// inline std::pair<std::string, PortInfo> InputPort(
505+
// StringView name,
506+
// BlackboardKey default_key,
507+
// StringView description)
508+
// {
509+
// auto out = CreatePort<T>(PortDirection::INPUT, name, description);
510+
// out.second.setDefaultValue(default_key);
511+
// return out;
512+
// }
513+
514+
// /** Syntactic sugar to invoke CreatePort<T>(PortDirection::INOUT,...)
515+
// * It also sets the default value to the blackboard entry specified
516+
// * in "default_key"
517+
// *
518+
// * @param name the name of the port
519+
// * @param default_key the key of an entry in the blackbard
520+
// * @param description optional human-readable description
521+
// */
522+
// template <typename T> [[nodiscard]]
523+
// inline std::pair<std::string, PortInfo> BidirectionalPort(
524+
// StringView name,
525+
// BlackboardKey default_key,
526+
// StringView description)
527+
// {
528+
// auto out = CreatePort<T>(PortDirection::INOUT, name, description);
529+
// out.second.setDefaultValue(default_key);
530+
// return out;
531+
// }
532+
533+
// /** Syntactic sugar to invoke CreatePort<T>(PortDirection::OUTPUT,...)
534+
// * It also sets the default value to the blackboard entry specified
535+
// * in "default_key"
536+
// *
537+
// * @param name the name of the port
538+
// * @param default_key the key of an entry in the blackbard
539+
// * @param description optional human-readable description
540+
// */
541+
// template <typename T> [[nodiscard]]
542+
// inline std::pair<std::string, PortInfo> OutputPort(
543+
// StringView name,
544+
// BlackboardKey default_key,
545+
// StringView description)
546+
// {
547+
// auto out = CreatePort<T>(PortDirection::OUTPUT, name, description);
548+
// out.second.setDefaultValue(default_key);
549+
// return out;
550+
// }
425551
//----------
426552

427553
using PortsList = std::unordered_map<std::string, PortInfo>;

include/behaviortree_cpp/tree_node.h

Lines changed: 30 additions & 18 deletions
Original file line numberDiff line numberDiff line change
@@ -396,28 +396,40 @@ inline Result TreeNode::getInput(const std::string& key, T& destination) const
396396
}
397397
};
398398

399-
auto remap_it = config().input_ports.find(key);
400-
if (remap_it == config().input_ports.end())
399+
std::string port_value_str;
400+
401+
auto input_port_it = config().input_ports.find(key);
402+
if(input_port_it != config().input_ports.end())
401403
{
402-
return nonstd::make_unexpected(StrCat("getInput() of node `", fullPath(),
403-
"` failed because "
404-
"NodeConfig::input_ports "
405-
"does not contain the key: [",
406-
key, "]"));
404+
port_value_str = input_port_it->second;
407405
}
408-
409-
// special case. Empty port value, we should use the default value,
410-
// if available in the model.
411-
// BUT, it the port type is a string, then an empty string might be
412-
// a valid value
413-
const std::string& port_value_str = remap_it->second;
414-
if(port_value_str.empty() && config().manifest)
406+
else
415407
{
416-
const auto& port_manifest = config().manifest->ports.at(key);
417-
const auto& default_value = port_manifest.defaultValue();
418-
if(!default_value.empty() && !default_value.isString())
408+
// maybe it is declared with a default value in the manifest
409+
auto port_manifest_it = config().manifest->ports.find(key);
410+
if (port_manifest_it == config().manifest->ports.end())
411+
{
412+
return nonstd::make_unexpected(
413+
StrCat("getInput() of node '", fullPath(),
414+
"' failed because the manifest doesn't contain"
415+
"the key: [", key, "]"));
416+
}
417+
const auto& port_info = port_manifest_it->second;
418+
// there is a default value
419+
if(port_info.defaultValue().empty())
420+
{
421+
return nonstd::make_unexpected(
422+
StrCat("getInput() of node '", fullPath(),
423+
"' failed because nor the manifest or the XML contain"
424+
"the key: [", key, "]"));
425+
}
426+
if(port_info.defaultValue().isString())
427+
{
428+
port_value_str = port_info.defaultValue().cast<std::string>();
429+
}
430+
else
419431
{
420-
destination = default_value.cast<T>();
432+
destination = port_info.defaultValue().cast<T>();
421433
return {};
422434
}
423435
}

src/xml_parsing.cpp

Lines changed: 14 additions & 8 deletions
Original file line numberDiff line numberDiff line change
@@ -782,16 +782,22 @@ TreeNode::Ptr XMLParser::PImpl::createNodeFromXML(const XMLElement* element,
782782
const std::string& port_name = port_it.first;
783783
const PortInfo& port_info = port_it.second;
784784

785-
auto direction = port_info.direction();
786-
787-
if (direction != PortDirection::OUTPUT &&
788-
config.input_ports.count(port_name) == 0 &&
789-
!port_info.defaultValue().empty())
785+
const auto direction = port_info.direction();
786+
const auto& default_string = port_info.defaultValueString();
787+
if(!default_string.empty())
790788
{
791-
try {
792-
config.input_ports.insert({port_name, port_info.defaultValueString()});
789+
if (direction != PortDirection::OUTPUT &&
790+
config.input_ports.count(port_name) == 0)
791+
{
792+
config.input_ports.insert({port_name, default_string});
793+
}
794+
795+
if (direction != PortDirection::INPUT &&
796+
config.output_ports.count(port_name) == 0 &&
797+
TreeNode::isBlackboardPointer(default_string))
798+
{
799+
config.output_ports.insert({port_name, default_string});
793800
}
794-
catch(LogicError&) {}
795801
}
796802
}
797803

0 commit comments

Comments
 (0)