hdf5serie  2.0.0
HDF5 Serie
interface.h
1/* Copyright (C) 2009 Markus Friedrich
2 *
3 * This library is free software; you can redistribute it and/or
4 * modify it under the terms of the GNU Lesser General Public
5 * License as published by the Free Software Foundation; either
6 * version 2.1 of the License, or (at your option) any later version.
7 *
8 * This library is distributed in the hope that it will be useful,
9 * but WITHOUT ANY WARRANTY; without even the implied warranty of
10 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
11 * Lesser General Public License for more details.
12 *
13 * You should have received a copy of the GNU Lesser General Public
14 * License along with this library; if not, write to the Free Software
15 * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA
16 *
17 * Contact:
18 * friedrich.at.gc@googlemail.com
19 *
20 */
21
22#ifndef _HDF5SERIE_INTERFACE_H_
23#define _HDF5SERIE_INTERFACE_H_
24
25#include <fmatvec/atom.h>
26#include <hdf5.h>
27#include <map>
28#include <set>
29#include <utility>
30#include <vector>
31
32namespace H5 {
33
34 // The class defines all base classes of the interface for HDF5Serie.
35 // The interface has the following virtual functions which gets, started from File, calles
36 // for all created children classes recursively:
37 // - close: closes all HDF5 handles (hid_t) before File will notify other processes that the file is closed
38 // - refresh: makes the HDF5 refresh calls
39 // - flush: makes the HDF5 flush calls
40 // - enableSWMR: for type=write: closes all attributes than switches File to SWMR writing mode
41 // for type=writeWithRename: closes all elements, rename the file, reopen all elements
42 // except attributes, then switches File to SWMR writing mode
43
44 struct ErrorInfo {
45 ErrorInfo(hid_t cls_id_, hid_t maj_num_, hid_t min_num_, unsigned line_,
46 std::string func_name_, std::string file_name_, std::string desc_) :
47 cls_id (cls_id_),
48 maj_num (maj_num_),
49 min_num (min_num_),
50 line (line_),
51 func_name(std::move(func_name_)),
52 file_name(std::move(file_name_)),
53 desc (std::move(desc_))
54 {}
55 hid_t cls_id;
56 hid_t maj_num;
57 hid_t min_num;
58 unsigned line;
59 std::string func_name;
60 std::string file_name;
61 std::string desc;
62 bool operator==(const ErrorInfo &b) const;
63 };
64
65 class Exception : public std::exception {
66 protected:
67 std::string path;
68 std::string msg;
69 mutable std::string whatMsg;
70 std::vector<ErrorInfo> errorStack;
71 public:
72 explicit Exception(std::string path_, std::string msg_, const std::vector<ErrorInfo> &errorStack_={});
73 ~Exception() noexcept override;
74 const char* what() const noexcept override;
75 const std::vector<ErrorInfo>& getErrorStack() const { return errorStack; }
76 };
77
78 class ScopedHID {
79 protected:
80 using CloseFunc = herr_t (*)(hid_t);
81 hid_t id{-1};
82 CloseFunc closeFunc{nullptr};
83 public:
84 ScopedHID() = default;
85 ScopedHID(hid_t id_, CloseFunc closeFunc_) : id(id_), closeFunc(closeFunc_) {
86 if(id<0)
87 throw Exception({}, "A call of a HDF5 function failed.");
88 if(!closeFunc)
89 throw Exception({}, "Internal erorr: no close function defined in ScopedHID.");
90 }
91 ScopedHID(const ScopedHID &) = delete;
92 ScopedHID(ScopedHID &&src) noexcept {
93 id = src.id;
94 closeFunc = src.closeFunc;
95 src.id = -1;
96 src.closeFunc = nullptr;
97 }
98 ScopedHID& operator=(const ScopedHID &) = delete;
99 ScopedHID& operator=(ScopedHID &&src) noexcept {
100 reset();
101 id = src.id;
102 closeFunc = src.closeFunc;
103 src.id = -1;
104 src.closeFunc = nullptr;
105 return *this;
106 }
107 ~ScopedHID() {
108 try {
109 reset();
110 }
111 catch(Exception &ex) {
112 std::cerr<<"Error in ScopedHID::dtor: "<<ex.what()<<std::endl;
113 }
114 }
115 operator hid_t() {
116 return id;
117 }
118 void reset() {
119 if(id>=0)
120 if(closeFunc(id)<0)
121 throw Exception({}, "Close function of ScopedHID failed.");
122 id=-1;
123 closeFunc=nullptr;
124 }
125 void reset(hid_t id_, CloseFunc closeFunc_) {
126 reset();
127 if(id_<0)
128 throw Exception({}, "A call to a HDF5 function failed.");
129 if(!closeFunc_)
130 throw Exception({}, "No close function defined.");
131 id=id_;
132 closeFunc=closeFunc_;
133 }
134 };
135
136 inline void checkCall(herr_t err) {
137 if(err<0)
138 throw Exception({}, "A call to a HDF5 function failed.");
139 }
140
141 class File;
142 class GroupBase;
143 class Attribute;
144 class Object;
145 template<class Child, class Self> class Container;
146
147 enum ElementType {
148 simpleDatasetScalar,
149 simpleDatasetVector,
150 simpleDatasetMatrix,
151 vectorSerie,
152 simpleAttributeScalar,
153 simpleAttributeVector,
154 simpleAttributeMatrix
155 };
156
157 class Element : virtual public fmatvec::Atom {
158 friend class Container<Attribute, Object>;
159 friend class Container<Object, GroupBase>;
160 protected:
161 ScopedHID id;
162 std::string name;
163 Element(std::string name_);
164 ~Element() override;
165 virtual void close();
166 virtual void refresh();
167 virtual void flush();
168 virtual void enableSWMR();
169 public:
171 hid_t getID() { return id; }
172 std::string getName() { return name; }
173 };
174
175 // a container of objects of type Child which have itself a parent of type Self
176 template<class Child, class Self>
177 class Container {
178 protected:
179 Container() = default;
180 ~Container() {
181 for(auto it=childs.begin(); it!=childs.end(); ++it)
182 delete it->second;
183 }
184 void close() {
185 for(auto it=childs.begin(); it!=childs.end(); ++it)
186 it->second->close();
187 }
188 void refresh() {
189 for(auto it=childs.begin(); it!=childs.end(); ++it)
190 it->second->refresh();
191 }
192 void flush() {
193 for(auto it=childs.begin(); it!=childs.end(); ++it)
194 it->second->flush();
195 }
196 void enableSWMR() {
197 if constexpr (std::is_same_v<Child, Attribute>) {
198 // attributes must be closed if SWMR is enabled
199 for(auto it=childs.begin(); it!=childs.end(); ++it)
200 delete it->second;
201 childs.clear();
202 }
203 else {
204 // for everything else we just call enableSWMR (which usually does just nothing)
205 for(auto it=childs.begin(); it!=childs.end(); ++it)
206 {
207 it->second->enableSWMR();
208 }
209 }
210 }
211 std::map<std::string, Child*> childs;
212
213 // create a objet of class T which is derived from Child
214 template<class T>
215 class Creator {
216 protected:
217 Self *self;
218 std::string name;
219 std::map<std::string, Child*> &childs;
220 public:
221 Creator(Self *self_, std::string name_, std::map<std::string, Child*> &childs_) :
222 self(self_), name(std::move(name_)), childs(childs_) {}
223
224 template<typename... Args>
225 T* operator()(Args&&... args) {
226 auto ret=childs.insert(std::pair<std::string, Child*>(name, NULL));
227 if(!ret.second)
228 throw Exception(self->getPath(), "A element of name "+name+" already exists.");
229 try {
230 auto* r=new T(static_cast<Self*>(self), name, std::forward<Args>(args)...);
231 ret.first->second=r;
232 return r;
233 }
234 catch(...) {
235 childs.erase(name);
236 throw;
237 }
238 }
239 };
240 template<class T>
241 Creator<T> createChild(const std::string &name_) {
242 if(name_.find_first_of('/')!=std::string::npos)
243 throw Exception(static_cast<Self*>(this)->getPath(), "Internal error: must be a relative name, not absolute or a path");
244 return Creator<T>(static_cast<Self*>(this), name_, childs);
245 }
246
247 template<class T>
248 T* openChild(const std::string &name_) {
249 if(name_.find_first_of('/')!=std::string::npos)
250 throw Exception(static_cast<Self*>(this)->getPath(), "Internal error: must be a relative name, not absolute or a path");
251 std::pair<typename std::map<std::string, Child*>::iterator, bool> ret=childs.insert(std::pair<std::string, Child*>(name_, NULL));
252 if(!ret.second) {
253 auto *o=dynamic_cast<T*>(ret.first->second);
254 if(!o)
255 std::runtime_error("The element "+name_+" if of other type.");
256 return o;
257 }
258 try {
259 auto* r=new T(0, static_cast<Self*>(this), name_);
260 ret.first->second=r;
261 return r;
262 }
263 catch(...) {
264 childs.erase(name_);
265 throw;
266 }
267 }
268 };
269
270 class Object : public Element, public Container<Attribute, Object> {
271 friend class Container<Object, GroupBase>;
272 protected:
273 Object(GroupBase *parent_, const std::string &name_);
274 ~Object() override;
275 void close() override;
276 void refresh() override;
277 void flush() override;
278 void enableSWMR() override;
279 GroupBase *parent;
280 File *file;
281 Object *getFileAsObject(); // helper function used in openChildAttribute
282 Object *getAttrParent(const std::string &path, size_t pos); // helper function used in openChildAttribute
283 public:
284 template<class T>
285 Creator<T> createChildAttribute(const std::string &path) {
286 if(path[0]=='/') // absolute path -> call openChildAttribute from file
287 return getFileAsObject()->createChildAttribute<T>(path.substr(1));
288 // now its a relative path
289 size_t pos;
290 if((pos=path.find_last_of('/'))==std::string::npos) // no / included -> call openChild from Container
291 return createChild<T>(path);
292 // now its a relative path including at least one /
293 return getAttrParent(path, pos)->createChild<T>(path.substr(pos+1));
294 }
295
296 template<class T>
297 T* openChildAttribute(const std::string &path) {
298 if(path[0]=='/') // absolute path -> call openChildAttribute from file
299 return getFileAsObject()->openChildAttribute<T>(path.substr(1));
300 // now its a relative path
301 size_t pos;
302 if((pos=path.find_last_of('/'))==std::string::npos) // no / included -> call openChild from Container
303 return openChild<T>(path);
304 // now its a relative path including at least one /
305 return getAttrParent(path, pos)->openChild<T>(path.substr(pos+1));
306 }
307 Attribute *openChildAttribute(const std::string &name_, ElementType *attributeType=nullptr, ScopedHID *type=nullptr);
308 std::set<std::string> getChildAttributeNames();
309 bool hasChildAttribute(const std::string &name_);
310 GroupBase *getParent() { return parent; }
311 File *getFile() { return file; }
312 std::string getPath();
313 };
314
315 class Attribute : public Element {
316 friend class Container<Attribute, Object>;
317 protected:
318 Attribute(Object *parent_, const std::string &name_);
319 ~Attribute() override;
320 Object *parent;
321 File *file;
322 void close() override;
323 void refresh() override;
324 void flush() override;
325 public:
326 Object *getParent() { return parent; }
327 File *getFile() { return file; }
328 std::string getPath();
329 };
330
331 class Dataset : public Object {
332 protected:
333 Dataset(GroupBase *parent_, const std::string &name_);
334 Dataset(int dummy, GroupBase *parent_, const std::string &name_);
335 ~Dataset() override;
336 void close() override;
337 void refresh() override;
338 void enableSWMR() override;
339 public:
340 void flush() override;
341 std::vector<hsize_t> getExtentDims();
342 };
343
344}
345
346#endif
Definition: interface.h:315
Definition: interface.h:215
Definition: interface.h:177
Definition: interface.h:331
Definition: interface.h:157
hid_t getID()
Note: use the returned hid_t only temporarily since it may get invalid, at least when File::enableSWM...
Definition: interface.h:171
Definition: interface.h:65
Definition: file.h:106
Definition: group.h:31
Definition: interface.h:270
Definition: interface.h:78
Definition: interface.h:44