#ifndef FESA_IO_HDF5_HDF5_RAII_H_ #define FESA_IO_HDF5_HDF5_RAII_H_ #include #include #include 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_