summaryrefslogtreecommitdiffstats
path: root/intl/icu/source/i18n/units_router.h
diff options
context:
space:
mode:
Diffstat (limited to '')
-rw-r--r--intl/icu/source/i18n/units_router.h166
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 */