]> granicus.if.org Git - icu/commitdiff
Implement complex unit converter
authorYounies Mahmoud <younies.mahmoud@gmail.com>
Mon, 16 Mar 2020 21:33:09 +0000 (22:33 +0100)
committerYounies Mahmoud <younies.mahmoud@gmail.com>
Mon, 16 Mar 2020 21:33:09 +0000 (22:33 +0100)
icu4c/source/i18n/complexunitsconverter.cpp [new file with mode: 0644]
icu4c/source/i18n/complexunitsconverter.h [new file with mode: 0644]

diff --git a/icu4c/source/i18n/complexunitsconverter.cpp b/icu4c/source/i18n/complexunitsconverter.cpp
new file mode 100644 (file)
index 0000000..f58a69d
--- /dev/null
@@ -0,0 +1,73 @@
+// © 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
+
+#include "cmemory.h"
+#include "complexunitsconverter.h"
+#include "uassert.h"
+#include "unicode/fmtable.h"
+#include "unitconverter.h"
+
+U_NAMESPACE_BEGIN
+
+ComplexUnitsConverter::ComplexUnitsConverter(const MeasureUnit inputUnit,
+                                             const MaybeStackVector<MeasureUnit> outputUnits,
+                                             UErrorCode &status) {
+    if (outputUnits.length() == 0) {
+        status = U_ILLEGAL_ARGUMENT_ERROR;
+        return;
+    }
+
+    MaybeStackVector<UnitConverter> converters;
+    for (int i = 0, n = outputUnits.length(); i < n; i++) {
+        if (i == 0) { // first element
+            converters.emplaceBack(UnitConverter(inputUnit, *outputUnits[i], status));
+
+        } else {
+            converters.emplaceBack(UnitConverter(*outputUnits[i - 1], *outputUnits[i], status));
+        }
+
+        if (U_FAILURE(status)) break;
+    }
+
+    if (U_FAILURE(status)) return;
+
+    unitConverters_.appendAll(converters, status);
+    units_.appendAll(outputUnits, status);
+}
+
+UBool ComplexUnitsConverter::greaterThanOrEqual(double quantity, double limit) {
+    U_ASSERT(unitConverters_.length() ?> 0);
+
+    // first quantity is the biggest one.
+    double newQuantity = (*unitConverters_[0]).convert(quantity);
+
+    return newQuantity >= limit;
+}
+
+MaybeStackVector<Measure> ComplexUnitsConverter::convert(double quantity, UErrorCode &status) {
+    MaybeStackVector<Measure> result;
+
+    for (int i = 0, n = unitConverters_.length(); i < n; ++i) {
+        quantity = (*unitConverters_[i]).convert(quantity);
+        if (i < n - 1) { // not last element
+            int64_t newQuantity = quantity;
+            Formattable formattableNewQuantity(newQuantity);
+            result.emplaceBack(Measure(formattableNewQuantity, units_[i], status));
+
+            quantity -= newQuantity;
+        } else { // Last element
+            Formattable formattableQuantity(quantity);
+            result.emplaceBack(Measure(formattableQuantity, units_[i], status));
+        }
+    }
+
+    return result;
+}
+
+U_NAMESPACE_END
+
+#endif /* #if !UCONFIG_NO_FORMATTING */
\ No newline at end of file
diff --git a/icu4c/source/i18n/complexunitsconverter.h b/icu4c/source/i18n/complexunitsconverter.h
new file mode 100644 (file)
index 0000000..27c6ecf
--- /dev/null
@@ -0,0 +1,56 @@
+// © 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 __COMPLEXUNITSCONVERTER_H__
+#define __COMPLEXUNITSCONVERTER_H__
+
+#include "cmemory.h"
+#include "unitconverter.h"
+
+#include "unicode/errorcode.h"
+#include "unicode/measunit.h"
+#include "unicode/measure.h"
+
+U_NAMESPACE_BEGIN
+
+class U_I18N_API ComplexUnitsConverter {
+  public:
+    /**
+     * 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.
+     *   - outputUnits must be ordered in a descending order depending on their size.
+     *      - e.g. mile, feet , inches.
+     * @param inputUnit represents the source unit.
+     * @param outputUnits a pointer to an array or the target units.
+     * @param lengthOfOutputUnits represents the length of the output units.
+     * @param status
+     */
+    ComplexUnitsConverter(const MeasureUnit inputUnit, const MaybeStackVector<MeasureUnit> outputUnits,
+                          UErrorCode &status);
+
+    // Returns true if the `quantity` in the `inputUnit` is greater than or equal than the `limit` in the
+    // biggest `outputUnits`
+    UBool greaterThanOrEqual(double quantity, double limit);
+
+    // Returns outputMeasures which is an array with the correspinding 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 has fraction values.
+    MaybeStackVector<Measure> convert(double quantity, UErrorCode &status);
+
+  private:
+    MaybeStackVector<UnitConverter> unitConverters_;
+    MaybeStackVector<MeasureUnit> units_;
+};
+
+U_NAMESPACE_END
+
+#endif //__COMPLEXUNITSCONVERTER_H__
+
+#endif /* #if !UCONFIG_NO_FORMATTING */