Loading [MathJax]/extensions/tex2jax.js
IODA
All Classes Namespaces Files Functions Variables Typedefs Enumerations Enumerator Friends Macros Modules Pages
Handles.h
Go to the documentation of this file.
1 #pragma once
2 /*
3  * (C) Copyright 2017-2020 Ryan Honeyager
4  * (C) Copyright 2020-2021 UCAR
5  *
6  * This software is licensed under the terms of the Apache Licence Version 2.0
7  * which can be obtained at http://www.apache.org/licenses/LICENSE-2.0.
8  */
9 /*! \addtogroup ioda_internals_engines_hh
10  *
11  * @{
12  * \file Handles.h
13  * \brief HDF5 resource handles in C++.
14  */
15 #include <hdf5.h>
16 
17 #include <functional>
18 #include <memory>
19 
20 namespace ioda {
21 namespace detail {
22 namespace Engines {
23 namespace HH {
24 
25 namespace Handles {
26 
27 /// @brief Describes what a handle points to.
28 /// @deprecated To be removed.
29 /// @ingroup ioda_internals_engines_hh
30 enum class Handle_Types {
31  ATTRIBUTE,
32  DATASET,
33  DATASPACE,
34  DATATYPE,
35  FILE,
36  GROUP,
37  LINK,
39  REFERENCE,
40  UNKNOWN
41 };
42 
43 /// @brief A class to wrap HDF5's hid_t resource handles.
44 /// @ingroup ioda_internals_engines_hh
45 ///
46 /// This class adds RAII resource management to keep track of the various
47 /// hid_t handles that HDF5 returns to ioda. A handle, in this context, is
48 /// an opaque integer that references an HDF5-internal data structure that
49 /// tracks what is accessing a particular resource like a file, a group, an
50 /// attribute, and so on. Whenever you open or create a resource, you get back
51 /// a handle that you reference when calling other functions on that resource.
52 ///
53 /// The problem with hid_t is that HDF5's C interface is a C interface, and there
54 /// are three key points that HH_hid_t aims to address.
55 ///
56 /// - You can go out of scope and accidentally lose track of an open resource handle.
57 /// - You can release the handle but might use the wrong function to release, since
58 /// HDF5 provides at least ten release functions.
59 /// - HDF5 has some reserved values, like H5P_DEFAULT, that are not strictly handles
60 /// but are passed to the same function calls. These values can never be released.
61 ///
62 /// Usage:
63 ///
64 /// Wrapping an HDF5 return call into a managed handle:
65 /// ```
66 /// hid_t raw_handle = H5Fopen(.....);
67 /// HH_hid_t managed_handle(raw_handle, Handles::Closers::CloseHDF5File::CloseP);
68 /// ...
69 /// ```
70 /// The functions in Handles::Closers let you specify which function releases a handle.
71 ///
72 /// Using a wrapped handle:
73 /// ```
74 /// auto res = H5Gopen(managed_handle(), ...);
75 /// // You could also explicitly type managed_handle.get().
76 /// ```
77 ///
78 /// Cloning a handle:
79 /// ```
80 /// HH_hid_t hnd2 = hnd1;
81 /// ```
82 ///
83 /// Checking if a handle is "valid" - i.e. that an error did not occur:
84 /// ```
85 /// HH_hid_t managed_handle(H5Fopen(.....), Handles::Closers::CloseHDF5File::CloseP);
86 /// if (!managed_handle.isValid()) throw;
87 /// ```
88 ///
89 /// @todo Autodetect hid_t handle "type" if possible and auto-assign the closer function.
90 /// Will not work in all cases, particularly property lists, as HDF5 does not have a
91 /// good detection function for these.
92 class HH_hid_t {
93  ::std::shared_ptr<hid_t> _h;
94  // Handle_Types _typ;
95 public:
97  hid_t get() const;
98  ::std::shared_ptr<hid_t> getShared() const;
99 
100  // Future handle type safety implementation:
101  // Handle_Types get_type() const { return _typ; }
102  // bool isA(Handle_Types t) const { return (_typ == t); }
103  // template <typename T>
104  // bool isA() const { return (_typ == ); }
105 
106  HH_hid_t();
107  HH_hid_t(::std::shared_ptr<hid_t> h);
108  HH_hid_t(hid_t val, const std::function<void(hid_t*)>& closer = nullptr);
109  hid_t operator()() const;
110  static HH_hid_t dummy();
111  bool isValid() const;
112 };
113 
114 /// @brief Encapsulate a static hid object in a shared pointer.
115 /// @ingroup ioda_internals_engines_hh
116 inline std::shared_ptr<hid_t> createStatic(hid_t newh) {
117  return std::shared_ptr<hid_t>(new hid_t(newh));
118 }
119 
120 /// @brief Detect invalid HDF5 ids
121 /// @ingroup ioda_internals_engines_hh
123  static inline bool isValid(hid_t h) {
124  htri_t res = H5Iis_valid(h);
125  if (res <= 0) {
126  return false;
127  }
128  return true;
129  }
130  static inline bool isInvalid(hid_t h) { return !isValid(h); }
131 };
132 
133 /// \brief Structs in this namespace implement close operations on HDF5 handles.
134 /// \ingroup ioda_internals_engines_hh
135 namespace Closers {
137  static inline void Close(hid_t h) { herr_t err = H5Aclose(h); }
138  static inline void CloseP(hid_t* h) {
139  if (*h >= 0) H5Aclose(*h);
140  delete h;
141  }
142 };
144  static inline void Close(hid_t h) { herr_t err = H5Fclose(h); }
145  static inline void CloseP(hid_t* h) {
146  if (*h >= 0) H5Fclose(*h);
147  delete h;
148  }
149 };
151  static inline void Close(hid_t h) { herr_t err = H5Dclose(h); }
152  static inline void CloseP(hid_t* h) {
153  if (*h >= 0) H5Dclose(*h);
154  delete h;
155  }
156 };
158  static inline void Close(hid_t h) { herr_t err = H5Sclose(h); }
159  static inline void CloseP(hid_t* h) {
160  if (*h >= 0) H5Sclose(*h);
161  delete h;
162  }
163 };
165  static inline void Close(hid_t h) { herr_t err = H5Tclose(h); }
166  static inline void CloseP(hid_t* h) {
167  if (*h >= 0) H5Tclose(*h);
168  delete h;
169  }
170 };
172  static inline void Close(hid_t h) { herr_t err = H5Gclose(h); }
173  static inline void CloseP(hid_t* h) {
174  if (*h >= 0) H5Gclose(*h);
175  delete h;
176  }
177 };
179  static inline void Close(hid_t h) { herr_t err = H5Pclose(h); }
180  static inline void CloseP(hid_t* h) {
181  if (*h >= 0) H5Pclose(*h);
182  delete h;
183  }
184 };
185 struct DoNotClose {
186  static inline void Close(hid_t) { return; }
187  static inline void CloseP(hid_t* h) { delete h; }
188 };
189 } // namespace Closers
190 } // namespace Handles
191 using Handles::HH_hid_t;
192 } // namespace HH
193 } // namespace Engines
194 } // namespace detail
195 } // namespace ioda
196 
197 /// @}
A class to wrap HDF5's hid_t resource handles.
Definition: Handles.h:92
::std::shared_ptr< hid_t > getShared() const
Definition: Handles.cpp:23
::std::shared_ptr< hid_t > _h
Definition: Handles.h:93
Handle_Types
Describes what a handle points to.
Definition: Handles.h:30
std::shared_ptr< hid_t > createStatic(hid_t newh)
Encapsulate a static hid object in a shared pointer.
Definition: Handles.h:116