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.
823 lines
24 KiB
823 lines
24 KiB
6 months ago
|
#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; }
|
||
|
};
|
||
|
|
||
|
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++;
|
||
|
}
|
||
|
|
||
|
michlib::message("Variable " + vname + ", request size " + nval);
|
||
|
for(const auto& r: reqs) michlib::message(r.name + " from " + r.beg + ", count " + r.count);
|
||
|
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};
|
||
|
}
|
||
|
|
||
|
if(transindex.size() != Dimensionity<Data>()) return {pref, "Output data dimensions not correspondind request dimensions"};
|
||
|
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::UINT1>>(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);
|
||
|
}
|
||
|
};
|