aqnwb 0.3.0
Loading...
Searching...
No Matches
ReadIO.hpp
Go to the documentation of this file.
1#pragma once
2
3#include <any>
4#include <array>
5#include <cassert>
6#include <cstdint>
7#include <iostream>
8#include <memory>
9#include <numeric>
10#include <stdexcept>
11#include <string>
12#include <type_traits>
13#include <typeindex>
14#include <variant>
15#include <vector>
16
17#include "BaseIO.hpp"
18#include "Types.hpp"
19
22
27namespace AQNWB::IO
28{
29
34{
35public:
43 std::any data;
49
68 std::type_index typeIndex = typeid(void);
69
72
76 DataBlockGeneric() = default;
77
81 DataBlockGeneric(const std::any& inData,
82 const SizeArray& inShape,
83 const std::type_index& inTypeIndex,
84 const IO::BaseDataType inBaseDataType)
85 : data(inData)
86 , shape(inShape)
87 , typeIndex(inTypeIndex)
88 , baseDataType(inBaseDataType)
89 {
90 }
91
97 inline BaseDataType getBaseDataType() const { return baseDataType; }
98
110 {
111 try {
112 switch (baseDataType.type) {
114 return std::any_cast<std::vector<uint8_t>>(data);
116 return std::any_cast<std::vector<uint16_t>>(data);
118 return std::any_cast<std::vector<uint32_t>>(data);
120 return std::any_cast<std::vector<uint64_t>>(data);
122 return std::any_cast<std::vector<int8_t>>(data);
124 return std::any_cast<std::vector<int16_t>>(data);
126 return std::any_cast<std::vector<int32_t>>(data);
128 return std::any_cast<std::vector<int64_t>>(data);
130 return std::any_cast<std::vector<float>>(data);
132 return std::any_cast<std::vector<double>>(data);
134 return std::any_cast<std::vector<std::string>>(data);
135 default:
136 return std::monostate {};
137 }
138 } catch (const std::bad_any_cast&) {
139 // If the actual type stored in `data` does not match the expected type
140 // based on `baseDataType`, a `std::bad_any_cast` exception will be
141 // thrown. In this case, we catch the exception and return
142 // `std::monostate` to indicate that the conversion failed.
143 return std::monostate {};
144 }
145 }
146};
147
164template<typename DTYPE, std::size_t NDIMS>
166{
167public:
168 using size_type = std::size_t;
169
178 ConstMultiArrayView(const DTYPE* data,
179 const std::array<size_type, NDIMS>& shape,
180 const std::array<size_type, NDIMS>& strides)
181 : m_data(data)
182 , m_shape(shape)
183 , m_strides(strides)
184 {
185 }
186
194 template<size_type N = NDIMS, typename std::enable_if_t<N == 1, int> = 0>
195 const DTYPE& operator[](size_type index) const
196 {
197 assert(index < m_shape[0]);
198 return m_data[index * m_strides[0]];
199 }
200
209 template<size_type N = NDIMS, typename std::enable_if_t<(N > 1), int> = 0>
210 ConstMultiArrayView<DTYPE, NDIMS - 1> operator[](size_type index) const
211 {
212 assert(index < m_shape[0]);
213 std::array<size_type, NDIMS - 1> sub_shape {};
214 std::array<size_type, NDIMS - 1> sub_strides {};
215 for (size_type i = 1; i < NDIMS; ++i) {
216 sub_shape[i - 1] = m_shape[i];
217 sub_strides[i - 1] = m_strides[i];
218 }
219 return ConstMultiArrayView<DTYPE, NDIMS - 1>(
220 m_data + index * m_strides[0], sub_shape, sub_strides);
221 }
222
229 template<size_type N = NDIMS, typename std::enable_if_t<N == 1, int> = 0>
230 const DTYPE* begin() const
231 {
232 assert(m_shape[0] == 0 || m_data != nullptr);
233 return m_data;
234 }
235
242 template<size_type N = NDIMS, typename std::enable_if_t<N == 1, int> = 0>
243 const DTYPE* end() const
244 {
245 assert(m_shape[0] == 0 || m_data != nullptr);
246 if (m_shape[0] == 0) {
247 return m_data;
248 }
249 return m_data + (m_shape[0] * m_strides[0]);
250 }
251
258 const std::array<size_type, NDIMS>& shape() const { return m_shape; }
259
260private:
261 const DTYPE* m_data;
262 std::array<size_type, NDIMS> m_shape;
263 std::array<size_type, NDIMS> m_strides;
264};
265
271template<typename DTYPE>
273{
274public:
278 std::vector<DTYPE> data;
288 const std::type_index typeIndex = typeid(DTYPE);
289
293 DataBlock(const std::vector<DTYPE>& inData, const SizeArray& inShape)
294 : data(inData)
295 , shape(inShape)
296 {
297 }
298
311 template<std::size_t NDIMS>
313 {
314 if (shape.size() != NDIMS) {
315 throw std::invalid_argument(
316 "Shape size does not match the number of dimensions.");
317 }
318
319 // Calculate the total number of elements expected
320 SizeType expected_size = std::accumulate(
321 shape.begin(), shape.end(), SizeType {1}, std::multiplies<SizeType> {});
322
323 if (data.size() != expected_size) {
324 throw std::invalid_argument("Data size does not match the shape.");
325 }
326
327 std::array<std::size_t, NDIMS> shape_array {};
328 for (std::size_t i = 0; i < NDIMS; ++i) {
329 shape_array[i] = static_cast<std::size_t>(shape[i]);
330 }
331
332 std::array<std::size_t, NDIMS> strides {};
333 std::size_t stride = 1;
334 for (std::size_t i = NDIMS; i-- > 0;) {
335 strides[i] = stride;
336 stride *= shape_array[i];
337 }
338
339 return ConstMultiArrayView<DTYPE, NDIMS>(data.data(), shape_array, strides);
340 }
341
353 const DataBlockGeneric& genericData)
354 {
355 auto result = DataBlock<DTYPE>(
356 std::any_cast<std::vector<DTYPE>>(genericData.data), genericData.shape);
357 return result;
358 }
359
371 {
373 }
374}; // class DataBlock
375
378template<StorageObjectType T>
379struct isAllowedStorageObjectType : std::false_type
380{
381};
382
385template<>
386struct isAllowedStorageObjectType<StorageObjectType::Dataset> : std::true_type
387{
388};
389
392template<>
393struct isAllowedStorageObjectType<StorageObjectType::Attribute> : std::true_type
394{
395};
396
405template<StorageObjectType OTYPE, typename VTYPE = std::any>
407{
408 // Embedded traits for compile time checking of allowed OTYPE for the class
409 // and methods
410private:
419 template<StorageObjectType U>
421 : std::integral_constant<bool, (U == StorageObjectType::Dataset)>
422 {
423 };
424
432 "StorageObjectType not allowed for ReadDataWrapper");
433
434 // Actual definition of the class
435public:
442 ReadDataWrapper(const std::shared_ptr<IO::BaseIO> io, const std::string& path)
443 : m_io(io)
444 , m_path(path)
445 {
446 }
447
452 static inline StorageObjectType getStorageObjectType() { return OTYPE; }
453
458 template<typename T>
459 static constexpr bool isType()
460 {
461 return std::is_same_v<VTYPE, T>;
462 }
463
468
473
477 virtual ~ReadDataWrapper() {}
478
483 inline const std::string& getPath() const { return m_path; }
484
489 inline std::shared_ptr<IO::BaseIO> getIO() const { return m_io; }
490
495 inline SizeArray getShape() const
496 {
497 return m_io->getStorageObjectShape(m_path);
498 }
499
504 inline SizeType getNumDimensions() const { return this->getShape().size(); }
505
512 {
513 return m_io->getStorageObjectDataType(m_path);
514 }
515
527 inline SizeArray getChunking() const
528 {
529 return m_io->getStorageObjectChunking(m_path);
530 }
531
546 template<StorageObjectType U = OTYPE,
547 typename std::enable_if<isDataset<U>::value, int>::type = 0>
552
557 inline bool exists() const
558 {
559 switch (OTYPE) {
560 case StorageObjectType::Dataset: {
561 return m_io->objectExists(m_path);
562 }
563 case StorageObjectType::Attribute: {
564 return m_io->attributeExists(m_path);
565 }
566 default: {
567 throw std::runtime_error("Unsupported StorageObjectType");
568 }
569 }
570 }
571
580 {
581 switch (OTYPE) {
582 case StorageObjectType::Dataset: {
583 return m_io->readDataset(m_path);
584 }
585 case StorageObjectType::Attribute: {
586 return m_io->readAttribute(m_path);
587 }
588 default: {
589 throw std::runtime_error("Unsupported StorageObjectType");
590 }
591 }
592 }
593
608 template<StorageObjectType U = OTYPE,
609 typename std::enable_if<isDataset<U>::value, int>::type = 0>
611 const SizeArray& count = {},
612 const SizeArray& stride = {},
613 const SizeArray& block = {}) const
614 {
615 // The function is only enabled for datasets so we don't need to check
616 // for attributes here.
617 return m_io->readDataset(m_path, start, count, stride, block);
618 }
619
634 template<typename T = VTYPE>
636 {
638 }
639
663 template<typename T = VTYPE,
664 StorageObjectType U = OTYPE,
665 typename std::enable_if<isDataset<U>::value, int>::type = 0>
666 inline DataBlock<VTYPE> values(const SizeArray& start,
667 const SizeArray& count = {},
668 const SizeArray& stride = {},
669 const SizeArray& block = {}) const
670 {
671 // The function is only enabled for datasets so we don't need to check
672 // for attributes here.
674 this->valuesGeneric(start, count, stride, block));
675 }
676
677protected:
681 const std::shared_ptr<IO::BaseIO> m_io;
685 std::string m_path;
686}; // ReadDataWrapper
687
688} // namespace AQNWB::IO
AQNWB::Types::StorageObjectType StorageObjectType
Definition BaseIO.hpp:20
AQNWB::Types::SizeArray SizeArray
Definition BaseIO.hpp:22
AQNWB::Types::SizeType SizeType
Definition Channel.hpp:8
Represents a base data type.
Definition BaseIO.hpp:47
@ T_I32
Signed 32-bit integer.
Definition BaseIO.hpp:60
@ T_I64
Signed 64-bit integer.
Definition BaseIO.hpp:61
@ T_I8
Signed 8-bit integer.
Definition BaseIO.hpp:58
@ T_U32
Unsigned 32-bit integer.
Definition BaseIO.hpp:56
@ T_U64
Unsigned 64-bit integer.
Definition BaseIO.hpp:57
@ T_U8
Unsigned 8-bit integer.
Definition BaseIO.hpp:54
@ T_F32
32-bit floating point
Definition BaseIO.hpp:62
@ T_STR
String.
Definition BaseIO.hpp:64
@ T_F64
64-bit floating point
Definition BaseIO.hpp:63
@ T_U16
Unsigned 16-bit integer.
Definition BaseIO.hpp:55
@ T_I16
Signed 16-bit integer.
Definition BaseIO.hpp:59
std::variant< std::monostate, std::vector< uint8_t >, std::vector< uint16_t >, std::vector< uint32_t >, std::vector< uint64_t >, std::vector< int8_t >, std::vector< int16_t >, std::vector< int32_t >, std::vector< int64_t >, std::vector< float >, std::vector< double >, std::vector< std::string > > BaseDataVectorVariant
Definition BaseIO.hpp:101
static BaseDataType fromTypeId(const std::type_index &typeIndex)
Get the BaseDataType from a std::type_index.
Definition BaseIO.hpp:122
Non-owning, multi-dimensional, read-only array view for contiguous data.
Definition ReadIO.hpp:166
const std::array< size_type, NDIMS > & shape() const
Get the shape of the multi-dimensional array view.
Definition ReadIO.hpp:258
std::array< size_type, NDIMS > m_strides
Stride per dimension.
Definition ReadIO.hpp:263
ConstMultiArrayView< DTYPE, NDIMS - 1 > operator[](size_type index) const
Access a sub-array view at the given index for multi-dimensional arrays.
Definition ReadIO.hpp:210
ConstMultiArrayView(const DTYPE *data, const std::array< size_type, NDIMS > &shape, const std::array< size_type, NDIMS > &strides)
Construct a multi-dimensional view over a contiguous data buffer.
Definition ReadIO.hpp:178
std::size_t size_type
Definition ReadIO.hpp:168
const DTYPE * end() const
Returns a pointer to one past the last element for 1D arrays.
Definition ReadIO.hpp:243
std::array< size_type, NDIMS > m_shape
Size of each dimension.
Definition ReadIO.hpp:262
const DTYPE & operator[](size_type index) const
Access element at the given index for 1D arrays.
Definition ReadIO.hpp:195
const DTYPE * m_data
Pointer to the data buffer.
Definition ReadIO.hpp:261
const DTYPE * begin() const
Returns a pointer to the beginning of the data for 1D arrays.
Definition ReadIO.hpp:230
Generic structure to hold type-erased data and shape.
Definition ReadIO.hpp:34
SizeArray shape
The 1D vector with the n-dimensional shape of the data. Set to empty in case of scalar data.
Definition ReadIO.hpp:48
IO::BaseDataType baseDataType
The base data type for the data block.
Definition ReadIO.hpp:71
DataBlockGeneric()=default
Default constructor.
BaseDataType getBaseDataType() const
Get the BaseDataType for the data.
Definition ReadIO.hpp:97
std::any data
Definition ReadIO.hpp:43
BaseDataType::BaseDataVectorVariant as_variant() const
Cast the data to an std::variant for convenient access.
Definition ReadIO.hpp:109
DataBlockGeneric(const std::any &inData, const SizeArray &inShape, const std::type_index &inTypeIndex, const IO::BaseDataType inBaseDataType)
Parameterized constructor.
Definition ReadIO.hpp:81
std::type_index typeIndex
Type index of the values stored in the data vector.
Definition ReadIO.hpp:68
Structure to hold data and shape for a typed data vector.
Definition ReadIO.hpp:273
SizeArray shape
The 1D vector with the n-dimensional shape of the data. Set to empty in case of scalar data.
Definition ReadIO.hpp:283
static DataBlock< DTYPE > fromGeneric(const DataBlockGeneric &genericData)
Factory method to create an DataBlock from a DataBlockGeneric.
Definition ReadIO.hpp:352
const std::type_index typeIndex
Type index of the values stored in the data vector. Here this is fixed to typeid(DTYPE).
Definition ReadIO.hpp:288
std::vector< DTYPE > data
Definition ReadIO.hpp:278
DataBlock(const std::vector< DTYPE > &inData, const SizeArray &inShape)
Definition ReadIO.hpp:293
BaseDataType getBaseDataType() const
Get the BaseDataType for the data.
Definition ReadIO.hpp:370
ConstMultiArrayView< DTYPE, NDIMS > as_multi_array() const
Transform the data to a multi-dimensional array view for convenient access.
Definition ReadIO.hpp:312
IO::LinkArrayDataSetConfig toLinkArrayDataSetConfig() const
Constructs a AQNWB::IO::LinkArrayDataSetConfig from this wrapper.
Definition ReadIO.hpp:548
static constexpr bool isType()
Function to check at compile-time whether the object is of a particular VTYPE, e.g....
Definition ReadIO.hpp:459
SizeArray getChunking() const
Get the chunking configuration of the data object.
Definition ReadIO.hpp:527
SizeType getNumDimensions() const
Get the number of dimensions of the data object.
Definition ReadIO.hpp:504
ReadDataWrapper & operator=(const ReadDataWrapper &)=delete
Deleted copy assignment operator to prevent copying.
IO::BaseDataType getDataType() const
Get the data type of the data object.
Definition ReadIO.hpp:511
std::string m_path
Path to the dataset or attribute to read.
Definition ReadIO.hpp:685
const std::shared_ptr< IO::BaseIO > m_io
Pointer to the I/O object to use for reading.
Definition ReadIO.hpp:681
DataBlock< VTYPE > values() const
Reads an attribute with a specified data type.
Definition ReadIO.hpp:635
DataBlock< VTYPE > values(const SizeArray &start, const SizeArray &count={}, const SizeArray &stride={}, const SizeArray &block={}) const
Reads an dataset with a specified data type.
Definition ReadIO.hpp:666
DataBlockGeneric valuesGeneric() const
Reads a dataset and determines the data type.
Definition ReadIO.hpp:579
virtual ~ReadDataWrapper()
Destructor.
Definition ReadIO.hpp:477
const std::string & getPath() const
Gets the path of the registered type.
Definition ReadIO.hpp:483
static StorageObjectType getStorageObjectType()
Function to return the AQNWB::Types::StorageObjectType OTYPE of the instance.
Definition ReadIO.hpp:452
std::shared_ptr< IO::BaseIO > getIO() const
Get a shared pointer to the IO object.
Definition ReadIO.hpp:489
bool exists() const
Check that the object exists.
Definition ReadIO.hpp:557
ReadDataWrapper(const std::shared_ptr< IO::BaseIO > io, const std::string &path)
Default constructor.
Definition ReadIO.hpp:442
DataBlockGeneric valuesGeneric(const SizeArray &start, const SizeArray &count={}, const SizeArray &stride={}, const SizeArray &block={}) const
Reads a dataset and determines the data type.
Definition ReadIO.hpp:610
SizeArray getShape() const
Get the shape of the data object.
Definition ReadIO.hpp:495
ReadDataWrapper(const ReadDataWrapper &)=delete
Deleted copy constructor to prevent construction-copying.
StorageObjectType
Types of object used in the NWB schema.
Definition Types.hpp:56
size_t SizeType
Alias for the size type used in the project.
Definition Types.hpp:100
The namespace for IO components of AqNWB.
Internal embedded Trait to Check the OTYPE Enum Value at compile time.
Definition ReadIO.hpp:422
Definition ReadIO.hpp:380