Program Listing for File h5ppHid.h

Return to documentation for file (/home/david/GitProjects/h5pp/h5pp/include/h5pp/details/h5ppHid.h)

#pragma once
#include <hdf5.h>
#include <string>

namespace h5pp::hid {

    // Base class for all the safe "hid_t" wrapper classes. Zero value is the default for H5P and H5E so it's ok for them to return it zero
    template<typename hid_h5x, bool zeroValueIsOK = false>
    class hid_base {
        protected:
        hid_t val = 0;

        public:
        hid_base() = default;
        hid_base(std::initializer_list<int>) = delete;
        // Use enable_if to avoid implicit conversion from hid_h5x and still have a non-explicit hid_t constructor
        template<typename T, typename = std::enable_if_t<std::is_same_v<T, hid_t>>>
        hid_base(const T &other) {
            // constructor from hid_t
            if constexpr(zeroValueIsOK){
                if(other > 0 and not valid(other)) throw std::runtime_error("Given identifier must be valid");
            }else{
                if(not valid(other)) throw std::runtime_error("Given identifier must be valid");
            }
            val = other;
        }

        hid_base(const hid_base &other) {
            // Copy constructor
            if constexpr(zeroValueIsOK){
                if(other.val > 0 and not valid(other.val)) throw std::runtime_error("Given identifier must be valid");
            }else{
                if(not valid(other.val)) throw std::runtime_error("Given identifier must be valid");
            }
            val = other.val; // Checks that we got a valid identifier through .value() (throws)
            if(valid(other.val))
                H5Iinc_ref(val); // Increment reference counter of identifier
        }


        hid_base &operator=(const hid_base &rhs) {
            if(this == &rhs) return *this;
            // Copy assignment
            if constexpr(zeroValueIsOK){
                if(rhs.val > 0 and not valid(rhs.val)) throw std::runtime_error("Given identifier must be valid");
            }else{
                if(not valid(rhs.val)) throw std::runtime_error("Given identifier must be valid");
            }
            if(not equal(rhs.val)) close(); // Drop current
            val = rhs.val;
            if(valid(val))
                H5Iinc_ref(val); // Increment reference counter of identifier
            return *this;
        }
        virtual void                      close()     = 0;
        [[nodiscard]] virtual std::string tag() const = 0;
        [[nodiscard]] const hid_t &       value() const {
            if(valid() or (val == 0 and zeroValueIsOK))
                return val;
            else {
                H5Eprint(H5E_DEFAULT, stderr);
                throw std::runtime_error("Tried to return invalid identifier " + tag() + ":" + std::to_string(val));
            }
        }

        [[nodiscard]] auto refcount() const {
            if(zeroValueIsOK and val == 0) return 0;
            if(valid()) {
                auto refc = H5Iget_ref(val);
                if(refc >= 0)
                    return refc;
                else {
                    H5Eprint(H5E_DEFAULT, stderr);
                    throw std::runtime_error("Could not get reference count of identifier " + tag() + ":" + std::to_string(val));
                }
            } else {
                return 0;
            }
        }

        [[nodiscard]] std::string pretty_print() { return tag() + ":" + std::to_string(val) + "(" + std::to_string(refcount()) + ")"; }
        [[nodiscard]] std::string safe_print() { return std::to_string(val) + "(" + std::to_string(refcount()) + ")"; }

        [[nodiscard]] bool valid(const hid_t &other) const {
            auto result = H5Iis_valid(other);
            if(result < 0){
                H5Eprint(H5E_DEFAULT, stderr);
                throw std::runtime_error("Failed to determine validity of identifier");
            }
            return result > 0;
        }
        [[nodiscard]] bool valid() const { return valid(val); }
        [[nodiscard]] bool valid(const hid_h5x &other) const { return other.valid(); }

        // hid_t operators
        [[nodiscard]] virtual bool equal(const hid_t &rhs) const = 0;

        template<typename T, typename = std::enable_if_t<std::is_arithmetic_v<T>>>
        bool operator==(const T &rhs) const {
            return equal(rhs);
        }
        template<typename T, typename = std::enable_if_t<std::is_arithmetic_v<T>>>
        bool operator!=(const T &rhs) const {
            return not equal(rhs);
        }
        template<typename T, typename = std::enable_if_t<std::is_arithmetic_v<T>>>
        bool operator<=(const T &rhs) const {
            return val <= rhs;
        }
        template<typename T, typename = std::enable_if_t<std::is_arithmetic_v<T>>>
        bool operator>=(const T &rhs) const {
            return val >= rhs;
        }
        template<typename T, typename = std::enable_if_t<std::is_arithmetic_v<T>>>
        bool operator<(const T &rhs) const {
            return val < rhs;
        }
        template<typename T, typename = std::enable_if_t<std::is_arithmetic_v<T>>>
        bool operator>(const T &rhs) const {
            return val > rhs;
        }

        // hid_h5x operators
        [[nodiscard]] bool equal(const hid_h5x &rhs) const { return equal(rhs.value()); }
        bool               operator==(const hid_h5x &rhs) const { return equal(rhs); }
        bool               operator!=(const hid_h5x &rhs) const { return not equal(rhs); }
        bool               operator<=(const hid_h5x &rhs) const { return val <= rhs.value(); }
        bool               operator>=(const hid_h5x &rhs) const { return val >= rhs.value(); }
        bool               operator<(const hid_h5x &rhs) const { return val < rhs.value(); }
        bool               operator>(const hid_h5x &rhs) const { return val > rhs.value(); }

