h5gt 0.2.0
C++ wrapper for HDF5 library (based on HighFive project)
Loading...
Searching...
No Matches
H5DataType_misc.hpp
1/*
2 * Copyright (c), 2017, Adrien Devresse <adrien.devresse@epfl.ch>
3 *
4 * Distributed under the Boost Software License, Version 1.0.
5 * (See accompanying file LICENSE_1_0.txt or copy at
6 * http://www.boost.org/LICENSE_1_0.txt)
7 *
8 */
9#ifndef H5DATATYPE_MISC_HPP
10#define H5DATATYPE_MISC_HPP
11
12#include <string>
13#include <complex>
14#include <cstring>
15
16#include <H5Ppublic.h>
17#include <H5Tpublic.h>
18
19
20namespace h5gt {
21
22namespace { // unnamed
23inline DataTypeClass convert_type_class(const H5T_class_t& tclass);
24inline std::string type_class_string(DataTypeClass);
25inline hid_t create_string(std::size_t length);
26}
27
28inline bool DataType::empty() const noexcept {
29 return _hid == H5I_INVALID_HID;
30}
31
32inline DataTypeClass DataType::getClass() const {
33 return convert_type_class(H5Tget_class(_hid));
34}
35
36inline size_t DataType::getSize() const {
37 return H5Tget_size(_hid);
38}
39
42inline bool DataType::isTypeEqual(const DataType& other) const {
43 htri_t isT1_VarLen = H5Tis_variable_str(_hid);
44 htri_t isT2_VarLen = H5Tis_variable_str(other._hid);
45 if (isT1_VarLen > 0 && isT2_VarLen > 0)
46 return true;
47
48 if (isT1_VarLen > 0 && isT1_VarLen <= 0 ||
49 isT1_VarLen <= 0 && isT1_VarLen > 0)
50 return false;
51
52 return (H5Tequal(_hid, other._hid) > 0);
53}
54
55inline bool DataType::isVariableStr() const {
56 auto var_value = H5Tis_variable_str(_hid);
57 if (var_value < 0) {
58 HDF5ErrMapper::ToException<DataTypeException>(
59 "Unable to define datatype size to variable");
60 }
61 return static_cast<bool>(var_value);
62}
63
64inline bool DataType::isFixedLenStr() const {
65 return getClass() == DataTypeClass::String && !isVariableStr();
66}
67
68inline bool DataType::isReference() const {
69 return H5Tequal(_hid, H5T_STD_REF_OBJ) > 0;
70}
71
72inline bool DataType::operator==(const DataType& other) const {
73 return Object::operator==(other);
74}
75
76inline bool DataType::operator!=(const DataType& other) const {
77 return !(*this == other);
78}
79
80inline std::string DataType::string() const {
81 return type_class_string(getClass()) + std::to_string(getSize() * 8);
82}
83
84// char mapping
85template <>
86inline AtomicType<char>::AtomicType(Endian endian) {
87 if (endian == Little){
88 _hid = H5Tcopy(H5T_STD_I8LE);
89 } else if (endian == Big){
90 _hid = H5Tcopy(H5T_STD_I8BE);
91 } else {
92 _hid = H5Tcopy(H5T_NATIVE_CHAR);
93 }
94}
95
96template <>
97inline AtomicType<signed char>::AtomicType(Endian endian) {
98 if (endian == Little){
99 _hid = H5Tcopy(H5T_STD_I8LE);
100 } else if (endian == Big){
101 _hid = H5Tcopy(H5T_STD_I8BE);
102 } else {
103 _hid = H5Tcopy(H5T_NATIVE_CHAR);
104 }
105}
106
107template <>
108inline AtomicType<unsigned char>::AtomicType(Endian endian) {
109 if (endian == Little){
110 _hid = H5Tcopy(H5T_STD_U8LE);
111 } else if (endian == Big){
112 _hid = H5Tcopy(H5T_STD_U8BE);
113 } else {
114 _hid = H5Tcopy(H5T_NATIVE_UCHAR);
115 }
116}
117
118// short mapping
119template <>
120inline AtomicType<short>::AtomicType(Endian endian) {
121 if (endian == Little){
122 _hid = H5Tcopy(H5T_STD_I16LE);
123 } else if (endian == Big){
124 _hid = H5Tcopy(H5T_STD_I16BE);
125 } else {
126 _hid = H5Tcopy(H5T_NATIVE_SHORT);
127 }
128}
129
130template <>
131inline AtomicType<unsigned short>::AtomicType(Endian endian) {
132 if (endian == Little){
133 _hid = H5Tcopy(H5T_STD_U16LE);
134 } else if (endian == Big){
135 _hid = H5Tcopy(H5T_STD_U16BE);
136 } else {
137 _hid = H5Tcopy(H5T_NATIVE_USHORT);
138 }
139}
140
141// integer mapping
142template <>
143inline AtomicType<int>::AtomicType(Endian endian) {
144 if (endian == Little){
145 _hid = H5Tcopy(H5T_STD_I32LE);
146 } else if (endian == Big){
147 _hid = H5Tcopy(H5T_STD_I32BE);
148 } else {
149 _hid = H5Tcopy(H5T_NATIVE_INT);
150 }
151}
152
153template <>
154inline AtomicType<unsigned>::AtomicType(Endian endian) {
155 if (endian == Little){
156 _hid = H5Tcopy(H5T_STD_U32LE);
157 } else if (endian == Big){
158 _hid = H5Tcopy(H5T_STD_U32BE);
159 } else {
160 _hid = H5Tcopy(H5T_NATIVE_UINT);
161 }
162}
163
164// long mapping
165template <>
166inline AtomicType<long>::AtomicType(Endian endian) {
167 if (endian == Little){
168 _hid = H5Tcopy(H5T_STD_I32LE);
169 } else if (endian == Big){
170 _hid = H5Tcopy(H5T_STD_I32BE);
171 } else {
172 _hid = H5Tcopy(H5T_NATIVE_LONG);
173 }
174}
175
176template <>
177inline AtomicType<unsigned long>::AtomicType(Endian endian) {
178 if (endian == Little){
179 _hid = H5Tcopy(H5T_STD_U32LE);
180 } else if (endian == Big){
181 _hid = H5Tcopy(H5T_STD_U32BE);
182 } else {
183 _hid = H5Tcopy(H5T_NATIVE_ULONG);
184 }
185}
186
187// long long mapping
188template <>
189inline AtomicType<long long>::AtomicType(Endian endian) {
190 if (endian == Little){
191 _hid = H5Tcopy(H5T_STD_I64LE);
192 } else if (endian == Big){
193 _hid = H5Tcopy(H5T_STD_I64BE);
194 } else {
195 _hid = H5Tcopy(H5T_NATIVE_LLONG);
196 }
197}
198
199template <>
200inline AtomicType<unsigned long long>::AtomicType(Endian endian) {
201 if (endian == Little){
202 _hid = H5Tcopy(H5T_STD_U64LE);
203 } else if (endian == Big){
204 _hid = H5Tcopy(H5T_STD_U64BE);
205 } else {
206 _hid = H5Tcopy(H5T_NATIVE_ULLONG);
207 }
208}
209
210// float and double mapping
211template <>
212inline AtomicType<float>::AtomicType(Endian endian) {
213 if (endian == Little){
214 _hid = H5Tcopy(H5T_IEEE_F32LE);
215 } else if (endian == Big){
216 _hid = H5Tcopy(H5T_IEEE_F32BE);
217 } else {
218 _hid = H5Tcopy(H5T_NATIVE_FLOAT);
219 }
220}
221
222template <>
223inline AtomicType<double>::AtomicType(Endian endian) {
224 if (endian == Little){
225 _hid = H5Tcopy(H5T_IEEE_F64LE);
226 } else if (endian == Big){
227 _hid = H5Tcopy(H5T_IEEE_F64BE);
228 } else {
229 _hid = H5Tcopy(H5T_NATIVE_DOUBLE);
230 }
231}
232
233// boolean mapping
234template <>
235inline AtomicType<bool>::AtomicType(Endian endian) {
236 if (endian == Little){
237 _hid = H5Tcopy(H5T_STD_I8LE);
238 } else if (endian == Big){
239 _hid = H5Tcopy(H5T_STD_I8BE);
240 } else {
241 _hid = H5Tcopy(H5T_NATIVE_HBOOL);
242 }
243}
244
245// std string
246template <>
247inline AtomicType<std::string>::AtomicType(Endian endian) {
248 _hid = create_string(H5T_VARIABLE);
249}
250
251// std string
252template <>
253inline AtomicType<const char*>::AtomicType(Endian endian) {
254 _hid = create_string(H5T_VARIABLE);
255}
256
257// Fixed-Length strings
258// require class specialization templated for the char length
259template <size_t StrLen>
260class AtomicType<char[StrLen]> : public DataType {
261public:
262 inline AtomicType() : DataType(create_string(StrLen)) {}
263};
264
265template <size_t StrLen>
266class AtomicType<FixedLenStringArray<StrLen>> : public DataType {
267public:
268 inline AtomicType() : DataType(create_string(StrLen)) {}
269};
270
271template <>
272inline AtomicType<std::complex<double> >::AtomicType(Endian endian) {
273 if (endian == Little){
274 static struct ComplexType : public Object {
275 ComplexType() {
276 _hid = H5Tcreate(H5T_COMPOUND, sizeof(std::complex<double>));
277 // h5py/numpy compatible datatype
278 H5Tinsert(_hid, "r", 0, H5T_IEEE_F64LE);
279 H5Tinsert(_hid, "i", sizeof(double), H5T_IEEE_F64LE);
280 };
281 } complexType;
282 _hid = H5Tcopy(complexType.getId(false));
283 } else if (endian == Big){
284 static struct ComplexType : public Object {
285 ComplexType() {
286 _hid = H5Tcreate(H5T_COMPOUND, sizeof(std::complex<double>));
287 // h5py/numpy compatible datatype
288 H5Tinsert(_hid, "r", 0, H5T_IEEE_F64BE);
289 H5Tinsert(_hid, "i", sizeof(double), H5T_IEEE_F64BE);
290 };
291 } complexType;
292 _hid = H5Tcopy(complexType.getId(false));
293 } else {
294 static struct ComplexType : public Object {
295 ComplexType() {
296 _hid = H5Tcreate(H5T_COMPOUND, sizeof(std::complex<double>));
297 // h5py/numpy compatible datatype
298 H5Tinsert(_hid, "r", 0, H5T_NATIVE_DOUBLE);
299 H5Tinsert(_hid, "i", sizeof(double), H5T_NATIVE_DOUBLE);
300 };
301 } complexType;
302 _hid = H5Tcopy(complexType.getId(false));
303 }
304}
305
306template <>
307inline AtomicType<std::complex<float> >::AtomicType(Endian endian) {
308 if (endian == Little){
309 static struct ComplexType : public Object {
310 ComplexType() {
311 _hid = H5Tcreate(H5T_COMPOUND, sizeof(std::complex<float>));
312 // h5py/numpy compatible datatype
313 H5Tinsert(_hid, "r", 0, H5T_IEEE_F32LE);
314 H5Tinsert(_hid, "i", sizeof(float), H5T_IEEE_F32LE);
315 };
316 } complexType;
317 _hid = H5Tcopy(complexType.getId(false));
318 } else if (endian == Big){
319 static struct ComplexType : public Object {
320 ComplexType() {
321 _hid = H5Tcreate(H5T_COMPOUND, sizeof(std::complex<float>));
322 // h5py/numpy compatible datatype
323 H5Tinsert(_hid, "r", 0, H5T_IEEE_F32BE);
324 H5Tinsert(_hid, "i", sizeof(float), H5T_IEEE_F32BE);
325 };
326 } complexType;
327 _hid = H5Tcopy(complexType.getId(false));
328 } else {
329 static struct ComplexType : public Object {
330 ComplexType() {
331 _hid = H5Tcreate(H5T_COMPOUND, sizeof(std::complex<float>));
332 // h5py/numpy compatible datatype
333 H5Tinsert(_hid, "r", 0, H5T_NATIVE_FLOAT);
334 H5Tinsert(_hid, "i", sizeof(float), H5T_NATIVE_FLOAT);
335 };
336 } complexType;
337 _hid = H5Tcopy(complexType.getId(false));
338 }
339}
340
341// Other cases not supported. Fail early with a user message
342template <typename T>
343AtomicType<T>::AtomicType(Endian endian) {
344 static_assert(details::inspector<T>::recursive_ndim == 0,
345 "Atomic types cant be arrays, except for char[] (fixed-len strings)");
346 static_assert(details::inspector<T>::recursive_ndim > 0, "Type not supported");
347}
348
349
350// class FixedLenStringArray<N>
351
352template <std::size_t N>
353inline FixedLenStringArray<N>
354::FixedLenStringArray(const char array[][N], std::size_t length) {
355 datavec.resize(length);
356 std::memcpy(datavec[0].data(), array[0].data(), N * length);
357}
358
359template <std::size_t N>
361::FixedLenStringArray(const std::string* iter_begin, const std::string* iter_end) {
362 datavec.resize(static_cast<std::size_t>(iter_end - iter_begin));
363 for (auto& dst_array : datavec) {
364 const char* src = (iter_begin++)->c_str();
365 const size_t length = std::min(N - 1 , std::strlen(src));
366 std::memcpy(dst_array.data(), src, length);
367 dst_array[length] = 0;
368 }
369}
370
371template <std::size_t N>
372inline FixedLenStringArray<N>
373::FixedLenStringArray(const std::vector<std::string> & vec)
374 : FixedLenStringArray(&vec.front(), &vec.back()) {}
375
376template <std::size_t N>
378::FixedLenStringArray(const std::initializer_list<std::string>& init_list)
379 : FixedLenStringArray(init_list.begin(), init_list.end()) {}
380
381template <std::size_t N>
382inline void FixedLenStringArray<N>::push_back(const std::string& src) {
383 datavec.emplace_back();
384 const size_t length = std::min(N - 1 , src.length());
385 std::memcpy(datavec.back().data(), src.c_str(), length);
386 datavec.back()[length] = 0;
387}
388
389template <std::size_t N>
390inline void FixedLenStringArray<N>::push_back(const std::array<char, N>& src) {
391 datavec.emplace_back();
392 std::copy(src.begin(), src.end(), datavec.back().data());
393}
394
395template <std::size_t N>
396inline std::string FixedLenStringArray<N>::getString(std::size_t i) const {
397 return std::string(datavec[i].data());
398}
399
400// Internal
401// Reference mapping
402template <>
403inline AtomicType<Reference>::AtomicType(Endian endian) {
404 _hid = H5Tcopy(H5T_STD_REF_OBJ);
405}
406
407
408// Calculate the padding required to align an element of a struct
409#define _H5_STRUCT_PADDING(current_size, member_size) (((member_size) - (current_size)) % (member_size))
410
411inline void CompoundType::create(size_t size) {
412 if (size == 0) {
413 size_t current_size = 0, max_type_size = 0;
414
415 // Do a first pass to find the total size of the compound datatype
416 for (auto& member: members) {
417 size_t member_size = H5Tget_size(member.base_type.getId(false));
418 if (member_size == 0) {
419 throw DataTypeException("Cannot get size of DataType with hid: " +
420 std::to_string(member.base_type.getId(false)));
421 }
422
423 // Set the offset of this member within the struct according to the
424 // standard alignment rules
425 member.offset = current_size + _H5_STRUCT_PADDING(current_size, member_size);
426
427 // Set the current size to the end of the new member
428 current_size = member.offset + member_size;
429
430 max_type_size = std::max(max_type_size, member_size);
431 }
432
433 size = current_size + _H5_STRUCT_PADDING(current_size, max_type_size);
434 }
435
436 // Create the HDF5 type
437 if((_hid = H5Tcreate(H5T_COMPOUND, size)) < 0) {
438 HDF5ErrMapper::ToException<DataTypeException>(
439 "Could not create new compound datatype");
440 }
441
442 // Loop over all the members and insert them into the datatype
443 for (const auto& member: members) {
444 if(H5Tinsert(_hid, member.name.c_str(), member.offset, member.base_type.getId(false)) < 0) {
445 HDF5ErrMapper::ToException<DataTypeException>(
446 "Could not add new member to datatype"
447 );
448 }
449 }
450}
451
452#undef _H5_STRUCT_PADDING
453
454inline void CompoundType::commit(const Object& object, const std::string& name) const {
455 H5Tcommit2(object.getId(false), name.c_str(), getId(false), H5P_DEFAULT, H5P_DEFAULT, H5P_DEFAULT);
456}
457
458inline DataTypeClass CompoundType::getMemberClass(const unsigned& member_no) const {
459 return convert_type_class(H5Tget_member_class(_hid, member_no));
460}
461
462inline int CompoundType::getMemberIndex(const std::string& field_name) const {
463 return H5Tget_member_index(_hid, field_name.c_str());
464}
465
466inline std::string CompoundType::getMemberName(const unsigned& field_idx) const {
467 return std::string(H5Tget_member_name(_hid, field_idx));
468}
469
470inline size_t CompoundType::getMemberOffset(const unsigned& memb_no) const {
471 return H5Tget_member_offset(_hid, memb_no);
472}
473
474inline hid_t CompoundType::getMemberType(const unsigned& field_idx) const {
475 return H5Tget_member_type(_hid, field_idx);
476}
477
478inline int CompoundType::getNMembers() const {
479 return H5Tget_nmembers(_hid);
480}
481
482
483
484template<typename T>
485inline void EnumType<T>::create() {
486 // Create the HDF5 type
487 if((_hid = H5Tenum_create(AtomicType<T>{}.getId(false))) < 0) {
488 HDF5ErrMapper::ToException<DataTypeException>(
489 "Could not create new enum datatype");
490 }
491
492 // Loop over all the members and insert them into the datatype
493 for (const auto& member: members) {
494 if(H5Tenum_insert(_hid, member.name.c_str(), &(member.value)) < 0) {
495 HDF5ErrMapper::ToException<DataTypeException>(
496 "Could not add new member to this enum datatype"
497 );
498 }
499 }
500}
501
502template<typename T>
503inline void EnumType<T>::commit(const Object& object, const std::string& name) const {
504 H5Tcommit2(object.getId(false), name.c_str(), getId(false), H5P_DEFAULT, H5P_DEFAULT, H5P_DEFAULT);
505}
506
507template<typename T>
508inline int EnumType<T>::getMemberIndex(const std::string& field_name) const {
509 return H5Tget_member_index(_hid, field_name.c_str());
510}
511
512template<typename T>
513inline std::string EnumType<T>::getMemberName(const unsigned& field_idx) const {
514 return std::string(H5Tget_member_name(_hid, field_idx));
515}
516
517template<typename T>
518inline void EnumType<T>::getMemberValue(const unsigned& memb_no, void *value) const {
519 if (H5Tget_member_value(_hid, memb_no, value) < 0){
520 HDF5ErrMapper::ToException<DataTypeException>(
521 "Could not get member value for this enum datatype"
522 );
523 }
524}
525
526template<typename T>
527inline int EnumType<T>::getNMembers() const {
528 return H5Tget_nmembers(_hid);
529}
530
531
532
533namespace {
534
535inline hid_t create_string(size_t length){
536 hid_t _hid = H5Tcopy(H5T_C_S1);
537 if (H5Tset_size(_hid, length) < 0) {
538 HDF5ErrMapper::ToException<DataTypeException>(
539 "Unable to define datatype size to variable");
540 }
541 // define encoding to UTF-8 by default
542 H5Tset_cset(_hid, H5T_CSET_UTF8);
543 return _hid;
544}
545
546
547inline DataTypeClass convert_type_class(const H5T_class_t& tclass) {
548 switch(tclass) {
549 case H5T_TIME:
550 return DataTypeClass::Time;
551 case H5T_INTEGER:
552 return DataTypeClass::Integer;
553 case H5T_FLOAT:
554 return DataTypeClass::Float;
555 case H5T_STRING:
556 return DataTypeClass::String;
557 case H5T_BITFIELD:
558 return DataTypeClass::BitField;
559 case H5T_OPAQUE:
560 return DataTypeClass::Opaque;
561 case H5T_COMPOUND:
562 return DataTypeClass::Compound;
563 case H5T_REFERENCE:
564 return DataTypeClass::Reference;
565 case H5T_ENUM:
566 return DataTypeClass::Enum;
567 case H5T_VLEN:
568 return DataTypeClass::VarLen;
569 case H5T_ARRAY:
570 return DataTypeClass::Array;
571 case H5T_NO_CLASS:
572 case H5T_NCLASSES:
573 default:
574 return DataTypeClass::Invalid;
575 }
576}
577
578
579inline std::string type_class_string(DataTypeClass tclass) {
580 switch(tclass) {
581 case DataTypeClass::Time:
582 return "Time";
583 case DataTypeClass::Integer:
584 return "Integer";
585 case DataTypeClass::Float:
586 return "Float";
587 case DataTypeClass::String:
588 return "String";
589 case DataTypeClass::BitField:
590 return "BitField";
591 case DataTypeClass::Opaque:
592 return "Opaque";
593 case DataTypeClass::Compound:
594 return "Compound";
595 case DataTypeClass::Reference:
596 return "Reference";
597 case DataTypeClass::Enum:
598 return "Enum";
599 case DataTypeClass::VarLen:
600 return "Varlen";
601 case DataTypeClass::Array:
602 return "Array";
603 default:
604 return "(Invalid)";
605 }
606}
607
608} // unnamed namespace
609
610
612template <typename T>
613inline DataType create_datatype() {
614 return AtomicType<T>();
615}
616
618template <typename T>
619inline DataType create_and_check_datatype() {
620
621 DataType t = create_datatype<T>();
622 if (t.empty()) {
623 throw DataTypeException("Type given to create_and_check_datatype is not valid");
624 }
625
626 // Skip check if the base type is a variable length string
627 if (t.isVariableStr()) {
628 return t;
629 }
630
631 // Check that the size of the template type matches the size that HDF5 is
632 // expecting.
633 if(!t.isReference() && (sizeof(T) != t.getSize())) {
634 std::ostringstream ss;
635 ss << "Size of array type " << sizeof(T)
636 << " != that of memory datatype " << t.getSize()
637 << std::endl;
638 throw DataTypeException(ss.str());
639 }
640
641 return t;
642}
643
644} // namespace h5gt
645
646
647#endif // H5DATATYPE_MISC_HPP
create an HDF5 DataType from a C++ type
Definition H5DataType.hpp:124
void commit(const Object &object, const std::string &name) const
Commit datatype into the given Object.
Definition H5DataType_misc.hpp:454
hid_t getMemberType(const unsigned &field_idx) const
return predefined type specified by hdf5 macro like: H5T_C_S1, H5T_NATIVE_INT, H5T_IEEE_F32BE etc.
Definition H5DataType_misc.hpp:474
HDF5 Data Type.
Definition H5DataType.hpp:48
size_t getSize() const
Returns the length (in bytes) of this type elements.
Definition H5DataType_misc.hpp:36
std::string string() const
Returns a friendly description of the type (e.g. Float32)
Definition H5DataType_misc.hpp:80
bool operator==(const DataType &other) const
operator == Check if objects reside in the same file and equal to each other
Definition H5DataType_misc.hpp:72
bool isReference() const
Returns whether the type is a Reference.
Definition H5DataType_misc.hpp:68
bool empty() const noexcept
Check the DataType was default constructed. Such value might represent auto-detection of the datatype...
Definition H5DataType_misc.hpp:28
DataTypeClass getClass() const
Return the fundamental type.
Definition H5DataType_misc.hpp:32
virtual bool isTypeEqual(const DataType &other) const
isTypeEqual Unlike == operator this only checks if the data types are equal and do not check if they ...
Definition H5DataType_misc.hpp:42
bool isVariableStr() const
Returns whether the type is a variable-length string.
Definition H5DataType_misc.hpp:55
bool isFixedLenStr() const
Returns whether the type is a fixed-length string.
Definition H5DataType_misc.hpp:64
Create a enum HDF5 datatype.
Definition H5DataType.hpp:241
void commit(const Object &object, const std::string &name) const
Commit datatype into the given Object.
Definition H5DataType_misc.hpp:503
A structure representing a set of fixed-length strings.
Definition H5DataType.hpp:305
void push_back(const std::string &)
Append an std::string to the buffer structure.
Definition H5DataType_misc.hpp:382
std::string getString(std::size_t index) const
Retrieve a string from the structure as std::string.
Definition H5DataType_misc.hpp:396
Definition H5Object.hpp:55
hid_t getId(const bool &increaseRefCount=false) const noexcept
getId
Definition H5Object_misc.hpp:172
bool operator==(const Object &other) const
When coparing objects h5gt::File must be open.
Definition H5Object_misc.hpp:105