Grindstone Game Engine v0.2.0
An open source game engine and toolkit.
Loading...
Searching...
No Matches
Blackboard.hpp
1#pragma once
2
3#include <map>
4#include <optional>
5#include <format>
6
7#include "BlackboardEntry.hpp"
8#include <Common/Result.hpp>
9
10namespace Grindstone {
11 class Blackboard {
12 public:
13 enum class BlackboardError {
14 Success,
15 MismatchingType,
16 KeyNotFound
17 };
18
19 template<typename T>
20 BlackboardError SetValue(BlackboardKey key, T value) {
21 static_assert(sizeof(T) <= sizeof(BlackboardValue), "Value is too big - use a pointer.");
22 std::type_index type = (typeid(T));
23
24 auto it = entries.find(key);
25 if (it == entries.end()) {
26 auto insertedEntry = entries.emplace(key, BlackboardEntry(type));
27 memcpy(&insertedEntry.first->second.value, &value, sizeof(T));
28 }
29 else if (it->second.type != type) {
30 return BlackboardError::MismatchingType;
31 }
32 else {
33 memcpy(&it->second.value, &value, sizeof(T));
34 }
35
36 return BlackboardError::Success;
37 }
38
39 template<typename T>
40 BlackboardError SetValueIfExists(BlackboardKey key, T value) {
41 static_assert(sizeof(T) <= sizeof(BlackboardValue), "Value is too big - use a pointer.");
42 std::type_index type = (typeid(T));
43
44 auto it = entries.find(key);
45 if (it == entries.end()) {
46 return BlackboardError::KeyNotFound;
47 }
48 else if (it->second.type != type) {
49 return BlackboardError::MismatchingType;
50 }
51 else {
52 memcpy(&it->second.value, &value, sizeof(T));
53 }
54
55 return BlackboardError::Success;
56 }
57
58 template<typename T>
59 [[nodiscard]] Grindstone::Result<T, BlackboardError> GetValue(BlackboardKey key) const {
60 static_assert(sizeof(T) <= sizeof(BlackboardValue), "Value is too big - use a pointer.");
61 std::type_index type = (typeid(T));
62 auto it = entries.find(key);
63 if (it == entries.end()) {
64 return BlackboardError::KeyNotFound;
65 }
66 else if (it->second.type != type) {
67 return BlackboardError::MismatchingType;
68 }
69 else {
70 T value{};
71 memcpy(&value, &it->second.value, sizeof(T));
72 return value;
73 }
74 }
75
76 template<typename T>
77 [[nodiscard]] bool TryGetValue(BlackboardKey key, T& outValue) const {
78 static_assert(sizeof(T) <= sizeof(BlackboardValue), "Value is too big - use a pointer.");
79 std::type_index type = (typeid(T));
80 auto it = entries.find(key);
81 if (it == entries.end()) {
82 return false;
83 }
84
85 if (it->second.type != type) {
86 return false;
87 }
88
89 memcpy(&outValue, &it->second, sizeof(T));
90
91 return true;
92 }
93
94 template<typename T>
95 static inline BlackboardKey GetBlackboardKeyFromType() {
96 // TODO: Name mangling may cause issues - consider introducing static class name method.
97 return typeid(T).name();
98 }
99
100 template<typename T>
101 BlackboardError SetValue(T value) {
102 const BlackboardKey key = GetBlackboardKeyFromType<T>();
103 static_assert(sizeof(T) <= sizeof(BlackboardValue), "Value is too big - use a pointer.");
104 std::type_index type = (typeid(T));
105
106 auto it = entries.find(key);
107 if (it == entries.end()) {
108 auto insertedEntry = entries.emplace(key, BlackboardEntry(type));
109 memcpy(&insertedEntry.first->second.value, &value, sizeof(T));
110 }
111 else if (it->second.type != type) {
112 return BlackboardError::MismatchingType;
113 }
114 else {
115 memcpy(&it->second.value, &value, sizeof(T));
116 }
117
118 return BlackboardError::Success;
119 }
120
121 template<typename T>
122 BlackboardError SetValueIfExists(T value) {
123 const BlackboardKey key = GetBlackboardKeyFromType<T>();
124 static_assert(sizeof(T) <= sizeof(BlackboardValue), "Value is too big - use a pointer.");
125 std::type_index type = (typeid(T));
126
127 auto it = entries.find(key);
128 if (it == entries.end()) {
129 return BlackboardError::KeyNotFound;
130 }
131 else if (it->second.type != type) {
132 return BlackboardError::MismatchingType;
133 }
134 else {
135 memcpy(&it->second.value, value, sizeof(T));
136 }
137
138 return BlackboardError::Success;
139 }
140
141 template<typename T>
142 [[nodiscard]] Grindstone::Result<T, BlackboardError> GetValue() const {
143 const BlackboardKey key = GetBlackboardKeyFromType<T>();
144 static_assert(sizeof(T) <= sizeof(BlackboardValue), "Value is too big - use a pointer.");
145 std::type_index type = (typeid(T));
146 auto it = entries.find(key);
147 if (it == entries.end()) {
148 return BlackboardError::KeyNotFound;
149 }
150 else if (it->second.type != type) {
151 return BlackboardError::MismatchingType;
152 }
153 else {
154 T value{};
155 memcpy(&value, &it->second.value, sizeof(T));
156 return value;
157 }
158 }
159
160 template<typename T>
161 [[nodiscard]] bool TryGetValue(T& outValue) const {
162 const BlackboardKey key = GetBlackboardKeyFromType<T>();
163 static_assert(sizeof(T) <= sizeof(BlackboardValue), "Value is too big - use a pointer.");
164 std::type_index type = (typeid(T));
165 auto it = entries.find(key);
166 if (it == entries.end()) {
167 return false;
168 }
169
170 if (it->second.type != type) {
171 return false;
172 }
173
174 memcpy(&outValue, &it->second.value, sizeof(T));
175 return true;
176 }
177
178 protected:
179 std::map<BlackboardKey, BlackboardEntry> entries;
180
181 };
182}
183
184template<>
185struct std::formatter<Grindstone::Blackboard::BlackboardError> {
186 constexpr auto parse(std::format_parse_context& ctx) {
187 return ctx.begin();
188 }
189
190 auto format(const Grindstone::Blackboard::BlackboardError& error, std::format_context& ctx) const {
191 switch (error) {
192 case Grindstone::Blackboard::BlackboardError::Success:
193 return std::format_to(ctx.out(), "Success");
194 case Grindstone::Blackboard::BlackboardError::MismatchingType:
195 return std::format_to(ctx.out(), "Mismatching Type");
196 case Grindstone::Blackboard::BlackboardError::KeyNotFound:
197 return std::format_to(ctx.out(), "Key not found");
198 default:
199 return std::format_to(ctx.out(), "Unknown Error");
200 }
201 }
202};
Definition Blackboard.hpp:11
Definition Assert.hpp:16
Definition BlackboardEntry.hpp:10
Definition Result.hpp:7