4#include "pixelbullet/math/validation.h"
14#include <system_error>
27enum class NodeType : uint8_t
38using NodeValue = std::string;
39using NodeProperty = std::pair<std::string, class Node>;
40using NodeProperties = std::vector<NodeProperty>;
61 constexpr Format(
int s,
char nl,
char spc,
bool inline_arr)
69 std::string indentation(
const int indent_level)
const
71 ASSERT(indent_level >= 0,
"Negative indentation level");
73 return std::string(
static_cast<std::size_t
>(
spaces_per_indent * indent_level),
' ');
82 Node(
const Node&) =
default;
83 Node(Node&&) noexcept = default;
84 Node& operator=(const Node&) = default;
85 Node& operator=(Node&&) noexcept = default;
88 [[nodiscard]] const NodeValue& value() const noexcept;
89 void set_value(const NodeValue& value);
90 void set_value(NodeValue&& value);
92 [[nodiscard]] NodeType type() const noexcept;
93 void set_type(NodeType type);
97 [[nodiscard]]
bool is_valid() const noexcept;
99 [[nodiscard]] const NodeProperties& properties() const noexcept;
100 NodeProperties& properties();
102 [[nodiscard]]
bool has_property(const std::
string& name) const;
103 [[nodiscard]] const Node* get_property(const std::
string& name) const;
104 void set_property(const std::
string& name, const Node& node);
105 bool remove_property(const std::
string& name);
108 Node& operator[](const std::
string& key);
109 const Node& operator[](const std::
string& key) const;
112 Node& operator[](std::
size_t index);
113 const Node& operator[](std::
size_t index) const;
116 template <typename T>
124 template <
typename T>
125 void set(
const T& in)
133 return properties_.begin();
137 return properties_.end();
141 return properties_.begin();
145 return properties_.end();
149 [[nodiscard]] std::size_t size() const noexcept
151 return properties_.size();
170 if (node.value_ ==
"true" || node.value_ ==
"1")
174 else if (node.value_ ==
"false" || node.value_ ==
"0")
180 ASSERT(
false,
"Invalid boolean value: {}", node.value_);
188 node.set_value(b ?
"true" :
"false");
189 node.set_type(NodeType::Boolean);
193 static bool parse_yaml(Node& node, std::string_view str);
197 void EnsureObjectStateForMutation();
199 NodeProperties properties_;
201 NodeType type_ = NodeType::Null;
208 requires std::is_arithmetic_v<T>
209Node& operator<<(
Node& node,
const T& value)
212 if constexpr (std::is_floating_point_v<T>)
214 ASSERT(pixelbullet::math::is_finite(
static_cast<long double>(value)),
"Cannot serialize non-finite floating-point value");
217 const auto [ptr, ec] = std::to_chars(buffer, buffer +
sizeof(buffer), value);
218 ASSERT(ec == std::errc(),
"Conversion to string failed");
219 node.set_value(std::string(buffer, ptr));
220 if constexpr (std::is_integral_v<T>)
222 node.set_type(NodeType::Integer);
224 else if constexpr (std::is_floating_point_v<T>)
226 node.set_type(NodeType::Decimal);
232 requires std::is_arithmetic_v<T>
233void operator>>(
const Node& node, T& value)
235 const std::string& s = node.value();
236 const char* begin = s.data();
237 const char* end = s.data() + s.size();
238 const auto result = std::from_chars(begin, end, value);
239 ASSERT(result.ec == std::errc() && result.ptr == end,
"Conversion failed for value: {}", s);
242inline Node& operator<<(
Node& node,
const std::string& value)
244 node.set_value(value);
245 node.set_type(NodeType::String);
249inline Node& operator<<(
Node& node,
const char* value)
251 ASSERT(value !=
nullptr,
"Cannot serialize null C string");
252 node.set_value(value);
253 node.set_type(NodeType::String);
257inline const Node& operator>>(
const Node& node, std::string& value)
259 value = node.value();
264Node& operator<<(
Node& node,
const std::vector<T>& vec)
266 node.set_type(NodeType::Array);
267 auto& props = node.properties();
269 for (
const T& item : vec)
273 props.emplace_back(
"", child);
279void operator>>(
const Node& node, std::vector<T>& vec)
281 ASSERT(node.type() == NodeType::Array,
"Node is not an array");
283 for (
const auto& [key, child] : node.properties())
287 vec.push_back(std::move(item));
292Node& operator<<(
Node& node,
const std::map<std::string, T>& mapData)
294 node.set_type(NodeType::Object);
295 auto& props = node.properties();
297 for (
const auto& [key, value] : mapData)
301 props.emplace_back(key, child);
307void operator>>(
const Node& node, std::map<std::string, T>& mapData)
309 ASSERT(node.type() == NodeType::Object,
"Node is not an object");
311 for (
const auto& [key, child] : node.properties())
315 mapData.emplace(key, std::move(item));
319inline bool operator==(
const Node& lhs,
const Node& rhs)
321 return lhs.type() == rhs.type() && lhs.value() == rhs.value() && lhs.properties() == rhs.properties();
324inline bool operator!=(
const Node& lhs,
const Node& rhs)
326 return !(lhs == rhs);
329inline bool operator<(
const Node& lhs,
const Node& rhs)
331 if (lhs.type() != rhs.type())
333 return lhs.type() < rhs.type();
335 if (lhs.value() != rhs.value())
337 return lhs.value() < rhs.value();
339 return lhs.properties() < rhs.properties();
344 requires std::is_enum_v<T>
345const Node& operator>>(
const Node& node, T&
object)
347 using Underlying = std::underlying_type_t<T>;
350 object =
static_cast<T
>(value);
355 requires std::is_enum_v<T>
356Node& operator<<(
Node& node, T
object)
358 return node << static_cast<std::underlying_type_t<T>>(object);
361inline const Node& operator>>(
const Node& node, std::pair<std::string, std::string>& p)
363 ASSERT(node.type() == NodeType::Object,
"Expected object type for a pair");
364 const auto& props = node.properties();
365 ASSERT(props.size() == 1,
"Expected exactly one property for a pair");
366 p.first = props[0].first;
367 props[0].second >> p.second;
371inline Node& operator<<(
Node& node,
const std::pair<std::string, std::string>& p)
373 node.set_type(NodeType::Object);
374 auto& props = node.properties();
377 valueNode << p.second;
378 props.emplace_back(p.first, valueNode);
Provides assertion and panic mechanisms with optional custom formatting.
#define ASSERT(condition,...)
Asserts that a condition is true.
Definition assert.h:142
Represents a hierarchical node capable of storing various data types and supporting YAML serializatio...
Definition node.h:49
friend Node & operator<<(Node &node, const Node &in)
Copy content from one node to another.
Definition node.h:162
friend const Node & operator>>(const Node &node, Node &out)
Copy the node's content.
Definition node.h:155