Index: source/i18n/nfrs.cpp |
diff --git a/source/i18n/nfrs.cpp b/source/i18n/nfrs.cpp |
index 1a4bf493f3eb7ef83cd1ab8a601884a69c890044..85ebb06fabd4ed9ac7b6d91956d24d93bb7b85e9 100644 |
--- a/source/i18n/nfrs.cpp |
+++ b/source/i18n/nfrs.cpp |
@@ -1,6 +1,6 @@ |
/* |
****************************************************************************** |
-* Copyright (C) 1997-2014, International Business Machines |
+* Copyright (C) 1997-2015, International Business Machines |
* Corporation and others. All Rights Reserved. |
****************************************************************************** |
* file name: nfrs.cpp |
@@ -26,6 +26,22 @@ |
#include "cmemory.h" |
#endif |
+enum { |
+ /** -x */ |
+ NEGATIVE_RULE_INDEX = 0, |
+ /** x.x */ |
+ IMPROPER_FRACTION_RULE_INDEX = 1, |
+ /** 0.x */ |
+ PROPER_FRACTION_RULE_INDEX = 2, |
+ /** x.0 */ |
+ MASTER_RULE_INDEX = 3, |
+ /** Inf */ |
+ INFINITY_RULE_INDEX = 4, |
+ /** NaN */ |
+ NAN_RULE_INDEX = 5, |
+ NON_NUMERICAL_RULE_LENGTH = 6 |
+}; |
+ |
U_NAMESPACE_BEGIN |
#if 0 |
@@ -104,10 +120,6 @@ static const UChar gColon = 0x003a; |
static const UChar gSemicolon = 0x003b; |
static const UChar gLineFeed = 0x000a; |
-static const UChar gFourSpaces[] = |
-{ |
- 0x20, 0x20, 0x20, 0x20, 0 |
-}; /* " " */ |
static const UChar gPercentPercent[] = |
{ |
0x25, 0x25, 0 |
@@ -118,17 +130,17 @@ static const UChar gNoparse[] = |
0x40, 0x6E, 0x6F, 0x70, 0x61, 0x72, 0x73, 0x65, 0 |
}; /* "@noparse" */ |
-NFRuleSet::NFRuleSet(UnicodeString* descriptions, int32_t index, UErrorCode& status) |
+NFRuleSet::NFRuleSet(RuleBasedNumberFormat *_owner, UnicodeString* descriptions, int32_t index, UErrorCode& status) |
: name() |
, rules(0) |
- , negativeNumberRule(NULL) |
+ , owner(_owner) |
+ , fractionRules() |
, fIsFractionRuleSet(FALSE) |
, fIsPublic(FALSE) |
, fIsParseable(TRUE) |
- , fRecursionCount(0) |
{ |
- for (int i = 0; i < 3; ++i) { |
- fractionRules[i] = NULL; |
+ for (int32_t i = 0; i < NON_NUMERICAL_RULE_LENGTH; ++i) { |
+ nonNumericalRules[i] = NULL; |
} |
if (U_FAILURE(status)) { |
@@ -179,7 +191,7 @@ NFRuleSet::NFRuleSet(UnicodeString* descriptions, int32_t index, UErrorCode& sta |
} |
void |
-NFRuleSet::parseRules(UnicodeString& description, const RuleBasedNumberFormat* owner, UErrorCode& status) |
+NFRuleSet::parseRules(UnicodeString& description, UErrorCode& status) |
{ |
// start by creating a Vector whose elements are Strings containing |
// the descriptions of the rules (one rule per element). The rules |
@@ -217,85 +229,103 @@ NFRuleSet::parseRules(UnicodeString& description, const RuleBasedNumberFormat* o |
// (this isn't a for loop because we might be deleting items from |
// the vector-- we want to make sure we only increment i when |
// we _didn't_ delete aything from the vector) |
- uint32_t i = 0; |
- while (i < rules.size()) { |
+ int32_t rulesSize = rules.size(); |
+ for (int32_t i = 0; i < rulesSize; i++) { |
NFRule* rule = rules[i]; |
+ int64_t baseValue = rule->getBaseValue(); |
- switch (rule->getType()) { |
+ if (baseValue == 0) { |
// if the rule's base value is 0, fill in a default |
// base value (this will be 1 plus the preceding |
// rule's base value for regular rule sets, and the |
// same as the preceding rule's base value in fraction |
// rule sets) |
- case NFRule::kNoBase: |
rule->setBaseValue(defaultBaseValue, status); |
- if (!isFractionRuleSet()) { |
- ++defaultBaseValue; |
- } |
- ++i; |
- break; |
- |
- // if it's the negative-number rule, copy it into its own |
- // data member and delete it from the list |
- case NFRule::kNegativeNumberRule: |
- if (negativeNumberRule) { |
- delete negativeNumberRule; |
- } |
- negativeNumberRule = rules.remove(i); |
- break; |
- |
- // if it's the improper fraction rule, copy it into the |
- // correct element of fractionRules |
- case NFRule::kImproperFractionRule: |
- if (fractionRules[0]) { |
- delete fractionRules[0]; |
- } |
- fractionRules[0] = rules.remove(i); |
- break; |
- |
- // if it's the proper fraction rule, copy it into the |
- // correct element of fractionRules |
- case NFRule::kProperFractionRule: |
- if (fractionRules[1]) { |
- delete fractionRules[1]; |
- } |
- fractionRules[1] = rules.remove(i); |
- break; |
- |
- // if it's the master rule, copy it into the |
- // correct element of fractionRules |
- case NFRule::kMasterRule: |
- if (fractionRules[2]) { |
- delete fractionRules[2]; |
- } |
- fractionRules[2] = rules.remove(i); |
- break; |
- |
+ } |
+ else { |
// if it's a regular rule that already knows its base value, |
// check to make sure the rules are in order, and update |
// the default base value for the next rule |
- default: |
- if (rule->getBaseValue() < defaultBaseValue) { |
+ if (baseValue < defaultBaseValue) { |
// throw new IllegalArgumentException("Rules are not in order"); |
status = U_PARSE_ERROR; |
return; |
} |
- defaultBaseValue = rule->getBaseValue(); |
- if (!isFractionRuleSet()) { |
- ++defaultBaseValue; |
- } |
- ++i; |
- break; |
+ defaultBaseValue = baseValue; |
+ } |
+ if (!fIsFractionRuleSet) { |
+ ++defaultBaseValue; |
} |
} |
} |
+/** |
+ * Set one of the non-numerical rules. |
+ * @param rule The rule to set. |
+ */ |
+void NFRuleSet::setNonNumericalRule(NFRule *rule) { |
+ int64_t baseValue = rule->getBaseValue(); |
+ if (baseValue == NFRule::kNegativeNumberRule) { |
+ delete nonNumericalRules[NEGATIVE_RULE_INDEX]; |
+ nonNumericalRules[NEGATIVE_RULE_INDEX] = rule; |
+ } |
+ else if (baseValue == NFRule::kImproperFractionRule) { |
+ setBestFractionRule(IMPROPER_FRACTION_RULE_INDEX, rule, TRUE); |
+ } |
+ else if (baseValue == NFRule::kProperFractionRule) { |
+ setBestFractionRule(PROPER_FRACTION_RULE_INDEX, rule, TRUE); |
+ } |
+ else if (baseValue == NFRule::kMasterRule) { |
+ setBestFractionRule(MASTER_RULE_INDEX, rule, TRUE); |
+ } |
+ else if (baseValue == NFRule::kInfinityRule) { |
+ delete nonNumericalRules[INFINITY_RULE_INDEX]; |
+ nonNumericalRules[INFINITY_RULE_INDEX] = rule; |
+ } |
+ else if (baseValue == NFRule::kNaNRule) { |
+ delete nonNumericalRules[NAN_RULE_INDEX]; |
+ nonNumericalRules[NAN_RULE_INDEX] = rule; |
+ } |
+} |
+ |
+/** |
+ * Determine the best fraction rule to use. Rules matching the decimal point from |
+ * DecimalFormatSymbols become the main set of rules to use. |
+ * @param originalIndex The index into nonNumericalRules |
+ * @param newRule The new rule to consider |
+ * @param rememberRule Should the new rule be added to fractionRules. |
+ */ |
+void NFRuleSet::setBestFractionRule(int32_t originalIndex, NFRule *newRule, UBool rememberRule) { |
+ if (rememberRule) { |
+ fractionRules.add(newRule); |
+ } |
+ NFRule *bestResult = nonNumericalRules[originalIndex]; |
+ if (bestResult == NULL) { |
+ nonNumericalRules[originalIndex] = newRule; |
+ } |
+ else { |
+ // We have more than one. Which one is better? |
+ const DecimalFormatSymbols *decimalFormatSymbols = owner->getDecimalFormatSymbols(); |
+ if (decimalFormatSymbols->getSymbol(DecimalFormatSymbols::kDecimalSeparatorSymbol).charAt(0) |
+ == newRule->getDecimalPoint()) |
+ { |
+ nonNumericalRules[originalIndex] = newRule; |
+ } |
+ // else leave it alone |
+ } |
+} |
+ |
NFRuleSet::~NFRuleSet() |
{ |
- delete negativeNumberRule; |
- delete fractionRules[0]; |
- delete fractionRules[1]; |
- delete fractionRules[2]; |
+ for (int i = 0; i < NON_NUMERICAL_RULE_LENGTH; i++) { |
+ if (i != IMPROPER_FRACTION_RULE_INDEX |
+ && i != PROPER_FRACTION_RULE_INDEX |
+ && i != MASTER_RULE_INDEX) |
+ { |
+ delete nonNumericalRules[i]; |
+ } |
+ // else it will be deleted via NFRuleList fractionRules |
+ } |
} |
static UBool |
@@ -316,12 +346,16 @@ NFRuleSet::operator==(const NFRuleSet& rhs) const |
{ |
if (rules.size() == rhs.rules.size() && |
fIsFractionRuleSet == rhs.fIsFractionRuleSet && |
- name == rhs.name && |
- util_equalRules(negativeNumberRule, rhs.negativeNumberRule) && |
- util_equalRules(fractionRules[0], rhs.fractionRules[0]) && |
- util_equalRules(fractionRules[1], rhs.fractionRules[1]) && |
- util_equalRules(fractionRules[2], rhs.fractionRules[2])) { |
+ name == rhs.name) { |
+ // ...then compare the non-numerical rule lists... |
+ for (int i = 0; i < NON_NUMERICAL_RULE_LENGTH; i++) { |
+ if (!util_equalRules(nonNumericalRules[i], rhs.nonNumericalRules[i])) { |
+ return FALSE; |
+ } |
+ } |
+ |
+ // ...then compare the rule lists... |
for (uint32_t i = 0; i < rules.size(); ++i) { |
if (*rules[i] != *rhs.rules[i]) { |
return FALSE; |
@@ -332,41 +366,62 @@ NFRuleSet::operator==(const NFRuleSet& rhs) const |
return FALSE; |
} |
-#define RECURSION_LIMIT 50 |
+void |
+NFRuleSet::setDecimalFormatSymbols(const DecimalFormatSymbols &newSymbols, UErrorCode& status) { |
+ for (uint32_t i = 0; i < rules.size(); ++i) { |
+ rules[i]->setDecimalFormatSymbols(newSymbols, status); |
+ } |
+ // Switch the fraction rules to mirror the DecimalFormatSymbols. |
+ for (int32_t nonNumericalIdx = IMPROPER_FRACTION_RULE_INDEX; nonNumericalIdx <= MASTER_RULE_INDEX; nonNumericalIdx++) { |
+ if (nonNumericalRules[nonNumericalIdx]) { |
+ for (uint32_t fIdx = 0; fIdx < fractionRules.size(); fIdx++) { |
+ NFRule *fractionRule = fractionRules[fIdx]; |
+ if (nonNumericalRules[nonNumericalIdx]->getBaseValue() == fractionRule->getBaseValue()) { |
+ setBestFractionRule(nonNumericalIdx, fractionRule, FALSE); |
+ } |
+ } |
+ } |
+ } |
+ |
+ for (uint32_t nnrIdx = 0; nnrIdx < NON_NUMERICAL_RULE_LENGTH; nnrIdx++) { |
+ NFRule *rule = nonNumericalRules[nnrIdx]; |
+ if (rule) { |
+ rule->setDecimalFormatSymbols(newSymbols, status); |
+ } |
+ } |
+} |
+ |
+#define RECURSION_LIMIT 64 |
void |
-NFRuleSet::format(int64_t number, UnicodeString& toAppendTo, int32_t pos, UErrorCode& status) const |
+NFRuleSet::format(int64_t number, UnicodeString& toAppendTo, int32_t pos, int32_t recursionCount, UErrorCode& status) const |
{ |
- NFRule *rule = findNormalRule(number); |
+ if (recursionCount >= RECURSION_LIMIT) { |
+ // stop recursion |
+ status = U_INVALID_STATE_ERROR; |
+ return; |
+ } |
+ const NFRule *rule = findNormalRule(number); |
if (rule) { // else error, but can't report it |
- NFRuleSet* ncThis = (NFRuleSet*)this; |
- if (ncThis->fRecursionCount++ >= RECURSION_LIMIT) { |
- // stop recursion |
- ncThis->fRecursionCount = 0; |
- } else { |
- rule->doFormat(number, toAppendTo, pos, status); |
- ncThis->fRecursionCount--; |
- } |
+ rule->doFormat(number, toAppendTo, pos, ++recursionCount, status); |
} |
} |
void |
-NFRuleSet::format(double number, UnicodeString& toAppendTo, int32_t pos, UErrorCode& status) const |
+NFRuleSet::format(double number, UnicodeString& toAppendTo, int32_t pos, int32_t recursionCount, UErrorCode& status) const |
{ |
- NFRule *rule = findDoubleRule(number); |
+ if (recursionCount >= RECURSION_LIMIT) { |
+ // stop recursion |
+ status = U_INVALID_STATE_ERROR; |
+ return; |
+ } |
+ const NFRule *rule = findDoubleRule(number); |
if (rule) { // else error, but can't report it |
- NFRuleSet* ncThis = (NFRuleSet*)this; |
- if (ncThis->fRecursionCount++ >= RECURSION_LIMIT) { |
- // stop recursion |
- ncThis->fRecursionCount = 0; |
- } else { |
- rule->doFormat(number, toAppendTo, pos, status); |
- ncThis->fRecursionCount--; |
- } |
+ rule->doFormat(number, toAppendTo, pos, ++recursionCount, status); |
} |
} |
-NFRule* |
+const NFRule* |
NFRuleSet::findDoubleRule(double number) const |
{ |
// if this is a fraction rule set, use findFractionRuleSetRule() |
@@ -374,33 +429,49 @@ NFRuleSet::findDoubleRule(double number) const |
return findFractionRuleSetRule(number); |
} |
+ if (uprv_isNaN(number)) { |
+ const NFRule *rule = nonNumericalRules[NAN_RULE_INDEX]; |
+ if (!rule) { |
+ rule = owner->getDefaultNaNRule(); |
+ } |
+ return rule; |
+ } |
+ |
// if the number is negative, return the negative number rule |
// (if there isn't a negative-number rule, we pretend it's a |
// positive number) |
if (number < 0) { |
- if (negativeNumberRule) { |
- return negativeNumberRule; |
+ if (nonNumericalRules[NEGATIVE_RULE_INDEX]) { |
+ return nonNumericalRules[NEGATIVE_RULE_INDEX]; |
} else { |
number = -number; |
} |
} |
+ if (uprv_isInfinite(number)) { |
+ const NFRule *rule = nonNumericalRules[INFINITY_RULE_INDEX]; |
+ if (!rule) { |
+ rule = owner->getDefaultInfinityRule(); |
+ } |
+ return rule; |
+ } |
+ |
// if the number isn't an integer, we use one of the fraction rules... |
if (number != uprv_floor(number)) { |
// if the number is between 0 and 1, return the proper |
// fraction rule |
- if (number < 1 && fractionRules[1]) { |
- return fractionRules[1]; |
+ if (number < 1 && nonNumericalRules[PROPER_FRACTION_RULE_INDEX]) { |
+ return nonNumericalRules[PROPER_FRACTION_RULE_INDEX]; |
} |
// otherwise, return the improper fraction rule |
- else if (fractionRules[0]) { |
- return fractionRules[0]; |
+ else if (nonNumericalRules[IMPROPER_FRACTION_RULE_INDEX]) { |
+ return nonNumericalRules[IMPROPER_FRACTION_RULE_INDEX]; |
} |
} |
// if there's a master rule, use it to format the number |
- if (fractionRules[2]) { |
- return fractionRules[2]; |
+ if (nonNumericalRules[MASTER_RULE_INDEX]) { |
+ return nonNumericalRules[MASTER_RULE_INDEX]; |
} |
// and if we haven't yet returned a rule, use findNormalRule() |
@@ -409,7 +480,7 @@ NFRuleSet::findDoubleRule(double number) const |
return findNormalRule(r); |
} |
-NFRule * |
+const NFRule * |
NFRuleSet::findNormalRule(int64_t number) const |
{ |
// if this is a fraction rule set, use findFractionRuleSetRule() |
@@ -422,8 +493,8 @@ NFRuleSet::findNormalRule(int64_t number) const |
// if the number is negative, return the negative-number rule |
// (if there isn't one, pretend the number is positive) |
if (number < 0) { |
- if (negativeNumberRule) { |
- return negativeNumberRule; |
+ if (nonNumericalRules[NEGATIVE_RULE_INDEX]) { |
+ return nonNumericalRules[NEGATIVE_RULE_INDEX]; |
} else { |
number = -number; |
} |
@@ -480,7 +551,7 @@ NFRuleSet::findNormalRule(int64_t number) const |
return result; |
} |
// else use the master rule |
- return fractionRules[2]; |
+ return nonNumericalRules[MASTER_RULE_INDEX]; |
} |
/** |
@@ -498,7 +569,7 @@ NFRuleSet::findNormalRule(int64_t number) const |
* a number between 0 and 1) |
* @return The rule to use to format this number |
*/ |
-NFRule* |
+const NFRule* |
NFRuleSet::findFractionRuleSetRule(double number) const |
{ |
// the obvious way to do this (multiply the value being formatted |
@@ -631,40 +702,16 @@ NFRuleSet::parse(const UnicodeString& text, ParsePosition& pos, double upperBoun |
fprintf(stderr, "'\n"); |
fprintf(stderr, " parse negative: %d\n", this, negativeNumberRule != 0); |
#endif |
- |
- // start by trying the negative number rule (if there is one) |
- if (negativeNumberRule) { |
- Formattable tempResult; |
-#ifdef RBNF_DEBUG |
- fprintf(stderr, " <nfrs before negative> %x ub: %g\n", negativeNumberRule, upperBound); |
-#endif |
- UBool success = negativeNumberRule->doParse(text, workingPos, 0, upperBound, tempResult); |
-#ifdef RBNF_DEBUG |
- fprintf(stderr, " <nfrs after negative> success: %d wpi: %d\n", success, workingPos.getIndex()); |
-#endif |
- if (success && workingPos.getIndex() > highWaterMark.getIndex()) { |
- result = tempResult; |
- highWaterMark = workingPos; |
- } |
- workingPos = pos; |
- } |
-#ifdef RBNF_DEBUG |
- fprintf(stderr, "<nfrs> continue fractional with text '"); |
- dumpUS(stderr, text); |
- fprintf(stderr, "' hwm: %d\n", highWaterMark.getIndex()); |
-#endif |
- // then try each of the fraction rules |
- { |
- for (int i = 0; i < 3; i++) { |
- if (fractionRules[i]) { |
- Formattable tempResult; |
- UBool success = fractionRules[i]->doParse(text, workingPos, 0, upperBound, tempResult); |
- if (success && (workingPos.getIndex() > highWaterMark.getIndex())) { |
- result = tempResult; |
- highWaterMark = workingPos; |
- } |
- workingPos = pos; |
+ // Try each of the negative rules, fraction rules, infinity rules and NaN rules |
+ for (int i = 0; i < NON_NUMERICAL_RULE_LENGTH; i++) { |
+ if (nonNumericalRules[i]) { |
+ Formattable tempResult; |
+ UBool success = nonNumericalRules[i]->doParse(text, workingPos, 0, upperBound, tempResult); |
+ if (success && (workingPos.getIndex() > highWaterMark.getIndex())) { |
+ result = tempResult; |
+ highWaterMark = workingPos; |
} |
+ workingPos = pos; |
} |
} |
#ifdef RBNF_DEBUG |
@@ -720,30 +767,37 @@ NFRuleSet::parse(const UnicodeString& text, ParsePosition& pos, double upperBoun |
void |
NFRuleSet::appendRules(UnicodeString& result) const |
{ |
+ uint32_t i; |
+ |
// the rule set name goes first... |
result.append(name); |
result.append(gColon); |
result.append(gLineFeed); |
// followed by the regular rules... |
- for (uint32_t i = 0; i < rules.size(); i++) { |
- result.append(gFourSpaces, 4); |
+ for (i = 0; i < rules.size(); i++) { |
rules[i]->_appendRuleText(result); |
result.append(gLineFeed); |
} |
// followed by the special rules (if they exist) |
- if (negativeNumberRule) { |
- result.append(gFourSpaces, 4); |
- negativeNumberRule->_appendRuleText(result); |
- result.append(gLineFeed); |
- } |
- |
- { |
- for (uint32_t i = 0; i < 3; ++i) { |
- if (fractionRules[i]) { |
- result.append(gFourSpaces, 4); |
- fractionRules[i]->_appendRuleText(result); |
+ for (i = 0; i < NON_NUMERICAL_RULE_LENGTH; ++i) { |
+ NFRule *rule = nonNumericalRules[i]; |
+ if (nonNumericalRules[i]) { |
+ if (rule->getBaseValue() == NFRule::kImproperFractionRule |
+ || rule->getBaseValue() == NFRule::kProperFractionRule |
+ || rule->getBaseValue() == NFRule::kMasterRule) |
+ { |
+ for (uint32_t fIdx = 0; fIdx < fractionRules.size(); fIdx++) { |
+ NFRule *fractionRule = fractionRules[fIdx]; |
+ if (fractionRule->getBaseValue() == rule->getBaseValue()) { |
+ fractionRule->_appendRuleText(result); |
+ result.append(gLineFeed); |
+ } |
+ } |
+ } |
+ else { |
+ rule->_appendRuleText(result); |
result.append(gLineFeed); |
} |
} |