From: Shane F. Carr Date: Fri, 6 Jan 2023 19:24:02 +0000 (+0000) Subject: ICU-22093 Polish for SimpleNumberFormatter X-Git-Tag: cldr/2023-02-02~12 X-Git-Url: https://granicus.if.org/sourcecode?a=commitdiff_plain;h=89c1700424ee903718fad955c240017d6431d0eb;p=icu ICU-22093 Polish for SimpleNumberFormatter See #2277 --- diff --git a/icu4c/source/i18n/number_capi.cpp b/icu4c/source/i18n/number_capi.cpp index 13b0cd0aef3..bc08989fc95 100644 --- a/icu4c/source/i18n/number_capi.cpp +++ b/icu4c/source/i18n/number_capi.cpp @@ -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 diff --git a/icu4c/source/i18n/unicode/usimplenumberformatter.h b/icu4c/source/i18n/unicode/usimplenumberformatter.h index c045d7a9d76..ef89b46b9c5 100644 --- a/icu4c/source/i18n/unicode/usimplenumberformatter.h +++ b/icu4c/source/i18n/unicode/usimplenumberformatter.h @@ -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: + * *
  * LocalUSimpleNumberFormatterPointer uformatter(usnumf_openForLocale("de-CH", status));
  * LocalUFormattedNumberPointer uresult(unumf_openResult(status));
@@ -26,6 +28,26 @@
  *     u"55",
  *     ufmtval_getString(unumf_resultAsValue(uresult.getAlias(), status), nullptr, status));
  * 
+ * + * Example using pure C: + * + *
+ * 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);
+ * 
*/ #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, diff --git a/icu4c/source/test/cintltst/unumberformattertst.c b/icu4c/source/test/cintltst/unumberformattertst.c index 3079dcf302d..d5ee04eeeeb 100644 --- a/icu4c/source/test/cintltst/unumberformattertst.c +++ b/icu4c/source/test/cintltst/unumberformattertst.c @@ -12,6 +12,7 @@ #include #include #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( diff --git a/icu4c/source/test/intltest/numbertest_simple.cpp b/icu4c/source/test/intltest/numbertest_simple.cpp index e6e42e7fbae..dd5c26ccff4 100644 --- a/icu4c/source/test/intltest/numbertest_simple.cpp +++ b/icu4c/source/test/intltest/numbertest_simple.cpp @@ -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)); + } }