Skip to content

Commit

Permalink
Added support for reading object header information with `h5pp::File:…
Browse files Browse the repository at this point in the history
…:getLinkInfo(linkpath)`

* And added assertReadReady() function to LinkInfo
  • Loading branch information
DavidAce committed Aug 28, 2021
1 parent acefa76 commit 4e9747f
Show file tree
Hide file tree
Showing 3 changed files with 151 additions and 16 deletions.
18 changes: 14 additions & 4 deletions include/h5pp/details/h5ppFile.h
Original file line number Diff line number Diff line change
Expand Up @@ -1448,6 +1448,12 @@ namespace h5pp {
return h5pp::hdf5::getTypeInfo_allAttributes(openFileHandle(), linkPath, std::nullopt, plists.linkAccess);
}

[[nodiscard]] LinkInfo getLinkInfo(std::string_view linkPath) const {
Options options;
options.linkPath = h5pp::util::safe_str(linkPath);
return h5pp::scan::readLinkInfo(openFileHandle(), options, plists);
}

template<typename InfoType>
[[nodiscard]] InfoType getInfo(std::string_view linkPath) const {
if constexpr(std::is_same_v<InfoType, DsetInfo>)
Expand All @@ -1456,10 +1462,13 @@ namespace h5pp {
return getTableInfo(linkPath);
else if constexpr(std::is_same_v<InfoType, TypeInfo>)
return getTypeInfoDataset(linkPath);
else if constexpr(std::is_same_v<InfoType, LinkInfo>)
return getLinkInfo(linkPath);
else
static_assert(h5pp::type::sfinae::invalid_type_v<InfoType>,
"Template function [h5pp::File::getInfo<InfoType>(std::string_view linkPath)] "
"requires InfoType: [h5pp::DsetInfo], [h5pp::TableInfo] or [h5pp::TypeInfo]");
"Template function 'h5pp::File::getInfo<InfoType>(std::string_view linkPath)' "
"requires template type 'InfoType' to be one of "
"[h5pp::DsetInfo], [h5pp::TableInfo], [h5pp::TypeInfo] or [h5pp::LinkInfo]");
}

template<typename InfoType>
Expand All @@ -1470,8 +1479,9 @@ namespace h5pp {
return getTypeInfoAttribute(linkPath, attrName);
else
static_assert(h5pp::type::sfinae::invalid_type_v<InfoType>,
"Template function [h5pp::File::getInfo<InfoType>(std::string_view linkPath, std::string_view attrName)] "
"requires InfoType: [h5pp::AttrInfo] or [h5pp::TypeInfo]");
"Template function 'h5pp::File::getInfo<InfoType>(std::string_view linkPath, std::string_view attrName)' "
"requires template type 'InfoType' to be either "
"[h5pp::AttrInfo] or [h5pp::TypeInfo]");
}

