Coverage Report

Created: 2026-01-25 06:58

next uncovered line (L), next uncovered region (R), next uncovered branch (B)
/src/icu/icu4c/source/i18n/units_converter.h
Line
Count
Source
1
// © 2020 and later: Unicode, Inc. and others.
2
// License & terms of use: http://www.unicode.org/copyright.html
3
4
#include "unicode/utypes.h"
5
6
#if !UCONFIG_NO_FORMATTING
7
#ifndef __UNITS_CONVERTER_H__
8
#define __UNITS_CONVERTER_H__
9
10
#include "cmemory.h"
11
#include "fixedstring.h"
12
#include "measunit_impl.h"
13
#include "unicode/errorcode.h"
14
#include "unicode/stringpiece.h"
15
#include "unicode/uobject.h"
16
#include "units_converter.h"
17
#include "units_data.h"
18
19
U_NAMESPACE_BEGIN
20
namespace units {
21
22
/* Internal Structure */
23
24
// Constants corresponding to unitConstants in CLDR's units.xml.
25
enum Constants {
26
    CONSTANT_FT2M,       // ft_to_m
27
    CONSTANT_PI,         // PI
28
    CONSTANT_GRAVITY,    // Gravity of earth (9.80665 m/s^2), "g".
29
    CONSTANT_G,          // Newtonian constant of gravitation, "G".
30
    CONSTANT_GAL_IMP2M3, // Gallon imp to m3
31
    CONSTANT_LB2KG,      // Pound to Kilogram
32
    CONSTANT_GLUCOSE_MOLAR_MASS,
33
    CONSTANT_ITEM_PER_MOLE,
34
    CONSTANT_METERS_PER_AU,
35
    CONSTANT_SEC_PER_JULIAN_YEAR,
36
    CONSTANT_SPEED_OF_LIGHT_METERS_PER_SECOND,
37
    CONSTANT_SHO_TO_M3,   // https://en.wikipedia.org/wiki/Japanese_units_of_measurement
38
    CONSTANT_TSUBO_TO_M2, // https://en.wikipedia.org/wiki/Japanese_units_of_measurement
39
    CONSTANT_SHAKU_TO_M,  // https://en.wikipedia.org/wiki/Japanese_units_of_measurement
40
    CONSTANT_AMU,         // Atomic Mass Unit https://www.nist.gov/pml/special-publication-811/nist-guide-si-chapter-5-units-outside-si#table7
41
42
    // Must be the last element.
43
    CONSTANTS_COUNT
44
};
45
46
// These values are a hard-coded subset of unitConstants in the units
47
// resources file. A unit test checks that all constants in the resource
48
// file are at least recognised by the code. Derived constants' values or
49
// hard-coded derivations are not checked.
50
// In ICU4J, these constants live in UnitConverter.Factor.getConversionRate().
51
static const double constantsValues[CONSTANTS_COUNT] = {
52
    0.3048,                    // CONSTANT_FT2M
53
    411557987.0 / 131002976.0, // CONSTANT_PI
54
    9.80665,                   // CONSTANT_GRAVITY
55
    6.67408E-11,               // CONSTANT_G
56
    0.00454609,                // CONSTANT_GAL_IMP2M3
57
    0.45359237,                // CONSTANT_LB2KG
58
    180.1557,                  // CONSTANT_GLUCOSE_MOLAR_MASS
59
    6.02214076E+23,            // CONSTANT_ITEM_PER_MOLE
60
    149597870700,              // CONSTANT_METERS_PER_AU
61
    31557600,                  // CONSTANT_SEC_PER_JULIAN_YEAR
62
    299792458,                 // CONSTANT_SPEED_OF_LIGHT_METERS_PER_SECOND
63
    2401.0 / (1331.0 * 1000.0),
64
    400.0 / 121.0,
65
    4.0 / 121.0,
66
    1.66053878283E-27,         // CONSTANT_AMU
67
};
68
69
typedef enum Signum {
70
    NEGATIVE = -1,
71
    POSITIVE = 1,
72
} Signum;
73
74
/* Represents a conversion factor */
75
struct U_I18N_API_CLASS Factor {
76
    double factorNum = 1;
77
    double factorDen = 1;
78
    double offset = 0;
79
    bool reciprocal = false;
80
81
    // Exponents for the symbolic constants
82
    int32_t constantExponents[CONSTANTS_COUNT] = {};
83
84
    void multiplyBy(const Factor &rhs);
85
    void divideBy(const Factor &rhs);
86
    void divideBy(const uint64_t constant);
87
88
    // Apply the power to the factor.
89
    void power(int32_t power);
90
91
    // Apply SI or binary prefix to the Factor.
92
    void applyPrefix(UMeasurePrefix unitPrefix);
93
94
    // Does an in-place substitution of the "symbolic constants" based on
95
    // constantExponents (resetting the exponents).
96
    //
97
    // In ICU4J, see UnitConverter.Factor.getConversionRate().
98
    U_I18N_API void substituteConstants();
99
};
100
101
struct ConversionInfo {
102
    double conversionRate;
103
    double offset;
104
    bool reciprocal;
105
};
106
107
/*
108
 * Adds a single factor element to the `Factor`. e.g "ft3m", "2.333" or "cup2m3". But not "cup2m3^3".
109
 */
110
void U_I18N_API addSingleFactorConstant(StringPiece baseStr, int32_t power, Signum sigNum,
111
                                        Factor &factor, UErrorCode &status);
112
113
/**
114
 * Represents the conversion rate between `source` and `target`.
115
 * TODO ICU-22683: COnsider moving the handling of special mappings (e.g. beaufort) to a separate
116
 * struct.
117
 */
118
struct ConversionRate : public UMemory {
119
    const MeasureUnitImpl source;
120
    const MeasureUnitImpl target;
121
    FixedString specialSource;
122
    FixedString specialTarget;
123
    double factorNum = 1;
124
    double factorDen = 1;
125
    double sourceOffset = 0;
126
    double targetOffset = 0;
127
    bool reciprocal = false;
128
129
    ConversionRate(MeasureUnitImpl &&source, MeasureUnitImpl &&target)
130
0
        : source(std::move(source)), target(std::move(target)), specialSource(), specialTarget() {}
131
};
132
133
enum Convertibility {
134
    RECIPROCAL,
135
    CONVERTIBLE,
136
    UNCONVERTIBLE,
137
};
138
139
MeasureUnitImpl extractCompoundBaseUnit(const MeasureUnitImpl& source,
140
                                        const ConversionRates& conversionRates,
141
                                        UErrorCode& status);
142
143
/**
144
 * Check if the convertibility between `source` and `target`.
145
 * For example:
146
 *    `meter` and `foot` are `CONVERTIBLE`.
147
 *    `meter-per-second` and `second-per-meter` are `RECIPROCAL`.
148
 *    `meter` and `pound` are `UNCONVERTIBLE`.
149
 *
150
 * NOTE:
151
 *    Only works with SINGLE and COMPOUND units. If one of the units is a
152
 *    MIXED unit, an error will occur. For more information, see UMeasureUnitComplexity.
153
 */
154
Convertibility U_I18N_API extractConvertibility(const MeasureUnitImpl &source,
155
                                                const MeasureUnitImpl &target,
156
                                                const ConversionRates &conversionRates,
157
                                                UErrorCode &status);
158
159
/**
160
 * Converts from a source `MeasureUnit` to a target `MeasureUnit`.
161
 *
162
 * NOTE:
163
 *    Only works with SINGLE and COMPOUND units. If one of the units is a
164
 *    MIXED unit, an error will occur. For more information, see UMeasureUnitComplexity.
165
 */
166
class U_I18N_API_CLASS UnitsConverter : public UMemory {
167
  public:
168
    /**
169
     * Constructor of `UnitConverter`.
170
     * NOTE:
171
     *   - source and target must be under the same category
172
     *      - e.g. meter to mile --> both of them are length units.
173
     * NOTE:
174
     *    This constructor creates an instance of `ConversionRates` internally.
175
     *
176
     * @param sourceIdentifier represents the source unit identifier.
177
     * @param targetIdentifier represents the target unit identifier.
178
     * @param status
179
     */
180
    U_I18N_API UnitsConverter(StringPiece sourceIdentifier, StringPiece targetIdentifier,
181
                              UErrorCode &status);
182
183
    /**
184
     * Constructor of `UnitConverter`.
185
     * NOTE:
186
     *   - source and target must be under the same category
187
     *      - e.g. meter to mile --> both of them are length units.
188
     *
189
     * @param source represents the source unit.
190
     * @param target represents the target unit.
191
     * @param ratesInfo Contains all the needed conversion rates.
192
     * @param status
193
     */
194
    U_I18N_API UnitsConverter(const MeasureUnitImpl &source, const MeasureUnitImpl &target,
195
                              const ConversionRates &ratesInfo, UErrorCode &status);
196
197
    /**
198
     * Compares two single units and returns 1 if the first one is greater, -1 if the second
199
     * one is greater and 0 if they are equal.
200
     *
201
     * NOTE:
202
     *  Compares only single units that are convertible.
203
     */
204
    static int32_t compareTwoUnits(const MeasureUnitImpl &firstUnit, const MeasureUnitImpl &SecondUnit,
205
                                   const ConversionRates &ratesInfo, UErrorCode &status);
206
207
    /**
208
     * Convert a measurement expressed in the source unit to a measurement
209
     * expressed in the target unit.
210
     *
211
     * @param inputValue the value to be converted.
212
     * @return the converted value.
213
     */
214
    U_I18N_API double convert(double inputValue) const;
215
216
    /**
217
     * The inverse of convert(): convert a measurement expressed in the target
218
     * unit to a measurement expressed in the source unit.
219
     *
220
     * @param inputValue the value to be converted.
221
     * @return the converted value.
222
     */
223
    U_I18N_API double convertInverse(double inputValue) const;
224
225
    U_I18N_API ConversionInfo getConversionInfo() const;
226
227
  private:
228
    ConversionRate conversionRate_;
229
230
    /**
231
     * Initialises the object.
232
     */
233
    void init(const ConversionRates &ratesInfo, UErrorCode &status);
234
235
    /**
236
     * Convert from what should be discrete scale values for a particular unit like beaufort
237
     * to a corresponding value in the base unit (which can have any decimal value, like meters/sec).
238
     * This can handle different scales, specified by minBaseForScaleValues[].
239
     */
240
    double scaleToBase(double scaleValue, double minBaseForScaleValues[], int scaleMax) const;
241
242
    /**
243
     * Convert from a value in the base unit (which can have any decimal value, like meters/sec) to a corresponding
244
     * discrete value in a scale (like beaufort), where each scale value represents a range of base values.
245
     * This can handle different scales, specified by minBaseForScaleValues[].
246
     */
247
    double baseToScale(double baseValue, double minBaseForScaleValues[], int scaleMax) const;
248
249
};
250
251
} // namespace units
252
U_NAMESPACE_END
253
254
#endif //__UNITS_CONVERTER_H__
255
256
#endif /* #if !UCONFIG_NO_FORMATTING */