HighFive 3.2.0
HighFive - Header-only C++ HDF5 interface
Loading...
Searching...
No Matches
H5DataType_misc.hpp
Go to the documentation of this file.
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#pragma once
10
11#include <string>
12#include <complex>
13#include <cstring>
14#if HIGHFIVE_CXX_STD >= 17
15#include <cstddef>
16#endif
17
18#include <H5Ppublic.h>
19
20#include "H5Inspector_misc.hpp"
21#include "h5t_wrapper.hpp"
22#include "h5i_wrapper.hpp"
23
24namespace HighFive {
25
26namespace { // unnamed
27inline DataTypeClass convert_type_class(const H5T_class_t& tclass);
28inline std::string type_class_string(DataTypeClass);
29inline hid_t create_string(std::size_t length);
30} // namespace
31
32inline bool DataType::empty() const noexcept {
33 return _hid == H5I_INVALID_HID;
34}
35
37 return convert_type_class(detail::h5t_get_class(_hid));
38}
39
40inline size_t DataType::getSize() const {
41 return detail::h5t_get_size(_hid);
42}
43
44inline bool DataType::operator==(const DataType& other) const {
45 return detail::h5t_equal(_hid, other._hid) > 0;
46}
47
48inline bool DataType::operator!=(const DataType& other) const {
49 return !(*this == other);
50}
51
52inline bool DataType::isVariableStr() const {
53 return detail::h5t_is_variable_str(_hid) > 0;
54}
55
56inline bool DataType::isFixedLenStr() const {
58}
59
60inline bool DataType::isReference() const {
61 return detail::h5t_equal(_hid, H5T_STD_REF_OBJ) > 0;
62}
63
66 throw DataTypeException("Invalid conversion to StringType.");
67 }
68
69 if (isValid()) {
70 detail::h5i_inc_ref(_hid);
71 }
72
73 return StringType(_hid);
74}
75
78 throw DataTypeException("Invalid conversion to IntegerType.");
79 }
80
81 if (isValid()) {
82 detail::h5i_inc_ref(_hid);
83 }
84
85 return IntegerType(_hid);
86}
87
88inline std::string DataType::string() const {
89 return type_class_string(getClass()) + std::to_string(getSize() * 8);
90}
91
93 return StringPadding(detail::h5t_get_strpad(_hid));
94}
95
97 return CharacterSet(detail::h5t_get_cset(_hid));
98}
99
101 StringPadding padding,
102 CharacterSet character_set) {
103 if (size == 0 && padding == StringPadding::NullTerminated) {
104 throw DataTypeException(
105 "Fixed-length, null-terminated need at least one byte to store the null-character.");
106 }
107
108 _hid = detail::h5t_copy(H5T_C_S1);
109
110 detail::h5t_set_size(_hid, hsize_t(size));
111 detail::h5t_set_cset(_hid, H5T_cset_t(character_set));
112 detail::h5t_set_strpad(_hid, H5T_str_t(padding));
113}
114
116 _hid = detail::h5t_copy(H5T_C_S1);
117
118 detail::h5t_set_size(_hid, H5T_VARIABLE);
119 detail::h5t_set_cset(_hid, H5T_cset_t(character_set));
120}
121
122// char mapping
123template <>
125 _hid = detail::h5t_copy(H5T_NATIVE_CHAR);
126}
127
128template <>
130 _hid = detail::h5t_copy(H5T_NATIVE_SCHAR);
131}
132
133template <>
135 _hid = detail::h5t_copy(H5T_NATIVE_UCHAR);
136}
137
138// short mapping
139template <>
141 _hid = detail::h5t_copy(H5T_NATIVE_SHORT);
142}
143
144template <>
146 _hid = detail::h5t_copy(H5T_NATIVE_USHORT);
147}
148
149// integer mapping
150template <>
152 _hid = detail::h5t_copy(H5T_NATIVE_INT);
153}
154
155template <>
157 _hid = detail::h5t_copy(H5T_NATIVE_UINT);
158}
159
160// long mapping
161template <>
163 _hid = detail::h5t_copy(H5T_NATIVE_LONG);
164}
165
166template <>
168 _hid = detail::h5t_copy(H5T_NATIVE_ULONG);
169}
170
171// long long mapping
172template <>
174 _hid = detail::h5t_copy(H5T_NATIVE_LLONG);
175}
176
177template <>
179 _hid = detail::h5t_copy(H5T_NATIVE_ULLONG);
180}
181
182// half-float, float, double and long double mapping
183template <>
185 _hid = detail::h5t_copy(H5T_NATIVE_FLOAT);
186}
187
188template <>
190 _hid = detail::h5t_copy(H5T_NATIVE_DOUBLE);
191}
192
193template <>
195 _hid = detail::h5t_copy(H5T_NATIVE_LDOUBLE);
196}
197
198// std string
199template <>
201 _hid = create_string(H5T_VARIABLE);
202}
203
204#if HIGHFIVE_CXX_STD >= 17
205// std byte
206template <>
208 _hid = detail::h5t_copy(H5T_NATIVE_B8);
209}
210#endif
211
212// Fixed-Length strings
213// require class specialization templated for the char length
214template <size_t StrLen>
215class AtomicType<char[StrLen]>: public DataType {
216 public:
217 inline AtomicType()
218 : DataType(create_string(StrLen)) {}
219};
220
221template <typename T>
222class AtomicType<std::complex<T>>: public DataType {
223 public:
224 inline AtomicType()
225 : DataType(
226 CompoundType({{"r", create_datatype<T>(), 0}, {"i", create_datatype<T>(), sizeof(T)}},
227 sizeof(std::complex<T>))) {
228 static_assert(std::is_arithmetic<T>::value,
229 "std::complex accepts only floating point and integral numbers.");
230 }
231};
232
233// For boolean we act as h5py
235 return {{"FALSE", details::Boolean::HighFiveFalse}, {"TRUE", details::Boolean::HighFiveTrue}};
236}
237
238
239namespace detail {
240template <class T>
241struct FalseType {
242 static constexpr const bool value = false;
243};
244} // namespace detail
245
246// Other cases not supported. Fail early with a user message
247template <typename T>
249 // Certain compilers reject a plain `false`.
250 static_assert(
251 ::HighFive::detail::FalseType<T>::value,
252 "Missing specialization of AtomicType<T>. Therefore, type T is not supported by HighFive.");
253}
254
255
256// Internal
257// Reference mapping
258template <>
260 _hid = detail::h5t_copy(H5T_STD_REF_OBJ);
261}
262
263inline size_t find_first_atomic_member_size(hid_t hid) {
264 // Recursive exit condition
265 if (detail::h5t_get_class(hid) == H5T_COMPOUND) {
266 auto number_of_members = detail::h5t_get_nmembers(hid);
267 if (number_of_members == -1) {
268 throw DataTypeException("Cannot get members of CompoundType with hid: " +
269 std::to_string(hid));
270 }
271 if (number_of_members == 0) {
272 throw DataTypeException("No members defined for CompoundType with hid: " +
273 std::to_string(hid));
274 }
275
276 auto member_type = detail::h5t_get_member_type(hid, 0);
277 auto size = find_first_atomic_member_size(member_type);
278 detail::h5t_close(member_type);
279 return size;
280 } else if (detail::h5t_get_class(hid) == H5T_STRING) {
281 return 1;
282 }
283 return detail::h5t_get_size(hid);
284}
285
286namespace detail {
287// Calculate the padding required to align an element of a struct
288// For padding see explanation here: https://en.cppreference.com/w/cpp/language/object#Alignment
289// It is to compute padding following last element inserted inside a struct
290// 1) We want to push back an element padded to the structure
291// 'current_size' is the size of the structure before adding the new element.
292// 'member_size' the size of the element we want to add.
293// 2) We want to compute the final padding for the global structure
294// 'current_size' is the size of the whole structure without final padding
295// 'member_size' is the maximum size of all element of the struct
296//
297// The basic formula is only to know how much we need to add to 'current_size' to fit
298// 'member_size'.
299// And at the end, we do another computation because the end padding, should fit the biggest
300// element of the struct.
301//
302// As we are with `size_t` element, we need to compute everything inside R+
303inline size_t struct_padding(size_t current_size, size_t member_size) {
304 if (member_size == 0) {
305 throw DataTypeException("Unexpected `member_size == 0`.");
306 }
307
308 return member_size >= current_size
309 ? (member_size - current_size) % member_size
310 : ((member_size - ((current_size - member_size) % member_size))) % member_size;
311}
312} // namespace detail
313
314inline void CompoundType::create(size_t size) {
315 if (size == 0) {
316 size_t current_size = 0, max_atomic_size = 0;
317
318 // Do a first pass to find the total size of the compound datatype
319 for (auto& member: members) {
320 size_t member_size = detail::h5t_get_size(member.base_type.getId());
321
322 if (member_size == 0) {
323 throw DataTypeException("Cannot get size of DataType with hid: " +
324 std::to_string(member.base_type.getId()));
325 }
326
327 size_t first_atomic_size = find_first_atomic_member_size(member.base_type.getId());
328
329 // Set the offset of this member within the struct according to the
330 // standard alignment rules. The c++ standard specifies that:
331 // > objects have an alignment requirement of which their size is a multiple
332 member.offset = current_size + detail::struct_padding(current_size, first_atomic_size);
333
334 // Set the current size to the end of the new member
335 current_size = member.offset + member_size;
336
337 // Keep track of the highest atomic member size because it's needed
338 // for the padding of the complete compound type.
339 max_atomic_size = std::max(max_atomic_size, first_atomic_size);
340 }
341
342 size = current_size + detail::struct_padding(current_size, max_atomic_size);
343 }
344
345 // Create the HDF5 type
346 _hid = detail::h5t_create(H5T_COMPOUND, size);
347
348 // Loop over all the members and insert them into the datatype
349 for (const auto& member: members) {
350 detail::h5t_insert(_hid, member.name.c_str(), member.offset, member.base_type.getId());
351 }
352}
353
354inline void CompoundType::commit(const Object& object, const std::string& name) const {
355 detail::h5t_commit2(
356 object.getId(), name.c_str(), getId(), H5P_DEFAULT, H5P_DEFAULT, H5P_DEFAULT);
357}
358
359template <typename T>
360inline void EnumType<T>::create() {
361 // Create the HDF5 type
362 _hid = detail::h5t_enum_create(AtomicType<typename std::underlying_type<T>::type>{}.getId());
363
364 // Loop over all the members and insert them into the datatype
365 for (const auto& member: members) {
366 detail::h5t_enum_insert(_hid, member.name.c_str(), &(member.value));
367 }
368}
369
370template <typename T>
371inline void EnumType<T>::commit(const Object& object, const std::string& name) const {
372 detail::h5t_commit2(
373 object.getId(), name.c_str(), getId(), H5P_DEFAULT, H5P_DEFAULT, H5P_DEFAULT);
374}
375
376namespace {
377
378inline hid_t create_string(size_t length) {
379 hid_t _hid = detail::h5t_copy(H5T_C_S1);
380 detail::h5t_set_size(_hid, length);
381 detail::h5t_set_cset(_hid, H5T_CSET_UTF8);
382 return _hid;
383}
384
385
386inline DataTypeClass convert_type_class(const H5T_class_t& tclass) {
387 switch (tclass) {
388 case H5T_TIME:
389 return DataTypeClass::Time;
390 case H5T_INTEGER:
392 case H5T_FLOAT:
394 case H5T_STRING:
396 case H5T_BITFIELD:
398 case H5T_OPAQUE:
400 case H5T_COMPOUND:
402 case H5T_REFERENCE:
404 case H5T_ENUM:
405 return DataTypeClass::Enum;
406 case H5T_VLEN:
408 case H5T_ARRAY:
410 case H5T_NO_CLASS:
411 case H5T_NCLASSES:
412 default:
414 }
415}
416
417
418inline std::string type_class_string(DataTypeClass tclass) {
419 switch (tclass) {
421 return "Time";
423 return "Integer";
425 return "Float";
427 return "String";
429 return "BitField";
431 return "Opaque";
433 return "Compound";
435 return "Reference";
437 return "Enum";
439 return "Varlen";
441 return "Array";
442 default:
443 return "(Invalid)";
444 }
445}
446
447} // unnamed namespace
448
449
451template <typename T>
453 return AtomicType<T>();
454}
455
456
458template <typename T>
460 DataType t = create_datatype<T>();
461 if (t.empty()) {
462 throw DataTypeException("Type given to create_and_check_datatype is not valid");
463 }
464
465 // Skip check if the base type is a variable length string
466 if (t.isVariableStr()) {
467 return t;
468 }
469
470 // Check that the size of the template type matches the size that HDF5 is
471 // expecting.
472 if (t.isReference() || t.isFixedLenStr()) {
473 return t;
474 }
475 if (sizeof(T) != t.getSize()) {
476 std::ostringstream ss;
477 ss << "Size of array type " << sizeof(T) << " != that of memory datatype " << t.getSize()
478 << std::endl;
479 throw DataTypeException(ss.str());
480 }
481
482 return t;
483}
484
485} // namespace HighFive
486HIGHFIVE_REGISTER_TYPE(HighFive::details::Boolean, HighFive::create_enum_boolean)
487
488namespace HighFive {
489
490template <>
492 return create_datatype<HighFive::details::Boolean>();
493}
494
495} // namespace HighFive
#define HIGHFIVE_REGISTER_TYPE(type, function)
Macro to extend datatype of HighFive.
Definition H5DataType.hpp:383
AtomicType()
Definition H5DataType_misc.hpp:217
AtomicType()
Definition H5DataType_misc.hpp:224
create an HDF5 DataType from a C++ type
Definition H5DataType.hpp:211
AtomicType()
Definition H5DataType_misc.hpp:248
Create a compound HDF5 datatype.
Definition H5DataType.hpp:222
void commit(const Object &object, const std::string &name) const
Commit datatype into the given Object.
Definition H5DataType_misc.hpp:354
Exception specific to HighFive DataType interface.
Definition H5Exception.hpp:97
HDF5 Data Type.
Definition H5DataType.hpp:62
bool operator==(const DataType &other) const
Definition H5DataType_misc.hpp:44
bool isFixedLenStr() const
Returns whether the type is a fixed-length string.
Definition H5DataType_misc.hpp:56
size_t getSize() const
Returns the length (in bytes) of this type elements.
Definition H5DataType_misc.hpp:40
IntegerType asIntegerType() const
Returns this datatype as a IntegerType.
Definition H5DataType_misc.hpp:76
bool isVariableStr() const
Returns whether the type is a variable-length string.
Definition H5DataType_misc.hpp:52
bool empty() const noexcept
Check the DataType was default constructed.
Definition H5DataType_misc.hpp:32
std::string string() const
Returns a friendly description of the type (e.g. Float32)
Definition H5DataType_misc.hpp:88
DataTypeClass getClass() const
Return the fundamental type.
Definition H5DataType_misc.hpp:36
bool isReference() const
Returns whether the type is a Reference.
Definition H5DataType_misc.hpp:60
StringType asStringType() const
Returns this datatype as a StringType.
Definition H5DataType_misc.hpp:64
bool operator!=(const DataType &other) const
Definition H5DataType_misc.hpp:48
Create a enum HDF5 datatype.
Definition H5DataType.hpp:318
void commit(const Object &object, const std::string &name) const
Commit datatype into the given Object.
Definition H5DataType_misc.hpp:371
FixedLengthStringType(size_t size, StringPadding padding, CharacterSet character_set=CharacterSet::Ascii)
Create a fixed length string datatype.
Definition H5DataType_misc.hpp:100
An Integer datatype (i.e. H5T_INTEGER).
Definition H5DataType.hpp:194
Definition H5Object.hpp:36
hid_t getId() const noexcept
getId
Definition H5Object_misc.hpp:75
bool isValid() const noexcept
isValid
Definition H5Object_misc.hpp:71
hid_t _hid
Definition H5Object.hpp:98
Definition H5DataType.hpp:136
StringPadding getPadding() const
For fixed length stings return the padding.
Definition H5DataType_misc.hpp:92
CharacterSet getCharacterSet() const
For stings return the character set.
Definition H5DataType_misc.hpp:96
VariableLengthStringType(CharacterSet character_set=CharacterSet::Ascii)
Create a variable length string HDF5 datatype.
Definition H5DataType_misc.hpp:115
Definition assert_compatible_spaces.hpp:15
EnumType< details::Boolean > create_enum_boolean()
Definition H5DataType_misc.hpp:234
DataType create_and_check_datatype()
Create a DataType instance representing type T and perform a sanity check on its size.
Definition H5DataType_misc.hpp:459
DataType create_datatype()
Create a DataType instance representing type T.
Definition H5DataType_misc.hpp:452
CharacterSet
Definition H5DataType.hpp:131
DataType create_datatype< bool >()
Definition H5DataType_misc.hpp:491
size_t find_first_atomic_member_size(hid_t hid)
Definition H5DataType_misc.hpp:263
DataTypeClass
Enum of Fundamental data classes.
Definition H5DataType.hpp:31
StringPadding
Definition string_padding.hpp:7