]> granicus.if.org Git - icu/commitdiff
ICU-22093 Polish for SimpleNumberFormatter
authorShane F. Carr <shane@unicode.org>
Fri, 6 Jan 2023 19:24:02 +0000 (19:24 +0000)
committerShane F. Carr <shane@unicode.org>
Thu, 12 Jan 2023 17:38:27 +0000 (11:38 -0600)
See #2277

icu4c/source/i18n/number_capi.cpp
icu4c/source/i18n/unicode/usimplenumberformatter.h
icu4c/source/test/cintltst/unumberformattertst.c
icu4c/source/test/intltest/numbertest_simple.cpp

index 13b0cd0aef3fc37db388bca30edce045d0a28d73..bc08989fc95d63485e13438bbbe79c32ed8ef206 100644 (file)
@@ -255,13 +255,22 @@ unumf_close(UNumberFormatter* f) {
 
 U_CAPI USimpleNumber* U_EXPORT2
 usnum_openForInt64(int64_t value, UErrorCode* ec) {
-    auto* impl = new USimpleNumberData();
-    if (impl == nullptr) {
+    auto* number = new USimpleNumberData();
+    if (number == nullptr) {
         *ec = U_MEMORY_ALLOCATION_ERROR;
         return nullptr;
     }
-    impl->fNumber = SimpleNumber::forInt64(value, *ec);
-    return impl->exportForC();
+    number->fNumber = SimpleNumber::forInt64(value, *ec);
+    return number->exportForC();
+}
+
+U_CAPI void U_EXPORT2
+usnum_setToInt64(USimpleNumber* unumber, int64_t value, UErrorCode* ec) {
+    auto* number = USimpleNumberData::validate(unumber, *ec);
+    if (U_FAILURE(*ec)) {
+        return;
+    }
+    number->fNumber = SimpleNumber::forInt64(value, *ec);
 }
 
 U_CAPI void U_EXPORT2
@@ -342,7 +351,7 @@ usnumf_openForLocaleAndGroupingStrategy(
 }
 
 U_CAPI void U_EXPORT2
-usnumf_formatAndAdoptNumber(
+usnumf_format(
         const USimpleNumberFormatter* uformatter,
         USimpleNumber* unumber,
         UFormattedNumber* uresult,
@@ -351,12 +360,13 @@ usnumf_formatAndAdoptNumber(
     auto* number = USimpleNumberData::validate(unumber, *ec);
     auto* result = UFormattedNumberApiHelper::validate(uresult, *ec);
     if (U_FAILURE(*ec)) {
-        delete number;
         return;
     }
     auto localResult = formatter->fFormatter.format(std::move(number->fNumber), *ec);
-    result->setTo(std::move(localResult)); 
-    delete number;
+    if (U_FAILURE(*ec)) {
+        return;
+    }
+    result->setTo(std::move(localResult));
 }
 
 U_CAPI void U_EXPORT2
index c045d7a9d765969e2c07d0e683b8cab75661631b..ef89b46b9c5cdd9b8e7cd2e45d66e351deadd36e 100644 (file)
@@ -18,6 +18,8 @@
  * These functions render locale-aware number strings but without the bells and whistles found in
  * other number formatting APIs such as those in unumberformatter.h, like units and currencies.
  *
+ * Example using C++ helpers:
+ *
  * <pre>
  * LocalUSimpleNumberFormatterPointer uformatter(usnumf_openForLocale("de-CH", status));
  * LocalUFormattedNumberPointer uresult(unumf_openResult(status));
  *     u"55",
  *     ufmtval_getString(unumf_resultAsValue(uresult.getAlias(), status), nullptr, status));
  * </pre>
+ *
+ * Example using pure C:
+ * 
+ * <pre>
+ * UErrorCode ec = U_ZERO_ERROR;
+ * USimpleNumberFormatter* uformatter = usnumf_openForLocale("bn", &ec);
+ * USimpleNumber* unumber = usnum_openForInt64(1000007, &ec);
+ * UFormattedNumber* uresult = unumf_openResult(&ec);
+ * usnumf_format(uformatter, unumber, uresult, &ec);
+ * int32_t len;
+ * const UChar* str = ufmtval_getString(unumf_resultAsValue(uresult, &ec), &len, &ec);
+ * if (assertSuccess("Formatting end-to-end", &ec)) {
+ *     assertUEquals("Should produce a result in Bangla digits", u"১০,০০,০০৭", str);
+ * }
+
+ * // Cleanup:
+ * unumf_closeResult(uresult);
+ * usnum_close(unumber);
+ * usnumf_close(uformatter);
+ * </pre>
  */
 
 #ifndef U_HIDE_DRAFT_API
@@ -85,6 +107,17 @@ U_CAPI USimpleNumber* U_EXPORT2
 usnum_openForInt64(int64_t value, UErrorCode* ec);
 
 
+/**
+ * Overwrites the value in a USimpleNumber to an int64_t.
+ *
+ * This can be used to reset the number value after formatting.
+ *
+ * @draft ICU 73
+ */
+U_CAPI void U_EXPORT2
+usnum_setToInt64(USimpleNumber* unumber, int64_t value, UErrorCode* ec);
+
+
 /**
  * Changes the value of the USimpleNumber by a power of 10.
  *
@@ -175,14 +208,13 @@ usnumf_openForLocaleAndGroupingStrategy(
 /**
  * Formats a number using this SimpleNumberFormatter.
  *
- * The USimpleNumber is adopted and must not be freed after calling this function,
- * even if the function sets an error code. If you use LocalUSimpleNumberPointer,
- * call `.orphan()` when passing it to this function.
+ * The USimpleNumber is cleared after calling this function. It can be re-used via
+ * usnum_setToInt64.
  *
  * @draft ICU 73
  */
 U_CAPI void U_EXPORT2
-usnumf_formatAndAdoptNumber(
+usnumf_format(
     const USimpleNumberFormatter* uformatter,
     USimpleNumber* unumber,
     UFormattedNumber* uresult,
index 3079dcf302dc0ee20182e2b03590d4bce1d501e6..d5ee04eeeebd769730257661e6200f0f422c01fe 100644 (file)
@@ -12,6 +12,7 @@
 #include <stdbool.h>
 #include <stdio.h>
 #include "unicode/unumberformatter.h"
+#include "unicode/usimplenumberformatter.h"
 #include "unicode/umisc.h"
 #include "unicode/unum.h"
 #include "unicode/ustring.h"
@@ -25,6 +26,10 @@ static void TestSkeletonFormatToFields(void);
 
 static void TestExampleCode(void);
 
+static void TestSimpleNumberFormatterExample(void);
+
+static void TestSimpleNumberFormatterFull(void);
+
 static void TestFormattedValue(void);
 
 static void TestSkeletonParseError(void);
@@ -45,6 +50,8 @@ void addUNumberFormatterTest(TestNode** root) {
     TESTCASE(TestSkeletonFormatToString);
     TESTCASE(TestSkeletonFormatToFields);
     TESTCASE(TestExampleCode);
+    TESTCASE(TestSimpleNumberFormatterExample);
+    TESTCASE(TestSimpleNumberFormatterFull);
     TESTCASE(TestFormattedValue);
     TESTCASE(TestSkeletonParseError);
     TESTCASE(TestToDecimalNumber);
@@ -212,6 +219,60 @@ static void TestExampleCode() {
 }
 
 
+static void TestSimpleNumberFormatterExample() {
+    // This is the example in usimplenumberformatter.h
+    UErrorCode ec = U_ZERO_ERROR;
+    USimpleNumberFormatter* uformatter = usnumf_openForLocale("bn", &ec);
+    USimpleNumber* unumber = usnum_openForInt64(1000007, &ec);
+    UFormattedNumber* uresult = unumf_openResult(&ec);
+    usnumf_format(uformatter, unumber, uresult, &ec);
+    int32_t len;
+    const UChar* str = ufmtval_getString(unumf_resultAsValue(uresult, &ec), &len, &ec);
+    if (assertSuccess("Formatting end-to-end 1", &ec)) {
+        assertUEquals("Should produce a result in Bangla digits", u"১০,০০,০০৭", str);
+    }
+
+    // Cleanup:
+    unumf_closeResult(uresult);
+    usnum_close(unumber);
+    usnumf_close(uformatter);
+}
+
+
+static void TestSimpleNumberFormatterFull() {
+    UErrorCode ec = U_ZERO_ERROR;
+    USimpleNumberFormatter* uformatter = usnumf_openForLocaleAndGroupingStrategy("de-CH", UNUM_GROUPING_ON_ALIGNED, &ec);
+    UFormattedNumber* uresult = unumf_openResult(&ec);
+
+    usnumf_formatInt64(uformatter, 4321, uresult, &ec);
+    int32_t len;
+    const UChar* str = str = ufmtval_getString(unumf_resultAsValue(uresult, &ec), &len, &ec);
+    if (assertSuccess("Formatting end-to-end 2", &ec)) {
+        assertUEquals("Should produce a result with Swiss symbols", u"4’321", str);
+    }
+
+    USimpleNumber* unumber = usnum_openForInt64(1000007, &ec);
+    usnum_setToInt64(unumber, 98765, &ec);
+    usnum_multiplyByPowerOfTen(unumber, -2, &ec);
+    usnum_roundTo(unumber, -1, UNUM_ROUND_HALFDOWN, &ec);
+    usnum_setMinimumIntegerDigits(unumber, 4, &ec);
+    usnum_setMinimumFractionDigits(unumber, 3, &ec);
+    usnum_truncateStart(unumber, 1, &ec);
+    usnum_setSign(unumber, UNUM_SIMPLE_NUMBER_PLUS_SIGN, &ec);
+
+    usnumf_format(uformatter, unumber, uresult, &ec);
+    str = ufmtval_getString(unumf_resultAsValue(uresult, &ec), &len, &ec);
+    if (assertSuccess("Formatting end-to-end 3", &ec)) {
+        assertUEquals("Should produce a result with mutated number", u"+0’007.600", str);
+    }
+
+    // Cleanup:
+    unumf_closeResult(uresult);
+    usnum_close(unumber);
+    usnumf_close(uformatter);
+}
+
+
 static void TestFormattedValue() {
     UErrorCode ec = U_ZERO_ERROR;
     UNumberFormatter* uformatter = unumf_openForSkeletonAndLocale(
index e6e42e7fbaeb1bc5d9b7da311a3aa0dc8b77d02a..dd5c26ccff4c15b8a021781cc7dbdc1b1936c2b7 100644 (file)
@@ -185,21 +185,45 @@ void SimpleNumberFormatterTest::testCAPI() {
         ufmtval_getString(unumf_resultAsValue(uresult.getAlias(), status), nullptr, status));
 
     LocalUSimpleNumberPointer unumber(usnum_openForInt64(44, status));
-    usnumf_formatAndAdoptNumber(uformatter.getAlias(), unumber.orphan(), uresult.getAlias(), status);
+    usnumf_format(uformatter.getAlias(), unumber.getAlias(), uresult.getAlias(), status);
     assertEquals("",
         u"44",
         ufmtval_getString(unumf_resultAsValue(uresult.getAlias(), status), nullptr, status));
 
-    unumber.adoptInstead(usnum_openForInt64(2335, status));
+    // Can't re-use a number without setting it again
+    usnumf_format(uformatter.getAlias(), unumber.getAlias(), uresult.getAlias(), status);
+    status.expectErrorAndReset(U_ILLEGAL_ARGUMENT_ERROR);
+    usnum_multiplyByPowerOfTen(unumber.getAlias(), 0, status);
+    status.expectErrorAndReset(U_INVALID_STATE_ERROR);
+
+    usnum_setToInt64(unumber.getAlias(), 2335, status);
     usnum_multiplyByPowerOfTen(unumber.getAlias(), -2, status);
     usnum_roundTo(unumber.getAlias(), -1, UNUM_ROUND_HALFEVEN, status);
     usnum_truncateStart(unumber.getAlias(), 1, status);
     usnum_setMinimumFractionDigits(unumber.getAlias(), 3, status);
     usnum_setMinimumIntegerDigits(unumber.getAlias(), 3, status);
-    usnumf_formatAndAdoptNumber(uformatter.getAlias(), unumber.orphan(), uresult.getAlias(), status);
+    usnumf_format(uformatter.getAlias(), unumber.getAlias(), uresult.getAlias(), status);
     assertEquals("",
         u"003.400",
         ufmtval_getString(unumf_resultAsValue(uresult.getAlias(), status), nullptr, status));
+
+    // Setting twice should overwrite the first value
+    usnum_setToInt64(unumber.getAlias(), 1111, status);
+    usnum_setToInt64(unumber.getAlias(), 2222, status);
+    usnumf_format(uformatter.getAlias(), unumber.getAlias(), uresult.getAlias(), status);
+    assertEquals("",
+        u"2’222",
+        ufmtval_getString(unumf_resultAsValue(uresult.getAlias(), status), nullptr, status));
+
+    {
+        // This is the exact example in usimplenumberformatter.h
+        LocalUSimpleNumberFormatterPointer uformatter(usnumf_openForLocale("de-CH", status));
+        LocalUFormattedNumberPointer uresult(unumf_openResult(status));
+        usnumf_formatInt64(uformatter.getAlias(), 55, uresult.getAlias(), status);
+        assertEquals("",
+            u"55",
+            ufmtval_getString(unumf_resultAsValue(uresult.getAlias(), status), nullptr, status));
+    }
 }