Skip to content

Commit 3686584

Browse files
committed
updated interface with Expected
1 parent 3a9784f commit 3686584

File tree

5 files changed

+96
-25
lines changed

5 files changed

+96
-25
lines changed

include/behaviortree_cpp/basic_types.h

Lines changed: 1 addition & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -335,11 +335,9 @@ using Result = Expected<std::monostate>;
335335
struct Timestamp
336336
{
337337
uint64_t seq = 0;
338-
std::chrono::nanoseconds stamp = std::chrono::nanoseconds(0);
338+
std::chrono::nanoseconds time = std::chrono::nanoseconds(0);
339339
};
340340

341-
using ResultStamped = Expected<Timestamp>;
342-
343341
[[nodiscard]] bool IsAllowedPortName(StringView str);
344342

345343
class TypeInfo

include/behaviortree_cpp/blackboard.h

Lines changed: 23 additions & 17 deletions
Original file line numberDiff line numberDiff line change
@@ -4,7 +4,6 @@
44
#include <memory>
55
#include <unordered_map>
66
#include <mutex>
7-
#include <optional>
87

98
#include "behaviortree_cpp/basic_types.h"
109
#include "behaviortree_cpp/contrib/json.hpp"
@@ -19,6 +18,13 @@ namespace BT
1918
/// with a locked mutex as long as the object is in scope
2019
using AnyPtrLocked = LockedPtr<Any>;
2120

21+
template <typename T>
22+
struct StampedValue
23+
{
24+
T value;
25+
Timestamp stamp;
26+
};
27+
2228
/**
2329
* @brief The Blackboard is the mechanism used by BehaviorTrees to exchange
2430
* typed data.
@@ -83,7 +89,7 @@ class Blackboard
8389
[[nodiscard]] bool get(const std::string& key, T& value) const;
8490

8591
template <typename T>
86-
std::optional<Timestamp> getStamped(const std::string& key, T& value) const;
92+
[[nodiscard]] Expected<Timestamp> getStamped(const std::string& key, T& value) const;
8793

8894
/**
8995
* Version of get() that throws if it fails.
@@ -92,7 +98,7 @@ class Blackboard
9298
[[nodiscard]] T get(const std::string& key) const;
9399

94100
template <typename T>
95-
std::pair<T, Timestamp> getStamped(const std::string& key) const;
101+
[[nodiscard]] Expected<StampedValue<T>> getStamped(const std::string& key) const;
96102

97103
/// Update the entry with the given key
98104
template <typename T>
@@ -307,36 +313,36 @@ inline bool Blackboard::get(const std::string& key, T& value) const
307313
}
308314

309315
template <typename T>
310-
inline std::optional<Timestamp> Blackboard::getStamped(const std::string& key,
311-
T& value) const
316+
inline Expected<Timestamp> Blackboard::getStamped(const std::string& key, T& value) const
312317
{
313318
if(auto entry = getEntry(key))
314319
{
315320
std::unique_lock lk(entry->entry_mutex);
316321
if(entry->value.empty())
317322
{
318-
return std::nullopt;
323+
return nonstd::make_unexpected(StrCat("Blackboard::getStamped() error. Entry [",
324+
key, "] hasn't been initialized, yet"));
319325
}
320326
value = entry->value.cast<T>();
321327
return Timestamp{ entry->sequence_id, entry->stamp };
322328
}
323-
return std::nullopt;
329+
return nonstd::make_unexpected(
330+
StrCat("Blackboard::getStamped() error. Missing key [", key, "]"));
324331
}
325332

326333
template <typename T>
327-
inline std::pair<T, Timestamp> Blackboard::getStamped(const std::string& key) const
334+
inline Expected<StampedValue<T>> Blackboard::getStamped(const std::string& key) const
328335
{
329-
if(auto entry = getEntry(key))
336+
StampedValue<T> out;
337+
if(auto res = getStamped<T>(key, out.value))
330338
{
331-
std::unique_lock lk(entry->entry_mutex);
332-
if(entry->value.empty())
333-
{
334-
throw RuntimeError("Blackboard::get() error. Entry [", key,
335-
"] hasn't been initialized, yet");
336-
}
337-
return { entry->value.cast<T>(), Timestamp{ entry->sequence_id, entry->stamp } };
339+
out.stamp = *res;
340+
return out;
341+
}
342+
else
343+
{
344+
return nonstd::make_unexpected(res.error());
338345
}
339-
throw RuntimeError("Blackboard::get() error. Missing key [", key, "]");
340346
}
341347

342348
} // namespace BT

include/behaviortree_cpp/tree_node.h

Lines changed: 33 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -218,13 +218,23 @@ class TreeNode
218218
* convertFromString<T>() is used automatically to parse the text.
219219
*
220220
* @param key the name of the port.
221+
* @param destination reference to the object where the value should be stored
221222
* @return false if an error occurs.
222223
*/
223224
template <typename T>
224225
Result getInput(const std::string& key, T& destination) const;
225226

