Back to home page

EIC code displayed by LXR

 
 

    


File indexing completed on 2026-09-23 09:14:20

0001 /*
0002  *  Copyright (c), 2017, Adrien Devresse <adrien.devresse@epfl.ch>
0003  *
0004  *  Distributed under the Boost Software License, Version 1.0.
0005  *    (See accompanying file LICENSE_1_0.txt or copy at
0006  *          http://www.boost.org/LICENSE_1_0.txt)
0007  *
0008  */
0009 #pragma once
0010 
0011 #include <string>
0012 #include <complex>
0013 #include <cstring>
0014 #if HIGHFIVE_CXX_STD >= 17
0015 #include <cstddef>
0016 #endif
0017 
0018 #include <H5Ppublic.h>
0019 
0020 #include "H5Inspector_misc.hpp"
0021 #include "h5t_wrapper.hpp"
0022 #include "h5i_wrapper.hpp"
0023 
0024 namespace HighFive {
0025 
0026 namespace {  // unnamed
0027 inline DataTypeClass convert_type_class(const H5T_class_t& tclass);
0028 inline std::string type_class_string(DataTypeClass);
0029 inline hid_t create_string(std::size_t length);
0030 }  // namespace
0031 
0032 inline bool DataType::empty() const noexcept {
0033     return _hid == H5I_INVALID_HID;
0034 }
0035 
0036 inline DataTypeClass DataType::getClass() const {
0037     return convert_type_class(detail::h5t_get_class(_hid));
0038 }
0039 
0040 inline size_t DataType::getSize() const {
0041     return detail::h5t_get_size(_hid);
0042 }
0043 
0044 inline bool DataType::operator==(const DataType& other) const {
0045     return detail::h5t_equal(_hid, other._hid) > 0;
0046 }
0047 
0048 inline bool DataType::operator!=(const DataType& other) const {
0049     return !(*this == other);
0050 }
0051 
0052 inline bool DataType::isVariableStr() const {
0053     return detail::h5t_is_variable_str(_hid) > 0;
0054 }
0055 
0056 inline bool DataType::isFixedLenStr() const {
0057     return getClass() == DataTypeClass::String && !isVariableStr();
0058 }
0059 
0060 inline bool DataType::isReference() const {
0061     return detail::h5t_equal(_hid, H5T_STD_REF_OBJ) > 0;
0062 }
0063 
0064 inline StringType DataType::asStringType() const {
0065     if (getClass() != DataTypeClass::String) {
0066         throw DataTypeException("Invalid conversion to StringType.");
0067     }
0068 
0069     if (isValid()) {
0070         detail::h5i_inc_ref(_hid);
0071     }
0072 
0073     return StringType(_hid);
0074 }
0075 
0076 inline IntegerType DataType::asIntegerType() const {
0077     if (getClass() != DataTypeClass::Integer) {
0078         throw DataTypeException("Invalid conversion to IntegerType.");
0079     }
0080 
0081     if (isValid()) {
0082         detail::h5i_inc_ref(_hid);
0083     }
0084 
0085     return IntegerType(_hid);
0086 }
0087 
0088 inline std::string DataType::string() const {
0089     return type_class_string(getClass()) + std::to_string(getSize() * 8);
0090 }
0091 
0092 inline StringPadding StringType::getPadding() const {
0093     return StringPadding(detail::h5t_get_strpad(_hid));
0094 }
0095 
0096 inline CharacterSet StringType::getCharacterSet() const {
0097     return CharacterSet(detail::h5t_get_cset(_hid));
0098 }
0099 
0100 inline FixedLengthStringType::FixedLengthStringType(size_t size,
0101                                                     StringPadding padding,
0102                                                     CharacterSet character_set) {
0103     if (size == 0 && padding == StringPadding::NullTerminated) {
0104         throw DataTypeException(
0105             "Fixed-length, null-terminated need at least one byte to store the null-character.");
0106     }
0107 
0108     _hid = detail::h5t_copy(H5T_C_S1);
0109 
0110     detail::h5t_set_size(_hid, hsize_t(size));
0111     detail::h5t_set_cset(_hid, H5T_cset_t(character_set));
0112     detail::h5t_set_strpad(_hid, H5T_str_t(padding));
0113 }
0114 
0115 inline VariableLengthStringType::VariableLengthStringType(CharacterSet character_set) {
0116     _hid = detail::h5t_copy(H5T_C_S1);
0117 
0118     detail::h5t_set_size(_hid, H5T_VARIABLE);
0119     detail::h5t_set_cset(_hid, H5T_cset_t(character_set));
0120 }
0121 
0122 // char mapping
0123 template <>
0124 inline AtomicType<char>::AtomicType() {
0125     _hid = detail::h5t_copy(H5T_NATIVE_CHAR);
0126 }
0127 
0128 template <>
0129 inline AtomicType<signed char>::AtomicType() {
0130     _hid = detail::h5t_copy(H5T_NATIVE_SCHAR);
0131 }
0132 
0133 template <>
0134 inline AtomicType<unsigned char>::AtomicType() {
0135     _hid = detail::h5t_copy(H5T_NATIVE_UCHAR);
0136 }
0137 
0138 // short mapping
0139 template <>
0140 inline AtomicType<short>::AtomicType() {
0141     _hid = detail::h5t_copy(H5T_NATIVE_SHORT);
0142 }
0143 
0144 template <>
0145 inline AtomicType<unsigned short>::AtomicType() {
0146     _hid = detail::h5t_copy(H5T_NATIVE_USHORT);
0147 }
0148 
0149 // integer mapping
0150 template <>
0151 inline AtomicType<int>::AtomicType() {
0152     _hid = detail::h5t_copy(H5T_NATIVE_INT);
0153 }
0154 
0155 template <>
0156 inline AtomicType<unsigned>::AtomicType() {
0157     _hid = detail::h5t_copy(H5T_NATIVE_UINT);
0158 }
0159 
0160 // long mapping
0161 template <>
0162 inline AtomicType<long>::AtomicType() {
0163     _hid = detail::h5t_copy(H5T_NATIVE_LONG);
0164 }
0165 
0166 template <>
0167 inline AtomicType<unsigned long>::AtomicType() {
0168     _hid = detail::h5t_copy(H5T_NATIVE_ULONG);
0169 }
0170 
0171 // long long mapping
0172 template <>
0173 inline AtomicType<long long>::AtomicType() {
0174     _hid = detail::h5t_copy(H5T_NATIVE_LLONG);
0175 }
0176 
0177 template <>
0178 inline AtomicType<unsigned long long>::AtomicType() {
0179     _hid = detail::h5t_copy(H5T_NATIVE_ULLONG);
0180 }
0181 
0182 // half-float, float, double and long double mapping
0183 template <>
0184 inline AtomicType<float>::AtomicType() {
0185     _hid = detail::h5t_copy(H5T_NATIVE_FLOAT);
0186 }
0187 
0188 template <>
0189 inline AtomicType<double>::AtomicType() {
0190     _hid = detail::h5t_copy(H5T_NATIVE_DOUBLE);
0191 }
0192 
0193 template <>
0194 inline AtomicType<long double>::AtomicType() {
0195     _hid = detail::h5t_copy(H5T_NATIVE_LDOUBLE);
0196 }
0197 
0198 // std string
0199 template <>
0200 inline AtomicType<std::string>::AtomicType() {
0201     _hid = create_string(H5T_VARIABLE);
0202 }
0203 
0204 #if HIGHFIVE_CXX_STD >= 17
0205 // std byte
0206 template <>
0207 inline AtomicType<std::byte>::AtomicType() {
0208     _hid = detail::h5t_copy(H5T_NATIVE_B8);
0209 }
0210 #endif
0211 
0212 // Fixed-Length strings
0213 // require class specialization templated for the char length
0214 template <size_t StrLen>
0215 class AtomicType<char[StrLen]>: public DataType {
0216   public:
0217     inline AtomicType()
0218         : DataType(create_string(StrLen)) {}
0219 };
0220 
0221 template <typename T>
0222 class AtomicType<std::complex<T>>: public DataType {
0223   public:
0224     inline AtomicType()
0225         : DataType(
0226               CompoundType({{"r", create_datatype<T>(), 0}, {"i", create_datatype<T>(), sizeof(T)}},
0227                            sizeof(std::complex<T>))) {
0228         static_assert(std::is_arithmetic<T>::value,
0229                       "std::complex accepts only floating point and integral numbers.");
0230     }
0231 };
0232 
0233 // For boolean we act as h5py
0234 inline EnumType<details::Boolean> create_enum_boolean() {
0235     return {{"FALSE", details::Boolean::HighFiveFalse}, {"TRUE", details::Boolean::HighFiveTrue}};
0236 }
0237 
0238 
0239 namespace detail {
0240 template <class T>
0241 struct FalseType {
0242     static constexpr const bool value = false;
0243 };
0244 }  // namespace detail
0245 
0246 // Other cases not supported. Fail early with a user message
0247 template <typename T>
0248 AtomicType<T>::AtomicType() {
0249     // Certain compilers reject a plain `false`.
0250     static_assert(
0251         ::HighFive::detail::FalseType<T>::value,
0252         "Missing specialization of AtomicType<T>. Therefore, type T is not supported by HighFive.");
0253 }
0254 
0255 
0256 // Internal
0257 // Reference mapping
0258 template <>
0259 inline AtomicType<Reference>::AtomicType() {
0260     _hid = detail::h5t_copy(H5T_STD_REF_OBJ);
0261 }
0262 
0263 inline size_t find_first_atomic_member_size(hid_t hid) {
0264     // Recursive exit condition
0265     if (detail::h5t_get_class(hid) == H5T_COMPOUND) {
0266         auto number_of_members = detail::h5t_get_nmembers(hid);
0267         if (number_of_members == -1) {
0268             throw DataTypeException("Cannot get members of CompoundType with hid: " +
0269                                     std::to_string(hid));
0270         }
0271         if (number_of_members == 0) {
0272             throw DataTypeException("No members defined for CompoundType with hid: " +
0273                                     std::to_string(hid));
0274         }
0275 
0276         auto member_type = detail::h5t_get_member_type(hid, 0);
0277         auto size = find_first_atomic_member_size(member_type);
0278         detail::h5t_close(member_type);
0279         return size;
0280     } else if (detail::h5t_get_class(hid) == H5T_STRING) {
0281         return 1;
0282     }
0283     return detail::h5t_get_size(hid);
0284 }
0285 
0286 namespace detail {
0287 // Calculate the padding required to align an element of a struct
0288 // For padding see explanation here: https://en.cppreference.com/w/cpp/language/object#Alignment
0289 // It is to compute padding following last element inserted inside a struct
0290 // 1) We want to push back an element padded to the structure
0291 // 'current_size' is the size of the structure before adding the new element.
0292 // 'member_size' the size of the element we want to add.
0293 // 2) We want to compute the final padding for the global structure
0294 // 'current_size' is the size of the whole structure without final padding
0295 // 'member_size' is the maximum size of all element of the struct
0296 //
0297 // The basic formula is only to know how much we need to add to 'current_size' to fit
0298 // 'member_size'.
0299 // And at the end, we do another computation because the end padding, should fit the biggest
0300 // element of the struct.
0301 //
0302 // As we are with `size_t` element, we need to compute everything inside R+
0303 inline size_t struct_padding(size_t current_size, size_t member_size) {
0304     if (member_size == 0) {
0305         throw DataTypeException("Unexpected `member_size == 0`.");
0306     }
0307 
0308     return member_size >= current_size
0309                ? (member_size - current_size) % member_size
0310                : ((member_size - ((current_size - member_size) % member_size))) % member_size;
0311 }
0312 }  // namespace detail
0313 
0314 inline void CompoundType::create(size_t size) {
0315     if (size == 0) {
0316         size_t current_size = 0, max_atomic_size = 0;
0317 
0318         // Do a first pass to find the total size of the compound datatype
0319         for (auto& member: members) {
0320             size_t member_size = detail::h5t_get_size(member.base_type.getId());
0321 
0322             if (member_size == 0) {
0323                 throw DataTypeException("Cannot get size of DataType with hid: " +
0324                                         std::to_string(member.base_type.getId()));
0325             }
0326 
0327             size_t first_atomic_size = find_first_atomic_member_size(member.base_type.getId());
0328 
0329             // Set the offset of this member within the struct according to the
0330             // standard alignment rules. The c++ standard specifies that:
0331             // > objects have an alignment requirement of which their size is a multiple
0332             member.offset = current_size + detail::struct_padding(current_size, first_atomic_size);
0333 
0334             // Set the current size to the end of the new member
0335             current_size = member.offset + member_size;
0336 
0337             // Keep track of the highest atomic member size because it's needed
0338             // for the padding of the complete compound type.
0339             max_atomic_size = std::max(max_atomic_size, first_atomic_size);
0340         }
0341 
0342         size = current_size + detail::struct_padding(current_size, max_atomic_size);
0343     }
0344 
0345     // Create the HDF5 type
0346     _hid = detail::h5t_create(H5T_COMPOUND, size);
0347 
0348     // Loop over all the members and insert them into the datatype
0349     for (const auto& member: members) {
0350         detail::h5t_insert(_hid, member.name.c_str(), member.offset, member.base_type.getId());
0351     }
0352 }
0353 
0354 inline void CompoundType::commit(const Object& object, const std::string& name) const {
0355     detail::h5t_commit2(
0356         object.getId(), name.c_str(), getId(), H5P_DEFAULT, H5P_DEFAULT, H5P_DEFAULT);
0357 }
0358 
0359 template <typename T>
0360 inline void EnumType<T>::create() {
0361     // Create the HDF5 type
0362     _hid = detail::h5t_enum_create(AtomicType<typename std::underlying_type<T>::type>{}.getId());
0363 
0364     // Loop over all the members and insert them into the datatype
0365     for (const auto& member: members) {
0366         detail::h5t_enum_insert(_hid, member.name.c_str(), &(member.value));
0367     }
0368 }
0369 
0370 template <typename T>
0371 inline void EnumType<T>::commit(const Object& object, const std::string& name) const {
0372     detail::h5t_commit2(
0373         object.getId(), name.c_str(), getId(), H5P_DEFAULT, H5P_DEFAULT, H5P_DEFAULT);
0374 }
0375 
0376 namespace {
0377 
0378 inline hid_t create_string(size_t length) {
0379     hid_t _hid = detail::h5t_copy(H5T_C_S1);
0380     detail::h5t_set_size(_hid, length);
0381     detail::h5t_set_cset(_hid, H5T_CSET_UTF8);
0382     return _hid;
0383 }
0384 
0385 
0386 inline DataTypeClass convert_type_class(const H5T_class_t& tclass) {
0387     switch (tclass) {
0388     case H5T_TIME:
0389         return DataTypeClass::Time;
0390     case H5T_INTEGER:
0391         return DataTypeClass::Integer;
0392     case H5T_FLOAT:
0393         return DataTypeClass::Float;
0394     case H5T_STRING:
0395         return DataTypeClass::String;
0396     case H5T_BITFIELD:
0397         return DataTypeClass::BitField;
0398     case H5T_OPAQUE:
0399         return DataTypeClass::Opaque;
0400     case H5T_COMPOUND:
0401         return DataTypeClass::Compound;
0402     case H5T_REFERENCE:
0403         return DataTypeClass::Reference;
0404     case H5T_ENUM:
0405         return DataTypeClass::Enum;
0406     case H5T_VLEN:
0407         return DataTypeClass::VarLen;
0408     case H5T_ARRAY:
0409         return DataTypeClass::Array;
0410     case H5T_NO_CLASS:
0411     case H5T_NCLASSES:
0412     default:
0413         return DataTypeClass::Invalid;
0414     }
0415 }
0416 
0417 
0418 inline std::string type_class_string(DataTypeClass tclass) {
0419     switch (tclass) {
0420     case DataTypeClass::Time:
0421         return "Time";
0422     case DataTypeClass::Integer:
0423         return "Integer";
0424     case DataTypeClass::Float:
0425         return "Float";
0426     case DataTypeClass::String:
0427         return "String";
0428     case DataTypeClass::BitField:
0429         return "BitField";
0430     case DataTypeClass::Opaque:
0431         return "Opaque";
0432     case DataTypeClass::Compound:
0433         return "Compound";
0434     case DataTypeClass::Reference:
0435         return "Reference";
0436     case DataTypeClass::Enum:
0437         return "Enum";
0438     case DataTypeClass::VarLen:
0439         return "Varlen";
0440     case DataTypeClass::Array:
0441         return "Array";
0442     default:
0443         return "(Invalid)";
0444     }
0445 }
0446 
0447 }  // unnamed namespace
0448 
0449 
0450 /// \brief Create a DataType instance representing type T
0451 template <typename T>
0452 inline DataType create_datatype() {
0453     return AtomicType<T>();
0454 }
0455 
0456 
0457 /// \brief Create a DataType instance representing type T and perform a sanity check on its size
0458 template <typename T>
0459 inline DataType create_and_check_datatype() {
0460     DataType t = create_datatype<T>();
0461     if (t.empty()) {
0462         throw DataTypeException("Type given to create_and_check_datatype is not valid");
0463     }
0464 
0465     // Skip check if the base type is a variable length string
0466     if (t.isVariableStr()) {
0467         return t;
0468     }
0469 
0470     // Check that the size of the template type matches the size that HDF5 is
0471     // expecting.
0472     if (t.isReference() || t.isFixedLenStr()) {
0473         return t;
0474     }
0475     if (sizeof(T) != t.getSize()) {
0476         std::ostringstream ss;
0477         ss << "Size of array type " << sizeof(T) << " != that of memory datatype " << t.getSize()
0478            << std::endl;
0479         throw DataTypeException(ss.str());
0480     }
0481 
0482     return t;
0483 }
0484 
0485 }  // namespace HighFive
0486 HIGHFIVE_REGISTER_TYPE(HighFive::details::Boolean, HighFive::create_enum_boolean)
0487 
0488 namespace HighFive {
0489 
0490 template <>
0491 inline DataType create_datatype<bool>() {
0492     return create_datatype<HighFive::details::Boolean>();
0493 }
0494 
0495 }  // namespace HighFive