blackboard.h
Go to the documentation of this file.
1 #pragma once
2 
3 #include <string>
4 #include <memory>
5 #include <unordered_map>
6 #include <mutex>
7 
13 
14 namespace BT
15 {
16 
20 
21 template <typename T>
23 {
24  T value;
26 };
27 
33 {
34 public:
35  using Ptr = std::shared_ptr<Blackboard>;
36 
37 protected:
38  // This is intentionally protected. Use Blackboard::create instead
40  {}
41 
42 public:
43  struct Entry
44  {
49 
50  uint64_t sequence_id = 0;
51  // timestamp since epoch
52  std::chrono::nanoseconds stamp = std::chrono::nanoseconds{ 0 };
53 
54  Entry(const TypeInfo& _info) : info(_info)
55  {}
56 
57  Entry& operator=(const Entry& other);
58  };
59 
64  {
65  return std::shared_ptr<Blackboard>(new Blackboard(parent));
66  }
67 
68  virtual ~Blackboard() = default;
69 
70  void enableAutoRemapping(bool remapping);
71 
72  [[nodiscard]] const std::shared_ptr<Entry> getEntry(const std::string& key) const;
73 
74  [[nodiscard]] std::shared_ptr<Blackboard::Entry> getEntry(const std::string& key);
75 
76  [[nodiscard]] AnyPtrLocked getAnyLocked(const std::string& key);
77 
78  [[nodiscard]] AnyPtrLocked getAnyLocked(const std::string& key) const;
79 
80  [[deprecated("Use getAnyLocked instead")]] const Any*
81  getAny(const std::string& key) const;
82 
83  [[deprecated("Use getAnyLocked instead")]] Any* getAny(const std::string& key);
84 
88  template <typename T>
89  [[nodiscard]] bool get(const std::string& key, T& value) const;
90 
91  template <typename T>
92  [[nodiscard]] Expected<Timestamp> getStamped(const std::string& key, T& value) const;
93 
97  template <typename T>
98  [[nodiscard]] T get(const std::string& key) const;
99 
100  template <typename T>
101  [[nodiscard]] Expected<StampedValue<T>> getStamped(const std::string& key) const;
102 
104  template <typename T>
105  void set(const std::string& key, const T& value);
106 
107  void unset(const std::string& key);
108 
109  [[nodiscard]] const TypeInfo* entryInfo(const std::string& key);
110 
111  void addSubtreeRemapping(StringView internal, StringView external);
112 
113  void debugMessage() const;
114 
115  [[nodiscard]] std::vector<StringView> getKeys() const;
116 
117  [[deprecated("This command is unsafe. Consider using Backup/Restore instead")]] void
118  clear();
119 
120  [[deprecated("Use getAnyLocked to access safely an Entry")]] std::recursive_mutex&
121  entryMutex() const;
122 
123  void createEntry(const std::string& key, const TypeInfo& info);
124 
134  void cloneInto(Blackboard& dst) const;
135 
137 
138  // recursively look for parent Blackboard, until you find the root
140 
141  const Blackboard* rootBlackboard() const;
142 
143 private:
145  mutable std::recursive_mutex entry_mutex_;
146  std::unordered_map<std::string, std::shared_ptr<Entry>> storage_;
147  std::weak_ptr<Blackboard> parent_bb_;
148  std::unordered_map<std::string, std::string> internal_to_external_;
149 
150  std::shared_ptr<Entry> createEntryImpl(const std::string& key, const TypeInfo& info);
151 
152  bool autoremapping_ = false;
153 };
154 
161 
167 void ImportBlackboardFromJSON(const nlohmann::json& json, Blackboard& blackboard);
168 
169 //------------------------------------------------------
170 
171 template <typename T>
172 inline T Blackboard::get(const std::string& key) const
173 {
174  if(auto any_ref = getAnyLocked(key))
175  {
176  const auto& any = any_ref.get();
177  if(any->empty())
178  {
179  throw RuntimeError("Blackboard::get() error. Entry [", key,
180  "] hasn't been initialized, yet");
181  }
182  return any_ref.get()->cast<T>();
183  }
184  throw RuntimeError("Blackboard::get() error. Missing key [", key, "]");
185 }
186 
187 inline void Blackboard::unset(const std::string& key)
188 {
189  std::unique_lock lock(mutex_);
190 
191  // check local storage
192  auto it = storage_.find(key);
193  if(it == storage_.end())
194  {
195  // No entry, nothing to do.
196  return;
197  }
198 
199  storage_.erase(it);
200 }
201 
202 template <typename T>
203 inline void Blackboard::set(const std::string& key, const T& value)
204 {
205  if(StartWith(key, '@'))
206  {
207  rootBlackboard()->set(key.substr(1, key.size() - 1), value);
208  return;
209  }
210  std::unique_lock lock(mutex_);
211 
212  // check local storage
213  auto it = storage_.find(key);
214  if(it == storage_.end())
215  {
216  // create a new entry
217  Any new_value(value);
218  lock.unlock();
219  std::shared_ptr<Blackboard::Entry> entry;
220  // if a new generic port is created with a string, it's type should be AnyTypeAllowed
221  if constexpr(std::is_same_v<std::string, T>)
222  {
224  }
225  else
226  {
227  PortInfo new_port(PortDirection::INOUT, new_value.type(),
228  GetAnyFromStringFunctor<T>());
229  entry = createEntryImpl(key, new_port);
230  }
231  lock.lock();
232 
233  entry->value = new_value;
234  entry->sequence_id++;
235  entry->stamp = std::chrono::steady_clock::now().time_since_epoch();
236  }
237  else
238  {
239  // this is not the first time we set this entry, we need to check
240  // if the type is the same or not.
241  Entry& entry = *it->second;
242  std::scoped_lock scoped_lock(entry.entry_mutex);
243 
244  Any& previous_any = entry.value;
245  Any new_value(value);
246 
247  // special case: entry exists but it is not strongly typed... yet
248  if(!entry.info.isStronglyTyped())
249  {
250  // Use the new type to create a new entry that is strongly typed.
251  entry.info = TypeInfo::Create<T>();
252  entry.sequence_id++;
253  entry.stamp = std::chrono::steady_clock::now().time_since_epoch();
254  previous_any = std::move(new_value);
255  return;
256  }
257 
258  std::type_index previous_type = entry.info.type();
259 
260  // check type mismatch
261  if(previous_type != std::type_index(typeid(T)) && previous_type != new_value.type())
262  {
263  bool mismatching = true;
265  {
266  Any any_from_string = entry.info.parseString(value);
267  if(any_from_string.empty() == false)
268  {
269  mismatching = false;
270  new_value = std::move(any_from_string);
271  }
272  }
273  // check if we are doing a safe cast between numbers
274  // for instance, it is safe to use int(100) to set
275  // a uint8_t port, but not int(-42) or int(300)
276  if constexpr(std::is_arithmetic_v<T>)
277  {
278  if(mismatching && isCastingSafe(previous_type, value))
279  {
280  mismatching = false;
281  }
282  }
283 
284  if(mismatching)
285  {
286  debugMessage();
287 
288  auto msg = StrCat("Blackboard::set(", key,
289  "): once declared, "
290  "the type of a port shall not change. "
291  "Previously declared type [",
292  BT::demangle(previous_type), "], current type [",
293  BT::demangle(typeid(T)), "]");
294  throw LogicError(msg);
295  }
296  }
297  // if doing set<BT::Any>, skip type check
298  if constexpr(std::is_same_v<Any, T>)
299  {
300  previous_any = new_value;
301  }
302  else
303  {
304  // copy only if the type is compatible
305  new_value.copyInto(previous_any);
306  }
307  entry.sequence_id++;
308  entry.stamp = std::chrono::steady_clock::now().time_since_epoch();
309  }
310 }
311 
312 template <typename T>
313 inline bool Blackboard::get(const std::string& key, T& value) const
314 {
315  if(auto any_ref = getAnyLocked(key))
316  {
317  if(any_ref.get()->empty())
318  {
319  return false;
320  }
321  value = any_ref.get()->cast<T>();
322  return true;
323  }
324  return false;
325 }
326 
327 template <typename T>
328 inline Expected<Timestamp> Blackboard::getStamped(const std::string& key, T& value) const
329 {
330  if(auto entry = getEntry(key))
331  {
332  std::unique_lock lk(entry->entry_mutex);
333  if(entry->value.empty())
334  {
335  return nonstd::make_unexpected(StrCat("Blackboard::getStamped() error. Entry [",
336  key, "] hasn't been initialized, yet"));
337  }
338  value = entry->value.cast<T>();
339  return Timestamp{ entry->sequence_id, entry->stamp };
340  }
341  return nonstd::make_unexpected(
342  StrCat("Blackboard::getStamped() error. Missing key [", key, "]"));
343 }
344 
345 template <typename T>
346 inline Expected<StampedValue<T>> Blackboard::getStamped(const std::string& key) const
347 {
348  StampedValue<T> out;
349  if(auto res = getStamped<T>(key, out.value))
350  {
351  out.stamp = *res;
352  return out;
353  }
354  else
355  {
356  return nonstd::make_unexpected(res.error());
357  }
358 }
359 
360 } // namespace BT
BT::PortInfo
Definition: basic_types.h:392
BT
Definition: ex01_wrap_legacy.cpp:29
BT::Blackboard::set
void set(const std::string &key, const T &value)
Update the entry with the given key.
Definition: blackboard.h:203
BT::Blackboard::parent_bb_
std::weak_ptr< Blackboard > parent_bb_
Definition: blackboard.h:147
BT::demangle
std::string demangle(char const *name)
Definition: demangle_util.h:74
BT::Blackboard::Entry::sequence_id
uint64_t sequence_id
Definition: blackboard.h:50
BT::Blackboard::clear
void clear()
Definition: blackboard.cpp:131
BT::PortDirection::INOUT
@ INOUT
exceptions.h
BT::Blackboard::Entry::info
TypeInfo info
Definition: blackboard.h:46
BT::Any
Definition: safe_any.hpp:36
BT::StampedValue::stamp
Timestamp stamp
Definition: blackboard.h:25
BT::StampedValue
Definition: blackboard.h:22
BT::Blackboard::entry_mutex_
std::recursive_mutex entry_mutex_
Definition: blackboard.h:145
BT::Blackboard::createEntryImpl
std::shared_ptr< Entry > createEntryImpl(const std::string &key, const TypeInfo &info)
Definition: blackboard.cpp:208
basic_types.h
BT::Blackboard::unset
void unset(const std::string &key)
Definition: blackboard.h:187
BT::Blackboard::get
bool get(const std::string &key, T &value) const
Definition: blackboard.h:313
BT::Expected
nonstd::expected< T, std::string > Expected
Definition: basic_types.h:85
BT::Blackboard::parent
Blackboard::Ptr parent()
Definition: blackboard.cpp:199
BT::StringView
std::string_view StringView
Definition: basic_types.h:59
BT::Blackboard::mutex_
std::mutex mutex_
Definition: blackboard.h:144
BT::ImportBlackboardFromJSON
void ImportBlackboardFromJSON(const nlohmann::json &json, Blackboard &blackboard)
ImportBlackboardFromJSON will append elements to the blackboard, using the values parsed from the JSO...
Definition: blackboard.cpp:280
BT::Blackboard::createEntry
void createEntry(const std::string &key, const TypeInfo &info)
Definition: blackboard.cpp:142
BT::Blackboard::Entry::operator=
Entry & operator=(const Entry &other)
Definition: blackboard.cpp:297
BT::Blackboard::storage_
std::unordered_map< std::string, std::shared_ptr< Entry > > storage_
Definition: blackboard.h:146
BT::Blackboard::getEntry
const std::shared_ptr< Entry > getEntry(const std::string &key) const
Definition: blackboard.cpp:47
BT::isCastingSafe
bool isCastingSafe(const std::type_index &type, const T &val)
Definition: safe_any.hpp:252
basic_json
namespace for Niels Lohmann
Definition: json.hpp:3411
BT::Any::type
const std::type_index & type() const noexcept
Definition: safe_any.hpp:196
BT::Blackboard::getKeys
std::vector< StringView > getKeys() const
Definition: blackboard.cpp:116
lexy::_detail::any_ref
any_base * any_ref
Definition: any_ref.hpp:43
BT::LogicError
Definition: exceptions.h:45
magic_enum::detail::value
constexpr E value(std::size_t i) noexcept
Definition: magic_enum.hpp:664
BT::Blackboard::getAny
const Any * getAny(const std::string &key) const
Definition: blackboard.cpp:36
BT::Blackboard::Blackboard
Blackboard(Blackboard::Ptr parent)
Definition: blackboard.h:39
BT::ExportBlackboardToJSON
nlohmann::json ExportBlackboardToJSON(const Blackboard &blackboard)
ExportBlackboardToJSON will create a JSON that contains the current values of the blackboard....
Definition: blackboard.cpp:263
locked_reference.hpp
BT::Blackboard::debugMessage
void debugMessage() const
Definition: blackboard.cpp:95
mutex
static pthread_mutex_t mutex
Definition: minitrace.cpp:77
BT::StampedValue::value
T value
Definition: blackboard.h:24
BT::Blackboard::Ptr
std::shared_ptr< Blackboard > Ptr
Definition: blackboard.h:35
BT::Blackboard::entryInfo
const TypeInfo * entryInfo(const std::string &key)
Definition: blackboard.cpp:83
BT::Blackboard::enableAutoRemapping
void enableAutoRemapping(bool remapping)
Definition: blackboard.cpp:13
BT::StringConverter
std::function< Any(StringView)> StringConverter
Definition: basic_types.h:206
BT::Timestamp
Definition: basic_types.h:335
BT::Blackboard::Entry
Definition: blackboard.h:43
BT::Blackboard::~Blackboard
virtual ~Blackboard()=default
BT::AnyPtrLocked
LockedPtr< Any > AnyPtrLocked
Definition: blackboard.h:19
BT::Blackboard::entryMutex
std::recursive_mutex & entryMutex() const
Definition: blackboard.cpp:137
BT::Any::empty
bool empty() const noexcept
Definition: safe_any.hpp:207
BT::Blackboard::cloneInto
void cloneInto(Blackboard &dst) const
cloneInto copies the values of the entries into another blackboard. Known limitations:
Definition: blackboard.cpp:154
BT::Blackboard::rootBlackboard
Blackboard * rootBlackboard()
Definition: blackboard.cpp:307
BT::Blackboard::addSubtreeRemapping
void addSubtreeRemapping(StringView internal, StringView external)
Definition: blackboard.cpp:89
BT::RuntimeError
Definition: exceptions.h:58
BT::Blackboard
The Blackboard is the mechanism used by BehaviorTrees to exchange typed data.
Definition: blackboard.h:32
BT::TypeInfo::type
const std::type_index & type() const
Definition: basic_types.cpp:373
BT::LockedPtr
The LockedPtr class is used to share a pointer to an object and a mutex that protects the read/write ...
Definition: locked_reference.hpp:16
safe_any.hpp
BT::StrCat
std::string StrCat()
Definition: strcat.hpp:46
BT::Blackboard::create
static Blackboard::Ptr create(Blackboard::Ptr parent={})
Definition: blackboard.h:63
json.hpp
BT::Blackboard::Entry::value
Any value
Definition: blackboard.h:45
BT::StartWith
bool StartWith(StringView str, StringView prefix)
Definition: basic_types.cpp:464
json
basic_json<> json
default specialization
Definition: json.hpp:3422
BT::TypeInfo
Definition: basic_types.h:345
BT::Blackboard::Entry::string_converter
StringConverter string_converter
Definition: blackboard.h:47
BT::Blackboard::internal_to_external_
std::unordered_map< std::string, std::string > internal_to_external_
Definition: blackboard.h:148
BT::Any::copyInto
void copyInto(Any &dst)
Definition: safe_any.hpp:322
BT::Blackboard::Entry::stamp
std::chrono::nanoseconds stamp
Definition: blackboard.h:52
BT::TypeInfo::parseString
Any parseString(const char *str) const
Definition: basic_types.cpp:383
BT::Blackboard::getStamped
Expected< Timestamp > getStamped(const std::string &key, T &value) const
Definition: blackboard.h:328
lexyd::any
constexpr auto any
Matches anything and consumes all remaining characters.
Definition: 3rdparty/lexy/include/lexy/dsl/any.hpp:42
BT::Blackboard::autoremapping_
bool autoremapping_
Definition: blackboard.h:152
lexy::_detail::any_base::get
constexpr T & get() noexcept
Definition: any_ref.hpp:25
BT::TypeInfo::isStronglyTyped
bool isStronglyTyped() const
Definition: basic_types.h:376
BT::Blackboard::Entry::entry_mutex
std::mutex entry_mutex
Definition: blackboard.h:48
BT::Blackboard::Entry::Entry
Entry(const TypeInfo &_info)
Definition: blackboard.h:54
BT::Blackboard::getAnyLocked
AnyPtrLocked getAnyLocked(const std::string &key)
Definition: blackboard.cpp:18


behaviortree_cpp_v4
Author(s): Davide Faconti
autogenerated on Fri Jun 28 2024 02:20:07