1 #pragma once 2 3 #include <cassert> 4 #include <cstdint> 5 #include <stdexcept> 6 #include <utility> 7 8 #include <hdf5.h> 9 10 namespace ont { namespace hdf5 { 11 12 /// Thrown when something goes wrong internally in HDF5. 13 class Exception : public std::runtime_error 14 { 15 public: Exception()16 Exception() 17 : std::runtime_error("HDF5 exception") 18 { 19 } 20 }; 21 22 /// An HDF5 identifier. 23 /// 24 /// IdRef should be used by anything that wants to keep a reference to a HDF5 25 /// object. 26 using Id = hid_t; 27 28 /// Maintains a reference to an HDF5 identifier. 29 /// 30 /// When you first create the identifier, use IdRef::claim() to grab it and make 31 /// sure it will be closed. 32 class IdRef final 33 { 34 public: 35 /// Create an IdRef that takes ownership of an existing reference. 36 /// 37 /// This is intended for use when you receive an ID from the HDF5 library. 38 /// 39 /// The reference counter will be decremented on destruction, but will not 40 /// be incremented. 41 static IdRef claim(Id id); 42 43 /// Create an IdRef that takes a new reference to the ID. 44 /// 45 /// The reference counter will be incremented on creation, and decremented 46 /// on destruction. 47 static IdRef ref(Id id); 48 49 /// Create an IdRef that refers to a global ID. 50 /// 51 /// No reference counting will be done. global(Id id)52 static IdRef global(Id id) 53 { 54 return IdRef(id, true); 55 } 56 57 /// Create an IdRef that refers to a global ID. This call 58 /// takes a non-global id and makes it global. 59 /// 60 /// No reference counting will be done. 61 static IdRef global_ref(Id id); 62 63 /// Create an invalid IdRef. 64 /// 65 /// The only use for the resulting object is to copy or move into it. 66 IdRef() = default; 67 68 IdRef(IdRef const& other); 69 IdRef& operator=(IdRef const&); 70 IdRef(IdRef && other)71 IdRef(IdRef && other) 72 : m_id(other.m_id) 73 , m_is_global_constant(other.m_is_global_constant) 74 { 75 other.m_id = -1; 76 other.m_is_global_constant = false; 77 } 78 IdRef& operator=(IdRef && other) 79 { 80 std::swap(m_id, other.m_id); 81 std::swap(m_is_global_constant, other.m_is_global_constant); 82 return *this; 83 } 84 85 ~IdRef(); 86 swap(IdRef & other)87 void swap(IdRef & other) { 88 std::swap(m_id, other.m_id); 89 std::swap(m_is_global_constant, other.m_is_global_constant); 90 } 91 92 /// Take ownership of the ID. 93 /// 94 /// This object will no longer hold a reference to the ID. It is up to the 95 /// called to deref the ID. release()96 Id release() { 97 Id id = m_id; 98 m_id = -1; 99 m_is_global_constant = false; 100 return id; 101 } 102 103 /// Get the ID. 104 /// 105 /// The reference count will not be changed. This is mostly for passing into 106 /// HDF5 function calls. get()107 Id get() const 108 { 109 assert(m_id >= 0); 110 return m_id; 111 } 112 113 /// Get the reference count of the ID. 114 int ref_count() const; 115 116 /// Check whether this IdRef contains an ID. 117 /// 118 /// Note that it does not check whether HDF5 thinks the ID is valid. 119 explicit operator bool() const { return m_id >= 0; } 120 121 private: 122 // use claim() or ref() IdRef(Id id)123 explicit IdRef(Id id) : m_id(id), m_is_global_constant(false) {} IdRef(Id id,bool is_global)124 explicit IdRef(Id id, bool is_global) 125 : m_id(id) 126 , m_is_global_constant(is_global) 127 {} 128 129 Id m_id = -1; 130 bool m_is_global_constant = false; 131 }; 132 133 }}