
.. _program_listing_file__home_david_GitProjects_h5pp_h5pp_include_h5pp_details_h5ppHid.h:

Program Listing for File h5ppHid.h
==================================

|exhale_lsh| :ref:`Return to documentation for file <file__home_david_GitProjects_h5pp_h5pp_include_h5pp_details_h5ppHid.h>` (``/home/david/GitProjects/h5pp/h5pp/include/h5pp/details/h5ppHid.h``)

.. |exhale_lsh| unicode:: U+021B0 .. UPWARDS ARROW WITH TIP LEFTWARDS

.. code-block:: cpp

   #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);
               }
           }
       };
   }
