tor-browser

The Tor Browser
git clone https://git.dasho.dev/tor-browser.git
Log | Files | Refs | README | LICENSE

units_router.h (5897B)


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