227+
/**
228+
* @brief getInputStamped is similar to getInput(dey, destination),
229+
* but it returne also the Timestamp object, that can be used to check if
230+
* a value was updated and when.
231+
*
232+
* @param key the name of the port.
233+
* @param destination reference to the object where the value should be stored
234+
*/
226235
template <typename T>
227-
ResultStamped getInputStamped(const std::string& key, T& destination) const;
236+
[[nodiscard]] Expected<Timestamp> getInputStamped(const std::string& key,
237+
T& destination) const;
228238

229239
/** Same as bool getInput(const std::string& key, T& destination)
230240
* but using optional.
@@ -239,6 +249,26 @@ class TreeNode
239249
return (res) ? Expected<T>(out) : nonstd::make_unexpected(res.error());
240250
}
241251

252+
/** Same as bool getInputStamped(const std::string& key, T& destination)
253+
* but return StampedValue<T>
254+
*
255+
* @param key the name of the port.
256+
*/
257+
template <typename T>
258+
[[nodiscard]] Expected<StampedValue<T>> getInputStamped(const std::string& key) const
259+
{
260+
StampedValue<T> out;
261+
if(auto res = getInputStamped(key, out.value))
262+
{
263+
out.stamp = *res;
264+
return out;
265+
}
266+
else
267+
{
268+
return nonstd::make_unexpected(res.error());
269+
}
270+
}
271+
242272
/**
243273
* @brief setOutput modifies the content of an Output port
244274
* @param key the name of the port.
@@ -393,8 +423,8 @@ T TreeNode::parseString(const std::string& str) const
393423
}
394424

395425
template <typename T>
396-
inline ResultStamped TreeNode::getInputStamped(const std::string& key,
397-
T& destination) const
426+
inline Expected<Timestamp> TreeNode::getInputStamped(const std::string& key,
427+
T& destination) const
398428
{
399429
std::string port_value_str;
400430

src/decorators/skip_unless_updated.cpp

Lines changed: 0 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -10,8 +10,6 @@
1010
* WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
1111
*/
1212

13-
#pragma once
14-
1513
#include "behaviortree_cpp/decorators/skip_unless_updated.h"
1614

1715
namespace BT

tests/gtest_blackboard.cpp

Lines changed: 39 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -606,3 +606,42 @@ TEST(BlackboardTest, RootBlackboard)
606606
ASSERT_EQ(3, tree.rootBlackboard()->get<int>("var3"));
607607
ASSERT_EQ(4, tree.rootBlackboard()->get<int>("var4"));
608608
}
609+
610+
TEST(BlackboardTest, TimestampedInterface)
611+
{
612+
auto bb = BT::Blackboard::create();
613+
614+
// still empty, expected to fail
615+
int value;
616+
ASSERT_FALSE(bb->getStamped<int>("value"));
617+
ASSERT_FALSE(bb->getStamped("value", value));
618+
619+
auto nsec_before = std::chrono::steady_clock::now().time_since_epoch().count();
620+
bb->set("value", 42);
621+
auto result = bb->getStamped<int>("value");
622+
auto stamp_opt = bb->getStamped<int>("value", value);
623+
624+
ASSERT_EQ(result->value, 42);
625+
ASSERT_EQ(result->stamp.seq, 1);
626+
ASSERT_GE(result->stamp.time.count(), nsec_before);
627+
628+
ASSERT_EQ(value, 42);
629+
ASSERT_TRUE(stamp_opt);
630+
ASSERT_EQ(stamp_opt->seq, 1);
631+
ASSERT_GE(stamp_opt->time.count(), nsec_before);
632+
633+
//---------------------------------
634+
nsec_before = std::chrono::steady_clock::now().time_since_epoch().count();
635+
bb->set("value", 69);
636+
result = bb->getStamped<int>("value");
637+
stamp_opt = bb->getStamped<int>("value", value);
638+
639+
ASSERT_EQ(result->value, 69);
640+
ASSERT_EQ(result->stamp.seq, 2);
641+
ASSERT_GE(result->stamp.time.count(), nsec_before);
642+
643+
ASSERT_EQ(value, 69);
644+
ASSERT_TRUE(stamp_opt);
645+
ASSERT_EQ(stamp_opt->seq, 2);
646+
ASSERT_GE(stamp_opt->time.count(), nsec_before);
647+
}

0 commit comments

Comments
 (0)