MayaFlux 0.1.0
Digital-First Multimedia Processing Framework
Loading...
Searching...
No Matches
ContainerUtils.cpp
Go to the documentation of this file.
1#include "ContainerUtils.hpp"
2#include "DataUtils.hpp"
4#include "RegionUtils.hpp"
5
7
8namespace MayaFlux::Kakshya {
9
10std::unordered_map<std::string, std::any> extract_processing_state_info(const std::shared_ptr<SignalSourceContainer>& container)
11{
12 if (!container) {
13 throw std::invalid_argument("Container is null");
14 }
15
16 std::unordered_map<std::string, std::any> state_info;
17
18 state_info["processing_state"] = static_cast<int>(container->get_processing_state());
19 state_info["is_ready"] = container->is_ready_for_processing();
20
21 if (auto stream = std::dynamic_pointer_cast<StreamContainer>(container)) {
22 state_info["read_position"] = stream->get_read_position();
23 state_info["is_stream_container"] = true;
24 } else {
25 state_info["is_stream_container"] = false;
26 }
27
28 return state_info;
29}
30
31std::unordered_map<std::string, std::any> extract_processor_info(const std::shared_ptr<SignalSourceContainer>& container)
32{
33 if (!container) {
34 throw std::invalid_argument("Container is null");
35 }
36
37 std::unordered_map<std::string, std::any> processor_info;
38
39 if (auto processor = container->get_default_processor()) {
40 processor_info["has_processor"] = true;
41 processor_info["processor_processing"] = processor->is_processing();
42 } else {
43 processor_info["has_processor"] = false;
44 }
45
46 if (auto chain = container->get_processing_chain()) {
47 processor_info["has_processing_chain"] = true;
48 // TODO: Could add more chain information here
49 } else {
50 processor_info["has_processing_chain"] = false;
51 }
52
53 return processor_info;
54}
55
56bool transition_state(ProcessingState& current_state, ProcessingState new_state, std::function<void()> on_transition)
57{
58 static const std::unordered_map<ProcessingState, std::unordered_set<ProcessingState>> valid_transitions = {
65 };
66 auto it = valid_transitions.find(current_state);
67 if (it != valid_transitions.end() && (it->second.count(new_state) != 0U)) {
68 current_state = new_state;
69 if (on_transition)
70 on_transition();
71 return true;
72 }
73 return false;
74}
75
76std::unordered_map<std::string, std::any> analyze_access_pattern(const Region& region,
77 const std::shared_ptr<SignalSourceContainer>& container)
78{
79 std::unordered_map<std::string, std::any> analysis;
80
81 if (!container) {
82 throw std::invalid_argument("Container is null");
83 }
84
85 const auto dimensions = container->get_dimensions();
86 const auto memory_layout = container->get_memory_layout();
87
88 analysis["is_contiguous"] = is_region_access_contiguous(region, container);
89 analysis["memory_layout"] = static_cast<int>(memory_layout);
90
91 uint64_t region_size = 1;
92 for (size_t i = 0; i < region.start_coordinates.size() && i < region.end_coordinates.size(); ++i) {
93 region_size *= (region.end_coordinates[i] - region.start_coordinates[i] + 1);
94 }
95 analysis["region_size"] = region_size;
96
97 if (!dimensions.empty()) {
98 auto strides = calculate_strides(dimensions);
99 analysis["access_stride"] = strides[0]; // Primary dimension stride
100 }
101
102 return analysis;
103}
104
105DataVariant extract_channel_data(const std::shared_ptr<SignalSourceContainer>& container,
106 uint32_t channel_index)
107{
108 if (!container) {
109 throw std::invalid_argument("Container is null");
110 }
111
112 const auto structure = container->get_structure();
113 auto channel_count = structure.get_channel_count();
114
115 if (channel_index >= channel_count) {
116 throw std::out_of_range("Channel index out of range");
117 }
118
119 auto data = container->get_data();
120
121 if (structure.organization == OrganizationStrategy::PLANAR) {
122 if (channel_index >= data.size()) {
123 throw std::out_of_range("Channel index out of range for planar data");
124 }
125 return data[channel_index];
126 }
127
128 std::vector<double> temp_storage;
129 auto interleaved_span = extract_from_variant<double>(data[0], temp_storage);
130
131 if (interleaved_span.empty()) {
132 throw std::runtime_error("Failed to extract interleaved data");
133 }
134
135 if (interleaved_span.size() % channel_count != 0) {
136 throw std::runtime_error("Interleaved data size is not a multiple of channel count");
137 }
138
139#ifdef MAYAFLUX_PLATFORM_MACOS
140 std::vector<double> channel_data;
141 for (size_t i = channel_index; i < interleaved_span.size(); i += channel_count) {
142 channel_data.push_back(interleaved_span[i]);
143 }
144#else
145 auto channel_view = interleaved_span
146 | std::views::drop(channel_index)
147 | std::views::stride(channel_count);
148
149 std::vector<double> channel_data;
150 std::ranges::copy(channel_view, std::back_inserter(channel_data));
151#endif // MAYAFLUX_PLATFORM_MACOS
152
153 return DataVariant { std::move(channel_data) };
154}
155
156std::pair<std::shared_ptr<SignalSourceContainer>, std::vector<DataDimension>>
157validate_container_for_analysis(const std::shared_ptr<SignalSourceContainer>& container)
158{
159 if (!container || !container->has_data()) {
160 throw std::invalid_argument("Container is null or has no data");
161 }
162
163 auto dimensions = container->get_dimensions();
164 if (dimensions.empty()) {
165 throw std::runtime_error("Container has no dimensions");
166 }
167
168 return std::make_pair(container, std::move(dimensions));
169}
170
171std::vector<std::span<double>> extract_numeric_data(const std::shared_ptr<SignalSourceContainer>& container)
172{
173 if (!container || !container->has_data()) {
174 throw std::invalid_argument("Container is null or has no data");
175 }
176
177 auto container_data = container->get_data();
178
179 return container_data
180 | std::views::transform([](DataVariant& variant) -> std::span<double> {
181 return convert_variant_to_double(variant);
182 })
183 | std::ranges::to<std::vector>();
184}
185
186void validate_numeric_data_for_analysis(const std::vector<double>& data,
187 const std::string& operation_name,
188 size_t min_size)
189{
190 if (data.empty()) {
191 throw std::invalid_argument("Cannot perform " + operation_name + " on empty data");
192 }
193
194 if (data.size() < min_size) {
195 throw std::invalid_argument(operation_name + " requires at least " + std::to_string(min_size) + " data points, got " + std::to_string(data.size()));
196 }
197
198 if (auto invalid_it = std::ranges::find_if_not(data, [](double val) {
199 return std::isfinite(val);
200 });
201 invalid_it != data.end()) {
202
203 const auto index = std::distance(data.begin(), invalid_it);
204 throw std::invalid_argument(operation_name + " data contains NaN or infinite values at index " + std::to_string(index));
205 }
206}
207
208}
ProcessingState
Represents the current processing lifecycle state of a container.
@ READY
Container has data loaded and is ready for processing.
@ NEEDS_REMOVAL
Container is marked for removal from the system.
@ IDLE
Container is inactive with no data or not ready for processing.
@ ERROR
Container is in an error state and cannot proceed.
@ PROCESSING
Container is actively being processed.
@ PROCESSED
Container has completed processing and results are available.
std::unordered_map< std::string, std::any > analyze_access_pattern(const Region &region, const std::shared_ptr< SignalSourceContainer > &container)
Determine optimal memory access pattern for region.
bool is_region_access_contiguous(const Region &region, const std::shared_ptr< SignalSourceContainer > &container)
Check if region access will be contiguous in memory.
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
std::vector< uint64_t > calculate_strides(const std::vector< DataDimension > &dimensions)
Calculate memory strides for each dimension (row-major order).
DataVariant extract_channel_data(const std::shared_ptr< SignalSourceContainer > &container, uint32_t channel_index)
Extract data from a specific channel.
@ PLANAR
Separate DataVariant per logical unit (LLL...RRR for stereo)
std::unordered_map< std::string, std::any > extract_processing_state_info(const std::shared_ptr< SignalSourceContainer > &container)
Extract processing state information from container.
std::vector< std::span< double > > extract_numeric_data(const std::shared_ptr< SignalSourceContainer > &container)
Extracts numeric data from container with fallback handling.
void validate_numeric_data_for_analysis(const std::vector< double > &data, const std::string &operation_name, size_t min_size)
Validates numeric data for analysis operations.
std::pair< std::shared_ptr< SignalSourceContainer >, std::vector< DataDimension > > validate_container_for_analysis(const std::shared_ptr< SignalSourceContainer > &container)
Validates container for analysis operations with comprehensive checks.
std::span< double > convert_variant_to_double(DataVariant &data, Utils::ComplexConversionStrategy strategy=Utils::ComplexConversionStrategy::MAGNITUDE)
Convert variant to double span.
std::unordered_map< std::string, std::any > extract_processor_info(const std::shared_ptr< SignalSourceContainer > &container)
Extract processor information from container.
bool transition_state(ProcessingState &current_state, ProcessingState new_state, std::function< void()> on_transition)
Perform a state transition for a ProcessingState, with optional callback.
std::vector< uint64_t > end_coordinates
Ending frame index (inclusive)
Definition Region.hpp:72
std::vector< uint64_t > start_coordinates
Starting frame index (inclusive)
Definition Region.hpp:69
Represents a point or span in N-dimensional space.
Definition Region.hpp:67