-
Notifications
You must be signed in to change notification settings - Fork 18
Expand file tree
/
Copy pathH5DataType.hpp
More file actions
394 lines (334 loc) · 11.1 KB
/
H5DataType.hpp
File metadata and controls
394 lines (334 loc) · 11.1 KB
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
180
181
182
183
184
185
186
187
188
189
190
191
192
193
194
195
196
197
198
199
200
201
202
203
204
205
206
207
208
209
210
211
212
213
214
215
216
217
218
219
220
221
222
223
224
225
226
227
228
229
230
231
232
233
234
235
236
237
238
239
240
241
242
243
244
245
246
247
248
249
250
251
252
253
254
255
256
257
258
259
260
261
262
263
264
265
266
267
268
269
270
271
272
273
274
275
276
277
278
279
280
281
282
283
284
285
286
287
288
289
290
291
292
293
294
295
296
297
298
299
300
301
302
303
304
305
306
307
308
309
310
311
312
313
314
315
316
317
318
319
320
321
322
323
324
325
326
327
328
329
330
331
332
333
334
335
336
337
338
339
340
341
342
343
344
345
346
347
348
349
350
351
352
353
354
355
356
357
358
359
360
361
362
363
364
365
366
367
368
369
370
371
372
373
374
375
376
377
378
379
380
381
382
383
384
385
386
387
388
389
390
391
392
393
394
/*
* Copyright (c), 2017, Adrien Devresse <adrien.devresse@epfl.ch>
*
* Distributed under the Boost Software License, Version 1.0.
* (See accompanying file LICENSE_1_0.txt or copy at
* http://www.boost.org/LICENSE_1_0.txt)
*
*/
#pragma once
#include <type_traits>
#include <vector>
#include <H5Tpublic.h>
#include "H5Object.hpp"
#include "bits/H5Utils.hpp"
#include "bits/string_padding.hpp"
#include "H5PropertyList.hpp"
#include "bits/h5_wrapper.hpp"
#include "bits/h5t_wrapper.hpp"
namespace HighFive {
///
/// \brief Enum of Fundamental data classes
///
enum class DataTypeClass {
Time = 1 << 1,
Integer = 1 << 2,
Float = 1 << 3,
String = 1 << 4,
BitField = 1 << 5,
Opaque = 1 << 6,
Compound = 1 << 7,
Reference = 1 << 8,
Enum = 1 << 9,
VarLen = 1 << 10,
Array = 1 << 11,
Invalid = 0
};
inline DataTypeClass operator|(DataTypeClass lhs, DataTypeClass rhs) {
using T = std::underlying_type<DataTypeClass>::type;
return static_cast<DataTypeClass>(static_cast<T>(lhs) | static_cast<T>(rhs));
}
inline DataTypeClass operator&(DataTypeClass lhs, DataTypeClass rhs) {
using T = std::underlying_type<DataTypeClass>::type;
return static_cast<DataTypeClass>(static_cast<T>(lhs) & static_cast<T>(rhs));
}
class StringType;
class IntegerType;
///
/// \brief HDF5 Data Type
///
class DataType: public Object {
public:
explicit DataType(hid_t hid) noexcept :
Object(hid)
{
}
bool operator==(const DataType& other) const;
bool operator!=(const DataType& other) const;
///
/// \brief Return the fundamental type.
///
DataTypeClass getClass() const;
///
/// \brief Returns the length (in bytes) of this type elements
///
/// Notice that the size of variable length sequences may have limited applicability
/// given that it refers to the size of the control structure. For info see
/// https://support.hdfgroup.org/HDF5/doc/RM/RM_H5T.html#Datatype-GetSize
size_t getSize() const;
///
/// \brief Returns a friendly description of the type (e.g. Float32)
///
std::string string() const;
///
/// \brief Returns whether the type is a variable-length string
///
bool isVariableStr() const;
///
/// \brief Returns whether the type is a fixed-length string
///
bool isFixedLenStr() const;
///
/// \brief Returns this datatype as a `StringType`.
///
StringType asStringType() const;
///
/// \brief Returns this datatype as a `IntegerType`.
///
IntegerType asIntegerType() const;
///
/// \brief Check the DataType was default constructed.
///
bool empty() const noexcept;
/// \brief Returns whether the type is a Reference
bool isReference() const;
/// \brief Get the list of properties for creation of this DataType
DataTypeCreateProps getCreatePropertyList() const {
return details::get_plist<DataTypeCreateProps>(*this, H5Tget_create_plist);
}
protected:
using Object::Object;
friend class Attribute;
friend class File;
friend class DataSet;
friend class CompoundType;
template <typename Derivate>
friend class NodeTraits;
};
enum class CharacterSet : std::underlying_type<H5T_cset_t>::type {
Ascii = H5T_CSET_ASCII,
Utf8 = H5T_CSET_UTF8,
};
class StringType: public DataType {
public:
///
/// \brief For stings return the character set.
///
CharacterSet getCharacterSet() const;
///
/// \brief For fixed length stings return the padding.
///
StringPadding getPadding() const;
protected:
using DataType::DataType;
friend class DataType;
};
class FixedLengthStringType: public StringType {
public:
///
/// \brief Create a fixed length string datatype.
///
/// The string will be `size` bytes long, regardless whether it's ASCII or
/// UTF8. In particular, a string with `n` UFT8 characters in general
/// requires `4*n` bytes.
///
/// The string padding is subtle, essentially it's just a hint. While
/// commonly, a null-terminated string is guaranteed to have one `'\0'`
/// which marks the semantic end of the string, this is not enforced by
/// HDF5. In fact, there are HDF5 files that contain strings that claim to
/// be null-terminated but aren't. The length of the buffer must be at
/// least `size` bytes regardless of the padding. HDF5 will read or write
/// `size` bytes, irrespective of when (if at all) the `\0` occurs.
///
/// Note that when writing, passing `StringPadding::NullTerminated` is a
/// guarantee to the reader that it contains a `\0`. Therefore, make sure
/// that the string really is null-terminated. Otherwise prefer a
/// null-padded string. This mearly states that the buffer is filled up
/// with 0 or more `\0`.
FixedLengthStringType(size_t size,
StringPadding padding,
CharacterSet character_set = CharacterSet::Ascii);
};
class VariableLengthStringType: public StringType {
public:
///
/// \brief Create a variable length string HDF5 datatype.
///
explicit VariableLengthStringType(CharacterSet character_set = CharacterSet::Ascii);
};
///
/// \brief An Integer datatype (i.e. H5T_INTEGER).
///
/// Provides access to the API that's only valid for integers. Use
/// DataType::asIntegerType to convert from a generic DataType.
///
class IntegerType: public DataType {
public:
bool isSigned() {
return detail::h5t_get_sign(getId()) != H5T_SGN_NONE;
}
protected:
using DataType::DataType;
friend class DataType;
};
///
/// \brief create an HDF5 DataType from a C++ type
///
/// Support only basic data type
///
template <typename T>
class AtomicType: public DataType {
public:
AtomicType();
using basic_type = T;
};
///
/// \brief Create a compound HDF5 datatype
///
class CompoundType: public DataType {
public:
///
/// \brief Use for defining a sub-type of compound type
struct member_def {
member_def(std::string t_name, DataType t_base_type, size_t t_offset = 0)
: name(std::move(t_name))
, base_type(std::move(t_base_type))
, offset(t_offset) {}
std::string name;
DataType base_type;
size_t offset;
};
///
/// \brief Initializes a compound type from a vector of member definitions
/// \param t_members
/// \param size
inline CompoundType(const std::vector<member_def>& t_members, size_t size = 0)
: members(t_members) {
create(size);
}
inline CompoundType(std::vector<member_def>&& t_members, size_t size = 0)
: members(std::move(t_members)) {
create(size);
}
inline CompoundType(const std::initializer_list<member_def>& t_members, size_t size = 0)
: members(t_members) {
create(size);
}
///
/// \brief Initializes a compound type from a DataType
/// \param type
inline explicit CompoundType(DataType&& type)
: DataType(type) {
if (getClass() != DataTypeClass::Compound) {
std::ostringstream ss;
ss << "hid " << _hid << " does not refer to a compound data type";
throw DataTypeException(ss.str());
}
size_t n_members = static_cast<size_t>(detail::h5t_get_nmembers(_hid));
members.reserve(n_members);
for (unsigned i = 0; i < n_members; i++) {
char* name = detail::h5t_get_member_name(_hid, i);
size_t offset = detail::h5t_get_member_offset(_hid, i);
hid_t member_hid = detail::h5t_get_member_type(_hid, i);
DataType member_type{member_hid};
members.emplace_back(std::string(name), member_type, offset);
detail::h5_free_memory(name);
}
}
/// \brief Commit datatype into the given Object
/// \param object Location to commit object into
/// \param name Name to give the datatype
inline void commit(const Object& object, const std::string& name) const;
/// \brief Get read access to the CompoundType members
inline const std::vector<member_def>& getMembers() const noexcept {
return members;
}
private:
/// A vector of the member_def members of this CompoundType
std::vector<member_def> members;
/// \brief Automatically create the type from the set of members
/// using standard struct alignment.
/// \param size Total size of data type
void create(size_t size = 0);
};
///
/// \brief Create a enum HDF5 datatype
///
/// \code{.cpp}
/// enum class Position {
/// FIRST = 1,
/// SECOND = 2,
/// };
///
/// EnumType<Position> create_enum_position() {
/// return {{"FIRST", Position::FIRST},
/// {"SECOND", Position::SECOND}};
/// }
///
/// // You have to register the type inside HighFive
/// HIGHFIVE_REGISTER_TYPE(Position, create_enum_position)
///
/// void write_first(H5::File& file) {
/// auto dataset = file.createDataSet("/foo", Position::FIRST);
/// }
/// \endcode
template <typename T>
class EnumType: public DataType {
public:
///
/// \brief Use for defining a member of enum type
struct member_def {
member_def(const std::string& t_name, T t_value)
: name(t_name)
, value(std::move(t_value)) {}
std::string name;
T value;
};
EnumType(const EnumType& other) = default;
EnumType(const std::vector<member_def>& t_members)
: members(t_members) {
static_assert(std::is_enum<T>::value, "EnumType<T>::create takes only enum");
if (members.empty()) {
HDF5ErrMapper::ToException<DataTypeException>(
"Could not create an enum without members");
}
create();
}
EnumType(std::initializer_list<member_def> t_members)
: EnumType(std::vector<member_def>(t_members)) {}
/// \brief Commit datatype into the given Object
/// \param object Location to commit object into
/// \param name Name to give the datatype
void commit(const Object& object, const std::string& name) const;
private:
std::vector<member_def> members;
void create();
};
/// \brief Create a DataType instance representing type T
template <typename T>
DataType create_datatype();
/// \brief Create a DataType instance representing type T and perform a sanity check on its size
template <typename T>
DataType create_and_check_datatype();
} // namespace HighFive
/// \brief Macro to extend datatype of HighFive
///
/// This macro has to be called outside of any namespace.
///
/// \code{.cpp}
/// namespace app {
/// enum FooBar { FOO = 1, BAR = 2 };
/// EnumType create_enum_foobar() {
/// return EnumType<FooBar>({{"FOO", FooBar::FOO},
/// {"BAR", FooBar::BAR}});
/// }
/// }
///
/// HIGHFIVE_REGISTER_TYPE(FooBar, ::app::create_enum_foobar)
/// \endcode
#define HIGHFIVE_REGISTER_TYPE(type, function) \
template <> \
inline HighFive::DataType HighFive::create_datatype<type>() { \
return function(); \
}
#include "bits/H5DataType_misc.hpp"