ICU-13597 Revising UNumberFormatter according to feedback: (1) adds LocalPointer; (2) makes buffer export behavior consistent; (3) removes const from unumf_closeResult; and (4) improves API docs.

X-SVN-Rev: 41244
This commit is contained in:
Shane Carr 2018-04-18 09:42:05 +00:00
parent ad2ea9d38f
commit efa58f5d80
5 changed files with 130 additions and 10 deletions

View file

@ -150,9 +150,9 @@ unumf_resultToString(const UFormattedNumber* uresult, UChar* buffer, int32_t buf
const UFormattedNumberData* result = UFormattedNumberData::validate(uresult, *ec);
if (U_FAILURE(*ec)) { return 0; }
if (buffer == nullptr) {
// Return the length without setting an error.
return result->string.length();
if (buffer == nullptr ? bufferCapacity != 0 : bufferCapacity < 0) {
*ec = U_ILLEGAL_ARGUMENT_ERROR;
return 0;
}
return result->string.toTempUnicodeString().extract(buffer, bufferCapacity, *ec);
@ -188,7 +188,7 @@ unumf_resultGetAllFields(const UFormattedNumber* uresult, UFieldPositionIterator
}
U_CAPI void U_EXPORT2
unumf_closeResult(const UFormattedNumber* uresult) {
unumf_closeResult(UFormattedNumber* uresult) {
UErrorCode localStatus = U_ZERO_ERROR;
const UFormattedNumberData* impl = UFormattedNumberData::validate(uresult, localStatus);
if (U_FAILURE(localStatus)) { return; }

View file

@ -38,17 +38,41 @@
* unumf_formatDouble(uformatter, 5142.3, uresult, &ec);
* if (U_FAILURE(ec)) { return; }
*
* // Export the string:
* // Export the string to a malloc'd buffer:
* int32_t len = unumf_resultToString(uresult, NULL, 0, &ec);
* // at this point, ec == U_BUFFER_OVERFLOW_ERROR
* ec = U_ZERO_ERROR;
* UChar* buffer = (UChar*) malloc((len+1)*sizeof(UChar));
* unumf_resultToString(uresult, buffer, len+1, &ec);
* if (U_FAILURE(ec)) { return; }
* // buffer should equal "5,142"
*
* // Cleanup:
* unumf_close(uformatter);
* unumf_closeResult(uresult);
* free(buffer);
* </pre>
*
* If you are a C++ user linking against the C libraries, you can use the LocalPointer versions of these
* APIs. The following example uses LocalPointer with the decimal number and field position APIs:
*
* <pre>
* // Setup:
* LocalUNumberFormatterPointer uformatter(unumf_openFromSkeletonAndLocale(u"percent", -1, "en", &ec));
* LocalUFormattedNumberPointer uresult(unumf_openResult(&ec));
* if (U_FAILURE(ec)) { return; }
*
* // Format a decimal number:
* unumf_formatDecimal(uformatter.getAlias(), "9.87E6", -1, uresult.getAlias(), &ec);
* if (U_FAILURE(ec)) { return; }
*
* // Get the location of the percent sign:
* UFieldPosition ufpos = {UNUM_PERCENT_FIELD, 0, 0};
* unumf_resultGetField(uresult.getAlias(), &ufpos, &ec);
* // ufpos should contain beginIndex=7 and endIndex=8 since the string is "0.00987%"
*
* // No need to do any cleanup since we are using LocalPointer.
* </pre>
*/
@ -373,6 +397,7 @@ typedef enum UNumberDecimalSeparatorDisplay {
*
* @draft ICU 62
*/
struct UNumberFormatter;
typedef struct UNumberFormatter UNumberFormatter;
@ -383,6 +408,7 @@ typedef struct UNumberFormatter UNumberFormatter;
*
* @draft ICU 62
*/
struct UFormattedNumber;
typedef struct UFormattedNumber UFormattedNumber;
@ -395,6 +421,10 @@ typedef struct UFormattedNumber UFormattedNumber;
*
* NOTE: This is a C-compatible API; C++ users should build against numberformatter.h instead.
*
* @param skeleton The skeleton string, like u"percent round-integer"
* @param skeletonLen The number of UChars in the skeleton string, or -1 it it is NUL-terminated.
* @param locale The NUL-terminated locale ID.
* @param ec Set if an error occurs.
* @draft ICU 62
*/
U_DRAFT UNumberFormatter* U_EXPORT2
@ -407,6 +437,7 @@ unumf_openFromSkeletonAndLocale(const UChar* skeleton, int32_t skeletonLen, cons
*
* NOTE: This is a C-compatible API; C++ users should build against numberformatter.h instead.
*
* @param ec Set if an error occurs.
* @draft ICU 62
*/
U_DRAFT UFormattedNumber* U_EXPORT2
@ -419,6 +450,10 @@ unumf_openResult(UErrorCode* ec);
*
* NOTE: This is a C-compatible API; C++ users should build against numberformatter.h instead.
*
* @param uformatter A formatter object created by unumf_openFromSkeletonAndLocale or similar.
* @param value The number to be formatted.
* @param uresult The object that will be mutated to store the result; see unumf_openResult.
* @param ec Set if an error occurs.
* @draft ICU 62
*/
U_DRAFT void U_EXPORT2
@ -432,6 +467,10 @@ unumf_formatInt(const UNumberFormatter* uformatter, int64_t value, UFormattedNum
*
* NOTE: This is a C-compatible API; C++ users should build against numberformatter.h instead.
*
* @param uformatter A formatter object created by unumf_openFromSkeletonAndLocale or similar.
* @param value The number to be formatted.
* @param uresult The object that will be mutated to store the result; see unumf_openResult.
* @param ec Set if an error occurs.
* @draft ICU 62
*/
U_DRAFT void U_EXPORT2
@ -448,6 +487,11 @@ unumf_formatDouble(const UNumberFormatter* uformatter, double value, UFormattedN
*
* NOTE: This is a C-compatible API; C++ users should build against numberformatter.h instead.
*
* @param uformatter A formatter object created by unumf_openFromSkeletonAndLocale or similar.
* @param value The numeric string to be formatted.
* @param valueLen The length of the numeric string, or -1 if it is NUL-terminated.
* @param uresult The object that will be mutated to store the result; see unumf_openResult.
* @param ec Set if an error occurs.
* @draft ICU 62
*/
U_DRAFT void U_EXPORT2
@ -460,12 +504,13 @@ unumf_formatDecimal(const UNumberFormatter* uformatter, const char* value, int32
* If bufferCapacity is greater than the required length, a terminating NUL is written.
* If bufferCapacity is less than the required length, an error code is set.
*
* If NULL is passed as the buffer argument, the required length is returned without setting an error.
*
* NOTE: This is a C-compatible API; C++ users should build against numberformatter.h instead.
*
* @param uresult The object containing the formatted number.
* @param buffer Where to save the string output.
* @param bufferCapacity The number of UChars available in the buffer.
* @param ec Set if an error occurs.
* @return The required length.
*
* @draft ICU 62
*/
U_DRAFT int32_t U_EXPORT2
@ -481,10 +526,13 @@ unumf_resultToString(const UFormattedNumber* uresult, UChar* buffer, int32_t buf
* only ever return the first occurrence. Use unumf_resultGetAllFields() to access all occurrences of an
* attribute.
*
* @param uresult The object containing the formatted number.
* @param fpos
* A pointer to a UFieldPosition. On input, position->field is read. On output,
* position->beginIndex and position->endIndex indicate the beginning and ending indices of field
* number position->field, if such a field exists.
* @param ec Set if an error occurs.
* @draft ICU 62
*/
U_DRAFT void U_EXPORT2
unumf_resultGetField(const UFormattedNumber* uresult, UFieldPosition* ufpos, UErrorCode* ec);
@ -496,6 +544,7 @@ unumf_resultGetField(const UFormattedNumber* uresult, UFieldPosition* ufpos, UEr
*
* If you need information on only one field, consider using unumf_resultGetField().
*
* @param uresult The object containing the formatted number.
* @param fpositer
* A pointer to a UFieldPositionIterator created by {@link #ufieldpositer_open}. Iteration
* information already present in the UFieldPositionIterator is deleted, and the iterator is reset
@ -504,6 +553,8 @@ unumf_resultGetField(const UFormattedNumber* uresult, UFieldPosition* ufpos, UEr
* the UNumberFormatFields enum. Fields are not returned in a guaranteed order. Fields cannot
* overlap, but they may nest. For example, 1234 could format as "1,234" which might consist of a
* grouping separator field for ',' and an integer field encompassing the entire string.
* @param ec Set if an error occurs.
* @draft ICU 62
*/
U_DRAFT void U_EXPORT2
unumf_resultGetAllFields(const UFormattedNumber* uresult, UFieldPositionIterator* ufpositer,
@ -515,6 +566,7 @@ unumf_resultGetAllFields(const UFormattedNumber* uresult, UFieldPositionIterator
*
* NOTE: This is a C-compatible API; C++ users should build against numberformatter.h instead.
*
* @param uformatter An object created by unumf_openFromSkeletonAndLocale().
* @draft ICU 62
*/
U_DRAFT void U_EXPORT2
@ -526,10 +578,52 @@ unumf_close(UNumberFormatter* uformatter);
*
* NOTE: This is a C-compatible API; C++ users should build against numberformatter.h instead.
*
* @param uresult An object created by unumf_openResult().
* @draft ICU 62
*/
U_DRAFT void U_EXPORT2
unumf_closeResult(const UFormattedNumber* uresult);
unumf_closeResult(UFormattedNumber* uresult);
#if U_SHOW_CPLUSPLUS_API
U_NAMESPACE_BEGIN
/**
* \class LocalUNumberFormatterPointer
* "Smart pointer" class; closes a UNumberFormatter via unumf_close().
* For most methods see the LocalPointerBase base class.
*
* Usage:
* <pre>
* LocalUNumberFormatterPointer uformatter(unumf_openFromSkeletonAndLocale(...));
* // no need to explicitly call unumf_close()
* </pre>
*
* @see LocalPointerBase
* @see LocalPointer
* @draft ICU 62
*/
U_DEFINE_LOCAL_OPEN_POINTER(LocalUNumberFormatterPointer, UNumberFormatter, unumf_close);
/**
* \class LocalUNumberFormatterPointer
* "Smart pointer" class; closes a UFormattedNumber via unumf_closeResult().
* For most methods see the LocalPointerBase base class.
*
* Usage:
* <pre>
* LocalUFormattedNumberPointer uformatter(unumf_openResult(...));
* // no need to explicitly call unumf_closeResult()
* </pre>
*
* @see LocalPointerBase
* @see LocalPointer
* @draft ICU 62
*/
U_DEFINE_LOCAL_OPEN_POINTER(LocalUFormattedNumberPointer, UFormattedNumber, unumf_closeResult);
U_NAMESPACE_END
#endif // U_SHOW_CPLUSPLUS_API
#endif //__UNUMBERFORMATTER_H__

View file

@ -147,8 +147,10 @@ static void TestExampleCode() {
unumf_formatDouble(uformatter, 5142.3, uresult, &ec);
assertSuccess("There should not be a failure in the example code", &ec);
// Export the string:
// Export the string to a malloc'd buffer:
int32_t len = unumf_resultToString(uresult, NULL, 0, &ec);
assertTrue("No buffer yet", ec == U_BUFFER_OVERFLOW_ERROR);
ec = U_ZERO_ERROR;
UChar* buffer = (UChar*) uprv_malloc((len+1)*sizeof(UChar));
unumf_resultToString(uresult, buffer, len+1, &ec);
assertSuccess("There should not be a failure in the example code", &ec);

View file

@ -70,6 +70,7 @@ class NumberFormatterApiTest : public IntlTest {
void errors();
void validRanges();
void copyMove();
void localPointerCAPI();
void runIndexedTest(int32_t index, UBool exec, const char *&name, char *par = 0);

View file

@ -84,6 +84,7 @@ void NumberFormatterApiTest::runIndexedTest(int32_t index, UBool exec, const cha
TESTCASE_AUTO(errors);
TESTCASE_AUTO(validRanges);
TESTCASE_AUTO(copyMove);
TESTCASE_AUTO(localPointerCAPI);
TESTCASE_AUTO_END;
}
@ -2206,6 +2207,28 @@ void NumberFormatterApiTest::copyMove() {
assertEquals("FormattedNumber move assignment", u"20%", result.toString());
}
void NumberFormatterApiTest::localPointerCAPI() {
// NOTE: This is also the sample code in unumberformatter.h
UErrorCode ec = U_ZERO_ERROR;
// Setup:
LocalUNumberFormatterPointer uformatter(unumf_openFromSkeletonAndLocale(u"percent", -1, "en", &ec));
LocalUFormattedNumberPointer uresult(unumf_openResult(&ec));
assertSuccess("", ec);
// Format a decimal number:
unumf_formatDecimal(uformatter.getAlias(), "9.87E-3", -1, uresult.getAlias(), &ec);
assertSuccess("", ec);
// Get the location of the percent sign:
UFieldPosition ufpos = {UNUM_PERCENT_FIELD, 0, 0};
unumf_resultGetField(uresult.getAlias(), &ufpos, &ec);
assertEquals("Percent sign location within '0.00987%'", 7, ufpos.beginIndex);
assertEquals("Percent sign location within '0.00987%'", 8, ufpos.endIndex);
// No need to do any cleanup since we are using LocalPointer.
}
void NumberFormatterApiTest::assertFormatDescending(const char16_t* umessage, const char16_t* uskeleton,
const UnlocalizedNumberFormatter& f, Locale locale,