MayaFlux 0.1.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 // Create grouped dimension
82 m_dimensions.clear();
83 m_dimensions.push_back(create_structured_dimension<T>(
84 static_cast<uint64_t>(data.size()),
85 target_modality));
86 } else {
87 append_structured_to_existing(std::move(data));
88 }
89 }
90
91 /**
92 * @brief Insert data from span (copy operation)
93 * @tparam T Element type
94 * @param data_span Source span
95 * @param target_modality Semantic interpretation
96 */
97 template <typename T>
98 void insert_from_span(std::span<const T> data_span, DataModality target_modality)
99 {
100 std::vector<T> data_copy(data_span.begin(), data_span.end());
101
102 if constexpr (GlmType<T>) {
103 insert_structured(std::move(data_copy), target_modality);
104 } else {
105 insert_scalar(std::move(data_copy), target_modality);
106 }
107 }
108
109 /**
110 * @brief Convert and insert from different type
111 * @tparam From Source type
112 * @tparam To Target type
113 * @param source Source data
114 * @param target_modality Semantic interpretation
115 */
116 template <typename From, typename To>
117 void insert_converted(const std::vector<From>& source, DataModality target_modality)
118 {
119 std::vector<To> converted;
120 converted.reserve(source.size());
121
122 if constexpr (std::is_arithmetic_v<From> && std::is_arithmetic_v<To>) {
123 std::ranges::transform(source, std::back_inserter(converted),
124 [](From val) { return static_cast<To>(val); });
125 } else if constexpr (std::is_same_v<From, std::complex<float>> || std::is_same_v<From, std::complex<double>>) {
126 std::ranges::transform(source, std::back_inserter(converted),
127 [](From val) { return static_cast<To>(std::abs(val)); });
128 } else {
129 error<std::invalid_argument>(
130 Journal::Component::Kakshya,
131 Journal::Context::Runtime,
132 std::source_location::current(),
133 "Unsupported conversion from {} to {}",
134 typeid(From).name(),
135 typeid(To).name());
136 }
137
138 insert_scalar(std::move(converted), target_modality);
139 }
140
141 /**
142 * @brief Reserve space without initialization
143 * @param element_count Number of elements
144 * @param target_modality Determines storage type
145 */
146 void reserve_space(size_t element_count, DataModality target_modality)
147 {
148 // Determine appropriate type based on modality
149 if (is_structured_modality(target_modality)) {
150 switch (target_modality) {
151 case DataModality::VERTEX_POSITIONS_3D:
152 case DataModality::VERTEX_NORMALS_3D:
153 case DataModality::VERTEX_TANGENTS_3D:
154 case DataModality::VERTEX_COLORS_RGB:
155 m_variant = std::vector<glm::vec3>();
156 std::get<std::vector<glm::vec3>>(m_variant).reserve(element_count);
157 break;
158
159 case DataModality::TEXTURE_COORDS_2D:
160 m_variant = std::vector<glm::vec2>();
161 std::get<std::vector<glm::vec2>>(m_variant).reserve(element_count);
162 break;
163
164 case DataModality::VERTEX_COLORS_RGBA:
165 m_variant = std::vector<glm::vec4>();
166 std::get<std::vector<glm::vec4>>(m_variant).reserve(element_count);
167 break;
168
169 case DataModality::TRANSFORMATION_MATRIX:
170 m_variant = std::vector<glm::mat4>();
171 std::get<std::vector<glm::mat4>>(m_variant).reserve(element_count);
172 break;
173
174 default:
175 error<std::invalid_argument>(
176 Journal::Component::Kakshya,
177 Journal::Context::Runtime,
178 std::source_location::current(),
179 "Modality {} does not represent structured GLM data",
180 modality_to_string(target_modality));
181 }
182 } else {
183 // Default to double for scalar modalities
184 m_variant = std::vector<double>();
185 std::get<std::vector<double>>(m_variant).reserve(element_count);
186 }
187
188 m_modality = target_modality;
189 }
190
191 /**
192 * @brief Clear all data while preserving modality
193 */
195 {
196 std::visit([](auto& vec) { vec.clear(); }, m_variant);
197 m_dimensions.clear();
198 }
199
200 [[nodiscard]] DataModality current_modality() const { return m_modality; }
201
202 [[nodiscard]] bool is_empty() const
203 {
204 return std::visit([](const auto& vec) { return vec.empty(); }, m_variant);
205 }
206
207private:
209 std::vector<DataDimension>& m_dimensions;
211
212 /**
213 * @brief Validate scalar insertion matches modality expectations
214 */
216 {
217 if (is_structured_modality(modality)) {
218 error<std::invalid_argument>(
219 Journal::Component::Kakshya,
220 Journal::Context::Runtime,
221 std::source_location::current(),
222 "Modality {} expects structured data (GLM types), not scalars. "
223 "Use insert_structured() or change modality.",
224 modality_to_string(modality));
225 }
226 }
227
228 /**
229 * @brief Validate structured insertion matches GLM component count
230 */
231 template <GlmType T>
233 {
234 constexpr size_t components = glm_component_count<T>();
235
236 bool valid = false;
237 switch (modality) {
238 case DataModality::VERTEX_POSITIONS_3D:
239 case DataModality::VERTEX_NORMALS_3D:
240 case DataModality::VERTEX_TANGENTS_3D:
241 case DataModality::VERTEX_COLORS_RGB:
242 valid = (components == 3);
243 break;
244
245 case DataModality::TEXTURE_COORDS_2D:
246 valid = (components == 2);
247 break;
248
249 case DataModality::VERTEX_COLORS_RGBA:
250 valid = (components == 4);
251 break;
252
253 case DataModality::TRANSFORMATION_MATRIX:
254 valid = (components == 16);
255 break;
256
257 default:
258 error<std::invalid_argument>(
259 Journal::Component::Kakshya,
260 Journal::Context::Runtime,
261 std::source_location::current(),
262 "Modality {} does not represent structured GLM data",
263 modality_to_string(modality));
264 }
265
266 if (!valid) {
267 error<std::invalid_argument>(
268 Journal::Component::Kakshya,
269 Journal::Context::Runtime,
270 std::source_location::current(),
271 "GLM type component count ({}) doesn't match modality {}. "
272 "Suggested type: {}",
273 components,
274 modality_to_string(modality),
275 suggest_glm_type_for_modality(modality));
276 }
277 }
278
279 /**
280 * @brief Create dimension descriptor for structured data
281 */
282 template <GlmType T>
283 [[nodiscard]] DataDimension create_structured_dimension(uint64_t element_count,
284 DataModality modality) const
285 {
286 // Use the static factory methods where available
287 switch (modality) {
288 case DataModality::VERTEX_POSITIONS_3D:
289 return DataDimension::vertex_positions(element_count);
290
291 case DataModality::VERTEX_NORMALS_3D:
292 return DataDimension::vertex_normals(element_count);
293
294 case DataModality::TEXTURE_COORDS_2D:
295 return DataDimension::texture_coords(element_count);
296
297 case DataModality::VERTEX_COLORS_RGB:
298 return DataDimension::vertex_colors(element_count, false);
299
300 case DataModality::VERTEX_COLORS_RGBA:
301 return DataDimension::vertex_colors(element_count, true);
302
303 case DataModality::TRANSFORMATION_MATRIX:
304 case DataModality::VERTEX_TANGENTS_3D:
305 default: {
306 // Use grouped factory for other structured types
307 constexpr size_t components = glm_component_count<T>();
308 return DataDimension::grouped(
309 modality_to_dimension_name(modality),
310 element_count,
311 static_cast<uint8_t>(components),
312 modality_to_role(modality));
313 }
314 }
315 }
316
317 /**
318 * @brief Append scalar data to existing storage
319 */
320 template <typename T>
321 void append_to_existing(std::vector<T> new_data)
322 {
323 std::visit([&](auto& existing_vec) {
324 using ExistingType = typename std::decay_t<decltype(existing_vec)>::value_type;
325
326 if constexpr (std::is_same_v<ExistingType, T>) {
327 existing_vec.insert(existing_vec.end(),
328 new_data.begin(),
329 new_data.end());
330 } else if constexpr (std::is_arithmetic_v<ExistingType> && std::is_arithmetic_v<T>) {
331 // Convert and append
332 for (const auto& val : new_data) {
333 existing_vec.push_back(static_cast<ExistingType>(val));
334 }
335 } else {
336 error<std::invalid_argument>(
337 Journal::Component::Kakshya,
338 Journal::Context::Runtime,
339 std::source_location::current(),
340 "Cannot append: incompatible types in variant (existing: {}, new: {})",
341 typeid(ExistingType).name(),
342 typeid(T).name());
343 }
344 },
345 m_variant);
346
347 // Update dimension size
348 if (!m_dimensions.empty()) {
349 m_dimensions[0].size = std::visit(
350 [](const auto& vec) { return static_cast<uint64_t>(vec.size()); },
351 m_variant);
352 }
353 }
354
355 /**
356 * @brief Append structured data to existing storage
357 */
358 template <GlmType T>
359 void append_structured_to_existing(std::vector<T> new_data)
360 {
361 if (!std::holds_alternative<std::vector<T>>(m_variant)) {
362 error<std::invalid_argument>(
363 Journal::Component::Kakshya,
364 Journal::Context::Runtime,
365 std::source_location::current(),
366 "Cannot append: existing variant doesn't hold matching GLM type ({})",
367 typeid(T).name());
368 }
369
370 auto& existing = std::get<std::vector<T>>(m_variant);
371 existing.insert(existing.end(), new_data.begin(), new_data.end());
372
373 // Update dimension size
374 if (!m_dimensions.empty()) {
375 m_dimensions[0].size = existing.size();
376 }
377 }
378
379 /**
380 * @brief Convert modality to appropriate dimension name
381 */
382 static std::string modality_to_dimension_name(DataModality modality)
383 {
384 switch (modality) {
385 case DataModality::VERTEX_POSITIONS_3D:
386 return "positions";
387 case DataModality::VERTEX_NORMALS_3D:
388 return "normals";
389 case DataModality::VERTEX_TANGENTS_3D:
390 return "tangents";
391 case DataModality::VERTEX_COLORS_RGB:
392 case DataModality::VERTEX_COLORS_RGBA:
393 return "colors";
394 case DataModality::TEXTURE_COORDS_2D:
395 return "texcoords";
396 case DataModality::TRANSFORMATION_MATRIX:
397 return "transforms";
398 case DataModality::AUDIO_1D:
399 return "samples";
400 case DataModality::AUDIO_MULTICHANNEL:
401 return "channels";
402 default:
403 return "data";
404 }
405 }
406
407 /**
408 * @brief Convert modality to dimension role
409 */
411 {
412 switch (modality) {
413 case DataModality::AUDIO_1D:
414 case DataModality::AUDIO_MULTICHANNEL:
415 return DataDimension::Role::TIME;
416
417 case DataModality::VERTEX_POSITIONS_3D:
418 case DataModality::VERTEX_NORMALS_3D:
419 case DataModality::VERTEX_TANGENTS_3D:
420 case DataModality::TEXTURE_COORDS_2D:
421 return DataDimension::Role::UV;
422
423 case DataModality::VERTEX_COLORS_RGB:
424 case DataModality::VERTEX_COLORS_RGBA:
425 return DataDimension::Role::CHANNEL;
426
427 default:
428 return DataDimension::Role::CUSTOM;
429 }
430 }
431
432 /**
433 * @brief Suggest appropriate GLM type for a modality
434 */
435 static std::string_view suggest_glm_type_for_modality(DataModality modality)
436 {
437 switch (modality) {
438 case DataModality::VERTEX_POSITIONS_3D:
439 case DataModality::VERTEX_NORMALS_3D:
440 case DataModality::VERTEX_TANGENTS_3D:
441 case DataModality::VERTEX_COLORS_RGB:
442 return "glm::vec3";
443
444 case DataModality::TEXTURE_COORDS_2D:
445 return "glm::vec2";
446
447 case DataModality::VERTEX_COLORS_RGBA:
448 return "glm::vec4";
449
450 case DataModality::TRANSFORMATION_MATRIX:
451 return "glm::mat4";
452
453 default:
454 return "unknown";
455 }
456 }
457};
458
459} // 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:80
Role
Semantic role of the dimension.
Definition NDData.hpp:145
Minimal dimension descriptor focusing on structure only.
Definition NDData.hpp:138