units_complexconverter.h 6.1 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136
  1. // © 2020 and later: Unicode, Inc. and others.
  2. // License & terms of use: http://www.unicode.org/copyright.html
  3. #include "unicode/utypes.h"
  4. #if !UCONFIG_NO_FORMATTING
  5. #ifndef __UNITS_COMPLEXCONVERTER_H__
  6. #define __UNITS_COMPLEXCONVERTER_H__
  7. #include "cmemory.h"
  8. #include "measunit_impl.h"
  9. #include "number_roundingutils.h"
  10. #include "unicode/errorcode.h"
  11. #include "unicode/measure.h"
  12. #include "units_converter.h"
  13. #include "units_data.h"
  14. U_NAMESPACE_BEGIN
  15. // Export explicit template instantiations of MaybeStackArray, MemoryPool and
  16. // MaybeStackVector. This is required when building DLLs for Windows. (See
  17. // datefmt.h, collationiterator.h, erarules.h and others for similar examples.)
  18. //
  19. // Note: These need to be outside of the units namespace, or Clang will generate
  20. // a compile error.
  21. #if U_PF_WINDOWS <= U_PLATFORM && U_PLATFORM <= U_PF_CYGWIN
  22. template class U_I18N_API MaybeStackArray<units::UnitsConverter*, 8>;
  23. template class U_I18N_API MemoryPool<units::UnitsConverter, 8>;
  24. template class U_I18N_API MaybeStackVector<units::UnitsConverter, 8>;
  25. template class U_I18N_API MaybeStackArray<MeasureUnitImpl*, 8>;
  26. template class U_I18N_API MemoryPool<MeasureUnitImpl, 8>;
  27. template class U_I18N_API MaybeStackVector<MeasureUnitImpl, 8>;
  28. template class U_I18N_API MaybeStackArray<MeasureUnit*, 8>;
  29. template class U_I18N_API MemoryPool<MeasureUnit, 8>;
  30. template class U_I18N_API MaybeStackVector<MeasureUnit, 8>;
  31. #endif
  32. namespace units {
  33. /**
  34. * Converts from single or compound unit to single, compound or mixed units.
  35. * For example, from `meter` to `foot+inch`.
  36. *
  37. * DESIGN:
  38. * This class uses `UnitsConverter` in order to perform the single converter (i.e. converters from a
  39. * single unit to another single unit). Therefore, `ComplexUnitsConverter` class contains multiple
  40. * instances of the `UnitsConverter` to perform the conversion.
  41. */
  42. class U_I18N_API ComplexUnitsConverter : public UMemory {
  43. public:
  44. /**
  45. * Constructs `ComplexUnitsConverter` for an `targetUnit` that could be Single, Compound or Mixed.
  46. * In case of:
  47. * 1- Single and Compound units,
  48. * the conversion will not perform anything, the input will be equal to the output.
  49. * 2- Mixed Unit
  50. * the conversion will consider the input is the biggest unit. And will convert it to be spread
  51. * through the target units. For example: if target unit is "inch-and-foot", and the input is 2.5.
  52. * The converter will consider the input value in "foot", because foot is the biggest unit.
  53. * Then, it will convert 2.5 feet to "inch-and-foot".
  54. *
  55. * @param targetUnit could be any units type (single, compound or mixed).
  56. * @param ratesInfo
  57. * @param status
  58. */
  59. ComplexUnitsConverter(const MeasureUnitImpl &targetUnit, const ConversionRates &ratesInfo,
  60. UErrorCode &status);
  61. /**
  62. * Constructor of `ComplexUnitsConverter`.
  63. * NOTE:
  64. * - inputUnit and outputUnits must be under the same category
  65. * - e.g. meter to feet and inches --> all of them are length units.
  66. *
  67. * @param inputUnit represents the source unit. (should be single or compound unit).
  68. * @param outputUnits represents the output unit. could be any type. (single, compound or mixed).
  69. * @param status
  70. */
  71. ComplexUnitsConverter(StringPiece inputUnitIdentifier, StringPiece outputUnitsIdentifier,
  72. UErrorCode &status);
  73. /**
  74. * Constructor of `ComplexUnitsConverter`.
  75. * NOTE:
  76. * - inputUnit and outputUnits must be under the same category
  77. * - e.g. meter to feet and inches --> all of them are length units.
  78. *
  79. * @param inputUnit represents the source unit. (should be single or compound unit).
  80. * @param outputUnits represents the output unit. could be any type. (single, compound or mixed).
  81. * @param ratesInfo a ConversionRates instance containing the unit conversion rates.
  82. * @param status
  83. */
  84. ComplexUnitsConverter(const MeasureUnitImpl &inputUnit, const MeasureUnitImpl &outputUnits,
  85. const ConversionRates &ratesInfo, UErrorCode &status);
  86. // Returns true if the specified `quantity` of the `inputUnit`, expressed in terms of the biggest
  87. // unit in the MeasureUnit `outputUnit`, is greater than or equal to `limit`.
  88. // For example, if the input unit is `meter` and the target unit is `foot+inch`. Therefore, this
  89. // function will convert the `quantity` from `meter` to `foot`, then, it will compare the value in
  90. // `foot` with the `limit`.
  91. UBool greaterThanOrEqual(double quantity, double limit) const;
  92. // Returns outputMeasures which is an array with the corresponding values.
  93. // - E.g. converting meters to feet and inches.
  94. // 1 meter --> 3 feet, 3.3701 inches
  95. // NOTE:
  96. // the smallest element is the only element that could have fractional values. And all
  97. // other elements are floored to the nearest integer
  98. MaybeStackVector<Measure>
  99. convert(double quantity, icu::number::impl::RoundingImpl *rounder, UErrorCode &status) const;
  100. // TODO(ICU-21937): Make it private after submitting the public units conversion API.
  101. MaybeStackVector<UnitsConverter> unitsConverters_;
  102. // TODO(ICU-21937): Make it private after submitting the public units conversion API.
  103. // Individual units of mixed units, sorted big to small, with indices
  104. // indicating the requested output mixed unit order.
  105. MaybeStackVector<MeasureUnitImplWithIndex> units_;
  106. private:
  107. // Sorts units_, which must be populated before calling this, and populates
  108. // unitsConverters_.
  109. void init(const MeasureUnitImpl &inputUnit, const ConversionRates &ratesInfo, UErrorCode &status);
  110. // Applies the rounder to the quantity (last element) and bubble up any carried value to all the
  111. // intValues.
  112. // TODO(ICU-21288): get smarter about precision for mixed units.
  113. void applyRounder(MaybeStackArray<int64_t, 5> &intValues, double &quantity,
  114. icu::number::impl::RoundingImpl *rounder, UErrorCode &status) const;
  115. };
  116. } // namespace units
  117. U_NAMESPACE_END
  118. #endif //__UNITS_COMPLEXCONVERTER_H__
  119. #endif /* #if !UCONFIG_NO_FORMATTING */