Skip to content
Merged
Show file tree
Hide file tree
Changes from 2 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
2 changes: 1 addition & 1 deletion include/highfive/H5DataSpace.hpp
Original file line number Diff line number Diff line change
Expand Up @@ -82,7 +82,7 @@ class DataSpace: public Object {
/// \endcode
/// \since 2.3
template <size_t N>
explicit DataSpace(const std::array<size_t, N>& dims);
constexpr explicit DataSpace(const std::array<size_t, N>& dims);

/// \brief Create a DataSpace of N-dimensions from an initializer list.
/// \param dims Dimensions of the new DataSpace
Expand Down
9 changes: 6 additions & 3 deletions include/highfive/bits/H5Dataspace_misc.hpp
Original file line number Diff line number Diff line change
Expand Up @@ -31,15 +31,18 @@ inline DataSpace::DataSpace(const std::vector<size_t>& dims)
: DataSpace(dims.begin(), dims.end()) {}

template <size_t N>
inline DataSpace::DataSpace(const std::array<size_t, N>& dims)
: DataSpace(dims.begin(), dims.end()) {}
constexpr DataSpace::DataSpace(const std::array<size_t, N>& dims) {
std::array<hsize_t, N> real_dims;
std::copy(dims.begin(), dims.end(), real_dims.begin());
_hid = detail::h5s_create_simple(static_cast<int>(N), real_dims.data(), nullptr);
}

inline DataSpace::DataSpace(const std::initializer_list<size_t>& items)
: DataSpace(std::vector<size_t>(items)) {}

template <typename... Args>
inline DataSpace::DataSpace(size_t dim1, Args... dims)
: DataSpace(std::vector<size_t>{dim1, static_cast<size_t>(dims)...}) {}
: DataSpace(std::array{dim1, static_cast<size_t>(dims)...}) {}
Copy link
Contributor

@1uc 1uc Dec 11, 2025

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Also easy to merge. (Technically, it uses C++17, but it's easy to fix.)

Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Thanks! Help wanted to refactoring the code for c++14.

Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Yes, no worries :) Same goes for all other requests for help. If I have permission to push commits to your branch, that's the easiest way for me to make the changes. I'll try to find time tomorrow. Nice feature, thank you.


template <class IT, typename>
inline DataSpace::DataSpace(const IT begin, const IT end) {
Expand Down
7 changes: 5 additions & 2 deletions include/highfive/bits/H5Slice_traits.hpp
Original file line number Diff line number Diff line change
Expand Up @@ -10,6 +10,9 @@

#include <cstdlib>
#include <vector>
#if __cplusplus >= 201703L
#include <optional>
#endif

#include "H5_definitions.hpp"
#include "H5Utils.hpp"
Expand Down Expand Up @@ -416,7 +419,6 @@ class ProductSet {
friend class SliceTraits;
};


template <typename Derivate>
class SliceTraits {
public:
Expand All @@ -428,7 +430,8 @@ class SliceTraits {
/// nicely into a multi-dimensional array, but only a subset of such an array.
///
/// Therefore, the only memspaces supported for general hyperslabs are one-dimensional arrays.
Selection select(const HyperSlab& hyper_slab) const;
template <class HyperSlabInterface>
Selection select(const HyperSlabInterface& hyper_slab) const;

///
/// \brief Select an \p hyper_slab in the current Slice/Dataset.
Expand Down
8 changes: 4 additions & 4 deletions include/highfive/bits/H5Slice_traits_misc.hpp
Original file line number Diff line number Diff line change
Expand Up @@ -229,18 +229,18 @@ inline Selection SliceTraits<Derivate>::select(const HyperSlab& hyper_slab,
}

template <typename Derivate>
inline Selection SliceTraits<Derivate>::select(const HyperSlab& hyper_slab) const {
template <class HyperSlabInterface>
inline Selection SliceTraits<Derivate>::select(const HyperSlabInterface& hyper_slab) const {
const auto& slice = static_cast<const Derivate&>(*this);
auto filespace = slice.getSpace();
filespace = hyper_slab.apply(filespace);

auto n_elements = detail::h5s_get_select_npoints(filespace.getId());
auto memspace = DataSpace(std::array<size_t, 1>{size_t(n_elements)});
const auto n_elements = detail::h5s_get_select_npoints(filespace.getId());
auto memspace = DataSpace{static_cast<size_t>(n_elements)};

return detail::make_selection(memspace, filespace, details::get_dataset(slice));
}
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

If RegularHyperSlabNoMalloc where user defined, I don't know how to solve this.

Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

As you might have noticed I'm not so keen on having both a statically sized version and fixed-sized version. Especially, because it's currently not done for performance reasons and HighFive is very consistent about using std::vector for shapes.

Now for the good news: we could use SFINAE for select allowing users to pass in any type for which hyper_slab.apply(filespace) is valid (and maybe something else). Once, HighFive can accept anything "slab-like", there's no need to implement select specifically for RegularHyperSlabNoMalloc. For now RegularHyperSlabNoMalloc could live outside of HighFive (or in an example). That way even if you fork HighFive, rebasing your changes would be trivial, e.g. if you put RegularHyperSlabNoMalloc in a separate header, the chance of a merge conflict seems zero. Also, not adding it now doesn't mean we can't ever add it.

@antonysigma Would this work for you? The SFINAE part isn't strictly needed, in a first version an unconstrained template parameter would suffice. That way if you don't feel like fighting SFINAE, I can take care of it later.

Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Re: moving RegularHyperSlabNoMalloc<Rank> to src/examples/ folder. For sure! Please check out the new changes.

Re: SFINAE for select(const T& hyper_slab). Sounds good to me. Please review the new changes following your advises. I suppose the system can tolerate the additional H5Sget_select_npoints calls for now. Once HighFive project migrates to c++17, we have more advanced tricks to compute npoints at compile-time.

Would this work for you? The SFINAE part isn't strictly needed, in a first version an unconstrained template parameter would suffice. That way if you don't feel like fighting SFINAE, I can take care of it later.

Yes, help wanted to tighten the constraints eventually.

Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

We'll first try with H5Sget_select_npoints if profiling/analysis shows it's bad, then computing the size of the hyperslab will become (optional if need be) part of the HyperSlab interface.



template <typename Derivate>
inline Selection SliceTraits<Derivate>::select(const std::vector<size_t>& offset,
const std::vector<size_t>& count,
Expand Down
97 changes: 97 additions & 0 deletions src/examples/select_partial_dataset_cpp17.cpp
Original file line number Diff line number Diff line change
@@ -0,0 +1,97 @@
/*
* Copyright (c), 2017, Adrien Devresse
*
* Distributed under the Boost Software License, Version 1.0.
* (See accompanying file LICENSE_1_0.txt or copy at
* http://www.boost.org/LICENSE_1_0.txt)
*
*/
Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I don't mind the author to be Adrien, or who ever can compose the CMake file for me. Help wanted here to compose the CMakeLists.txt.

Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I'd say it's either your name or "HighFive developers" and the year is 2025. Let me know which one you prefer.

Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

For sure. My name "Antony Chan".

#include <functional>
#include <iostream>
#include <string>
#include <vector>

#include <highfive/highfive.hpp>

namespace {
template <size_t Rank>
struct RegularHyperSlabNoMalloc {
constexpr size_t rank() const {
return Rank;
}

/// Dimensions when all gaps are removed.
constexpr std::array<size_t, Rank> packedDims() const {
auto dims = std::array<size_t, Rank>{};

for (size_t i = 0; i < Rank; ++i) {
dims[i] = count[i] * (block ? (*block)[i] : 1);
}

return dims;
}

HighFive::DataSpace apply(const HighFive::DataSpace& space_) const {
auto space = space_.clone();
const auto error_code = H5Sselect_hyperslab(space.getId(),
H5S_SELECT_SET,
offset.data(),
stride ? stride->data() : nullptr,
count.data(),
block ? block->data() : nullptr);

if (error_code < 0) {
HighFive::HDF5ErrMapper::ToException<HighFive::DataSpaceException>(
"Unable to select hyperslab");
}
return space;
}

std::array<hsize_t, Rank> offset{};
std::array<hsize_t, Rank> count{};
std::optional<std::array<hsize_t, Rank>> stride{std::nullopt};
std::optional<std::array<hsize_t, Rank>> block{std::nullopt};
};
} // namespace

int main(void) {
using namespace HighFive;

// Create a new file using the default property lists.
//
// Note: In C++14, using braces in constructor implies "explicit" keyword. Compiler logs will
// warn about possible implicit type conversion that may involves transient memory allocations.
File file{"select_partial_example_cpp17.h5", File::ReadWrite | File::Create | File::Truncate};

// we have some example values in a 2D vector 2x5
// Specifying the inner dimensions as std::array ensures that the two-dimensional data is
// contiguous, so that the compiler will only invoke one single memory allocation. The
// compiler also ensures the column counts are identical.
//
// Note: C++17 required.
const std::vector values{std::array{1.0, 2.0, 4.0, 8.0, 16.0},
{32.0, 64.0, 128.0, 256.0, 512.0}};

// let's create a dataset of this size
DataSet dataset = file.createDataSet<double>("dset", DataSpace::From(values));
// and write them
dataset.write(values);


// now we read back 2x2 values after an offset of 0x2
// Notice that std::array lives in the stack space memory. No memory allocation required.
std::array<std::array<double, 2>, 2> result;

// Specify the selection without any memory allocations.
dataset.select(RegularHyperSlabNoMalloc<2>{{0, 2}, {2, 2}}).read_raw(result.front().data());

// we print out 4 values
for (auto i: result) {
for (auto j: i) {
std::cout << ' ' << j;
}
std::cout << '\n';
}

return 0; // successfully terminated
}