12e5b6d6dSopenharmony_ci// © 2020 and later: Unicode, Inc. and others.
22e5b6d6dSopenharmony_ci// License & terms of use: http://www.unicode.org/copyright.html
32e5b6d6dSopenharmony_ci
42e5b6d6dSopenharmony_ci#include "unicode/utypes.h"
52e5b6d6dSopenharmony_ci
62e5b6d6dSopenharmony_ci#if !UCONFIG_NO_FORMATTING
72e5b6d6dSopenharmony_ci#ifndef __UNITS_CONVERTER_H__
82e5b6d6dSopenharmony_ci#define __UNITS_CONVERTER_H__
92e5b6d6dSopenharmony_ci
102e5b6d6dSopenharmony_ci#include "cmemory.h"
112e5b6d6dSopenharmony_ci#include "measunit_impl.h"
122e5b6d6dSopenharmony_ci#include "unicode/errorcode.h"
132e5b6d6dSopenharmony_ci#include "unicode/stringpiece.h"
142e5b6d6dSopenharmony_ci#include "unicode/uobject.h"
152e5b6d6dSopenharmony_ci#include "units_converter.h"
162e5b6d6dSopenharmony_ci#include "units_data.h"
172e5b6d6dSopenharmony_ci
182e5b6d6dSopenharmony_ciU_NAMESPACE_BEGIN
192e5b6d6dSopenharmony_cinamespace units {
202e5b6d6dSopenharmony_ci
212e5b6d6dSopenharmony_ci/* Internal Structure */
222e5b6d6dSopenharmony_ci
232e5b6d6dSopenharmony_ci// Constants corresponding to unitConstants in CLDR's units.xml.
242e5b6d6dSopenharmony_cienum Constants {
252e5b6d6dSopenharmony_ci    CONSTANT_FT2M,       // ft_to_m
262e5b6d6dSopenharmony_ci    CONSTANT_PI,         // PI
272e5b6d6dSopenharmony_ci    CONSTANT_GRAVITY,    // Gravity of earth (9.80665 m/s^2), "g".
282e5b6d6dSopenharmony_ci    CONSTANT_G,          // Newtonian constant of gravitation, "G".
292e5b6d6dSopenharmony_ci    CONSTANT_GAL_IMP2M3, // Gallon imp to m3
302e5b6d6dSopenharmony_ci    CONSTANT_LB2KG,      // Pound to Kilogram
312e5b6d6dSopenharmony_ci    CONSTANT_GLUCOSE_MOLAR_MASS,
322e5b6d6dSopenharmony_ci    CONSTANT_ITEM_PER_MOLE,
332e5b6d6dSopenharmony_ci    CONSTANT_METERS_PER_AU,
342e5b6d6dSopenharmony_ci    CONSTANT_SEC_PER_JULIAN_YEAR,
352e5b6d6dSopenharmony_ci    CONSTANT_SPEED_OF_LIGHT_METERS_PER_SECOND,
362e5b6d6dSopenharmony_ci
372e5b6d6dSopenharmony_ci    // Must be the last element.
382e5b6d6dSopenharmony_ci    CONSTANTS_COUNT
392e5b6d6dSopenharmony_ci};
402e5b6d6dSopenharmony_ci
412e5b6d6dSopenharmony_ci// These values are a hard-coded subset of unitConstants in the units
422e5b6d6dSopenharmony_ci// resources file. A unit test checks that all constants in the resource
432e5b6d6dSopenharmony_ci// file are at least recognised by the code. Derived constants' values or
442e5b6d6dSopenharmony_ci// hard-coded derivations are not checked.
452e5b6d6dSopenharmony_ci// In ICU4J, these constants live in UnitConverter.Factor.getConversionRate().
462e5b6d6dSopenharmony_cistatic const double constantsValues[CONSTANTS_COUNT] = {
472e5b6d6dSopenharmony_ci    0.3048,                    // CONSTANT_FT2M
482e5b6d6dSopenharmony_ci    411557987.0 / 131002976.0, // CONSTANT_PI
492e5b6d6dSopenharmony_ci    9.80665,                   // CONSTANT_GRAVITY
502e5b6d6dSopenharmony_ci    6.67408E-11,               // CONSTANT_G
512e5b6d6dSopenharmony_ci    0.00454609,                // CONSTANT_GAL_IMP2M3
522e5b6d6dSopenharmony_ci    0.45359237,                // CONSTANT_LB2KG
532e5b6d6dSopenharmony_ci    180.1557,                  // CONSTANT_GLUCOSE_MOLAR_MASS
542e5b6d6dSopenharmony_ci    6.02214076E+23,            // CONSTANT_ITEM_PER_MOLE
552e5b6d6dSopenharmony_ci    149597870700,              // CONSTANT_METERS_PER_AU
562e5b6d6dSopenharmony_ci    31557600,                  // CONSTANT_SEC_PER_JULIAN_YEAR
572e5b6d6dSopenharmony_ci    299792458,                 // CONSTANT_SPEED_OF_LIGHT_METERS_PER_SECOND
582e5b6d6dSopenharmony_ci};
592e5b6d6dSopenharmony_ci
602e5b6d6dSopenharmony_citypedef enum Signum {
612e5b6d6dSopenharmony_ci    NEGATIVE = -1,
622e5b6d6dSopenharmony_ci    POSITIVE = 1,
632e5b6d6dSopenharmony_ci} Signum;
642e5b6d6dSopenharmony_ci
652e5b6d6dSopenharmony_ci/* Represents a conversion factor */
662e5b6d6dSopenharmony_cistruct U_I18N_API Factor {
672e5b6d6dSopenharmony_ci    double factorNum = 1;
682e5b6d6dSopenharmony_ci    double factorDen = 1;
692e5b6d6dSopenharmony_ci    double offset = 0;
702e5b6d6dSopenharmony_ci    bool reciprocal = false;
712e5b6d6dSopenharmony_ci
722e5b6d6dSopenharmony_ci    // Exponents for the symbolic constants
732e5b6d6dSopenharmony_ci    int32_t constantExponents[CONSTANTS_COUNT] = {};
742e5b6d6dSopenharmony_ci
752e5b6d6dSopenharmony_ci    void multiplyBy(const Factor &rhs);
762e5b6d6dSopenharmony_ci    void divideBy(const Factor &rhs);
772e5b6d6dSopenharmony_ci
782e5b6d6dSopenharmony_ci    // Apply the power to the factor.
792e5b6d6dSopenharmony_ci    void power(int32_t power);
802e5b6d6dSopenharmony_ci
812e5b6d6dSopenharmony_ci    // Apply SI or binary prefix to the Factor.
822e5b6d6dSopenharmony_ci    void applyPrefix(UMeasurePrefix unitPrefix);
832e5b6d6dSopenharmony_ci
842e5b6d6dSopenharmony_ci    // Does an in-place substitution of the "symbolic constants" based on
852e5b6d6dSopenharmony_ci    // constantExponents (resetting the exponents).
862e5b6d6dSopenharmony_ci    //
872e5b6d6dSopenharmony_ci    // In ICU4J, see UnitConverter.Factor.getConversionRate().
882e5b6d6dSopenharmony_ci    void substituteConstants();
892e5b6d6dSopenharmony_ci};
902e5b6d6dSopenharmony_ci
912e5b6d6dSopenharmony_cistruct U_I18N_API ConversionInfo {
922e5b6d6dSopenharmony_ci    double conversionRate;
932e5b6d6dSopenharmony_ci    double offset;
942e5b6d6dSopenharmony_ci    bool reciprocal;
952e5b6d6dSopenharmony_ci};
962e5b6d6dSopenharmony_ci
972e5b6d6dSopenharmony_ci/*
982e5b6d6dSopenharmony_ci * Adds a single factor element to the `Factor`. e.g "ft3m", "2.333" or "cup2m3". But not "cup2m3^3".
992e5b6d6dSopenharmony_ci */
1002e5b6d6dSopenharmony_civoid U_I18N_API addSingleFactorConstant(StringPiece baseStr, int32_t power, Signum sigNum,
1012e5b6d6dSopenharmony_ci                                        Factor &factor, UErrorCode &status);
1022e5b6d6dSopenharmony_ci
1032e5b6d6dSopenharmony_ci/**
1042e5b6d6dSopenharmony_ci * Represents the conversion rate between `source` and `target`.
1052e5b6d6dSopenharmony_ci */
1062e5b6d6dSopenharmony_cistruct U_I18N_API ConversionRate : public UMemory {
1072e5b6d6dSopenharmony_ci    const MeasureUnitImpl source;
1082e5b6d6dSopenharmony_ci    const MeasureUnitImpl target;
1092e5b6d6dSopenharmony_ci    double factorNum = 1;
1102e5b6d6dSopenharmony_ci    double factorDen = 1;
1112e5b6d6dSopenharmony_ci    double sourceOffset = 0;
1122e5b6d6dSopenharmony_ci    double targetOffset = 0;
1132e5b6d6dSopenharmony_ci    bool reciprocal = false;
1142e5b6d6dSopenharmony_ci
1152e5b6d6dSopenharmony_ci    ConversionRate(MeasureUnitImpl &&source, MeasureUnitImpl &&target)
1162e5b6d6dSopenharmony_ci        : source(std::move(source)), target(std::move(target)) {}
1172e5b6d6dSopenharmony_ci};
1182e5b6d6dSopenharmony_ci
1192e5b6d6dSopenharmony_cienum Convertibility {
1202e5b6d6dSopenharmony_ci    RECIPROCAL,
1212e5b6d6dSopenharmony_ci    CONVERTIBLE,
1222e5b6d6dSopenharmony_ci    UNCONVERTIBLE,
1232e5b6d6dSopenharmony_ci};
1242e5b6d6dSopenharmony_ci
1252e5b6d6dSopenharmony_ciMeasureUnitImpl U_I18N_API extractCompoundBaseUnit(const MeasureUnitImpl &source,
1262e5b6d6dSopenharmony_ci                                                   const ConversionRates &conversionRates,
1272e5b6d6dSopenharmony_ci                                                   UErrorCode &status);
1282e5b6d6dSopenharmony_ci
1292e5b6d6dSopenharmony_ci/**
1302e5b6d6dSopenharmony_ci * Check if the convertibility between `source` and `target`.
1312e5b6d6dSopenharmony_ci * For example:
1322e5b6d6dSopenharmony_ci *    `meter` and `foot` are `CONVERTIBLE`.
1332e5b6d6dSopenharmony_ci *    `meter-per-second` and `second-per-meter` are `RECIPROCAL`.
1342e5b6d6dSopenharmony_ci *    `meter` and `pound` are `UNCONVERTIBLE`.
1352e5b6d6dSopenharmony_ci *
1362e5b6d6dSopenharmony_ci * NOTE:
1372e5b6d6dSopenharmony_ci *    Only works with SINGLE and COMPOUND units. If one of the units is a
1382e5b6d6dSopenharmony_ci *    MIXED unit, an error will occur. For more information, see UMeasureUnitComplexity.
1392e5b6d6dSopenharmony_ci */
1402e5b6d6dSopenharmony_ciConvertibility U_I18N_API extractConvertibility(const MeasureUnitImpl &source,
1412e5b6d6dSopenharmony_ci                                                const MeasureUnitImpl &target,
1422e5b6d6dSopenharmony_ci                                                const ConversionRates &conversionRates,
1432e5b6d6dSopenharmony_ci                                                UErrorCode &status);
1442e5b6d6dSopenharmony_ci
1452e5b6d6dSopenharmony_ci/**
1462e5b6d6dSopenharmony_ci * Converts from a source `MeasureUnit` to a target `MeasureUnit`.
1472e5b6d6dSopenharmony_ci *
1482e5b6d6dSopenharmony_ci * NOTE:
1492e5b6d6dSopenharmony_ci *    Only works with SINGLE and COMPOUND units. If one of the units is a
1502e5b6d6dSopenharmony_ci *    MIXED unit, an error will occur. For more information, see UMeasureUnitComplexity.
1512e5b6d6dSopenharmony_ci */
1522e5b6d6dSopenharmony_ciclass U_I18N_API UnitsConverter : public UMemory {
1532e5b6d6dSopenharmony_ci  public:
1542e5b6d6dSopenharmony_ci    /**
1552e5b6d6dSopenharmony_ci     * Constructor of `UnitConverter`.
1562e5b6d6dSopenharmony_ci     * NOTE:
1572e5b6d6dSopenharmony_ci     *   - source and target must be under the same category
1582e5b6d6dSopenharmony_ci     *      - e.g. meter to mile --> both of them are length units.
1592e5b6d6dSopenharmony_ci     * NOTE:
1602e5b6d6dSopenharmony_ci     *    This constructor creates an instance of `ConversionRates` internally.
1612e5b6d6dSopenharmony_ci     *
1622e5b6d6dSopenharmony_ci     * @param sourceIdentifier represents the source unit identifier.
1632e5b6d6dSopenharmony_ci     * @param targetIdentifier represents the target unit identifier.
1642e5b6d6dSopenharmony_ci     * @param status
1652e5b6d6dSopenharmony_ci     */
1662e5b6d6dSopenharmony_ci    UnitsConverter(StringPiece sourceIdentifier, StringPiece targetIdentifier, UErrorCode &status);
1672e5b6d6dSopenharmony_ci
1682e5b6d6dSopenharmony_ci    /**
1692e5b6d6dSopenharmony_ci     * Constructor of `UnitConverter`.
1702e5b6d6dSopenharmony_ci     * NOTE:
1712e5b6d6dSopenharmony_ci     *   - source and target must be under the same category
1722e5b6d6dSopenharmony_ci     *      - e.g. meter to mile --> both of them are length units.
1732e5b6d6dSopenharmony_ci     *
1742e5b6d6dSopenharmony_ci     * @param source represents the source unit.
1752e5b6d6dSopenharmony_ci     * @param target represents the target unit.
1762e5b6d6dSopenharmony_ci     * @param ratesInfo Contains all the needed conversion rates.
1772e5b6d6dSopenharmony_ci     * @param status
1782e5b6d6dSopenharmony_ci     */
1792e5b6d6dSopenharmony_ci    UnitsConverter(const MeasureUnitImpl &source, const MeasureUnitImpl &target,
1802e5b6d6dSopenharmony_ci                  const ConversionRates &ratesInfo, UErrorCode &status);
1812e5b6d6dSopenharmony_ci
1822e5b6d6dSopenharmony_ci    /**
1832e5b6d6dSopenharmony_ci     * Compares two single units and returns 1 if the first one is greater, -1 if the second
1842e5b6d6dSopenharmony_ci     * one is greater and 0 if they are equal.
1852e5b6d6dSopenharmony_ci     *
1862e5b6d6dSopenharmony_ci     * NOTE:
1872e5b6d6dSopenharmony_ci     *  Compares only single units that are convertible.
1882e5b6d6dSopenharmony_ci     */
1892e5b6d6dSopenharmony_ci    static int32_t compareTwoUnits(const MeasureUnitImpl &firstUnit, const MeasureUnitImpl &SecondUnit,
1902e5b6d6dSopenharmony_ci                                   const ConversionRates &ratesInfo, UErrorCode &status);
1912e5b6d6dSopenharmony_ci
1922e5b6d6dSopenharmony_ci    /**
1932e5b6d6dSopenharmony_ci     * Convert a measurement expressed in the source unit to a measurement
1942e5b6d6dSopenharmony_ci     * expressed in the target unit.
1952e5b6d6dSopenharmony_ci     *
1962e5b6d6dSopenharmony_ci     * @param inputValue the value to be converted.
1972e5b6d6dSopenharmony_ci     * @return the converted value.
1982e5b6d6dSopenharmony_ci     */
1992e5b6d6dSopenharmony_ci    double convert(double inputValue) const;
2002e5b6d6dSopenharmony_ci
2012e5b6d6dSopenharmony_ci    /**
2022e5b6d6dSopenharmony_ci     * The inverse of convert(): convert a measurement expressed in the target
2032e5b6d6dSopenharmony_ci     * unit to a measurement expressed in the source unit.
2042e5b6d6dSopenharmony_ci     *
2052e5b6d6dSopenharmony_ci     * @param inputValue the value to be converted.
2062e5b6d6dSopenharmony_ci     * @return the converted value.
2072e5b6d6dSopenharmony_ci     */
2082e5b6d6dSopenharmony_ci    double convertInverse(double inputValue) const;
2092e5b6d6dSopenharmony_ci
2102e5b6d6dSopenharmony_ci    ConversionInfo getConversionInfo() const;
2112e5b6d6dSopenharmony_ci
2122e5b6d6dSopenharmony_ci  private:
2132e5b6d6dSopenharmony_ci    ConversionRate conversionRate_;
2142e5b6d6dSopenharmony_ci
2152e5b6d6dSopenharmony_ci    /**
2162e5b6d6dSopenharmony_ci     * Initialises the object.
2172e5b6d6dSopenharmony_ci     */
2182e5b6d6dSopenharmony_ci    void init(const ConversionRates &ratesInfo, UErrorCode &status);
2192e5b6d6dSopenharmony_ci};
2202e5b6d6dSopenharmony_ci
2212e5b6d6dSopenharmony_ci} // namespace units
2222e5b6d6dSopenharmony_ciU_NAMESPACE_END
2232e5b6d6dSopenharmony_ci
2242e5b6d6dSopenharmony_ci#endif //__UNITS_CONVERTER_H__
2252e5b6d6dSopenharmony_ci
2262e5b6d6dSopenharmony_ci#endif /* #if !UCONFIG_NO_FORMATTING */
227