diff options
Diffstat (limited to 'intl/icu/source/i18n/units_converter.h')
-rw-r--r-- | intl/icu/source/i18n/units_converter.h | 226 |
1 files changed, 226 insertions, 0 deletions
diff --git a/intl/icu/source/i18n/units_converter.h b/intl/icu/source/i18n/units_converter.h new file mode 100644 index 0000000000..fd1d6ec422 --- /dev/null +++ b/intl/icu/source/i18n/units_converter.h @@ -0,0 +1,226 @@ +// © 2020 and later: Unicode, Inc. and others. +// License & terms of use: http://www.unicode.org/copyright.html + +#include "unicode/utypes.h" + +#if !UCONFIG_NO_FORMATTING +#ifndef __UNITS_CONVERTER_H__ +#define __UNITS_CONVERTER_H__ + +#include "cmemory.h" +#include "measunit_impl.h" +#include "unicode/errorcode.h" +#include "unicode/stringpiece.h" +#include "unicode/uobject.h" +#include "units_converter.h" +#include "units_data.h" + +U_NAMESPACE_BEGIN +namespace units { + +/* Internal Structure */ + +// Constants corresponding to unitConstants in CLDR's units.xml. +enum Constants { + CONSTANT_FT2M, // ft_to_m + CONSTANT_PI, // PI + CONSTANT_GRAVITY, // Gravity of earth (9.80665 m/s^2), "g". + CONSTANT_G, // Newtonian constant of gravitation, "G". + CONSTANT_GAL_IMP2M3, // Gallon imp to m3 + CONSTANT_LB2KG, // Pound to Kilogram + CONSTANT_GLUCOSE_MOLAR_MASS, + CONSTANT_ITEM_PER_MOLE, + CONSTANT_METERS_PER_AU, + CONSTANT_SEC_PER_JULIAN_YEAR, + CONSTANT_SPEED_OF_LIGHT_METERS_PER_SECOND, + + // Must be the last element. + CONSTANTS_COUNT +}; + +// These values are a hard-coded subset of unitConstants in the units +// resources file. A unit test checks that all constants in the resource +// file are at least recognised by the code. Derived constants' values or +// hard-coded derivations are not checked. +// In ICU4J, these constants live in UnitConverter.Factor.getConversionRate(). +static const double constantsValues[CONSTANTS_COUNT] = { + 0.3048, // CONSTANT_FT2M + 411557987.0 / 131002976.0, // CONSTANT_PI + 9.80665, // CONSTANT_GRAVITY + 6.67408E-11, // CONSTANT_G + 0.00454609, // CONSTANT_GAL_IMP2M3 + 0.45359237, // CONSTANT_LB2KG + 180.1557, // CONSTANT_GLUCOSE_MOLAR_MASS + 6.02214076E+23, // CONSTANT_ITEM_PER_MOLE + 149597870700, // CONSTANT_METERS_PER_AU + 31557600, // CONSTANT_SEC_PER_JULIAN_YEAR + 299792458, // CONSTANT_SPEED_OF_LIGHT_METERS_PER_SECOND +}; + +typedef enum Signum { + NEGATIVE = -1, + POSITIVE = 1, +} Signum; + +/* Represents a conversion factor */ +struct U_I18N_API Factor { + double factorNum = 1; + double factorDen = 1; + double offset = 0; + bool reciprocal = false; + + // Exponents for the symbolic constants + int32_t constantExponents[CONSTANTS_COUNT] = {}; + + void multiplyBy(const Factor &rhs); + void divideBy(const Factor &rhs); + + // Apply the power to the factor. + void power(int32_t power); + + // Apply SI or binary prefix to the Factor. + void applyPrefix(UMeasurePrefix unitPrefix); + + // Does an in-place substitution of the "symbolic constants" based on + // constantExponents (resetting the exponents). + // + // In ICU4J, see UnitConverter.Factor.getConversionRate(). + void substituteConstants(); +}; + +struct U_I18N_API ConversionInfo { + double conversionRate; + double offset; + bool reciprocal; +}; + +/* + * Adds a single factor element to the `Factor`. e.g "ft3m", "2.333" or "cup2m3". But not "cup2m3^3". + */ +void U_I18N_API addSingleFactorConstant(StringPiece baseStr, int32_t power, Signum sigNum, + Factor &factor, UErrorCode &status); + +/** + * Represents the conversion rate between `source` and `target`. + */ +struct U_I18N_API ConversionRate : public UMemory { + const MeasureUnitImpl source; + const MeasureUnitImpl target; + double factorNum = 1; + double factorDen = 1; + double sourceOffset = 0; + double targetOffset = 0; + bool reciprocal = false; + + ConversionRate(MeasureUnitImpl &&source, MeasureUnitImpl &&target) + : source(std::move(source)), target(std::move(target)) {} +}; + +enum Convertibility { + RECIPROCAL, + CONVERTIBLE, + UNCONVERTIBLE, +}; + +MeasureUnitImpl U_I18N_API extractCompoundBaseUnit(const MeasureUnitImpl &source, + const ConversionRates &conversionRates, + UErrorCode &status); + +/** + * Check if the convertibility between `source` and `target`. + * For example: + * `meter` and `foot` are `CONVERTIBLE`. + * `meter-per-second` and `second-per-meter` are `RECIPROCAL`. + * `meter` and `pound` are `UNCONVERTIBLE`. + * + * NOTE: + * Only works with SINGLE and COMPOUND units. If one of the units is a + * MIXED unit, an error will occur. For more information, see UMeasureUnitComplexity. + */ +Convertibility U_I18N_API extractConvertibility(const MeasureUnitImpl &source, + const MeasureUnitImpl &target, + const ConversionRates &conversionRates, + UErrorCode &status); + +/** + * Converts from a source `MeasureUnit` to a target `MeasureUnit`. + * + * NOTE: + * Only works with SINGLE and COMPOUND units. If one of the units is a + * MIXED unit, an error will occur. For more information, see UMeasureUnitComplexity. + */ +class U_I18N_API UnitsConverter : public UMemory { + public: + /** + * Constructor of `UnitConverter`. + * NOTE: + * - source and target must be under the same category + * - e.g. meter to mile --> both of them are length units. + * NOTE: + * This constructor creates an instance of `ConversionRates` internally. + * + * @param sourceIdentifier represents the source unit identifier. + * @param targetIdentifier represents the target unit identifier. + * @param status + */ + UnitsConverter(StringPiece sourceIdentifier, StringPiece targetIdentifier, UErrorCode &status); + + /** + * Constructor of `UnitConverter`. + * NOTE: + * - source and target must be under the same category + * - e.g. meter to mile --> both of them are length units. + * + * @param source represents the source unit. + * @param target represents the target unit. + * @param ratesInfo Contains all the needed conversion rates. + * @param status + */ + UnitsConverter(const MeasureUnitImpl &source, const MeasureUnitImpl &target, + const ConversionRates &ratesInfo, UErrorCode &status); + + /** + * Compares two single units and returns 1 if the first one is greater, -1 if the second + * one is greater and 0 if they are equal. + * + * NOTE: + * Compares only single units that are convertible. + */ + static int32_t compareTwoUnits(const MeasureUnitImpl &firstUnit, const MeasureUnitImpl &SecondUnit, + const ConversionRates &ratesInfo, UErrorCode &status); + + /** + * Convert a measurement expressed in the source unit to a measurement + * expressed in the target unit. + * + * @param inputValue the value to be converted. + * @return the converted value. + */ + double convert(double inputValue) const; + + /** + * The inverse of convert(): convert a measurement expressed in the target + * unit to a measurement expressed in the source unit. + * + * @param inputValue the value to be converted. + * @return the converted value. + */ + double convertInverse(double inputValue) const; + + ConversionInfo getConversionInfo() const; + + private: + ConversionRate conversionRate_; + + /** + * Initialises the object. + */ + void init(const ConversionRates &ratesInfo, UErrorCode &status); +}; + +} // namespace units +U_NAMESPACE_END + +#endif //__UNITS_CONVERTER_H__ + +#endif /* #if !UCONFIG_NO_FORMATTING */ |