HighFive 2.9.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 <size_t StrLen>
210class AtomicType<deprecated::FixedLenStringArray<StrLen>>: public DataType {
211 public:
212 inline AtomicType()
213 : DataType(create_string(StrLen)) {}
214};
215
216template <typename T>
217class AtomicType<std::complex<T>>: public DataType {
218 public:
219 inline AtomicType()
220 : DataType(
221 CompoundType({{"r", create_datatype<T>(), 0}, {"i", create_datatype<T>(), sizeof(T)}},
222 sizeof(std::complex<T>))) {
223 static_assert(std::is_arithmetic<T>::value,
224 "std::complex accepts only floating point and integral numbers.");
225 }
226};
227
228// For boolean we act as h5py
230 return {{"FALSE", details::Boolean::HighFiveFalse}, {"TRUE", details::Boolean::HighFiveTrue}};
231}
232
233// Other cases not supported. Fail early with a user message
234template <typename T>
236 static_assert(details::inspector<T>::recursive_ndim == 0,
237 "Atomic types cant be arrays, except for char[] (fixed-length strings)");
238 static_assert(details::inspector<T>::recursive_ndim > 0, "Type not supported");
239}
240
241
242namespace deprecated {
243template <std::size_t N>
244inline FixedLenStringArray<N>::FixedLenStringArray(const char array[][N], std::size_t length) {
245 datavec.resize(length);
246 std::memcpy(datavec[0].data(), array[0].data(), N * length);
247}
248
249template <std::size_t N>
250inline FixedLenStringArray<N>::FixedLenStringArray(const std::string* iter_begin,
251 const std::string* iter_end) {
252 datavec.reserve(static_cast<std::size_t>(iter_end - iter_begin));
253 for (std::string const* it = iter_begin; it != iter_end; ++it) {
254 push_back(*it);
255 }
256}
257
258template <std::size_t N>
259inline FixedLenStringArray<N>::FixedLenStringArray(const std::vector<std::string>& vec)
260 : FixedLenStringArray(vec.data(), vec.data() + vec.size()) {}
261
262template <std::size_t N>
264 const std::initializer_list<std::string>& init_list)
265 : FixedLenStringArray(init_list.begin(), init_list.end()) {}
266
267template <std::size_t N>
268inline void FixedLenStringArray<N>::push_back(const std::string& src) {
269 datavec.emplace_back();
270 const size_t length = std::min(N - 1, src.length());
271 std::memcpy(datavec.back().data(), src.c_str(), length);
272 datavec.back()[length] = 0;
273}
274
275template <std::size_t N>
276inline void FixedLenStringArray<N>::push_back(const std::array<char, N>& src) {
277 datavec.emplace_back();
278 std::copy(src.begin(), src.end(), datavec.back().data());
279}
280
281template <std::size_t N>
282inline std::string FixedLenStringArray<N>::getString(std::size_t i) const {
283 return std::string(datavec[i].data());
284}
285} // namespace deprecated
286
287// Internal
288// Reference mapping
289template <>
291 _hid = detail::h5t_copy(H5T_STD_REF_OBJ);
292}
293
294inline size_t find_first_atomic_member_size(hid_t hid) {
295 // Recursive exit condition
296 if (detail::h5t_get_class(hid) == H5T_COMPOUND) {
297 auto number_of_members = detail::h5t_get_nmembers(hid);
298 if (number_of_members == -1) {
299 throw DataTypeException("Cannot get members of CompoundType with hid: " +
300 std::to_string(hid));
301 }
302 if (number_of_members == 0) {
303 throw DataTypeException("No members defined for CompoundType with hid: " +
304 std::to_string(hid));
305 }
306
307 auto member_type = detail::h5t_get_member_type(hid, 0);
308 auto size = find_first_atomic_member_size(member_type);
309 detail::h5t_close(member_type);
310 return size;
311 } else if (detail::h5t_get_class(hid) == H5T_STRING) {
312 return 1;
313 }
314 return detail::h5t_get_size(hid);
315}
316
317// Calculate the padding required to align an element of a struct
318// For padding see explanation here: https://en.cppreference.com/w/cpp/language/object#Alignment
319// It is to compute padding following last element inserted inside a struct
320// 1) We want to push back an element padded to the structure
321// 'current_size' is the size of the structure before adding the new element.
322// 'member_size' the size of the element we want to add.
323// 2) We want to compute the final padding for the global structure
324// 'current_size' is the size of the whole structure without final padding
325// 'member_size' is the maximum size of all element of the struct
326//
327// The basic formula is only to know how much we need to add to 'current_size' to fit
328// 'member_size'.
329// And at the end, we do another computation because the end padding, should fit the biggest
330// element of the struct.
331//
332// As we are with `size_t` element, we need to compute everything inside R+
333#define _H5_STRUCT_PADDING(current_size, member_size) \
334 (((member_size) >= (current_size)) \
335 ? (((member_size) - (current_size)) % (member_size)) \
336 : ((((member_size) - (((current_size) - (member_size)) % (member_size)))) % \
337 (member_size)))
338
339inline void CompoundType::create(size_t size) {
340 if (size == 0) {
341 size_t current_size = 0, max_atomic_size = 0;
342
343 // Do a first pass to find the total size of the compound datatype
344 for (auto& member: members) {
345 size_t member_size = detail::h5t_get_size(member.base_type.getId());
346
347 if (member_size == 0) {
348 throw DataTypeException("Cannot get size of DataType with hid: " +
349 std::to_string(member.base_type.getId()));
350 }
351
352 size_t first_atomic_size = find_first_atomic_member_size(member.base_type.getId());
353
354 // Set the offset of this member within the struct according to the
355 // standard alignment rules. The c++ standard specifies that:
356 // > objects have an alignment requirement of which their size is a multiple
357 member.offset = current_size + _H5_STRUCT_PADDING(current_size, first_atomic_size);
358
359 // Set the current size to the end of the new member
360 current_size = member.offset + member_size;
361
362 // Keep track of the highest atomic member size because it's needed
363 // for the padding of the complete compound type.
364 max_atomic_size = std::max(max_atomic_size, first_atomic_size);
365 }
366
367 size = current_size + _H5_STRUCT_PADDING(current_size, max_atomic_size);
368 }
369
370 // Create the HDF5 type
371 _hid = detail::h5t_create(H5T_COMPOUND, size);
372
373 // Loop over all the members and insert them into the datatype
374 for (const auto& member: members) {
375 detail::h5t_insert(_hid, member.name.c_str(), member.offset, member.base_type.getId());
376 }
377}
378
379#undef _H5_STRUCT_PADDING
380
381inline void CompoundType::commit(const Object& object, const std::string& name) const {
382 detail::h5t_commit2(
383 object.getId(), name.c_str(), getId(), H5P_DEFAULT, H5P_DEFAULT, H5P_DEFAULT);
384}
385
386template <typename T>
387inline void EnumType<T>::create() {
388 // Create the HDF5 type
389 _hid = detail::h5t_enum_create(AtomicType<typename std::underlying_type<T>::type>{}.getId());
390
391 // Loop over all the members and insert them into the datatype
392 for (const auto& member: members) {
393 detail::h5t_enum_insert(_hid, member.name.c_str(), &(member.value));
394 }
395}
396
397template <typename T>
398inline void EnumType<T>::commit(const Object& object, const std::string& name) const {
399 detail::h5t_commit2(
400 object.getId(), name.c_str(), getId(), H5P_DEFAULT, H5P_DEFAULT, H5P_DEFAULT);
401}
402
403namespace {
404
405inline hid_t create_string(size_t length) {
406 hid_t _hid = detail::h5t_copy(H5T_C_S1);
407 detail::h5t_set_size(_hid, length);
408 detail::h5t_set_cset(_hid, H5T_CSET_UTF8);
409 return _hid;
410}
411
412
413inline DataTypeClass convert_type_class(const H5T_class_t& tclass) {
414 switch (tclass) {
415 case H5T_TIME:
416 return DataTypeClass::Time;
417 case H5T_INTEGER:
419 case H5T_FLOAT:
421 case H5T_STRING:
423 case H5T_BITFIELD:
425 case H5T_OPAQUE:
427 case H5T_COMPOUND:
429 case H5T_REFERENCE:
431 case H5T_ENUM:
432 return DataTypeClass::Enum;
433 case H5T_VLEN:
435 case H5T_ARRAY:
437 case H5T_NO_CLASS:
438 case H5T_NCLASSES:
439 default:
441 }
442}
443
444
445inline std::string type_class_string(DataTypeClass tclass) {
446 switch (tclass) {
448 return "Time";
450 return "Integer";
452 return "Float";
454 return "String";
456 return "BitField";
458 return "Opaque";
460 return "Compound";
462 return "Reference";
464 return "Enum";
466 return "Varlen";
468 return "Array";
469 default:
470 return "(Invalid)";
471 }
472}
473
474} // unnamed namespace
475
476
478template <typename T>
480 return AtomicType<T>();
481}
482
483
485template <typename T>
487 DataType t = create_datatype<T>();
488 if (t.empty()) {
489 throw DataTypeException("Type given to create_and_check_datatype is not valid");
490 }
491
492 // Skip check if the base type is a variable length string
493 if (t.isVariableStr()) {
494 return t;
495 }
496
497 // Check that the size of the template type matches the size that HDF5 is
498 // expecting.
499 if (t.isReference() || t.isFixedLenStr()) {
500 return t;
501 }
502 if (sizeof(T) != t.getSize()) {
503 std::ostringstream ss;
504 ss << "Size of array type " << sizeof(T) << " != that of memory datatype " << t.getSize()
505 << std::endl;
506 throw DataTypeException(ss.str());
507 }
508
509 return t;
510}
511
512} // namespace HighFive
513HIGHFIVE_REGISTER_TYPE(HighFive::details::Boolean, HighFive::create_enum_boolean)
514
515namespace HighFive {
516
517template <>
519 return create_datatype<HighFive::details::Boolean>();
520}
521
522} // namespace HighFive
523
524#ifdef H5_USE_HALF_FLOAT
526#endif
#define HIGHFIVE_REGISTER_TYPE(type, function)
Macro to extend datatype of HighFive.
Definition H5DataType.hpp:488
#define _H5_STRUCT_PADDING(current_size, member_size)
Definition H5DataType_misc.hpp:333
AtomicType()
Definition H5DataType_misc.hpp:205
AtomicType()
Definition H5DataType_misc.hpp:219
create an HDF5 DataType from a C++ type
Definition H5DataType.hpp:187
AtomicType()
Definition H5DataType_misc.hpp:235
Create a compound HDF5 datatype.
Definition H5DataType.hpp:198
void commit(const Object &object, const std::string &name) const
Commit datatype into the given Object.
Definition H5DataType_misc.hpp:381
Exception specific to HighFive DataType interface.
Definition H5Exception.hpp:94
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:398
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:54
hid_t getId() const noexcept
getId
Definition H5Object_misc.hpp:69
bool isValid() const noexcept
isValid
Definition H5Object_misc.hpp:65
hid_t _hid
Definition H5Object.hpp:105
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
A structure representing a set of fixed-length strings.
Definition H5DataType.hpp:356
void push_back(const std::string &)
Append an std::string to the buffer structure.
Definition H5DataType_misc.hpp:268
std::string getString(std::size_t index) const
Retrieve a string from the structure as std::string.
Definition H5DataType_misc.hpp:282
Definition H5_definitions.hpp:22
EnumType< details::Boolean > create_enum_boolean()
Definition H5DataType_misc.hpp:229
DataType create_and_check_datatype()
Create a DataType instance representing type T and perform a sanity check on its size.
Definition H5DataType_misc.hpp:486
DataType create_datatype()
Create a DataType instance representing type T.
Definition H5DataType_misc.hpp:479
CharacterSet
Definition H5DataType.hpp:125
DataType create_datatype< bool >()
Definition H5DataType_misc.hpp:518
size_t find_first_atomic_member_size(hid_t hid)
Definition H5DataType_misc.hpp:294
DataTypeClass
Enum of Fundamental data classes.
Definition H5DataType.hpp:31
StringPadding
Definition string_padding.hpp:7