Utopia  2
Framework for studying models of complex & adaptive systems.
hdfattribute.hh
Go to the documentation of this file.
1 
8 #ifndef UTOPIA_DATAIO_HDFATTRIBUTE_HH
9 #define UTOPIA_DATAIO_HDFATTRIBUTE_HH
10 
11 #include <cstring>
12 #include <functional>
13 #include <memory>
14 #include <string>
15 
16 #include <hdf5.h>
17 #include <hdf5_hl.h>
18 
19 #include "hdfbufferfactory.hh"
20 #include "hdfdataspace.hh"
21 #include "hdfobject.hh"
22 #include "hdftype.hh"
23 
24 namespace Utopia
25 {
26 namespace DataIO
27 {
28 
45 class HDFAttribute final : public HDFObject< HDFCategory::attribute >
46 {
47  private:
51  std::vector< hsize_t > _shape;
52 
57 
63 
69 
79  template < typename result_type >
80  void
81  __create_attribute__(hsize_t typesize = 0)
82  {
83  this->_log->debug("Creating attribute {}", _path);
84 
85  _dataspace.open(this->_path + " dataspace", _shape.size(), _shape, {});
86 
87  _type.open< result_type >("datatype of " + _path, typesize);
88 
89  this->bind_to(H5Acreate2(_parent_identifier.get_id(),
90  _path.c_str(),
91  _type.get_C_id(),
92  _dataspace.get_C_id(), // dspace
93  H5P_DEFAULT,
94  H5P_DEFAULT),
95  &H5Aclose,
96  _path);
97  }
98 
105  template < typename Type >
106  herr_t
107  __write_container__(Type attribute_data)
108  {
109  this->_log->debug("Writing container data to attribute {} ...", _path);
110  using value_type_1 = typename Type::value_type;
112 
113  // we can write directly if we have a plain vector, no nested or
114  // stringtype.
115  if constexpr (std::is_same_v< Type, std::vector< value_type_1 > > and
116  not Utils::is_container_v< value_type_1 > and
117  not Utils::is_string_v< value_type_1 >)
118  {
119  this->_log->debug("... of simple vector type");
120 
121  // check if attribute has been created, else do
122  if (get_C_id() == -1)
123  {
124  __create_attribute__< base_type >(0);
125  }
126 
127  return H5Awrite(
128  get_C_id(), _type.get_C_id(), attribute_data.data());
129  }
130  // when stringtype or containertype is stored in a container, then
131  // we have to buffer. bufferfactory handles how to do this in detail
132  else
133  {
134  this->_log->debug("... of non-trivial container type");
135  // if we want to write std::arrays then we can use
136  // fixed size array types. Else we use variable length arrays.
137  if constexpr (Utils::is_array_like_v< value_type_1 >)
138  {
139  this->_log->debug("... of fixed size array type");
140  constexpr std::size_t s =
142 
143  if (get_C_id() == -1)
144  {
145  __create_attribute__< base_type >(s);
146  }
147 
148  auto buffer = HDFBufferFactory::buffer(
149  std::begin(attribute_data),
150  std::end(attribute_data),
151  [](auto& value) -> value_type_1& { return value; });
152 
153  return H5Awrite(get_C_id(), _type.get_C_id(), buffer.data());
154  }
155  else
156  {
157  this->_log->debug("... of variable length type");
158  if (get_C_id() == -1)
159  {
160  __create_attribute__< base_type >();
161  }
162 
163  auto buffer = HDFBufferFactory::buffer(
164  std::begin(attribute_data),
165  std::end(attribute_data),
166  [](auto& value) -> value_type_1& { return value; });
167 
168  return H5Awrite(get_C_id(), _type.get_C_id(), buffer.data());
169  }
170  }
171  }
172 
173  // Function for writing stringtypes, char*, const char*, std::string
174  template < typename Type >
175  herr_t
176  __write_stringtype__(Type attribute_data)
177  {
178 
179  this->_log->debug("Writing string data to attribute {} ...", _path);
180 
181  // Since std::string cannot be written directly,
182  // (only const char*/char* can), a buffer pointer has been added
183  // to handle writing in a clearer way and with less code
184  auto len = 0;
185  const char* buffer = nullptr;
186 
187  if constexpr (std::is_pointer_v< Type >) // const char* or char* ->
188  // strlen needed
189  {
190  len = std::strlen(attribute_data);
191  buffer = attribute_data;
192  }
193  else // simple for strings
194  {
195  len = attribute_data.size();
196  buffer = attribute_data.c_str();
197  }
198 
199  // check if attribute has been created, else do
200  if (get_C_id() == -1)
201  {
202  __create_attribute__< const char* >(len);
203  }
204 
205  // use that strings store data in consecutive memory
206  return H5Awrite(get_C_id(), _type.get_C_id(), buffer);
207  }
208 
209  // Function for writing pointer types, shape of the array has to be given
210  // where shape means the same as in python
211  template < typename Type >
212  herr_t
213  __write_pointertype__(Type attribute_data)
214  {
215  this->_log->debug("Writing pointer data to attribute {} ...", _path);
216 
217  // result types removes pointers, references, and qualifiers
218  using basetype = Utils::remove_qualifier_t< Type >;
219 
220  if (get_C_id() == -1)
221  {
222  __create_attribute__< basetype >();
223  }
224 
225  return H5Awrite(get_C_id(), _type.get_C_id(), attribute_data);
226  }
227 
228  // function for writing a scalartype.
229  template < typename Type >
230  herr_t
231  __write_scalartype__(Type attribute_data)
232  {
233  this->_log->debug("Writing scalar data to attribute {} ...", _path);
234 
235  // because we just write a scalar, the shape tells basically that
236  // the attribute is pointlike: 1D and 1 entry.
237  if (get_C_id() == -1)
238  {
239  __create_attribute__< std::decay_t< Type > >();
240  }
241 
242  return H5Awrite(get_C_id(), _type.get_C_id(), &attribute_data);
243  }
244 
245  // Container reader.
246  // We could want to read into a predefined buffer for some reason (frequent
247  // reads), and thus this and the following functions expect an argument
248  // 'buffer' to store their data in. The function 'read(..)' is then
249  // overloaded to allow for automatic buffer creation or a buffer argument.
250  template < typename Type >
251  herr_t
252  __read_container__(Type& buffer)
253  {
254 
255  this->_log->debug("Reading container data from attribute {} ...",
256  _path);
257 
258  using value_type_1 =
260 
261  // when the value_type of Type is a container again, we want nested
262  // arrays basically. Therefore we have to check if the desired type
263  // Type is suitable to hold them, read the nested data into a hvl_t
264  // container, assuming that they are varlen because this is the more
265  // general case, and then turn them into the desired type again...
266  if constexpr (Utils::is_container_v< value_type_1 >)
267  {
268  using value_type_2 =
270 
271  // if we have nested containers of depth larger than 2, throw a
272  // runtime error because we cannot handle this
273  // TODO extend this to work more generally
274  if constexpr (Utils::is_container_v< value_type_2 >)
275  {
276  throw std::runtime_error(
277  "Cannot read data into nested containers with depth > 3 "
278  "in attribute " +
279  _path + " into vector containers!");
280  }
281 
282  // everything is fine.
283 
284  // check if type given in the buffer is std::array.
285  // If it is, the user knew that the data stored there
286  // has always the same length, otherwise she does not
287  // know and thus it is assumed that the data is variable
288  // length.
289  if constexpr (Utils::is_array_like_v< value_type_1 >)
290  {
291  this->_log->debug("... of fixed size array type");
292  return H5Aread(get_C_id(), _type.get_C_id(), buffer.data());
293  }
294  else
295  {
296  this->_log->debug("... of variable size type");
297 
298  std::vector< hvl_t > temp_buffer(buffer.size());
299 
300  herr_t err =
301  H5Aread(get_C_id(), _type.get_C_id(), temp_buffer.data());
302 
303  // turn the varlen buffer into the desired type
304  // Cumbersome, but necessary...
305 
306  this->_log->debug("... turning read data into desired type");
307 
308  for (std::size_t i = 0; i < buffer.size(); ++i)
309  {
310  buffer[i].resize(temp_buffer[i].len);
311  for (std::size_t j = 0; j < temp_buffer[i].len; ++j)
312  {
313  buffer[i][j] =
314  static_cast< value_type_2* >(temp_buffer[i].p)[j];
315  }
316  }
317 
318  #if H5_VERSION_GE(1, 12 , 0)
319  herr_t status = H5Treclaim(_type.get_C_id(),
320  _dataspace.get_C_id(),
321  H5P_DEFAULT,
322  temp_buffer.data());
323  #else
324  herr_t status = H5Dvlen_reclaim (_type.get_C_id(),
325  _dataspace.get_C_id(),
326  H5P_DEFAULT,
327  temp_buffer.data());
328  #endif
329 
330  if (status < 0)
331  {
332  throw std::runtime_error("Error, something went wrong while reading in " + _path + " while reclaiming vlen memory");
333  }
334  // return shape and buffer. Expect to use structured bindings
335  // to extract that later
336  return err;
337  }
338  }
339  else // no nested container, but one containing simple types
340  {
341  if constexpr (!std::is_same_v< std::vector< value_type_1 >, Type >)
342  {
343  throw std::runtime_error("Can only read data from " + _path +
344  " into vector containers!");
345  }
346  else
347  {
348  // when strings are desired to be stored as value_types of the
349  // container, we need to treat them a bit differently,
350  // because hdf5 cannot read directly to them.
351  if constexpr (Utils::is_string_v< value_type_1 >)
352  {
353  this->_log->debug("... of string type");
354 
355  std::vector< char* > temp_buffer(buffer.size());
356 
357  herr_t err = H5Aread(
358  get_C_id(), _type.get_C_id(), temp_buffer.data());
359 
360  // turn temp_buffer into the desired datatype and return
361  for (std::size_t i = 0; i < buffer.size(); ++i)
362  {
363  buffer[i] = temp_buffer[i];
364  }
365 
366  // reclaim memory from the temp_buffer, because
367  // the char* therein are allocated by hdf5, but not freed
368  for (auto&& c: temp_buffer)
369  {
370  free(c);
371  }
372 
373  return err;
374  }
375  else // others are straight forward
376  {
377  this->_log->debug("... of scalar type");
378 
379  return H5Aread(get_C_id(), _type.get_C_id(), buffer.data());
380  }
381  }
382  }
383  }
384 
385  // read attirbute data which contains a single string.
386  // this is always read into std::strings, and hence
387  // we can use 'resize'
388  template < typename Type >
389  auto
390  __read_stringtype__(Type& buffer)
391  {
392 
393  this->_log->debug("Reading string type from attribute {}", _path);
394 
395  // resize buffer to the size of the type
396  buffer.resize(_type.size());
397 
398  // read data
399  return H5Aread(get_C_id(), _type.get_C_id(), buffer.data());
400  }
401 
402  // read pointertype. Either this is given by the user, or
403  // it is assumed to be 1d, thereby flattening Nd attributes
404  template < typename Type >
405  auto
406  __read_pointertype__(Type buffer)
407  {
408  this->_log->debug("Reading pointer type from attribute {}", _path);
409 
410  return H5Aread(get_C_id(), _type.get_C_id(), buffer);
411  }
412 
413  // read scalar type, trivial
414  template < typename Type >
415  auto
416  __read_scalartype__(Type& buffer)
417  {
418  this->_log->debug("Reading scalar type from attribute {}", _path);
419 
420  return H5Aread(get_C_id(), _type.get_C_id(), &buffer);
421  }
422 
423  public:
429 
435  void
437  {
438  using std::swap;
439  using Utopia::DataIO::swap;
440  swap(static_cast< Base& >(*this), static_cast< Base& >(other));
441  swap(_shape, other._shape);
443  swap(_dataspace, other._dataspace);
444  }
445 
453  {
454  return _dataspace;
455  }
456 
462  auto
464  {
465  return _type;
466  }
467 
475  {
476  return _parent_identifier;
477  }
478 
482  void
483  close()
484  {
485  _type.close();
486  _dataspace.close();
487  _shape.resize(0);
489 
490  _dataspace.close();
491 
492  if (is_valid())
493  {
494  Base::close();
495  }
496  }
497 
503  auto
505  {
506  // the below is done to retain vector type for _shape member,
507  // which otherwise would break interface due to type change.
508  auto shape = _dataspace.size();
509  _shape.assign(shape.begin(), shape.end());
510 
511  return _shape;
512  }
513 
520  template < HDFCategory cat >
521  void
522  open(const HDFObject< cat >& parent, std::string name)
523  {
524  this->_log->debug(
525  "Opening attribute named {} in object {}", name, parent.get_path());
526  open(parent.get_id_object(), name);
527  }
528 
535  void
536  open(const HDFIdentifier& parent, std::string name)
537  {
538  // update members
539  _parent_identifier = parent;
540 
541  _path = name;
542 
543  if (parent.is_valid())
544  {
545 
546  if (H5LTfind_attribute(_parent_identifier.get_id(),
547  _path.c_str()) == 1)
548  {
549  this->_log->debug("... attribute exists already, opening");
550  // attribute exists, open
552  _path.c_str(),
553  H5P_DEFAULT),
554  &H5Aclose,
555  name);
556 
557  _type.open(*this);
558 
559  // README (regarding usage of this in constructors): the usage
560  // of *this is save here, because we always have a valid object
561  // of type HDFDataspace even in ctor given that this is neither
562  // a derived class nor we call a virtual function
563  _dataspace.open(*this);
564  get_shape();
565  }
566  else
567  {
568  this->_log->debug("... attribute does not yet exist, have to "
569  "wait for incoming data to build it");
570 
571  this->_id = HDFIdentifier();
572  }
573  }
574  else
575  {
576  throw std::invalid_argument(
577  "Parent object of attribute '" + _path +
578  "' is invalid! Has it been closed already or not been opened "
579  "yet?");
580  }
581  }
582 
607  template < typename Type >
608  auto
610  {
611  this->_log->debug("Reading attribute {}", _path);
612 
613  if (_shape.size() == 0)
614  {
615  get_shape();
616  }
617 
618  // Read can only be done in 1d, and this loop takes care of
619  // computing a 1d size which can accomodate all elements.
620  // This is then passed to the container holding the elements in the end.
621  std::size_t size = 1;
622  for (auto& value : _shape)
623  {
624  size *= value;
625  }
626 
627  // type to read in is a container type, which can hold containers
628  // themselvels or just plain types.
629  if constexpr (Utils::is_container_v< Type >)
630  {
631  Type buffer(size);
632  herr_t err = __read_container__(buffer);
633  if (err < 0)
634  {
635  throw std::runtime_error("Error in reading data from " + _path +
636  " into container types");
637  }
638 
639  return std::make_tuple(_shape, buffer);
640  }
641  else if constexpr (Utils::is_string_v< Type >) // we can have string
642  // types too, i.e. char*,
643  // const char*,
644  // std::string
645  {
646  std::string buffer; // resized in __read_stringtype__ because this
647  // as a scalar
648  herr_t err = __read_stringtype__(buffer);
649  if (err < 0)
650  {
651  throw std::runtime_error("Error in reading data from " + _path +
652  " into stringtype");
653  }
654 
655  return std::make_tuple(_shape, buffer);
656  }
657  else if constexpr (std::is_pointer_v< Type > &&
658  !Utils::is_string_v< Type >)
659  {
660  std::shared_ptr< Utils::remove_qualifier_t<Type> > buffer(
661  new Utils::remove_qualifier_t<Type>[size], std::default_delete<Utils::remove_qualifier_t<Type>[]>());
662 
663  herr_t err = __read_pointertype__(buffer.get());
664  if (err < 0)
665  {
666  throw std::runtime_error("Error in reading data from " + _path +
667  " into pointertype");
668  }
669  return std::make_tuple(_shape, buffer);
670  }
671  else // reading scalar types is simple enough
672  {
673  Type buffer(0);
674  herr_t err = __read_scalartype__(buffer);
675  if (err < 0)
676  {
677  throw std::runtime_error("Error in reading data from " + _path +
678  " into scalar");
679  }
680  return std::make_tuple(_shape, buffer);
681  }
682  }
683 
693  template < typename Type >
694  void
695  read(Type& buffer)
696  {
697  this->_log->debug("Reading attribute {} into given buffer", _path);
698 
699  if (_shape.size() == 0)
700  {
701  get_shape();
702  }
703 
704  // type to read in is a container type, which can hold containers
705  // themselvels or just plain types.
706  if constexpr (Utils::is_container_v< Type >)
707  {
708  // needed to make sure that the buffer has the correct size
709 
710  std::size_t size = 1;
711  for (auto& value : _shape)
712  {
713  size *= value;
714  }
715 
716  if (buffer.size() != size)
717  {
718  buffer.resize(size);
719  }
720 
721  herr_t err = __read_container__(buffer);
722  if (err < 0)
723  {
724  throw std::runtime_error("Error in reading data from " + _path +
725  " into container types");
726  }
727  }
728  else if constexpr (Utils::is_string_v< Type >) // we can have string
729  // types too, i.e. char*,
730  // const char*,
731  // std::string
732  {
733  // resized in __read_stringtype__ because this as a scalar
734  herr_t err = __read_stringtype__(buffer);
735  if (err < 0)
736  {
737  throw std::runtime_error("Error in reading data from " + _path +
738  " into stringtype");
739  }
740  }
741  else if constexpr (std::is_pointer_v< Type > &&
742  !Utils::is_string_v< Type >)
743  {
744  herr_t err = __read_pointertype__(buffer);
745 
746  if (err < 0)
747  {
748  throw std::runtime_error("Error in reading data from " + _path +
749  " into pointertype");
750  }
751  }
752  else // reading scalar types is simple enough
753  {
754  herr_t err = __read_scalartype__(buffer);
755  if (err < 0)
756  {
757  throw std::runtime_error("Error in reading data from " + _path +
758  " into scalar");
759  }
760  }
761  }
762 
778  template < typename Type >
779  void
780  write(Type attribute_data, std::vector< hsize_t > shape = {})
781  {
782  this->_log->debug("Writing data to attribute {}", _path);
783 
784  // check if we have a container. Writing containers requires further
785  // t tests, plain old data can be written right away
786 
787  if constexpr (Utils::is_container_v< Type >) // container type
788  {
789  // get the shape from the data. This function is written such
790  // that it writes always 1d, unless a pointer type with different
791  // shape is given.
792  if (_shape.size() == 0)
793  {
794  _shape = { attribute_data.size() };
795  }
796  else
797  {
798  _shape = shape;
799  }
800  herr_t err = __write_container__(attribute_data);
801 
802  if (err < 0)
803  {
804  throw std::runtime_error(
805  "An error occurred while writing a containertype to "
806  "attribute " +
807  _path + "!");
808  }
809  }
810  // write string types, i.e. const char*, char*, std::string
811  // These are not containers but not normal scalars either,
812  // so they have to be treated separatly
813  else if constexpr (Utils::is_string_v< Type >)
814  {
815  _shape = { 1 };
816 
817  herr_t err = __write_stringtype__(attribute_data);
818 
819  if (err < 0)
820  {
821  throw std::runtime_error(
822  "An error occurred while writing a stringtype to "
823  "attribute " +
824  _path + "!");
825  }
826  }
827  // We can also write pointer types, but then the shape of the array
828  // has to be given explicitly. This does not handle stringtypes,
829  // even though const char* /char* are pointer types
830  else if constexpr (std::is_pointer_v< Type > &&
831  !Utils::is_string_v< Type >)
832  {
833  if (shape.size() == 0)
834  {
835  throw std::runtime_error(
836  "Attribute: " + _path +
837  ","
838  "The shape parameter has to be given for pointers "
839  "because "
840  "it cannot be determined automatically");
841  }
842  else
843  {
844  _shape = shape;
845  }
846 
847  herr_t err = __write_pointertype__(attribute_data);
848 
849  if (err < 0)
850  {
851  throw std::runtime_error(
852  "An error occurred while writing a pointertype/plain array "
853  "to "
854  "attribute " +
855  _path + "!");
856  }
857  }
858  // plain scalar types are treated in a straight forward way
859  else
860  {
861  _shape = { 1 };
862 
863  herr_t err = __write_scalartype__(attribute_data);
864  if (err < 0)
865  {
866  throw std::runtime_error(
867  "An error occurred while writing a scalar "
868  "to "
869  "attribute " +
870  _path + "!");
871  }
872  }
873  }
874 
887  template < typename Iter, typename Adaptor >
888  void
890  Iter begin,
891  Iter end,
892  Adaptor adaptor = [](auto& value) { return value; },
893  [[maybe_unused]] std::vector< hsize_t > shape = {})
894  {
895  this->_log->debug("Writing data from iterator range to attribute {}",
896  _path);
897 
898  using Type = Utils::remove_qualifier_t< decltype(adaptor(*begin)) >;
899  // if we copy only the content of [begin, end), then simple vector
900  // copy suffices
901  if constexpr (std::is_same< Type, typename Iter::value_type >::value)
902  {
903  write(std::vector< Type >(begin, end));
904  }
905  else
906  {
907 
908  std::vector< Type > buff(std::distance(begin, end));
909  std::generate(buff.begin(), buff.end(), [&begin, &adaptor]() {
910  return adaptor(*(begin++));
911  });
912 
913  write(buff, shape);
914  }
915  }
916 
921  HDFAttribute() = default;
922 
928  HDFAttribute(const HDFAttribute& other) = default;
929 
935  HDFAttribute(HDFAttribute&& other) = default;
936 
944  HDFAttribute&
945  operator=(const HDFAttribute& other) = default;
946 
953  HDFAttribute&
954  operator=(HDFAttribute&& other) = default;
959  virtual ~HDFAttribute()
960  {
961  close();
962  }
963 
971  template < HDFCategory cat >
972  HDFAttribute(const HDFObject< cat >& object, std::string name) :
973  _shape(std::vector< hsize_t >())
974  {
975  open(object, name);
976  }
977 };
978 
987 void
989 {
990  lhs.swap(rhs);
991 }
992  // end of group HDF5 // end of group DataIO
995 
996 } // namespace DataIO
997 } // namespace Utopia
998 #endif
Class for hdf5 attribute, which can be attached to groups and datasets.
Definition: hdfattribute.hh:46
virtual ~HDFAttribute()
Destructor.
Definition: hdfattribute.hh:959
void close()
closes the attribute
Definition: hdfattribute.hh:483
HDFType _type
type done in the HDFAttribute
Definition: hdfattribute.hh:68
auto __read_pointertype__(Type buffer)
Definition: hdfattribute.hh:406
herr_t __read_container__(Type &buffer)
Definition: hdfattribute.hh:252
HDFAttribute(const HDFObject< cat > &object, std::string name)
Constructor for attribute.
Definition: hdfattribute.hh:972
auto __read_scalartype__(Type &buffer)
Definition: hdfattribute.hh:416
HDFIdentifier get_parent_id()
Get the hdf5 identifier to which the attribute belongs.
Definition: hdfattribute.hh:474
void __create_attribute__(hsize_t typesize=0)
private helper function for creation of attribute
Definition: hdfattribute.hh:81
herr_t __write_stringtype__(Type attribute_data)
Definition: hdfattribute.hh:176
auto read()
Reads data from attribute, and returns the data and its shape in the form of a hsize_t vector.
Definition: hdfattribute.hh:609
void open(const HDFObject< cat > &parent, std::string name)
Open a new attribute on HDFObject 'parent' with name 'name'.
Definition: hdfattribute.hh:522
HDFAttribute & operator=(HDFAttribute &&other)=default
Attribute move assignment operator.
void open(const HDFIdentifier &parent, std::string name)
Open a new attribute on HDFObject 'parent' with name 'name'.
Definition: hdfattribute.hh:536
HDFDataspace get_filespace()
Get the file-dataspace object.
Definition: hdfattribute.hh:452
HDFAttribute(const HDFAttribute &other)=default
Copy constructor.
auto get_shape()
Get the shape object.
Definition: hdfattribute.hh:504
void write(Iter begin, Iter end, Adaptor adaptor=[](auto &value) { return value;}, [[maybe_unused]] std::vector< hsize_t > shape={})
Function for writing data to the attribute.
Definition: hdfattribute.hh:889
auto __read_stringtype__(Type &buffer)
Definition: hdfattribute.hh:390
HDFAttribute & operator=(const HDFAttribute &other)=default
Copy assignment operator.
void swap(HDFAttribute &other)
Exchange states between caller and argument.
Definition: hdfattribute.hh:436
void write(Type attribute_data, std::vector< hsize_t > shape={})
Function for writing data to the attribute.
Definition: hdfattribute.hh:780
HDFAttribute(HDFAttribute &&other)=default
Move constructor.
std::vector< hsize_t > _shape
size of the attributes dataspace
Definition: hdfattribute.hh:51
herr_t __write_pointertype__(Type attribute_data)
Definition: hdfattribute.hh:213
HDFIdentifier _parent_identifier
Identifier of the parent object.
Definition: hdfattribute.hh:56
herr_t __write_container__(Type attribute_data)
Function for writing containers as attribute.
Definition: hdfattribute.hh:107
herr_t __write_scalartype__(Type attribute_data)
Definition: hdfattribute.hh:231
void read(Type &buffer)
Reads data from attribute into a predefined buffer, and returns the data and its shape in the form of...
Definition: hdfattribute.hh:695
HDFDataspace _dataspace
Dataspace object that manages topology of data written and read.
Definition: hdfattribute.hh:62
auto get_type()
Get the type object.
Definition: hdfattribute.hh:463
HDFAttribute()=default
Default constructor, deleted because of reference member.
static auto buffer(Iter begin, Iter end, Adaptor &&adaptor)
static function for turning an iterator range with arbitrarty datatypes into a vector of data as retu...
Definition: hdfbufferfactory.hh:96
Class that wraps an HDF5 dataspace and takes care of managing its resources.
Definition: hdfdataspace.hh:37
Wrapper class around an hdf5 identifier, used to manage reference counts of the object this identifie...
Definition: hdfidentifier.hh:29
void close()
Close the identifier and render the C-Level id held invalid.
Definition: hdfidentifier.hh:134
hid_t get_id() const
Get the HDF5 id held by this object.
Definition: hdfidentifier.hh:53
bool is_valid() const
Check if thi ID refers to a valid object.
Definition: hdfidentifier.hh:77
Common base class for all HDF5 classes in the DATAIO Module i.e., for all classes that wrap HDF5-C-Li...
Definition: hdfobject.hh:37
auto get_id_object() const
Get the id object.
Definition: hdfobject.hh:99
std::string _path
Name of the object.
Definition: hdfobject.hh:50
std::string get_path() const
Get the name or path object.
Definition: hdfobject.hh:88
void close()
Close function which takes care of correctly closing the object and managing the reference counter.
Definition: hdfobject.hh:161
virtual bool is_valid() const
Check if the object is still valid.
Definition: hdfobject.hh:143
std::shared_ptr< spdlog::logger > _log
pointer to the logger for dataio
Definition: hdfobject.hh:56
HDFIdentifier _id
Identifier object that binds an instance of this class to an HDF5 object.
Definition: hdfobject.hh:44
hid_t get_C_id() const
Get the C id object.
Definition: hdfobject.hh:120
void bind_to(hid_t id, std::function< herr_t(hid_t) > closing_func, std::string path={})
Open the object and bind it to a HDF5 object identified by 'id' with name 'path'. Object should be cr...
Definition: hdfobject.hh:186
Class which handles the conversion of C-types into hdf5types.
Definition: hdftype.hh:136
void open(T &&object)
Open the HDF5 type associated with an HDFObject, i.e., a dataset or an attribute.
Definition: hdftype.hh:224
void close()
Construct close from the given arguments.
Definition: hdftype.hh:322
std::size_t size() const
Size of the type held in bytes.
Definition: hdftype.hh:210
void swap(WriteTask< BGB, DW, DB, AWG, AWD > &lhs, WriteTask< BGB, DW, DB, AWG, AWD > &rhs)
Swaps the state of lhs and rhs.
Definition: write_task.hh:240
arma::Row< hsize_t > size()
Get the current size of the dataspace in each dimension.
Definition: hdfdataspace.hh:94
void swap(HDFAttribute &lhs, HDFAttribute &rhs)
Swaps the states of Attributes rhs and lhs.
Definition: hdfattribute.hh:988
void open()
Open the dataspace - set it to be equivalent to any data that later will be used to write or read.
Definition: hdfdataspace.hh:117
In this file, a class for automatically creating intermediate buffer data structures between the user...
This file provides a class which is responsible for the automatic conversion between C/C++ types and ...
auto end(zip< Containers... > &zipper)
end function like std::end
Definition: zip.hh:550
auto begin(zip< Containers... > &zipper)
Begin function like std::begin.
Definition: zip.hh:537
typename remove_qualifier< T >::type remove_qualifier_t
Shorthand for 'typename remove_qualifier::value'.
Definition: type_traits.hh:97
Definition: agent.hh:11
Definition: parallel.hh:235
Return the size of a Type T containing other types at compile time. If no object for which an overloa...
Definition: type_traits.hh:438