Grail (C++)  1.3.0
A multi-platform, modular, universal engine for embedding advanced AI in games.
BlackboardEntry.hh
1 // Copyright QED Software 2023.
2 
3 #ifndef GRAIL_BLACKBOARD_ENTRY_H
4 #define GRAIL_BLACKBOARD_ENTRY_H
5 
6 #include "../GrailLogger/LoggerManager.hh"
7 
8 #include <string>
9 #include <functional>
10 #include <iostream>
11 #include <memory>
12 #include <type_traits>
13 #include <string>
14 #include <functional>
15 #include <map>
16 #include <mutex>
17 #include <typeinfo>
18 #include <utility>
19 #include <cassert>
20 
21 #ifndef BUILD_UNREAL
22 #include <any>
23 #endif
24 
25 namespace grail
26 {
27  class Blackboard;
28  template<typename T>
29  std::string SerializeData(const T& element);
30 
34  template <typename T>
35  struct IsRawArray : std::false_type {};
36 
37  template <typename T>
38  struct IsRawArray<T[]> : std::true_type {};
39 
40  template <typename T, std::size_t N>
41  struct IsRawArray<T[N]> : std::true_type {};
42 
43  template <typename T>
44  constexpr bool IsRawArrayValue = IsRawArray<T>::value;
45 
46  /***
47  * Attribution 1:
48  * The code inside the macros below was written by Louis Delacroix.
49  * The original publicly available link to repository:
50  * https://gist.github.com/louisdx/1076849
51  ***/
52  #define DECLARE_HAS_CONST_ITERATOR(NAME_SUFFIX, ITERATOR_TYPE) \
53  template<typename T> \
54  struct HasConstIterator_##NAME_SUFFIX \
55  { \
56  private: \
57  typedef char One; \
58  typedef struct { char array[2]; } Two; \
59 \
60  template<typename C> \
61  static One Test(typename C::ITERATOR_TYPE*); \
62  template<typename C> \
63  static Two Test(...); \
64 \
65  public:\
66  static const bool value = sizeof(Test<T>(0)) == sizeof(One);\
67  typedef T type;\
68  };
69 
70 #define DECLARE_HAS_BEGIN_END(NAME_SUFFIX, ITERATOR_TYPE) \
71  template <typename T>\
72  struct HasBeginEnd_##NAME_SUFFIX\
73  {\
74  struct Dummy\
75  {\
76  typedef void ITERATOR_TYPE;\
77  };\
78 \
79  typedef typename std::conditional<HasConstIterator_##NAME_SUFFIX<T>::value, T, Dummy>::type TType;\
80  typedef typename TType::ITERATOR_TYPE Iterator;\
81 \
82  struct Fallback\
83  {\
84  Iterator begin() const;\
85  Iterator end() const;\
86  };\
87 \
88  struct Derived : TType, Fallback\
89  {\
90  };\
91 \
92  template<typename C, C> struct ChT;\
93 \
94  template<typename C> static char(&f(ChT<Iterator(Fallback::*)() const, &C::begin>*))[1];\
95  template<typename C> static char(&f(...))[2];\
96  template<typename C> static char(&g(ChT<Iterator(Fallback::*)() const, &C::end>*))[1];\
97  template<typename C> static char(&g(...))[2];\
98 \
99  static const bool beginValue = sizeof(f<Derived>(0)) == 2;\
100  static const bool endValue = sizeof(g<Derived>(0)) == 2;\
101  };
102  /*End of Attribution 1*/
103 
104  template <typename>
105  struct IsPair : std::false_type { };
106 
107  template <typename T, typename U>
108  struct IsPair<std::pair<T, U>> : std::true_type { };
109 
110  template <typename> struct IsTuple : std::false_type {};
111 
112  template <typename ...T> struct IsTuple<std::tuple<T...>> : std::true_type {};
113 
114  template <typename T>
115  struct IsSharedPointer : std::false_type {};
116 
117  template <typename T>
118  struct IsWeakPointer : std::false_type {};
119 
120  template <typename T>
121  struct IsSharedPointer<std::shared_ptr<T>> : std::true_type {};
122 
123  template <typename T>
124  struct IsWeakPointer<std::weak_ptr<T>> : std::true_type {};
125 
126 /***
127 * Attribution 2:
128 * The code below has been inspired by:
129 https://stackoverflow.com/questions/9407367/determine-if-a-type-is-an-stl-container-at-compile-time
130 ***/
131 #define DECLARE_IS_CONTAINER(NAME_SUFFIX, ITERATOR_TYPE) \
132  DECLARE_HAS_CONST_ITERATOR(NAME_SUFFIX, ITERATOR_TYPE)\
133  DECLARE_HAS_BEGIN_END(NAME_SUFFIX, ITERATOR_TYPE)\
134  template <typename T>\
135  struct IsContainer_##NAME_SUFFIX\
136  {\
137  static const bool value = HasConstIterator_##NAME_SUFFIX<T>::value &&\
138  HasBeginEnd_##NAME_SUFFIX<T>::beginValue && HasBeginEnd_##NAME_SUFFIX<T>::endValue;\
139  };
140 
141  DECLARE_IS_CONTAINER(Std, const_iterator)
142 
143  template<typename T, typename = void>
144  struct CanToString : std::false_type {};
145 
146  template<typename T>
147  struct CanToString<T, std::void_t<decltype(std::to_string(std::declval<T>()))>> : std::true_type {};
148 
149  template<typename T, typename = void>
150  struct BelongsToLibraryTypeGroup : std::false_type {};
151 
152  template<typename T>
153  struct BelongsToLibraryTypeGroup<T, std::void_t<decltype(SerializeLibraryType(std::declval<T>()))>> : std::true_type {};
154 
155  template<typename T, typename = void>
156  struct BelongsToUserTypeGroup : std::false_type {};
157 
158  template<typename T>
159  struct BelongsToUserTypeGroup<T, std::void_t<decltype(SerializeUserType(std::declval<T>()))>> : std::true_type {};
160 
162  template <size_t I>
164  {
165  template <typename T>
166  static std::string Serialize(T& tuple, size_t index)
167  {
168  if (index == I - 1)
169  {
170  return SerializeData(std::get<I - 1>(tuple));
171  }
172  else
173  {
174  return TupleVisitor<I - 1>::Serialize(tuple, index);
175  }
176  }
177  };
178 
179  template <>
180  struct TupleVisitor<0>
181  {
182  template <typename T>
183  static std::string Serialize(T& tuple, size_t index)
184  {
185  return SerializeData(tuple);
186  }
187  };
188 
189  template <typename... Ts>
190  std::string ToString(std::tuple<Ts...> const& tuple, size_t index)
191  {
192  return TupleVisitor<sizeof...(Ts)>::Serialize(tuple, index);
193  }
194 
195  template <typename... Ts>
196  std::string ToString(std::tuple<Ts...>& tuple, size_t index)
197  {
198  return TupleVisitor<sizeof...(Ts)>::Serialize(tuple, index);
199  }
200 
201  template <typename T>
202  std::string SerializeContainer(const T& element)
203  {
204  std::string returnable = "{";
205  for (const auto& elementPart : element)
206  {
207  returnable += SerializeData(elementPart);
208  returnable += ",";
209  }
210 
211  if (returnable.length() > 1)
212  {
213  returnable[returnable.length() - 1]='}';
214  }
215  else
216  {
217  returnable += "}";
218  }
219 
220  return returnable;
221  }
222 
226  template<typename T>
227  std::string SerializeData(const T& element)
228  {
229  if constexpr (std::is_pointer<T>::value || IsSharedPointer<T>::value)
230  {
231  if (element == nullptr)
232  {
233  return "nullptr";
234  }
235 
236  if (IsRawArrayValue<std::remove_pointer_t<T>>)
237  {
238  GRAIL_LOG(consts::DEFAULT_GRAIL_LOG_GROUP, logger::Severity::WARNING, "Attempted to serialize a raw array. Raw arrays are not supported for serialization.");
239  return "Raw array not supported for serialization";
240  }
241 
242  return SerializeData(*element);
243  }
244  else if constexpr (IsWeakPointer<T>::value)
245  {
246  return SerializeData(element.lock());
247  }
248  else if constexpr (IsContainer_Std<T>::value)
249  {
250  return SerializeContainer(element);
251  }
252  else if constexpr (CanToString<T>::value)
253  {
254  return std::to_string(element);
255  }
256  else if constexpr (IsPair<T>::value)
257  {
258  return "{" + SerializeData(element.first) + "," + SerializeData(element.second) + "}";
259  }
260  else if constexpr (IsTuple<T>::value)
261  {
262  std::string returnable = "{";
263  for (int i = 0; i < std::tuple_size<T>::value; ++i)
264  {
265  if (i != 0)
266  {
267  returnable += ",";
268  }
269 
270  returnable += ToString(element, i);
271  }
272  return returnable + "}";
273  }
274 
275  if constexpr (BelongsToLibraryTypeGroup<T>::value)
276  {
277  auto returnable = SerializeLibraryType(element);
278  if(returnable != "")
279  {
280  return returnable;
281  }
282  }
283  if constexpr (BelongsToUserTypeGroup<T>::value)
284  {
285  auto returnable = SerializeUserType(element);
286  if(returnable != "")
287  {
288  return returnable;
289  }
290  }
291 
292  return "Serialization function for type not implemented.";
293  }
294 
295  template<size_t N>
296  std::string SerializeData(const char(&element)[N]);
297 
298  template<>
299  std::string SerializeData<char*>(char* const& element);
300 
301  template<>
302  std::string SerializeData(const char* const& element);
303 
304  template<>
305  std::string SerializeData<std::string>(const std::string& element);
306 
307  template<>
308  std::string SerializeData<Blackboard>(const Blackboard& element);
309 
314  {
319  template <typename T>
320  void SetValue(const T& value)
321  {
322 #ifndef BUILD_UNREAL
323  std::any any = value;
324  data = any;
325 
326  serializationFunction = [](const std::any& value)
327  {
328  return SerializeData<T>(std::any_cast<const T&>(value));
329  };
330 #else
331  auto deleter = [](void* memory)
332  {
333  T* dataPointer = static_cast<T*>(memory);
334  delete dataPointer;
335  };
336  auto cloner = [](void* memory)
337  {
338  T* dataPointer = static_cast<T*>(memory);
339  return new T{ *dataPointer };
340  };
341 
342  data = UnsafeAny(new T{ value }, deleter, cloner);
343  serializationFunction = [](const UnsafeAny& value)
344  {
345  return SerializeData(*static_cast<T*>(value.GetDataPointer()));
346  };
347 #endif
348  }
349 
355  template <typename T>
356  const T& GetValue() const
357  {
358 #ifndef BUILD_UNREAL
359  return std::any_cast<const T&>(data);
360 #else
361  return *static_cast<T*>(data.GetDataPointer());
362 #endif
363  }
364 
370  std::string ToString() const
371  {
372  return serializationFunction(data);
373  }
374 
375 #ifndef BUILD_UNREAL
376  std::any data;
377  std::function<std::string(const std::any&)> serializationFunction;
378 #else
379  class UnsafeAny
380  {
381  friend bool operator == (const UnsafeAny& first, const UnsafeAny& second);
382 
383  public:
384  UnsafeAny() = default;
385  UnsafeAny(void* dataPointer, std::function<void(void*)> deleter, std::function<void* (void*)> cloner);
386 
387  UnsafeAny(const UnsafeAny& other);
388  UnsafeAny(UnsafeAny&& other);
389 
390  ~UnsafeAny();
391 
392  UnsafeAny& operator = (const UnsafeAny& other);
393  UnsafeAny& operator = (UnsafeAny&& other);
394 
395  void* GetDataPointer() const;
396 
397  private:
398  void* dataPointer{ nullptr };
399  std::function<void(void*)> deleter{ [](void*) {} };
400  std::function<void* (void*)> cloner{ [](void*) { return nullptr; } };
401  };
402 
403  UnsafeAny data;
404  std::function<std::string(const UnsafeAny&)> serializationFunction;
405 #endif
406  };
407 }
408 #endif //GRAIL_BLACKBOARD_ENTRY_H
grail::BlackboardEntry::SetValue
void SetValue(const T &value)
SetValue - insterts value of any time into the blackboard entry by converting it to any.
Definition: BlackboardEntry.hh:320
grail::IsWeakPointer
Definition: BlackboardEntry.hh:118
grail::IsSharedPointer
Definition: BlackboardEntry.hh:115
grail::IsTuple
Definition: BlackboardEntry.hh:110
grail::BlackboardEntry::ToString
std::string ToString() const
ToString - Returns serialization of data stored in the entry.
Definition: BlackboardEntry.hh:370
grail::IsRawArray
SFINAE below - all sorts of helpers to determine types in runtime
Definition: BlackboardEntry.hh:35
grail::TupleVisitor
Helpers to iterate over tuples (visitor pattern)
Definition: BlackboardEntry.hh:163
grail::IsPair
Definition: BlackboardEntry.hh:105
grail::BelongsToLibraryTypeGroup
Definition: BlackboardEntry.hh:150
grail::CanToString
Definition: BlackboardEntry.hh:144
grail::BlackboardEntry::GetValue
const T & GetValue() const
GetValue - Returns value stored in the blackboard entry.
Definition: BlackboardEntry.hh:356
grail::BelongsToUserTypeGroup
Definition: BlackboardEntry.hh:156
grail::BlackboardEntry
Definition: BlackboardEntry.hh:313