1 // © 2020 and later: Unicode, Inc. and others.
2 // License & terms of use: http://www.unicode.org/copyright.html
3 
4 #include "unicode/utypes.h"
5 
6 #if !UCONFIG_NO_FORMATTING
7 #ifndef __UNITS_COMPLEXCONVERTER_H__
8 #define __UNITS_COMPLEXCONVERTER_H__
9 
10 #include "cmemory.h"
11 #include "measunit_impl.h"
12 #include "number_roundingutils.h"
13 #include "unicode/errorcode.h"
14 #include "unicode/measure.h"
15 #include "units_converter.h"
16 #include "units_data.h"
17 
18 U_NAMESPACE_BEGIN
19 
20 // Export explicit template instantiations of MaybeStackArray, MemoryPool and
21 // MaybeStackVector. This is required when building DLLs for Windows. (See
22 // datefmt.h, collationiterator.h, erarules.h and others for similar examples.)
23 //
24 // Note: These need to be outside of the units namespace, or Clang will generate
25 // a compile error.
26 #if U_PF_WINDOWS <= U_PLATFORM && U_PLATFORM <= U_PF_CYGWIN
27 template class U_I18N_API MaybeStackArray<units::UnitConverter*, 8>;
28 template class U_I18N_API MemoryPool<units::UnitConverter, 8>;
29 template class U_I18N_API MaybeStackVector<units::UnitConverter, 8>;
30 template class U_I18N_API MaybeStackArray<MeasureUnitImpl*, 8>;
31 template class U_I18N_API MemoryPool<MeasureUnitImpl, 8>;
32 template class U_I18N_API MaybeStackVector<MeasureUnitImpl, 8>;
33 template class U_I18N_API MaybeStackArray<MeasureUnit*, 8>;
34 template class U_I18N_API MemoryPool<MeasureUnit, 8>;
35 template class U_I18N_API MaybeStackVector<MeasureUnit, 8>;
36 #endif
37 
38 namespace units {
39 
40 /**
41  *  Converts from single or compound unit to single, compound or mixed units.
42  * For example, from `meter` to `foot+inch`.
43  *
44  *  DESIGN:
45  *    This class uses `UnitConverter` in order to perform the single converter (i.e. converters from a
46  *    single unit to another single unit). Therefore, `ComplexUnitsConverter` class contains multiple
47  *    instances of the `UnitConverter` to perform the conversion.
48  */
49 class U_I18N_API ComplexUnitsConverter : public UMemory {
50   public:
51     /**
52      * Constructor of `ComplexUnitsConverter`.
53      * NOTE:
54      *   - inputUnit and outputUnits must be under the same category
55      *      - e.g. meter to feet and inches --> all of them are length units.
56      *
57      * @param inputUnit represents the source unit. (should be single or compound unit).
58      * @param outputUnits represents the output unit. could be any type. (single, compound or mixed).
59      * @param status
60      */
61     ComplexUnitsConverter(const MeasureUnitImpl &inputUnit, const MeasureUnitImpl &outputUnits,
62                           const ConversionRates &ratesInfo, UErrorCode &status);
63 
64     // Returns true if the specified `quantity` of the `inputUnit`, expressed in terms of the biggest
65     // unit in the MeasureUnit `outputUnit`, is greater than or equal to `limit`.
66     //    For example, if the input unit is `meter` and the target unit is `foot+inch`. Therefore, this
67     //    function will convert the `quantity` from `meter` to `foot`, then, it will compare the value in
68     //    `foot` with the `limit`.
69     UBool greaterThanOrEqual(double quantity, double limit) const;
70 
71     // Returns outputMeasures which is an array with the corresponding values.
72     //    - E.g. converting meters to feet and inches.
73     //                  1 meter --> 3 feet, 3.3701 inches
74     //         NOTE:
75     //           the smallest element is the only element that could have fractional values. And all
76     //           other elements are floored to the nearest integer
77     MaybeStackVector<Measure>
78     convert(double quantity, icu::number::impl::RoundingImpl *rounder, UErrorCode &status) const;
79 
80   private:
81     MaybeStackVector<UnitConverter> unitConverters_;
82     // Individual units of mixed units, sorted big to small
83     MaybeStackVector<MeasureUnitImpl> units_;
84     // Individual units of mixed units, sorted in desired output order
85     MaybeStackVector<MeasureUnit> outputUnits_;
86 };
87 
88 } // namespace units
89 U_NAMESPACE_END
90 
91 #endif //__UNITS_COMPLEXCONVERTER_H__
92 
93 #endif /* #if !UCONFIG_NO_FORMATTING */
94