From 75dec59c1b11b476f6902aa36a8f3aba7f3d45b0 Mon Sep 17 00:00:00 2001 From: Luc Grosheintz Date: Fri, 22 Aug 2025 10:12:00 +0200 Subject: [PATCH] add: support for checking sign of integer datatype. An integer HDF5 datatype (i.e. one that has class `H5T_INTEGER`) can be signed or unsigned. This commit adds a class `IntegerType` which supports the method `isSigned`. Intended use: auto dtype = /* obtain datatype */; if(dtype.getClass() == DataTypeClass::Integer) { auto int_type = dtype.asIntegerType(); if(int_type.isSigned()) { // ... } --- include/highfive/H5DataType.hpp | 22 ++++++++++++++++++++++ include/highfive/bits/H5DataType_misc.hpp | 12 ++++++++++++ include/highfive/bits/h5t_wrapper.hpp | 8 ++++++++ tests/unit/tests_high_five_base.cpp | 15 +++++++++++++++ 4 files changed, 57 insertions(+) diff --git a/include/highfive/H5DataType.hpp b/include/highfive/H5DataType.hpp index 44886c23..35bff7f8 100644 --- a/include/highfive/H5DataType.hpp +++ b/include/highfive/H5DataType.hpp @@ -54,6 +54,7 @@ inline DataTypeClass operator&(DataTypeClass lhs, DataTypeClass rhs) { } class StringType; +class IntegerType; /// /// \brief HDF5 Data Type @@ -97,6 +98,11 @@ class DataType: public Object { /// StringType asStringType() const; + /// + /// \brief Returns this datatype as a `IntegerType`. + /// + IntegerType asIntegerType() const; + /// /// \brief Check the DataType was default constructed. /// @@ -179,6 +185,22 @@ class VariableLengthStringType: public StringType { 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 diff --git a/include/highfive/bits/H5DataType_misc.hpp b/include/highfive/bits/H5DataType_misc.hpp index 6ce17ec5..cd875417 100644 --- a/include/highfive/bits/H5DataType_misc.hpp +++ b/include/highfive/bits/H5DataType_misc.hpp @@ -73,6 +73,18 @@ inline StringType DataType::asStringType() const { return StringType(_hid); } +inline IntegerType DataType::asIntegerType() const { + if (getClass() != DataTypeClass::Integer) { + throw DataTypeException("Invalid conversion to IntegerType."); + } + + if (isValid()) { + detail::h5i_inc_ref(_hid); + } + + return IntegerType(_hid); +} + inline std::string DataType::string() const { return type_class_string(getClass()) + std::to_string(getSize() * 8); } diff --git a/include/highfive/bits/h5t_wrapper.hpp b/include/highfive/bits/h5t_wrapper.hpp index f2c7bb09..0959d5b8 100644 --- a/include/highfive/bits/h5t_wrapper.hpp +++ b/include/highfive/bits/h5t_wrapper.hpp @@ -24,6 +24,14 @@ inline hsize_t h5t_get_size(hid_t hid) { return size; } +inline H5T_sign_t h5t_get_sign(hid_t type_id) { + auto sign = H5Tget_sign(type_id); + if (sign == H5T_SGN_ERROR) { + HDF5ErrMapper::ToException("Error getting the sign of datatype."); + } + return sign; +} + inline H5T_cset_t h5t_get_cset(hid_t hid) { auto cset = H5Tget_cset(hid); if (cset == H5T_CSET_ERROR) { diff --git a/tests/unit/tests_high_five_base.cpp b/tests/unit/tests_high_five_base.cpp index a086a3f4..0dcbf967 100644 --- a/tests/unit/tests_high_five_base.cpp +++ b/tests/unit/tests_high_five_base.cpp @@ -2332,6 +2332,21 @@ TEST_CASE("HighFiveDataTypeClass") { CHECK(((Float | String) & String) == String); } +TEST_CASE("HighFiveIntegerType") { + SECTION("signed int") { + auto dtype = create_datatype().asIntegerType(); + CHECK(dtype.isSigned()); + } + SECTION("unsigned int") { + auto dtype = create_datatype().asIntegerType(); + CHECK(!dtype.isSigned()); + } + SECTION("invalid conversion") { + auto dtype = create_datatype(); + CHECK_THROWS(dtype.asIntegerType()); + } +} + #ifdef HIGHFIVE_TEST_EIGEN template