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