MayaFlux 0.1.0
Digital-First Multimedia Processing Framework
Loading...
Searching...
No Matches
DataAccess.hpp
Go to the documentation of this file.
1#pragma once
2
3#include "NDData.hpp"
4
5#include <glm/gtc/type_ptr.hpp>
6
8
9namespace MayaFlux::Kakshya {
10
11/**
12 * @class DataAccess
13 * @brief Type-erased accessor for NDData with semantic view construction
14 *
15 * Provides a unified interface to access data either as structured types
16 * (glm::vec3, etc.) or as scalar arrays (double, float), based on modality
17 * and user intent. Container classes remain template-free.
18 */
19class MAYAFLUX_API DataAccess {
20public:
22 const std::vector<DataDimension>& dimensions,
23 DataModality modality)
24 : m_variant(variant)
25 , m_dimensions(dimensions)
26 , m_modality(modality)
27 {
28 }
29
30 /**
31 * @brief Get explicit typed view of data
32 * @tparam T View type (glm::vec3, double, float, etc.)
33 * @return Span-like view of data as type T
34 *
35 * @note If type conversion is needed, the view remains valid for the
36 * lifetime of this DataAccess object. Multiple calls with the
37 * same type reuse the cached conversion.
38 */
39 template <typename T>
40 auto view() const;
41
42 /**
43 * @brief Get raw buffer info for GPU upload
44 * @return Tuple of (void* data, size_t bytes, format_hint)
45 */
46 [[nodiscard]] auto gpu_buffer() const
47 {
48 return std::visit([&](auto& vec) {
49 using T = typename std::decay_t<decltype(vec)>::value_type;
50 return std::make_tuple(
51 static_cast<const void*>(vec.data()),
52 vec.size() * sizeof(T),
53 get_format_hint<T>());
54 },
55 m_variant);
56 }
57
58 [[nodiscard]] DataModality modality() const { return m_modality; }
59
60 [[nodiscard]] bool is_structured() const
61 {
62 return !m_dimensions.empty() && m_dimensions[0].grouping.has_value();
63 }
64
65 [[nodiscard]] size_t element_count() const
66 {
67 if (is_structured()) {
68 return m_dimensions[0].size;
69 }
70 return std::visit([](const auto& vec) { return vec.size(); }, m_variant);
71 }
72
73 [[nodiscard]] size_t component_count() const
74 {
75 if (is_structured() && m_dimensions[0].grouping) {
76 return m_dimensions[0].grouping->count;
77 }
78 return 1;
79 }
80
81 [[nodiscard]] std::string type_description() const
82 {
83 if (is_structured()) {
84 return Journal::format("{}Ă—{} ({})",
85 element_count(),
86 component_count(),
87 modality_to_string(m_modality));
88 }
89 return Journal::format("scalarĂ—{} ({})",
90 element_count(),
91 modality_to_string(m_modality));
92 }
93
94 /**
95 * @brief Get suggested view type for this data's modality
96 * @return String describing recommended view type
97 */
98 [[nodiscard]] std::string_view suggested_view_type() const
99 {
100 switch (m_modality) {
101 case DataModality::VERTEX_POSITIONS_3D:
102 case DataModality::VERTEX_NORMALS_3D:
103 case DataModality::VERTEX_TANGENTS_3D:
104 case DataModality::VERTEX_COLORS_RGB:
105 return "glm::vec3";
106
107 case DataModality::TEXTURE_COORDS_2D:
108 return "glm::vec2";
109
110 case DataModality::VERTEX_COLORS_RGBA:
111 return "glm::vec4";
112
113 case DataModality::TRANSFORMATION_MATRIX:
114 return "glm::mat4";
115
116 case DataModality::AUDIO_1D:
117 case DataModality::AUDIO_MULTICHANNEL:
118 case DataModality::SPECTRAL_2D:
119 return "double";
120
121 case DataModality::IMAGE_2D:
122 case DataModality::IMAGE_COLOR:
123 case DataModality::TEXTURE_2D:
124 return "float";
125
126 default:
127 return "unknown";
128 }
129 }
130
131private:
133 const std::vector<DataDimension>& m_dimensions;
135
136 mutable std::optional<std::vector<uint8_t>> m_conversion_cache;
137
138 template <typename T>
139 static uint32_t get_format_hint()
140 {
141 // Return VkFormat or similar enum based on type
142 // Placeholder for now
143 return 0;
144 }
145
146 template <typename T>
147 requires std::is_arithmetic_v<T>
148 std::span<const T> create_scalar_view() const;
149
150 template <typename T>
151 void validate_structured_access() const;
152
153 /**
154 * @brief Ensure conversion cache exists and is properly sized
155 * @tparam T Target component type
156 * @param required_bytes Size needed in bytes
157 * @return Pointer to cache storage
158 */
159 template <typename T>
160 void* ensure_conversion_cache(size_t required_bytes) const
161 {
162 if (!m_conversion_cache || m_conversion_cache->size() < required_bytes) {
163 m_conversion_cache = std::vector<uint8_t>(required_bytes);
164 }
165 return m_conversion_cache->data();
166 }
167};
168
169/**
170 * @class StructuredView
171 * @brief Span-like view that interprets flat data as structured types (glm::vec3, etc.)
172 */
173template <typename T>
174 requires GlmType<T>
176public:
177 using value_type = T;
178 using component_type = glm_component_type<T>;
179 static constexpr size_t components = glm_component_count<T>();
180
181 StructuredView(const void* data, size_t element_count, size_t stride_bytes = 0)
182 : m_data(static_cast<const component_type*>(data))
183 , m_element_count(element_count)
184 , m_stride(stride_bytes == 0 ? components : stride_bytes / sizeof(component_type))
185 {
186 }
187
188 T operator[](size_t idx) const
189 {
190 const component_type* base = m_data + (idx * m_stride);
191 return construct_glm_type<T>(base);
192 }
193
194 class iterator {
195 public:
196 using difference_type = std::ptrdiff_t;
197 using value_type = T;
198
199 iterator(const component_type* ptr, size_t stride)
200 : m_ptr(ptr)
201 , m_stride(stride)
202 {
203 }
204
205 T operator*() const { return construct_glm_type<T>(m_ptr); }
207 {
208 m_ptr += m_stride;
209 return *this;
210 }
212 {
213 iterator tmp = *this;
214 ++(*this);
215 return tmp;
216 }
217 bool operator==(const iterator& other) const { return m_ptr == other.m_ptr; }
218 bool operator!=(const iterator& other) const { return m_ptr != other.m_ptr; }
219
220 private:
222 size_t m_stride;
223 };
224
225 iterator begin() const { return iterator(m_data, m_stride); }
227
228 [[nodiscard]] size_t size() const { return m_element_count; }
229
230 // GPU upload: get raw pointer (zero-copy when stride is tight)
231 [[nodiscard]] const void* data() const { return m_data; }
232 [[nodiscard]] size_t size_bytes() const { return m_element_count * m_stride * sizeof(component_type); }
233
234 std::vector<T> to_vector() const
235 {
236 std::vector<T> result;
237 result.reserve(m_element_count);
238 for (size_t i = 0; i < m_element_count; ++i) {
239 result.push_back((*this)[i]);
240 }
241 return result;
242 }
243
244private:
247 size_t m_stride; // In units of component_type
248
249 template <typename GlmType>
251 {
252 if constexpr (GlmVec2Type<GlmType>) {
253 return GlmType { components[0], components[1] };
254 } else if constexpr (GlmVec3Type<GlmType>) {
255 return GlmType { components[0], components[1], components[2] };
256 } else if constexpr (GlmVec4Type<GlmType>) {
257 return GlmType { components[0], components[1], components[2], components[3] };
258 } else if constexpr (GlmMatrixType<GlmType>) {
259 return glm::make_mat4(components);
260 }
261 }
262};
263
264// ============================================================================
265// TEMPLATE IMPLEMENTATIONS
266// ============================================================================
267
268template <typename T>
270{
271 if constexpr (GlmType<T>) {
272 validate_structured_access<T>();
273
274 return std::visit([&](auto& vec) -> StructuredView<T> {
275 using StorageType = typename std::decay_t<decltype(vec)>::value_type;
276 using ComponentType = glm_component_type<T>;
277 constexpr size_t components = glm_component_count<T>();
278
279 size_t required_components = m_dimensions[0].size * components;
280 if (vec.size() < required_components) {
281 error<std::runtime_error>(
284 std::source_location::current(),
285 "Insufficient data: need {} elements of type {} but have {} elements of type {}",
286 m_dimensions[0].size,
287 typeid(T).name(),
288 vec.size() / components,
289 typeid(StorageType).name());
290 }
291
292 if constexpr (std::is_same_v<StorageType, ComponentType>) {
293 return StructuredView<T>(vec.data(), m_dimensions[0].size);
294 } else if constexpr (std::is_convertible_v<StorageType, ComponentType>) {
295 size_t required_bytes = vec.size() * sizeof(ComponentType);
296 void* cache_ptr = ensure_conversion_cache<ComponentType>(required_bytes);
297
298 ComponentType* cache_data = static_cast<ComponentType*>(cache_ptr);
299 std::ranges::transform(vec, cache_data,
300 [](auto val) { return static_cast<ComponentType>(val); });
301
302 return StructuredView<T>(cache_data, m_dimensions[0].size);
303 } else {
304 error<std::invalid_argument>(
307 std::source_location::current(),
308 "Cannot convert storage type {} to component type {}",
309 typeid(StorageType).name(),
310 typeid(ComponentType).name());
311 }
312 },
313 m_variant);
314
315 } else if constexpr (std::is_arithmetic_v<T>) {
316 return create_scalar_view<T>();
317
318 } else {
319 static_assert(always_false_v<T>,
320 "Unsupported view type. Use glm types or arithmetic types (double, float, int, etc.)");
321 }
322}
323
324template <typename T>
325 requires std::is_arithmetic_v<T>
326std::span<const T> DataAccess::create_scalar_view() const
327{
328 return std::visit([this](auto& vec) -> std::span<const T> {
329 using StorageType = typename std::decay_t<decltype(vec)>::value_type;
330
331 if constexpr (std::is_same_v<StorageType, T>) {
332 return std::span<const T>(vec.data(), vec.size());
333 } else if constexpr (std::is_convertible_v<StorageType, T>) {
334 size_t required_bytes = vec.size() * sizeof(T);
335 void* cache_ptr = ensure_conversion_cache<T>(required_bytes);
336
337 T* cache_data = static_cast<T*>(cache_ptr);
338 std::ranges::transform(vec, cache_data,
339 [](auto val) { return static_cast<T>(val); });
340
341 return std::span<const T>(cache_data, vec.size());
342 } else {
343 error<std::invalid_argument>(
346 std::source_location::current(),
347 "Cannot convert storage type {} to requested type {}",
348 typeid(StorageType).name(),
349 typeid(T).name());
350 }
351 },
352 m_variant);
353}
354
355template <typename T>
357{
358 constexpr size_t requested_components = glm_component_count<T>();
359
360 if (m_dimensions.empty()) {
361 error<std::runtime_error>(
364 std::source_location::current(),
365 "Cannot create structured view: no dimensions defined");
366 }
367
368 if (!m_dimensions[0].grouping) {
369 error<std::runtime_error>(
372 std::source_location::current(),
373 "Cannot create structured view: dimension '{}' missing component grouping. "
374 "Use DataDimension::grouped() to create structured dimensions.",
375 m_dimensions[0].name);
376 }
377
378 size_t actual_components = m_dimensions[0].grouping->count;
379 if (actual_components != requested_components) {
380 error<std::runtime_error>(
383 std::source_location::current(),
384 "Component count mismatch: requested {} components ({}), but data has {} components per element. "
385 "Suggested type: {}",
386 requested_components,
387 typeid(T).name(),
388 actual_components,
390 }
391}
392
393} // namespace MayaFlux::Kakshya
static uint32_t get_format_hint()
const std::vector< DataDimension > & m_dimensions
void * ensure_conversion_cache(size_t required_bytes) const
Ensure conversion cache exists and is properly sized.
std::span< const T > create_scalar_view() const
auto gpu_buffer() const
Get raw buffer info for GPU upload.
DataAccess(DataVariant &variant, const std::vector< DataDimension > &dimensions, DataModality modality)
auto view() const
Get explicit typed view of data.
DataModality modality() const
std::string_view suggested_view_type() const
Get suggested view type for this data's modality.
std::optional< std::vector< uint8_t > > m_conversion_cache
std::string type_description() const
void validate_structured_access() const
Type-erased accessor for NDData with semantic view construction.
iterator(const component_type *ptr, size_t stride)
bool operator==(const iterator &other) const
bool operator!=(const iterator &other) const
static GlmType construct_glm_type(const component_type *components)
std::vector< T > to_vector() const
static constexpr size_t components
StructuredView(const void *data, size_t element_count, size_t stride_bytes=0)
glm_component_type< T > component_type
const component_type * m_data
Span-like view that interprets flat data as structured types (glm::vec3, etc.)
@ Runtime
General runtime operations (default fallback)
@ Kakshya
Containers[Signalsource, Stream, File], Regions, DataProcessors.
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
std::string_view modality_to_string(DataModality modality)
Convert DataModality enum to string representation.
Definition NDData.cpp:80