units_complexconverter.h (5489B)
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_COMPLEXCONVERTER_H__ 8 #define __UNITS_COMPLEXCONVERTER_H__ 9 10 #include "cmemory.h" 11 #include "measunit_impl.h" 12 #include "number_roundingutils.h" 13 #include "unicode/errorcode.h" 14 #include "unicode/measure.h" 15 #include "units_converter.h" 16 #include "units_data.h" 17 18 U_NAMESPACE_BEGIN 19 20 namespace units { 21 22 /** 23 * Converts from single or compound unit to single, compound or mixed units. 24 * For example, from `meter` to `foot+inch`. 25 * 26 * DESIGN: 27 * This class uses `UnitsConverter` in order to perform the single converter (i.e. converters from a 28 * single unit to another single unit). Therefore, `ComplexUnitsConverter` class contains multiple 29 * instances of the `UnitsConverter` to perform the conversion. 30 */ 31 class U_I18N_API_CLASS ComplexUnitsConverter : public UMemory { 32 public: 33 /** 34 * Constructs `ComplexUnitsConverter` for an `targetUnit` that could be Single, Compound or Mixed. 35 * In case of: 36 * 1- Single and Compound units, 37 * the conversion will not perform anything, the input will be equal to the output. 38 * 2- Mixed Unit 39 * the conversion will consider the input is the biggest unit. And will convert it to be spread 40 * through the target units. For example: if target unit is "inch-and-foot", and the input is 2.5. 41 * The converter will consider the input value in "foot", because foot is the biggest unit. 42 * Then, it will convert 2.5 feet to "inch-and-foot". 43 * 44 * @param targetUnit could be any units type (single, compound or mixed). 45 * @param ratesInfo 46 * @param status 47 */ 48 ComplexUnitsConverter(const MeasureUnitImpl &targetUnit, const ConversionRates &ratesInfo, 49 UErrorCode &status); 50 /** 51 * Constructor of `ComplexUnitsConverter`. 52 * NOTE: 53 * - inputUnit and outputUnits must be under the same category 54 * - e.g. meter to feet and inches --> all of them are length units. 55 * 56 * @param inputUnit represents the source unit. (should be single or compound unit). 57 * @param outputUnits represents the output unit. could be any type. (single, compound or mixed). 58 * @param status 59 */ 60 U_I18N_API ComplexUnitsConverter(StringPiece inputUnitIdentifier, 61 StringPiece outputUnitsIdentifier, 62 UErrorCode &status); 63 64 /** 65 * Constructor of `ComplexUnitsConverter`. 66 * NOTE: 67 * - inputUnit and outputUnits must be under the same category 68 * - e.g. meter to feet and inches --> all of them are length units. 69 * 70 * @param inputUnit represents the source unit. (should be single or compound unit). 71 * @param outputUnits represents the output unit. could be any type. (single, compound or mixed). 72 * @param ratesInfo a ConversionRates instance containing the unit conversion rates. 73 * @param status 74 */ 75 U_I18N_API ComplexUnitsConverter(const MeasureUnitImpl &inputUnit, 76 const MeasureUnitImpl &outputUnits, 77 const ConversionRates &ratesInfo, 78 UErrorCode &status); 79 80 // Returns true if the specified `quantity` of the `inputUnit`, expressed in terms of the biggest 81 // unit in the MeasureUnit `outputUnit`, is greater than or equal to `limit`. 82 // For example, if the input unit is `meter` and the target unit is `foot+inch`. Therefore, this 83 // function will convert the `quantity` from `meter` to `foot`, then, it will compare the value in 84 // `foot` with the `limit`. 85 UBool greaterThanOrEqual(double quantity, double limit) const; 86 87 // Returns outputMeasures which is an array with the corresponding values. 88 // - E.g. converting meters to feet and inches. 89 // 1 meter --> 3 feet, 3.3701 inches 90 // NOTE: 91 // the smallest element is the only element that could have fractional values. And all 92 // other elements are floored to the nearest integer 93 U_I18N_API MaybeStackVector<Measure> 94 convert(double quantity, icu::number::impl::RoundingImpl *rounder, UErrorCode &status) const; 95 96 // TODO(ICU-21937): Make it private after submitting the public units conversion API. 97 MaybeStackVector<UnitsConverter> unitsConverters_; 98 99 // TODO(ICU-21937): Make it private after submitting the public units conversion API. 100 // Individual units of mixed units, sorted big to small, with indices 101 // indicating the requested output mixed unit order. 102 MaybeStackVector<MeasureUnitImplWithIndex> units_; 103 104 private: 105 // Sorts units_, which must be populated before calling this, and populates 106 // unitsConverters_. 107 void init(const MeasureUnitImpl &inputUnit, const ConversionRates &ratesInfo, UErrorCode &status); 108 109 // Applies the rounder to the quantity (last element) and bubble up any carried value to all the 110 // intValues. 111 // TODO(ICU-21288): get smarter about precision for mixed units. 112 void applyRounder(MaybeStackArray<int64_t, 5> &intValues, double &quantity, 113 icu::number::impl::RoundingImpl *rounder, UErrorCode &status) const; 114 }; 115 116 } // namespace units 117 U_NAMESPACE_END 118 119 #endif //__UNITS_COMPLEXCONVERTER_H__ 120 121 #endif /* #if !UCONFIG_NO_FORMATTING */