3#include "behaviortree_cpp/basic_types.h"
4#ifdef BTCPP_SYSTEM_JSON
5#include <nlohmann/json.hpp>
7#include "behaviortree_cpp/contrib/json.hpp"
9#include "behaviortree_cpp/exceptions.h"
10#include "behaviortree_cpp/utils/locked_reference.hpp"
11#include "behaviortree_cpp/utils/polymorphic_cast_registry.hpp"
12#include "behaviortree_cpp/utils/safe_any.hpp"
16#include <shared_mutex>
18#include <unordered_map>
35
36
37
45 Blackboard(
Blackboard::Ptr parent) : parent_bb_(parent)
58 StringConverter string_converter;
59 mutable std::mutex entry_mutex;
61 uint64_t sequence_id = 0;
65 Entry(
const TypeInfo& _info) : info(_info)
69 Entry(
const Entry&) =
delete;
71 Entry(
Entry&&) =
delete;
76
77
80 return std::shared_ptr<Blackboard>(
new Blackboard(parent));
83 virtual ~Blackboard() =
default;
85 void enableAutoRemapping(
bool remapping);
87 [[
nodiscard]]
const std::shared_ptr<
Entry> getEntry(
const std::string& key)
const;
91 [[
nodiscard]] AnyPtrLocked getAnyLocked(
const std::string& key);
93 [[
nodiscard]] AnyPtrLocked getAnyLocked(
const std::string& key)
const;
96 getAny(
const std::string& key)
const;
98 [[
deprecated(
"Use getAnyLocked instead")]]
Any* getAny(
const std::string& key);
101
102
103 template <
typename T>
104 [[nodiscard]]
bool get(
const std::string& key, T& value)
const;
106 template <
typename T>
107 [[nodiscard]] Expected<Timestamp> getStamped(
const std::string& key, T& value)
const;
110
111
112 template <
typename T>
113 [[nodiscard]] T
get(
const std::string& key)
const;
115 template <
typename T>
116 [[nodiscard]] Expected<StampedValue<T>> getStamped(
const std::string& key)
const;
119 template <
typename T>
120 void set(
const std::string& key,
const T& value);
122 void unset(
const std::string& key);
126 void addSubtreeRemapping(StringView internal, StringView external);
128 void debugMessage()
const;
136 "The views may dangle: use getKeyNames")]] [[
nodiscard]] std::vector<StringView>
139 [[
deprecated(
"This command is unsafe. Consider using Backup/Restore instead")]]
void
142 void createEntry(
const std::string& key,
const TypeInfo& info);
145
146
147
148
149
150
151
152
163
164
165
166
167
170 polymorphic_registry_ = std::move(registry);
174
175
178 return polymorphic_registry_.get();
182
183
184
185
186
187 template <
typename T>
191 mutable std::shared_mutex storage_mutex_;
192 std::unordered_map<std::string, std::shared_ptr<Entry>> storage_;
194 std::unordered_map<std::string, std::string> internal_to_external_;
196 std::shared_ptr<
Entry> createEntryImpl(
const std::string& key,
const TypeInfo& info);
198 bool autoremapping_ =
false;
205
206
207
208
212
213
214
215
224 auto result = any->tryCast<T>();
227 return result.value();
233 if(polymorphic_registry_)
235 auto poly_result = any->tryCastWithRegistry<T>(*polymorphic_registry_);
238 return poly_result.value();
243 return nonstd::make_unexpected(result.error());
249 if(
auto any_ref = getAnyLocked(key))
251 const auto& any = any_ref.get();
254 throw RuntimeError(
"Blackboard::get() error. Entry [", key,
255 "] hasn't been initialized, yet");
257 auto result = tryCastWithPolymorphicFallback<T>(any);
260 throw std::runtime_error(result.error());
262 return result.value();
264 throw RuntimeError(
"Blackboard::get() error. Missing key [", key,
"]");
267inline void Blackboard::unset(
const std::string& key)
270 std::shared_ptr<
Entry> removed;
271 std::unique_lock storage_lock(storage_mutex_);
274 auto it = storage_.find(key);
275 if(it == storage_.end())
281 removed = std::move(it->second);
286inline void Blackboard::
set(
const std::string& key,
const T& value)
288 if(StartWith(key,
'@'))
290 rootBlackboard()->set(key.substr(1, key.size() - 1), value);
298 auto entry_ptr = getEntry(key);
302 Any new_value(value);
305 if constexpr(std::is_same_v<std::string, T>)
307 entry = createEntryImpl(key, PortInfo(PortDirection::INOUT));
311 PortInfo new_port(PortDirection::INOUT, new_value.type(),
312 GetAnyFromStringFunctor<T>());
313 entry = createEntryImpl(key, new_port);
318 std::scoped_lock entry_lock(entry->entry_mutex);
319 entry->value = new_value;
320 entry->sequence_id++;
321 entry->stamp = std::chrono::steady_clock::now().time_since_epoch();
327 Entry& entry = *entry_ptr;
329 std::scoped_lock scoped_lock(entry.entry_mutex);
331 Any& previous_any = entry.value;
332 Any new_value(value);
335 if(!entry.info.isStronglyTyped())
340 entry.stamp = std::chrono::steady_clock::now().time_since_epoch();
341 previous_any = std::move(new_value);
345 std::type_index previous_type = entry.info.type();
348 if(previous_type != std::type_index(
typeid(T)) && previous_type != new_value.type())
350 bool mismatching =
true;
351 if(std::is_constructible<StringView, T>::value)
353 Any any_from_string = entry.info.parseString(value);
354 if(any_from_string.empty() ==
false)
357 new_value = std::move(any_from_string);
363 if constexpr(std::is_arithmetic_v<T>)
365 if(mismatching && isCastingSafe(previous_type, value))
375 auto msg = StrCat(
"Blackboard::set(", key,
377 "the type of a port shall not change. "
378 "Previously declared type [",
379 BT::demangle(previous_type),
"], current type [",
380 BT::demangle(
typeid(T)),
"]");
381 throw LogicError(msg);
385 if constexpr(std::is_same_v<Any, T>)
387 previous_any = new_value;
392 new_value.copyInto(previous_any);
395 entry.stamp = std::chrono::steady_clock::now().time_since_epoch();
400inline bool Blackboard::
get(
const std::string& key, T& value)
const
402 if(
auto any_ref = getAnyLocked(key))
404 const auto& any = any_ref.get();
409 auto result = tryCastWithPolymorphicFallback<T>(any);
412 throw std::runtime_error(result.error());
414 value = result.value();
421inline Expected<Timestamp>
Blackboard::getStamped(
const std::string& key, T& value)
const
423 if(
auto entry = getEntry(key))
425 std::unique_lock lk(entry->entry_mutex);
426 if(entry->value.empty())
428 return nonstd::make_unexpected(StrCat(
"Blackboard::getStamped() error. Entry [",
429 key,
"] hasn't been initialized, yet"));
431 auto result = tryCastWithPolymorphicFallback<T>(&entry->value);
434 value = result.value();
435 return Timestamp{ entry->sequence_id, entry->stamp };
437 return nonstd::make_unexpected(result.error());
439 return nonstd::make_unexpected(
440 StrCat(
"Blackboard::getStamped() error. Missing key [", key,
"]"));
444inline Expected<StampedValue<T>>
Blackboard::getStamped(
const std::string& key)
const
447 if(
auto res = getStamped<T>(key, out.value))
454 return nonstd::make_unexpected(res.error());
Definition: safe_any.hpp:57
The Blackboard is the mechanism used by BehaviorTrees to exchange typed data.
Definition: blackboard.h:39
void set(const std::string &key, const T &value)
Update the entry with the given key.
Definition: blackboard.h:286
T get(const std::string &key) const
Definition: blackboard.h:247
const PolymorphicCastRegistry * polymorphicCastRegistry() const
Get the polymorphic cast registry (may be null).
Definition: blackboard.h:176
void setPolymorphicCastRegistry(std::shared_ptr< PolymorphicCastRegistry > registry)
Set the polymorphic cast registry for this blackboard.
Definition: blackboard.h:168
std::vector< std::string > getKeyNames() const
The names of all the entries stored in this blackboard (copies).
Expected< T > tryCastWithPolymorphicFallback(const Any *any) const
Cast Any value with polymorphic fallback for shared_ptr types.
Definition: blackboard.h:221
bool get(const std::string &key, T &value) const
Definition: blackboard.h:400
static Blackboard::Ptr create(Blackboard::Ptr parent={})
Definition: blackboard.h:78
void cloneInto(Blackboard &dst) const
cloneInto copies the values of the entries into another blackboard. Known limitations:
The LockedPtr class is used to share a pointer to an object and a mutex that protects the read/write ...
Definition: locked_reference.hpp:22
Registry for polymorphic shared_ptr cast relationships.
Definition: polymorphic_cast_registry.hpp:47
Definition: basic_types.h:424
Definition: basic_types.h:377
Definition: action_node.h:24
void ImportBlackboardFromJSON(const nlohmann::json &json, Blackboard &blackboard)
ImportBlackboardFromJSON will append elements to the blackboard, using the values parsed from the JSO...
nlohmann::json ExportBlackboardToJSON(const Blackboard &blackboard)
ExportBlackboardToJSON will create a JSON that contains the current values of the blackboard....
Definition: blackboard.h:55
Definition: blackboard.h:29
Definition: basic_types.h:357
Definition: safe_any.hpp:46