diff options
Diffstat (limited to 'intl/icu/source/i18n/units_complexconverter.h')
-rw-r--r-- | intl/icu/source/i18n/units_complexconverter.h | 136 |
1 files changed, 136 insertions, 0 deletions
diff --git a/intl/icu/source/i18n/units_complexconverter.h b/intl/icu/source/i18n/units_complexconverter.h new file mode 100644 index 0000000000..d56ce8d4ce --- /dev/null +++ b/intl/icu/source/i18n/units_complexconverter.h @@ -0,0 +1,136 @@ +// © 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_COMPLEXCONVERTER_H__ +#define __UNITS_COMPLEXCONVERTER_H__ + +#include "cmemory.h" +#include "measunit_impl.h" +#include "number_roundingutils.h" +#include "unicode/errorcode.h" +#include "unicode/measure.h" +#include "units_converter.h" +#include "units_data.h" + +U_NAMESPACE_BEGIN + +// 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::UnitsConverter*, 8>; +template class U_I18N_API MemoryPool<units::UnitsConverter, 8>; +template class U_I18N_API MaybeStackVector<units::UnitsConverter, 8>; +template class U_I18N_API MaybeStackArray<MeasureUnitImpl*, 8>; +template class U_I18N_API MemoryPool<MeasureUnitImpl, 8>; +template class U_I18N_API MaybeStackVector<MeasureUnitImpl, 8>; +template class U_I18N_API MaybeStackArray<MeasureUnit*, 8>; +template class U_I18N_API MemoryPool<MeasureUnit, 8>; +template class U_I18N_API MaybeStackVector<MeasureUnit, 8>; +#endif + +namespace units { + +/** + * Converts from single or compound unit to single, compound or mixed units. + * For example, from `meter` to `foot+inch`. + * + * DESIGN: + * This class uses `UnitsConverter` in order to perform the single converter (i.e. converters from a + * single unit to another single unit). Therefore, `ComplexUnitsConverter` class contains multiple + * instances of the `UnitsConverter` to perform the conversion. + */ +class U_I18N_API ComplexUnitsConverter : public UMemory { + public: + /** + * Constructs `ComplexUnitsConverter` for an `targetUnit` that could be Single, Compound or Mixed. + * In case of: + * 1- Single and Compound units, + * the conversion will not perform anything, the input will be equal to the output. + * 2- Mixed Unit + * the conversion will consider the input is the biggest unit. And will convert it to be spread + * through the target units. For example: if target unit is "inch-and-foot", and the input is 2.5. + * The converter will consider the input value in "foot", because foot is the biggest unit. + * Then, it will convert 2.5 feet to "inch-and-foot". + * + * @param targetUnit could be any units type (single, compound or mixed). + * @param ratesInfo + * @param status + */ + ComplexUnitsConverter(const MeasureUnitImpl &targetUnit, const ConversionRates &ratesInfo, + UErrorCode &status); + /** + * Constructor of `ComplexUnitsConverter`. + * NOTE: + * - inputUnit and outputUnits must be under the same category + * - e.g. meter to feet and inches --> all of them are length units. + * + * @param inputUnit represents the source unit. (should be single or compound unit). + * @param outputUnits represents the output unit. could be any type. (single, compound or mixed). + * @param status + */ + ComplexUnitsConverter(StringPiece inputUnitIdentifier, StringPiece outputUnitsIdentifier, + UErrorCode &status); + + /** + * Constructor of `ComplexUnitsConverter`. + * NOTE: + * - inputUnit and outputUnits must be under the same category + * - e.g. meter to feet and inches --> all of them are length units. + * + * @param inputUnit represents the source unit. (should be single or compound unit). + * @param outputUnits represents the output unit. could be any type. (single, compound or mixed). + * @param ratesInfo a ConversionRates instance containing the unit conversion rates. + * @param status + */ + ComplexUnitsConverter(const MeasureUnitImpl &inputUnit, const MeasureUnitImpl &outputUnits, + const ConversionRates &ratesInfo, UErrorCode &status); + + // Returns true if the specified `quantity` of the `inputUnit`, expressed in terms of the biggest + // unit in the MeasureUnit `outputUnit`, is greater than or equal to `limit`. + // For example, if the input unit is `meter` and the target unit is `foot+inch`. Therefore, this + // function will convert the `quantity` from `meter` to `foot`, then, it will compare the value in + // `foot` with the `limit`. + UBool greaterThanOrEqual(double quantity, double limit) const; + + // Returns outputMeasures which is an array with the corresponding values. + // - E.g. converting meters to feet and inches. + // 1 meter --> 3 feet, 3.3701 inches + // NOTE: + // the smallest element is the only element that could have fractional values. And all + // other elements are floored to the nearest integer + MaybeStackVector<Measure> + convert(double quantity, icu::number::impl::RoundingImpl *rounder, UErrorCode &status) const; + + // TODO(ICU-21937): Make it private after submitting the public units conversion API. + MaybeStackVector<UnitsConverter> unitsConverters_; + + // TODO(ICU-21937): Make it private after submitting the public units conversion API. + // Individual units of mixed units, sorted big to small, with indices + // indicating the requested output mixed unit order. + MaybeStackVector<MeasureUnitImplWithIndex> units_; + + private: + // Sorts units_, which must be populated before calling this, and populates + // unitsConverters_. + void init(const MeasureUnitImpl &inputUnit, const ConversionRates &ratesInfo, UErrorCode &status); + + // Applies the rounder to the quantity (last element) and bubble up any carried value to all the + // intValues. + // TODO(ICU-21288): get smarter about precision for mixed units. + void applyRounder(MaybeStackArray<int64_t, 5> &intValues, double &quantity, + icu::number::impl::RoundingImpl *rounder, UErrorCode &status) const; +}; + +} // namespace units +U_NAMESPACE_END + +#endif //__UNITS_COMPLEXCONVERTER_H__ + +#endif /* #if !UCONFIG_NO_FORMATTING */ |