ICU-20562 Adding toDecimalNumber method to C++ FormattedNumber.

This commit is contained in:
Shane Carr 2019-08-14 15:47:41 -07:00 committed by Shane F. Carr
parent 4e07b85279
commit 4785f55622
7 changed files with 78 additions and 1 deletions

View File

@ -55,6 +55,8 @@ class U_I18N_API DecNum : public UMemory {
bool isZero() const;
void toString(ByteSink& output, UErrorCode& status) const;
inline const decNumber* getRawDecNumber() const {
return fData.getAlias();
}

View File

@ -9,6 +9,7 @@
#include "number_utypes.h"
#include "util.h"
#include "number_decimalquantity.h"
#include "number_decnum.h"
U_NAMESPACE_BEGIN
namespace number {
@ -28,6 +29,13 @@ void FormattedNumber::getAllFieldPositions(FieldPositionIterator& iterator, UErr
getAllFieldPositionsImpl(fpih, status);
}
void FormattedNumber::toDecimalNumber(ByteSink& sink, UErrorCode& status) const {
UPRV_FORMATTED_VALUE_METHOD_GUARD(UPRV_NOARG)
impl::DecNum decnum;
fData->quantity.toDecNum(decnum, status);
decnum.toString(sink, status);
}
void FormattedNumber::getAllFieldPositionsImpl(FieldPositionIteratorHandler& fpih,
UErrorCode& status) const {
UPRV_FORMATTED_VALUE_METHOD_GUARD(UPRV_NOARG)

View File

@ -252,4 +252,15 @@ bool DecNum::isZero() const {
return decNumberIsZero(fData.getAlias());
}
void DecNum::toString(ByteSink& output, UErrorCode& status) const {
if (U_FAILURE(status)) {
return;
}
// "string must be at least dn->digits+14 characters long"
int32_t minCapacity = fData.getAlias()->digits + 14;
MaybeStackArray<char, 30> buffer(minCapacity);
uprv_decNumberToString(fData, buffer.getAlias());
output.Append(buffer.getAlias(), static_cast<int32_t>(uprv_strlen(buffer.getAlias())));
}
#endif /* #if !UCONFIG_NO_FORMATTING */

View File

@ -11,8 +11,9 @@
#if !UCONFIG_NO_FORMATTING
#include "unicode/appendable.h"
#include "unicode/dcfmtsym.h"
#include "unicode/bytestream.h"
#include "unicode/currunit.h"
#include "unicode/dcfmtsym.h"
#include "unicode/fieldpos.h"
#include "unicode/formattedvalue.h"
#include "unicode/fpositer.h"
@ -2520,6 +2521,27 @@ class U_I18N_API FormattedNumber : public UMemory, public FormattedValue {
*/
void getAllFieldPositions(FieldPositionIterator &iterator, UErrorCode &status) const;
/**
* Export the formatted number as a "numeric string" conforming to the
* syntax defined in the Decimal Arithmetic Specification, available at
* http://speleotrove.com/decimal
*
* This endpoint is useful for obtaining the exact number being printed
* after scaling and rounding have been applied by the number formatter.
*
* Example call site:
*
* auto decimalNumber = fn.toDecimalNumber<std::string>(status);
*
* @tparam StringClass A string class compatible with StringByteSink;
* for example, std::string.
* @param status Set if an error occurs.
* @return A StringClass containing the numeric string.
* @draft ICU 65
*/
template<typename StringClass>
inline StringClass toDecimalNumber(UErrorCode& status) const;
#ifndef U_HIDE_INTERNAL_API
/**
@ -2553,6 +2575,9 @@ class U_I18N_API FormattedNumber : public UMemory, public FormattedValue {
explicit FormattedNumber(UErrorCode errorCode)
: fData(nullptr), fErrorCode(errorCode) {}
// TODO(ICU-20775): Propose this as API.
void toDecimalNumber(ByteSink& sink, UErrorCode& status) const;
// To give LocalizedNumberFormatter format methods access to this class's constructor:
friend class LocalizedNumberFormatter;
@ -2560,6 +2585,16 @@ class U_I18N_API FormattedNumber : public UMemory, public FormattedValue {
friend struct impl::UFormattedNumberImpl;
};
#ifndef U_HIDE_DRAFT_API
template<typename StringClass>
StringClass FormattedNumber::toDecimalNumber(UErrorCode& status) const {
StringClass result;
StringByteSink<StringClass> sink(&result);
toDecimalNumber(sink, status);
return result;
};
#endif // U_HIDE_DRAFT_API
/**
* See the main description in numberformatter.h for documentation and examples.
*

View File

@ -650,6 +650,13 @@ unumf_resultGetAllFieldPositions(const UFormattedNumber* uresult, UFieldPosition
UErrorCode* ec);
// TODO(ICU-20775): Propose this as API.
// NOTE: This is not currently implemented.
// U_DRAFT int32_t U_EXPORT2
// unumf_resultToDecimalNumber(const UFormattedNumber* uresult, char* buffer, int32_t bufferCapacity,
// UErrorCode* ec);
/**
* Releases the UNumberFormatter created by unumf_openForSkeletonAndLocale().
*

View File

@ -82,6 +82,7 @@ class NumberFormatterApiTest : public IntlTestWithFieldPosition {
void copyMove();
void localPointerCAPI();
void toObject();
void toDecimalNumber();
void runIndexedTest(int32_t index, UBool exec, const char *&name, char *par = 0);

View File

@ -104,6 +104,7 @@ void NumberFormatterApiTest::runIndexedTest(int32_t index, UBool exec, const cha
TESTCASE_AUTO(copyMove);
TESTCASE_AUTO(localPointerCAPI);
TESTCASE_AUTO(toObject);
TESTCASE_AUTO(toDecimalNumber);
TESTCASE_AUTO_END;
}
@ -3033,6 +3034,18 @@ void NumberFormatterApiTest::toObject() {
}
}
void NumberFormatterApiTest::toDecimalNumber() {
IcuTestErrorCode status(*this, "toDecimalNumber");
FormattedNumber fn = NumberFormatter::withLocale("bn-BD")
.scale(Scale::powerOfTen(2))
.precision(Precision::maxSignificantDigits(5))
.formatDouble(9.87654321e12, status);
assertEquals("Should have expected localized string result",
u"৯৮,৭৬,৫০,,,,", fn.toString(status));
assertEquals(u"Should have expected toDecimalNumber string result",
"9.8765E+14", fn.toDecimalNumber<std::string>(status).c_str());
}
void NumberFormatterApiTest::assertFormatDescending(const char16_t* umessage, const char16_t* uskeleton,
const UnlocalizedNumberFormatter& f, Locale locale,