MayaFlux 0.4.0
Digital-First Multimedia Processing Framework
Loading...
Searching...
No Matches
DataInsertion.hpp
Go to the documentation of this file.
1#pragma once
2
4
5#include <glm/gtc/type_ptr.hpp>
6
7namespace MayaFlux::Kakshya {
8
9/**
10 * @class DataInsertion
11 * @brief Type-erased writer for NDData with semantic construction
12 *
13 * Companion to DataAccess for write operations. Provides unified interface
14 * to insert data from various sources (GLM types, scalar arrays, etc.) into
15 * DataVariant storage while maintaining appropriate dimension metadata.
16 *
17 * Design principle: All types are equal. GLM specializations exist for
18 * ergonomics, not privileged status.
19 */
20class MAYAFLUX_API DataInsertion {
21public:
23 std::vector<DataDimension>& dimensions,
24 DataModality& modality)
25 : m_variant(variant)
26 , m_dimensions(dimensions)
27 , m_modality(modality)
28 {
29 }
30
31 /**
32 * @brief Insert scalar array data
33 * @tparam T Scalar arithmetic type (float, double, int, etc.)
34 * @param data Source data
35 * @param target_modality Semantic interpretation of data
36 * @param replace_existing If true, replaces existing data; if false, appends
37 */
38 template <typename T>
39 requires std::is_arithmetic_v<T>
40 void insert_scalar(std::vector<T> data,
41 DataModality target_modality,
42 bool replace_existing = true)
43 {
44 validate_scalar_insertion(target_modality);
45
46 if (replace_existing) {
47 m_variant = std::move(data);
48 m_modality = target_modality;
49
50 m_dimensions.clear();
51 m_dimensions.emplace_back(
52 modality_to_dimension_name(target_modality),
53 static_cast<uint64_t>(data.size()),
54 1,
55 modality_to_role(target_modality));
56 } else {
57 append_to_existing(std::move(data));
58 }
59 }
60
61 /**
62 * @brief Insert structured GLM data with automatic dimension setup
63 * @tparam T GLM type (glm::vec2, glm::vec3, glm::vec4, glm::mat4)
64 * @param data Source GLM elements
65 * @param target_modality Semantic interpretation (must match GLM component count)
66 * @param replace_existing If true, replaces existing data; if false, appends
67 */
68 template <GlmType T>
69 void insert_structured(std::vector<T> data,
70 DataModality target_modality,
71 bool replace_existing = true)
72 {
73 validate_structured_insertion<T>(target_modality);
74
75 if (replace_existing) {
76 m_variant = std::move(data);
77 m_modality = target_modality;
78
79 m_dimensions.clear();
80 m_dimensions.push_back(create_structured_dimension<T>(
81 static_cast<uint64_t>(data.size()),
82 target_modality));
83 } else {
84 append_structured_to_existing(std::move(data));
85 }
86 }
87
88 /**
89 * @brief Insert data from span (copy operation)
90 * @tparam T Element type
91 * @param data_span Source span
92 * @param target_modality Semantic interpretation
93 */
94 template <typename T>
95 void insert_from_span(std::span<const T> data_span, DataModality target_modality)
96 {
97 std::vector<T> data_copy(data_span.begin(), data_span.end());
98
99 if constexpr (GlmType<T>) {
100 insert_structured(std::move(data_copy), target_modality);
101 } else {
102 insert_scalar(std::move(data_copy), target_modality);
103 }
104 }
105
106 /**
107 * @brief Convert and insert from different type
108 * @tparam From Source type
109 * @tparam To Target type
110 * @param source Source data
111 * @param target_modality Semantic interpretation
112 */
113 template <typename From, typename To>
114 void insert_converted(const std::vector<From>& source, DataModality target_modality)
115 {
116 std::vector<To> converted;
117 auto source_span = std::span<From>(
118 const_cast<From*>(source.data()), source.size());
119 convert_data<From, To>(source_span, converted);
120
121 if constexpr (GlmType<To>) {
122 insert_structured(std::move(converted), target_modality);
123 } else {
124 insert_scalar(std::move(converted), target_modality);
125 }
126 }
127
128 /**
129 * @brief Reserve space without initialization
130 * @param element_count Number of elements
131 * @param target_modality Determines storage type
132 */
133 void reserve_space(size_t element_count, DataModality target_modality)
134 {
135 if (is_structured_modality(target_modality)) {
136 switch (target_modality) {
137 case DataModality::VERTEX_POSITIONS_3D:
138 case DataModality::VERTEX_NORMALS_3D:
139 case DataModality::VERTEX_TANGENTS_3D:
140 case DataModality::VERTEX_COLORS_RGB:
141 m_variant = std::vector<glm::vec3>();
142 std::get<std::vector<glm::vec3>>(m_variant).reserve(element_count);
143 break;
144
145 case DataModality::TEXTURE_COORDS_2D:
146 m_variant = std::vector<glm::vec2>();
147 std::get<std::vector<glm::vec2>>(m_variant).reserve(element_count);
148 break;
149
150 case DataModality::VERTEX_COLORS_RGBA:
151 m_variant = std::vector<glm::vec4>();
152 std::get<std::vector<glm::vec4>>(m_variant).reserve(element_count);
153 break;
154
155 case DataModality::TRANSFORMATION_MATRIX:
156 m_variant = std::vector<glm::mat4>();
157 std::get<std::vector<glm::mat4>>(m_variant).reserve(element_count);
158 break;
159
160 default:
161 error<std::invalid_argument>(
162 Journal::Component::Kakshya,
163 Journal::Context::Runtime,
164 std::source_location::current(),
165 "Modality {} does not represent structured GLM data",
166 modality_to_string(target_modality));
167 }
168 } else {
169 m_variant = std::vector<double>();
170 std::get<std::vector<double>>(m_variant).reserve(element_count);
171 }
172
173 m_modality = target_modality;
174 }
175
176 /**
177 * @brief Clear all data while preserving modality
178 */
180 {
181 std::visit([](auto& vec) { vec.clear(); }, m_variant);
182 m_dimensions.clear();
183 }
184
185 [[nodiscard]] DataModality current_modality() const { return m_modality; }
186
187 [[nodiscard]] bool is_empty() const
188 {
189 return std::visit([](const auto& vec) { return vec.empty(); }, m_variant);
190 }
191
192private:
194 std::vector<DataDimension>& m_dimensions;
196
197 /**
198 * @brief Validate scalar insertion matches modality expectations
199 */
201 {
202 if (is_structured_modality(modality)) {
203 error<std::invalid_argument>(
204 Journal::Component::Kakshya,
205 Journal::Context::Runtime,
206 std::source_location::current(),
207 "Modality {} expects structured data (GLM types), not scalars. "
208 "Use insert_structured() or change modality.",
209 modality_to_string(modality));
210 }
211 }
212
213 /**
214 * @brief Validate structured insertion matches GLM component count
215 */
216 template <GlmType T>
218 {
219 constexpr size_t components = glm_component_count<T>();
220
221 bool valid = false;
222 switch (modality) {
223 case DataModality::VERTEX_POSITIONS_3D:
224 case DataModality::VERTEX_NORMALS_3D:
225 case DataModality::VERTEX_TANGENTS_3D:
226 case DataModality::VERTEX_COLORS_RGB:
227 valid = (components == 3);
228 break;
229
230 case DataModality::TEXTURE_COORDS_2D:
231 valid = (components == 2);
232 break;
233
234 case DataModality::VERTEX_COLORS_RGBA:
235 valid = (components == 4);
236 break;
237
238 case DataModality::TRANSFORMATION_MATRIX:
239 valid = (components == 16);
240 break;
241
242 default:
243 error<std::invalid_argument>(
244 Journal::Component::Kakshya,
245 Journal::Context::Runtime,
246 std::source_location::current(),
247 "Modality {} does not represent structured GLM data",
248 modality_to_string(modality));
249 }
250
251 if (!valid) {
252 error<std::invalid_argument>(
253 Journal::Component::Kakshya,
254 Journal::Context::Runtime,
255 std::source_location::current(),
256 "GLM type component count ({}) doesn't match modality {}. "
257 "Suggested type: {}",
258 components,
259 modality_to_string(modality),
260 suggest_glm_type_for_modality(modality));
261 }
262 }
263
264 /**
265 * @brief Create dimension descriptor for structured data
266 */
267 template <GlmType T>
268 [[nodiscard]] DataDimension create_structured_dimension(uint64_t element_count,
269 DataModality modality) const
270 {
271 switch (modality) {
272 case DataModality::VERTEX_POSITIONS_3D:
273 return DataDimension::vertex_positions(element_count);
274
275 case DataModality::VERTEX_NORMALS_3D:
276 return DataDimension::vertex_normals(element_count);
277
278 case DataModality::TEXTURE_COORDS_2D:
279 return DataDimension::texture_coords(element_count);
280
281 case DataModality::VERTEX_COLORS_RGB:
282 return DataDimension::vertex_colors(element_count, false);
283
284 case DataModality::VERTEX_COLORS_RGBA:
285 return DataDimension::vertex_colors(element_count, true);
286
287 case DataModality::TRANSFORMATION_MATRIX:
288 case DataModality::VERTEX_TANGENTS_3D:
289 default: {
290 constexpr size_t components = glm_component_count<T>();
291 return DataDimension::grouped(
292 modality_to_dimension_name(modality),
293 element_count,
294 static_cast<uint8_t>(components),
295 modality_to_role(modality));
296 }
297 }
298 }
299
300 /**
301 * @brief Append scalar data to existing storage
302 */
303 template <typename T>
304 void append_to_existing(std::vector<T> new_data)
305 {
306 std::visit([&](auto& existing_vec) {
307 using ExistingType = typename std::decay_t<decltype(existing_vec)>::value_type;
308
309 if constexpr (std::is_same_v<ExistingType, T>) {
310 existing_vec.insert(existing_vec.end(),
311 new_data.begin(),
312 new_data.end());
313 } else if constexpr (std::is_arithmetic_v<ExistingType> && std::is_arithmetic_v<T>) {
314 for (const auto& val : new_data) {
315 existing_vec.push_back(static_cast<ExistingType>(val));
316 }
317 } else {
318 error<std::invalid_argument>(
319 Journal::Component::Kakshya,
320 Journal::Context::Runtime,
321 std::source_location::current(),
322 "Cannot append: incompatible types in variant (existing: {}, new: {})",
323 typeid(ExistingType).name(),
324 typeid(T).name());
325 }
326 },
327 m_variant);
328
329 if (!m_dimensions.empty()) {
330 m_dimensions[0].size = std::visit(
331 [](const auto& vec) { return static_cast<uint64_t>(vec.size()); },
332 m_variant);
333 }
334 }
335
336 /**
337 * @brief Append structured data to existing storage
338 */
339 template <GlmType T>
340 void append_structured_to_existing(std::vector<T> new_data)
341 {
342 if (!std::holds_alternative<std::vector<T>>(m_variant)) {
343 error<std::invalid_argument>(
344 Journal::Component::Kakshya,
345 Journal::Context::Runtime,
346 std::source_location::current(),
347 "Cannot append: existing variant doesn't hold matching GLM type ({})",
348 typeid(T).name());
349 }
350
351 auto& existing = std::get<std::vector<T>>(m_variant);
352 existing.insert(existing.end(), new_data.begin(), new_data.end());
353
354 if (!m_dimensions.empty()) {
355 m_dimensions[0].size = existing.size();
356 }
357 }
358
359 /**
360 * @brief Convert modality to appropriate dimension name
361 */
362 static std::string modality_to_dimension_name(DataModality modality)
363 {
364 switch (modality) {
365 case DataModality::VERTEX_POSITIONS_3D:
366 return "positions";
367 case DataModality::VERTEX_NORMALS_3D:
368 return "normals";
369 case DataModality::VERTEX_TANGENTS_3D:
370 return "tangents";
371 case DataModality::VERTEX_COLORS_RGB:
372 case DataModality::VERTEX_COLORS_RGBA:
373 return "colors";
374 case DataModality::TEXTURE_COORDS_2D:
375 return "texcoords";
376 case DataModality::TRANSFORMATION_MATRIX:
377 return "transforms";
378 case DataModality::AUDIO_1D:
379 return "samples";
380 case DataModality::AUDIO_MULTICHANNEL:
381 return "channels";
382 default:
383 return "data";
384 }
385 }
386
387 /**
388 * @brief Convert modality to dimension role
389 */
391 {
392 switch (modality) {
393 case DataModality::AUDIO_1D:
394 case DataModality::AUDIO_MULTICHANNEL:
395 return DataDimension::Role::TIME;
396
397 case DataModality::VERTEX_POSITIONS_3D:
398 case DataModality::VERTEX_NORMALS_3D:
399 case DataModality::VERTEX_TANGENTS_3D:
400 case DataModality::TEXTURE_COORDS_2D:
401 return DataDimension::Role::UV;
402
403 case DataModality::VERTEX_COLORS_RGB:
404 case DataModality::VERTEX_COLORS_RGBA:
405 return DataDimension::Role::CHANNEL;
406
407 default:
408 return DataDimension::Role::CUSTOM;
409 }
410 }
411
412 /**
413 * @brief Suggest appropriate GLM type for a modality
414 */
415 static std::string_view suggest_glm_type_for_modality(DataModality modality)
416 {
417 switch (modality) {
418 case DataModality::VERTEX_POSITIONS_3D:
419 case DataModality::VERTEX_NORMALS_3D:
420 case DataModality::VERTEX_TANGENTS_3D:
421 case DataModality::VERTEX_COLORS_RGB:
422 return "glm::vec3";
423
424 case DataModality::TEXTURE_COORDS_2D:
425 return "glm::vec2";
426
427 case DataModality::VERTEX_COLORS_RGBA:
428 return "glm::vec4";
429
430 case DataModality::TRANSFORMATION_MATRIX:
431 return "glm::mat4";
432
433 default:
434 return "unknown";
435 }
436 }
437};
438
439} // namespace MayaFlux::Kakshya
Cycle Behavior: The for_cycles(N) configuration controls how many times the capture operation execute...
void append_structured_to_existing(std::vector< T > new_data)
Append structured data to existing storage.
void insert_scalar(std::vector< T > data, DataModality target_modality, bool replace_existing=true)
Insert scalar array data.
void validate_structured_insertion(DataModality modality) const
Validate structured insertion matches GLM component count.
static std::string modality_to_dimension_name(DataModality modality)
Convert modality to appropriate dimension name.
void reserve_space(size_t element_count, DataModality target_modality)
Reserve space without initialization.
std::vector< DataDimension > & m_dimensions
DataInsertion(DataVariant &variant, std::vector< DataDimension > &dimensions, DataModality &modality)
void insert_structured(std::vector< T > data, DataModality target_modality, bool replace_existing=true)
Insert structured GLM data with automatic dimension setup.
void validate_scalar_insertion(DataModality modality) const
Validate scalar insertion matches modality expectations.
void append_to_existing(std::vector< T > new_data)
Append scalar data to existing storage.
static std::string_view suggest_glm_type_for_modality(DataModality modality)
Suggest appropriate GLM type for a modality.
DataModality current_modality() const
DataDimension create_structured_dimension(uint64_t element_count, DataModality modality) const
Create dimension descriptor for structured data.
void insert_converted(const std::vector< From > &source, DataModality target_modality)
Convert and insert from different type.
static DataDimension::Role modality_to_role(DataModality modality)
Convert modality to dimension role.
void clear_data()
Clear all data while preserving modality.
void insert_from_span(std::span< const T > data_span, DataModality target_modality)
Insert data from span (copy operation)
Type-erased writer for NDData with semantic construction.
std::variant< std::vector< double >, std::vector< float >, std::vector< uint8_t >, std::vector< uint16_t >, std::vector< uint32_t >, std::vector< std::complex< float > >, std::vector< std::complex< double > >, std::vector< glm::vec2 >, std::vector< glm::vec3 >, std::vector< glm::vec4 >, std::vector< glm::mat4 > > DataVariant
Multi-type data storage for different precision needs.
Definition NDData.hpp:76
DataModality
Data modality types for cross-modal analysis.
Definition NDData.hpp:81
bool is_structured_modality(DataModality modality)
Check if a modality represents structured data (vectors, matrices).
Definition NDData.hpp:115
std::string_view modality_to_string(DataModality modality)
Convert DataModality enum to string representation.
Definition NDData.cpp:83
Role
Semantic role of the dimension.
Definition NDData.hpp:149
Minimal dimension descriptor focusing on structure only.
Definition NDData.hpp:142