• 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 enum Constants {
24     CONSTANT_FT2M,    // ft2m stands for foot to meter.
25     CONSTANT_PI,      // PI
26     CONSTANT_GRAVITY, // Gravity
27     CONSTANT_G,
28     CONSTANT_GAL_IMP2M3, // Gallon imp to m3
29     CONSTANT_LB2KG,      // Pound to Kilogram
30 
31     // Must be the last element.
32     CONSTANTS_COUNT
33 };
34 
35 // These values are a hard-coded subset of unitConstants in the units
36 // resources file. A unit test checks that all constants in the resource
37 // file are at least recognised by the code. Derived constants' values or
38 // hard-coded derivations are not checked.
39 static const double constantsValues[CONSTANTS_COUNT] = {
40     0.3048,                    // CONSTANT_FT2M
41     411557987.0 / 131002976.0, // CONSTANT_PI
42     9.80665,                   // CONSTANT_GRAVITY
43     6.67408E-11,               // CONSTANT_G
44     0.00454609,                // CONSTANT_GAL_IMP2M3
45     0.45359237,                // CONSTANT_LB2KG
46 };
47 
48 typedef enum Signum {
49     NEGATIVE = -1,
50     POSITIVE = 1,
51 } Signum;
52 
53 /* Represents a conversion factor */
54 struct U_I18N_API Factor {
55     double factorNum = 1;
56     double factorDen = 1;
57     double offset = 0;
58     bool reciprocal = false;
59     int32_t constants[CONSTANTS_COUNT] = {};
60 
61     void multiplyBy(const Factor &rhs);
62     void divideBy(const Factor &rhs);
63 
64     // Apply the power to the factor.
65     void power(int32_t power);
66 
67     // Flip the `Factor`, for example, factor= 2/3, flippedFactor = 3/2
68     void flip();
69 
70     // Apply SI prefix to the `Factor`
71     void applySiPrefix(UMeasureSIPrefix siPrefix);
72     void substituteConstants();
73 };
74 
75 /*
76  * Adds a single factor element to the `Factor`. e.g "ft3m", "2.333" or "cup2m3". But not "cup2m3^3".
77  */
78 void U_I18N_API addSingleFactorConstant(StringPiece baseStr, int32_t power, Signum sigNum,
79                                         Factor &factor, UErrorCode &status);
80 
81 /**
82  * Represents the conversion rate between `source` and `target`.
83  */
84 struct U_I18N_API ConversionRate : public UMemory {
85     const MeasureUnitImpl source;
86     const MeasureUnitImpl target;
87     double factorNum = 1;
88     double factorDen = 1;
89     double sourceOffset = 0;
90     double targetOffset = 0;
91     bool reciprocal = false;
92 
ConversionRateConversionRate93     ConversionRate(MeasureUnitImpl &&source, MeasureUnitImpl &&target)
94         : source(std::move(source)), target(std::move(target)) {}
95 };
96 
97 enum Convertibility {
98     RECIPROCAL,
99     CONVERTIBLE,
100     UNCONVERTIBLE,
101 };
102 
103 MeasureUnitImpl U_I18N_API extractCompoundBaseUnit(const MeasureUnitImpl &source,
104                                                    const ConversionRates &conversionRates,
105                                                    UErrorCode &status);
106 
107 /**
108  * Check if the convertibility between `source` and `target`.
109  * For example:
110  *    `meter` and `foot` are `CONVERTIBLE`.
111  *    `meter-per-second` and `second-per-meter` are `RECIPROCAL`.
112  *    `meter` and `pound` are `UNCONVERTIBLE`.
113  *
114  * NOTE:
115  *    Only works with SINGLE and COMPOUND units. If one of the units is a
116  *    MIXED unit, an error will occur. For more information, see UMeasureUnitComplexity.
117  */
118 Convertibility U_I18N_API extractConvertibility(const MeasureUnitImpl &source,
119                                                 const MeasureUnitImpl &target,
120                                                 const ConversionRates &conversionRates,
121                                                 UErrorCode &status);
122 
123 /**
124  * Converts from a source `MeasureUnit` to a target `MeasureUnit`.
125  *
126  * NOTE:
127  *    Only works with SINGLE and COMPOUND units. If one of the units is a
128  *    MIXED unit, an error will occur. For more information, see UMeasureUnitComplexity.
129  */
130 class U_I18N_API UnitConverter : public UMemory {
131   public:
132     /**
133      * Constructor of `UnitConverter`.
134      * NOTE:
135      *   - source and target must be under the same category
136      *      - e.g. meter to mile --> both of them are length units.
137      *
138      * @param source represents the source unit.
139      * @param target represents the target unit.
140      * @param ratesInfo Contains all the needed conversion rates.
141      * @param status
142      */
143     UnitConverter(const MeasureUnitImpl &source, const MeasureUnitImpl &target,
144                   const ConversionRates &ratesInfo, UErrorCode &status);
145 
146     /**
147      * Convert a measurement expressed in the source unit to a measurement
148      * expressed in the target unit.
149      *
150      * @param inputValue the value to be converted.
151      * @return the converted value.
152      */
153     double convert(double inputValue) const;
154 
155     /**
156      * The inverse of convert(): convert a measurement expressed in the target
157      * unit to a measurement expressed in the source unit.
158      *
159      * @param inputValue the value to be converted.
160      * @return the converted value.
161      */
162     double convertInverse(double inputValue) const;
163 
164   private:
165     ConversionRate conversionRate_;
166 };
167 
168 } // namespace units
169 U_NAMESPACE_END
170 
171 #endif //__UNITS_CONVERTER_H__
172 
173 #endif /* #if !UCONFIG_NO_FORMATTING */
174