8#include <glm/gtc/type_ptr.hpp>
13template <
typename From,
typename To,
typename Enable =
void>
15 static std::span<To>
convert(std::span<From> ,
19 static_assert(always_false_v<From>,
"No conversion available for these types");
28 static std::span<T>
convert(std::span<T> source,
38template <
typename From,
typename To>
42 ArithmeticData<From> && ArithmeticData<To> && !std::is_same_v<From, To> && !GlmType<From> && !GlmType<To>>> {
44 std::span<From> source,
45 std::vector<To>& storage,
48 storage.resize(source.size());
50 source.begin(), source.end(), storage.begin(),
51 [](From val) { return static_cast<To>(val); });
53 return std::span<To>(storage.data(), storage.size());
59template <
typename From,
typename To>
63 ComplexData<From> && ArithmeticData<To> && !GlmType<From> && !GlmType<To>>> {
65 std::span<From> source,
66 std::vector<To>& storage,
69 storage.resize(source.size());
71 for (
size_t i = 0; i < source.size(); ++i) {
74 storage[i] =
static_cast<To
>(std::abs(source[i]));
77 storage[i] =
static_cast<To
>(source[i].real());
80 storage[i] =
static_cast<To
>(source[i].imag());
83 storage[i] =
static_cast<To
>(std::norm(source[i]));
88 return std::span<To>(storage.data(), storage.size());
94template <
typename From,
typename To>
98 ArithmeticData<From> && ComplexData<To> && !GlmType<From> && !GlmType<To>>> {
100 std::span<From> source,
101 std::vector<To>& storage,
104 using ComplexValueType =
typename To::value_type;
105 storage.resize(source.size());
107 for (
size_t i = 0; i < source.size(); ++i) {
108 storage[i] = To(
static_cast<ComplexValueType
>(source[i]), ComplexValueType { 0 });
111 return std::span<To>(storage.data(), storage.size());
117template <
typename From,
typename To>
121 GlmType<From> && ArithmeticData<To> && !GlmType<To>>> {
123 std::span<From> source,
124 std::vector<To>& storage,
127 constexpr size_t components = glm_component_count<From>();
128 using ComponentType = glm_component_type<From>;
130 storage.resize(source.size() * components);
133 for (
const auto& elem : source) {
134 const ComponentType* ptr = glm::value_ptr(elem);
135 for (
size_t c = 0; c < components; ++c) {
136 storage[out_idx++] =
static_cast<To
>(ptr[c]);
140 return std::span<To>(storage.data(), storage.size());
146template <
typename From,
typename To>
150 ArithmeticData<From> && GlmType<To> && !GlmType<From>>> {
152 std::span<From> source,
153 std::vector<To>& storage,
156 constexpr size_t components = glm_component_count<To>();
157 using ComponentType = glm_component_type<To>;
159 if (source.size() % components != 0) {
160 error<std::invalid_argument>(
163 std::source_location::current(),
164 "Source size ({}) must be multiple of GLM component count ({})",
169 size_t element_count = source.size() / components;
170 storage.resize(element_count);
172 for (
size_t i = 0; i < element_count; ++i) {
173 ComponentType temp[components];
174 for (
size_t c = 0; c < components; ++c) {
175 temp[c] =
static_cast<ComponentType
>(source[i * components + c]);
178 if constexpr (GlmVec2Type<To>) {
179 storage[i] = To(temp[0], temp[1]);
180 }
else if constexpr (GlmVec3Type<To>) {
181 storage[i] = To(temp[0], temp[1], temp[2]);
182 }
else if constexpr (GlmVec4Type<To>) {
183 storage[i] = To(temp[0], temp[1], temp[2], temp[3]);
184 }
else if constexpr (GlmMatrixType<To>) {
185 storage[i] = glm::make_mat4(temp);
189 return std::span<To>(storage.data(), storage.size());
195template <
typename From,
typename To>
199 GlmType<From> && GlmType<To> && !std::is_same_v<From, To> && (glm_component_count<From>() == glm_component_count<To>())>> {
201 std::span<From> source,
202 std::vector<To>& storage,
205 using FromComponent = glm_component_type<From>;
206 using ToComponent = glm_component_type<To>;
207 constexpr size_t components = glm_component_count<From>();
209 storage.resize(source.size());
211 for (
size_t i = 0; i < source.size(); ++i) {
212 const FromComponent* src_ptr = glm::value_ptr(source[i]);
213 ToComponent temp[components];
215 for (
size_t c = 0; c < components; ++c) {
216 temp[c] =
static_cast<ToComponent
>(src_ptr[c]);
219 if constexpr (GlmVec2Type<To>) {
220 storage[i] = To(temp[0], temp[1]);
221 }
else if constexpr (GlmVec3Type<To>) {
222 storage[i] = To(temp[0], temp[1], temp[2]);
223 }
else if constexpr (GlmVec4Type<To>) {
224 storage[i] = To(temp[0], temp[1], temp[2], temp[3]);
225 }
else if constexpr (GlmMatrixType<To>) {
226 storage[i] = glm::make_mat4(temp);
230 return std::span<To>(storage.data(), storage.size());
235template <
typename From,
typename To>
239 ComplexData<From> && ComplexData<To> && !GlmType<From> && !GlmType<To> && !std::is_same_v<From, To>>> {
241 std::span<From> source,
242 std::vector<To>& storage,
245 using FromValue =
typename From::value_type;
246 using ToValue =
typename To::value_type;
248 storage.resize(source.size());
249 for (
size_t i = 0; i < source.size(); ++i) {
250 const auto r =
static_cast<FromValue
>(source[i].real());
251 const auto im =
static_cast<FromValue
>(source[i].imag());
252 storage[i] = To(
static_cast<ToValue
>(r),
static_cast<ToValue
>(im));
255 return std::span<To>(storage.data(), storage.size());
286template <ProcessableData T>
287constexpr std::span<T>
extract_frame(std::span<T> data, uint64_t frame_index, uint64_t frame_size)
noexcept
289 uint64_t start = frame_index * frame_size;
290 uint64_t end = std::min(
static_cast<uint64_t
>(start + frame_size),
291 static_cast<uint64_t
>(data.size()));
293 if (start >= data.size()) {
297 return data.subspan(start, end - start);
308template <ProcessableData T>
310 const std::vector<std::span<T>>& channel_spans,
311 uint64_t frame_index,
312 std::vector<T>& output_buffer)
noexcept
314 output_buffer.clear();
315 output_buffer.reserve(channel_spans.size());
317 for (
const auto& channel_span : channel_spans) {
318 if (frame_index < channel_span.size()) {
319 output_buffer.push_back(channel_span[frame_index]);
321 output_buffer.push_back(T { 0 });
325 return std::span<T>(output_buffer.data(), output_buffer.size());
336template <
typename From,
typename To>
338 std::vector<To>& storage,
347template <
typename From,
typename To>
348 requires(ComplexData<From> && ArithmeticData<To>)
350 std::span<To> destination,
353 std::vector<To> temp_storage;
354 auto result =
convert_data(source, temp_storage, strategy);
355 std::copy_n(result.begin(), std::min(result.size(), destination.size()), destination.begin());
365template <ProcessableData T>
369 if (std::holds_alternative<std::vector<T>>(variant)) {
370 auto& vec = std::get<std::vector<T>>(variant);
371 return std::span<T>(vec.data(), vec.size());
374 return std::visit([&variant, strategy](
auto& data) -> std::span<T> {
375 using ValueType =
typename std::decay_t<
decltype(data)>::value_type;
377 if constexpr (is_convertible_data_v<ValueType, T>) {
378 std::vector<T> new_storage;
379 auto source_span = std::span<ValueType>(data.data(), data.size());
380 auto result =
convert_data(source_span, new_storage, strategy);
382 variant = std::move(new_storage);
383 auto& new_vec = std::get<std::vector<T>>(variant);
384 return std::span<T>(new_vec.data(), new_vec.size());
386 error<std::invalid_argument>(
389 std::source_location::current(),
390 "No conversion available from {} to {}",
391 typeid(ValueType).name(),
398template <ProcessableData T>
402 return convert_variant<T>(
const_cast<DataVariant&
>(variant), strategy);
405template <ProcessableData T>
407 const std::vector<DataVariant>& variants,
410 std::vector<std::span<T>> result;
411 result.reserve(variants.size());
413 for (
const auto& i : variants) {
414 result.push_back(convert_variant<T>(
const_cast<DataVariant&
>(i), strategy));
428template <ProcessableData From, ProcessableData To>
430 std::vector<To>& destination,
433 const size_t total_bytes = source.size() *
sizeof(From);
434 const size_t required_elements = (total_bytes +
sizeof(To) - 1) /
sizeof(To);
435 destination.resize(required_elements);
437 if constexpr (std::is_same_v<From, To>) {
438 destination.resize(source.size());
439 std::memcpy(destination.data(), source.data(), total_bytes);
440 return std::span<To>(destination.data(), source.size());
441 }
else if constexpr (std::is_trivially_copyable_v<From> && std::is_trivially_copyable_v<To> && (
sizeof(From) ==
sizeof(To))) {
443 std::memcpy(destination.data(), source.data(), total_bytes);
444 return std::span<To>(destination.data(), source.size());
447 std::vector<From> temp(source.begin(), source.end());
448 auto converted = convert_data<From, To>(std::span<const From>(temp), strategy);
449 destination.assign(converted.begin(), converted.end());
450 return std::span<To>(destination.data(), destination.size());
460template <ProcessableData T>
462 std::vector<T>& storage,
465 return std::visit([&storage, strategy](
const auto& data) -> std::span<T> {
466 using ValueType =
typename std::decay_t<
decltype(data)>::value_type;
468 if constexpr (std::is_same_v<ValueType, T>) {
470 return std::span<T>(storage.data(), storage.size());
471 }
else if constexpr (is_convertible_data_v<ValueType, T>) {
472 auto source_span = std::span<const ValueType>(data.data(), data.size());
473 std::vector<ValueType> temp_source(source_span.begin(), source_span.end());
474 auto temp_span = std::span<ValueType>(temp_source.data(), temp_source.size());
478 error<std::invalid_argument>(
481 std::source_location::current(),
482 "No conversion available from {} to {}",
483 typeid(ValueType).name(),
500 return std::visit([pos](
const auto& data) -> std::optional<T> {
501 using DataType = std::decay_t<
decltype(data)>;
502 using ValueType =
typename DataType::value_type;
504 if (pos >= data.size()) {
508 if constexpr (std::is_same_v<ValueType, T>) {
510 }
else if constexpr (std::is_arithmetic_v<ValueType> && std::is_arithmetic_v<T>) {
511 return static_cast<T
>(data[pos]);
512 }
else if constexpr (std::is_same_v<ValueType, std::complex<float>> || std::is_same_v<ValueType, std::complex<double>>) {
513 if constexpr (std::is_arithmetic_v<T>) {
514 return static_cast<T
>(std::abs(data[pos]));
552 std::vector<T> temp_storage;
553 auto input_span = extract_from_variant<T>(input, temp_storage);
554 auto output_span = get_typed_data<T>(output);
555 std::copy_n(input_span.begin(), std::min(input_span.size(), output_span.size()),
556 output_span.begin());
568 return convert_variant<double>(data, strategy);
577void set_metadata_value(std::unordered_map<std::string, std::any>& metadata,
const std::string& key, std::any value);
587std::optional<T>
get_metadata_value(
const std::unordered_map<std::string, std::any>& metadata,
const std::string& key)
589 auto it = metadata.find(key);
590 if (it != metadata.end()) {
592 return safe_any_cast<T>(it->second);
593 }
catch (
const std::bad_any_cast&) {
@ Runtime
General runtime operations (default fallback)
@ Kakshya
Containers[Signalsource, Stream, File], Regions, DataProcessors.
void convert_complex(std::span< From > source, std::span< To > destination, Utils::ComplexConversionStrategy strategy)
Legacy interface - redirects to convert_data.
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< std::span< T > > convert_variants(const std::vector< DataVariant > &variants, Utils::ComplexConversionStrategy strategy=Utils::ComplexConversionStrategy::MAGNITUDE)
std::span< T > convert_variant(DataVariant &variant, Utils::ComplexConversionStrategy strategy=Utils::ComplexConversionStrategy::MAGNITUDE)
Get const span from DataVariant without conversion (zero-copy for matching types)
std::vector< DataDimension > detect_data_dimensions(const DataVariant &data)
Detect data dimensions from a DataVariant.
uint64_t calculate_frame_size(const std::vector< DataDimension > &dimensions)
Calculate the frame size (number of elements per frame) for a set of dimensions.
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::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.
DataModality
Data modality types for cross-modal analysis.
std::type_index get_variant_type_index(const DataVariant &data)
Get type index from DataVariant.
int find_dimension_by_role(const std::vector< DataDimension > &dimensions, DataDimension::Role role)
Find the index of a dimension by its semantic role.
std::span< const double > safe_copy_data_variant_to_span(const DataVariant &input, std::vector< double > &output)
Safely copy data from a DataVariant to a span of doubles.
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).
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.
void safe_copy_data_variant(const DataVariant &input, DataVariant &output)
Safely copy data from a DataVariant to another DataVariant, handling type conversion.
std::span< double > convert_variant_to_double(DataVariant &data, Utils::ComplexConversionStrategy strategy=Utils::ComplexConversionStrategy::MAGNITUDE)
Convert variant to double span.
uint64_t calculate_total_elements(const std::vector< DataDimension > &dimensions)
Calculate the total number of elements in an N-dimensional container.
std::span< T > extract_from_variant(const DataVariant &variant, std::vector< T > &storage, Utils::ComplexConversionStrategy strategy=Utils::ComplexConversionStrategy::MAGNITUDE)
Get typed span from DataVariant using concepts.
std::span< To > extract_data(std::span< const From > source, std::vector< To > &destination, Utils::ComplexConversionStrategy strategy=Utils::ComplexConversionStrategy::MAGNITUDE)
Concept-based data extraction with type conversion.
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::span< To > convert_data(std::span< From > source, std::vector< To > &storage, Utils::ComplexConversionStrategy strategy=Utils::ComplexConversionStrategy::MAGNITUDE)
Convert a span of one data type to another (with type conversion).
ComplexConversionStrategy
Strategy for converting complex numbers to real values.
@ SQUARED_MAGNITUDE
|z|² = real² + imag²
@ MAGNITUDE
|z| = sqrt(real² + imag²)
static std::span< To > convert(std::span< From > source, std::vector< To > &storage, Utils::ComplexConversionStrategy=Utils::ComplexConversionStrategy::MAGNITUDE)
static std::span< To > convert(std::span< From > source, std::vector< To > &storage, Utils::ComplexConversionStrategy=Utils::ComplexConversionStrategy::MAGNITUDE)
static std::span< To > convert(std::span< From > source, std::vector< To > &storage, Utils::ComplexConversionStrategy=Utils::ComplexConversionStrategy::MAGNITUDE)
static std::span< To > convert(std::span< From > source, std::vector< To > &storage, Utils::ComplexConversionStrategy strategy)
static std::span< To > convert(std::span< From > source, std::vector< To > &storage, Utils::ComplexConversionStrategy=Utils::ComplexConversionStrategy::MAGNITUDE)
static std::span< To > convert(std::span< From > source, std::vector< To > &storage, Utils::ComplexConversionStrategy=Utils::ComplexConversionStrategy::MAGNITUDE)
static std::span< To > convert(std::span< From > source, std::vector< To > &storage, Utils::ComplexConversionStrategy=Utils::ComplexConversionStrategy::MAGNITUDE)
static std::span< T > convert(std::span< T > source, std::vector< T > &, Utils::ComplexConversionStrategy=Utils::ComplexConversionStrategy::MAGNITUDE)
static std::span< To > convert(std::span< From >, std::vector< To > &, Utils::ComplexConversionStrategy=Utils::ComplexConversionStrategy::MAGNITUDE)
Role
Semantic role of the dimension.