[[nodiscard]] bool fileIsValid() const { return h5pp::hdf5::fileIsValid(filePath); }
Expand Down
56 changes: 55 additions & 1 deletion include/h5pp/details/h5ppInfo.h
Original file line number Diff line number Diff line change
Expand Up @@ -378,7 +378,7 @@ namespace h5pp {

/*!
* \struct AttrInfo
* Struct with optional fields describing data on file, i.e. a dataset
* Struct with optional fields describing an attribute on file
*/
struct AttrInfo {
std::optional<hid::h5f> h5File = std::nullopt;
Expand Down Expand Up @@ -609,4 +609,58 @@ namespace h5pp {
}
};

struct LinkInfo {
std::optional<hid::h5f> h5File = std::nullopt;
std::optional<hid::h5o> h5Link = std::nullopt;
std::optional<std::string> linkPath = std::nullopt;
std::optional<bool> linkExists = std::nullopt;
std::optional<H5O_hdr_info_t> h5HdrInfo = std::nullopt; /*!< Information struct for object header metadata */
std::optional<hsize_t> h5HdrByte = std::nullopt; /*!< Total space for storing object header in file */
std::optional<H5O_type_t> h5ObjType = std::nullopt; /*!< Object type (dataset, group etc) */
std::optional<unsigned> refCount = std::nullopt; /*!< Reference count of object */
std::optional<time_t> atime = std::nullopt; /*!< Access time */
std::optional<time_t> mtime = std::nullopt; /*!< Modification time */
std::optional<time_t> ctime = std::nullopt; /*!< Change time */
std::optional<time_t> btime = std::nullopt; /*!< Birth time */
std::optional<hsize_t> num_attrs = std::nullopt; /*!< Number of attributes attached to object */
[[nodiscard]] std::string string(bool enable = true) const {
std::string msg;
if(not enable) return msg;
/* clang-format off */
if(refCount) msg.append(h5pp::format(" | refCount {}", refCount.value()));
if(h5HdrByte) msg.append(h5pp::format(" | header bytes {}", h5HdrByte.value()));
if(linkPath) msg.append(h5pp::format(" | link [{}]", linkPath.value()));
return msg;
/* clang-format on */
}

[[nodiscard]] hid::h5f getLocId() const {
if(h5File) return h5File.value();
if(h5Link) return H5Iget_file_id(h5Link.value());
h5pp::logger::log->debug("Header location id is not defined");
return static_cast<hid_t>(0);
}
[[nodiscard]] bool hasLocId() const { return h5File.has_value() or h5Link.has_value(); }

void assertReadReady() const {
std::string error_msg;
/* clang-format off */
if(not h5File) error_msg.append("\t h5File\n");
if(not h5Link) error_msg.append("\t h5Link\n");
if(not linkPath) error_msg.append("\t linkPath\n");
if(not linkExists) error_msg.append("\t linkExists\n");
if(not h5HdrInfo) error_msg.append("\t h5HdrInfo\n");
if(not h5HdrByte) error_msg.append("\t h5HdrByte\n");
if(not h5ObjType) error_msg.append("\t h5ObjType\n");
if(not refCount) error_msg.append("\t refCount\n");
if(not atime) error_msg.append("\t atime\n");
if(not mtime) error_msg.append("\t mtime\n");
if(not ctime) error_msg.append("\t ctime\n");
if(not btime) error_msg.append("\t btime\n");
if(not num_attrs) error_msg.append("\t num_attrs\n");
/* clang-format on */
if(not error_msg.empty()) throw std::runtime_error(h5pp::format("Cannot read from table: The following fields are not set:\n{}", error_msg));
}
};

}
93 changes: 82 additions & 11 deletions include/h5pp/details/h5ppScan.h
Original file line number Diff line number Diff line change
Expand Up @@ -200,9 +200,9 @@ namespace h5pp::scan {
* @param plists (optional) access property for the file. Used to determine link access property when searching for the dataset.
*/
template<typename DataType, typename h5x>
[[nodiscard]] inline h5pp::DsetInfo inferDsetInfo(const h5x & loc,
const DataType & data,
const Options & options = Options(),
[[nodiscard]] inline h5pp::DsetInfo inferDsetInfo(const h5x &loc,
const DataType &data,
const Options &options = Options(),
const PropertyLists &plists = PropertyLists()) {
static_assert(h5pp::type::sfinae::is_h5_loc_v<h5x>,
"Template function [h5pp::scan::inferDsetInfo(const h5x & loc, ...)] requires type h5x to be: "
Expand Down Expand Up @@ -431,10 +431,10 @@ namespace h5pp::scan {
* If the attribute exists properties are read from file.
* Otherwise properties are inferred from the given data */
template<typename DataType, typename h5x>
inline void inferAttrInfo(AttrInfo & info,
const h5x & loc,
const DataType & data,
const Options & options,
inline void inferAttrInfo(AttrInfo &info,
const h5x &loc,
const DataType &data,
const Options &options,
const PropertyLists &plists = PropertyLists()) {
static_assert(h5pp::type::sfinae::is_h5_loc_v<h5x>,
"Template function [h5pp::scan::readAttrInfo(..., const h5x & loc, ...)] requires type h5x to be: "
Expand Down Expand Up @@ -659,7 +659,7 @@ namespace h5pp::scan {
std::vector<size_t> field_offsets(n_fields);
std::vector<std::string> field_names_vec(n_fields);
size_t record_bytes;
char ** field_names = new char *[n_fields];
char **field_names = new char *[n_fields];
for(size_t i = 0; i < n_fields; i++) field_names[i] = new char[255];

// Read the data
Expand Down Expand Up @@ -710,9 +710,9 @@ namespace h5pp::scan {
}

template<typename h5x>
inline void makeTableInfo(h5pp::TableInfo & info,
const h5x & loc,
const Options & options,
inline void makeTableInfo(h5pp::TableInfo &info,
const h5x &loc,
const Options &options,
std::string_view tableTitle,
const PropertyLists &plists = PropertyLists()) {
readTableInfo(info, loc, options, plists);
Expand Down Expand Up @@ -805,4 +805,75 @@ namespace h5pp::scan {
h5pp::format("Could not infer table info for new table [{}]: No table title given", info.tablePath.value()));
}

/*! \brief Populates an AttrInfo object with properties read from file */
template<typename h5x>
inline void readLinkInfo(LinkInfo &info, const h5x &loc, const Options &options, const PropertyLists &plists = PropertyLists()) {
static_assert(h5pp::type::sfinae::is_h5_loc_v<h5x>,
"Template function [h5pp::scan::readLinkInfo(..., const h5x & loc, ...)] requires type h5x to be: "
"[h5pp::hid::h5f], [h5pp::hid::h5g] or [h5pp::hid::h5o]");

if(not options.linkPath and not info.linkPath) throw std::runtime_error("Could not read attribute info: No link path was given");
if(not info.linkPath) info.linkPath = h5pp::util::safe_str(options.linkPath.value());

h5pp::logger::log->debug("Scanning header of object [{}]", info.linkPath.value());

// Copy the location
if(not info.h5File) {
if constexpr(std::is_same_v<h5x, hid::h5f>)
info.h5File = loc;
else
info.h5File = H5Iget_file_id(loc);
}

/* It's important to note the convention used here:
* * linkPath is relative to loc.
* * loc can be a file or group, but NOT a dataset.
* * h5Link is the object on which the attribute is attached.
* * h5Link is an h5o object which means that it can be a file, group or dataset.
* * loc != h5Link.
*
*/

if(not info.linkExists) info.linkExists = h5pp::hdf5::checkIfLinkExists(info.getLocId(), info.linkPath.value(), plists.linkAccess);

// If the link does not exist, there isn't much else to do so we return;
if(info.linkExists and not info.linkExists.value()) return;

// From here on the link exists
if(not info.h5Link) info.h5Link = h5pp::hdf5::openLink<hid::h5o>(loc, info.linkPath.value(), info.linkExists, plists.linkAccess);

H5O_hdr_info_t hInfo;
H5O_info_t oInfo;
#if defined(H5Oget_info_vers) && H5Oget_info_vers >= 2
H5O_native_info_t nInfo;
H5Oget_native_info(info.h5Link.value(), &nInfo, H5O_INFO_ALL);
H5Oget_info(info.h5Link.value(), &oInfo, H5O_INFO_ALL);
hInfo = nInfo.hdr;
#else
H5Oget_info(info.h5Link.value(), &oInfo);
hinfo = oInfo.hdr;
#endif

info.h5HdrInfo = hInfo;
info.h5HdrByte = hInfo.space.total;
info.h5ObjType = oInfo.type;
info.refCount = oInfo.rc;
info.atime = oInfo.atime;
info.mtime = oInfo.mtime;
info.ctime = oInfo.ctime;
info.btime = oInfo.btime;
info.num_attrs = oInfo.num_attrs;

h5pp::logger::log->trace("Scanned header metadata {}", info.string(h5pp::logger::logIf(0)));
}

/*! \brief Creates and returns a populated AttrInfo object with properties read from file */
template<typename h5x>
[[nodiscard]] inline h5pp::LinkInfo
readLinkInfo(const h5x &loc, const Options &options, const PropertyLists &plists = PropertyLists()) {
h5pp::LinkInfo info;
readLinkInfo(info, loc, options, plists);
return info;
}

}

0 comments on commit 4e9747f

Please sign in to comment.