        [[nodiscard]] operator hid_t() const { return value(); } // Class can be used as an actual hid_t

        explicit             operator bool() const { return valid() and val > 0; } // Test if set with syntax if(a)
        explicit             operator std::string() const { return tag() + ":" + std::to_string(val); }
        explicit             operator std::string_view() const { return tag() + ":" + std::string_view(val); }
        friend std::ostream &operator<<(std::ostream &os, const hid_h5x &t) { return os << t.tag() << ":" << t.val; }
        virtual ~hid_base() = default;
    };

    // All our safe hid_t wrapper classes
    class h5p final : public hid_base<h5p, true> {
        public:
        using hid_base::hid_base;
        ~h5p() final { close(); }
        [[nodiscard]] std::string tag() const final { return "h5p"; }
        [[nodiscard]] bool        equal(const hid_t &rhs) const final { return (val > 0 and rhs > 0 and H5Pequal(val, rhs)) or val == rhs; }
        void                      close() final {
            if(valid()) {
                if(H5Iget_ref(val) > 1)
                    H5Idec_ref(val);
                else if(H5Pclose(val) < 0)
                    H5Eprint(H5E_DEFAULT, stderr);
            }
        }
    };

    class h5s final : public hid_base<h5s> {
        public:
        using hid_base::hid_base;
        ~h5s() final { close(); }
        [[nodiscard]] std::string tag() const final { return "h5s"; }
        [[nodiscard]] bool        equal(const hid_t &rhs) const final { return val == rhs; }
        void                      close() final {
            if(valid()) {
                if(H5Iget_ref(val) > 1)
                    H5Idec_ref(val);
                else if(H5Sclose(val) < 0)
                    H5Eprint(H5E_DEFAULT, stderr);
            }
        }
    };

    class h5t final : public hid_base<h5t> {
        public:
        using hid_base::hid_base;
        ~h5t() final { close(); }
        [[nodiscard]] std::string tag() const final { return "h5t"; }
        [[nodiscard]] bool        equal(const hid_t &rhs) const final { return (valid(val) and valid(rhs) and H5Tequal(val, rhs)) or val == rhs; }
        void                      close() final {
            if(valid()) {
                if(H5Iget_ref(val) > 1)
                    H5Idec_ref(val);
                else if(H5Tclose(val) < 0)
                    H5Eprint(H5E_DEFAULT, stderr);
            }
        }
    };

    class h5d final : public hid_base<h5d> {
        public:
        using hid_base::hid_base;
        ~h5d() final { close(); }
        [[nodiscard]] std::string tag() const final { return "h5d"; }
        [[nodiscard]] bool        equal(const hid_t &rhs) const final { return val == rhs; }
        void                      close() final {
            if(valid()) {
                if(H5Iget_ref(val) > 1)
                    H5Idec_ref(val);
                else if(H5Dclose(val) < 0)
                    H5Eprint(H5E_DEFAULT, stderr);
            }
        }
    };

    class h5g final : public hid_base<h5g> {
        public:
        using hid_base::hid_base;
        ~h5g() final { close(); }
        [[nodiscard]] std::string tag() const final { return "h5g"; }
        [[nodiscard]] bool        equal(const hid_t &rhs) const final { return val == rhs; }
        void                      close() final {
            if(valid()) {
                if(H5Iget_ref(val) > 1)
                    H5Idec_ref(val);
                else if(H5Gclose(val) < 0)
                    H5Eprint(H5E_DEFAULT, stderr);
            }
        }
    };

    class h5a final : public hid_base<h5a> {
        public:
        using hid_base::hid_base;
        ~h5a() final { close(); }
        [[nodiscard]] std::string tag() const final { return "h5a"; }
        [[nodiscard]] bool        equal(const hid_t &rhs) const final { return val == rhs; }
        void                      close() final {
            if(valid()) {
                if(H5Iget_ref(val) > 1)
                    H5Idec_ref(val);
                else if(H5Aclose(val) < 0)
                    H5Eprint(H5E_DEFAULT, stderr);
            }
        }
    };

    class h5o final : public hid_base<h5o> {
        public:
        using hid_base::hid_base;
        ~h5o() final { close(); }
        [[nodiscard]] std::string tag() const final { return "h5o"; }
        [[nodiscard]] bool        equal(const hid_t &rhs) const final { return val == rhs; }
        void                      close() final {
            if(valid()) {
                if(H5Iget_ref(val) > 1)
                    H5Idec_ref(val);
                else if(H5Oclose(val) < 0)
                    H5Eprint(H5E_DEFAULT, stderr);
            }
        }
    };

    class h5f final : public hid_base<h5f> {
        public:
        using hid_base::hid_base;
        ~h5f() final { close(); }
        [[nodiscard]] std::string tag() const final { return "h5f"; }
        [[nodiscard]] bool        equal(const hid_t &rhs) const final { return val == rhs; }
        void                      close() final {
            if(H5Iget_ref(val) > 1)
                H5Idec_ref(val);
            else if(H5Fclose(val) < 0)
                H5Eprint(H5E_DEFAULT, stderr);
        }
    };

    class h5e final : public hid_base<h5e, true> {
        public:
        using hid_base::hid_base;
        ~h5e() final { close(); }
        [[nodiscard]] std::string tag() const final { return "h5e"; }
        [[nodiscard]] bool        equal(const hid_t &rhs) const final { return val == rhs; }
        void                      close() final {
            if(valid()) {
                if(H5Iget_ref(val) > 1)
                    H5Idec_ref(val);
                else
                    H5Eclose_stack(val);
            }
        }
    };
}