1*0e209d39SAndroid Build Coastguard Worker // © 2020 and later: Unicode, Inc. and others. 2*0e209d39SAndroid Build Coastguard Worker // License & terms of use: http://www.unicode.org/copyright.html 3*0e209d39SAndroid Build Coastguard Worker 4*0e209d39SAndroid Build Coastguard Worker #include "unicode/utypes.h" 5*0e209d39SAndroid Build Coastguard Worker 6*0e209d39SAndroid Build Coastguard Worker #if !UCONFIG_NO_FORMATTING 7*0e209d39SAndroid Build Coastguard Worker #ifndef __UNITS_ROUTER_H__ 8*0e209d39SAndroid Build Coastguard Worker #define __UNITS_ROUTER_H__ 9*0e209d39SAndroid Build Coastguard Worker 10*0e209d39SAndroid Build Coastguard Worker #include <limits> 11*0e209d39SAndroid Build Coastguard Worker 12*0e209d39SAndroid Build Coastguard Worker #include "cmemory.h" 13*0e209d39SAndroid Build Coastguard Worker #include "measunit_impl.h" 14*0e209d39SAndroid Build Coastguard Worker #include "unicode/locid.h" 15*0e209d39SAndroid Build Coastguard Worker #include "unicode/measunit.h" 16*0e209d39SAndroid Build Coastguard Worker #include "unicode/stringpiece.h" 17*0e209d39SAndroid Build Coastguard Worker #include "unicode/uobject.h" 18*0e209d39SAndroid Build Coastguard Worker #include "units_complexconverter.h" 19*0e209d39SAndroid Build Coastguard Worker #include "units_data.h" 20*0e209d39SAndroid Build Coastguard Worker 21*0e209d39SAndroid Build Coastguard Worker U_NAMESPACE_BEGIN 22*0e209d39SAndroid Build Coastguard Worker 23*0e209d39SAndroid Build Coastguard Worker // Forward declarations 24*0e209d39SAndroid Build Coastguard Worker class Measure; 25*0e209d39SAndroid Build Coastguard Worker namespace number { 26*0e209d39SAndroid Build Coastguard Worker class Precision; 27*0e209d39SAndroid Build Coastguard Worker } 28*0e209d39SAndroid Build Coastguard Worker 29*0e209d39SAndroid Build Coastguard Worker namespace units { 30*0e209d39SAndroid Build Coastguard Worker 31*0e209d39SAndroid Build Coastguard Worker struct RouteResult : UMemory { 32*0e209d39SAndroid Build Coastguard Worker // A list of measures: a single measure for single units, multiple measures 33*0e209d39SAndroid Build Coastguard Worker // for mixed units. 34*0e209d39SAndroid Build Coastguard Worker MaybeStackVector<Measure> measures; 35*0e209d39SAndroid Build Coastguard Worker 36*0e209d39SAndroid Build Coastguard Worker // The output unit for this RouteResult. This may be a MIXED unit - for 37*0e209d39SAndroid Build Coastguard Worker // example: "yard-and-foot-and-inch", for which `measures` will have three 38*0e209d39SAndroid Build Coastguard Worker // elements. 39*0e209d39SAndroid Build Coastguard Worker MeasureUnitImpl outputUnit; 40*0e209d39SAndroid Build Coastguard Worker RouteResultRouteResult41*0e209d39SAndroid Build Coastguard Worker RouteResult(MaybeStackVector<Measure> measures, MeasureUnitImpl outputUnit) 42*0e209d39SAndroid Build Coastguard Worker : measures(std::move(measures)), outputUnit(std::move(outputUnit)) {} 43*0e209d39SAndroid Build Coastguard Worker }; 44*0e209d39SAndroid Build Coastguard Worker 45*0e209d39SAndroid Build Coastguard Worker /** 46*0e209d39SAndroid Build Coastguard Worker * Contains the complex unit converter and the limit which representing the smallest value that the 47*0e209d39SAndroid Build Coastguard Worker * converter should accept. For example, if the converter is converting to `foot+inch` and the limit 48*0e209d39SAndroid Build Coastguard Worker * equals 3.0, thus means the converter should not convert to a value less than `3.0 feet`. 49*0e209d39SAndroid Build Coastguard Worker * 50*0e209d39SAndroid Build Coastguard Worker * NOTE: 51*0e209d39SAndroid Build Coastguard Worker * if the limit doest not has a value `i.e. (std::numeric_limits<double>::lowest())`, this mean there 52*0e209d39SAndroid Build Coastguard Worker * is no limit for the converter. 53*0e209d39SAndroid Build Coastguard Worker */ 54*0e209d39SAndroid Build Coastguard Worker struct ConverterPreference : UMemory { 55*0e209d39SAndroid Build Coastguard Worker ComplexUnitsConverter converter; 56*0e209d39SAndroid Build Coastguard Worker double limit; 57*0e209d39SAndroid Build Coastguard Worker UnicodeString precision; 58*0e209d39SAndroid Build Coastguard Worker 59*0e209d39SAndroid Build Coastguard Worker // The output unit for this ConverterPreference. This may be a MIXED unit - 60*0e209d39SAndroid Build Coastguard Worker // for example: "yard-and-foot-and-inch". 61*0e209d39SAndroid Build Coastguard Worker MeasureUnitImpl targetUnit; 62*0e209d39SAndroid Build Coastguard Worker 63*0e209d39SAndroid Build Coastguard Worker // In case there is no limit, the limit will be -inf. ConverterPreferenceConverterPreference64*0e209d39SAndroid Build Coastguard Worker ConverterPreference(const MeasureUnitImpl &source, const MeasureUnitImpl &complexTarget, 65*0e209d39SAndroid Build Coastguard Worker UnicodeString precision, const ConversionRates &ratesInfo, UErrorCode &status) 66*0e209d39SAndroid Build Coastguard Worker : ConverterPreference(source, complexTarget, std::numeric_limits<double>::lowest(), precision, 67*0e209d39SAndroid Build Coastguard Worker ratesInfo, status) {} 68*0e209d39SAndroid Build Coastguard Worker ConverterPreferenceConverterPreference69*0e209d39SAndroid Build Coastguard Worker ConverterPreference(const MeasureUnitImpl &source, const MeasureUnitImpl &complexTarget, 70*0e209d39SAndroid Build Coastguard Worker double limit, UnicodeString precision, const ConversionRates &ratesInfo, 71*0e209d39SAndroid Build Coastguard Worker UErrorCode &status) 72*0e209d39SAndroid Build Coastguard Worker : converter(source, complexTarget, ratesInfo, status), limit(limit), 73*0e209d39SAndroid Build Coastguard Worker precision(std::move(precision)), targetUnit(complexTarget.copy(status)) {} 74*0e209d39SAndroid Build Coastguard Worker }; 75*0e209d39SAndroid Build Coastguard Worker 76*0e209d39SAndroid Build Coastguard Worker } // namespace units 77*0e209d39SAndroid Build Coastguard Worker 78*0e209d39SAndroid Build Coastguard Worker // Export explicit template instantiations of MaybeStackArray, MemoryPool and 79*0e209d39SAndroid Build Coastguard Worker // MaybeStackVector. This is required when building DLLs for Windows. (See 80*0e209d39SAndroid Build Coastguard Worker // datefmt.h, collationiterator.h, erarules.h and others for similar examples.) 81*0e209d39SAndroid Build Coastguard Worker // 82*0e209d39SAndroid Build Coastguard Worker // Note: These need to be outside of the units namespace, or Clang will generate 83*0e209d39SAndroid Build Coastguard Worker // a compile error. 84*0e209d39SAndroid Build Coastguard Worker #if U_PF_WINDOWS <= U_PLATFORM && U_PLATFORM <= U_PF_CYGWIN 85*0e209d39SAndroid Build Coastguard Worker template class U_I18N_API MaybeStackArray<units::ConverterPreference*, 8>; 86*0e209d39SAndroid Build Coastguard Worker template class U_I18N_API MemoryPool<units::ConverterPreference, 8>; 87*0e209d39SAndroid Build Coastguard Worker template class U_I18N_API MaybeStackVector<units::ConverterPreference, 8>; 88*0e209d39SAndroid Build Coastguard Worker #endif 89*0e209d39SAndroid Build Coastguard Worker 90*0e209d39SAndroid Build Coastguard Worker namespace units { 91*0e209d39SAndroid Build Coastguard Worker 92*0e209d39SAndroid Build Coastguard Worker /** 93*0e209d39SAndroid Build Coastguard Worker * `UnitsRouter` responsible for converting from a single unit (such as `meter` or `meter-per-second`) to 94*0e209d39SAndroid Build Coastguard Worker * one of the complex units based on the limits. 95*0e209d39SAndroid Build Coastguard Worker * For example: 96*0e209d39SAndroid Build Coastguard Worker * if the input is `meter` and the output as following 97*0e209d39SAndroid Build Coastguard Worker * {`foot+inch`, limit: 3.0} 98*0e209d39SAndroid Build Coastguard Worker * {`inch` , limit: no value (-inf)} 99*0e209d39SAndroid Build Coastguard Worker * Thus means if the input in `meter` is greater than or equal to `3.0 feet`, the output will be in 100*0e209d39SAndroid Build Coastguard Worker * `foot+inch`, otherwise, the output will be in `inch`. 101*0e209d39SAndroid Build Coastguard Worker * 102*0e209d39SAndroid Build Coastguard Worker * NOTE: 103*0e209d39SAndroid Build Coastguard Worker * the output units and the their limits MUST BE in order, for example, if the output units, from the 104*0e209d39SAndroid Build Coastguard Worker * previous example, are the following: 105*0e209d39SAndroid Build Coastguard Worker * {`inch` , limit: no value (-inf)} 106*0e209d39SAndroid Build Coastguard Worker * {`foot+inch`, limit: 3.0} 107*0e209d39SAndroid Build Coastguard Worker * IN THIS CASE THE OUTPUT WILL BE ALWAYS IN `inch`. 108*0e209d39SAndroid Build Coastguard Worker * 109*0e209d39SAndroid Build Coastguard Worker * NOTE: 110*0e209d39SAndroid Build Coastguard Worker * the output units and their limits will be extracted from the units preferences database by knowing 111*0e209d39SAndroid Build Coastguard Worker * the following: 112*0e209d39SAndroid Build Coastguard Worker * - input unit 113*0e209d39SAndroid Build Coastguard Worker * - locale 114*0e209d39SAndroid Build Coastguard Worker * - usage 115*0e209d39SAndroid Build Coastguard Worker * 116*0e209d39SAndroid Build Coastguard Worker * DESIGN: 117*0e209d39SAndroid Build Coastguard Worker * `UnitRouter` uses internally `ComplexUnitConverter` in order to convert the input units to the 118*0e209d39SAndroid Build Coastguard Worker * desired complex units and to check the limit too. 119*0e209d39SAndroid Build Coastguard Worker */ 120*0e209d39SAndroid Build Coastguard Worker class U_I18N_API UnitsRouter { 121*0e209d39SAndroid Build Coastguard Worker public: 122*0e209d39SAndroid Build Coastguard Worker UnitsRouter(StringPiece inputUnitIdentifier, const Locale &locale, StringPiece usage, 123*0e209d39SAndroid Build Coastguard Worker UErrorCode &status); 124*0e209d39SAndroid Build Coastguard Worker UnitsRouter(const MeasureUnit &inputUnit, const Locale &locale, StringPiece usage, 125*0e209d39SAndroid Build Coastguard Worker UErrorCode &status); 126*0e209d39SAndroid Build Coastguard Worker 127*0e209d39SAndroid Build Coastguard Worker /** 128*0e209d39SAndroid Build Coastguard Worker * Performs locale and usage sensitive unit conversion. 129*0e209d39SAndroid Build Coastguard Worker * @param quantity The quantity to convert, expressed in terms of inputUnit. 130*0e209d39SAndroid Build Coastguard Worker * @param rounder If not null, this RoundingImpl will be used to do rounding 131*0e209d39SAndroid Build Coastguard Worker * on the converted value. If the rounder lacks an fPrecision, the 132*0e209d39SAndroid Build Coastguard Worker * rounder will be modified to use the preferred precision for the usage 133*0e209d39SAndroid Build Coastguard Worker * and locale preference, alternatively with the default precision. 134*0e209d39SAndroid Build Coastguard Worker * @param status Receives status. 135*0e209d39SAndroid Build Coastguard Worker */ 136*0e209d39SAndroid Build Coastguard Worker RouteResult route(double quantity, icu::number::impl::RoundingImpl *rounder, UErrorCode &status) const; 137*0e209d39SAndroid Build Coastguard Worker 138*0e209d39SAndroid Build Coastguard Worker /** 139*0e209d39SAndroid Build Coastguard Worker * Returns the list of possible output units, i.e. the full set of 140*0e209d39SAndroid Build Coastguard Worker * preferences, for the localized, usage-specific unit preferences. 141*0e209d39SAndroid Build Coastguard Worker * 142*0e209d39SAndroid Build Coastguard Worker * The returned pointer should be valid for the lifetime of the 143*0e209d39SAndroid Build Coastguard Worker * UnitsRouter instance. 144*0e209d39SAndroid Build Coastguard Worker */ 145*0e209d39SAndroid Build Coastguard Worker const MaybeStackVector<MeasureUnit> *getOutputUnits() const; 146*0e209d39SAndroid Build Coastguard Worker 147*0e209d39SAndroid Build Coastguard Worker private: 148*0e209d39SAndroid Build Coastguard Worker // List of possible output units. TODO: converterPreferences_ now also has 149*0e209d39SAndroid Build Coastguard Worker // this data available. Maybe drop outputUnits_ and have getOutputUnits 150*0e209d39SAndroid Build Coastguard Worker // construct a the list from data in converterPreferences_ instead? 151*0e209d39SAndroid Build Coastguard Worker MaybeStackVector<MeasureUnit> outputUnits_; 152*0e209d39SAndroid Build Coastguard Worker 153*0e209d39SAndroid Build Coastguard Worker MaybeStackVector<ConverterPreference> converterPreferences_; 154*0e209d39SAndroid Build Coastguard Worker 155*0e209d39SAndroid Build Coastguard Worker static number::Precision parseSkeletonToPrecision(icu::UnicodeString precisionSkeleton, 156*0e209d39SAndroid Build Coastguard Worker UErrorCode &status); 157*0e209d39SAndroid Build Coastguard Worker 158*0e209d39SAndroid Build Coastguard Worker void init(const MeasureUnit &inputUnit, const Locale &locale, StringPiece usage, UErrorCode &status); 159*0e209d39SAndroid Build Coastguard Worker }; 160*0e209d39SAndroid Build Coastguard Worker 161*0e209d39SAndroid Build Coastguard Worker } // namespace units 162*0e209d39SAndroid Build Coastguard Worker U_NAMESPACE_END 163*0e209d39SAndroid Build Coastguard Worker 164*0e209d39SAndroid Build Coastguard Worker #endif //__UNITS_ROUTER_H__ 165*0e209d39SAndroid Build Coastguard Worker 166*0e209d39SAndroid Build Coastguard Worker #endif /* #if !UCONFIG_NO_FORMATTING */ 167