diff options
Diffstat (limited to '')
-rw-r--r-- | intl/icu/source/i18n/units_router.h | 166 |
1 files changed, 166 insertions, 0 deletions
diff --git a/intl/icu/source/i18n/units_router.h b/intl/icu/source/i18n/units_router.h new file mode 100644 index 0000000000..978fdf91fd --- /dev/null +++ b/intl/icu/source/i18n/units_router.h @@ -0,0 +1,166 @@ +// © 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_ROUTER_H__ +#define __UNITS_ROUTER_H__ + +#include <limits> + +#include "cmemory.h" +#include "measunit_impl.h" +#include "unicode/locid.h" +#include "unicode/measunit.h" +#include "unicode/stringpiece.h" +#include "unicode/uobject.h" +#include "units_complexconverter.h" +#include "units_data.h" + +U_NAMESPACE_BEGIN + +// Forward declarations +class Measure; +namespace number { +class Precision; +} + +namespace units { + +struct RouteResult : UMemory { + // A list of measures: a single measure for single units, multiple measures + // for mixed units. + MaybeStackVector<Measure> measures; + + // The output unit for this RouteResult. This may be a MIXED unit - for + // example: "yard-and-foot-and-inch", for which `measures` will have three + // elements. + MeasureUnitImpl outputUnit; + + RouteResult(MaybeStackVector<Measure> measures, MeasureUnitImpl outputUnit) + : measures(std::move(measures)), outputUnit(std::move(outputUnit)) {} +}; + +/** + * Contains the complex unit converter and the limit which representing the smallest value that the + * converter should accept. For example, if the converter is converting to `foot+inch` and the limit + * equals 3.0, thus means the converter should not convert to a value less than `3.0 feet`. + * + * NOTE: + * if the limit doest not has a value `i.e. (std::numeric_limits<double>::lowest())`, this mean there + * is no limit for the converter. + */ +struct ConverterPreference : UMemory { + ComplexUnitsConverter converter; + double limit; + UnicodeString precision; + + // The output unit for this ConverterPreference. This may be a MIXED unit - + // for example: "yard-and-foot-and-inch". + MeasureUnitImpl targetUnit; + + // In case there is no limit, the limit will be -inf. + ConverterPreference(const MeasureUnitImpl &source, const MeasureUnitImpl &complexTarget, + UnicodeString precision, const ConversionRates &ratesInfo, UErrorCode &status) + : ConverterPreference(source, complexTarget, std::numeric_limits<double>::lowest(), precision, + ratesInfo, status) {} + + ConverterPreference(const MeasureUnitImpl &source, const MeasureUnitImpl &complexTarget, + double limit, UnicodeString precision, const ConversionRates &ratesInfo, + UErrorCode &status) + : converter(source, complexTarget, ratesInfo, status), limit(limit), + precision(std::move(precision)), targetUnit(complexTarget.copy(status)) {} +}; + +} // namespace units + +// Export explicit template instantiations of MaybeStackArray, MemoryPool and +// MaybeStackVector. This is required when building DLLs for Windows. (See +// datefmt.h, collationiterator.h, erarules.h and others for similar examples.) +// +// Note: These need to be outside of the units namespace, or Clang will generate +// a compile error. +#if U_PF_WINDOWS <= U_PLATFORM && U_PLATFORM <= U_PF_CYGWIN +template class U_I18N_API MaybeStackArray<units::ConverterPreference*, 8>; +template class U_I18N_API MemoryPool<units::ConverterPreference, 8>; +template class U_I18N_API MaybeStackVector<units::ConverterPreference, 8>; +#endif + +namespace units { + +/** + * `UnitsRouter` responsible for converting from a single unit (such as `meter` or `meter-per-second`) to + * one of the complex units based on the limits. + * For example: + * if the input is `meter` and the output as following + * {`foot+inch`, limit: 3.0} + * {`inch` , limit: no value (-inf)} + * Thus means if the input in `meter` is greater than or equal to `3.0 feet`, the output will be in + * `foot+inch`, otherwise, the output will be in `inch`. + * + * NOTE: + * the output units and the their limits MUST BE in order, for example, if the output units, from the + * previous example, are the following: + * {`inch` , limit: no value (-inf)} + * {`foot+inch`, limit: 3.0} + * IN THIS CASE THE OUTPUT WILL BE ALWAYS IN `inch`. + * + * NOTE: + * the output units and their limits will be extracted from the units preferences database by knowing + * the following: + * - input unit + * - locale + * - usage + * + * DESIGN: + * `UnitRouter` uses internally `ComplexUnitConverter` in order to convert the input units to the + * desired complex units and to check the limit too. + */ +class U_I18N_API UnitsRouter { + public: + UnitsRouter(StringPiece inputUnitIdentifier, const Locale &locale, StringPiece usage, + UErrorCode &status); + UnitsRouter(const MeasureUnit &inputUnit, const Locale &locale, StringPiece usage, + UErrorCode &status); + + /** + * Performs locale and usage sensitive unit conversion. + * @param quantity The quantity to convert, expressed in terms of inputUnit. + * @param rounder If not null, this RoundingImpl will be used to do rounding + * on the converted value. If the rounder lacks an fPrecision, the + * rounder will be modified to use the preferred precision for the usage + * and locale preference, alternatively with the default precision. + * @param status Receives status. + */ + RouteResult route(double quantity, icu::number::impl::RoundingImpl *rounder, UErrorCode &status) const; + + /** + * Returns the list of possible output units, i.e. the full set of + * preferences, for the localized, usage-specific unit preferences. + * + * The returned pointer should be valid for the lifetime of the + * UnitsRouter instance. + */ + const MaybeStackVector<MeasureUnit> *getOutputUnits() const; + + private: + // List of possible output units. TODO: converterPreferences_ now also has + // this data available. Maybe drop outputUnits_ and have getOutputUnits + // construct a the list from data in converterPreferences_ instead? + MaybeStackVector<MeasureUnit> outputUnits_; + + MaybeStackVector<ConverterPreference> converterPreferences_; + + static number::Precision parseSkeletonToPrecision(icu::UnicodeString precisionSkeleton, + UErrorCode &status); + + void init(const MeasureUnit &inputUnit, const Locale &locale, StringPiece usage, UErrorCode &status); +}; + +} // namespace units +U_NAMESPACE_END + +#endif //__UNITS_ROUTER_H__ + +#endif /* #if !UCONFIG_NO_FORMATTING */ |