HighFive 3.0.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
76inline std::string DataType::string() const {
77 return type_class_string(getClass()) + std::to_string(getSize() * 8);
78}
79
81 return StringPadding(detail::h5t_get_strpad(_hid));
82}
83
85 return CharacterSet(detail::h5t_get_cset(_hid));
86}
87
89 StringPadding padding,
90 CharacterSet character_set) {
91 if (size == 0 && padding == StringPadding::NullTerminated) {
93 "Fixed-length, null-terminated need at least one byte to store the null-character.");
94 }
95
96 _hid = detail::h5t_copy(H5T_C_S1);
97
98 detail::h5t_set_size(_hid, hsize_t(size));
99 detail::h5t_set_cset(_hid, H5T_cset_t(character_set));
100 detail::h5t_set_strpad(_hid, H5T_str_t(padding));
101}
102
104 _hid = detail::h5t_copy(H5T_C_S1);
105
106 detail::h5t_set_size(_hid, H5T_VARIABLE);
107 detail::h5t_set_cset(_hid, H5T_cset_t(character_set));
108}
109
110// char mapping
111template <>
113 _hid = detail::h5t_copy(H5T_NATIVE_CHAR);
114}
115
116template <>
118 _hid = detail::h5t_copy(H5T_NATIVE_SCHAR);
119}
120
121template <>
123 _hid = detail::h5t_copy(H5T_NATIVE_UCHAR);
124}
125
126// short mapping
127template <>
129 _hid = detail::h5t_copy(H5T_NATIVE_SHORT);
130}
131
132template <>
134 _hid = detail::h5t_copy(H5T_NATIVE_USHORT);
135}
136
137// integer mapping
138template <>
140 _hid = detail::h5t_copy(H5T_NATIVE_INT);
141}
142
143template <>
145 _hid = detail::h5t_copy(H5T_NATIVE_UINT);
146}
147
148// long mapping
149template <>
151 _hid = detail::h5t_copy(H5T_NATIVE_LONG);
152}
153
154template <>
156 _hid = detail::h5t_copy(H5T_NATIVE_ULONG);
157}
158
159// long long mapping
160template <>
162 _hid = detail::h5t_copy(H5T_NATIVE_LLONG);
163}
164
165template <>
167 _hid = detail::h5t_copy(H5T_NATIVE_ULLONG);
168}
169
170// half-float, float, double and long double mapping
171template <>
173 _hid = detail::h5t_copy(H5T_NATIVE_FLOAT);
174}
175
176template <>
178 _hid = detail::h5t_copy(H5T_NATIVE_DOUBLE);
179}
180
181template <>
183 _hid = detail::h5t_copy(H5T_NATIVE_LDOUBLE);
184}
185
186// std string
187template <>
189 _hid = create_string(H5T_VARIABLE);
190}
191
192#if HIGHFIVE_CXX_STD >= 17
193// std byte
194template <>
196 _hid = detail::h5t_copy(H5T_NATIVE_B8);
197}
198#endif
199
200// Fixed-Length strings
201// require class specialization templated for the char length
202template <size_t StrLen>
203class AtomicType<char[StrLen]>: public DataType {
204 public:
205 inline AtomicType()
206 : DataType(create_string(StrLen)) {}
207};
208
209template <typename T>
210class AtomicType<std::complex<T>>: public DataType {
211 public:
212 inline AtomicType()
213 : DataType(
214 CompoundType({{"r", create_datatype<T>(), 0}, {"i", create_datatype<T>(), sizeof(T)}},
215 sizeof(std::complex<T>))) {
216 static_assert(std::is_arithmetic<T>::value,
217 "std::complex accepts only floating point and integral numbers.");
218 }
219};
220
221// For boolean we act as h5py
223 return {{"FALSE", details::Boolean::HighFiveFalse}, {"TRUE", details::Boolean::HighFiveTrue}};
224}
225
226// Other cases not supported. Fail early with a user message
227template <typename T>
229 static_assert(
230 true,
231 "Missing specialization of AtomicType<T>. Therefore, type T is not supported by HighFive.");
232}
233
234
235// Internal
236// Reference mapping
237template <>
239 _hid = detail::h5t_copy(H5T_STD_REF_OBJ);
240}
241
242inline size_t find_first_atomic_member_size(hid_t hid) {
243 // Recursive exit condition
244 if (detail::h5t_get_class(hid) == H5T_COMPOUND) {
245 auto number_of_members = detail::h5t_get_nmembers(hid);
246 if (number_of_members == -1) {
247 throw DataTypeException("Cannot get members of CompoundType with hid: " +
248 std::to_string(hid));
249 }
250 if (number_of_members == 0) {
251 throw DataTypeException("No members defined for CompoundType with hid: " +
252 std::to_string(hid));
253 }
254
255 auto member_type = detail::h5t_get_member_type(hid, 0);
256 auto size = find_first_atomic_member_size(member_type);
257 detail::h5t_close(member_type);
258 return size;
259 } else if (detail::h5t_get_class(hid) == H5T_STRING) {
260 return 1;
261 }
262 return detail::h5t_get_size(hid);
263}
264
265namespace detail {
266// Calculate the padding required to align an element of a struct
267// For padding see explanation here: https://en.cppreference.com/w/cpp/language/object#Alignment
268// It is to compute padding following last element inserted inside a struct
269// 1) We want to push back an element padded to the structure
270// 'current_size' is the size of the structure before adding the new element.
271// 'member_size' the size of the element we want to add.
272// 2) We want to compute the final padding for the global structure
273// 'current_size' is the size of the whole structure without final padding
274// 'member_size' is the maximum size of all element of the struct
275//
276// The basic formula is only to know how much we need to add to 'current_size' to fit
277// 'member_size'.
278// And at the end, we do another computation because the end padding, should fit the biggest
279// element of the struct.
280//
281// As we are with `size_t` element, we need to compute everything inside R+
282inline size_t struct_padding(size_t current_size, size_t member_size) {
283 if (member_size == 0) {
284 throw DataTypeException("Unexpected `member_size == 0`.");
285 }
286
287 return member_size >= current_size
288 ? (member_size - current_size) % member_size
289 : ((member_size - ((current_size - member_size) % member_size))) % member_size;
290}
291} // namespace detail
292
293inline void CompoundType::create(size_t size) {
294 if (size == 0) {
295 size_t current_size = 0, max_atomic_size = 0;
296
297 // Do a first pass to find the total size of the compound datatype
298 for (auto& member: members) {
299 size_t member_size = detail::h5t_get_size(member.base_type.getId());
300
301 if (member_size == 0) {
302 throw DataTypeException("Cannot get size of DataType with hid: " +
303 std::to_string(member.base_type.getId()));
304 }
305
306 size_t first_atomic_size = find_first_atomic_member_size(member.base_type.getId());
307
308 // Set the offset of this member within the struct according to the
309 // standard alignment rules. The c++ standard specifies that:
310 // > objects have an alignment requirement of which their size is a multiple
311 member.offset = current_size + detail::struct_padding(current_size, first_atomic_size);
312
313 // Set the current size to the end of the new member
314 current_size = member.offset + member_size;
315
316 // Keep track of the highest atomic member size because it's needed
317 // for the padding of the complete compound type.
318 max_atomic_size = std::max(max_atomic_size, first_atomic_size);
319 }
320
321 size = current_size + detail::struct_padding(current_size, max_atomic_size);
322 }
323
324 // Create the HDF5 type
325 _hid = detail::h5t_create(H5T_COMPOUND, size);
326
327 // Loop over all the members and insert them into the datatype
328 for (const auto& member: members) {
329 detail::h5t_insert(_hid, member.name.c_str(), member.offset, member.base_type.getId());
330 }
331}
332
333inline void CompoundType::commit(const Object& object, const std::string& name) const {
334 detail::h5t_commit2(
335 object.getId(), name.c_str(), getId(), H5P_DEFAULT, H5P_DEFAULT, H5P_DEFAULT);
336}
337
338template <typename T>
339inline void EnumType<T>::create() {
340 // Create the HDF5 type
341 _hid = detail::h5t_enum_create(AtomicType<typename std::underlying_type<T>::type>{}.getId());
342
343 // Loop over all the members and insert them into the datatype
344 for (const auto& member: members) {
345 detail::h5t_enum_insert(_hid, member.name.c_str(), &(member.value));
346 }
347}
348
349template <typename T>
350inline void EnumType<T>::commit(const Object& object, const std::string& name) const {
351 detail::h5t_commit2(
352 object.getId(), name.c_str(), getId(), H5P_DEFAULT, H5P_DEFAULT, H5P_DEFAULT);
353}
354
355namespace {
356
357inline hid_t create_string(size_t length) {
358 hid_t _hid = detail::h5t_copy(H5T_C_S1);
359 detail::h5t_set_size(_hid, length);
360 detail::h5t_set_cset(_hid, H5T_CSET_UTF8);
361 return _hid;
362}
363
364
365inline DataTypeClass convert_type_class(const H5T_class_t& tclass) {
366 switch (tclass) {
367 case H5T_TIME:
368 return DataTypeClass::Time;
369 case H5T_INTEGER:
371 case H5T_FLOAT:
373 case H5T_STRING:
375 case H5T_BITFIELD:
377 case H5T_OPAQUE:
379 case H5T_COMPOUND:
381 case H5T_REFERENCE:
383 case H5T_ENUM:
384 return DataTypeClass::Enum;
385 case H5T_VLEN:
387 case H5T_ARRAY:
389 case H5T_NO_CLASS:
390 case H5T_NCLASSES:
391 default:
393 }
394}
395
396
397inline std::string type_class_string(DataTypeClass tclass) {
398 switch (tclass) {
400 return "Time";
402 return "Integer";
404 return "Float";
406 return "String";
408 return "BitField";
410 return "Opaque";
412 return "Compound";
414 return "Reference";
416 return "Enum";
418 return "Varlen";
420 return "Array";
421 default:
422 return "(Invalid)";
423 }
424}
425
426} // unnamed namespace
427
428
430template <typename T>
432 return AtomicType<T>();
433}
434
435
437template <typename T>
439 DataType t = create_datatype<T>();
440 if (t.empty()) {
441 throw DataTypeException("Type given to create_and_check_datatype is not valid");
442 }
443
444 // Skip check if the base type is a variable length string
445 if (t.isVariableStr()) {
446 return t;
447 }
448
449 // Check that the size of the template type matches the size that HDF5 is
450 // expecting.
451 if (t.isReference() || t.isFixedLenStr()) {
452 return t;
453 }
454 if (sizeof(T) != t.getSize()) {
455 std::ostringstream ss;
456 ss << "Size of array type " << sizeof(T) << " != that of memory datatype " << t.getSize()
457 << std::endl;
458 throw DataTypeException(ss.str());
459 }
460
461 return t;
462}
463
464} // namespace HighFive
465HIGHFIVE_REGISTER_TYPE(HighFive::details::Boolean, HighFive::create_enum_boolean)
466
467namespace HighFive {
468
469template <>
471 return create_datatype<HighFive::details::Boolean>();
472}
473
474} // namespace HighFive
#define HIGHFIVE_REGISTER_TYPE(type, function)
Macro to extend datatype of HighFive.
Definition H5DataType.hpp:361
AtomicType()
Definition H5DataType_misc.hpp:205
AtomicType()
Definition H5DataType_misc.hpp:212
create an HDF5 DataType from a C++ type
Definition H5DataType.hpp:189
AtomicType()
Definition H5DataType_misc.hpp:228
Create a compound HDF5 datatype.
Definition H5DataType.hpp:200
void commit(const Object &object, const std::string &name) const
Commit datatype into the given Object.
Definition H5DataType_misc.hpp:333
Exception specific to HighFive DataType interface.
Definition H5Exception.hpp:97
HDF5 Data Type.
Definition H5DataType.hpp:61
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
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:76
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:296
void commit(const Object &object, const std::string &name) const
Commit datatype into the given Object.
Definition H5DataType_misc.hpp:350
FixedLengthStringType(size_t size, StringPadding padding, CharacterSet character_set=CharacterSet::Ascii)
Create a fixed length string datatype.
Definition H5DataType_misc.hpp:88
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:130
StringPadding getPadding() const
For fixed length stings return the padding.
Definition H5DataType_misc.hpp:80
CharacterSet getCharacterSet() const
For stings return the character set.
Definition H5DataType_misc.hpp:84
VariableLengthStringType(CharacterSet character_set=CharacterSet::Ascii)
Create a variable length string HDF5 datatype.
Definition H5DataType_misc.hpp:103
Definition assert_compatible_spaces.hpp:15
EnumType< details::Boolean > create_enum_boolean()
Definition H5DataType_misc.hpp:222
DataType create_and_check_datatype()
Create a DataType instance representing type T and perform a sanity check on its size.
Definition H5DataType_misc.hpp:438
DataType create_datatype()
Create a DataType instance representing type T.
Definition H5DataType_misc.hpp:431
CharacterSet
Definition H5DataType.hpp:125
DataType create_datatype< bool >()
Definition H5DataType_misc.hpp:470
size_t find_first_atomic_member_size(hid_t hid)
Definition H5DataType_misc.hpp:242
DataTypeClass
Enum of Fundamental data classes.
Definition H5DataType.hpp:31
StringPadding
Definition string_padding.hpp:7