Sparkle 0.0.1
Loading...
Searching...
No Matches
spk_buffer_layout.hpp
1#pragma once
2
3#include <cstddef>
4#include <cstdint>
5#include <stdexcept>
6#include <string>
7#include <type_traits>
8#include <unordered_map>
9#include <variant>
10#include <vector>
11
12namespace spk
13{
26 {
27 public:
31 using Buffer = std::uint8_t *;
32
33 class Element;
34
35 private:
36 struct ObjectData
37 {
38 std::unordered_map<std::wstring, Element> children;
39 };
40
41 struct ArrayData
42 {
43 std::vector<Element> elements;
44
50 void build(std::size_t p_count, const Element &p_unitElement);
51 };
52
53 public:
64 class Element
65 {
66 friend class BufferLayout;
67 friend struct ObjectData;
68 friend struct ArrayData;
69
70 public:
74 using Content = std::variant<std::monostate, ObjectData, ArrayData>;
75
79 Element() = default;
80
85 explicit Element(std::size_t p_size) :
86 _offset(0),
87 _size(p_size),
88 _content(std::monostate{})
89 {
90 }
91
92 private:
93 Element(std::size_t p_offset, std::size_t p_size) :
94 _offset(p_offset),
95 _size(p_size),
96 _content(std::monostate{})
97 {
98 }
99
100 public:
105 Element(const Element &p_other) = default;
111 Element &operator=(const Element &p_other) = default;
112
117 std::size_t offset() const;
122 std::size_t size() const;
123
128 void bind(Buffer p_parentBuffer);
129
136 template <typename TType>
137 Element &operator=(const TType &p_value)
138 {
139 setData(p_value);
140 return *this;
141 }
142
143 template <typename TType>
149 void setData(const TType &p_value)
150 {
151 static_assert(std::is_trivially_copyable_v<TType>, "Element::setData requires trivially copyable types");
152 setData(&p_value, sizeof(TType));
153 }
154
161 template <typename TType>
162 const TType &as() const
163 {
164 static_assert(std::is_trivially_copyable_v<TType>, "Element::as requires trivially copyable types");
165 if (_buffer == nullptr)
166 {
167 throw std::runtime_error("Element::as: buffer is null (not bound)");
168 }
169 if (sizeof(TType) != _size)
170 {
171 throw std::runtime_error("Element::as: size mismatch");
172 }
173 return *reinterpret_cast<const TType *>(_buffer);
174 }
175
182 template <typename TType>
183 TType &as()
184 {
185 static_assert(std::is_trivially_copyable_v<TType>, "Element::as requires trivially copyable types");
186 if (_buffer == nullptr)
187 {
188 throw std::runtime_error("Element::as: buffer is null (not bound)");
189 }
190 if (sizeof(TType) != _size)
191 {
192 throw std::runtime_error("Element::as: size mismatch");
193 }
194 return *reinterpret_cast<TType *>(_buffer);
195 }
196
202 void setData(const void *p_data, std::size_t p_size);
203
211 Element &addMember(const std::wstring &p_name, std::size_t p_relativeOffset, const Element &p_member);
212
221 Element &addArray(const std::wstring &p_name, std::size_t p_relativeOffset, std::size_t p_count, const Element &p_arrayElement);
222
230 Element &addArray(const std::wstring &p_name, std::size_t p_count, const Element &p_arrayElement);
231
238 Element &operator[](const std::wstring &p_name);
245 const Element &operator[](const std::wstring &p_name) const;
246
253 Element &operator[](std::size_t p_index);
260 const Element &operator[](std::size_t p_index) const;
261
266 void remove(const std::wstring &p_name);
267
272 std::unordered_map<std::wstring, Element> &objectChildren();
277 const std::unordered_map<std::wstring, Element> &objectChildren() const;
278
283 std::vector<Element> &arrayElements();
288 const std::vector<Element> &arrayElements() const;
289
290 private:
295 bool _isObject() const;
300 bool _isArray() const;
301
305 void _makeObject();
309 void _makeArray();
310
315 ObjectData &_asObject();
320 const ObjectData &_asObject() const;
321
326 ArrayData &_asArray();
331 const ArrayData &_asArray() const;
332
340 void _validateChildBounds(std::size_t p_relativeOffset, std::size_t p_childSize, const char *p_context) const;
341
342 Buffer _buffer = nullptr;
343 std::size_t _offset = 0;
344 std::size_t _size = 0;
345 Content _content = std::monostate{};
346 };
347
348 private:
349 Buffer _buffer = nullptr;
350 Element _root;
351
352 public:
358 BufferLayout(Buffer p_buffer, std::size_t p_size);
359
364 Element &root();
369 const Element &root() const;
370
378 Element &addMember(const std::wstring &p_name, std::size_t p_relativeOffset, const Element &p_member);
379
388 Element &addArray(const std::wstring &p_name, std::size_t p_relativeOffset, std::size_t p_count, const Element &p_arrayElement);
389
395 Element &operator[](const std::wstring &p_name);
401 const Element &operator[](const std::wstring &p_name) const;
402
407 void remove(const std::wstring &p_name);
412 void resize(std::size_t p_size);
413 };
414}
Node within a BufferLayout representing an object, array or leaf segment.
Definition spk_buffer_layout.hpp:65
Element & operator=(const TType &p_value)
Assigns data to this element via setData.
Definition spk_buffer_layout.hpp:137
Element & operator=(const Element &p_other)=default
Assigns layout metadata from another element.
Element & addArray(const std::wstring &p_name, std::size_t p_relativeOffset, std::size_t p_count, const Element &p_arrayElement)
Adds an array child with explicit offset for the first element.
Definition spk_buffer_layout.cpp:90
std::unordered_map< std::wstring, Element > & objectChildren()
Returns mutable children map for objects.
Definition spk_buffer_layout.cpp:200
Element()=default
Builds an empty element.
std::vector< Element > & arrayElements()
Returns mutable array elements.
Definition spk_buffer_layout.cpp:210
std::size_t offset() const
Returns the byte offset from the parent buffer start.
Definition spk_buffer_layout.cpp:9
Element(const Element &p_other)=default
Copies layout metadata from another element.
const TType & as() const
Interprets the element data as a const reference to a value type.
Definition spk_buffer_layout.hpp:162
TType & as()
Interprets the element data as a mutable reference to a value type.
Definition spk_buffer_layout.hpp:183
void remove(const std::wstring &p_name)
Removes a named child from an object element.
Definition spk_buffer_layout.cpp:189
Element(std::size_t p_size)
Builds a leaf element with a fixed size.
Definition spk_buffer_layout.hpp:85
Element & addMember(const std::wstring &p_name, std::size_t p_relativeOffset, const Element &p_member)
Adds a named child member to an object element.
Definition spk_buffer_layout.cpp:62
void setData(const TType &p_value)
Writes trivially-copyable data into the element.
Definition spk_buffer_layout.hpp:149
Element & operator[](const std::wstring &p_name)
Accesses a named child element by reference.
Definition spk_buffer_layout.cpp:147
std::size_t size() const
Returns the size of this element in bytes.
Definition spk_buffer_layout.cpp:14
void bind(Buffer p_parentBuffer)
Binds this element to a parent buffer.
Definition spk_buffer_layout.cpp:19
std::variant< std::monostate, ObjectData, ArrayData > Content
Internal storage describing whether the element is empty, object or array shaped.
Definition spk_buffer_layout.hpp:74
BufferLayout(Buffer p_buffer, std::size_t p_size)
Creates a layout bound to a buffer.
Definition spk_buffer_layout.cpp:284
void remove(const std::wstring &p_name)
Removes a named child from the root.
Definition spk_buffer_layout.cpp:330
void resize(std::size_t p_size)
Resizes the underlying buffer and updates the root size.
Definition spk_buffer_layout.cpp:335
std::uint8_t * Buffer
Raw byte buffer bound to the layout operations.
Definition spk_buffer_layout.hpp:31
Element & addMember(const std::wstring &p_name, std::size_t p_relativeOffset, const Element &p_member)
Adds a named member to the root object.
Definition spk_buffer_layout.cpp:310
Element & root()
Accesses the root element.
Definition spk_buffer_layout.cpp:300
Element & addArray(const std::wstring &p_name, std::size_t p_relativeOffset, std::size_t p_count, const Element &p_arrayElement)
Adds an array to the root with explicit offset.
Definition spk_buffer_layout.cpp:315
Element & operator[](const std::wstring &p_name)
Accesses a named child from the root.
Definition spk_buffer_layout.cpp:320
STL namespace.