Grail (C++)  1.2.0
A multi-platform, modular, universal engine for embedding advanced AI in games.
Blackboard.hh
1 // Copyright QED Software 2023.
2 
3 #ifndef GRAIL_BLACKBOARD_H
4 #define GRAIL_BLACKBOARD_H
5 
6 #include "consts.h"
7 #include "../GrailLogger/LoggerManager.hh"
8 
9 #include <functional>
10 #include <map>
11 #include <mutex>
12 
13 #ifndef BUILD_UNREAL
14 #include <any>
15 #endif
16 
17 namespace grail
18 {
22  class Blackboard
23  {
24  #ifdef BUILD_UNREAL
25  class UnsafeAny;
26  friend bool operator == (const UnsafeAny& first, const UnsafeAny& second);
27  #endif
28 
29  public:
30  Blackboard() = default;
31  Blackboard(const Blackboard& other);
32  Blackboard(Blackboard&& other) = delete;
33 
34  ~Blackboard() = default;
35 
36  Blackboard& operator =(const Blackboard& other);
37  Blackboard& operator =(Blackboard&& other) = delete;
38 
46  #ifndef BUILD_UNREAL
47  static void TwoWayMerge(Blackboard& first,
48  Blackboard& second,
49  std::function<const std::any&(const std::any&, const std::any&)> firstStrategy =
51  std::function<const std::any&(const std::any&, const std::any&)> secondStrategy =
52  OursStrategy);
53  #else
54  static void TwoWayMerge(Blackboard& first, Blackboard& second,
55  std::function<const UnsafeAny&(const UnsafeAny&, const UnsafeAny&)> firstStrategy = OursStrategy,
56  std::function<const UnsafeAny&(const UnsafeAny&, const UnsafeAny&)> secondStrategy = OursStrategy);
57  #endif
58 
65  #ifndef BUILD_UNREAL
66  static const std::any& OursStrategy(const std::any& ours, const std::any& theirs);
67  #else
68  static const UnsafeAny& OursStrategy(const UnsafeAny& ours, const UnsafeAny& theirs);
69  #endif
70 
77  #ifndef BUILD_UNREAL
78  static const std::any& TheirsStrategy(const std::any& ours, const std::any& theirs);
79  #else
80  static const UnsafeAny& TheirsStrategy(const UnsafeAny& ours, const UnsafeAny& theirs);
81  #endif
82 
88  #ifndef BUILD_UNREAL
89  void Merge(const Blackboard& other,
90  std::function<const std::any&(const std::any&, const std::any&)> mergeStrategy = OursStrategy);
91  #else
92  void Merge(const Blackboard& other, std::function<const UnsafeAny&(const UnsafeAny&, const UnsafeAny&)> mergeStrategy = OursStrategy);
93  #endif
94 
99  void RemoveEntry(const std::string& key);
100 
106  bool ContainsKey(const std::string& key) const;
107 
112  size_t Size() const;
113 
114  template <typename T>
120  void SetValue(const std::string& key, const T& value)
121  {
122  std::lock_guard<std::mutex> lock{mutex};
123  #ifndef BUILD_UNREAL
124  std::any any = value;
125  data[key] = any;
126  #else
127  auto deleter = [](void* memory)
128  {
129  T* dataPointer = static_cast<T*>(memory);
130  delete dataPointer;
131  };
132  auto cloner = [](void* memory)
133  {
134  T* dataPointer = static_cast<T*>(memory);
135  return new T{*dataPointer};
136  };
137 
138  data[key] = UnsafeAny(new T{value}, deleter, cloner);
139  #endif
140  }
141 
142  template <typename T, std::enable_if_t<!std::is_reference<T>::value>* = nullptr>
148  void SetValue(const std::string& key, T&& value)
149  {
150  std::lock_guard<std::mutex> lock{mutex};
151  #ifndef BUILD_UNREAL
152  data[key] = std::any{value};
153  #else
154  auto deleter = [](void* memory)
155  {
156  T* dataPointer = static_cast<T*>(memory);
157  delete dataPointer;
158  };
159  auto cloner = [](void* memory)
160  {
161  T* dataPointer = static_cast<T*>(memory);
162  return new T{*dataPointer};
163  };
164  data[key] = UnsafeAny(new T{value}, deleter, cloner);
165  #endif
166  }
167 
168  template <typename T>
173  void SetDefaultValue(const std::string& key)
174  {
175  std::lock_guard<std::mutex> lock{mutex};
176  #ifndef BUILD_UNREAL
177  data[key] = std::any{T{}};
178  #else
179  auto deleter = [](void* memory)
180  {
181  T* dataPointer = static_cast<T*>(memory);
182  delete dataPointer;
183  };
184  auto cloner = [](void* memory)
185  {
186  T* dataPointer = static_cast<T*>(memory);
187  return new T{*dataPointer};
188  };
189  data[key] = UnsafeAny(new T{}, deleter, cloner);
190  #endif
191  }
192 
193  template <typename T>
199  const T& GetValue(const std::string& key) const
200  {
201  std::lock_guard<std::mutex> lock{mutex};
202  auto iterator = data.find(key);
203  if(iterator == data.end())
204  {
205  GRAIL_LOG(consts::DEFAULT_GRAIL_LOG_GROUP, logger::Severity::CRITICAL, "Invalid key (" + key + ")");
206  }
207  #ifndef BUILD_UNREAL
208  return std::any_cast<const T&>(iterator->second);
209  #else
210  return *static_cast<T*>(iterator->second.GetDataPointer());
211  #endif
212  }
213 
214  template <typename T>
220  T& GetOrAddValue(const std::string& key)
221  {
222  std::lock_guard<std::mutex> lock{mutex};
223  #ifndef BUILD_UNREAL
224  return std::any_cast<T&>(data[key]);
225  #else
226  auto iterator = data.find(key);
227  if(iterator == data.end())
228  {
229  auto deleter = [](void* memory)
230  {
231  T* dataPointer = static_cast<T*>(memory);
232  delete dataPointer;
233  };
234  auto cloner = [](void* memory)
235  {
236  T* dataPointer = static_cast<T*>(memory);
237  return new T{*dataPointer};
238  };
239  iterator = data.emplace(std::piecewise_construct, std::forward_as_tuple(key),
240  std::forward_as_tuple(new T{}, deleter, cloner)).first;
241  }
242  return *static_cast<T*>(iterator->second.GetDataPointer());
243  #endif
244  }
245 
246  template <typename T>
253  bool TryGetValue(const std::string& key, T& outValue) const
254  {
255  std::lock_guard<std::mutex> lock{mutex};
256  auto iter = data.find(key);
257  if(iter != data.end())
258  {
259  #ifndef BUILD_UNREAL
260  outValue = std::any_cast<T>(iter->second);
261  #else
262  outValue = *static_cast<T*>(iter->second.GetDataPointer());
263  #endif
264  return true;
265  }
266  return false;
267  }
268 
269  void AddDataToNameMap(std::map<std::string, std::string>& outMap) const;
270 
271  private:
272  #ifndef BUILD_UNREAL
273  std::map<std::string, std::any> data{};
274  #else
275  class UnsafeAny
276  {
277  friend bool operator == (const UnsafeAny& first, const UnsafeAny& second);
278 
279  public:
280  UnsafeAny() = default;
281  UnsafeAny(void* dataPointer, std::function<void(void*)> deleter, std::function<void*(void*)> cloner);
282 
283  UnsafeAny(const UnsafeAny& other);
284  UnsafeAny(UnsafeAny&& other);
285 
286  ~UnsafeAny();
287 
288  UnsafeAny& operator = (const UnsafeAny& other);
289  UnsafeAny& operator = (UnsafeAny&& other);
290 
291  void* GetDataPointer() const;
292 
293  private:
294  void* dataPointer{nullptr};
295  std::function<void(void*)> deleter{[](void*){}};
296  std::function<void*(void*)> cloner{[](void*){ return nullptr; }};
297  };
298 
299  std::map<std::string, UnsafeAny> data{};
300  #endif
301  mutable std::mutex mutex{};
302  };
303 }
304 
305 #endif //GRAIL_BLACKBOARD_H
grail::Blackboard::Size
size_t Size() const
Size.
Definition: Blackboard.cpp:99
grail::Blackboard::TryGetValue
bool TryGetValue(const std::string &key, T &outValue) const
TryGetValue - Checks whether blackboard contains given key. If it does, assigns keyed value to refere...
Definition: Blackboard.hh:253
grail::Blackboard::TheirsStrategy
static const std::any & TheirsStrategy(const std::any &ours, const std::any &theirs)
TheirsStrategy.
Definition: Blackboard.cpp:47
grail::Blackboard::SetDefaultValue
void SetDefaultValue(const std::string &key)
SetDefaultValue - Inserts default value of given type keyed with name into this blackboard....
Definition: Blackboard.hh:173
grail::Blackboard
The Blackboard class - grail's universal data container.
Definition: Blackboard.hh:22
grail::Blackboard::ContainsKey
bool ContainsKey(const std::string &key) const
ContainsKey - Checks whether this blackboard contains given key.
Definition: Blackboard.cpp:93
grail::Blackboard::SetValue
void SetValue(const std::string &key, const T &value)
SetValue - Inserts value keyed with name into this blackboard. If key already exists new value is ass...
Definition: Blackboard.hh:120
grail::Blackboard::RemoveEntry
void RemoveEntry(const std::string &key)
RemoveValue - Deletes value keyed with given name from this blackboard.
Definition: Blackboard.cpp:87
grail::Blackboard::OursStrategy
static const std::any & OursStrategy(const std::any &ours, const std::any &theirs)
OursStrategy.
Definition: Blackboard.cpp:38
grail::Blackboard::Merge
void Merge(const Blackboard &other, std::function< const std::any &(const std::any &, const std::any &)> mergeStrategy=OursStrategy)
Merge - Merges data from other blackboard into this one. All conflicts are solved in favor of other b...
Definition: Blackboard.cpp:56
grail::Blackboard::GetOrAddValue
T & GetOrAddValue(const std::string &key)
GetOrAddValue - Returns value keyed with name. If blackboard does not contain key,...
Definition: Blackboard.hh:220
grail::Blackboard::SetValue
void SetValue(const std::string &key, T &&value)
SetValue - Inserts value keyed with name into this blackboard. If key already exists new value is ass...
Definition: Blackboard.hh:148
grail::Blackboard::TwoWayMerge
static void TwoWayMerge(Blackboard &first, Blackboard &second, std::function< const std::any &(const std::any &, const std::any &)> firstStrategy=OursStrategy, std::function< const std::any &(const std::any &, const std::any &)> secondStrategy=OursStrategy)
TwoWayMerge - merges second blackboard into first and first into second, uses provided merge strategi...
Definition: Blackboard.cpp:23
grail::Blackboard::GetValue
const T & GetValue(const std::string &key) const
GetValue - Returns value keyed with name. This method assumes that this blackboard contains given key...
Definition: Blackboard.hh:199