mirror of
https://github.com/paboyle/Grid.git
synced 2025-04-25 13:15:55 +01:00
Extended HDF5 serialisation of std::vector<T> where T now also includes Grid scalar/vector/matrix
Changed VectorUtils element traits to is_flattenable, because: a) contract changed on what it does; and b) no other Grid dependencies on element. Needs review. Initial tests work ... needs proper regression testing.
This commit is contained in:
parent
ef0ddd5d04
commit
7b89232251
@ -36,10 +36,10 @@ namespace Grid
|
|||||||
template <typename U>
|
template <typename U>
|
||||||
void writeRagged(const std::string &s, const std::vector<U> &x);
|
void writeRagged(const std::string &s, const std::vector<U> &x);
|
||||||
template <typename U>
|
template <typename U>
|
||||||
typename std::enable_if<element<std::vector<U>>::is_number, void>::type
|
typename std::enable_if<is_flattenable<std::vector<U>>::value>::type
|
||||||
writeDefault(const std::string &s, const std::vector<U> &x);
|
writeDefault(const std::string &s, const std::vector<U> &x);
|
||||||
template <typename U>
|
template <typename U>
|
||||||
typename std::enable_if<!element<std::vector<U>>::is_number, void>::type
|
typename std::enable_if<!is_flattenable<std::vector<U>>::value>::type
|
||||||
writeDefault(const std::string &s, const std::vector<U> &x) { writeRagged(s, x); }
|
writeDefault(const std::string &s, const std::vector<U> &x) { writeRagged(s, x); }
|
||||||
template <typename U>
|
template <typename U>
|
||||||
void writeMultiDim(const std::string &s, const std::vector<size_t> & Dimensions, const U * pDataRowMajor, size_t NumElements);
|
void writeMultiDim(const std::string &s, const std::vector<size_t> & Dimensions, const U * pDataRowMajor, size_t NumElements);
|
||||||
@ -68,10 +68,10 @@ namespace Grid
|
|||||||
template <typename U>
|
template <typename U>
|
||||||
void readRagged(const std::string &s, std::vector<U> &x);
|
void readRagged(const std::string &s, std::vector<U> &x);
|
||||||
template <typename U>
|
template <typename U>
|
||||||
typename std::enable_if<element<std::vector<U>>::is_number, void>::type
|
typename std::enable_if<is_flattenable<std::vector<U>>::value>::type
|
||||||
readDefault(const std::string &s, std::vector<U> &x);
|
readDefault(const std::string &s, std::vector<U> &x);
|
||||||
template <typename U>
|
template <typename U>
|
||||||
typename std::enable_if<!element<std::vector<U>>::is_number, void>::type
|
typename std::enable_if<!is_flattenable<std::vector<U>>::value>::type
|
||||||
readDefault(const std::string &s, std::vector<U> &x) { readRagged(s, x); }
|
readDefault(const std::string &s, std::vector<U> &x) { readRagged(s, x); }
|
||||||
template <typename U>
|
template <typename U>
|
||||||
void readMultiDim(const std::string &s, std::vector<U> &buf, std::vector<size_t> &dim);
|
void readMultiDim(const std::string &s, std::vector<U> &buf, std::vector<size_t> &dim);
|
||||||
@ -180,13 +180,13 @@ namespace Grid
|
|||||||
}
|
}
|
||||||
|
|
||||||
template <typename U>
|
template <typename U>
|
||||||
typename std::enable_if<element<std::vector<U>>::is_number, void>::type
|
typename std::enable_if<is_flattenable<std::vector<U>>::value>::type
|
||||||
Hdf5Writer::writeDefault(const std::string &s, const std::vector<U> &x)
|
Hdf5Writer::writeDefault(const std::string &s, const std::vector<U> &x)
|
||||||
{
|
{
|
||||||
if (isFlat(x))
|
if (isRegularShape(x))
|
||||||
{
|
{
|
||||||
// alias to element type
|
// alias to element type
|
||||||
typedef typename element<std::vector<U>>::type Element;
|
using Scalar = typename is_flattenable<std::vector<U>>::type;
|
||||||
|
|
||||||
// flatten the vector and getting dimensions
|
// flatten the vector and getting dimensions
|
||||||
Flatten<std::vector<U>> flat(x);
|
Flatten<std::vector<U>> flat(x);
|
||||||
@ -194,7 +194,7 @@ namespace Grid
|
|||||||
const auto &flatx = flat.getFlatVector();
|
const auto &flatx = flat.getFlatVector();
|
||||||
for (auto &d: flat.getDim())
|
for (auto &d: flat.getDim())
|
||||||
dim.push_back(d);
|
dim.push_back(d);
|
||||||
writeMultiDim<Element>(s, dim, &flatx[0], flatx.size());
|
writeMultiDim<Scalar>(s, dim, &flatx[0], flatx.size());
|
||||||
}
|
}
|
||||||
else
|
else
|
||||||
{
|
{
|
||||||
@ -239,7 +239,7 @@ namespace Grid
|
|||||||
void Hdf5Reader::readMultiDim(const std::string &s, std::vector<U> &buf, std::vector<size_t> &dim)
|
void Hdf5Reader::readMultiDim(const std::string &s, std::vector<U> &buf, std::vector<size_t> &dim)
|
||||||
{
|
{
|
||||||
// alias to element type
|
// alias to element type
|
||||||
typedef typename element<std::vector<U>>::type Element;
|
using Scalar = typename is_flattenable<std::vector<U>>::type;
|
||||||
|
|
||||||
// read the dimensions
|
// read the dimensions
|
||||||
H5NS::DataSpace dataSpace;
|
H5NS::DataSpace dataSpace;
|
||||||
@ -270,19 +270,19 @@ namespace Grid
|
|||||||
H5NS::DataSet dataSet;
|
H5NS::DataSet dataSet;
|
||||||
|
|
||||||
dataSet = group_.openDataSet(s);
|
dataSet = group_.openDataSet(s);
|
||||||
dataSet.read(buf.data(), Hdf5Type<Element>::type());
|
dataSet.read(buf.data(), Hdf5Type<Scalar>::type());
|
||||||
}
|
}
|
||||||
else
|
else
|
||||||
{
|
{
|
||||||
H5NS::Attribute attribute;
|
H5NS::Attribute attribute;
|
||||||
|
|
||||||
attribute = group_.openAttribute(s);
|
attribute = group_.openAttribute(s);
|
||||||
attribute.read(Hdf5Type<Element>::type(), buf.data());
|
attribute.read(Hdf5Type<Scalar>::type(), buf.data());
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
template <typename U>
|
template <typename U>
|
||||||
typename std::enable_if<element<std::vector<U>>::is_number, void>::type
|
typename std::enable_if<is_flattenable<std::vector<U>>::value>::type
|
||||||
Hdf5Reader::readDefault(const std::string &s, std::vector<U> &x)
|
Hdf5Reader::readDefault(const std::string &s, std::vector<U> &x)
|
||||||
{
|
{
|
||||||
if (H5Lexists (group_.getId(), s.c_str(), H5P_DEFAULT) > 0
|
if (H5Lexists (group_.getId(), s.c_str(), H5P_DEFAULT) > 0
|
||||||
@ -293,10 +293,10 @@ namespace Grid
|
|||||||
else
|
else
|
||||||
{
|
{
|
||||||
// alias to element type
|
// alias to element type
|
||||||
typedef typename element<std::vector<U>>::type Element;
|
using Scalar = typename is_flattenable<std::vector<U>>::type;
|
||||||
|
|
||||||
std::vector<size_t> dim;
|
std::vector<size_t> dim;
|
||||||
std::vector<Element> buf;
|
std::vector<Scalar> buf;
|
||||||
readMultiDim( s, buf, dim );
|
readMultiDim( s, buf, dim );
|
||||||
|
|
||||||
// reconstruct the multidimensional vector
|
// reconstruct the multidimensional vector
|
||||||
|
@ -236,21 +236,36 @@ namespace Grid {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
// Vector element trait //////////////////////////////////////////////////////
|
// is_flattenable<T>::value is true if T is a std::vector<> which can be flattened //////////////////////
|
||||||
template <typename T>
|
template <typename T, typename V = void>
|
||||||
struct element
|
struct is_flattenable : std::false_type
|
||||||
{
|
{
|
||||||
typedef T type;
|
using type = T;
|
||||||
static constexpr bool is_number = false;
|
using grid_type = T;
|
||||||
|
static constexpr int vecRank = 0;
|
||||||
|
static constexpr bool isGridTensor = false;
|
||||||
|
static constexpr bool children_flattenable = std::is_arithmetic<T>::value or is_complex<T>::value;
|
||||||
};
|
};
|
||||||
|
|
||||||
template <typename T>
|
template <typename T>
|
||||||
struct element<std::vector<T>>
|
struct is_flattenable<T, typename std::enable_if<isGridTensor<T>::value>::type> : std::false_type
|
||||||
{
|
{
|
||||||
typedef typename element<T>::type type;
|
using type = typename GridTypeMapper<T>::scalar_type;
|
||||||
static constexpr bool is_number = std::is_arithmetic<T>::value
|
using grid_type = T;
|
||||||
or is_complex<T>::value
|
static constexpr int vecRank = 0;
|
||||||
or element<T>::is_number;
|
static constexpr bool isGridTensor = true;
|
||||||
|
static constexpr bool children_flattenable = true;
|
||||||
|
};
|
||||||
|
|
||||||
|
template <typename T>
|
||||||
|
struct is_flattenable<std::vector<T>, typename std::enable_if<is_flattenable<T>::children_flattenable>::type>
|
||||||
|
: std::true_type
|
||||||
|
{
|
||||||
|
using type = typename is_flattenable<T>::type;
|
||||||
|
using grid_type = typename is_flattenable<T>::grid_type;
|
||||||
|
static constexpr bool isGridTensor = is_flattenable<T>::isGridTensor;
|
||||||
|
static constexpr int vecRank = is_flattenable<T>::vecRank + 1;
|
||||||
|
static constexpr bool children_flattenable = true;
|
||||||
};
|
};
|
||||||
|
|
||||||
// Vector flattening utility class ////////////////////////////////////////////
|
// Vector flattening utility class ////////////////////////////////////////////
|
||||||
@ -259,23 +274,30 @@ namespace Grid {
|
|||||||
class Flatten
|
class Flatten
|
||||||
{
|
{
|
||||||
public:
|
public:
|
||||||
typedef typename element<V>::type Element;
|
using Scalar = typename is_flattenable<V>::type;
|
||||||
|
static constexpr bool isGridTensor = is_flattenable<V>::isGridTensor;
|
||||||
public:
|
public:
|
||||||
explicit Flatten(const V &vector);
|
explicit Flatten(const V &vector);
|
||||||
const V & getVector(void);
|
const V & getVector(void) const { return vector_; }
|
||||||
const std::vector<Element> & getFlatVector(void);
|
const std::vector<Scalar> & getFlatVector(void) const { return flatVector_; }
|
||||||
const std::vector<size_t> & getDim(void);
|
const std::vector<size_t> & getDim(void) const { return dim_; }
|
||||||
private:
|
private:
|
||||||
void accumulate(const Element &e);
|
template <typename W> typename std::enable_if<!is_flattenable<W>::value && !is_flattenable<W>::isGridTensor>::type
|
||||||
template <typename W>
|
accumulate(const W &e);
|
||||||
void accumulate(const W &v);
|
template <typename W> typename std::enable_if<!is_flattenable<W>::value && is_flattenable<W>::isGridTensor>::type
|
||||||
void accumulateDim(const Element &e);
|
accumulate(const W &e);
|
||||||
template <typename W>
|
template <typename W> typename std::enable_if< is_flattenable<W>::value>::type
|
||||||
void accumulateDim(const W &v);
|
accumulate(const W &v);
|
||||||
|
template <typename W> typename std::enable_if<!is_flattenable<W>::value && !is_flattenable<W>::isGridTensor>::type
|
||||||
|
accumulateDim(const W &e) {} // Innermost is a scalar - do nothing
|
||||||
|
template <typename W> typename std::enable_if<!is_flattenable<W>::value && is_flattenable<W>::isGridTensor>::type
|
||||||
|
accumulateDim(const W &e);
|
||||||
|
template <typename W> typename std::enable_if< is_flattenable<W>::value>::type
|
||||||
|
accumulateDim(const W &v);
|
||||||
private:
|
private:
|
||||||
const V &vector_;
|
const V &vector_;
|
||||||
std::vector<Element> flatVector_;
|
std::vector<Scalar> flatVector_;
|
||||||
std::vector<size_t> dim_;
|
std::vector<size_t> dim_;
|
||||||
};
|
};
|
||||||
|
|
||||||
// Class to reconstruct a multidimensional std::vector
|
// Class to reconstruct a multidimensional std::vector
|
||||||
@ -283,38 +305,57 @@ namespace Grid {
|
|||||||
class Reconstruct
|
class Reconstruct
|
||||||
{
|
{
|
||||||
public:
|
public:
|
||||||
typedef typename element<V>::type Element;
|
using Scalar = typename is_flattenable<V>::type;
|
||||||
|
static constexpr bool isGridTensor = is_flattenable<V>::isGridTensor;
|
||||||
public:
|
public:
|
||||||
Reconstruct(const std::vector<Element> &flatVector,
|
Reconstruct(const std::vector<Scalar> &flatVector,
|
||||||
const std::vector<size_t> &dim);
|
const std::vector<size_t> &dim);
|
||||||
const V & getVector(void);
|
const V & getVector(void) const { return vector_; }
|
||||||
const std::vector<Element> & getFlatVector(void);
|
const std::vector<Scalar> & getFlatVector(void) const { return flatVector_; }
|
||||||
const std::vector<size_t> & getDim(void);
|
const std::vector<size_t> & getDim(void) const { return dim_; }
|
||||||
private:
|
private:
|
||||||
void fill(std::vector<Element> &v);
|
template <typename W> typename std::enable_if<!is_flattenable<W>::value && !is_flattenable<W>::isGridTensor>::type
|
||||||
template <typename W>
|
fill(W &v);
|
||||||
void fill(W &v);
|
template <typename W> typename std::enable_if<!is_flattenable<W>::value && is_flattenable<W>::isGridTensor>::type
|
||||||
void resize(std::vector<Element> &v, const unsigned int dim);
|
fill(W &v);
|
||||||
template <typename W>
|
template <typename W> typename std::enable_if< is_flattenable<W>::value>::type
|
||||||
void resize(W &v, const unsigned int dim);
|
fill(W &v);
|
||||||
|
template <typename W> typename std::enable_if< is_flattenable<W>::value && is_flattenable<W>::vecRank==1>::type
|
||||||
|
resize(W &v, const unsigned int dim);
|
||||||
|
template <typename W> typename std::enable_if< is_flattenable<W>::value && (is_flattenable<W>::vecRank>1)>::type
|
||||||
|
resize(W &v, const unsigned int dim);
|
||||||
|
template <typename W> typename std::enable_if<!is_flattenable<W>::isGridTensor>::type
|
||||||
|
checkInnermost(const W &e) {} // Innermost is a scalar - do nothing
|
||||||
|
template <typename W> typename std::enable_if< is_flattenable<W>::isGridTensor>::type
|
||||||
|
checkInnermost(const W &e);
|
||||||
private:
|
private:
|
||||||
V vector_;
|
V vector_;
|
||||||
const std::vector<Element> &flatVector_;
|
const std::vector<Scalar> &flatVector_;
|
||||||
std::vector<size_t> dim_;
|
std::vector<size_t> dim_;
|
||||||
size_t ind_{0};
|
size_t ind_{0};
|
||||||
unsigned int dimInd_{0};
|
unsigned int dimInd_{0};
|
||||||
};
|
};
|
||||||
|
|
||||||
// Flatten class template implementation
|
// Flatten class template implementation
|
||||||
template <typename V>
|
template <typename V>
|
||||||
void Flatten<V>::accumulate(const Element &e)
|
template <typename W> typename std::enable_if<!is_flattenable<W>::value && !is_flattenable<W>::isGridTensor>::type
|
||||||
|
Flatten<V>::accumulate(const W &e)
|
||||||
{
|
{
|
||||||
flatVector_.push_back(e);
|
flatVector_.push_back(e);
|
||||||
}
|
}
|
||||||
|
|
||||||
template <typename V>
|
template <typename V>
|
||||||
template <typename W>
|
template <typename W> typename std::enable_if<!is_flattenable<W>::value && is_flattenable<W>::isGridTensor>::type
|
||||||
void Flatten<V>::accumulate(const W &v)
|
Flatten<V>::accumulate(const W &e)
|
||||||
|
{
|
||||||
|
for (const Scalar &x: e) {
|
||||||
|
flatVector_.push_back(x);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
template <typename V>
|
||||||
|
template <typename W> typename std::enable_if<is_flattenable<W>::value>::type
|
||||||
|
Flatten<V>::accumulate(const W &v)
|
||||||
{
|
{
|
||||||
for (auto &e: v)
|
for (auto &e: v)
|
||||||
{
|
{
|
||||||
@ -323,11 +364,17 @@ namespace Grid {
|
|||||||
}
|
}
|
||||||
|
|
||||||
template <typename V>
|
template <typename V>
|
||||||
void Flatten<V>::accumulateDim(const Element &e) {};
|
template <typename W> typename std::enable_if<!is_flattenable<W>::value && is_flattenable<W>::isGridTensor>::type
|
||||||
|
Flatten<V>::accumulateDim(const W &e)
|
||||||
|
{
|
||||||
|
using Traits = GridTypeMapper<typename is_flattenable<W>::grid_type>;
|
||||||
|
for (int rank=0; rank < Traits::Rank; ++rank)
|
||||||
|
dim_.push_back(Traits::Dimension(rank));
|
||||||
|
}
|
||||||
|
|
||||||
template <typename V>
|
template <typename V>
|
||||||
template <typename W>
|
template <typename W> typename std::enable_if<is_flattenable<W>::value>::type
|
||||||
void Flatten<V>::accumulateDim(const W &v)
|
Flatten<V>::accumulateDim(const W &v)
|
||||||
{
|
{
|
||||||
dim_.push_back(v.size());
|
dim_.push_back(v.size());
|
||||||
accumulateDim(v[0]);
|
accumulateDim(v[0]);
|
||||||
@ -337,32 +384,26 @@ namespace Grid {
|
|||||||
Flatten<V>::Flatten(const V &vector)
|
Flatten<V>::Flatten(const V &vector)
|
||||||
: vector_(vector)
|
: vector_(vector)
|
||||||
{
|
{
|
||||||
accumulate(vector_);
|
|
||||||
accumulateDim(vector_);
|
accumulateDim(vector_);
|
||||||
}
|
std::size_t TotalSize{ dim_[0] };
|
||||||
|
for (int i = 1; i < dim_.size(); ++i) {
|
||||||
template <typename V>
|
TotalSize *= dim_[i];
|
||||||
const V & Flatten<V>::getVector(void)
|
}
|
||||||
{
|
flatVector_.reserve(TotalSize);
|
||||||
return vector_;
|
accumulate(vector_);
|
||||||
}
|
|
||||||
|
|
||||||
template <typename V>
|
|
||||||
const std::vector<typename Flatten<V>::Element> &
|
|
||||||
Flatten<V>::getFlatVector(void)
|
|
||||||
{
|
|
||||||
return flatVector_;
|
|
||||||
}
|
|
||||||
|
|
||||||
template <typename V>
|
|
||||||
const std::vector<size_t> & Flatten<V>::getDim(void)
|
|
||||||
{
|
|
||||||
return dim_;
|
|
||||||
}
|
}
|
||||||
|
|
||||||
// Reconstruct class template implementation
|
// Reconstruct class template implementation
|
||||||
template <typename V>
|
template <typename V>
|
||||||
void Reconstruct<V>::fill(std::vector<Element> &v)
|
template <typename W> typename std::enable_if<!is_flattenable<W>::value && !is_flattenable<W>::isGridTensor>::type
|
||||||
|
Reconstruct<V>::fill(W &v)
|
||||||
|
{
|
||||||
|
v = flatVector_[ind_++];
|
||||||
|
}
|
||||||
|
|
||||||
|
template <typename V>
|
||||||
|
template <typename W> typename std::enable_if<!is_flattenable<W>::value && is_flattenable<W>::isGridTensor>::type
|
||||||
|
Reconstruct<V>::fill(W &v)
|
||||||
{
|
{
|
||||||
for (auto &e: v)
|
for (auto &e: v)
|
||||||
{
|
{
|
||||||
@ -371,8 +412,8 @@ namespace Grid {
|
|||||||
}
|
}
|
||||||
|
|
||||||
template <typename V>
|
template <typename V>
|
||||||
template <typename W>
|
template <typename W> typename std::enable_if<is_flattenable<W>::value>::type
|
||||||
void Reconstruct<V>::fill(W &v)
|
Reconstruct<V>::fill(W &v)
|
||||||
{
|
{
|
||||||
for (auto &e: v)
|
for (auto &e: v)
|
||||||
{
|
{
|
||||||
@ -381,14 +422,15 @@ namespace Grid {
|
|||||||
}
|
}
|
||||||
|
|
||||||
template <typename V>
|
template <typename V>
|
||||||
void Reconstruct<V>::resize(std::vector<Element> &v, const unsigned int dim)
|
template <typename W> typename std::enable_if<is_flattenable<W>::value && is_flattenable<W>::vecRank==1>::type
|
||||||
|
Reconstruct<V>::resize(W &v, const unsigned int dim)
|
||||||
{
|
{
|
||||||
v.resize(dim_[dim]);
|
v.resize(dim_[dim]);
|
||||||
}
|
}
|
||||||
|
|
||||||
template <typename V>
|
template <typename V>
|
||||||
template <typename W>
|
template <typename W> typename std::enable_if<is_flattenable<W>::value && (is_flattenable<W>::vecRank>1)>::type
|
||||||
void Reconstruct<V>::resize(W &v, const unsigned int dim)
|
Reconstruct<V>::resize(W &v, const unsigned int dim)
|
||||||
{
|
{
|
||||||
v.resize(dim_[dim]);
|
v.resize(dim_[dim]);
|
||||||
for (auto &e: v)
|
for (auto &e: v)
|
||||||
@ -398,34 +440,31 @@ namespace Grid {
|
|||||||
}
|
}
|
||||||
|
|
||||||
template <typename V>
|
template <typename V>
|
||||||
Reconstruct<V>::Reconstruct(const std::vector<Element> &flatVector,
|
template <typename W> typename std::enable_if<is_flattenable<W>::isGridTensor>::type
|
||||||
|
Reconstruct<V>::checkInnermost(const W &)
|
||||||
|
{
|
||||||
|
using Traits = GridTypeMapper<typename is_flattenable<W>::grid_type>;
|
||||||
|
const int gridRank{Traits::Rank};
|
||||||
|
const int dimRank{static_cast<int>(dim_.size())};
|
||||||
|
assert(dimRank >= gridRank && "Tensor rank too low for Grid tensor");
|
||||||
|
for (int i=0; i<gridRank; ++i) {
|
||||||
|
assert(dim_[dimRank - gridRank + i] == Traits::Dimension(i) && "Tensor dimension doesn't match Grid tensor");
|
||||||
|
}
|
||||||
|
dim_.resize(dimRank - gridRank);
|
||||||
|
}
|
||||||
|
|
||||||
|
template <typename V>
|
||||||
|
Reconstruct<V>::Reconstruct(const std::vector<Scalar> &flatVector,
|
||||||
const std::vector<size_t> &dim)
|
const std::vector<size_t> &dim)
|
||||||
: flatVector_(flatVector)
|
: flatVector_(flatVector)
|
||||||
, dim_(dim)
|
, dim_(dim)
|
||||||
{
|
{
|
||||||
|
checkInnermost(vector_);
|
||||||
|
assert(dim_.size() == is_flattenable<V>::vecRank && "Tensor rank doesn't match nested std::vector rank");
|
||||||
resize(vector_, 0);
|
resize(vector_, 0);
|
||||||
fill(vector_);
|
fill(vector_);
|
||||||
}
|
}
|
||||||
|
|
||||||
template <typename V>
|
|
||||||
const V & Reconstruct<V>::getVector(void)
|
|
||||||
{
|
|
||||||
return vector_;
|
|
||||||
}
|
|
||||||
|
|
||||||
template <typename V>
|
|
||||||
const std::vector<typename Reconstruct<V>::Element> &
|
|
||||||
Reconstruct<V>::getFlatVector(void)
|
|
||||||
{
|
|
||||||
return flatVector_;
|
|
||||||
}
|
|
||||||
|
|
||||||
template <typename V>
|
|
||||||
const std::vector<size_t> & Reconstruct<V>::getDim(void)
|
|
||||||
{
|
|
||||||
return dim_;
|
|
||||||
}
|
|
||||||
|
|
||||||
// Vector IO utilities ///////////////////////////////////////////////////////
|
// Vector IO utilities ///////////////////////////////////////////////////////
|
||||||
// helper function to read space-separated values
|
// helper function to read space-separated values
|
||||||
template <typename T>
|
template <typename T>
|
||||||
@ -460,18 +499,18 @@ namespace Grid {
|
|||||||
return os;
|
return os;
|
||||||
}
|
}
|
||||||
|
|
||||||
// In general, scalar types are considered "flat" (regularly shaped)
|
// In general, scalar types are considered "flattenable" (regularly shaped)
|
||||||
template <typename T>
|
template <typename T>
|
||||||
bool isFlat(const T &t) { return true; }
|
bool isRegularShape(const T &t) { return true; }
|
||||||
|
|
||||||
// Return non-zero if all dimensions of this std::vector<std::vector<T>> are regularly shaped
|
// Return non-zero if all dimensions of this std::vector<std::vector<T>> are regularly shaped
|
||||||
template <typename T>
|
template <typename T>
|
||||||
bool isFlat(const std::vector<std::vector<T>> &v)
|
bool isRegularShape(const std::vector<std::vector<T>> &v)
|
||||||
{
|
{
|
||||||
// Make sure all of my rows are the same size
|
// Make sure all of my rows are the same size
|
||||||
for (std::size_t i = 0; i < v.size(); ++i)
|
for (std::size_t i = 0; i < v.size(); ++i)
|
||||||
{
|
{
|
||||||
if (v[i].size() != v[0].size() || !isFlat(v[i]))
|
if (v[i].size() != v[0].size() || !isRegularShape(v[i]))
|
||||||
{
|
{
|
||||||
return false;
|
return false;
|
||||||
}
|
}
|
||||||
|
Loading…
x
Reference in New Issue
Block a user