ICU-13306 Can not get and set rounding attributes for RBNF with C API
X-SVN-Rev: 40343
This commit is contained in:
parent
408afcee77
commit
e3ac9c5561
@ -687,6 +687,7 @@ RuleBasedNumberFormat::RuleBasedNumberFormat(const UnicodeString& description,
|
||||
, decimalFormatSymbols(NULL)
|
||||
, defaultInfinityRule(NULL)
|
||||
, defaultNaNRule(NULL)
|
||||
, roundingMode(DecimalFormat::ERoundingMode::kRoundUnnecessary)
|
||||
, lenient(FALSE)
|
||||
, lenientParseRules(NULL)
|
||||
, localizations(NULL)
|
||||
@ -711,6 +712,7 @@ RuleBasedNumberFormat::RuleBasedNumberFormat(const UnicodeString& description,
|
||||
, decimalFormatSymbols(NULL)
|
||||
, defaultInfinityRule(NULL)
|
||||
, defaultNaNRule(NULL)
|
||||
, roundingMode(DecimalFormat::ERoundingMode::kRoundUnnecessary)
|
||||
, lenient(FALSE)
|
||||
, lenientParseRules(NULL)
|
||||
, localizations(NULL)
|
||||
@ -735,6 +737,7 @@ RuleBasedNumberFormat::RuleBasedNumberFormat(const UnicodeString& description,
|
||||
, decimalFormatSymbols(NULL)
|
||||
, defaultInfinityRule(NULL)
|
||||
, defaultNaNRule(NULL)
|
||||
, roundingMode(DecimalFormat::ERoundingMode::kRoundUnnecessary)
|
||||
, lenient(FALSE)
|
||||
, lenientParseRules(NULL)
|
||||
, localizations(NULL)
|
||||
@ -758,6 +761,7 @@ RuleBasedNumberFormat::RuleBasedNumberFormat(const UnicodeString& description,
|
||||
, decimalFormatSymbols(NULL)
|
||||
, defaultInfinityRule(NULL)
|
||||
, defaultNaNRule(NULL)
|
||||
, roundingMode(DecimalFormat::ERoundingMode::kRoundUnnecessary)
|
||||
, lenient(FALSE)
|
||||
, lenientParseRules(NULL)
|
||||
, localizations(NULL)
|
||||
@ -782,6 +786,7 @@ RuleBasedNumberFormat::RuleBasedNumberFormat(const UnicodeString& description,
|
||||
, decimalFormatSymbols(NULL)
|
||||
, defaultInfinityRule(NULL)
|
||||
, defaultNaNRule(NULL)
|
||||
, roundingMode(DecimalFormat::ERoundingMode::kRoundUnnecessary)
|
||||
, lenient(FALSE)
|
||||
, lenientParseRules(NULL)
|
||||
, localizations(NULL)
|
||||
@ -803,6 +808,7 @@ RuleBasedNumberFormat::RuleBasedNumberFormat(URBNFRuleSetTag tag, const Locale&
|
||||
, decimalFormatSymbols(NULL)
|
||||
, defaultInfinityRule(NULL)
|
||||
, defaultNaNRule(NULL)
|
||||
, roundingMode(DecimalFormat::ERoundingMode::kRoundUnnecessary)
|
||||
, lenient(FALSE)
|
||||
, lenientParseRules(NULL)
|
||||
, localizations(NULL)
|
||||
@ -869,6 +875,7 @@ RuleBasedNumberFormat::RuleBasedNumberFormat(const RuleBasedNumberFormat& rhs)
|
||||
, decimalFormatSymbols(NULL)
|
||||
, defaultInfinityRule(NULL)
|
||||
, defaultNaNRule(NULL)
|
||||
, roundingMode(DecimalFormat::ERoundingMode::kRoundUnnecessary)
|
||||
, lenient(FALSE)
|
||||
, lenientParseRules(NULL)
|
||||
, localizations(NULL)
|
||||
@ -898,6 +905,7 @@ RuleBasedNumberFormat::operator=(const RuleBasedNumberFormat& rhs)
|
||||
setDecimalFormatSymbols(*rhs.getDecimalFormatSymbols());
|
||||
init(rhs.originalDescription, rhs.localizations ? rhs.localizations->ref() : NULL, perror, status);
|
||||
setDefaultRuleSet(rhs.getDefaultRuleSetName(), status);
|
||||
setRoundingMode(rhs.getRoundingMode());
|
||||
|
||||
capitalizationInfoSet = rhs.capitalizationInfoSet;
|
||||
capitalizationForUIListMenu = rhs.capitalizationForUIListMenu;
|
||||
@ -1195,7 +1203,7 @@ RuleBasedNumberFormat::format(double number,
|
||||
int32_t startPos = toAppendTo.length();
|
||||
UErrorCode status = U_ZERO_ERROR;
|
||||
if (defaultRuleSet) {
|
||||
defaultRuleSet->format(number, toAppendTo, toAppendTo.length(), 0, status);
|
||||
format(number, *defaultRuleSet, toAppendTo, status);
|
||||
}
|
||||
return adjustForCapitalizationContext(startPos, toAppendTo, status);
|
||||
}
|
||||
@ -1248,15 +1256,31 @@ RuleBasedNumberFormat::format(double number,
|
||||
} else {
|
||||
NFRuleSet *rs = findRuleSet(ruleSetName, status);
|
||||
if (rs) {
|
||||
int32_t startPos = toAppendTo.length();
|
||||
rs->format(number, toAppendTo, toAppendTo.length(), 0, status);
|
||||
adjustForCapitalizationContext(startPos, toAppendTo, status);
|
||||
format(number, *rs, toAppendTo, status);
|
||||
}
|
||||
}
|
||||
}
|
||||
return toAppendTo;
|
||||
}
|
||||
|
||||
void
|
||||
RuleBasedNumberFormat::format(double number,
|
||||
NFRuleSet& rs,
|
||||
UnicodeString& toAppendTo,
|
||||
UErrorCode& status) const
|
||||
{
|
||||
int32_t startPos = toAppendTo.length();
|
||||
if (getRoundingMode() != DecimalFormat::ERoundingMode::kRoundUnnecessary && !uprv_isNaN(number) && !uprv_isInfinite(number)) {
|
||||
DigitList digitList;
|
||||
digitList.set(number);
|
||||
digitList.setRoundingMode(getRoundingMode());
|
||||
digitList.roundFixedPoint(getMaximumFractionDigits());
|
||||
number = digitList.getDouble();
|
||||
}
|
||||
rs.format(number, toAppendTo, toAppendTo.length(), 0, status);
|
||||
adjustForCapitalizationContext(startPos, toAppendTo, status);
|
||||
}
|
||||
|
||||
/**
|
||||
* Bottleneck through which all the public format() methods
|
||||
* that take a long pass. By the time we get here, we know
|
||||
@ -1959,6 +1983,23 @@ RuleBasedNumberFormat::createPluralFormat(UPluralType pluralType,
|
||||
return new PluralFormat(locale, pluralType, pattern, status);
|
||||
}
|
||||
|
||||
/**
|
||||
* Get the rounding mode.
|
||||
* @return A rounding mode
|
||||
*/
|
||||
DecimalFormat::ERoundingMode RuleBasedNumberFormat::getRoundingMode() const {
|
||||
return roundingMode;
|
||||
}
|
||||
|
||||
/**
|
||||
* Set the rounding mode. This has no effect unless the rounding
|
||||
* increment is greater than zero.
|
||||
* @param roundingMode A rounding mode
|
||||
*/
|
||||
void RuleBasedNumberFormat::setRoundingMode(DecimalFormat::ERoundingMode roundingMode) {
|
||||
this->roundingMode = roundingMode;
|
||||
}
|
||||
|
||||
U_NAMESPACE_END
|
||||
|
||||
/* U_HAVE_RBNF */
|
||||
|
@ -30,6 +30,7 @@
|
||||
#define U_HAVE_RBNF 1
|
||||
|
||||
#include "unicode/dcfmtsym.h"
|
||||
#include "unicode/decimfmt.h"
|
||||
#include "unicode/fmtable.h"
|
||||
#include "unicode/locid.h"
|
||||
#include "unicode/numfmt.h"
|
||||
@ -1010,6 +1011,22 @@ public:
|
||||
*/
|
||||
virtual void setContext(UDisplayContext value, UErrorCode& status);
|
||||
|
||||
#ifndef U_HIDE_DRAFT_API
|
||||
/**
|
||||
* Get the rounding mode.
|
||||
* @return A rounding mode
|
||||
* @draft ICU 60
|
||||
*/
|
||||
virtual DecimalFormat::ERoundingMode getRoundingMode(void) const;
|
||||
|
||||
/**
|
||||
* Set the rounding mode.
|
||||
* @param roundingMode A rounding mode
|
||||
* @draft ICU 60
|
||||
*/
|
||||
virtual void setRoundingMode(DecimalFormat::ERoundingMode roundingMode);
|
||||
#endif /* U_HIDE_DRAFT_API */
|
||||
|
||||
public:
|
||||
/**
|
||||
* ICU "poor man's RTTI", returns a UClassID for this class.
|
||||
@ -1059,7 +1076,6 @@ private:
|
||||
void dispose();
|
||||
void stripWhitespace(UnicodeString& src);
|
||||
void initDefaultRuleSet();
|
||||
void format(double number, NFRuleSet& ruleSet);
|
||||
NFRuleSet* findRuleSet(const UnicodeString& name, UErrorCode& status) const;
|
||||
|
||||
/* friend access */
|
||||
@ -1079,6 +1095,7 @@ private:
|
||||
PluralFormat *createPluralFormat(UPluralType pluralType, const UnicodeString &pattern, UErrorCode& status) const;
|
||||
UnicodeString& adjustForCapitalizationContext(int32_t startPos, UnicodeString& currentResult, UErrorCode& status) const;
|
||||
UnicodeString& format(int64_t number, NFRuleSet *ruleSet, UnicodeString& toAppendTo, UErrorCode& status) const;
|
||||
void format(double number, NFRuleSet& rs, UnicodeString& toAppendTo, UErrorCode& status) const;
|
||||
|
||||
private:
|
||||
NFRuleSet **ruleSets;
|
||||
@ -1090,6 +1107,7 @@ private:
|
||||
DecimalFormatSymbols* decimalFormatSymbols;
|
||||
NFRule *defaultInfinityRule;
|
||||
NFRule *defaultNaNRule;
|
||||
DecimalFormat::ERoundingMode roundingMode;
|
||||
UBool lenient;
|
||||
UnicodeString* lenientParseRules;
|
||||
LocalizationInfo* localizations;
|
||||
|
@ -512,14 +512,42 @@ unum_getAttribute(const UNumberFormat* fmt,
|
||||
// Supported for all subclasses
|
||||
return nf->isLenient();
|
||||
}
|
||||
else if (attr == UNUM_MAX_INTEGER_DIGITS) {
|
||||
return nf->getMaximumIntegerDigits();
|
||||
}
|
||||
else if (attr == UNUM_MIN_INTEGER_DIGITS) {
|
||||
return nf->getMinimumIntegerDigits();
|
||||
}
|
||||
else if (attr == UNUM_INTEGER_DIGITS) {
|
||||
// TODO: what should this return?
|
||||
return nf->getMinimumIntegerDigits();
|
||||
}
|
||||
else if (attr == UNUM_MAX_FRACTION_DIGITS) {
|
||||
return nf->getMaximumFractionDigits();
|
||||
}
|
||||
else if (attr == UNUM_MIN_FRACTION_DIGITS) {
|
||||
return nf->getMinimumFractionDigits();
|
||||
}
|
||||
else if (attr == UNUM_FRACTION_DIGITS) {
|
||||
// TODO: what should this return?
|
||||
return nf->getMinimumFractionDigits();
|
||||
}
|
||||
|
||||
// The remaining attributea are only supported for DecimalFormat
|
||||
// DecimalFormat specific attributes
|
||||
const DecimalFormat* df = dynamic_cast<const DecimalFormat*>(nf);
|
||||
if (df != NULL) {
|
||||
UErrorCode ignoredStatus = U_ZERO_ERROR;
|
||||
return df->getAttribute(attr, ignoredStatus);
|
||||
}
|
||||
|
||||
// RuleBasedNumberFormat specific attributes
|
||||
const RuleBasedNumberFormat* rbnf = dynamic_cast<const RuleBasedNumberFormat*>(nf);
|
||||
if (rbnf != NULL) {
|
||||
if (attr == UNUM_ROUNDING_MODE) {
|
||||
return rbnf->getRoundingMode();
|
||||
}
|
||||
}
|
||||
|
||||
return -1;
|
||||
}
|
||||
|
||||
@ -534,12 +562,41 @@ unum_setAttribute( UNumberFormat* fmt,
|
||||
// keep this here as the class may not be a DecimalFormat
|
||||
return nf->setLenient(newValue != 0);
|
||||
}
|
||||
// The remaining attributea are only supported for DecimalFormat
|
||||
else if (attr == UNUM_MAX_INTEGER_DIGITS) {
|
||||
return nf->setMaximumIntegerDigits(newValue);
|
||||
}
|
||||
else if (attr == UNUM_MIN_INTEGER_DIGITS) {
|
||||
return nf->setMinimumIntegerDigits(newValue);
|
||||
}
|
||||
else if (attr == UNUM_INTEGER_DIGITS) {
|
||||
nf->setMinimumIntegerDigits(newValue);
|
||||
return nf->setMaximumIntegerDigits(newValue);
|
||||
}
|
||||
else if (attr == UNUM_MAX_FRACTION_DIGITS) {
|
||||
return nf->setMaximumFractionDigits(newValue);
|
||||
}
|
||||
else if (attr == UNUM_MIN_FRACTION_DIGITS) {
|
||||
return nf->setMinimumFractionDigits(newValue);
|
||||
}
|
||||
else if (attr == UNUM_FRACTION_DIGITS) {
|
||||
nf->setMinimumFractionDigits(newValue);
|
||||
return nf->setMaximumFractionDigits(newValue);
|
||||
}
|
||||
|
||||
// DecimalFormat specific attributes
|
||||
DecimalFormat* df = dynamic_cast<DecimalFormat*>(nf);
|
||||
if (df != NULL) {
|
||||
UErrorCode ignoredStatus = U_ZERO_ERROR;
|
||||
df->setAttribute(attr, newValue, ignoredStatus);
|
||||
}
|
||||
|
||||
// RuleBasedNumberFormat specific attributes
|
||||
RuleBasedNumberFormat* rbnf = dynamic_cast<RuleBasedNumberFormat*>(nf);
|
||||
if (rbnf != NULL) {
|
||||
if (attr == UNUM_ROUNDING_MODE) {
|
||||
return rbnf->setRoundingMode((DecimalFormat::ERoundingMode)newValue);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
U_CAPI double U_EXPORT2
|
||||
|
@ -64,6 +64,7 @@ static void TestCurrFmtNegSameAsPositive(void);
|
||||
static void TestVariousStylesAndAttributes(void);
|
||||
static void TestParseCurrPatternWithDecStyle(void);
|
||||
static void TestFormatForFields(void);
|
||||
static void TestRBNFRounding(void);
|
||||
|
||||
#define TESTCASE(x) addTest(root, &x, "tsformat/cnumtst/" #x)
|
||||
|
||||
@ -79,6 +80,7 @@ void addNumForTest(TestNode** root)
|
||||
TESTCASE(TestCurrencyRegression);
|
||||
TESTCASE(TestTextAttributeCrash);
|
||||
TESTCASE(TestRBNFFormat);
|
||||
TESTCASE(TestRBNFRounding);
|
||||
TESTCASE(TestNBSPInPattern);
|
||||
TESTCASE(TestInt64Parse);
|
||||
TESTCASE(TestParseZero);
|
||||
@ -1791,6 +1793,48 @@ static void TestRBNFFormat() {
|
||||
}
|
||||
}
|
||||
|
||||
static void TestRBNFRounding() {
|
||||
UChar fmtbuf[FORMAT_BUF_CAPACITY];
|
||||
UChar expectedBuf[FORMAT_BUF_CAPACITY];
|
||||
int32_t len;
|
||||
UErrorCode status = U_ZERO_ERROR;
|
||||
UNumberFormat* fmt = unum_open(UNUM_SPELLOUT, NULL, 0, "en_US", NULL, &status);
|
||||
if (U_FAILURE(status)) {
|
||||
log_err_status(status, "unable to open spellout -> %s\n", u_errorName(status));
|
||||
return;
|
||||
}
|
||||
len = unum_formatDouble(fmt, 10.123456789, fmtbuf, FORMAT_BUF_CAPACITY, NULL, &status);
|
||||
if (U_FAILURE(status)) {
|
||||
log_err_status(status, "unum_formatDouble 10.123456789 failed with %s\n", u_errorName(status));
|
||||
}
|
||||
u_uastrcpy(expectedBuf, "ten point one two three four five six seven eight nine");
|
||||
if (u_strcmp(expectedBuf, fmtbuf) != 0) {
|
||||
log_err("Wrong result for unrounded value\n");
|
||||
}
|
||||
unum_setAttribute(fmt, UNUM_MAX_FRACTION_DIGITS, 3);
|
||||
if (unum_getAttribute(fmt, UNUM_MAX_FRACTION_DIGITS) != 3) {
|
||||
log_err("UNUM_MAX_FRACTION_DIGITS was incorrectly ignored -> %d\n", unum_getAttribute(fmt, UNUM_MAX_FRACTION_DIGITS));
|
||||
}
|
||||
if (unum_getAttribute(fmt, UNUM_ROUNDING_MODE) != UNUM_ROUND_UNNECESSARY) {
|
||||
log_err("UNUM_ROUNDING_MODE was set -> %d\n", unum_getAttribute(fmt, UNUM_ROUNDING_MODE));
|
||||
}
|
||||
unum_setAttribute(fmt, UNUM_ROUNDING_MODE, UNUM_ROUND_HALFUP);
|
||||
if (unum_getAttribute(fmt, UNUM_ROUNDING_MODE) != UNUM_ROUND_HALFUP) {
|
||||
log_err("UNUM_ROUNDING_MODE was not set -> %d\n", unum_getAttribute(fmt, UNUM_ROUNDING_MODE));
|
||||
}
|
||||
len = unum_formatDouble(fmt, 10.123456789, fmtbuf, FORMAT_BUF_CAPACITY, NULL, &status);
|
||||
if (U_FAILURE(status)) {
|
||||
log_err_status(status, "unum_formatDouble 10.123456789 failed with %s\n", u_errorName(status));
|
||||
}
|
||||
u_uastrcpy(expectedBuf, "ten point one two three");
|
||||
if (u_strcmp(expectedBuf, fmtbuf) != 0) {
|
||||
char temp[512];
|
||||
u_austrcpy(temp, fmtbuf);
|
||||
log_err("Wrong result for rounded value. Got: %s\n", temp);
|
||||
}
|
||||
unum_close(fmt);
|
||||
}
|
||||
|
||||
static void TestCurrencyRegression(void) {
|
||||
/*
|
||||
I've found a case where unum_parseDoubleCurrency is not doing what I
|
||||
|
Loading…
Reference in New Issue
Block a user