MayaFlux 0.5.0
Digital-First Multimedia Processing Framework
Loading...
Searching...
No Matches
DataUtils.hpp
Go to the documentation of this file.
1#pragma once
2
4
6
7#include <glm/gtc/type_ptr.hpp>
8
9namespace MayaFlux::Kakshya {
10
11/**
12 * @enum ComplexConversionStrategy
13 * @brief Strategy for converting complex numbers to real values
14 */
15enum class ComplexConversionStrategy : uint8_t {
16 MAGNITUDE, ///< |z| = sqrt(real² + imag²)
17 REAL_PART, ///< z.real()
18 IMAG_PART, ///< z.imag()
19 SQUARED_MAGNITUDE ///< |z|² = real² + imag²
20};
21
22template <typename From, typename To, typename Enable = void>
24 static std::span<To> convert(std::span<From> /*source*/,
25 std::vector<To>& /*storage*/,
27 {
28 static_assert(always_false_v<From>, "No conversion available for these types");
29 return {};
30 }
31};
32
33// === Specialization: Identity Conversion ===
34
35template <typename T>
36struct DataConverter<T, T> {
37 static std::span<T> convert(std::span<T> source,
38 std::vector<T>&,
40 {
41 return source;
42 }
43};
44
45// === Specialization: Arithmetic to Arithmetic (excluding GLM) ===
46
47template <typename From, typename To>
49 From, To,
50 std::enable_if_t<
51 ArithmeticData<From> && ArithmeticData<To> && !std::is_same_v<From, To> && !GlmType<From> && !GlmType<To>>> {
52 static std::span<To> convert(
53 std::span<From> source,
54 std::vector<To>& storage,
56 {
57 storage.resize(source.size());
58 std::transform(
59 source.begin(), source.end(), storage.begin(),
60 [](From val) { return static_cast<To>(val); });
61
62 return std::span<To>(storage.data(), storage.size());
63 }
64};
65
66// === Specialization: Complex to Arithmetic ===
67
68template <typename From, typename To>
70 From, To,
71 std::enable_if_t<
72 ComplexData<From> && ArithmeticData<To> && !GlmType<From> && !GlmType<To>>> {
73 static std::span<To> convert(
74 std::span<From> source,
75 std::vector<To>& storage,
77 {
78 storage.resize(source.size());
79
80 for (size_t i = 0; i < source.size(); ++i) {
81 switch (strategy) {
83 storage[i] = static_cast<To>(std::abs(source[i]));
84 break;
86 storage[i] = static_cast<To>(source[i].real());
87 break;
89 storage[i] = static_cast<To>(source[i].imag());
90 break;
92 storage[i] = static_cast<To>(std::norm(source[i]));
93 break;
94 }
95 }
96
97 return std::span<To>(storage.data(), storage.size());
98 }
99};
100
101// === Specialization: Arithmetic to Complex ===
102
103template <typename From, typename To>
105 From, To,
106 std::enable_if_t<
107 ArithmeticData<From> && ComplexData<To> && !GlmType<From> && !GlmType<To>>> {
108 static std::span<To> convert(
109 std::span<From> source,
110 std::vector<To>& storage,
112 {
113 using ComplexValueType = typename To::value_type;
114 storage.resize(source.size());
115
116 for (size_t i = 0; i < source.size(); ++i) {
117 storage[i] = To(static_cast<ComplexValueType>(source[i]), ComplexValueType { 0 });
118 }
119
120 return std::span<To>(storage.data(), storage.size());
121 }
122};
123
124// === Specialization: GLM to Arithmetic (Flattening) ===
125
126template <typename From, typename To>
128 From, To,
129 std::enable_if_t<
130 GlmType<From> && ArithmeticData<To> && !GlmType<To>>> {
131 static std::span<To> convert(
132 std::span<From> source,
133 std::vector<To>& storage,
135 {
136 constexpr size_t components = glm_component_count<From>();
137 using ComponentType = glm_component_type<From>;
138
139 storage.resize(source.size() * components);
140
141 size_t out_idx = 0;
142 for (const auto& elem : source) {
143 const ComponentType* ptr = glm::value_ptr(elem);
144 for (size_t c = 0; c < components; ++c) {
145 storage[out_idx++] = static_cast<To>(ptr[c]);
146 }
147 }
148
149 return std::span<To>(storage.data(), storage.size());
150 }
151};
152
153// === Specialization: Arithmetic to GLM (Structuring) ===
154
155template <typename From, typename To>
157 From, To,
158 std::enable_if_t<
159 ArithmeticData<From> && GlmType<To> && !GlmType<From>>> {
160 static std::span<To> convert(
161 std::span<From> source,
162 std::vector<To>& storage,
164 {
165 constexpr size_t components = glm_component_count<To>();
166 using ComponentType = glm_component_type<To>;
167
168 if (source.size() % components != 0) {
169 error<std::invalid_argument>(
172 std::source_location::current(),
173 "Source size ({}) must be multiple of GLM component count ({})",
174 source.size(),
175 components);
176 }
177
178 size_t element_count = source.size() / components;
179 storage.resize(element_count);
180
181 for (size_t i = 0; i < element_count; ++i) {
182 ComponentType temp[components];
183 for (size_t c = 0; c < components; ++c) {
184 temp[c] = static_cast<ComponentType>(source[i * components + c]);
185 }
186
187 if constexpr (GlmVec2Type<To>) {
188 storage[i] = To(temp[0], temp[1]);
189 } else if constexpr (GlmVec3Type<To>) {
190 storage[i] = To(temp[0], temp[1], temp[2]);
191 } else if constexpr (GlmVec4Type<To>) {
192 storage[i] = To(temp[0], temp[1], temp[2], temp[3]);
193 } else if constexpr (GlmMatrixType<To>) {
194 storage[i] = glm::make_mat4(temp);
195 }
196 }
197
198 return std::span<To>(storage.data(), storage.size());
199 }
200};
201
202// === Specialization: GLM to GLM (same component count) ===
203
204template <typename From, typename To>
206 From, To,
207 std::enable_if_t<
208 GlmType<From> && GlmType<To> && !std::is_same_v<From, To> && (glm_component_count<From>() == glm_component_count<To>())>> {
209 static std::span<To> convert(
210 std::span<From> source,
211 std::vector<To>& storage,
213 {
214 using FromComponent = glm_component_type<From>;
215 using ToComponent = glm_component_type<To>;
216 constexpr size_t components = glm_component_count<From>();
217
218 storage.resize(source.size());
219
220 for (size_t i = 0; i < source.size(); ++i) {
221 const FromComponent* src_ptr = glm::value_ptr(source[i]);
222 ToComponent temp[components];
223
224 for (size_t c = 0; c < components; ++c) {
225 temp[c] = static_cast<ToComponent>(src_ptr[c]);
226 }
227
228 if constexpr (GlmVec2Type<To>) {
229 storage[i] = To(temp[0], temp[1]);
230 } else if constexpr (GlmVec3Type<To>) {
231 storage[i] = To(temp[0], temp[1], temp[2]);
232 } else if constexpr (GlmVec4Type<To>) {
233 storage[i] = To(temp[0], temp[1], temp[2], temp[3]);
234 } else if constexpr (GlmMatrixType<To>) {
235 storage[i] = glm::make_mat4(temp);
236 }
237 }
238
239 return std::span<To>(storage.data(), storage.size());
240 }
241};
242
243// === Specialization: Complex -> Complex ===
244template <typename From, typename To>
246 From, To,
247 std::enable_if_t<
248 ComplexData<From> && ComplexData<To> && !GlmType<From> && !GlmType<To> && !std::is_same_v<From, To>>> {
249 static std::span<To> convert(
250 std::span<From> source,
251 std::vector<To>& storage,
253 {
254 using FromValue = typename From::value_type;
255 using ToValue = typename To::value_type;
256
257 storage.resize(source.size());
258 for (size_t i = 0; i < source.size(); ++i) {
259 const auto r = static_cast<FromValue>(source[i].real());
260 const auto im = static_cast<FromValue>(source[i].imag());
261 storage[i] = To(static_cast<ToValue>(r), static_cast<ToValue>(im));
262 }
263
264 return std::span<To>(storage.data(), storage.size());
265 }
266};
267
268/**
269 * @brief Calculate the total number of elements in an N-dimensional container.
270 * @param dimensions Dimension descriptors.
271 * @return Product of all dimension sizes.
272 */
273uint64_t calculate_total_elements(const std::vector<DataDimension>& dimensions);
274
275/**
276 * @brief Calculate the frame size (number of elements per frame) for a set of dimensions.
277 * @param dimensions Dimension descriptors.
278 * @return Frame size (product of all but the first dimension).
279 */
280uint64_t calculate_frame_size(const std::vector<DataDimension>& dimensions);
281
282/**
283 * @brief Return the native element type of a DataVariant as a type_index.
284 *
285 * Returns typeid(E) where E is the value_type of the active alternative,
286 * consistent with NDDataContainer::value_element_type() and
287 * FrameView::element_type().
288 *
289 * @param data Source variant.
290 * @return std::type_index of the element type (e.g. typeid(uint8_t)).
291 */
292[[nodiscard]] std::type_index get_variant_element_type(const DataVariant& data);
293
294/**
295 * @brief Extract a single frame of data from a span.
296 * @tparam T Data type.
297 * @param data Source data span.
298 * @param frame_index Index of the frame to extract.
299 * @param frame_size Number of elements per frame.
300 * @return Span containing the frame data.
301 */
302template <ProcessableData T>
303constexpr std::span<T> extract_frame(std::span<T> data, uint64_t frame_index, uint64_t frame_size) noexcept
304{
305 uint64_t start = frame_index * frame_size;
306 uint64_t end = std::min(static_cast<uint64_t>(start + frame_size),
307 static_cast<uint64_t>(data.size()));
308
309 if (start >= data.size()) {
310 return {};
311 }
312
313 return data.subspan(start, end - start);
314}
315
316/**
317 * @brief Extract a single frame from planar data (returns interleaved).
318 * @tparam T Data type.
319 * @param channel_spans Vector of spans, one per channel.
320 * @param frame_index Index of the frame to extract.
321 * @param output_buffer Buffer to store interleaved frame data.
322 * @return Span containing the interleaved frame data.
323 */
324template <ProcessableData T>
325std::span<T> extract_frame(
326 const std::vector<std::span<T>>& channel_spans,
327 uint64_t frame_index,
328 std::vector<T>& output_buffer) noexcept
329{
330 output_buffer.clear();
331 output_buffer.reserve(channel_spans.size());
332
333 for (const auto& channel_span : channel_spans) {
334 if (frame_index < channel_span.size()) {
335 output_buffer.push_back(channel_span[frame_index]);
336 } else {
337 output_buffer.push_back(T { 0 });
338 }
339 }
340
341 return std::span<T>(output_buffer.data(), output_buffer.size());
342}
343
344/**
345 * @brief Convert a span of one data type to another (with type conversion).
346 * @tparam From Source type.
347 * @tparam To Destination type.
348 * @param source Source data span.
349 * @param dest Destination data span.
350 * @return Span of converted data.
351 */
352template <typename From, typename To>
353std::span<To> convert_data(std::span<From> source,
354 std::vector<To>& storage,
356{
357 return DataConverter<From, To>::convert(source, storage, strategy);
358}
359
360/**
361 * @brief Legacy interface - redirects to convert_data
362 */
363template <typename From, typename To>
364 requires(ComplexData<From> && ArithmeticData<To>)
365void convert_complex(std::span<From> source,
366 std::span<To> destination,
368{
369 std::vector<To> temp_storage;
370 auto result = convert_data(source, temp_storage, strategy);
371 std::copy_n(result.begin(), std::min(result.size(), destination.size()), destination.begin());
372}
373
374/**
375 * @brief Get const span from DataVariant without conversion (zero-copy for matching types)
376 * @tparam T Data type (must match DataVariant contents)
377 * @param variant DataVariant to extract from
378 * @return Const span of type T
379 * @throws std::runtime_error if type doesn't match
380 */
381template <ProcessableData T>
382std::span<T> convert_variant(DataVariant& variant,
384{
385 if (std::holds_alternative<std::vector<T>>(variant)) {
386 auto& vec = std::get<std::vector<T>>(variant);
387 return std::span<T>(vec.data(), vec.size());
388 }
389
390 return std::visit([&variant, strategy](auto& data) -> std::span<T> {
391 using ValueType = typename std::decay_t<decltype(data)>::value_type;
392
393 if constexpr (is_convertible_data_v<ValueType, T>) {
394 std::vector<T> new_storage;
395 auto source_span = std::span<ValueType>(data.data(), data.size());
396 auto result = convert_data(source_span, new_storage, strategy);
397
398 variant = std::move(new_storage);
399 auto& new_vec = std::get<std::vector<T>>(variant);
400 return std::span<T>(new_vec.data(), new_vec.size());
401 } else {
402 error<std::invalid_argument>(
405 std::source_location::current(),
406 "No conversion available from {} to {}",
407 typeid(ValueType).name(),
408 typeid(T).name());
409 }
410 },
411 variant);
412}
413
414template <ProcessableData T>
415std::span<T> convert_variant(const DataVariant& variant,
417{
418 return convert_variant<T>(const_cast<DataVariant&>(variant), strategy);
419}
420
421template <ProcessableData T>
422std::vector<std::span<T>> convert_variants(
423 const std::vector<DataVariant>& variants,
425{
426 std::vector<std::span<T>> result;
427 result.reserve(variants.size());
428
429 for (const auto& i : variants) {
430 result.push_back(convert_variant<T>(const_cast<DataVariant&>(i), strategy));
431 }
432 return result;
433}
434
435/**
436 * @brief Concept-based data extraction with type conversion
437 * @tparam T Target type (must satisfy ProcessableData)
438 * @param variant Source DataVariant (may be modified for conversion)
439 * @return Span of converted data
440 *
441 * Performance advantage: Eliminates runtime type dispatch for supported types
442 * Uses constexpr branching for compile-time optimization
443 */
444template <ProcessableData From, ProcessableData To>
445std::span<To> extract_data(std::span<const From> source,
446 std::vector<To>& destination,
448{
449 const size_t total_bytes = source.size() * sizeof(From);
450 const size_t required_elements = (total_bytes + sizeof(To) - 1) / sizeof(To);
451 destination.resize(required_elements);
452
453 if constexpr (std::is_same_v<From, To>) {
454 destination.resize(source.size());
455 std::memcpy(destination.data(), source.data(), total_bytes);
456 return std::span<To>(destination.data(), source.size());
457 } else if constexpr (std::is_trivially_copyable_v<From> && std::is_trivially_copyable_v<To> && (sizeof(From) == sizeof(To))) {
458 // Bitwise reinterpretation allowed (e.g. int32_t <-> float)
459 std::memcpy(destination.data(), source.data(), total_bytes);
460 return std::span<To>(destination.data(), source.size());
461 } else {
462 // General case — use proper conversion
463 std::vector<From> temp(source.begin(), source.end());
464 auto converted = convert_data<From, To>(std::span<const From>(temp), strategy);
465 destination.assign(converted.begin(), converted.end());
466 return std::span<To>(destination.data(), destination.size());
467 }
468}
469
470/**
471 * @brief Get typed span from DataVariant using concepts
472 * @tparam T Data type (must satisfy ProcessableData)
473 * @param variant DataVariant to extract from
474 * @return Span of type T, or empty span if type doesn't match
475 */
476template <ProcessableData T>
477std::span<T> extract_from_variant(const DataVariant& variant,
478 std::vector<T>& storage,
480{
481 return std::visit([&storage, strategy](const auto& data) -> std::span<T> {
482 using ValueType = typename std::decay_t<decltype(data)>::value_type;
483
484 if constexpr (std::is_same_v<ValueType, T>) {
485 storage = data;
486 return std::span<T>(storage.data(), storage.size());
487 } else if constexpr (is_convertible_data_v<ValueType, T>) {
488 auto source_span = std::span<const ValueType>(data.data(), data.size());
489 std::vector<ValueType> temp_source(source_span.begin(), source_span.end());
490 auto temp_span = std::span<ValueType>(temp_source.data(), temp_source.size());
491 return convert_data(temp_span, storage, strategy);
492 } else {
493 error<std::invalid_argument>(
496 std::source_location::current(),
497 "No conversion available from {} to {}",
498 typeid(ValueType).name(),
499 typeid(T).name());
500 }
501 },
502 variant);
503}
504
505/**
506 * @brief Extract a value of type T from a DataVariant at a specific position.
507 * @tparam T Desired type.
508 * @param variant DataVariant to extract from.
509 * @param pos Position in the data.
510 * @return Optional value of type T.
511 */
512template <typename T>
513std::optional<T> extract_from_variant_at(const DataVariant& variant, uint64_t pos)
514{
515 return std::visit([pos](const auto& data) -> std::optional<T> {
516 using DataType = std::decay_t<decltype(data)>;
517 using ValueType = typename DataType::value_type;
518
519 if (pos >= data.size()) {
520 return std::nullopt;
521 }
522
523 if constexpr (std::is_same_v<ValueType, T>) {
524 return data[pos];
525 } else if constexpr (std::is_arithmetic_v<ValueType> && std::is_arithmetic_v<T>) {
526 return static_cast<T>(data[pos]);
527 } else if constexpr (std::is_same_v<ValueType, std::complex<float>> || std::is_same_v<ValueType, std::complex<double>>) {
528 if constexpr (std::is_arithmetic_v<T>) {
529 return static_cast<T>(std::abs(data[pos]));
530 } else {
531 return std::nullopt;
532 }
533 } else {
534 return std::nullopt;
535 }
536 },
537 variant);
538}
539
540/**
541 * @brief Safely copy data from a DataVariant to another DataVariant, handling type conversion.
542 * @param input Source DataVariant.
543 * @param output Destination DataVariant.
544 */
546
547/**
548 * @brief Safely copy data from a DataVariant to another DataVariant of a specific type.
549 * @tparam T Data type.
550 * @param input Source DataVariant.
551 * @param output Destination DataVariant.
552 */
553template <typename T>
555{
556 std::vector<T> temp_storage;
557 auto input_span = extract_from_variant<T>(input, temp_storage);
558 auto output_span = get_typed_data<T>(output);
559 std::copy_n(input_span.begin(), std::min(input_span.size(), output_span.size()),
560 output_span.begin());
561}
562
563/**
564 * @brief Convert variant to double span
565 * @param data Source DataVariant (may be modified for conversion)
566 * @param strategy Conversion strategy for complex numbers
567 * @return Span of double data
568 */
569inline std::span<double> convert_variant_to_double(DataVariant& data,
571{
572 return convert_variant<double>(data, strategy);
573}
574
575/**
576 * @brief Extract a DataVariant holding pixel data as a normalised float span.
577 *
578 * Normalisation factors:
579 * uint8_t -> divided by 255.0f
580 * uint16_t -> divided by 65535.0f
581 * float -> zero-copy span directly into the variant's storage
582 *
583 * Does not mutate the variant. Writes into @p storage only when conversion
584 * is required. Returns an empty span if the active alternative is not one
585 * of the three pixel types (double, complex, and GLM variants return empty).
586 *
587 * @param variant Source DataVariant.
588 * @param storage Caller-supplied buffer. Reuse across calls to avoid
589 * per-frame allocation. Untouched when float is active.
590 * @return Normalised float span. Points into @p storage for uint8/uint16,
591 * directly into the variant's internal storage for float.
592 */
593[[nodiscard]] MAYAFLUX_API std::span<const float> as_normalised_float(
594 const DataVariant& variant, std::vector<float>& storage);
595
596/**
597 * @brief Convert a normalised float span back to uint8_t pixels.
598 *
599 * Multiplies each value by 255 and clamps to [0, 255]. Output size must
600 * equal src.size(). Single-channel input with channels=1 writes one byte
601 * per pixel. Three or four channel input writes interleaved bytes.
602 *
603 * @param src Normalised float span, values in [0, 1].
604 * @param dst Output span, size must equal src.size().
605 */
606MAYAFLUX_API void denormalise_to_uint8(
607 std::span<const float> src,
608 std::span<uint8_t> dst);
609
610/**
611 * @brief Convert a normalised float span back to uint8_t, returning a new vector.
612 *
613 * @param src Normalised float span, values in [0, 1].
614 * @return uint8_t vector of the same length as src.
615 */
616[[nodiscard]] MAYAFLUX_API std::vector<uint8_t> denormalise_to_uint8(
617 std::span<const float> src);
618
619/**
620 * @brief Set a value in a metadata map (key-value).
621 * @param metadata Metadata map.
622 * @param key Key to set.
623 * @param value Value to set.
624 */
625void set_metadata_value(std::unordered_map<std::string, std::any>& metadata, const std::string& key, std::any value);
626
627/**
628 * @brief Get a value from a metadata map by key.
629 * @tparam T Expected type.
630 * @param metadata Metadata map.
631 * @param key Key to retrieve.
632 * @return Optional value if present and convertible.
633 */
634template <typename T>
635std::optional<T> get_metadata_value(const std::unordered_map<std::string, std::any>& metadata, const std::string& key)
636{
637 auto it = metadata.find(key);
638 if (it != metadata.end()) {
639 try {
640 return safe_any_cast<T>(it->second);
641 } catch (const std::bad_any_cast&) {
642 return std::nullopt;
643 }
644 }
645 return std::nullopt;
646}
647
648/**
649 * @brief Find the index of a dimension by its semantic role.
650 * @param dimensions Dimension descriptors.
651 * @param role Semantic role to search for.
652 * @return Index of the dimension, or -1 if not found.
653 */
654int find_dimension_by_role(const std::vector<DataDimension>& dimensions, DataDimension::Role role);
655
656/**
657 * @brief Detects data modality from dimension information
658 * @param dimensions Vector of data dimensions with role information
659 * @return Detected DataModality type
660 *
661 * Consolidates modality detection logic that was duplicated across analyzers.
662 * Uses dimension roles and count to determine appropriate processing approach.
663 */
664DataModality detect_data_modality(const std::vector<DataDimension>& dimensions);
665
666/**
667 * @brief Detect data modality from dimensions and source variant scalar type.
668 *
669 * Resolves ambiguous cases where dimension roles alone are insufficient,
670 * primarily the TIME-only case where decimal, integer, and complex types
671 * would otherwise all collapse to the same result.
672 *
673 * @param dimensions Vector of data dimensions with role information.
674 * @param source Original DataVariant used to produce the dimensions.
675 * @return Detected DataModality type.
676 */
678 const std::vector<DataDimension>& dimensions,
679 const DataVariant& source);
680
681/**
682 * @brief Detect data dimensions from a DataVariant
683 * @param data DataVariant to analyze
684 * @return Vector of DataDimension descriptors
685 *
686 * This function analyzes the structure of the provided DataVariant and extracts
687 * dimension information, including size, stride, and semantic roles.
688 */
689std::vector<Kakshya::DataDimension> detect_data_dimensions(const DataVariant& data);
690
691/**
692 * @brief Detect data dimensions from a vector of DataVariants
693 * @param variants Vector of DataVariants to analyze
694 * @return Vector of DataDimension descriptors
695 *
696 * This function analyzes the structure of the provided vector of DataVariants and extracts
697 * dimension information, including size, stride, and semantic roles.
698 *
699 * WARNING: This method makes naive assumptions about the data structure and may lead to incorrect interpretations.
700 * It is recommended to use more specific methods when dealing with known containers, regions, or segments.
701 * Use this function only when absolutely necessary and be aware of potential computational errors.
702 */
703std::vector<Kakshya::DataDimension> detect_data_dimensions(const std::vector<Kakshya::DataVariant>& variants);
704}
Core::GlobalInputConfig input
Definition Config.cpp:38
Eigen::MatrixXd storage
const uint8_t * ptr
float value
std::shared_ptr< Core::VKImage > output
@ Runtime
General runtime operations (default fallback)
@ Kakshya
Containers[Signalsource, Stream, File], Regions, DataProcessors.
void denormalise_to_uint8(std::span< const float > src, std::span< uint8_t > dst)
Convert a normalised float span back to uint8_t pixels.
Definition DataUtils.cpp:95
std::optional< T > extract_from_variant_at(const DataVariant &variant, uint64_t pos)
Extract a value of type T from a DataVariant at a specific position.
std::vector< DataDimension > detect_data_dimensions(const DataVariant &data)
Detect data dimensions from a DataVariant.
std::span< const float > as_normalised_float(const DataVariant &variant, std::vector< float > &storage)
Extract a DataVariant holding pixel data as a normalised float span.
Definition DataUtils.cpp:61
std::span< T > extract_from_variant(const DataVariant &variant, std::vector< T > &storage, ComplexConversionStrategy strategy=ComplexConversionStrategy::MAGNITUDE)
Get typed span from DataVariant using concepts.
uint64_t calculate_frame_size(const std::vector< DataDimension > &dimensions)
Calculate the frame size (number of elements per frame) for a set of dimensions.
Definition DataUtils.cpp:17
constexpr std::span< T > extract_frame(std::span< T > data, uint64_t frame_index, uint64_t frame_size) noexcept
Extract a single frame of data from a span.
std::span< To > extract_data(std::span< const From > source, std::vector< To > &destination, ComplexConversionStrategy strategy=ComplexConversionStrategy::MAGNITUDE)
Concept-based data extraction with type conversion.
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:102
std::span< double > convert_variant_to_double(DataVariant &data, ComplexConversionStrategy strategy=ComplexConversionStrategy::MAGNITUDE)
Convert variant to double span.
DataModality
Data modality types for cross-modal analysis.
Definition NDData.hpp:164
int find_dimension_by_role(const std::vector< DataDimension > &dimensions, DataDimension::Role role)
Find the index of a dimension by its semantic role.
void set_metadata_value(std::unordered_map< std::string, std::any > &metadata, const std::string &key, std::any value)
Set a value in a metadata map (key-value).
void convert_complex(std::span< From > source, std::span< To > destination, ComplexConversionStrategy strategy)
Legacy interface - redirects to convert_data.
DataModality detect_data_modality(const std::vector< DataDimension > &dimensions)
Detects data modality from dimension information.
void safe_copy_typed_variant(const DataVariant &input, DataVariant &output)
Safely copy data from a DataVariant to another DataVariant of a specific type.
std::type_index get_variant_element_type(const DataVariant &data)
Return the native element type of a DataVariant as a type_index.
Definition DataUtils.cpp:28
void safe_copy_data_variant(const DataVariant &input, DataVariant &output)
Safely copy data from a DataVariant to another DataVariant, handling type conversion.
Definition DataUtils.cpp:36
std::span< To > convert_data(std::span< From > source, std::vector< To > &storage, ComplexConversionStrategy strategy=ComplexConversionStrategy::MAGNITUDE)
Convert a span of one data type to another (with type conversion).
ComplexConversionStrategy
Strategy for converting complex numbers to real values.
Definition DataUtils.hpp:15
@ SQUARED_MAGNITUDE
|z|² = real² + imag²
@ MAGNITUDE
|z| = sqrt(real² + imag²)
std::span< T > convert_variant(DataVariant &variant, ComplexConversionStrategy strategy=ComplexConversionStrategy::MAGNITUDE)
Get const span from DataVariant without conversion (zero-copy for matching types)
uint64_t calculate_total_elements(const std::vector< DataDimension > &dimensions)
Calculate the total number of elements in an N-dimensional container.
Definition DataUtils.cpp:7
std::optional< T > get_metadata_value(const std::unordered_map< std::string, std::any > &metadata, const std::string &key)
Get a value from a metadata map by key.
std::vector< std::span< T > > convert_variants(const std::vector< DataVariant > &variants, ComplexConversionStrategy strategy=ComplexConversionStrategy::MAGNITUDE)
static std::span< To > convert(std::span< From > source, std::vector< To > &storage, ComplexConversionStrategy=ComplexConversionStrategy::MAGNITUDE)
static std::span< To > convert(std::span< From > source, std::vector< To > &storage, ComplexConversionStrategy=ComplexConversionStrategy::MAGNITUDE)
static std::span< To > convert(std::span< From > source, std::vector< To > &storage, ComplexConversionStrategy=ComplexConversionStrategy::MAGNITUDE)
Definition DataUtils.hpp:52
static std::span< To > convert(std::span< From > source, std::vector< To > &storage, ComplexConversionStrategy strategy)
Definition DataUtils.hpp:73
static std::span< To > convert(std::span< From > source, std::vector< To > &storage, ComplexConversionStrategy=ComplexConversionStrategy::MAGNITUDE)
static std::span< To > convert(std::span< From > source, std::vector< To > &storage, ComplexConversionStrategy=ComplexConversionStrategy::MAGNITUDE)
static std::span< To > convert(std::span< From > source, std::vector< To > &storage, ComplexConversionStrategy=ComplexConversionStrategy::MAGNITUDE)
static std::span< T > convert(std::span< T > source, std::vector< T > &, ComplexConversionStrategy=ComplexConversionStrategy::MAGNITUDE)
Definition DataUtils.hpp:37
static std::span< To > convert(std::span< From >, std::vector< To > &, ComplexConversionStrategy=ComplexConversionStrategy::MAGNITUDE)
Definition DataUtils.hpp:24
Role
Semantic role of the dimension.
Definition NDData.hpp:234