HighFive 2.7.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#include <H5Tpublic.h>
20
21#ifdef H5_USE_HALF_FLOAT
22#include <half.hpp>
23#endif
24
25#include "H5Converter_misc.hpp"
26
27namespace HighFive {
28
29namespace { // unnamed
30inline DataTypeClass convert_type_class(const H5T_class_t& tclass);
31inline std::string type_class_string(DataTypeClass);
32inline hid_t create_string(std::size_t length);
33} // namespace
34
35inline bool DataType::empty() const noexcept {
36 return _hid == H5I_INVALID_HID;
37}
38
40 return convert_type_class(H5Tget_class(_hid));
41}
42
43inline size_t DataType::getSize() const {
44 return H5Tget_size(_hid);
45}
46
47inline bool DataType::operator==(const DataType& other) const {
48 return (H5Tequal(_hid, other._hid) > 0);
49}
50
51inline bool DataType::operator!=(const DataType& other) const {
52 return !(*this == other);
53}
54
55inline bool DataType::isVariableStr() const {
56 auto var_value = H5Tis_variable_str(_hid);
57 if (var_value < 0) {
58 HDF5ErrMapper::ToException<DataTypeException>("Unable to define datatype size to variable");
59 }
60 return static_cast<bool>(var_value);
61}
62
63inline bool DataType::isFixedLenStr() const {
65}
66
67inline bool DataType::isReference() const {
68 return H5Tequal(_hid, H5T_STD_REF_OBJ) > 0;
69}
70
71inline std::string DataType::string() const {
72 return type_class_string(getClass()) + std::to_string(getSize() * 8);
73}
74
75// char mapping
76template <>
78 _hid = H5Tcopy(H5T_NATIVE_CHAR);
79}
80
81template <>
83 _hid = H5Tcopy(H5T_NATIVE_SCHAR);
84}
85
86template <>
88 _hid = H5Tcopy(H5T_NATIVE_UCHAR);
89}
90
91// short mapping
92template <>
94 _hid = H5Tcopy(H5T_NATIVE_SHORT);
95}
96
97template <>
99 _hid = H5Tcopy(H5T_NATIVE_USHORT);
100}
101
102// integer mapping
103template <>
105 _hid = H5Tcopy(H5T_NATIVE_INT);
106}
107
108template <>
110 _hid = H5Tcopy(H5T_NATIVE_UINT);
111}
112
113// long mapping
114template <>
116 _hid = H5Tcopy(H5T_NATIVE_LONG);
117}
118
119template <>
121 _hid = H5Tcopy(H5T_NATIVE_ULONG);
122}
123
124// long long mapping
125template <>
127 _hid = H5Tcopy(H5T_NATIVE_LLONG);
128}
129
130template <>
132 _hid = H5Tcopy(H5T_NATIVE_ULLONG);
133}
134
135// half-float, float, double and long double mapping
136#ifdef H5_USE_HALF_FLOAT
137using float16_t = half_float::half;
138
139template <>
141 _hid = H5Tcopy(H5T_NATIVE_FLOAT);
142 // Sign position, exponent position, exponent size, mantissa position, mantissa size
143 H5Tset_fields(_hid, 15, 10, 5, 0, 10);
144 // Total datatype size (in bytes)
145 H5Tset_size(_hid, 2);
146 // Floating point exponent bias
147 H5Tset_ebias(_hid, 15);
148}
149#endif
150
151template <>
153 _hid = H5Tcopy(H5T_NATIVE_FLOAT);
154}
155
156template <>
158 _hid = H5Tcopy(H5T_NATIVE_DOUBLE);
159}
160
161template <>
163 _hid = H5Tcopy(H5T_NATIVE_LDOUBLE);
164}
165
166// std string
167template <>
169 _hid = create_string(H5T_VARIABLE);
170}
171
172#if HIGHFIVE_CXX_STD >= 17
173// std byte
174template <>
176 _hid = H5Tcopy(H5T_NATIVE_B8);
177}
178#endif
179
180// Fixed-Length strings
181// require class specialization templated for the char length
182template <size_t StrLen>
183class AtomicType<char[StrLen]>: public DataType {
184 public:
185 inline AtomicType()
186 : DataType(create_string(StrLen)) {}
187};
188
189template <size_t StrLen>
191 public:
192 inline AtomicType()
193 : DataType(create_string(StrLen)) {}
194};
195
196template <typename T>
197class AtomicType<std::complex<T>>: public DataType {
198 public:
199 inline AtomicType()
200 : DataType(
201 CompoundType({{"r", create_datatype<T>(), 0}, {"i", create_datatype<T>(), sizeof(T)}},
202 sizeof(std::complex<T>))) {
203 static_assert(std::is_floating_point<T>::value,
204 "std::complex accepts only floating point numbers.");
205 }
206};
207
208// For boolean we act as h5py
210 return {{"FALSE", details::Boolean::HighFiveFalse}, {"TRUE", details::Boolean::HighFiveTrue}};
211}
212
213// Other cases not supported. Fail early with a user message
214template <typename T>
216 static_assert(details::inspector<T>::recursive_ndim == 0,
217 "Atomic types cant be arrays, except for char[] (fixed-length strings)");
218 static_assert(details::inspector<T>::recursive_ndim > 0, "Type not supported");
219}
220
221
222// class FixedLenStringArray<N>
223
224template <std::size_t N>
225inline FixedLenStringArray<N>::FixedLenStringArray(const char array[][N], std::size_t length) {
226 datavec.resize(length);
227 std::memcpy(datavec[0].data(), array[0].data(), N * length);
228}
229
230template <std::size_t N>
231inline FixedLenStringArray<N>::FixedLenStringArray(const std::string* iter_begin,
232 const std::string* iter_end) {
233 datavec.resize(static_cast<std::size_t>(iter_end - iter_begin));
234 for (auto& dst_array: datavec) {
235 const char* src = (iter_begin++)->c_str();
236 const size_t length = std::min(N - 1, std::strlen(src));
237 std::memcpy(dst_array.data(), src, length);
238 dst_array[length] = 0;
239 }
240}
241
242template <std::size_t N>
243inline FixedLenStringArray<N>::FixedLenStringArray(const std::vector<std::string>& vec)
244 : FixedLenStringArray(&vec.front(), &vec.back()) {}
245
246template <std::size_t N>
248 const std::initializer_list<std::string>& init_list)
249 : FixedLenStringArray(init_list.begin(), init_list.end()) {}
250
251template <std::size_t N>
252inline void FixedLenStringArray<N>::push_back(const std::string& src) {
253 datavec.emplace_back();
254 const size_t length = std::min(N - 1, src.length());
255 std::memcpy(datavec.back().data(), src.c_str(), length);
256 datavec.back()[length] = 0;
257}
258
259template <std::size_t N>
260inline void FixedLenStringArray<N>::push_back(const std::array<char, N>& src) {
261 datavec.emplace_back();
262 std::copy(src.begin(), src.end(), datavec.back().data());
263}
264
265template <std::size_t N>
266inline std::string FixedLenStringArray<N>::getString(std::size_t i) const {
267 return std::string(datavec[i].data());
268}
269
270// Internal
271// Reference mapping
272template <>
274 _hid = H5Tcopy(H5T_STD_REF_OBJ);
275}
276
277inline size_t find_first_atomic_member_size(hid_t hid) {
278 // Recursive exit condition
279 if (H5Tget_class(hid) == H5T_COMPOUND) {
280 auto number_of_members = H5Tget_nmembers(hid);
281 if (number_of_members == -1) {
282 throw DataTypeException("Cannot get members of CompoundType with hid: " +
283 std::to_string(hid));
284 }
285 if (number_of_members == 0) {
286 throw DataTypeException("No members defined for CompoundType with hid: " +
287 std::to_string(hid));
288 }
289
290 auto member_type = H5Tget_member_type(hid, 0);
291 auto size = find_first_atomic_member_size(member_type);
292 H5Tclose(member_type);
293 return size;
294 } else if (H5Tget_class(hid) == H5T_STRING) {
295 return 1;
296 }
297 return H5Tget_size(hid);
298}
299
300// Calculate the padding required to align an element of a struct
301// For padding see explanation here: https://en.cppreference.com/w/cpp/language/object#Alignment
302// It is to compute padding following last element inserted inside a struct
303// 1) We want to push back an element padded to the structure
304// 'current_size' is the size of the structure before adding the new element.
305// 'member_size' the size of the element we want to add.
306// 2) We want to compute the final padding for the global structure
307// 'current_size' is the size of the whole structure without final padding
308// 'member_size' is the maximum size of all element of the struct
309//
310// The basic formula is only to know how much we need to add to 'current_size' to fit
311// 'member_size'.
312// And at the end, we do another computation because the end padding, should fit the biggest
313// element of the struct.
314//
315// As we are with `size_t` element, we need to compute everything inside R+
316#define _H5_STRUCT_PADDING(current_size, member_size) \
317 (((member_size) >= (current_size)) \
318 ? (((member_size) - (current_size)) % (member_size)) \
319 : ((((member_size) - (((current_size) - (member_size)) % (member_size)))) % \
320 (member_size)))
321
322inline void CompoundType::create(size_t size) {
323 if (size == 0) {
324 size_t current_size = 0, max_atomic_size = 0;
325
326 // Do a first pass to find the total size of the compound datatype
327 for (auto& member: members) {
328 size_t member_size = H5Tget_size(member.base_type.getId());
329
330 if (member_size == 0) {
331 throw DataTypeException("Cannot get size of DataType with hid: " +
332 std::to_string(member.base_type.getId()));
333 }
334
335 size_t first_atomic_size = find_first_atomic_member_size(member.base_type.getId());
336
337 // Set the offset of this member within the struct according to the
338 // standard alignment rules. The c++ standard specifies that:
339 // > objects have an alignment requirement of which their size is a multiple
340 member.offset = current_size + _H5_STRUCT_PADDING(current_size, first_atomic_size);
341
342 // Set the current size to the end of the new member
343 current_size = member.offset + member_size;
344
345 // Keep track of the highest atomic member size because it's needed
346 // for the padding of the complete compound type.
347 max_atomic_size = std::max(max_atomic_size, first_atomic_size);
348 }
349
350 size = current_size + _H5_STRUCT_PADDING(current_size, max_atomic_size);
351 }
352
353 // Create the HDF5 type
354 if ((_hid = H5Tcreate(H5T_COMPOUND, size)) < 0) {
355 HDF5ErrMapper::ToException<DataTypeException>("Could not create new compound datatype");
356 }
357
358 // Loop over all the members and insert them into the datatype
359 for (const auto& member: members) {
360 if (H5Tinsert(_hid, member.name.c_str(), member.offset, member.base_type.getId()) < 0) {
361 HDF5ErrMapper::ToException<DataTypeException>("Could not add new member to datatype");
362 }
363 }
364}
365
366#undef _H5_STRUCT_PADDING
367
368inline void CompoundType::commit(const Object& object, const std::string& name) const {
369 H5Tcommit2(object.getId(), name.c_str(), getId(), H5P_DEFAULT, H5P_DEFAULT, H5P_DEFAULT);
370}
371
372template <typename T>
373inline void EnumType<T>::create() {
374 // Create the HDF5 type
375 if ((_hid = H5Tenum_create(AtomicType<typename std::underlying_type<T>::type>{}.getId())) < 0) {
376 HDF5ErrMapper::ToException<DataTypeException>("Could not create new enum datatype");
377 }
378
379 // Loop over all the members and insert them into the datatype
380 for (const auto& member: members) {
381 if (H5Tenum_insert(_hid, member.name.c_str(), &(member.value)) < 0) {
383 "Could not add new member to this enum datatype");
384 }
385 }
386}
387
388template <typename T>
389inline void EnumType<T>::commit(const Object& object, const std::string& name) const {
390 H5Tcommit2(object.getId(), name.c_str(), getId(), H5P_DEFAULT, H5P_DEFAULT, H5P_DEFAULT);
391}
392
393namespace {
394
395inline hid_t create_string(size_t length) {
396 hid_t _hid = H5Tcopy(H5T_C_S1);
397 if (H5Tset_size(_hid, length) < 0) {
398 HDF5ErrMapper::ToException<DataTypeException>("Unable to define datatype size to variable");
399 }
400 // define encoding to UTF-8 by default
401 H5Tset_cset(_hid, H5T_CSET_UTF8);
402 return _hid;
403}
404
405
406inline DataTypeClass convert_type_class(const H5T_class_t& tclass) {
407 switch (tclass) {
408 case H5T_TIME:
409 return DataTypeClass::Time;
410 case H5T_INTEGER:
412 case H5T_FLOAT:
414 case H5T_STRING:
416 case H5T_BITFIELD:
418 case H5T_OPAQUE:
420 case H5T_COMPOUND:
422 case H5T_REFERENCE:
424 case H5T_ENUM:
425 return DataTypeClass::Enum;
426 case H5T_VLEN:
428 case H5T_ARRAY:
430 case H5T_NO_CLASS:
431 case H5T_NCLASSES:
432 default:
434 }
435}
436
437
438inline std::string type_class_string(DataTypeClass tclass) {
439 switch (tclass) {
441 return "Time";
443 return "Integer";
445 return "Float";
447 return "String";
449 return "BitField";
451 return "Opaque";
453 return "Compound";
455 return "Reference";
457 return "Enum";
459 return "Varlen";
461 return "Array";
462 default:
463 return "(Invalid)";
464 }
465}
466
467} // unnamed namespace
468
469
471template <typename T>
473 return AtomicType<T>();
474}
475
476
478template <typename T>
480 DataType t = create_datatype<T>();
481 if (t.empty()) {
482 throw DataTypeException("Type given to create_and_check_datatype is not valid");
483 }
484
485 // Skip check if the base type is a variable length string
486 if (t.isVariableStr()) {
487 return t;
488 }
489
490 // Check that the size of the template type matches the size that HDF5 is
491 // expecting.
492 if (t.isReference() || t.isFixedLenStr()) {
493 return t;
494 }
495 if (sizeof(T) != t.getSize()) {
496 std::ostringstream ss;
497 ss << "Size of array type " << sizeof(T) << " != that of memory datatype " << t.getSize()
498 << std::endl;
499 throw DataTypeException(ss.str());
500 }
501
502 return t;
503}
504
505} // namespace HighFive
506HIGHFIVE_REGISTER_TYPE(HighFive::details::Boolean, HighFive::create_enum_boolean)
#define HIGHFIVE_REGISTER_TYPE(type, function)
Macro to extend datatype of HighFive.
Definition H5DataType.hpp:406
#define _H5_STRUCT_PADDING(current_size, member_size)
Definition H5DataType_misc.hpp:316
AtomicType()
Definition H5DataType_misc.hpp:192
AtomicType()
Definition H5DataType_misc.hpp:185
AtomicType()
Definition H5DataType_misc.hpp:199
create an HDF5 DataType from a C++ type
Definition H5DataType.hpp:117
AtomicType()
Definition H5DataType_misc.hpp:215
Create a compound HDF5 datatype.
Definition H5DataType.hpp:128
void commit(const Object &object, const std::string &name) const
Commit datatype into the given Object.
Definition H5DataType_misc.hpp:368
Exception specific to HighFive DataType interface.
Definition H5Exception.hpp:94
HDF5 Data Type.
Definition H5DataType.hpp:54
bool operator==(const DataType &other) const
Definition H5DataType_misc.hpp:47
bool isFixedLenStr() const
Returns whether the type is a fixed-length string.
Definition H5DataType_misc.hpp:63
size_t getSize() const
Returns the length (in bytes) of this type elements.
Definition H5DataType_misc.hpp:43
bool isVariableStr() const
Returns whether the type is a variable-length string.
Definition H5DataType_misc.hpp:55
bool empty() const noexcept
Check the DataType was default constructed. Such value might represent auto-detection of the datatype...
Definition H5DataType_misc.hpp:35
std::string string() const
Returns a friendly description of the type (e.g. Float32)
Definition H5DataType_misc.hpp:71
DataTypeClass getClass() const
Return the fundamental type.
Definition H5DataType_misc.hpp:39
bool isReference() const
Returns whether the type is a Reference.
Definition H5DataType_misc.hpp:67
bool operator!=(const DataType &other) const
Definition H5DataType_misc.hpp:51
Create a enum HDF5 datatype.
Definition H5DataType.hpp:228
void commit(const Object &object, const std::string &name) const
Commit datatype into the given Object.
Definition H5DataType_misc.hpp:389
A structure representing a set of fixed-length strings.
Definition H5DataType.hpp:284
std::string getString(std::size_t index) const
Retrieve a string from the structure as std::string.
Definition H5DataType_misc.hpp:266
void push_back(const std::string &)
Append an std::string to the buffer structure.
Definition H5DataType_misc.hpp:252
Definition H5Object.hpp:54
hid_t getId() const noexcept
getId
Definition H5Object_misc.hpp:65
hid_t _hid
Definition H5Object.hpp:105
Definition H5_definitions.hpp:15
half_float::half float16_t
Definition H5DataType_misc.hpp:137
EnumType< details::Boolean > create_enum_boolean()
Definition H5DataType_misc.hpp:209
DataType create_and_check_datatype()
Create a DataType instance representing type T and perform a sanity check on its size.
Definition H5DataType_misc.hpp:479
DataType create_datatype()
Create a DataType instance representing type T.
Definition H5DataType_misc.hpp:472
size_t find_first_atomic_member_size(hid_t hid)
Definition H5DataType_misc.hpp:277
DataTypeClass
Enum of Fundamental data classes.
Definition H5DataType.hpp:25
static void ToException(const std::string &prefix_msg)
Definition H5Exception_misc.hpp:42