Back to home page

EIC code displayed by LXR

 
 

    


File indexing completed on 2026-05-21 08:26:23

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 <type_traits>
0012 #include <vector>
0013 
0014 #include <H5Tpublic.h>
0015 
0016 #include "H5Object.hpp"
0017 #include "bits/H5Utils.hpp"
0018 
0019 #include "bits/string_padding.hpp"
0020 #include "H5PropertyList.hpp"
0021 
0022 #include "bits/h5_wrapper.hpp"
0023 #include "bits/h5t_wrapper.hpp"
0024 
0025 namespace HighFive {
0026 
0027 
0028 ///
0029 /// \brief Enum of Fundamental data classes
0030 ///
0031 enum class DataTypeClass {
0032     Time = 1 << 1,
0033     Integer = 1 << 2,
0034     Float = 1 << 3,
0035     String = 1 << 4,
0036     BitField = 1 << 5,
0037     Opaque = 1 << 6,
0038     Compound = 1 << 7,
0039     Reference = 1 << 8,
0040     Enum = 1 << 9,
0041     VarLen = 1 << 10,
0042     Array = 1 << 11,
0043     Invalid = 0
0044 };
0045 
0046 inline DataTypeClass operator|(DataTypeClass lhs, DataTypeClass rhs) {
0047     using T = std::underlying_type<DataTypeClass>::type;
0048     return static_cast<DataTypeClass>(static_cast<T>(lhs) | static_cast<T>(rhs));
0049 }
0050 
0051 inline DataTypeClass operator&(DataTypeClass lhs, DataTypeClass rhs) {
0052     using T = std::underlying_type<DataTypeClass>::type;
0053     return static_cast<DataTypeClass>(static_cast<T>(lhs) & static_cast<T>(rhs));
0054 }
0055 
0056 class StringType;
0057 class IntegerType;
0058 
0059 ///
0060 /// \brief HDF5 Data Type
0061 ///
0062 class DataType: public Object {
0063   public:
0064     bool operator==(const DataType& other) const;
0065 
0066     bool operator!=(const DataType& other) const;
0067 
0068     ///
0069     /// \brief Return the fundamental type.
0070     ///
0071     DataTypeClass getClass() const;
0072 
0073     ///
0074     /// \brief Returns the length (in bytes) of this type elements
0075     ///
0076     /// Notice that the size of variable length sequences may have limited applicability
0077     /// given that it refers to the size of the control structure. For info see
0078     ///   https://support.hdfgroup.org/HDF5/doc/RM/RM_H5T.html#Datatype-GetSize
0079     size_t getSize() const;
0080 
0081     ///
0082     /// \brief Returns a friendly description of the type (e.g. Float32)
0083     ///
0084     std::string string() const;
0085 
0086     ///
0087     /// \brief Returns whether the type is a variable-length string
0088     ///
0089     bool isVariableStr() const;
0090 
0091     ///
0092     /// \brief Returns whether the type is a fixed-length string
0093     ///
0094     bool isFixedLenStr() const;
0095 
0096     ///
0097     /// \brief Returns this datatype as a `StringType`.
0098     ///
0099     StringType asStringType() const;
0100 
0101     ///
0102     /// \brief Returns this datatype as a `IntegerType`.
0103     ///
0104     IntegerType asIntegerType() const;
0105 
0106     ///
0107     /// \brief Check the DataType was default constructed.
0108     ///
0109     bool empty() const noexcept;
0110 
0111     /// \brief Returns whether the type is a Reference
0112     bool isReference() const;
0113 
0114     /// \brief Get the list of properties for creation of this DataType
0115     DataTypeCreateProps getCreatePropertyList() const {
0116         return details::get_plist<DataTypeCreateProps>(*this, H5Tget_create_plist);
0117     }
0118 
0119   protected:
0120     using Object::Object;
0121 
0122     friend class Attribute;
0123     friend class File;
0124     friend class DataSet;
0125     friend class CompoundType;
0126     template <typename Derivate>
0127     friend class NodeTraits;
0128 };
0129 
0130 
0131 enum class CharacterSet : std::underlying_type<H5T_cset_t>::type {
0132     Ascii = H5T_CSET_ASCII,
0133     Utf8 = H5T_CSET_UTF8,
0134 };
0135 
0136 class StringType: public DataType {
0137   public:
0138     ///
0139     /// \brief For stings return the character set.
0140     ///
0141     CharacterSet getCharacterSet() const;
0142 
0143     ///
0144     /// \brief For fixed length stings return the padding.
0145     ///
0146     StringPadding getPadding() const;
0147 
0148   protected:
0149     using DataType::DataType;
0150     friend class DataType;
0151 };
0152 
0153 class FixedLengthStringType: public StringType {
0154   public:
0155     ///
0156     /// \brief Create a fixed length string datatype.
0157     ///
0158     /// The string will be `size` bytes long, regardless whether it's ASCII or
0159     /// UTF8. In particular, a string with `n` UFT8 characters in general
0160     /// requires `4*n` bytes.
0161     ///
0162     /// The string padding is subtle, essentially it's just a hint. While
0163     /// commonly, a null-terminated string is guaranteed to have one `'\0'`
0164     /// which marks the semantic end of the string, this is not enforced by
0165     /// HDF5. In fact, there are HDF5 files that contain strings that claim to
0166     /// be null-terminated but aren't.  The length of the buffer must be at
0167     /// least `size` bytes regardless of the padding. HDF5 will read or write
0168     /// `size` bytes, irrespective of when (if at all) the `\0` occurs.
0169     ///
0170     /// Note that when writing, passing `StringPadding::NullTerminated` is a
0171     /// guarantee to the reader that it contains a `\0`. Therefore, make sure
0172     /// that the string really is null-terminated. Otherwise prefer a
0173     /// null-padded string. This mearly states that the buffer is filled up
0174     /// with 0 or more `\0`.
0175     FixedLengthStringType(size_t size,
0176                           StringPadding padding,
0177                           CharacterSet character_set = CharacterSet::Ascii);
0178 };
0179 
0180 class VariableLengthStringType: public StringType {
0181   public:
0182     ///
0183     /// \brief Create a variable length string HDF5 datatype.
0184     ///
0185     explicit VariableLengthStringType(CharacterSet character_set = CharacterSet::Ascii);
0186 };
0187 
0188 ///
0189 /// \brief An Integer datatype (i.e. H5T_INTEGER).
0190 ///
0191 /// Provides access to the API that's only valid for integers. Use
0192 /// DataType::asIntegerType to convert from a generic DataType.
0193 ///
0194 class IntegerType: public DataType {
0195   public:
0196     bool isSigned() {
0197         return detail::h5t_get_sign(getId()) != H5T_SGN_NONE;
0198     }
0199 
0200   protected:
0201     using DataType::DataType;
0202     friend class DataType;
0203 };
0204 
0205 ///
0206 /// \brief create an HDF5 DataType from a C++ type
0207 ///
0208 ///  Support only basic data type
0209 ///
0210 template <typename T>
0211 class AtomicType: public DataType {
0212   public:
0213     AtomicType();
0214 
0215     using basic_type = T;
0216 };
0217 
0218 
0219 ///
0220 /// \brief Create a compound HDF5 datatype
0221 ///
0222 class CompoundType: public DataType {
0223   public:
0224     ///
0225     /// \brief Use for defining a sub-type of compound type
0226     struct member_def {
0227         member_def(std::string t_name, DataType t_base_type, size_t t_offset = 0)
0228             : name(std::move(t_name))
0229             , base_type(std::move(t_base_type))
0230             , offset(t_offset) {}
0231         std::string name;
0232         DataType base_type;
0233         size_t offset;
0234     };
0235 
0236     ///
0237     /// \brief Initializes a compound type from a vector of member definitions
0238     /// \param t_members
0239     /// \param size
0240     inline CompoundType(const std::vector<member_def>& t_members, size_t size = 0)
0241         : members(t_members) {
0242         create(size);
0243     }
0244     inline CompoundType(std::vector<member_def>&& t_members, size_t size = 0)
0245         : members(std::move(t_members)) {
0246         create(size);
0247     }
0248     inline CompoundType(const std::initializer_list<member_def>& t_members, size_t size = 0)
0249         : members(t_members) {
0250         create(size);
0251     }
0252 
0253     ///
0254     /// \brief Initializes a compound type from a DataType
0255     /// \param type
0256     inline explicit CompoundType(DataType&& type)
0257         : DataType(type) {
0258         if (getClass() != DataTypeClass::Compound) {
0259             std::ostringstream ss;
0260             ss << "hid " << _hid << " does not refer to a compound data type";
0261             throw DataTypeException(ss.str());
0262         }
0263         size_t n_members = static_cast<size_t>(detail::h5t_get_nmembers(_hid));
0264         members.reserve(n_members);
0265         for (unsigned i = 0; i < n_members; i++) {
0266             char* name = detail::h5t_get_member_name(_hid, i);
0267             size_t offset = detail::h5t_get_member_offset(_hid, i);
0268             hid_t member_hid = detail::h5t_get_member_type(_hid, i);
0269             DataType member_type{member_hid};
0270             members.emplace_back(std::string(name), member_type, offset);
0271 
0272             detail::h5_free_memory(name);
0273         }
0274     }
0275 
0276     /// \brief Commit datatype into the given Object
0277     /// \param object Location to commit object into
0278     /// \param name Name to give the datatype
0279     inline void commit(const Object& object, const std::string& name) const;
0280 
0281     /// \brief Get read access to the CompoundType members
0282     inline const std::vector<member_def>& getMembers() const noexcept {
0283         return members;
0284     }
0285 
0286   private:
0287     /// A vector of the member_def members of this CompoundType
0288     std::vector<member_def> members;
0289 
0290     /// \brief Automatically create the type from the set of members
0291     ///        using standard struct alignment.
0292     /// \param size Total size of data type
0293     void create(size_t size = 0);
0294 };
0295 
0296 ///
0297 /// \brief Create a enum HDF5 datatype
0298 ///
0299 /// \code{.cpp}
0300 /// enum class Position {
0301 ///     FIRST = 1,
0302 ///     SECOND = 2,
0303 /// };
0304 ///
0305 /// EnumType<Position> create_enum_position() {
0306 ///     return {{"FIRST", Position::FIRST},
0307 ///             {"SECOND", Position::SECOND}};
0308 /// }
0309 ///
0310 /// // You have to register the type inside HighFive
0311 /// HIGHFIVE_REGISTER_TYPE(Position, create_enum_position)
0312 ///
0313 /// void write_first(H5::File& file) {
0314 ///     auto dataset = file.createDataSet("/foo", Position::FIRST);
0315 /// }
0316 /// \endcode
0317 template <typename T>
0318 class EnumType: public DataType {
0319   public:
0320     ///
0321     /// \brief Use for defining a member of enum type
0322     struct member_def {
0323         member_def(const std::string& t_name, T t_value)
0324             : name(t_name)
0325             , value(std::move(t_value)) {}
0326         std::string name;
0327         T value;
0328     };
0329 
0330     EnumType(const EnumType& other) = default;
0331 
0332     EnumType(const std::vector<member_def>& t_members)
0333         : members(t_members) {
0334         static_assert(std::is_enum<T>::value, "EnumType<T>::create takes only enum");
0335         if (members.empty()) {
0336             HDF5ErrMapper::ToException<DataTypeException>(
0337                 "Could not create an enum without members");
0338         }
0339         create();
0340     }
0341 
0342     EnumType(std::initializer_list<member_def> t_members)
0343         : EnumType(std::vector<member_def>(t_members)) {}
0344 
0345     /// \brief Commit datatype into the given Object
0346     /// \param object Location to commit object into
0347     /// \param name Name to give the datatype
0348     void commit(const Object& object, const std::string& name) const;
0349 
0350   private:
0351     std::vector<member_def> members;
0352 
0353     void create();
0354 };
0355 
0356 
0357 /// \brief Create a DataType instance representing type T
0358 template <typename T>
0359 DataType create_datatype();
0360 
0361 
0362 /// \brief Create a DataType instance representing type T and perform a sanity check on its size
0363 template <typename T>
0364 DataType create_and_check_datatype();
0365 }  // namespace HighFive
0366 
0367 
0368 /// \brief Macro to extend datatype of HighFive
0369 ///
0370 /// This macro has to be called outside of any namespace.
0371 ///
0372 /// \code{.cpp}
0373 /// namespace app {
0374 /// enum FooBar { FOO = 1, BAR = 2 };
0375 /// EnumType create_enum_foobar() {
0376 ///    return EnumType<FooBar>({{"FOO", FooBar::FOO},
0377 ///                             {"BAR", FooBar::BAR}});
0378 /// }
0379 /// }
0380 ///
0381 /// HIGHFIVE_REGISTER_TYPE(FooBar, ::app::create_enum_foobar)
0382 /// \endcode
0383 #define HIGHFIVE_REGISTER_TYPE(type, function)                    \
0384     template <>                                                   \
0385     inline HighFive::DataType HighFive::create_datatype<type>() { \
0386         return function();                                        \
0387     }
0388 
0389 #include "bits/H5DataType_misc.hpp"