Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

No constexpr rank via constexpr min-max rank. #938

Merged
merged 1 commit into from
May 14, 2024
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
15 changes: 9 additions & 6 deletions include/highfive/bits/H5Attribute_misc.hpp
Original file line number Diff line number Diff line change
Expand Up @@ -19,6 +19,7 @@

#include "../H5DataSpace.hpp"
#include "H5Converter_misc.hpp"
#include "H5Inspector_misc.hpp"
#include "H5ReadWrite_misc.hpp"
#include "H5Utils.hpp"
#include "h5a_wrapper.hpp"
Expand Down Expand Up @@ -73,10 +74,11 @@ inline void Attribute::read(T& array) const {
[this]() -> std::string { return this->getName(); },
details::BufferInfo<T>::Operation::read);

if (!details::checkDimensions(mem_space, buffer_info.n_dimensions)) {
if (!details::checkDimensions(mem_space, buffer_info.getMinRank(), buffer_info.getMaxRank())) {
std::ostringstream ss;
ss << "Impossible to read Attribute of dimensions " << mem_space.getNumberDimensions()
<< " into arrays of dimensions " << buffer_info.n_dimensions;
ss << "Impossible to read attribute of dimensions " << mem_space.getNumberDimensions()
<< " into arrays of dimensions: " << buffer_info.getMinRank() << "(min) to "
<< buffer_info.getMaxRank() << "(max)";
throw DataSpaceException(ss.str());
}
auto dims = mem_space.getDimensions();
Expand Down Expand Up @@ -137,10 +139,11 @@ inline void Attribute::write(const T& buffer) {
[this]() -> std::string { return this->getName(); },
details::BufferInfo<T>::Operation::write);

if (!details::checkDimensions(mem_space, buffer_info.n_dimensions)) {
if (!details::checkDimensions(mem_space, buffer_info.getMinRank(), buffer_info.getMaxRank())) {
std::ostringstream ss;
ss << "Impossible to write buffer of dimensions " << buffer_info.n_dimensions
<< " into dataset of dimensions " << mem_space.getNumberDimensions();
ss << "Impossible to write attribute of dimensions " << mem_space.getNumberDimensions()
<< " into arrays of dimensions: " << buffer_info.getMinRank() << "(min) to "
<< buffer_info.getMaxRank() << "(max)";
throw DataSpaceException(ss.str());
}
auto w = details::data_converter::serialize<T>(buffer, dims, file_datatype);
Expand Down
6 changes: 3 additions & 3 deletions include/highfive/bits/H5DataType_misc.hpp
Original file line number Diff line number Diff line change
Expand Up @@ -226,9 +226,9 @@ inline EnumType<details::Boolean> create_enum_boolean() {
// Other cases not supported. Fail early with a user message
template <typename T>
AtomicType<T>::AtomicType() {
static_assert(details::inspector<T>::recursive_ndim == 0,
"Atomic types cant be arrays, except for char[] (fixed-length strings)");
static_assert(details::inspector<T>::recursive_ndim > 0, "Type not supported");
static_assert(
true,
"Missing specialization of AtomicType<T>. Therefore, type T is not supported by HighFive.");
}


Expand Down
7 changes: 4 additions & 3 deletions include/highfive/bits/H5Dataspace_misc.hpp
Original file line number Diff line number Diff line change
Expand Up @@ -131,9 +131,10 @@ inline DataSpace DataSpace::FromCharArrayStrings(const char (&)[N][Width]) {

namespace details {

/// dimension checks @internal
inline bool checkDimensions(const DataSpace& mem_space, size_t n_dim_requested) {
return checkDimensions(mem_space.getDimensions(), n_dim_requested);
inline bool checkDimensions(const DataSpace& mem_space,
size_t min_dim_requested,
size_t max_dim_requested) {
return checkDimensions(mem_space.getDimensions(), min_dim_requested, max_dim_requested);
}

} // namespace details
Expand Down
84 changes: 63 additions & 21 deletions include/highfive/bits/H5Inspector_misc.hpp
Original file line number Diff line number Diff line change
Expand Up @@ -27,15 +27,18 @@
namespace HighFive {
namespace details {

inline bool checkDimensions(const std::vector<size_t>& dims, size_t n_dim_requested) {
if (dims.size() == n_dim_requested) {
inline bool checkDimensions(const std::vector<size_t>& dims,
size_t min_dim_requested,
size_t max_dim_requested) {
if (min_dim_requested <= dims.size() && dims.size() <= max_dim_requested) {
return true;
}


// Scalar values still support broadcasting
// into arrays with one element.
size_t n_elements = compute_total_size(dims);
return n_elements == 1 && n_dim_requested == 0;
return n_elements == 1 && min_dim_requested == 0;
}

} // namespace details
Expand All @@ -49,8 +52,6 @@ inspector<T> {
// hdf5_type is the base read by hdf5 (c-type) (e.g. std::vector<std::string> => const char*)
using hdf5_type

// Number of dimensions starting from here
static constexpr size_t recursive_ndim
// Is the inner type trivially copyable for optimisation
// If this value is true: data() is mandatory
// If this value is false: serialize, unserialize are mandatory
Expand Down Expand Up @@ -88,10 +89,16 @@ struct type_helper {
using hdf5_type = base_type;

static constexpr size_t ndim = 0;
static constexpr size_t recursive_ndim = ndim;
static constexpr size_t min_ndim = ndim;
static constexpr size_t max_ndim = ndim;

static constexpr bool is_trivially_copyable = std::is_trivially_copyable<type>::value;
static constexpr bool is_trivially_nestable = is_trivially_copyable;

static size_t getRank(const type& /* val */) {
return ndim;
}

static std::vector<size_t> getDimensions(const type& /* val */) {
return {};
}
Expand Down Expand Up @@ -216,17 +223,27 @@ struct inspector<std::vector<T>> {
using hdf5_type = typename inspector<value_type>::hdf5_type;

static constexpr size_t ndim = 1;
static constexpr size_t recursive_ndim = ndim + inspector<value_type>::recursive_ndim;
static constexpr size_t min_ndim = ndim + inspector<value_type>::min_ndim;
static constexpr size_t max_ndim = ndim + inspector<value_type>::max_ndim;

static constexpr bool is_trivially_copyable = std::is_trivially_copyable<value_type>::value &&
inspector<value_type>::is_trivially_nestable;
static constexpr bool is_trivially_nestable = false;

static size_t getRank(const type& val) {
if (!val.empty()) {
return ndim + inspector<value_type>::getRank(val[0]);
} else {
return min_ndim;
}
}

static std::vector<size_t> getDimensions(const type& val) {
std::vector<size_t> sizes(recursive_ndim, 1ul);
auto rank = getRank(val);
std::vector<size_t> sizes(rank, 1ul);
sizes[0] = val.size();
if (!val.empty()) {
auto s = inspector<value_type>::getDimensions(val[0]);
assert(s.size() + ndim == sizes.size());
for (size_t i = 0; i < s.size(); ++i) {
sizes[i + ndim] = s[i];
}
Expand Down Expand Up @@ -280,10 +297,16 @@ struct inspector<std::vector<bool>> {
using hdf5_type = uint8_t;

static constexpr size_t ndim = 1;
static constexpr size_t recursive_ndim = ndim;
static constexpr size_t min_ndim = ndim;
static constexpr size_t max_ndim = ndim;

static constexpr bool is_trivially_copyable = false;
static constexpr bool is_trivially_nestable = false;

static size_t getRank(const type& /* val */) {
return ndim;
}

static std::vector<size_t> getDimensions(const type& val) {
std::vector<size_t> sizes{val.size()};
return sizes;
Expand Down Expand Up @@ -327,18 +350,22 @@ struct inspector<std::array<T, N>> {
using hdf5_type = typename inspector<value_type>::hdf5_type;

static constexpr size_t ndim = 1;
static constexpr size_t recursive_ndim = ndim + inspector<value_type>::recursive_ndim;
static constexpr size_t min_ndim = ndim + inspector<value_type>::min_ndim;
static constexpr size_t max_ndim = ndim + inspector<value_type>::max_ndim;

static constexpr bool is_trivially_copyable = std::is_trivially_copyable<value_type>::value &&
inspector<value_type>::is_trivially_nestable;
static constexpr bool is_trivially_nestable = (sizeof(type) == N * sizeof(T)) &&
is_trivially_copyable;

static size_t getRank(const type& val) {
return ndim + inspector<value_type>::getRank(val[0]);
}

static std::vector<size_t> getDimensions(const type& val) {
std::vector<size_t> sizes{N};
if (!val.empty()) {
auto s = inspector<value_type>::getDimensions(val[0]);
sizes.insert(sizes.end(), s.begin(), s.end());
}
auto s = inspector<value_type>::getDimensions(val[0]);
sizes.insert(sizes.end(), s.begin(), s.end());
return sizes;
}

Expand Down Expand Up @@ -399,11 +426,21 @@ struct inspector<T*> {
using hdf5_type = typename inspector<value_type>::hdf5_type;

static constexpr size_t ndim = 1;
static constexpr size_t recursive_ndim = ndim + inspector<value_type>::recursive_ndim;
static constexpr size_t min_ndim = ndim + inspector<value_type>::min_ndim;
static constexpr size_t max_ndim = ndim + inspector<value_type>::max_ndim;

static constexpr bool is_trivially_copyable = std::is_trivially_copyable<value_type>::value &&
inspector<value_type>::is_trivially_nestable;
static constexpr bool is_trivially_nestable = false;

static size_t getRank(const type& val) {
if (val != nullptr) {
return ndim + inspector<value_type>::getRank(val[0]);
} else {
return min_ndim;
}
}

static std::vector<size_t> getDimensions(const type& /* val */) {
throw DataSpaceException("Not possible to have size of a T*");
}
Expand All @@ -430,7 +467,9 @@ struct inspector<T[N]> {
using hdf5_type = typename inspector<value_type>::hdf5_type;

static constexpr size_t ndim = 1;
static constexpr size_t recursive_ndim = ndim + inspector<value_type>::recursive_ndim;
static constexpr size_t min_ndim = ndim + inspector<value_type>::min_ndim;
static constexpr size_t max_ndim = ndim + inspector<value_type>::max_ndim;

static constexpr bool is_trivially_copyable = std::is_trivially_copyable<value_type>::value &&
inspector<value_type>::is_trivially_nestable;
static constexpr bool is_trivially_nestable = is_trivially_copyable;
Expand All @@ -450,12 +489,14 @@ struct inspector<T[N]> {
}
}

static size_t getRank(const type& val) {
return ndim + inspector<value_type>::getRank(val[0]);
}

static std::vector<size_t> getDimensions(const type& val) {
std::vector<size_t> sizes{N};
if (N > 0) {
auto s = inspector<value_type>::getDimensions(val[0]);
sizes.insert(sizes.end(), s.begin(), s.end());
}
auto s = inspector<value_type>::getDimensions(val[0]);
sizes.insert(sizes.end(), s.begin(), s.end());
return sizes;
}

Expand All @@ -478,5 +519,6 @@ struct inspector<T[N]> {
}
};


} // namespace details
} // namespace HighFive
27 changes: 23 additions & 4 deletions include/highfive/bits/H5ReadWrite_misc.hpp
Original file line number Diff line number Diff line change
Expand Up @@ -9,6 +9,7 @@
#pragma once

#include <H5Tpublic.h>
#include "H5Inspector_misc.hpp"
#include "H5Utils.hpp"

namespace HighFive {
Expand Down Expand Up @@ -57,10 +58,14 @@ struct BufferInfo {
template <class F>
BufferInfo(const DataType& dtype, F getName, Operation _op);

size_t getRank(const T& array) const;
size_t getMinRank() const;
size_t getMaxRank() const;

// member data for info depending on the destination dataset type
const bool is_fixed_len_string;
const size_t n_dimensions;
const DataType data_type;
const size_t rank_correction;
};

// details implementation
Expand Down Expand Up @@ -135,10 +140,9 @@ BufferInfo<T>::BufferInfo(const DataType& file_data_type, F getName, Operation _
: op(_op)
, is_fixed_len_string(file_data_type.isFixedLenStr())
// In case we are using Fixed-len strings we need to subtract one dimension
, n_dimensions(details::inspector<type_no_const>::recursive_ndim -
((is_fixed_len_string && is_char_array) ? 1 : 0))
, data_type(string_type_checker<char_array_t>::getDataType(create_datatype<elem_type>(),
file_data_type)) {
file_data_type))
, rank_correction((is_fixed_len_string && is_char_array) ? 1 : 0) {
// We warn. In case they are really not convertible an exception will rise on read/write
if (file_data_type.getClass() != data_type.getClass()) {
HIGHFIVE_LOG_WARN(getName() + "\": data and hdf5 dataset have different types: " +
Expand All @@ -157,6 +161,21 @@ BufferInfo<T>::BufferInfo(const DataType& file_data_type, F getName, Operation _
}
}

template <typename T>
size_t BufferInfo<T>::getRank(const T& array) const {
return details::inspector<type_no_const>::getRank(array) - rank_correction;
}

template <typename T>
size_t BufferInfo<T>::getMinRank() const {
return details::inspector<T>::min_ndim - rank_correction;
}

template <typename T>
size_t BufferInfo<T>::getMaxRank() const {
return details::inspector<T>::max_ndim - rank_correction;
}

} // namespace details

} // namespace HighFive
13 changes: 7 additions & 6 deletions include/highfive/bits/H5Slice_traits_misc.hpp
Original file line number Diff line number Diff line change
Expand Up @@ -180,10 +180,11 @@ inline void SliceTraits<Derivate>::read(T& array, const DataTransferProps& xfer_
[&slice]() -> std::string { return details::get_dataset(slice).getPath(); },
details::BufferInfo<T>::Operation::read);

if (!details::checkDimensions(mem_space, buffer_info.n_dimensions)) {
if (!details::checkDimensions(mem_space, buffer_info.getMinRank(), buffer_info.getMaxRank())) {
std::ostringstream ss;
ss << "Impossible to read DataSet of dimensions " << mem_space.getNumberDimensions()
<< " into arrays of dimensions " << buffer_info.n_dimensions;
<< " into arrays of dimensions: " << buffer_info.getMinRank() << "(min) to "
<< buffer_info.getMaxRank() << "(max)";
throw DataSpaceException(ss.str());
}
auto dims = mem_space.getDimensions();
Expand Down Expand Up @@ -254,11 +255,11 @@ inline void SliceTraits<Derivate>::write(const T& buffer, const DataTransferProp
[&slice]() -> std::string { return details::get_dataset(slice).getPath(); },
details::BufferInfo<T>::Operation::write);

if (!details::checkDimensions(mem_space, buffer_info.n_dimensions)) {
if (!details::checkDimensions(mem_space, buffer_info.getMinRank(), buffer_info.getMaxRank())) {
std::ostringstream ss;
ss << "Impossible to write buffer of dimensions "
<< details::format_vector(mem_space.getDimensions())
<< " into dataset with n = " << buffer_info.n_dimensions << " dimensions.";
ss << "Impossible to write buffer with dimensions n = " << buffer_info.getRank(buffer)
<< "into dataset with dimensions " << details::format_vector(mem_space.getDimensions())
<< ".";
throw DataSpaceException(ss.str());
}
auto w = details::data_converter::serialize<T>(buffer, dims, file_datatype);
Expand Down
30 changes: 24 additions & 6 deletions include/highfive/boost.hpp
Original file line number Diff line number Diff line change
Expand Up @@ -17,19 +17,31 @@ struct inspector<boost::multi_array<T, Dims>> {
using hdf5_type = typename inspector<value_type>::hdf5_type;

static constexpr size_t ndim = Dims;
static constexpr size_t recursive_ndim = ndim + inspector<value_type>::recursive_ndim;
static constexpr size_t min_ndim = ndim + inspector<value_type>::min_ndim;
static constexpr size_t max_ndim = ndim + inspector<value_type>::max_ndim;

static constexpr bool is_trivially_copyable = std::is_trivially_copyable<value_type>::value &&
inspector<value_type>::is_trivially_nestable;
static constexpr bool is_trivially_nestable = false;


static size_t getRank(const type& val) {
return ndim + inspector<value_type>::getRank(val.data()[0]);
}

static std::vector<size_t> getDimensions(const type& val) {
std::vector<size_t> sizes;
auto rank = getRank(val);
std::vector<size_t> sizes(rank, 1ul);
for (size_t i = 0; i < ndim; ++i) {
sizes.push_back(val.shape()[i]);
sizes[i] = val.shape()[i];
}
if (val.size() != 0) {
auto s = inspector<value_type>::getDimensions(val.data()[0]);
sizes.resize(ndim + s.size());
for (size_t i = 0; i < s.size(); ++i) {
sizes[ndim + i] = s[i];
}
}
auto s = inspector<value_type>::getDimensions(val.data()[0]);
sizes.insert(sizes.end(), s.begin(), s.end());
return sizes;
}

Expand Down Expand Up @@ -101,11 +113,17 @@ struct inspector<boost::numeric::ublas::matrix<T>> {
using hdf5_type = typename inspector<value_type>::hdf5_type;

static constexpr size_t ndim = 2;
static constexpr size_t recursive_ndim = ndim + inspector<value_type>::recursive_ndim;
static constexpr size_t min_ndim = ndim + inspector<value_type>::min_ndim;
static constexpr size_t max_ndim = ndim + inspector<value_type>::max_ndim;

static constexpr bool is_trivially_copyable = std::is_trivially_copyable<value_type>::value &&
inspector<value_type>::is_trivially_copyable;
static constexpr bool is_trivially_nestable = false;

static size_t getRank(const type& val) {
return ndim + inspector<value_type>::getRank(val(0, 0));
}

static std::vector<size_t> getDimensions(const type& val) {
std::vector<size_t> sizes{val.size1(), val.size2()};
auto s = inspector<value_type>::getDimensions(val(0, 0));
Expand Down
Loading
Loading