PixelBullet  0.0.1
A C++ game engine
Loading...
Searching...
No Matches
Node.hpp
1#pragma once
2
4#include "PixelBullet/Filesystem/String.hpp"
5
6#include <glm/glm.hpp>
7
8#include <algorithm>
9#include <charconv>
10#include <cstdint>
11#include <map>
12#include <sstream>
13#include <string>
14#include <string_view>
15#include <type_traits>
16#include <vector>
17
18namespace YAML
19{
20 class Node;
21}
22
23namespace PixelBullet
24{
26 enum class NodeType : uint8_t
27 {
28 Null,
29 Object,
30 Array,
31 String,
32 Boolean,
33 Integer,
34 Decimal,
35 Unknown,
36 Token,
37 EndOfFile
38 };
39
40 using NodeValue = std::string;
41 using NodeProperty = std::pair<std::string, class Node>;
42 using NodeProperties = std::vector<NodeProperty>;
43
50 class Node
51 {
52 public:
56 struct Format
57 {
59 char newLine;
60 char space;
62
63 constexpr Format(int8_t s, char nl, char spc, bool inlineArr)
65 , newLine(nl)
66 , space(spc)
67 , inlineArrays(inlineArr)
68 {
69 }
70
71 std::string GetIndentation(int8_t indentLevel) const
72 {
73 return std::string(spacesPerIndent * indentLevel, ' ');
74 }
75
76 static const Format Beautified;
77 static const Format Minified;
78 };
79
80 Node() = default;
81 Node(const Node&) = default;
82 Node(Node&&) noexcept = default;
83 Node& operator=(const Node&) = default;
84 Node& operator=(Node&&) noexcept = default;
85 ~Node() = default;
86
87 [[nodiscard]] const NodeValue& GetValue() const noexcept;
88 void SetValue(const NodeValue& value);
89 void SetValue(NodeValue&& value);
90
91 [[nodiscard]] NodeType GetType() const noexcept;
92 void SetType(NodeType type);
93
94 void Clear();
95
96 [[nodiscard]] bool IsValid() const noexcept;
97
98 [[nodiscard]] const NodeProperties& GetProperties() const noexcept;
99 NodeProperties& GetProperties();
100
101 [[nodiscard]] bool HasProperty(const std::string& name) const;
102 [[nodiscard]] const Node* GetProperty(const std::string& name) const;
103 void SetProperty(const std::string& name, const Node& node);
104 bool RemoveProperty(const std::string& name);
105
106 // For object-style indexing
107 Node& operator[](const std::string& key);
108 const Node& operator[](const std::string& key) const;
109
110 // For array-style indexing
111 Node& operator[](size_t index);
112 const Node& operator[](size_t index) const;
113
114 // Convenience functions for type conversion.
115 template <typename T>
116 T As() const
117 {
118 T out{};
119 (*this) >> out;
120 return out;
121 }
122
123 template <typename T>
124 void Set(const T& in)
125 {
126 (*this) << in;
127 }
128
129 // Iterators to properties
130 auto begin()
131 {
132 return m_Properties.begin();
133 }
134 auto end()
135 {
136 return m_Properties.end();
137 }
138 auto begin() const
139 {
140 return m_Properties.begin();
141 }
142 auto end() const
143 {
144 return m_Properties.end();
145 }
146
147 // Optional: returns the number of properties (useful for arrays/objects)
148 [[nodiscard]] size_t size() const noexcept
149 {
150 return m_Properties.size();
151 }
152
154 friend const Node& operator>>(const Node& node, Node& out)
155 {
156 out = node;
157 return node;
158 }
159
161 friend Node& operator<<(Node& node, const Node& in)
162 {
163 node = in;
164 return node;
165 }
166
167 friend const Node& operator>>(const Node& node, bool& b)
168 {
169 if (node.m_Value == "true" || node.m_Value == "1")
170 {
171 b = true;
172 }
173 else if (node.m_Value == "false" || node.m_Value == "0")
174 {
175 b = false;
176 }
177 else
178 {
179 ASSERT(false, "Invalid boolean value: {}", node.m_Value);
180 b = false;
181 }
182 return node;
183 }
184
185 friend Node& operator<<(Node& node, bool b)
186 {
187 node.m_Value = b ? "true" : "false";
188 node.m_Type = NodeType::Boolean;
189 return node;
190 }
191
192 static bool ParseYAML(Node& node, std::string_view str);
193 static bool WriteYAML(const Node& node, std::ostream& stream, const Format& format = Format::Minified);
194
195 private:
196 static Node YAMLToNode(const YAML::Node& yaml);
197 static YAML::Node NodeToYAML(const Node& node);
198
199 NodeProperties m_Properties;
200 NodeValue m_Value;
201 NodeType m_Type = NodeType::Null;
202 };
203
204 // --- Free Conversion Operators ---
205
206 // Arithmetic conversion using C++20 requires clause.
207 template <typename T>
208 requires std::is_arithmetic_v<T>
209 Node& operator<<(Node& node, const T& value)
210 {
211 char buffer[64]{};
212 auto [ptr, ec] = std::to_chars(buffer, buffer + sizeof(buffer), value);
213 ASSERT(ec == std::errc(), "Conversion to string failed");
214 node.SetValue(std::string(buffer, ptr));
215 if constexpr (std::is_integral_v<T>)
216 {
217 node.SetType(NodeType::Integer);
218 }
219 else if constexpr (std::is_floating_point_v<T>)
220 {
221 node.SetType(NodeType::Decimal);
222 }
223 return node;
224 }
225
226 template <typename T>
227 requires std::is_arithmetic_v<T>
228 void operator>>(const Node& node, T& value)
229 {
230 const std::string& s = node.GetValue();
231 auto result = std::from_chars(s.data(), s.data() + s.size(), value);
232 ASSERT(result.ec == std::errc(), "Conversion failed for value: {}", s);
233 }
234
235 inline Node& operator<<(Node& node, const std::string& value)
236 {
237 node.SetValue(value);
238 node.SetType(NodeType::String);
239 return node;
240 }
241
242 inline const Node& operator>>(const Node& node, std::string& value)
243 {
244 value = node.GetValue();
245 return node;
246 }
247
248 template <typename T>
249 Node& operator<<(Node& node, const std::vector<T>& vec)
250 {
251 node.SetType(NodeType::Array);
252 auto& props = node.GetProperties();
253 props.clear();
254 for (const T& item : vec)
255 {
256 Node child;
257 child << item;
258 props.emplace_back("", child);
259 }
260 return node;
261 }
262
263 template <typename T>
264 void operator>>(const Node& node, std::vector<T>& vec)
265 {
266 ASSERT(node.GetType() == NodeType::Array, "Node is not an array");
267 vec.clear();
268 for (const auto& [key, child] : node.GetProperties())
269 {
270 T item;
271 child >> item;
272 vec.push_back(std::move(item));
273 }
274 }
275
276 template <typename T>
277 Node& operator<<(Node& node, const std::map<std::string, T>& mapData)
278 {
279 node.SetType(NodeType::Object);
280 auto& props = node.GetProperties();
281 props.clear();
282 for (const auto& [key, value] : mapData)
283 {
284 Node child;
285 child << value;
286 props.emplace_back(key, child);
287 }
288 return node;
289 }
290
291 template <typename T>
292 void operator>>(const Node& node, std::map<std::string, T>& mapData)
293 {
294 ASSERT(node.GetType() == NodeType::Object, "Node is not an object");
295 mapData.clear();
296 for (const auto& [key, child] : node.GetProperties())
297 {
298 T item;
299 child >> item;
300 mapData.emplace(key, std::move(item));
301 }
302 }
303
304 inline bool operator==(const Node& lhs, const Node& rhs)
305 {
306 return lhs.GetType() == rhs.GetType() && lhs.GetValue() == rhs.GetValue() &&
307 lhs.GetProperties() == rhs.GetProperties();
308 }
309
310 inline bool operator!=(const Node& lhs, const Node& rhs)
311 {
312 return !(lhs == rhs);
313 }
314
315 inline bool operator<(const Node& lhs, const Node& rhs)
316 {
317 if (lhs.GetType() != rhs.GetType())
318 {
319 return lhs.GetType() < rhs.GetType();
320 }
321 if (lhs.GetValue() != rhs.GetValue())
322 {
323 return lhs.GetValue() < rhs.GetValue();
324 }
325 return lhs.GetProperties() < rhs.GetProperties();
326 }
327
328 // Enum conversions – now enabled only for enums.
329 template <typename T>
330 requires std::is_enum_v<T>
331 const Node& operator>>(const Node& node, T& object)
332 {
333 object = String::From<T>(node.GetValue());
334 return node;
335 }
336
337 template <typename T>
338 requires std::is_enum_v<T>
339 Node& operator<<(Node& node, T object)
340 {
341 node.SetValue(String::To(object));
342 node.SetType(NodeType::Integer);
343 return node;
344 }
345
346 inline const Node& operator>>(const Node& node, std::pair<std::string, std::string>& p)
347 {
348 ASSERT(node.GetType() == NodeType::Object, "Expected object type for a pair");
349 const auto& props = node.GetProperties();
350 ASSERT(props.size() == 1, "Expected exactly one property for a pair");
351 p.first = props[0].first;
352 props[0].second >> p.second;
353 return node;
354 }
355
356 inline Node& operator<<(Node& node, const std::pair<std::string, std::string>& p)
357 {
358 node.SetType(NodeType::Object);
359 auto& props = node.GetProperties();
360 props.clear();
361 Node valueNode;
362 valueNode << p.second;
363 props.emplace_back(p.first, valueNode);
364 return node;
365 }
366
367 inline Node& operator<<(Node& node, const glm::vec3& v)
368 {
369 node.SetType(NodeType::Array);
370 auto& props = node.GetProperties();
371 props.clear();
372
373 Node x, y, z;
374 x << v.x;
375 y << v.y;
376 z << v.z;
377 props.emplace_back("", std::move(x));
378 props.emplace_back("", std::move(y));
379 props.emplace_back("", std::move(z));
380 return node;
381 }
382
383 inline void operator>>(const Node& node, glm::vec3& v)
384 {
385 ASSERT(node.GetType() == NodeType::Array, "Node is not an array");
386 const auto& props = node.GetProperties();
387 ASSERT(props.size() >= 3, "Insufficient elements for glm::vec3");
388 props[0].second >> v.x;
389 props[1].second >> v.y;
390 props[2].second >> v.z;
391 }
392} // namespace PixelBullet
Provides assertion and panic mechanisms with optional custom formatting.
#define ASSERT(condition,...)
Asserts that a condition is true.
Definition Assert.hpp:151
Represents a hierarchical node capable of storing various data types and supporting YAML serializatio...
Definition Node.hpp:51
friend Node & operator<<(Node &node, const Node &in)
Copy content from one node to another.
Definition Node.hpp:161
friend const Node & operator>>(const Node &node, Node &out)
Copy the node's content.
Definition Node.hpp:154
Formatting options for YAML serialization.
Definition Node.hpp:57
char space
Space character.
Definition Node.hpp:60
char newLine
New line character.
Definition Node.hpp:59
static const Format Beautified
Predefined beautified format.
Definition Node.hpp:76
int8_t spacesPerIndent
Number of spaces per indent level.
Definition Node.hpp:58
bool inlineArrays
Flag to inline arrays.
Definition Node.hpp:61
static const Format Minified
Predefined minified format.
Definition Node.hpp:77