You can not select more than 25 topics
Topics must start with a letter or number, can include dashes ('-') and can be up to 35 characters long.
836 lines
25 KiB
836 lines
25 KiB
#pragma once |
|
#include "merrors.h" |
|
#include <utility> |
|
#include <variant> |
|
|
|
using michlib::Error; |
|
using michlib::int1; |
|
using michlib::int2; |
|
using michlib::int4; |
|
using michlib::int8; |
|
using michlib::int_cast; |
|
using michlib::MString; |
|
using michlib::RetVal; |
|
using michlib::uint1; |
|
using michlib::uint8; |
|
|
|
class NcZarrTypes |
|
{ |
|
protected: |
|
using AttVT = std::variant<std::monostate, int8, uint8, double, MString, bool>; |
|
|
|
class ArrCounter |
|
{ |
|
using VT = std::vector<size_t>; |
|
const VT count; |
|
VT ind; |
|
bool end; |
|
|
|
public: |
|
static size_t Index(const VT& i, const VT& c) |
|
{ |
|
size_t out = 0; |
|
size_t mul = 1; |
|
for(size_t ii = i.size(); ii != 0; ii--) |
|
{ |
|
out += mul * i[ii - 1]; |
|
mul *= c[ii - 1]; |
|
} |
|
return out; |
|
} |
|
|
|
static VT Index(size_t lind, const VT& c) |
|
{ |
|
VT out(c.size()); |
|
|
|
size_t j = lind; |
|
|
|
for(auto i = c.size(); i > 0; i--) |
|
{ |
|
out[i - 1] = j % c[i - 1]; |
|
j = j / c[i - 1]; |
|
} |
|
|
|
return out; |
|
} |
|
|
|
ArrCounter() = delete; |
|
ArrCounter(const VT& cnt): count(cnt), ind(cnt.size(), 0), end(false) {} |
|
|
|
size_t operator[](size_t i) const { return ind[i]; } |
|
|
|
ArrCounter& operator++() |
|
{ |
|
size_t curind = count.size(); |
|
while(curind != 0) |
|
{ |
|
ind[curind - 1]++; |
|
if(ind[curind - 1] >= count[curind - 1]) |
|
{ |
|
ind[curind - 1] = 0; |
|
curind--; |
|
} |
|
else |
|
return *this; |
|
} |
|
ind = count; |
|
end = true; |
|
return *this; |
|
} |
|
|
|
explicit operator bool() const { return !end; } |
|
|
|
size_t Index() const { return Index(ind, count); } |
|
size_t Index(const VT& i) const { return Index(i, count); } |
|
VT Index(size_t lind) const { return Index(lind, count); } |
|
|
|
size_t Count(size_t i) const { return count[i]; } |
|
|
|
const VT& VIndex() const { return ind; } |
|
VT VIndex(const VT& start) const |
|
{ |
|
VT out(ind.size()); |
|
for(size_t i = 0; i < ind.size(); i++) out[i] = ind[i] + start[i]; |
|
return out; |
|
} |
|
|
|
const auto& Count() const { return count; } |
|
|
|
size_t N() const |
|
{ |
|
size_t out = 1; |
|
for(size_t i = 0; i < count.size(); i++) out *= count[i]; |
|
return out; |
|
} |
|
}; |
|
|
|
public: |
|
enum class AttType |
|
{ |
|
UNDEF, |
|
INT, |
|
UINT, |
|
REAL, |
|
STRING, |
|
BOOL |
|
}; |
|
enum class VarType |
|
{ |
|
UNDEF, |
|
FLOAT, |
|
DOUBLE, |
|
INT1, |
|
INT2, |
|
INT4, |
|
INT8, |
|
UINT1 |
|
}; |
|
|
|
protected: |
|
template<VarType VT, class Dummy = void> struct VarType2Type; |
|
|
|
template<class Dummy> struct VarType2Type<VarType::FLOAT, Dummy> |
|
{ |
|
using type = float; |
|
}; |
|
template<class Dummy> struct VarType2Type<VarType::DOUBLE, Dummy> |
|
{ |
|
using type = double; |
|
}; |
|
template<class Dummy> struct VarType2Type<VarType::INT1, Dummy> |
|
{ |
|
using type = int1; |
|
}; |
|
template<class Dummy> struct VarType2Type<VarType::INT2, Dummy> |
|
{ |
|
using type = int2; |
|
}; |
|
template<class Dummy> struct VarType2Type<VarType::INT4, Dummy> |
|
{ |
|
using type = int4; |
|
}; |
|
template<class Dummy> struct VarType2Type<VarType::INT8, Dummy> |
|
{ |
|
using type = int8; |
|
}; |
|
template<class Dummy> struct VarType2Type<VarType::UINT1, Dummy> |
|
{ |
|
using type = uint1; |
|
}; |
|
|
|
template<VarType VT> using Type = VarType2Type<VT>::type; |
|
|
|
static constexpr size_t SizeOf(VarType vt) |
|
{ |
|
switch(vt) |
|
{ |
|
case(VarType::UNDEF): return 0; |
|
case(VarType::FLOAT): return sizeof(Type<VarType::FLOAT>); |
|
case(VarType::DOUBLE): return sizeof(Type<VarType::DOUBLE>); |
|
case(VarType::INT1): return sizeof(Type<VarType::INT1>); |
|
case(VarType::INT2): return sizeof(Type<VarType::INT2>); |
|
case(VarType::INT4): return sizeof(Type<VarType::INT4>); |
|
case(VarType::INT8): return sizeof(Type<VarType::INT8>); |
|
case(VarType::UINT1): return sizeof(Type<VarType::UINT1>); |
|
} |
|
return 0; |
|
} |
|
|
|
template<class T> static size_t FindInd(const MString& name, const std::vector<T>& arr) |
|
{ |
|
for(size_t i = 0; i < arr.size(); i++) |
|
if(arr[i].Name() == name) return i; |
|
return arr.size(); |
|
} |
|
|
|
class Attribute: public AttVT |
|
{ |
|
MString name; |
|
|
|
public: |
|
Attribute(const MString& n, AttVT&& v): AttVT(std::move(v)), name(n) {} |
|
Attribute(const std::string& n, AttVT&& v): AttVT(std::move(v)), name(n.c_str(), n.size()) {} |
|
|
|
const MString& Name() const { return name; } |
|
|
|
AttType Type() const |
|
{ |
|
if(std::holds_alternative<int8>(*this)) |
|
return AttType::INT; |
|
else if(std::holds_alternative<uint8>(*this)) |
|
return AttType::UINT; |
|
else if(std::holds_alternative<double>(*this)) |
|
return AttType::REAL; |
|
else if(std::holds_alternative<MString>(*this)) |
|
return AttType::STRING; |
|
else if(std::holds_alternative<bool>(*this)) |
|
return AttType::BOOL; |
|
|
|
return AttType::UNDEF; |
|
} |
|
|
|
int8 I() const |
|
{ |
|
if(std::holds_alternative<int8>(*this)) |
|
return std::get<int8>(*this); |
|
else if(std::holds_alternative<uint8>(*this)) |
|
return int_cast<int8>(std::get<uint8>(*this)); |
|
else if(std::holds_alternative<double>(*this)) |
|
return static_cast<int8>(std::get<double>(*this)); |
|
else if(std::holds_alternative<MString>(*this)) |
|
return std::get<MString>(*this).ToInteger<int8>(); |
|
else if(std::holds_alternative<bool>(*this)) |
|
return std::get<bool>(*this) ? 1 : 0; |
|
return 0; |
|
} |
|
|
|
uint8 U() const |
|
{ |
|
if(std::holds_alternative<int8>(*this)) |
|
return int_cast<uint8>(std::get<int8>(*this)); |
|
else if(std::holds_alternative<uint8>(*this)) |
|
return std::get<uint8>(*this); |
|
else if(std::holds_alternative<double>(*this)) |
|
return static_cast<uint8>(std::get<double>(*this)); |
|
else if(std::holds_alternative<MString>(*this)) |
|
return std::get<MString>(*this).ToInteger<uint8>(); |
|
else if(std::holds_alternative<bool>(*this)) |
|
return std::get<bool>(*this) ? 1 : 0; |
|
return 0; |
|
} |
|
|
|
double D() const |
|
{ |
|
if(std::holds_alternative<int8>(*this)) |
|
return std::get<int8>(*this); |
|
else if(std::holds_alternative<uint8>(*this)) |
|
return std::get<uint8>(*this); |
|
else if(std::holds_alternative<double>(*this)) |
|
return std::get<double>(*this); |
|
else if(std::holds_alternative<MString>(*this)) |
|
return michlib_internal::RealType<sizeof(double)>::String2Real(std::get<MString>(*this).Buf()); |
|
else if(std::holds_alternative<bool>(*this)) |
|
return std::get<bool>(*this) ? 1 : 0; |
|
return 0; |
|
} |
|
|
|
MString S() const |
|
{ |
|
if(std::holds_alternative<int8>(*this)) |
|
return MString().FromInt(std::get<int8>(*this)); |
|
else if(std::holds_alternative<uint8>(*this)) |
|
return MString().FromUInt(std::get<uint8>(*this)); |
|
else if(std::holds_alternative<double>(*this)) |
|
return MString().FromReal(std::get<double>(*this)); |
|
else if(std::holds_alternative<MString>(*this)) |
|
return std::get<MString>(*this); |
|
else if(std::holds_alternative<bool>(*this)) |
|
return MString().FromBool(std::get<bool>(*this)); |
|
return ""; |
|
} |
|
|
|
bool B() const |
|
{ |
|
if(std::holds_alternative<int8>(*this)) |
|
return std::get<int8>(*this) != 0; |
|
else if(std::holds_alternative<uint8>(*this)) |
|
return std::get<uint8>(*this) != 0; |
|
else if(std::holds_alternative<double>(*this)) |
|
return std::get<double>(*this) != 0.0; |
|
else if(std::holds_alternative<MString>(*this)) |
|
return std::get<MString>(*this).ToBool(); |
|
else if(std::holds_alternative<bool>(*this)) |
|
return std::get<bool>(*this); |
|
return false; |
|
} |
|
}; |
|
|
|
class Dimension |
|
{ |
|
MString name; |
|
size_t size; |
|
|
|
public: |
|
Dimension(const MString& str, size_t num): name(str), size(num) {} |
|
const MString& Name() const { return name; } |
|
|
|
size_t Size() const { return size; } |
|
}; |
|
|
|
class Variable |
|
{ |
|
public: |
|
using FillType = std::variant<std::monostate, int8, uint8, double>; |
|
|
|
private: |
|
MString name; |
|
VarType type = VarType::UNDEF; |
|
std::vector<size_t> dims; |
|
std::vector<Attribute> atts; |
|
FillType fill; |
|
|
|
public: |
|
Variable(const MString& name_, VarType type_, std::vector<size_t>&& dims_, std::vector<Attribute>&& atts_, FillType fill_ = 0): |
|
name(name_), type(type_), dims(std::move(dims_)), atts(std::move(atts_)), fill(fill_) |
|
{ |
|
} |
|
|
|
explicit operator bool() const { return type != VarType::UNDEF; } |
|
|
|
const auto& Dims() const { return dims; } |
|
|
|
size_t NDim() const { return dims.size(); } |
|
|
|
size_t NAtt() const { return atts.size(); } |
|
|
|
auto AttNames() const |
|
{ |
|
std::vector<MString> out; |
|
std::transform(atts.cbegin(), atts.cend(), std::back_inserter(out), [](const Attribute& a) { return a.Name(); }); |
|
return out; |
|
} |
|
|
|
AttType AttT(const MString& name) const |
|
{ |
|
size_t ind = FindInd(name, atts); |
|
return ind < atts.size() ? atts[ind].Type() : AttType::UNDEF; |
|
} |
|
|
|
int8 AttInt(const MString& name) const |
|
{ |
|
size_t ind = FindInd(name, atts); |
|
return ind < atts.size() ? atts[ind].I() : 0; |
|
} |
|
|
|
uint8 AttUInt(const MString& name) const |
|
{ |
|
size_t ind = FindInd(name, atts); |
|
return ind < atts.size() ? atts[ind].U() : 0; |
|
} |
|
|
|
double AttReal(const MString& name) const |
|
{ |
|
size_t ind = FindInd(name, atts); |
|
return ind < atts.size() ? atts[ind].D() : 0.0; |
|
} |
|
|
|
MString AttString(const MString& name) const |
|
{ |
|
size_t ind = FindInd(name, atts); |
|
return ind < atts.size() ? atts[ind].S() : MString(); |
|
} |
|
|
|
bool AttBool(const MString& name) const |
|
{ |
|
size_t ind = FindInd(name, atts); |
|
return ind < atts.size() ? atts[ind].B() : false; |
|
} |
|
|
|
const MString& Name() const { return name; } |
|
|
|
auto Type() const { return type; } |
|
|
|
const auto& Fill() const { return fill; } |
|
}; |
|
|
|
protected: |
|
std::vector<Attribute> gats; |
|
std::vector<Dimension> dims; |
|
std::vector<Variable> vars; |
|
|
|
public: |
|
operator bool() const { return !vars.empty(); } |
|
|
|
size_t NDim() const { return dims.size(); } |
|
|
|
size_t NDim(const MString& var) const |
|
{ |
|
size_t ind = FindInd(var, vars); |
|
return ind < vars.size() ? vars[ind].NDim() : 0; |
|
} |
|
|
|
size_t NAtt() const { return gats.size(); } |
|
|
|
auto AttNames() const |
|
{ |
|
std::vector<MString> out; |
|
std::transform(gats.cbegin(), gats.cend(), std::back_inserter(out), [](const Attribute& a) { return a.Name(); }); |
|
return out; |
|
} |
|
|
|
size_t NAtt(const MString& var) const |
|
{ |
|
if(!var.Exist()) return NAtt(); |
|
size_t ind = FindInd(var, vars); |
|
return ind < vars.size() ? vars[ind].NAtt() : 0; |
|
} |
|
|
|
auto AttNames(const MString& var) const |
|
{ |
|
if(!var.Exist()) return AttNames(); |
|
size_t ind = FindInd(var, vars); |
|
return ind < vars.size() ? vars[ind].AttNames() : decltype(AttNames())(); |
|
} |
|
|
|
auto VarNames() const |
|
{ |
|
std::vector<MString> out; |
|
std::transform(vars.cbegin(), vars.cend(), std::back_inserter(out), [](const Variable& v) { return v.Name(); }); |
|
return out; |
|
} |
|
|
|
VarType VarT(const MString& var) const |
|
{ |
|
size_t ind = FindInd(var, vars); |
|
return ind < vars.size() ? vars[ind].Type() : VarType::UNDEF; |
|
} |
|
|
|
auto VarFill(const MString& var) const |
|
{ |
|
size_t ind = FindInd(var, vars); |
|
return ind < vars.size() ? vars[ind].Fill() : Variable::FillType(); |
|
} |
|
|
|
auto DimNames() const |
|
{ |
|
std::vector<MString> out; |
|
std::transform(dims.cbegin(), dims.cend(), std::back_inserter(out), [](const Dimension& d) { return d.Name(); }); |
|
return out; |
|
} |
|
|
|
auto DimNames(const MString& var) const |
|
{ |
|
size_t ind = FindInd(var, vars); |
|
|
|
std::vector<MString> out; |
|
if(ind >= vars.size()) return out; |
|
|
|
auto vdims = vars[ind].Dims(); |
|
std::transform(vdims.cbegin(), vdims.cend(), std::back_inserter(out), [&dims = std::as_const(dims)](const size_t& i) { return dims[i].Name(); }); |
|
return out; |
|
} |
|
|
|
size_t DimSize(const MString& dim) const |
|
{ |
|
size_t ind = FindInd(dim, dims); |
|
return ind < dims.size() ? dims[ind].Size() : 0; |
|
} |
|
|
|
AttType AttT(const MString& var, const MString& name) const |
|
{ |
|
if(!var.Exist()) |
|
{ |
|
size_t ind = FindInd(name, gats); |
|
return ind < gats.size() ? gats[ind].Type() : AttType::UNDEF; |
|
} |
|
|
|
size_t ind = FindInd(var, vars); |
|
return ind < vars.size() ? vars[ind].AttT(name) : AttType::UNDEF; |
|
} |
|
|
|
int8 AttInt(const MString& var, const MString& name) const |
|
{ |
|
if(!var.Exist()) |
|
{ |
|
size_t ind = FindInd(name, gats); |
|
return ind < gats.size() ? gats[ind].I() : 0; |
|
} |
|
|
|
size_t ind = FindInd(var, vars); |
|
return ind < vars.size() ? vars[ind].AttInt(name) : 0; |
|
} |
|
|
|
uint8 AttUInt(const MString& var, const MString& name) const |
|
{ |
|
if(!var.Exist()) |
|
{ |
|
size_t ind = FindInd(name, gats); |
|
return ind < gats.size() ? gats[ind].U() : 0; |
|
} |
|
|
|
size_t ind = FindInd(var, vars); |
|
return ind < vars.size() ? vars[ind].AttUInt(name) : 0; |
|
} |
|
|
|
double AttReal(const MString& var, const MString& name) const |
|
{ |
|
if(!var.Exist()) |
|
{ |
|
size_t ind = FindInd(name, gats); |
|
return ind < gats.size() ? gats[ind].D() : 0.0; |
|
} |
|
|
|
size_t ind = FindInd(var, vars); |
|
return ind < vars.size() ? vars[ind].AttReal(name) : 0.0; |
|
} |
|
|
|
MString AttString(const MString& var, const MString& name) const |
|
{ |
|
if(!var.Exist()) |
|
{ |
|
size_t ind = FindInd(name, gats); |
|
return ind < gats.size() ? gats[ind].S() : MString(); |
|
} |
|
|
|
size_t ind = FindInd(var, vars); |
|
return ind < vars.size() ? vars[ind].AttString(name) : MString(); |
|
} |
|
|
|
bool AttBool(const MString& var, const MString& name) const |
|
{ |
|
if(!var.Exist()) |
|
{ |
|
size_t ind = FindInd(name, gats); |
|
return ind < gats.size() ? gats[ind].B() : false; |
|
} |
|
|
|
size_t ind = FindInd(var, vars); |
|
return ind < vars.size() ? vars[ind].AttBool(name) : false; |
|
} |
|
|
|
auto AttT(const MString& name) const { return AttT("", name); } |
|
auto AttInt(const MString& name) const { return AttInt("", name); } |
|
auto AttUInt(const MString& name) const { return AttUInt("", name); } |
|
auto AttReal(const MString& name) const { return AttReal("", name); } |
|
auto AttString(const MString& name) const { return AttString("", name); } |
|
auto AttBool(const MString& name) const { return AttBool("", name); } |
|
|
|
bool HasDim(const MString& name) const { return FindInd(name, dims) < dims.size(); } |
|
bool HasVar(const MString& name) const { return FindInd(name, vars) < vars.size(); } |
|
bool HasAtt(const MString& vname, const MString& aname) const { return AttT(vname, aname) != AttType::UNDEF; } |
|
bool HasAtt(const MString& aname) const { return AttT(aname) != AttType::UNDEF; } |
|
|
|
const auto& Vars() const { return vars; } |
|
const auto& Dims() const { return dims; } |
|
}; |
|
|
|
class DimReqDef |
|
{ |
|
protected: |
|
struct DimReq |
|
{ |
|
static const auto fill = std::numeric_limits<size_t>::max(); |
|
MString name; |
|
size_t beg, count; |
|
|
|
DimReq(): name(MString()), beg(fill), count(fill) {} |
|
DimReq(const char* n): name(n), beg(fill), count(fill) {} |
|
DimReq(const MString& n): name(n), beg(fill), count(fill) {} |
|
DimReq(MString&& n): name(std::move(n)), beg(fill), count(fill) {} |
|
DimReq(const char* n, size_t s): name(n), beg(s), count(fill) {} |
|
DimReq(const MString& n, size_t s): name(n), beg(s), count(fill) {} |
|
DimReq(MString&& n, size_t s): name(std::move(n)), beg(s), count(fill) {} |
|
DimReq(const char* n, size_t s, size_t c): name(n), beg(s), count(c) {} |
|
DimReq(const MString& n, size_t s, size_t c): name(n), beg(s), count(c) {} |
|
DimReq(MString&& n, size_t s, size_t c): name(std::move(n)), beg(s), count(c) {} |
|
|
|
const MString& Name() const { return name; } |
|
}; |
|
}; |
|
|
|
template<class C> class NcZarrRead: public C, public DimReqDef |
|
{ |
|
template<class Data> static constexpr size_t Dimensionity() |
|
{ |
|
if constexpr(requires(Data& d) { d(0, 0, 0, 0); }) return 4; |
|
if constexpr(requires(Data& d) { d(0, 0, 0); }) return 3; |
|
if constexpr(requires(Data& d) { d(0, 0); }) return 2; |
|
if constexpr(requires(Data& d) { d(0); }) return 1; |
|
return 0; |
|
} |
|
|
|
template<class Data, size_t D, class Dummy = void> struct DataTypeExtractorS; |
|
|
|
template<class Data, class Dummy> struct DataTypeExtractorS<Data, 1, Dummy> |
|
{ |
|
using type = std::decay_t<decltype(std::declval<Data>()(0))>; |
|
}; |
|
template<class Data, class Dummy> struct DataTypeExtractorS<Data, 2, Dummy> |
|
{ |
|
using type = std::decay_t<decltype(std::declval<Data>()(0, 0))>; |
|
}; |
|
template<class Data, class Dummy> struct DataTypeExtractorS<Data, 3, Dummy> |
|
{ |
|
using type = std::decay_t<decltype(std::declval<Data>()(0, 0, 0))>; |
|
}; |
|
template<class Data, class Dummy> struct DataTypeExtractorS<Data, 4, Dummy> |
|
{ |
|
using type = std::decay_t<decltype(std::declval<Data>()(0, 0, 0, 0))>; |
|
}; |
|
|
|
template<class Data> using DataTypeExtractor = DataTypeExtractorS<Data, Dimensionity<Data>()>::type; |
|
|
|
template<class VType, class Data, class Transform> |
|
Error Read(const MString& vname, const std::vector<size_t>& transindex, Data& data, Transform transform, std::vector<DimReq> reqs) const |
|
{ |
|
size_t nval = 1; |
|
for(const auto& r: reqs) nval *= r.count; |
|
const size_t indim = reqs.size(); |
|
constexpr size_t outdim = Dimensionity<Data>(); |
|
|
|
std::vector<size_t> start; |
|
std::vector<size_t> count; |
|
|
|
start.resize(indim); |
|
count.resize(indim); |
|
for(size_t i = 0; i < indim; i++) |
|
{ |
|
start[i] = reqs[i].beg; |
|
count[i] = reqs[i].count; |
|
} |
|
|
|
using DataType = DataTypeExtractor<Data>; |
|
DataType fillout; |
|
bool havefill = C::VarFill(vname).index() > 0; |
|
VType fillin = std::visit( |
|
[](auto v) |
|
{ |
|
if constexpr(std::is_convertible_v<decltype(v), VType>) |
|
return static_cast<VType>(v); |
|
else |
|
return std::numeric_limits<VType>::max(); |
|
}, |
|
C::VarFill(vname)); |
|
|
|
if constexpr(requires(Data& d) { // Data have own fillvalue |
|
{ |
|
d.Fillval() |
|
} -> std::convertible_to<DataType>; |
|
}) |
|
fillout = data.Fillval(); |
|
else // Data does'nt have own fillvalue, using variable fillvalue |
|
fillout = static_cast<DataType>(fillin); |
|
|
|
auto ret = C::template Read<VType>(vname, start.data(), count.data()); |
|
if(!ret) return ret; |
|
const auto& rawdata = ret.Value(); |
|
|
|
std::vector<size_t> mul(indim, 1); |
|
for(size_t i = indim - 1; i > 0; i--) mul[i - 1] = mul[i] * count[i]; |
|
|
|
size_t inind = 0; |
|
for(typename C::ArrCounter i(count); i; ++i) |
|
{ |
|
// TODO: Remove this testing block |
|
size_t cind = 0; |
|
for(size_t j = 0; j < indim; j++) cind += i[j] * mul[j]; |
|
if(cind != inind) return {"NcZarrRead::Read", "Internal error"}; |
|
if(i.Index() != inind) return {"NcZarrRead::Read", "Internal error"}; |
|
if(inind != i.Index(i.Index(inind, count), count)) return {"NcZarrRead::Read", "Internal error"}; |
|
|
|
DataType out; |
|
const VType& in = rawdata(inind); |
|
if(havefill && in == fillin) |
|
out = fillout; |
|
else |
|
out = transform(in); |
|
|
|
if constexpr(outdim == 1) |
|
data(i[transindex[0]]) = out; |
|
else if constexpr(outdim == 2) |
|
data(i[transindex[0]], i[transindex[1]]) = out; |
|
else if constexpr(outdim == 3) |
|
data(i[transindex[0]], i[transindex[1]], i[transindex[2]]) = out; |
|
else if constexpr(outdim == 4) |
|
data(i[transindex[0]], i[transindex[1]], i[transindex[2]], i[transindex[3]]) = out; |
|
|
|
inind++; |
|
} |
|
|
|
return Error(); |
|
} |
|
|
|
public: |
|
// Request is string |
|
template<class Data, class Transform> Error Read(const MString& vname, Data& data, Transform transform, const char* request) const |
|
{ |
|
return Read(vname, data, transform, MString(request)); |
|
} |
|
|
|
// Request by one dimension |
|
template<class Data, class Transform> Error Read(const MString& vname, Data& data, Transform transform, DimReq&& req1) const |
|
{ |
|
return Read(vname, data, transform, std::vector<DimReq>{std::move(req1)}); |
|
} |
|
// Request by two dimension |
|
template<class Data, class Transform> Error Read(const MString& vname, Data& data, Transform transform, DimReq&& req1, DimReq&& req2) const |
|
{ |
|
return Read(vname, data, transform, std::vector<DimReq>{std::move(req1), std::move(req2)}); |
|
} |
|
// Request by three dimension |
|
template<class Data, class Transform> Error Read(const MString& vname, Data& data, Transform transform, DimReq&& req1, DimReq&& req2, DimReq&& req3) const |
|
{ |
|
return Read(vname, data, transform, std::vector<DimReq>{std::move(req1), std::move(req2), std::move(req3)}); |
|
} |
|
// Request by four dimension |
|
template<class Data, class Transform> Error Read(const MString& vname, Data& data, Transform transform, DimReq&& req1, DimReq&& req2, DimReq&& req3, DimReq&& req4) const |
|
{ |
|
return Read(vname, data, transform, std::vector<DimReq>{std::move(req1), std::move(req2), std::move(req3), std::move(req4)}); |
|
} |
|
|
|
// Request full variable |
|
template<class Data, class Transform> Error Read(const MString& vname, Data& data, Transform transform) const |
|
{ |
|
static const MString pref = "NcZarrRead::Read"; |
|
if(!C::HasVar(vname)) return {pref, "Variable " + vname + " not found"}; |
|
|
|
std::vector<struct DimReq> pdims; |
|
|
|
const auto vdims = C::DimNames(vname); |
|
std::transform( |
|
vdims.cbegin(), vdims.cend(), std::back_inserter(pdims), [this](const MString& n) -> struct DimReq { |
|
return {n, 0, C::DimSize(n)}; |
|
}); |
|
|
|
return Read(vname, data, transform, pdims); |
|
} |
|
|
|
// Base function for all Read's |
|
template<class Data, class Transform> Error Read(const MString& vname, Data& data, Transform transform, std::vector<DimReq> reqs) const |
|
{ |
|
static const MString pref = "NcZarrRead::Read"; |
|
|
|
if(!C::HasVar(vname)) return {pref, "Variable " + vname + " not found"}; |
|
|
|
std::vector<struct DimReq> pdims; |
|
{ |
|
const auto vdims = C::DimNames(vname); |
|
std::transform( |
|
vdims.cbegin(), vdims.cend(), std::back_inserter(pdims), [](const MString& n) -> struct DimReq { |
|
return {n, 0, 1}; |
|
}); |
|
} |
|
|
|
std::vector<size_t> transindex; |
|
|
|
// Parse request |
|
if(reqs.size() == 0) return {pref, "Empty request"}; |
|
for(const auto& req: reqs) |
|
{ |
|
size_t ind = C::FindInd(req.name, pdims); |
|
if(ind >= pdims.size()) return {pref, "Variable " + vname + " has no dimension " + req.name}; |
|
|
|
for(size_t i = 0; i < transindex.size(); i++) |
|
if(transindex[i] == ind) return {pref, "Parameters for dimension " + req.name + " already defined"}; |
|
transindex.push_back(ind); |
|
|
|
size_t dlen = C::DimSize(pdims[ind].name); |
|
if(req.beg == req.fill && req.count == req.fill) // Only name, so, we request full length |
|
{ |
|
pdims[ind].beg = 0; |
|
pdims[ind].count = dlen; |
|
} |
|
else if(req.count == req.fill) // Name and first index |
|
{ |
|
pdims[ind].beg = req.beg; |
|
pdims[ind].count = 1; |
|
} |
|
else // Name, first index, count |
|
{ |
|
pdims[ind].beg = req.beg; |
|
pdims[ind].count = req.count; |
|
} |
|
// Sanity checks |
|
if(pdims[ind].count <= 0) return {pref, "Error parsing request: count must be greter then zero"}; |
|
if(pdims[ind].beg >= dlen) return {pref, MString("Error parsing request: start index ") + pdims[ind].beg + " must be lesser then " + pdims[ind].name + " size " + dlen}; |
|
if(pdims[ind].beg + pdims[ind].count > dlen) |
|
return {pref, MString("Error parsing request: start index ") + pdims[ind].beg + " with count " + pdims[ind].count + " exceeds " + pdims[ind].name + " size " + dlen}; |
|
|
|
// Ignore hyperplanes in requests for calculation of data dimensionality |
|
if(pdims[transindex.back()].count == 1) transindex.pop_back(); |
|
} |
|
|
|
if(transindex.size() != Dimensionity<Data>()) |
|
return {pref, MString("Output data dimensions (") + Dimensionity<Data>() + ") not corresponding request dimensions (" + transindex.size() + ")"}; |
|
switch(C::VarT(vname)) |
|
{ |
|
case(C::VarType::UNDEF): return {pref, "No variable with name " + vname + " (impossible)"}; |
|
case(C::VarType::FLOAT): return Read<typename C::template Type<C::VarType::FLOAT>>(vname, transindex, data, transform, pdims); |
|
case(C::VarType::DOUBLE): return Read<typename C::template Type<C::VarType::DOUBLE>>(vname, transindex, data, transform, pdims); |
|
case(C::VarType::INT1): return Read<typename C::template Type<C::VarType::INT1>>(vname, transindex, data, transform, pdims); |
|
case(C::VarType::INT2): return Read<typename C::template Type<C::VarType::INT2>>(vname, transindex, data, transform, pdims); |
|
case(C::VarType::INT4): return Read<typename C::template Type<C::VarType::INT4>>(vname, transindex, data, transform, pdims); |
|
case(C::VarType::INT8): return Read<typename C::template Type<C::VarType::INT8>>(vname, transindex, data, transform, pdims); |
|
case(C::VarType::UINT1): return Read<typename C::template Type<C::VarType::INT1>>(vname, transindex, data, transform, pdims); |
|
} |
|
|
|
return {pref, "Internal error (impossible)"}; |
|
} |
|
|
|
// Request by string argument |
|
template<class Data, class Transform> Error Read(const MString& vname, Data& data, Transform transform, const MString& request) const |
|
{ |
|
static const MString pref = "NcZarrRead::Read"; |
|
|
|
std::vector<struct DimReq> pdims; |
|
|
|
// Parse request |
|
const auto dimdesc = request.Split(";, \t"); |
|
if(dimdesc.size() == 0) return {pref, "Empty request"}; |
|
for(const auto& dd: dimdesc) |
|
{ |
|
const auto dimpar = dd.Split(":", true); |
|
|
|
if(dimpar.size() == 1) // Only name, so, we request full length |
|
pdims.emplace_back(dimpar[0]); |
|
else if(dimpar.size() == 2) // Name and first index |
|
pdims.emplace_back(dimpar[0], dimpar[1].ToInteger<size_t>()); |
|
else if(dimpar.size() == 3) // Name, first index, count |
|
pdims.emplace_back(dimpar[0], dimpar[1].ToInteger<size_t>(), dimpar[2].ToInteger<size_t>()); |
|
else |
|
return {pref, "Can't parse expression " + dd}; |
|
} |
|
|
|
return Read(vname, data, transform, pdims); |
|
} |
|
|
|
// Request full one-dimensional variable |
|
template<class Type> Error Read(const MString& vname, std::vector<Type>& out) const |
|
{ |
|
const auto& dnames = C::DimNames(vname); |
|
if(dnames.size() > 0) out.resize(C::DimSize(dnames[0])); |
|
auto data = [&vec = out](size_t i) -> Type& { return vec[i]; }; |
|
|
|
return Read(vname, data, std::identity()); |
|
} |
|
};
|
|
|