Marray
hdf5.hxx
1 // http://www.andres.sc
2 //
3 #pragma once
4 #ifndef ANDRES_HDF5_HXX
5 #define ANDRES_HDF5_HXX
6 
7 #include <cassert>
8 #include <string>
9 #include <vector>
10 #include <stdexcept>
11 
12 #include "hdf5.h"
13 
14 namespace andres {
15 
17 namespace hdf5 {
18 
21 
22 template<bool B> class HandleCheck;
23 template<> class HandleCheck<false> {
24 public:
25  HandleCheck()
26  { counter_ = H5Fget_obj_count(H5F_OBJ_ALL, H5F_OBJ_ALL); }
27  void check()
28  { assert(counter_ == H5Fget_obj_count(H5F_OBJ_ALL, H5F_OBJ_ALL)); }
29 private:
30  ssize_t counter_;
31 };
32 template<> class HandleCheck<true> {
33 public:
34  void check() {}
35 };
36 
37 template<class T>
38 inline hid_t uintTypeHelper() {
39  switch(sizeof(T)) {
40  case 1:
41  return H5T_STD_U8LE;
42  case 2:
43  return H5T_STD_U16LE;
44  case 4:
45  return H5T_STD_U32LE;
46  case 8:
47  return H5T_STD_U64LE;
48  default:
49  throw std::runtime_error("No matching HDF5 type.");
50  }
51 }
52 
53 template<class T>
54 inline hid_t intTypeHelper() {
55  switch(sizeof(T)) {
56  case 1:
57  return H5T_STD_I8LE;
58  case 2:
59  return H5T_STD_I16LE;
60  case 4:
61  return H5T_STD_I32LE;
62  case 8:
63  return H5T_STD_I64LE;
64  default:
65  throw std::runtime_error("No matching HDF5 type.");
66  }
67 }
68 
69 template<class T>
70 inline hid_t floatingTypeHelper() {
71  switch(sizeof(T)) {
72  case 4:
73  return H5T_IEEE_F32LE;
74  case 8:
75  return H5T_IEEE_F64LE;
76  default:
77  throw std::runtime_error("No matching HDF5 type.");
78  }
79 }
80 
81 template<class T>
82  inline hid_t hdf5Type();
83 template<> inline hid_t hdf5Type<unsigned char>()
84  { return uintTypeHelper<unsigned char>(); }
85 template<> inline hid_t hdf5Type<unsigned short>()
86  { return uintTypeHelper<unsigned short>(); }
87 template<> inline hid_t hdf5Type<unsigned int>()
88  { return uintTypeHelper<unsigned int>(); }
89 template<> inline hid_t hdf5Type<unsigned long>()
90  { return uintTypeHelper<unsigned long>(); }
91 template<> inline hid_t hdf5Type<unsigned long long>()
92  { return uintTypeHelper<unsigned long long>(); }
93 template<> inline hid_t hdf5Type<signed char>()
94  { return intTypeHelper<signed char>(); }
95 template<> inline hid_t hdf5Type<char>()
96  { return uintTypeHelper<char>(); }
97 template<> inline hid_t hdf5Type<short>()
98  { return intTypeHelper<short>(); }
99 template<> inline hid_t hdf5Type<int>()
100  { return intTypeHelper<int>(); }
101 template<> inline hid_t hdf5Type<long>()
102  { return intTypeHelper<long>(); }
103 template<> inline hid_t hdf5Type<long long>()
104  { return intTypeHelper<long long>(); }
105 template<> inline hid_t hdf5Type<float>()
106  { return floatingTypeHelper<float>(); }
107 template<> inline hid_t hdf5Type<double>()
108  { return floatingTypeHelper<double>(); }
109 
119 inline hid_t
121  const std::string& filename,
122  HDF5Version hdf5version = HDF5_VERSION_DEFAULT
123 ) {
124  hid_t version = H5P_DEFAULT;
125  if(hdf5version == HDF5_VERSION_LATEST) {
126  version = H5Pcreate(H5P_FILE_ACCESS);
127  H5Pset_libver_bounds(version, H5F_LIBVER_LATEST, H5F_LIBVER_LATEST);
128  }
129 
130  hid_t fileHandle = H5Fcreate(filename.c_str(), H5F_ACC_TRUNC, H5P_DEFAULT, version);
131  if(fileHandle < 0) {
132  throw std::runtime_error("Could not create HDF5 file: " + filename);
133  }
134 
135  return fileHandle;
136 }
137 
148 inline hid_t
150  const std::string& filename,
151  FileAccessMode fileAccessMode = READ_ONLY,
152  HDF5Version hdf5version = HDF5_VERSION_DEFAULT
153 ) {
154  hid_t access = H5F_ACC_RDONLY;
155  if(fileAccessMode == READ_WRITE) {
156  access = H5F_ACC_RDWR;
157  }
158 
159  hid_t version = H5P_DEFAULT;
160  if(hdf5version == HDF5_VERSION_LATEST) {
161  version = H5Pcreate(H5P_FILE_ACCESS);
162  H5Pset_libver_bounds(version, H5F_LIBVER_LATEST, H5F_LIBVER_LATEST);
163  }
164 
165  hid_t fileHandle = H5Fopen(filename.c_str(), access, version);
166  if(fileHandle < 0) {
167  throw std::runtime_error("Could not open HDF5 file: " + filename);
168  }
169 
170  return fileHandle;
171 }
172 
179 inline void closeFile(
180  const hid_t& handle
181 ) {
182  H5Fclose(handle);
183 }
184 
193 inline hid_t
195  const hid_t& parentHandle,
196  const std::string& groupName
197 ) {
198  hid_t groupHandle = H5Gcreate(parentHandle, groupName.c_str(),
199  H5P_DEFAULT, H5P_DEFAULT, H5P_DEFAULT);
200  if(groupHandle < 0) {
201  throw std::runtime_error("Could not create HDF5 group.");
202  }
203  return groupHandle;
204 }
205 
214 inline hid_t
216  const hid_t& parentHandle,
217  const std::string& groupName
218 ) {
219  hid_t groupHandle = H5Gopen(parentHandle, groupName.c_str(), H5P_DEFAULT);
220  if(groupHandle < 0) {
221  throw std::runtime_error("Could not open HDF5 group.");
222  }
223  return groupHandle;
224 }
225 
232 inline void
234  const hid_t& handle
235 ) {
236  H5Gclose(handle);
237 }
238 
241 template<class T>
242 inline void
244  const hid_t parentHandle,
245  const std::string datasetName,
246  const std::vector<T>& data
247 ) {
248  hsize_t shape[] = {data.size()};
249  hid_t dataspace = H5Screate_simple(1, shape, NULL);
250  if(dataspace < 0) {
251  throw std::runtime_error("could not create HDF5 dataspace.");
252  }
253  hid_t dataset = H5Dcreate(parentHandle, datasetName.c_str(), hdf5Type<T>(), dataspace, H5P_DEFAULT, H5P_DEFAULT, H5P_DEFAULT);
254  if(dataset < 0) {
255  H5Sclose(dataspace);
256  throw std::runtime_error("could not create HDF5 dataset.");
257  }
258  hid_t status = H5Dwrite(dataset, hdf5Type<T>(), H5S_ALL, H5S_ALL, H5P_DEFAULT, data.data());
259  H5Dclose(dataset);
260  H5Sclose(dataspace);
261  if(status < 0) {
262  throw std::runtime_error("could not write to HDF5 dataset.");
263  }
264 }
265 
268 template<class T>
269 inline void
271  const hid_t parentHandle,
272  const std::string datasetName,
273  std::vector<T>& data,
274  HDF5Version hdf5Version = HDF5_VERSION_DEFAULT
275 ) {
276  // open dataset and get types
277  hid_t dataset = H5Dopen(parentHandle, datasetName.c_str(), H5P_DEFAULT);
278  if(dataset < 0) {
279  throw std::runtime_error("could not open HDF5 dataset.");
280  }
281  hid_t typeFile = H5Dget_type(dataset);
282 
283  // get dimension and shape
284  hid_t filespace = H5Dget_space(dataset);
285  int dimension = H5Sget_simple_extent_ndims(filespace);
286  if(dimension != 1) {
287  throw std::runtime_error("HDF5 dataset is not one-dimensional.");
288  }
289  hsize_t size = 0;
290  herr_t status = H5Sget_simple_extent_dims(filespace, &size, NULL);
291  if(status < 0) {
292  H5Dclose(dataset);
293  H5Tclose(typeFile);
294  H5Sclose(filespace);
295  throw std::runtime_error("could not get shape of HDF5 dataset.");
296  }
297 
298  // read
299  data.resize(size);
300  status = H5Dread(dataset, hdf5Type<T>(), H5S_ALL, H5S_ALL, H5P_DEFAULT, data.data());
301 
302  // close dataset and types
303  H5Dclose(dataset);
304  H5Tclose(typeFile);
305  H5Sclose(filespace);
306  if(status < 0) {
307  throw std::runtime_error("could not read from HDF5 dataset 'points'.");
308  }
309 }
310 
320 template<class T>
321 inline void
323  const std::string& filename,
324  const std::string& datasetName,
325  std::vector<T>& out,
326  HDF5Version hdf5version
327 ) {
328  hid_t file = openFile(filename, READ_ONLY, hdf5version);
329  load(file, datasetName, out);
330  closeFile(file);
331 }
332 
333 } // namespace hdf5
334 } // namespace andres
335 
336 #endif // #ifndef ANDRES_HDF5_HXX