File: exceeds_limit.hpp

package info (click to toggle)
r-bioc-alabaster.base 1.6.1%2Bds-2
  • links: PTS, VCS
  • area: main
  • in suites: sid, trixie
  • size: 1,652 kB
  • sloc: cpp: 11,377; sh: 29; makefile: 2
file content (162 lines) | stat: -rw-r--r-- 5,815 bytes parent folder | download | duplicates (2)
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
#ifndef RITSUKO_HDF5_FORBID_LARGE_INTEGERS_HPP
#define RITSUKO_HDF5_FORBID_LARGE_INTEGERS_HPP

#include "H5Cpp.h"
#include <stdexcept>

/**
 * @file exceeds_limit.hpp
 * @brief Check for larger-than-expected types in HDF5 datasets.
 */

namespace ritsuko {

namespace hdf5 {

/**
 * Check if a HDF5 datatype could hold values beyond the range of a limiting integer type. 
 * This is used by validators to ensure that a dataset can be represented in memory by the limiting type.
 *
 * @param itype HDF5 integer datatype.
 * @param precision Number of bits in the limiting integer type, assuming 2's complement.
 * @param is_signed Whether the limiting integer type is signed.
 *
 * @return Whether the datatype cannot be represented by the limiting integer type.
 * `true` is also returned for non-integer datasets.
 */
inline bool exceeds_integer_limit(const H5::IntType& itype, size_t precision, bool is_signed) {
    if (itype.getSign() == H5T_SGN_NONE) {
        if (is_signed) {
            return (itype.getPrecision() >= precision); // equality, as one bit of the limiting type is used for the sign.
        } else {
            return (itype.getPrecision() > precision);
        }
    } else {
        if (is_signed) {
            return (itype.getPrecision() > precision);
        } else {
            return true;
        }
    }
}

/**
 * Overload of `exceeds_integer_limit()` that accepts a HDF5 dataset handle.
 *
 * @param handle Handle for a HDF5 dataset.
 * @param precision Number of bits in the limiting integer type, assuming 2's complement.
 * @param is_signed Whether the limiting integer type is signed.
 *
 * @return Whether the dataset uses a datatype than cannot be represented by the limiting integer type.
 */
inline bool exceeds_integer_limit(const H5::DataSet& handle, size_t precision, bool is_signed) {
    if (handle.getTypeClass() != H5T_INTEGER) {
        return true;
    }
    H5::IntType itype(handle);
    return exceeds_integer_limit(itype, precision, is_signed);
}

/**
 * Overload of `exceeds_integer_limit()` that accepts a HDF5 attribute handle.
 *
 * @param handle Handle for a HDF5 attribute.
 * @param precision Number of bits in the limiting integer type, assuming 2's complement.
 * @param is_signed Whether the limiting integer type is signed.
 *
 * @return Whether the attribute uses a datatype than cannot be represented by the limiting integer type.
 */
inline bool exceeds_integer_limit(const H5::Attribute& handle, size_t precision, bool is_signed) {
    if (handle.getTypeClass() != H5T_INTEGER) {
        return true;
    }
    return exceeds_integer_limit(handle.getIntType(), precision, is_signed);
}

/**
 * @cond
 */
inline bool exceeds_float_limit_by_integer(const H5::IntType& itype, size_t precision) {
    if (precision >= 64) {
        return exceeds_integer_limit(itype, 52, true);
    } else if (precision >= 32) {
        return exceeds_integer_limit(itype, 24, true);
    } else {
        return true;
    }
}

inline bool exceeds_float_limit_by_float(const H5::FloatType& ftype, size_t precision) {
    // Only considering IEEE-compatible types here.
    if (precision >= 64) {
        return !(
            ftype == H5::PredType::IEEE_F64LE || 
            ftype == H5::PredType::IEEE_F64BE ||
            ftype == H5::PredType::IEEE_F32LE || 
            ftype == H5::PredType::IEEE_F32BE
        );
    } else if (precision >= 32) {
        return !(
            ftype == H5::PredType::IEEE_F32LE || 
            ftype == H5::PredType::IEEE_F32BE
        );
    } else {
        return true;
    }
}
/**
 * @endcond
 */

/**
 * Check if a HDF5 datatype could hold values beyond the range of a limiting (IEEE754-compliant) float type.
 * This is used by validators to ensure that a dataset can be represented in memory by the limiting type.
 *
 * Note that the limiting float type is assumed to be IEEE754-compliant.
 * If the HDF5 datatype is not also IEEE754-compliant, it will be considered out-of-range regardless of its precision.
 * This is necessary as non-IEEE754 floats could have an arbitrary split of bits between the exponent and significand,
 * such that two float datatypes with the same number of bits could represent a different set of numbers.
 * (Though this seems unlikely in practice, as all CPU-specific predefined float types in later HDF5 versions are already aliases of the IEEE types.)
 *
 * @param handle Handle for a HDF5 dataset.
 * @param precision Number of bits in the limiting float type.
 *
 * @return Whether the dataset uses a datatype than cannot be represented by the limiting float type.
 * `true` is also returned for non-numeric datasets.
 */
inline bool exceeds_float_limit(const H5::DataSet& handle, size_t precision) {
    auto tclass = handle.getTypeClass();
    if (tclass == H5T_INTEGER) {
        return exceeds_float_limit_by_integer(H5::IntType(handle), precision);
    } else if (tclass == H5T_FLOAT) {
        return exceeds_float_limit_by_float(H5::FloatType(handle), precision);
    } else {
        return true;
    }
}

/**
 * Overload of `exceeds_float_limit()` that accepts a HDF5 attribute handle.
 *
 * @param handle Handle for a HDF5 attribute.
 * @param precision Number of bits in the limiting float type. 
 *
 * @return Whether the attribute uses a datatype than cannot be represented by the limiting integer type.
 * `true` is also returned for non-numeric attributes.
 */
inline bool exceeds_float_limit(const H5::Attribute& handle, size_t precision) {
    auto tclass = handle.getTypeClass();
    if (tclass == H5T_INTEGER) {
        return exceeds_float_limit_by_integer(handle.getIntType(), precision);
    } else if (tclass == H5T_FLOAT) {
        return exceeds_float_limit_by_float(handle.getFloatType(), precision);
    } else {
        return true;
    }
}

}

}

#endif