1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 62 63 64 65 66 67 68 69 70 71 72 73 74 75 76 77 78 79 80 81 82 83 84 85 86 87 88 89 90 91 92 93 94 95 96 97 98 99 100 101 102 103 104 105 106 107 108 109 110 111 112 113 114 115 116 117 118 119 120 121 122 123 124 125 126 127 128 129 130 131 132 133 134 135 136
|
// © 2020 and later: Unicode, Inc. and others.
// License & terms of use: http://www.unicode.org/copyright.html
#include <_foundation_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 <_foundation_unicode/errorcode.h>
#include <_foundation_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 */
|