HighFive 3.1.1
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// Other cases not supported. Fail early with a user message
239template <typename T>
241 static_assert(
242 true,
243 "Missing specialization of AtomicType<T>. Therefore, type T is not supported by HighFive.");
244}
245
246
247// Internal
248// Reference mapping
249template <>
251 _hid = detail::h5t_copy(H5T_STD_REF_OBJ);
252}
253
254inline size_t find_first_atomic_member_size(hid_t hid) {
255 // Recursive exit condition
256 if (detail::h5t_get_class(hid) == H5T_COMPOUND) {
257 auto number_of_members = detail::h5t_get_nmembers(hid);
258 if (number_of_members == -1) {
259 throw DataTypeException("Cannot get members of CompoundType with hid: " +
260 std::to_string(hid));
261 }
262 if (number_of_members == 0) {
263 throw DataTypeException("No members defined for CompoundType with hid: " +
264 std::to_string(hid));
265 }
266
267 auto member_type = detail::h5t_get_member_type(hid, 0);
268 auto size = find_first_atomic_member_size(member_type);
269 detail::h5t_close(member_type);
270 return size;
271 } else if (detail::h5t_get_class(hid) == H5T_STRING) {
272 return 1;
273 }
274 return detail::h5t_get_size(hid);
275}
276
277namespace detail {
278// Calculate the padding required to align an element of a struct
279// For padding see explanation here: https://en.cppreference.com/w/cpp/language/object#Alignment
280// It is to compute padding following last element inserted inside a struct
281// 1) We want to push back an element padded to the structure
282// 'current_size' is the size of the structure before adding the new element.
283// 'member_size' the size of the element we want to add.
284// 2) We want to compute the final padding for the global structure
285// 'current_size' is the size of the whole structure without final padding
286// 'member_size' is the maximum size of all element of the struct
287//
288// The basic formula is only to know how much we need to add to 'current_size' to fit
289// 'member_size'.
290// And at the end, we do another computation because the end padding, should fit the biggest
291// element of the struct.
292//
293// As we are with `size_t` element, we need to compute everything inside R+
294inline size_t struct_padding(size_t current_size, size_t member_size) {
295 if (member_size == 0) {
296 throw DataTypeException("Unexpected `member_size == 0`.");
297 }
298
299 return member_size >= current_size
300 ? (member_size - current_size) % member_size
301 : ((member_size - ((current_size - member_size) % member_size))) % member_size;
302}
303} // namespace detail
304
305inline void CompoundType::create(size_t size) {
306 if (size == 0) {
307 size_t current_size = 0, max_atomic_size = 0;
308
309 // Do a first pass to find the total size of the compound datatype
310 for (auto& member: members) {
311 size_t member_size = detail::h5t_get_size(member.base_type.getId());
312
313 if (member_size == 0) {
314 throw DataTypeException("Cannot get size of DataType with hid: " +
315 std::to_string(member.base_type.getId()));
316 }
317
318 size_t first_atomic_size = find_first_atomic_member_size(member.base_type.getId());
319
320 // Set the offset of this member within the struct according to the
321 // standard alignment rules. The c++ standard specifies that:
322 // > objects have an alignment requirement of which their size is a multiple
323 member.offset = current_size + detail::struct_padding(current_size, first_atomic_size);
324
325 // Set the current size to the end of the new member
326 current_size = member.offset + member_size;
327
328 // Keep track of the highest atomic member size because it's needed
329 // for the padding of the complete compound type.
330 max_atomic_size = std::max(max_atomic_size, first_atomic_size);
331 }
332
333 size = current_size + detail::struct_padding(current_size, max_atomic_size);
334 }
335
336 // Create the HDF5 type
337 _hid = detail::h5t_create(H5T_COMPOUND, size);
338
339 // Loop over all the members and insert them into the datatype
340 for (const auto& member: members) {
341 detail::h5t_insert(_hid, member.name.c_str(), member.offset, member.base_type.getId());
342 }
343}
344
345inline void CompoundType::commit(const Object& object, const std::string& name) const {
346 detail::h5t_commit2(
347 object.getId(), name.c_str(), getId(), H5P_DEFAULT, H5P_DEFAULT, H5P_DEFAULT);
348}
349
350template <typename T>
351inline void EnumType<T>::create() {
352 // Create the HDF5 type
353 _hid = detail::h5t_enum_create(AtomicType<typename std::underlying_type<T>::type>{}.getId());
354
355 // Loop over all the members and insert them into the datatype
356 for (const auto& member: members) {
357 detail::h5t_enum_insert(_hid, member.name.c_str(), &(member.value));
358 }
359}
360
361template <typename T>
362inline void EnumType<T>::commit(const Object& object, const std::string& name) const {
363 detail::h5t_commit2(
364 object.getId(), name.c_str(), getId(), H5P_DEFAULT, H5P_DEFAULT, H5P_DEFAULT);
365}
366
367namespace {
368
369inline hid_t create_string(size_t length) {
370 hid_t _hid = detail::h5t_copy(H5T_C_S1);
371 detail::h5t_set_size(_hid, length);
372 detail::h5t_set_cset(_hid, H5T_CSET_UTF8);
373 return _hid;
374}
375
376
377inline DataTypeClass convert_type_class(const H5T_class_t& tclass) {
378 switch (tclass) {
379 case H5T_TIME:
380 return DataTypeClass::Time;
381 case H5T_INTEGER:
383 case H5T_FLOAT:
385 case H5T_STRING:
387 case H5T_BITFIELD:
389 case H5T_OPAQUE:
391 case H5T_COMPOUND:
393 case H5T_REFERENCE:
395 case H5T_ENUM:
396 return DataTypeClass::Enum;
397 case H5T_VLEN:
399 case H5T_ARRAY:
401 case H5T_NO_CLASS:
402 case H5T_NCLASSES:
403 default:
405 }
406}
407
408
409inline std::string type_class_string(DataTypeClass tclass) {
410 switch (tclass) {
412 return "Time";
414 return "Integer";
416 return "Float";
418 return "String";
420 return "BitField";
422 return "Opaque";
424 return "Compound";
426 return "Reference";
428 return "Enum";
430 return "Varlen";
432 return "Array";
433 default:
434 return "(Invalid)";
435 }
436}
437
438} // unnamed namespace
439
440
442template <typename T>
444 return AtomicType<T>();
445}
446
447
449template <typename T>
451 DataType t = create_datatype<T>();
452 if (t.empty()) {
453 throw DataTypeException("Type given to create_and_check_datatype is not valid");
454 }
455
456 // Skip check if the base type is a variable length string
457 if (t.isVariableStr()) {
458 return t;
459 }
460
461 // Check that the size of the template type matches the size that HDF5 is
462 // expecting.
463 if (t.isReference() || t.isFixedLenStr()) {
464 return t;
465 }
466 if (sizeof(T) != t.getSize()) {
467 std::ostringstream ss;
468 ss << "Size of array type " << sizeof(T) << " != that of memory datatype " << t.getSize()
469 << std::endl;
470 throw DataTypeException(ss.str());
471 }
472
473 return t;
474}
475
476} // namespace HighFive
477HIGHFIVE_REGISTER_TYPE(HighFive::details::Boolean, HighFive::create_enum_boolean)
478
479namespace HighFive {
480
481template <>
483 return create_datatype<HighFive::details::Boolean>();
484}
485
486} // 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:240
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:345
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:362
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:450
DataType create_datatype()
Create a DataType instance representing type T.
Definition H5DataType_misc.hpp:443
CharacterSet
Definition H5DataType.hpp:131
DataType create_datatype< bool >()
Definition H5DataType_misc.hpp:482
size_t find_first_atomic_member_size(hid_t hid)
Definition H5DataType_misc.hpp:254
DataTypeClass
Enum of Fundamental data classes.
Definition H5DataType.hpp:31
StringPadding
Definition string_padding.hpp:7