Coverage Report

Created: 2025-06-24 06:43

/src/icu/source/i18n/units_converter.h
Line
Count
Source (jump to first uncovered line)
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 "measunit_impl.h"
12
#include "unicode/errorcode.h"
13
#include "unicode/stringpiece.h"
14
#include "unicode/uobject.h"
15
#include "units_converter.h"
16
#include "units_data.h"
17
18
U_NAMESPACE_BEGIN
19
namespace units {
20
21
/* Internal Structure */
22
23
// Constants corresponding to unitConstants in CLDR's units.xml.
24
enum Constants {
25
    CONSTANT_FT2M,       // ft_to_m
26
    CONSTANT_PI,         // PI
27
    CONSTANT_GRAVITY,    // Gravity of earth (9.80665 m/s^2), "g".
28
    CONSTANT_G,          // Newtonian constant of gravitation, "G".
29
    CONSTANT_GAL_IMP2M3, // Gallon imp to m3
30
    CONSTANT_LB2KG,      // Pound to Kilogram
31
    CONSTANT_GLUCOSE_MOLAR_MASS,
32
    CONSTANT_ITEM_PER_MOLE,
33
34
    // Must be the last element.
35
    CONSTANTS_COUNT
36
};
37
38
// These values are a hard-coded subset of unitConstants in the units
39
// resources file. A unit test checks that all constants in the resource
40
// file are at least recognised by the code. Derived constants' values or
41
// hard-coded derivations are not checked.
42
// In ICU4J, these constants live in UnitConverter.Factor.getConversionRate().
43
static const double constantsValues[CONSTANTS_COUNT] = {
44
    0.3048,                    // CONSTANT_FT2M
45
    411557987.0 / 131002976.0, // CONSTANT_PI
46
    9.80665,                   // CONSTANT_GRAVITY
47
    6.67408E-11,               // CONSTANT_G
48
    0.00454609,                // CONSTANT_GAL_IMP2M3
49
    0.45359237,                // CONSTANT_LB2KG
50
    180.1557,                  // CONSTANT_GLUCOSE_MOLAR_MASS
51
    6.02214076E+23,            // CONSTANT_ITEM_PER_MOLE
52
};
53
54
typedef enum Signum {
55
    NEGATIVE = -1,
56
    POSITIVE = 1,
57
} Signum;
58
59
/* Represents a conversion factor */
60
struct U_I18N_API Factor {
61
    double factorNum = 1;
62
    double factorDen = 1;
63
    double offset = 0;
64
    bool reciprocal = false;
65
66
    // Exponents for the symbolic constants
67
    int32_t constantExponents[CONSTANTS_COUNT] = {};
68
69
    void multiplyBy(const Factor &rhs);
70
    void divideBy(const Factor &rhs);
71
72
    // Apply the power to the factor.
73
    void power(int32_t power);
74
75
    // Apply SI or binary prefix to the Factor.
76
    void applyPrefix(UMeasurePrefix unitPrefix);
77
78
    // Does an in-place substitution of the "symbolic constants" based on
79
    // constantExponents (resetting the exponents).
80
    //
81
    // In ICU4J, see UnitConverter.Factor.getConversionRate().
82
    void substituteConstants();
83
};
84
85
struct U_I18N_API ConversionInfo {
86
    double conversionRate;
87
    double offset;
88
    bool reciprocal;
89
};
90
91
/*
92
 * Adds a single factor element to the `Factor`. e.g "ft3m", "2.333" or "cup2m3". But not "cup2m3^3".
93
 */
94
void U_I18N_API addSingleFactorConstant(StringPiece baseStr, int32_t power, Signum sigNum,
95
                                        Factor &factor, UErrorCode &status);
96
97
/**
98
 * Represents the conversion rate between `source` and `target`.
99
 */
100
struct U_I18N_API ConversionRate : public UMemory {
101
    const MeasureUnitImpl source;
102
    const MeasureUnitImpl target;
103
    double factorNum = 1;
104
    double factorDen = 1;
105
    double sourceOffset = 0;
106
    double targetOffset = 0;
107
    bool reciprocal = false;
108
109
    ConversionRate(MeasureUnitImpl &&source, MeasureUnitImpl &&target)
110
0
        : source(std::move(source)), target(std::move(target)) {}
111
};
112
113
enum Convertibility {
114
    RECIPROCAL,
115
    CONVERTIBLE,
116
    UNCONVERTIBLE,
117
};
118
119
MeasureUnitImpl U_I18N_API extractCompoundBaseUnit(const MeasureUnitImpl &source,
120
                                                   const ConversionRates &conversionRates,
121
                                                   UErrorCode &status);
122
123
/**
124
 * Check if the convertibility between `source` and `target`.
125
 * For example:
126
 *    `meter` and `foot` are `CONVERTIBLE`.
127
 *    `meter-per-second` and `second-per-meter` are `RECIPROCAL`.
128
 *    `meter` and `pound` are `UNCONVERTIBLE`.
129
 *
130
 * NOTE:
131
 *    Only works with SINGLE and COMPOUND units. If one of the units is a
132
 *    MIXED unit, an error will occur. For more information, see UMeasureUnitComplexity.
133
 */
134
Convertibility U_I18N_API extractConvertibility(const MeasureUnitImpl &source,
135
                                                const MeasureUnitImpl &target,
136
                                                const ConversionRates &conversionRates,
137
                                                UErrorCode &status);
138
139
/**
140
 * Converts from a source `MeasureUnit` to a target `MeasureUnit`.
141
 *
142
 * NOTE:
143
 *    Only works with SINGLE and COMPOUND units. If one of the units is a
144
 *    MIXED unit, an error will occur. For more information, see UMeasureUnitComplexity.
145
 */
146
class U_I18N_API UnitsConverter : public UMemory {
147
  public:
148
    /**
149
     * Constructor of `UnitConverter`.
150
     * NOTE:
151
     *   - source and target must be under the same category
152
     *      - e.g. meter to mile --> both of them are length units.
153
     * NOTE:
154
     *    This constructor creates an instance of `ConversionRates` internally.
155
     *
156
     * @param sourceIdentifier represents the source unit identifier.
157
     * @param targetIdentifier represents the target unit identifier.
158
     * @param status
159
     */
160
    UnitsConverter(StringPiece sourceIdentifier, StringPiece targetIdentifier, UErrorCode &status);
161
162
    /**
163
     * Constructor of `UnitConverter`.
164
     * NOTE:
165
     *   - source and target must be under the same category
166
     *      - e.g. meter to mile --> both of them are length units.
167
     *
168
     * @param source represents the source unit.
169
     * @param target represents the target unit.
170
     * @param ratesInfo Contains all the needed conversion rates.
171
     * @param status
172
     */
173
    UnitsConverter(const MeasureUnitImpl &source, const MeasureUnitImpl &target,
174
                  const ConversionRates &ratesInfo, UErrorCode &status);
175
176
    /**
177
     * Compares two single units and returns 1 if the first one is greater, -1 if the second
178
     * one is greater and 0 if they are equal.
179
     *
180
     * NOTE:
181
     *  Compares only single units that are convertible.
182
     */
183
    static int32_t compareTwoUnits(const MeasureUnitImpl &firstUnit, const MeasureUnitImpl &SecondUnit,
184
                                   const ConversionRates &ratesInfo, UErrorCode &status);
185
186
    /**
187
     * Convert a measurement expressed in the source unit to a measurement
188
     * expressed in the target unit.
189
     *
190
     * @param inputValue the value to be converted.
191
     * @return the converted value.
192
     */
193
    double convert(double inputValue) const;
194
195
    /**
196
     * The inverse of convert(): convert a measurement expressed in the target
197
     * unit to a measurement expressed in the source unit.
198
     *
199
     * @param inputValue the value to be converted.
200
     * @return the converted value.
201
     */
202
    double convertInverse(double inputValue) const;
203
204
    ConversionInfo getConversionInfo() const;
205
206
  private:
207
    ConversionRate conversionRate_;
208
209
    /**
210
     * Initialises the object.
211
     */ 
212
    void init(const ConversionRates &ratesInfo, UErrorCode &status);
213
};
214
215
} // namespace units
216
U_NAMESPACE_END
217
218
#endif //__UNITS_CONVERTER_H__
219
220
#endif /* #if !UCONFIG_NO_FORMATTING */