All Classes Namespaces Functions Typedefs Enumerations Pages
structserie.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_STRUCTSERIE_H_
23 #define _HDF5SERIE_STRUCTSERIE_H_
24 
25 #include <fmatvec/atom.h>
26 #include <vector>
27 #include <string>
28 #include <assert.h>
29 #include <hdf5serie/simpleattribute.h>
30 #include <cstring>
31 #include <cstdlib>
32 #include <iostream>
33 #include <stdexcept>
34 
35 namespace H5 {
36 
62  template<class S>
63  class StructSerie : virtual public fmatvec::Atom, public DataSet {
64  private:
65  CompType memDataType;
66  DataSpace memDataSpace;
67  hsize_t dims[1];
68  bool firstCall;
69  std::vector<int> structOffset;
70  public:
75  StructSerie();
76 
77 #ifdef PARSED_BY_DOXYGEN
78 // Use this code section if doxygen is running to generate documentation.
100  void registerMember(const S& s, const CTYPE& e, const std::string name);
101 
108  void registerMember(const S& s, const std::vector<CTYPE>& e, unsigned int N, const std::string name);
109 #else
110 // Use this code section else
111 # define FOREACHKNOWNTYPE(CTYPE, H5TYPE) \
112  void registerMember(const S& s, const CTYPE& e, const std::string name);
113 # include "hdf5serie/knowntypes.def"
114 # undef FOREACHKNOWNTYPE
115 
116 # define FOREACHKNOWNTYPE(CTYPE, H5TYPE) \
117  void registerMember(const S& s, const std::vector<CTYPE>& e, unsigned int N, const std::string name);
118 # include "hdf5serie/knowntypes.def"
119 # undef FOREACHKNOWNTYPE
120 #endif
121 
131  void create(const CommonFG& parent, const std::string& name, int compression=FileSerie::getDefaultCompression(), int chunkSize=FileSerie::getDefaultChunkSize());
132 
140  void open(const CommonFG& parent, const std::string& name);
141 
146  void setDescription(const std::string& desc);
147 
152  std::string getDescription();
153 
159  void append(const S& data);
160 
162  inline int getRows();
163 
165  inline unsigned int getMembers();
166 
171  S getRow(const int row);
172 
178  std::vector<std::string> getMemberLabel();
179 
180  void extend(const hsize_t* size);
181  };
182 
183 
184 
185  template<class S>
186  StructSerie<S>::StructSerie() : DataSet(), memDataType(), firstCall(true) {
187  dims[0]=0;
188  hsize_t memDims[]={1};
189  memDataSpace=DataSpace(1, memDims);
190  }
191 
192 # define FOREACHKNOWNTYPE(CTYPE, H5TYPE) \
193  template<class S> \
194  void StructSerie<S>::registerMember(const S& s, const CTYPE& e, const std::string name) { \
195  int size; \
196  if(!firstCall) size=memDataType.getSize(); else size=0; \
197  CompType oldMemDataType(memDataType); \
198  memDataType=CompType(size+toH5Type(e).getSize()); \
199  for(int i=0; i<(firstCall?0:oldMemDataType.getNmembers()); i++) \
200  memDataType.insertMember(oldMemDataType.getMemberName(i), oldMemDataType.getMemberOffset(i), oldMemDataType.getMemberDataType(i)); \
201  memDataType.insertMember(name, size, toH5Type(e)); \
202  structOffset.push_back((char*)&e-(char*)&s); \
203  firstCall=false; \
204  }
205 # include "hdf5serie/knowntypes.def"
206 # undef FOREACHKNOWNTYPE
207 
208 # define FOREACHKNOWNTYPE(CTYPE, H5TYPE) \
209  template<class S> \
210  void StructSerie<S>::registerMember(const S& s, const std::vector<CTYPE>& e, unsigned int N, const std::string name) { \
211  if(e.size()!=0 && e.size()!=N) throw Exception(getPath(), "wrong dimension"); \
212  int size; \
213  if(!firstCall) size=memDataType.getSize(); else size=0; \
214  CTYPE dummy; \
215  hsize_t dims[]={N}; \
216  CompType oldMemDataType(memDataType); \
217  memDataType=CompType(size+ArrayType(toH5Type(dummy), 1, dims).getSize()); \
218  for(int i=0; i<(firstCall?0:oldMemDataType.getNmembers()); i++) \
219  memDataType.insertMember(oldMemDataType.getMemberName(i), oldMemDataType.getMemberOffset(i), oldMemDataType.getMemberDataType(i)); \
220  memDataType.insertMember(name, size, ArrayType(toH5Type(dummy), 1, dims)); \
221  structOffset.push_back((char*)&e-(char*)&s); \
222  firstCall=false; \
223  }
224 # include "hdf5serie/knowntypes.def"
225 # undef FOREACHKNOWNTYPE
226 
227  template<class S>
228  void StructSerie<S>::create(const CommonFG& parent, const std::string& name, int compression, int chunkSize) {
229  if(firstCall) throw Exception(getPath(), "wrong call sequence");
230  dims[0]=0;
231  hsize_t maxDims[]={H5S_UNLIMITED};
232  DataSpace fileDataSpace(1, dims, maxDims);
233  DSetCreatPropList prop;
234  hsize_t chunkDims[]={static_cast<hsize_t>(chunkSize)};
235  prop.setChunk(1, chunkDims);
236  if(compression>0) prop.setDeflate(compression);
237  DataSet dataSet=parent.createDataSet(name, memDataType, fileDataSpace, prop); // increments the refcount
238  setId(dataSet.getId()); // increment the ref count (the ctor of dataset decrements it again)
239  fmatvec::Atom::msg(fmatvec::Atom::Debug)<<"HDF5:\n"
240  <<"Created object with name = "<<name<<", id = "<<getId()<<" at parent with id = "<<((Group*)&parent)->getId()<<"."<<std::endl;
241  }
242 
243  template<class S>
244  void StructSerie<S>::open(const CommonFG& parent, const std::string& name) {
245  if(firstCall) throw Exception(getPath(), "wrong call sequence");
246  DataSet dataSet=parent.openDataSet(name); // increments the refcount
247  setId(dataSet.getId()); // increment the ref count (the ctor of dataset decrements it again)
248 
249  DataSpace fileDataSpace=getSpace();
250  // Check if dataspace and datatype complies with the class
251  assert(fileDataSpace.getSimpleExtentNdims()==1);
252  hsize_t maxDims[1];
253  fileDataSpace.getSimpleExtentDims(dims, maxDims);
254  assert(maxDims[0]==H5S_UNLIMITED);
255 
256  assert(dataSet.getDataType().getClass()==H5T_COMPOUND);
257  assert((int)structOffset.size()==getCompType().getNmembers());
258  for(unsigned int i=0; i<structOffset.size(); i++) {
259  assert(getCompType().getMemberName(i)==memDataType.getMemberName(i));
260  assert(getCompType().getMemberOffset(i)==memDataType.getMemberOffset(i));
261  assert(getCompType().getMemberDataType(i).getClass()==memDataType.getMemberDataType(i).getClass());
262  }
263  fmatvec::Atom::msg(fmatvec::Atom::Debug)<<"HDF5:\n"
264  <<"Opened object with name = "<<name<<", id = "<<getId()<<" at parent with id = "<<((Group*)&parent)->getId()<<"."<<std::endl;
265  }
266 
267  template<class S>
268  void StructSerie<S>::setDescription(const std::string& description) {
269  SimpleAttribute<std::string> desc(*this, "Description", description);
270  }
271 
272  template<class S>
274  // save and disable c error printing
275  H5E_auto2_t func;
276  void* client_data;
277  Exception::getAutoPrint(func, &client_data);
278  Exception::dontPrint();
279  std::string ret;
280  // catch error if Attribute is not found
281  try {
282  ret=SimpleAttribute<std::string>::getData(*this, "Description");
283  }
284  catch(AttributeIException e) {
285  ret=std::string();
286  }
287  // restore c error printing
288  Exception::setAutoPrint(func, client_data);
289  return ret;
290  }
291 
292  template<class S>
293  void StructSerie<S>::append(const S& data) {
294  dims[0]++;
295  DataSet::extend(dims);
296 
297  hsize_t start[]={dims[0]-1};
298  hsize_t count[]={1};
299  DataSpace fileDataSpace=getSpace();
300  fileDataSpace.selectHyperslab(H5S_SELECT_SET, count, start);
301 
302  std::vector<char> buf(memDataType.getSize());
303  std::list<std::vector<char> > charptr;
304  for(int i=0; i<memDataType.getNmembers(); i++) {
305 # define FOREACHKNOWNTYPE(CTYPE, H5TYPE) \
306  if(memDataType.getMemberDataType(i)==H5TYPE) \
307  *(CTYPE*)(&buf[0]+memDataType.getMemberOffset(i))=*(CTYPE*)((char*)&data+structOffset[i]);
308 # include "knownpodtypes.def"
309 # undef FOREACHKNOWNTYPE
310  if(memDataType.getMemberDataType(i)==StrType(PredType::C_S1, H5T_VARIABLE)) {
311  charptr.push_back(std::vector<char>(((std::string*)((char*)&data+structOffset[i]))->size()+1));
312  char* str=&(*--charptr.end())[0];
313  strcpy(str, ((std::string*)((char*)&data+structOffset[i]))->c_str());
314  *(char**)(&buf[0]+memDataType.getMemberOffset(i))=str;
315  }
316  if(memDataType.getMemberDataType(i).getClass()==H5T_ARRAY) {
317  hsize_t dims[1];
318  memDataType.getMemberArrayType(i).getArrayDims(dims);
319 # define FOREACHKNOWNTYPE(CTYPE, H5TYPE) \
320  if(memDataType.getMemberDataType(i)==ArrayType(H5TYPE,1,dims)) { \
321  std::vector<CTYPE>* vec=(std::vector<CTYPE>*)((char*)&data+structOffset[i]); \
322  if(vec->size()!=dims[0]) throw Exception(getPath(), "the dimension does not match"); \
323  memcpy(&buf[0]+memDataType.getMemberOffset(i), &((*vec)[0]), dims[0]*sizeof(CTYPE)); \
324  }
325 # include "knownpodtypes.def"
326 # undef FOREACHKNOWNTYPE
327  if(memDataType.getMemberDataType(i)==ArrayType(StrType(PredType::C_S1, H5T_VARIABLE),1,dims))
328  for(unsigned int j=0; j<dims[0]; j++) {
329  std::vector<std::string>* vec=(std::vector<std::string>*)((char*)&data+structOffset[i]);
330  if(vec->size()!=dims[0]) throw Exception(getPath(), "the dimension does not match");
331  charptr.push_back(std::vector<char>((*vec)[j].size()+1));
332  char* str=&(*--charptr.end())[0];
333  strcpy(str, (*vec)[j].c_str());
334  *(char**)(&buf[0]+memDataType.getMemberOffset(i)+j*sizeof(char*))=str;
335  }
336  }
337  }
338  write(&buf[0], memDataType, memDataSpace, fileDataSpace);
339  }
340 
341  template<class S>
343  // get current dims from dataspace (maybe another (single-)writer process has increased the number of rows)
344  DataSpace fileDataSpace=getSpace();
345  fileDataSpace.getSimpleExtentDims(dims);
346  // return current value
347  return dims[0];
348  }
349 
350  template<class S>
351  unsigned int StructSerie<S>::getMembers() {
352  return memDataType.getNmembers();
353  }
354 
355  template<class S>
356  S StructSerie<S>::getRow(const int row) {
357  S data;
358  if(row<0 || row>=(int)dims[0]) {
359  fmatvec::Atom::msg(fmatvec::Atom::Warn)<<"HDF5 object with id = "<<getId()<<":\n"
360  <<"Requested struct number is out of range, returning a dummy struct."<<std::endl;
361  return data;
362  }
363 
364  hsize_t start[]={static_cast<hsize_t>(row)};
365  hsize_t count[]={1};
366  DataSpace fileDataSpace=getSpace();
367  fileDataSpace.selectHyperslab(H5S_SELECT_SET, count, start);
368 
369  std::vector<char> buf(memDataType.getSize());
370  read(&buf[0], memDataType, memDataSpace, fileDataSpace);
371  for(int i=0; i<memDataType.getNmembers(); i++) {
372 # define FOREACHKNOWNTYPE(CTYPE, H5TYPE) \
373  if(memDataType.getMemberDataType(i)==H5TYPE) \
374  *(CTYPE*)((char*)&data+structOffset[i])=*(CTYPE*)(&buf[0]+memDataType.getMemberOffset(i));
375 # include "knownpodtypes.def"
376 # undef FOREACHKNOWNTYPE
377  if(memDataType.getMemberDataType(i)==StrType(PredType::C_S1, H5T_VARIABLE)) {
378  char* str=*(char**)(&buf[0]+memDataType.getMemberOffset(i));
379  *((std::string*)((char*)&data+structOffset[i]))=str;
380  free(str);
381  }
382  if(memDataType.getMemberDataType(i).getClass()==H5T_ARRAY) {
383  hsize_t dims[1];
384  memDataType.getMemberArrayType(i).getArrayDims(dims);
385 # define FOREACHKNOWNTYPE(CTYPE, H5TYPE) \
386  if(memDataType.getMemberDataType(i)==ArrayType(H5TYPE,1,dims)) { \
387  std::vector<CTYPE>* vec=(std::vector<CTYPE>*)((char*)&data+structOffset[i]); \
388  vec->resize(dims[0]); \
389  memcpy(&((*vec)[0]), &buf[0]+memDataType.getMemberOffset(i), dims[0]*sizeof(CTYPE)); \
390  }
391 # include "knownpodtypes.def"
392 # undef FOREACHKNOWNTYPE
393  if(memDataType.getMemberDataType(i)==ArrayType(StrType(PredType::C_S1, H5T_VARIABLE),1,dims)) {
394  std::vector<std::string>* vec=(std::vector<std::string>*)((char*)&data+structOffset[i]);
395  vec->resize(dims[0]);
396  for(unsigned int j=0; j<dims[0]; j++) {
397  char* str=*(char**)(&buf[0]+memDataType.getMemberOffset(i)+j*sizeof(char*));
398  (*vec)[j]=str;
399  free(str);
400  }
401  }
402  }
403  }
404  return data;
405  }
406 
407  template<class S>
408  std::vector<std::string> StructSerie<S>::getMemberLabel() {
409  std::vector<std::string> ret;
410  for(int i=0; i<memDataType.getNmembers(); i++)
411  ret.push_back(memDataType.getMemberName(i));
412  return ret;
413  }
414 
415  template<class S>
416  void StructSerie<S>::extend(const hsize_t* size) {
417  assert(1);
418  }
419 
420 }
421 
422 #endif // _TIMESERIE_H_
Definition: interface.h:58
std::string getDescription()
Return the description for the dataset.
Definition: structserie.h:273
unsigned int getMembers()
Returns the number of members in the struct.
Definition: structserie.h:351
void setDescription(const std::string &desc)
Sets a description for the dataset.
Definition: structserie.h:268
int getRows()
Returns the number of elements in the dataset.
Definition: structserie.h:342
std::ostream & msg(MsgType type)
Definition: group.h:83
S getRow(const int row)
Returns the data struct at element row.
Definition: structserie.h:356
void create(const CommonFG &parent, const std::string &name, int compression=FileSerie::getDefaultCompression(), int chunkSize=FileSerie::getDefaultChunkSize())
Creating a dataset.
Definition: structserie.h:228
void append(const S &data)
Append a data struct.
Definition: structserie.h:293
StructSerie()
A stub constructor.
Definition: structserie.h:186
std::vector< std::string > getMemberLabel()
Returns the member labels.
Definition: structserie.h:408
void open(const CommonFG &parent, const std::string &name)
Open a dataset.
Definition: structserie.h:244
Serie of structs (compount datas).
Definition: structserie.h:63

Impressum / Disclaimer / Datenschutz Generated by doxygen 1.8.5 Valid HTML