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