HighFive 2.3.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#ifndef H5DATATYPE_MISC_HPP
10#define H5DATATYPE_MISC_HPP
11
12#include <string>
13#include <complex>
14#include <cstring>
15
16#include <H5Ppublic.h>
17#include <H5Tpublic.h>
18
19
20namespace HighFive {
21
22namespace { // unnamed
23inline DataTypeClass convert_type_class(const H5T_class_t& tclass);
24inline std::string type_class_string(DataTypeClass);
25inline hid_t create_string(std::size_t length);
26}
27
28inline bool DataType::empty() const noexcept {
29 return _hid == H5I_INVALID_HID;
30}
31
33 return convert_type_class(H5Tget_class(_hid));
34}
35
36inline size_t DataType::getSize() const {
37 return H5Tget_size(_hid);
38}
39
40inline bool DataType::operator==(const DataType& other) const {
41 return (H5Tequal(_hid, other._hid) > 0);
42}
43
44inline bool DataType::operator!=(const DataType& other) const {
45 return !(*this == other);
46}
47
48inline bool DataType::isVariableStr() const {
49 auto var_value = H5Tis_variable_str(_hid);
50 if (var_value < 0) {
51 HDF5ErrMapper::ToException<DataTypeException>(
52 "Unable to define datatype size to variable");
53 }
54 return static_cast<bool>(var_value);
55}
56
57inline bool DataType::isFixedLenStr() const {
59}
60
61inline bool DataType::isReference() const {
62 return H5Tequal(_hid, H5T_STD_REF_OBJ) > 0;
63}
64
65inline std::string DataType::string() const {
66 return type_class_string(getClass()) + std::to_string(getSize() * 8);
67}
68
69// char mapping
70template <>
72 _hid = H5Tcopy(H5T_NATIVE_CHAR);
73}
74
75template <>
77 _hid = H5Tcopy(H5T_NATIVE_SCHAR);
78}
79
80template <>
82 _hid = H5Tcopy(H5T_NATIVE_UCHAR);
83}
84
85// short mapping
86template <>
88 _hid = H5Tcopy(H5T_NATIVE_SHORT);
89}
90
91template <>
93 _hid = H5Tcopy(H5T_NATIVE_USHORT);
94}
95
96// integer mapping
97template <>
99 _hid = H5Tcopy(H5T_NATIVE_INT);
100}
101
102template <>
104 _hid = H5Tcopy(H5T_NATIVE_UINT);
105}
106
107// long mapping
108template <>
110 _hid = H5Tcopy(H5T_NATIVE_LONG);
111}
112
113template <>
115 _hid = H5Tcopy(H5T_NATIVE_ULONG);
116}
117
118// long long mapping
119template <>
121 _hid = H5Tcopy(H5T_NATIVE_LLONG);
122}
123
124template <>
126 _hid = H5Tcopy(H5T_NATIVE_ULLONG);
127}
128
129// float and double mapping
130template <>
132 _hid = H5Tcopy(H5T_NATIVE_FLOAT);
133}
134
135template <>
137 _hid = H5Tcopy(H5T_NATIVE_DOUBLE);
138}
139
140// boolean mapping
141template <>
143 _hid = H5Tcopy(H5T_NATIVE_HBOOL);
144}
145
146// std string
147template <>
149 _hid = create_string(H5T_VARIABLE);
150}
151
152// Fixed-Length strings
153// require class specialization templated for the char length
154template <size_t StrLen>
155class AtomicType<char[StrLen]> : public DataType {
156 public:
157 inline AtomicType() : DataType(create_string(StrLen)) {}
158};
159
160template <size_t StrLen>
161class AtomicType<FixedLenStringArray<StrLen>> : public DataType {
162 public:
163 inline AtomicType() : DataType(create_string(StrLen)) {}
164};
165
166template <>
167inline AtomicType<std::complex<double> >::AtomicType() {
168 static struct ComplexType : public Object {
169 ComplexType() {
170 _hid = H5Tcreate(H5T_COMPOUND, sizeof(std::complex<double>));
171 // h5py/numpy compatible datatype
172 H5Tinsert(_hid, "r", 0, H5T_NATIVE_DOUBLE);
173 H5Tinsert(_hid, "i", sizeof(double), H5T_NATIVE_DOUBLE);
174 };
175 } complexType;
176 _hid = H5Tcopy(complexType.getId());
177}
178
179// Other cases not supported. Fail early with a user message
180template <typename T>
182 static_assert(details::inspector<T>::recursive_ndim == 0,
183 "Atomic types cant be arrays, except for char[] (fixed-length strings)");
184 static_assert(details::inspector<T>::recursive_ndim > 0, "Type not supported");
185}
186
187
188// class FixedLenStringArray<N>
189
190template <std::size_t N>
192::FixedLenStringArray(const char array[][N], std::size_t length) {
193 datavec.resize(length);
194 std::memcpy(datavec[0].data(), array[0].data(), N * length);
195}
196
197template <std::size_t N>
199::FixedLenStringArray(const std::string* iter_begin, const std::string* iter_end) {
200 datavec.resize(static_cast<std::size_t>(iter_end - iter_begin));
201 for (auto& dst_array : datavec) {
202 const char* src = (iter_begin++)->c_str();
203 const size_t length = std::min(N - 1 , std::strlen(src));
204 std::memcpy(dst_array.data(), src, length);
205 dst_array[length] = 0;
206 }
207}
208
209template <std::size_t N>
211::FixedLenStringArray(const std::vector<std::string> & vec)
212 : FixedLenStringArray(&vec.front(), &vec.back()) {}
213
214template <std::size_t N>
216::FixedLenStringArray(const std::initializer_list<std::string>& init_list)
217 : FixedLenStringArray(init_list.begin(), init_list.end()) {}
218
219template <std::size_t N>
220inline void FixedLenStringArray<N>::push_back(const std::string& src) {
221 datavec.emplace_back();
222 const size_t length = std::min(N - 1 , src.length());
223 std::memcpy(datavec.back().data(), src.c_str(), length);
224 datavec.back()[length] = 0;
225}
226
227template <std::size_t N>
228inline void FixedLenStringArray<N>::push_back(const std::array<char, N>& src) {
229 datavec.emplace_back();
230 std::copy(src.begin(), src.end(), datavec.back().data());
231}
232
233template <std::size_t N>
234inline std::string FixedLenStringArray<N>::getString(std::size_t i) const {
235 return std::string(datavec[i].data());
236}
237
238// Internal
239// Reference mapping
240template <>
242 _hid = H5Tcopy(H5T_STD_REF_OBJ);
243}
244
245inline size_t find_first_atomic_member_size(hid_t hid)
246{
247 // Recursive exit condition
248 if (H5Tget_class(hid) != H5T_COMPOUND) {
249 return H5Tget_size(hid);
250 }
251
252 auto number_of_members = H5Tget_nmembers(hid);
253 if (number_of_members == -1) {
254 throw DataTypeException("Cannot get members of CompoundType with hid: " +
255 std::to_string(hid));
256 }
257 if (number_of_members == 0) {
258 throw DataTypeException("No members defined for CompoundType with hid: " +
259 std::to_string(hid));
260 }
261
262 auto member_type = H5Tget_member_type(hid, 0);
263 auto size = find_first_atomic_member_size(member_type);
264 H5Tclose(member_type);
265 return size;
266}
267
268// Calculate the padding required to align an element of a struct
269#define _H5_STRUCT_PADDING(current_size, member_size) (((member_size) - (current_size)) % (member_size))
270
271inline void CompoundType::create(size_t size) {
272 if (size == 0) {
273 size_t current_size = 0, max_atomic_size = 0;
274
275 // Do a first pass to find the total size of the compound datatype
276 for (auto& member: members) {
277 size_t member_size = H5Tget_size(member.base_type.getId());
278
279 if (member_size == 0) {
280 throw DataTypeException("Cannot get size of DataType with hid: " +
281 std::to_string(member.base_type.getId()));
282 }
283
284 size_t first_atomic_size = find_first_atomic_member_size(member.base_type.getId());
285
286 // Set the offset of this member within the struct according to the
287 // standard alignment rules. The c++ standard specifies that:
288 // > objects have an alignment requirement of which their size is a multiple
289 member.offset = current_size + _H5_STRUCT_PADDING(current_size, first_atomic_size);
290
291 // Set the current size to the end of the new member
292 current_size = member.offset + member_size;
293
294 // Keep track of the highest atomic member size because it's needed
295 // for the padding of the complete compound type.
296 max_atomic_size = std::max(max_atomic_size, first_atomic_size);
297 }
298
299 size = current_size + _H5_STRUCT_PADDING(current_size, max_atomic_size);
300 }
301
302 // Create the HDF5 type
303 if((_hid = H5Tcreate(H5T_COMPOUND, size)) < 0) {
304 HDF5ErrMapper::ToException<DataTypeException>(
305 "Could not create new compound datatype");
306 }
307
308 // Loop over all the members and insert them into the datatype
309 for (const auto& member: members) {
310 if(H5Tinsert(_hid, member.name.c_str(), member.offset, member.base_type.getId()) < 0) {
311 HDF5ErrMapper::ToException<DataTypeException>(
312 "Could not add new member to datatype"
313 );
314 }
315 }
316}
317
318#undef _H5_STRUCT_PADDING
319
320inline void CompoundType::commit(const Object& object, const std::string& name) const {
321 H5Tcommit2(object.getId(), name.c_str(), getId(), H5P_DEFAULT, H5P_DEFAULT, H5P_DEFAULT);
322}
323
324template<typename T>
325inline void EnumType<T>::create() {
326 // Create the HDF5 type
327 if((_hid = H5Tenum_create(AtomicType<typename std::underlying_type<T>::type>{}.getId())) < 0) {
328 HDF5ErrMapper::ToException<DataTypeException>(
329 "Could not create new enum datatype");
330 }
331
332 // Loop over all the members and insert them into the datatype
333 for (const auto& member: members) {
334 if(H5Tenum_insert(_hid, member.name.c_str(), &(member.value)) < 0) {
335 HDF5ErrMapper::ToException<DataTypeException>(
336 "Could not add new member to this enum datatype"
337 );
338 }
339 }
340}
341
342template<typename T>
343inline void EnumType<T>::commit(const Object& object, const std::string& name) const {
344 H5Tcommit2(object.getId(), name.c_str(), getId(), H5P_DEFAULT, H5P_DEFAULT, H5P_DEFAULT);
345}
346
347namespace {
348
349inline hid_t create_string(size_t length){
350 hid_t _hid = H5Tcopy(H5T_C_S1);
351 if (H5Tset_size(_hid, length) < 0) {
352 HDF5ErrMapper::ToException<DataTypeException>(
353 "Unable to define datatype size to variable");
354 }
355 // define encoding to UTF-8 by default
356 H5Tset_cset(_hid, H5T_CSET_UTF8);
357 return _hid;
358}
359
360
361inline DataTypeClass convert_type_class(const H5T_class_t& tclass) {
362 switch(tclass) {
363 case H5T_TIME:
364 return DataTypeClass::Time;
365 case H5T_INTEGER:
367 case H5T_FLOAT:
369 case H5T_STRING:
371 case H5T_BITFIELD:
373 case H5T_OPAQUE:
375 case H5T_COMPOUND:
377 case H5T_REFERENCE:
379 case H5T_ENUM:
380 return DataTypeClass::Enum;
381 case H5T_VLEN:
383 case H5T_ARRAY:
385 case H5T_NO_CLASS:
386 case H5T_NCLASSES:
387 default:
389 }
390}
391
392
393inline std::string type_class_string(DataTypeClass tclass) {
394 switch(tclass) {
396 return "Time";
398 return "Integer";
400 return "Float";
402 return "String";
404 return "BitField";
406 return "Opaque";
408 return "Compound";
410 return "Reference";
412 return "Enum";
414 return "Varlen";
416 return "Array";
417 default:
418 return "(Invalid)";
419 }
420}
421
422} // unnamed namespace
423
424
426template <typename T>
428 return AtomicType<T>();
429}
430
431
433template <typename T>
435
436 DataType t = create_datatype<T>();
437 if (t.empty()) {
438 throw DataTypeException("Type given to create_and_check_datatype is not valid");
439 }
440
441 // Skip check if the base type is a variable length string
442 if (t.isVariableStr()) {
443 return t;
444 }
445
446 // Check that the size of the template type matches the size that HDF5 is
447 // expecting.
448 if (t.isReference() || t.isFixedLenStr()) {
449 return t;
450 }
451 if (sizeof(T) != t.getSize()) {
452 std::ostringstream ss;
453 ss << "Size of array type " << sizeof(T)
454 << " != that of memory datatype " << t.getSize()
455 << std::endl;
456 throw DataTypeException(ss.str());
457 }
458
459 return t;
460}
461
462} // namespace HighFive
463
464
465#endif // H5DATATYPE_MISC_HPP
#define _H5_STRUCT_PADDING(current_size, member_size)
Definition: H5DataType_misc.hpp:269
AtomicType()
Definition: H5DataType_misc.hpp:163
AtomicType()
Definition: H5DataType_misc.hpp:157
create an HDF5 DataType from a C++ type
Definition: H5DataType.hpp:100
AtomicType()
Definition: H5DataType_misc.hpp:181
void commit(const Object &object, const std::string &name) const
Commit datatype into the given Object.
Definition: H5DataType_misc.hpp:320
Exception specific to HighFive DataType interface.
Definition: H5Exception.hpp:83
HDF5 Data Type.
Definition: H5DataType.hpp:42
bool operator==(const DataType &other) const
Definition: H5DataType_misc.hpp:40
bool isFixedLenStr() const
Returns whether the type is a fixed-length string.
Definition: H5DataType_misc.hpp:57
size_t getSize() const
Returns the length (in bytes) of this type elements.
Definition: H5DataType_misc.hpp:36
bool isVariableStr() const
Returns whether the type is a variable-length string.
Definition: H5DataType_misc.hpp:48
bool empty() const noexcept
Check the DataType was default constructed. Such value might represent auto-detection of the datatype...
Definition: H5DataType_misc.hpp:28
std::string string() const
Returns a friendly description of the type (e.g. Float32)
Definition: H5DataType_misc.hpp:65
DataTypeClass getClass() const
Return the fundamental type.
Definition: H5DataType_misc.hpp:32
bool isReference() const
Returns whether the type is a Reference.
Definition: H5DataType_misc.hpp:61
bool operator!=(const DataType &other) const
Definition: H5DataType_misc.hpp:44
Create a enum HDF5 datatype.
Definition: H5DataType.hpp:188
void commit(const Object &object, const std::string &name) const
Commit datatype into the given Object.
Definition: H5DataType_misc.hpp:343
A structure representing a set of fixed-length strings.
Definition: H5DataType.hpp:239
void resize(std::size_t n)
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:234
void push_back(const std::string &)
Append an std::string to the buffer structure.
Definition: H5DataType_misc.hpp:220
Definition: H5Object.hpp:36
hid_t getId() const noexcept
getId
Definition: H5Object_misc.hpp:55
hid_t _hid
Definition: H5Object.hpp:87
Definition: H5_definitions.hpp:15
DataType create_and_check_datatype()
Create a DataType instance representing type T and perform a sanity check on its size.
Definition: H5DataType_misc.hpp:434
DataType create_datatype()
Create a DataType instance representing type T.
Definition: H5DataType_misc.hpp:427
size_t find_first_atomic_member_size(hid_t hid)
Definition: H5DataType_misc.hpp:245
DataTypeClass
Enum of Fundamental data classes.
Definition: H5DataType.hpp:23