111 lines
2.7 KiB
C++
111 lines
2.7 KiB
C++
#ifndef FESA_IO_HDF5_HDF5_RAII_H_
|
|
#define FESA_IO_HDF5_HDF5_RAII_H_
|
|
|
|
#include <hdf5.h>
|
|
|
|
#include <stdexcept>
|
|
#include <string>
|
|
|
|
namespace fesa::hdf5_internal {
|
|
|
|
/// @brief Owns one HDF5 identifier and its matching close operation.
|
|
/// @note This move-only wrapper never crosses the private HDF5 boundary.
|
|
class Hdf5Handle {
|
|
public:
|
|
using Closer = herr_t (*)(hid_t);
|
|
|
|
Hdf5Handle() = default;
|
|
Hdf5Handle(hid_t value, Closer closer) : value_{value}, closer_{closer} {}
|
|
Hdf5Handle(const Hdf5Handle&) = delete;
|
|
Hdf5Handle& operator=(const Hdf5Handle&) = delete;
|
|
Hdf5Handle(Hdf5Handle&& other) noexcept
|
|
: value_{other.value_}, closer_{other.closer_} {
|
|
other.value_ = -1;
|
|
other.closer_ = nullptr;
|
|
}
|
|
Hdf5Handle& operator=(Hdf5Handle&& other) noexcept {
|
|
if (this != &other) {
|
|
Reset();
|
|
value_ = other.value_;
|
|
closer_ = other.closer_;
|
|
other.value_ = -1;
|
|
other.closer_ = nullptr;
|
|
}
|
|
return *this;
|
|
}
|
|
~Hdf5Handle() { Reset(); }
|
|
|
|
hid_t Get() const noexcept { return value_; }
|
|
herr_t CloseChecked() noexcept {
|
|
if (value_ < 0 || closer_ == nullptr) {
|
|
return 0;
|
|
}
|
|
const hid_t value = value_;
|
|
const Closer closer = closer_;
|
|
value_ = -1;
|
|
closer_ = nullptr;
|
|
return closer(value);
|
|
}
|
|
|
|
private:
|
|
void Reset() noexcept {
|
|
if (value_ >= 0 && closer_ != nullptr) {
|
|
(void)closer_(value_);
|
|
}
|
|
value_ = -1;
|
|
closer_ = nullptr;
|
|
}
|
|
|
|
hid_t value_{-1};
|
|
Closer closer_{nullptr};
|
|
};
|
|
|
|
/// @brief Converts an HDF5 failure into the private exception transport.
|
|
class Hdf5Failure final : public std::runtime_error {
|
|
public:
|
|
explicit Hdf5Failure(const std::string& message)
|
|
: std::runtime_error{message} {}
|
|
};
|
|
|
|
/// @brief Requires a successful HDF5 status code.
|
|
inline void RequireHdf5(herr_t result, const char* message) {
|
|
if (result < 0) {
|
|
throw Hdf5Failure{message};
|
|
}
|
|
}
|
|
|
|
/// @brief Requires a valid HDF5 identifier.
|
|
inline hid_t RequireHdf5Id(hid_t result, const char* message) {
|
|
if (result < 0) {
|
|
throw Hdf5Failure{message};
|
|
}
|
|
return result;
|
|
}
|
|
|
|
/// @brief Suppresses backend error-stack output while FESA translates errors.
|
|
class Hdf5ErrorSilencer {
|
|
public:
|
|
Hdf5ErrorSilencer() {
|
|
if (H5Eget_auto2(H5E_DEFAULT, &callback_, &client_data_) >= 0 &&
|
|
H5Eset_auto2(H5E_DEFAULT, nullptr, nullptr) >= 0) {
|
|
active_ = true;
|
|
}
|
|
}
|
|
Hdf5ErrorSilencer(const Hdf5ErrorSilencer&) = delete;
|
|
Hdf5ErrorSilencer& operator=(const Hdf5ErrorSilencer&) = delete;
|
|
~Hdf5ErrorSilencer() {
|
|
if (active_) {
|
|
(void)H5Eset_auto2(H5E_DEFAULT, callback_, client_data_);
|
|
}
|
|
}
|
|
|
|
private:
|
|
H5E_auto2_t callback_{nullptr};
|
|
void* client_data_{nullptr};
|
|
bool active_{false};
|
|
};
|
|
|
|
} // namespace fesa::hdf5_internal
|
|
|
|
#endif // FESA_IO_HDF5_HDF5_RAII_H_
|