Botcraft 1.21.4
Loading...
Searching...
No Matches
Blackboard.hpp
Go to the documentation of this file.
1#pragma once
2
3#include <any>
4#include <functional>
5#include <map>
6#include <stdexcept>
7#include <string>
8
9namespace Botcraft
10{
11 /// @brief Wrapper around a reference that will run a callback on destruct
12 /// @tparam T Type of the reference
13 template<typename T>
15 {
16 public:
17 NotifyOnEndUseRef(T& r, const std::function<void()>& on_destruct_callback_) : _ref(r), on_destruct_callback(on_destruct_callback_) {}
25
26 /// @brief Reference getter. Only works on lvalue to prevent calling it on a temporary object (which would run
27 /// the callback immediately instead of when going out of scope.
28 /// @return The wrapped reference
29 T& ref() const& { return _ref; }
30 T& ref() const&& = delete;
31
32 private:
33 T& _ref;
34 std::function<void()> on_destruct_callback;
35 };
36
38 {
39 public:
40 virtual void OnReset() = 0;
41 virtual void OnValueChanged(const std::string& key, const std::any& value) = 0;
42 virtual void OnValueRemoved(const std::string& key) = 0;
43 };
44
45 /// @brief A map wrapper to store arbitrary data
47 {
48 public:
49 Blackboard();
51
52 /// @brief Get the map value at key, casting it to T.
53 /// The map has to contains key and it has to be a T.
54 /// @tparam T Any type, must match the type stored at key
55 /// @param key key to retrieve the value from
56 /// @return The stored value
57 template<class T>
58 const T& Get(const std::string& key)
59 {
60 try
61 {
62 return std::any_cast<T&>(blackboard.at(key));
63 }
64 catch (const std::out_of_range& e)
65 {
66 throw std::out_of_range("invalid blackboard key: " + key);
67 }
68 }
69
70 /// @brief Get the map value at key, casting it to T.
71 /// If the key is not present in the map, add
72 /// it with default_value, and returns it.
73 /// @tparam T Any type, must match the type stored at key
74 /// @param key key to retrieve the value from
75 /// @param default_value The default value to return if key is not found
76 /// @return The stored value
77 template<class T>
78 const T& Get(const std::string& key, const T& default_value)
79 {
80 auto it = blackboard.find(key);
81 if (it == blackboard.end())
82 {
83 it = blackboard.insert(std::pair<std::string, std::any>(key, default_value)).first;
84 NotifyKeyChanged(key, it->second);
85 }
86 return std::any_cast<T&>(it->second);
87 }
88
89 /// @brief Get a ref to the map value at key, casting it to T&. key must exist in the blackboard.
90 /// Usage example:
91 /// ```cpp
92 /// {
93 /// NotifyOnEndUseRef<int> raw_ref = blackboard.GetRef<int>("key");
94 /// int& my_ref = raw_ref.ref;
95 /// my_ref = 8;
96 /// } // End of scope, raw_ref is destroyed and blackboard is notified value has potentially changed
97 /// ```
98 /// @tparam T Any type, must match the type stored at key
99 /// @param key key to retrieve the value from
100 /// @return The stored value
101 template<class T>
102 NotifyOnEndUseRef<T> GetRef(const std::string& key)
103 {
104 try
105 {
106 return NotifyOnEndUseRef(std::any_cast<T&>(blackboard.at(key)), [this, key]() { NotifyKeyChanged(key, blackboard.at(key)); });
107 }
108 catch (const std::out_of_range& e)
109 {
110 throw std::out_of_range("invalid blackboard key: " + key);
111 }
112 }
113
114 /// @brief Get a ref to the map value at key, casting it to T&.
115 /// If the key is not present in the map, add it with default_value, and returns it.
116 /// Usage example:
117 /// ```cpp
118 /// {
119 /// NotifyOnEndUseRef<int> raw_ref = blackboard.GetRef<int>("key", 0);
120 /// int& my_ref = raw_ref.ref;
121 /// my_ref = 8;
122 /// } // End of scope, raw_ref is destroyed and blackboard is notified value has potentially changed
123 /// ```
124 /// @tparam T Any type, must match the type stored at key
125 /// @param key key to retrieve the value from
126 /// @param default_value The default value to return if key is not found
127 /// @return The stored value
128 template<class T>
129 NotifyOnEndUseRef<T> GetRef(const std::string& key, const T& default_value)
130 {
131 auto it = blackboard.find(key);
132 if (it == blackboard.end())
133 {
134 it = blackboard.insert(std::pair<std::string, std::any>(key, default_value)).first;
135 }
136 return NotifyOnEndUseRef(std::any_cast<T&>(it->second), [this, key]() { NotifyKeyChanged(key, blackboard.at(key)); });
137 }
138
139 /// @brief Set map entry at key to value
140 /// @tparam T Any type, be careful to be explicit with strings because "foo" is not a std::string but a C-style char*
141 /// @param key key to store the value at
142 /// @param value value to store at key
143 template<class T>
144 void Set(const std::string& key, const T& value)
145 {
146 blackboard[key] = value;
147 NotifyKeyChanged(key, blackboard[key]);
148 }
149
150 /// @brief Copy a blackboard value
151 /// @param src Source key, must exist in the blackboard
152 /// @param dst Destination key
153 void Copy(const std::string& src, const std::string& dst);
154
155 /// @brief Remove a map entry if present
156 /// @param key key we want to remove
157 void Erase(const std::string& key);
158
159 /// @brief Clear all the entries in the blackboard and load new ones
160 /// @param values Values to load into the blackboard after clearing
161 void Reset(const std::map<std::string, std::any>& values = {});
162
163 void Subscribe(BlackboardObserver* observer);
164
165 void Unsubscribe(BlackboardObserver* observer);
166
167 private:
168 void NotifyCleared() const;
169 void NotifyKeyRemoved(const std::string& key) const;
170 void NotifyKeyChanged(const std::string& key, const std::any& value) const;
171
172 private:
173 std::map<std::string, std::any> blackboard;
174 std::vector<BlackboardObserver*> observers;
175 };
176} // namespace Botcraft
virtual void OnValueChanged(const std::string &key, const std::any &value)=0
virtual void OnValueRemoved(const std::string &key)=0
A map wrapper to store arbitrary data.
const T & Get(const std::string &key, const T &default_value)
Get the map value at key, casting it to T.
void Set(const std::string &key, const T &value)
Set map entry at key to value.
NotifyOnEndUseRef< T > GetRef(const std::string &key)
Get a ref to the map value at key, casting it to T&.
std::map< std::string, std::any > blackboard
const T & Get(const std::string &key)
Get the map value at key, casting it to T.
NotifyOnEndUseRef< T > GetRef(const std::string &key, const T &default_value)
Get a ref to the map value at key, casting it to T&.
std::vector< BlackboardObserver * > observers
Wrapper around a reference that will run a callback on destruct.
std::function< void()> on_destruct_callback
T & ref() const &
Reference getter.
NotifyOnEndUseRef(T &r, const std::function< void()> &on_destruct_callback_)
T & ref() const &&=delete
STL namespace.