ICU-22093 Polish for SimpleNumberFormatter

See #2277
This commit is contained in:
Shane F. Carr 2023-01-06 19:24:02 +00:00
parent ad82a6693a
commit 89c1700424
4 changed files with 142 additions and 15 deletions

View 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

View 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));
@ -26,6 +28,26 @@
* 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,

View 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"4321", 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"+0007.600", str);
}
// Cleanup:
unumf_closeResult(uresult);
usnum_close(unumber);
usnumf_close(uformatter);
}
static void TestFormattedValue() {
UErrorCode ec = U_ZERO_ERROR;
UNumberFormatter* uformatter = unumf_openForSkeletonAndLocale(

View 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"2222",
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));
}
}