mirror of
https://github.com/unicode-org/icu.git
synced 2025-04-13 08:53:20 +00:00
ICU-11564 Improve the thread safety of RBNF.
The recursion count is now a method argument instead of a data member. Some data fields are now marked final to ensure thread safety, which caused reordering of some data initialization/parsing. Setting the DecimalFormatSymbols no longer reparses the rules, but it just sets a new version of DecimalFormatSymbols instead. X-SVN-Rev: 37383
This commit is contained in:
parent
a649861ff9
commit
a423e7cb09
4 changed files with 135 additions and 151 deletions
icu4j/main/classes/core/src/com/ibm/icu/text
|
@ -106,7 +106,7 @@ final class NFRule {
|
|||
* rule list
|
||||
* @param ownersOwner The RuleBasedNumberFormat that owns the
|
||||
* rule set that owns the new rule(s)
|
||||
* @param returnList A list of NFRules
|
||||
* @param returnList One or more instances of NFRule are added and returned here
|
||||
*/
|
||||
public static void makeRules(String description,
|
||||
NFRuleSet owner,
|
||||
|
@ -684,7 +684,7 @@ final class NFRule {
|
|||
* @param pos The position in toInsertInto where the resultant text
|
||||
* should be inserted
|
||||
*/
|
||||
public void doFormat(long number, StringBuffer toInsertInto, int pos) {
|
||||
public void doFormat(long number, StringBuffer toInsertInto, int pos, int recursionCount) {
|
||||
// first, insert the rule's rule text into toInsertInto at the
|
||||
// specified position, then insert the results of the substitutions
|
||||
// into the right places in toInsertInto (notice we do the
|
||||
|
@ -709,10 +709,10 @@ final class NFRule {
|
|||
lengthOffset = ruleText.length() - (toInsertInto.length() - initialLength);
|
||||
}
|
||||
if (!sub2.isNullSubstitution()) {
|
||||
sub2.doSubstitution(number, toInsertInto, pos - (sub2.getPos() > pluralRuleStart ? lengthOffset : 0));
|
||||
sub2.doSubstitution(number, toInsertInto, pos - (sub2.getPos() > pluralRuleStart ? lengthOffset : 0), recursionCount);
|
||||
}
|
||||
if (!sub1.isNullSubstitution()) {
|
||||
sub1.doSubstitution(number, toInsertInto, pos - (sub1.getPos() > pluralRuleStart ? lengthOffset : 0));
|
||||
sub1.doSubstitution(number, toInsertInto, pos - (sub1.getPos() > pluralRuleStart ? lengthOffset : 0), recursionCount);
|
||||
}
|
||||
}
|
||||
|
||||
|
@ -725,7 +725,7 @@ final class NFRule {
|
|||
* @param pos The position in toInsertInto where the resultant text
|
||||
* should be inserted
|
||||
*/
|
||||
public void doFormat(double number, StringBuffer toInsertInto, int pos) {
|
||||
public void doFormat(double number, StringBuffer toInsertInto, int pos, int recursionCount) {
|
||||
// first, insert the rule's rule text into toInsertInto at the
|
||||
// specified position, then insert the results of the substitutions
|
||||
// into the right places in toInsertInto
|
||||
|
@ -751,10 +751,10 @@ final class NFRule {
|
|||
lengthOffset = ruleText.length() - (toInsertInto.length() - initialLength);
|
||||
}
|
||||
if (!sub2.isNullSubstitution()) {
|
||||
sub2.doSubstitution(number, toInsertInto, pos - (sub2.getPos() > pluralRuleStart ? lengthOffset : 0));
|
||||
sub2.doSubstitution(number, toInsertInto, pos - (sub2.getPos() > pluralRuleStart ? lengthOffset : 0), recursionCount);
|
||||
}
|
||||
if (!sub1.isNullSubstitution()) {
|
||||
sub1.doSubstitution(number, toInsertInto, pos - (sub1.getPos() > pluralRuleStart ? lengthOffset : 0));
|
||||
sub1.doSubstitution(number, toInsertInto, pos - (sub1.getPos() > pluralRuleStart ? lengthOffset : 0), recursionCount);
|
||||
}
|
||||
}
|
||||
|
||||
|
@ -1203,4 +1203,13 @@ final class NFRule {
|
|||
RbnfLenientScanner scanner = formatter.getLenientScanner();
|
||||
return scanner != null && scanner.allIgnorable(str);
|
||||
}
|
||||
|
||||
public void setDecimalFormatSymbols(DecimalFormatSymbols newSymbols) {
|
||||
if (sub1 != null) {
|
||||
sub1.setDecimalFormatSymbols(newSymbols);
|
||||
}
|
||||
if (sub2 != null) {
|
||||
sub2.setDecimalFormatSymbols(newSymbols);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
|
|
@ -29,7 +29,7 @@ final class NFRuleSet {
|
|||
/**
|
||||
* The rule set's name
|
||||
*/
|
||||
private String name;
|
||||
private final String name;
|
||||
|
||||
/**
|
||||
* The rule set's regular rules
|
||||
|
@ -61,17 +61,12 @@ final class NFRuleSet {
|
|||
/**
|
||||
* True if the rule set is parseable.
|
||||
*/
|
||||
private boolean isParseable = true;
|
||||
private final boolean isParseable;
|
||||
|
||||
/**
|
||||
* Used to limit recursion for bad rule sets.
|
||||
* Limit of recursion. It's about a 64 bit number formatted in base 2.
|
||||
*/
|
||||
private int recursionCount = 0;
|
||||
|
||||
/**
|
||||
* Limit of recursion.
|
||||
*/
|
||||
private static final int RECURSION_LIMIT = 50;
|
||||
private static final int RECURSION_LIMIT = 64;
|
||||
|
||||
//-----------------------------------------------------------------------
|
||||
// construction
|
||||
|
@ -102,7 +97,13 @@ final class NFRuleSet {
|
|||
throw new IllegalArgumentException("Rule set name doesn't end in colon");
|
||||
}
|
||||
else {
|
||||
name = description.substring(0, pos);
|
||||
String name = description.substring(0, pos);
|
||||
this.isParseable = !name.endsWith("@noparse");
|
||||
if (!this.isParseable) {
|
||||
name = name.substring(0,name.length()-8); // Remove the @noparse from the name
|
||||
}
|
||||
this.name = name;
|
||||
|
||||
while (pos < description.length() && PatternProps.isWhiteSpace(description.charAt(++pos))) {
|
||||
}
|
||||
description = description.substring(pos);
|
||||
|
@ -113,17 +114,13 @@ final class NFRuleSet {
|
|||
// if the description doesn't begin with a rule set name, its
|
||||
// name is "%default"
|
||||
name = "%default";
|
||||
isParseable = true;
|
||||
}
|
||||
|
||||
if (description.length() == 0) {
|
||||
throw new IllegalArgumentException("Empty rule set description");
|
||||
}
|
||||
|
||||
if ( name.endsWith("@noparse")) {
|
||||
name = name.substring(0,name.length()-8); // Remove the @noparse from the name
|
||||
isParseable = false;
|
||||
}
|
||||
|
||||
// all of the other members of NFRuleSet are initialized
|
||||
// by parseRules()
|
||||
}
|
||||
|
@ -389,15 +386,13 @@ final class NFRuleSet {
|
|||
* @param pos The position in toInsertInto where the result of
|
||||
* this operation is to be inserted
|
||||
*/
|
||||
public void format(long number, StringBuffer toInsertInto, int pos) {
|
||||
public void format(long number, StringBuffer toInsertInto, int pos, int recursionCount) {
|
||||
NFRule applicableRule = findNormalRule(number);
|
||||
|
||||
if (++recursionCount >= RECURSION_LIMIT) {
|
||||
recursionCount = 0;
|
||||
if (recursionCount >= RECURSION_LIMIT) {
|
||||
throw new IllegalStateException("Recursion limit exceeded when applying ruleSet " + name);
|
||||
}
|
||||
applicableRule.doFormat(number, toInsertInto, pos);
|
||||
--recursionCount;
|
||||
applicableRule.doFormat(number, toInsertInto, pos, ++recursionCount);
|
||||
}
|
||||
|
||||
/**
|
||||
|
@ -408,15 +403,13 @@ final class NFRuleSet {
|
|||
* @param pos The position in toInsertInto where the result of
|
||||
* this operation is to be inserted
|
||||
*/
|
||||
public void format(double number, StringBuffer toInsertInto, int pos) {
|
||||
public void format(double number, StringBuffer toInsertInto, int pos, int recursionCount) {
|
||||
NFRule applicableRule = findRule(number);
|
||||
|
||||
if (++recursionCount >= RECURSION_LIMIT) {
|
||||
recursionCount = 0;
|
||||
if (recursionCount >= RECURSION_LIMIT) {
|
||||
throw new IllegalStateException("Recursion limit exceeded when applying ruleSet " + name);
|
||||
}
|
||||
applicableRule.doFormat(number, toInsertInto, pos);
|
||||
--recursionCount;
|
||||
applicableRule.doFormat(number, toInsertInto, pos, ++recursionCount);
|
||||
}
|
||||
|
||||
/**
|
||||
|
@ -779,4 +772,10 @@ final class NFRuleSet {
|
|||
|
||||
return result;
|
||||
}
|
||||
|
||||
public void setDecimalFormatSymbols(DecimalFormatSymbols newSymbols) {
|
||||
for (NFRule rule : rules) {
|
||||
rule.setDecimalFormatSymbols(newSymbols);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
|
|
@ -1,6 +1,6 @@
|
|||
/*
|
||||
*******************************************************************************
|
||||
* Copyright (C) 1996-2014, International Business Machines Corporation and *
|
||||
* Copyright (C) 1996-2015, International Business Machines Corporation and *
|
||||
* others. All Rights Reserved. *
|
||||
*******************************************************************************
|
||||
*/
|
||||
|
@ -292,14 +292,14 @@ abstract class NFSubstitution {
|
|||
* rule text begins (this value is added to this substitution's
|
||||
* position to determine exactly where to insert the new text)
|
||||
*/
|
||||
public void doSubstitution(long number, StringBuffer toInsertInto, int position) {
|
||||
public void doSubstitution(long number, StringBuffer toInsertInto, int position, int recursionCount) {
|
||||
if (ruleSet != null) {
|
||||
// perform a transformation on the number that is dependent
|
||||
// on the type of substitution this is, then just call its
|
||||
// rule set's format() method to format the result
|
||||
long numberToFormat = transformNumber(number);
|
||||
|
||||
ruleSet.format(numberToFormat, toInsertInto, position + pos);
|
||||
ruleSet.format(numberToFormat, toInsertInto, position + pos, recursionCount);
|
||||
} else {
|
||||
// or perform the transformation on the number (preserving
|
||||
// the result's fractional part if the formatter it set
|
||||
|
@ -324,7 +324,7 @@ abstract class NFSubstitution {
|
|||
* rule text begins (this value is added to this substitution's
|
||||
* position to determine exactly where to insert the new text)
|
||||
*/
|
||||
public void doSubstitution(double number, StringBuffer toInsertInto, int position) {
|
||||
public void doSubstitution(double number, StringBuffer toInsertInto, int position, int recursionCount) {
|
||||
// perform a transformation on the number being formatted that
|
||||
// is dependent on the type of substitution this is
|
||||
double numberToFormat = transformNumber(number);
|
||||
|
@ -332,14 +332,14 @@ abstract class NFSubstitution {
|
|||
// if the result is an integer, from here on out we work in integer
|
||||
// space (saving time and memory and preserving accuracy)
|
||||
if (numberToFormat == Math.floor(numberToFormat) && ruleSet != null) {
|
||||
ruleSet.format((long)numberToFormat, toInsertInto, position + pos);
|
||||
ruleSet.format((long)numberToFormat, toInsertInto, position + pos, recursionCount);
|
||||
|
||||
// if the result isn't an integer, then call either our rule set's
|
||||
// format() method or our DecimalFormat's format() method to
|
||||
// format the result
|
||||
} else {
|
||||
if (ruleSet != null) {
|
||||
ruleSet.format(numberToFormat, toInsertInto, position + pos);
|
||||
ruleSet.format(numberToFormat, toInsertInto, position + pos, recursionCount);
|
||||
} else {
|
||||
toInsertInto.insert(position + this.pos, numberFormat.format(numberToFormat));
|
||||
}
|
||||
|
@ -533,6 +533,13 @@ abstract class NFSubstitution {
|
|||
public boolean isModulusSubstitution() {
|
||||
return false;
|
||||
}
|
||||
|
||||
|
||||
public void setDecimalFormatSymbols(DecimalFormatSymbols newSymbols) {
|
||||
if (numberFormat != null) {
|
||||
numberFormat.setDecimalFormatSymbols(newSymbols);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
//===================================================================
|
||||
|
@ -697,13 +704,7 @@ class MultiplierSubstitution extends NFSubstitution {
|
|||
* @return true if the two substitutions are functionally equal
|
||||
*/
|
||||
public boolean equals(Object that) {
|
||||
if (super.equals(that)) {
|
||||
MultiplierSubstitution that2 = (MultiplierSubstitution)that;
|
||||
|
||||
return divisor == that2.divisor;
|
||||
} else {
|
||||
return false;
|
||||
}
|
||||
return super.equals(that) && divisor == ((MultiplierSubstitution) that).divisor;
|
||||
}
|
||||
|
||||
//-----------------------------------------------------------------------
|
||||
|
@ -798,7 +799,7 @@ class ModulusSubstitution extends NFSubstitution {
|
|||
* If this is a >>> substitution, the rule to use to format
|
||||
* the substitution value. Otherwise, null.
|
||||
*/
|
||||
NFRule ruleToUse;
|
||||
private final NFRule ruleToUse;
|
||||
|
||||
//-----------------------------------------------------------------------
|
||||
// construction
|
||||
|
@ -893,18 +894,18 @@ class ModulusSubstitution extends NFSubstitution {
|
|||
* into
|
||||
* @param position The position of the rule text in toInsertInto
|
||||
*/
|
||||
public void doSubstitution(long number, StringBuffer toInsertInto, int position) {
|
||||
public void doSubstitution(long number, StringBuffer toInsertInto, int position, int recursionCount) {
|
||||
// if this isn't a >>> substitution, just use the inherited version
|
||||
// of this function (which uses either a rule set or a DecimalFormat
|
||||
// to format its substitution value)
|
||||
if (ruleToUse == null) {
|
||||
super.doSubstitution(number, toInsertInto, position);
|
||||
super.doSubstitution(number, toInsertInto, position, recursionCount);
|
||||
|
||||
// a >>> substitution goes straight to a particular rule to
|
||||
// format the substitution value
|
||||
} else {
|
||||
// a >>> substitution goes straight to a particular rule to
|
||||
// format the substitution value
|
||||
long numberToFormat = transformNumber(number);
|
||||
ruleToUse.doFormat(numberToFormat, toInsertInto, position + pos);
|
||||
ruleToUse.doFormat(numberToFormat, toInsertInto, position + pos, recursionCount);
|
||||
}
|
||||
}
|
||||
|
||||
|
@ -916,19 +917,19 @@ class ModulusSubstitution extends NFSubstitution {
|
|||
* into
|
||||
* @param position The position of the rule text in toInsertInto
|
||||
*/
|
||||
public void doSubstitution(double number, StringBuffer toInsertInto, int position) {
|
||||
public void doSubstitution(double number, StringBuffer toInsertInto, int position, int recursionCount) {
|
||||
// if this isn't a >>> substitution, just use the inherited version
|
||||
// of this function (which uses either a rule set or a DecimalFormat
|
||||
// to format its substitution value)
|
||||
if (ruleToUse == null) {
|
||||
super.doSubstitution(number, toInsertInto, position);
|
||||
super.doSubstitution(number, toInsertInto, position, recursionCount);
|
||||
|
||||
// a >>> substitution goes straight to a particular rule to
|
||||
// format the substitution value
|
||||
} else {
|
||||
// a >>> substitution goes straight to a particular rule to
|
||||
// format the substitution value
|
||||
double numberToFormat = transformNumber(number);
|
||||
|
||||
ruleToUse.doFormat(numberToFormat, toInsertInto, position + pos);
|
||||
ruleToUse.doFormat(numberToFormat, toInsertInto, position + pos, recursionCount);
|
||||
}
|
||||
}
|
||||
|
||||
|
@ -972,10 +973,10 @@ class ModulusSubstitution extends NFSubstitution {
|
|||
if (ruleToUse == null) {
|
||||
return super.doParse(text, parsePosition, baseValue, upperBound, lenientParse);
|
||||
|
||||
// but if it IS a >>> substitution, we have to do it here: we
|
||||
// use the specific rule's doParse() method, and then we have to
|
||||
// do some of the other work of NFRuleSet.parse()
|
||||
} else {
|
||||
// but if it IS a >>> substitution, we have to do it here: we
|
||||
// use the specific rule's doParse() method, and then we have to
|
||||
// do some of the other work of NFRuleSet.parse()
|
||||
Number tempResult = ruleToUse.doParse(text, parsePosition, false, upperBound);
|
||||
|
||||
if (parsePosition.getIndex() != 0) {
|
||||
|
@ -1145,13 +1146,13 @@ class FractionalPartSubstitution extends NFSubstitution {
|
|||
* true if this substitution should have the default "by digits"
|
||||
* behavior, false otherwise
|
||||
*/
|
||||
private boolean byDigits = false;
|
||||
private final boolean byDigits;
|
||||
|
||||
/**
|
||||
* true if we automatically insert spaces to separate names of digits
|
||||
* set to false by '>>>' in fraction rules, used by Thai.
|
||||
*/
|
||||
private boolean useSpaces = true;
|
||||
private final boolean useSpaces;
|
||||
|
||||
//-----------------------------------------------------------------------
|
||||
// construction
|
||||
|
@ -1169,10 +1170,10 @@ class FractionalPartSubstitution extends NFSubstitution {
|
|||
super(pos, ruleSet, formatter, description);
|
||||
if (description.equals(">>") || description.equals(">>>") || ruleSet == this.ruleSet) {
|
||||
byDigits = true;
|
||||
if (description.equals(">>>")) {
|
||||
useSpaces = false;
|
||||
}
|
||||
useSpaces = !description.equals(">>>");
|
||||
} else {
|
||||
byDigits = false;
|
||||
useSpaces = true;
|
||||
this.ruleSet.makeIntoFractionRuleSet();
|
||||
}
|
||||
}
|
||||
|
@ -1191,11 +1192,11 @@ class FractionalPartSubstitution extends NFSubstitution {
|
|||
* @param position The position of the owning rule's rule text in
|
||||
* toInsertInto
|
||||
*/
|
||||
public void doSubstitution(double number, StringBuffer toInsertInto, int position) {
|
||||
public void doSubstitution(double number, StringBuffer toInsertInto, int position, int recursionCount) {
|
||||
if (!byDigits) {
|
||||
// if we're not in "byDigits" mode, just use the inherited
|
||||
// doSubstitution() routine
|
||||
super.doSubstitution(number, toInsertInto, position);
|
||||
super.doSubstitution(number, toInsertInto, position, recursionCount);
|
||||
}
|
||||
else {
|
||||
// if we're in "byDigits" mode, transform the value into an integer
|
||||
|
@ -1216,7 +1217,7 @@ class FractionalPartSubstitution extends NFSubstitution {
|
|||
} else {
|
||||
pad = true;
|
||||
}
|
||||
ruleSet.format(dl.digits[--dl.count] - '0', toInsertInto, position + pos);
|
||||
ruleSet.format(dl.digits[--dl.count] - '0', toInsertInto, position + pos, recursionCount);
|
||||
}
|
||||
while (dl.decimalAt < 0) {
|
||||
if (pad && useSpaces) {
|
||||
|
@ -1224,7 +1225,7 @@ class FractionalPartSubstitution extends NFSubstitution {
|
|||
} else {
|
||||
pad = true;
|
||||
}
|
||||
ruleSet.format(0, toInsertInto, position + pos);
|
||||
ruleSet.format(0, toInsertInto, position + pos, recursionCount);
|
||||
++dl.decimalAt;
|
||||
}
|
||||
}
|
||||
|
@ -1449,12 +1450,12 @@ class NumeratorSubstitution extends NFSubstitution {
|
|||
* The denominator of the fraction we're finding the numerator for.
|
||||
* (The base value of the rule that owns this substitution.)
|
||||
*/
|
||||
double denominator;
|
||||
private final double denominator;
|
||||
|
||||
/**
|
||||
* True if we format leading zeros (this is a hack for Hebrew spellout)
|
||||
*/
|
||||
boolean withZeros;
|
||||
private final boolean withZeros;
|
||||
|
||||
//-----------------------------------------------------------------------
|
||||
// construction
|
||||
|
@ -1498,7 +1499,7 @@ class NumeratorSubstitution extends NFSubstitution {
|
|||
public boolean equals(Object that) {
|
||||
if (super.equals(that)) {
|
||||
NumeratorSubstitution that2 = (NumeratorSubstitution)that;
|
||||
return denominator == that2.denominator;
|
||||
return denominator == that2.denominator && withZeros == that2.withZeros;
|
||||
} else {
|
||||
return false;
|
||||
}
|
||||
|
@ -1518,7 +1519,7 @@ class NumeratorSubstitution extends NFSubstitution {
|
|||
* rule text begins (this value is added to this substitution's
|
||||
* position to determine exactly where to insert the new text)
|
||||
*/
|
||||
public void doSubstitution(double number, StringBuffer toInsertInto, int position) {
|
||||
public void doSubstitution(double number, StringBuffer toInsertInto, int position, int recursionCount) {
|
||||
// perform a transformation on the number being formatted that
|
||||
// is dependent on the type of substitution this is
|
||||
//String s = toInsertInto.toString();
|
||||
|
@ -1530,7 +1531,7 @@ class NumeratorSubstitution extends NFSubstitution {
|
|||
int len = toInsertInto.length();
|
||||
while ((nf *= 10) < denominator) {
|
||||
toInsertInto.insert(position + pos, ' ');
|
||||
ruleSet.format(0, toInsertInto, position + pos);
|
||||
ruleSet.format(0, toInsertInto, position + pos, recursionCount);
|
||||
}
|
||||
position += toInsertInto.length() - len;
|
||||
}
|
||||
|
@ -1538,14 +1539,14 @@ class NumeratorSubstitution extends NFSubstitution {
|
|||
// if the result is an integer, from here on out we work in integer
|
||||
// space (saving time and memory and preserving accuracy)
|
||||
if (numberToFormat == Math.floor(numberToFormat) && ruleSet != null) {
|
||||
ruleSet.format((long)numberToFormat, toInsertInto, position + pos);
|
||||
ruleSet.format((long)numberToFormat, toInsertInto, position + pos, recursionCount);
|
||||
|
||||
// if the result isn't an integer, then call either our rule set's
|
||||
// format() method or our DecimalFormat's format() method to
|
||||
// format the result
|
||||
} else {
|
||||
if (ruleSet != null) {
|
||||
ruleSet.format(numberToFormat, toInsertInto, position + pos);
|
||||
ruleSet.format(numberToFormat, toInsertInto, position + pos, recursionCount);
|
||||
} else {
|
||||
toInsertInto.insert(position + pos, numberFormat.format(numberToFormat));
|
||||
}
|
||||
|
@ -1701,13 +1702,6 @@ class NullSubstitution extends NFSubstitution {
|
|||
// boilerplate
|
||||
//-----------------------------------------------------------------------
|
||||
|
||||
/**
|
||||
* Only checks for class equality
|
||||
*/
|
||||
public boolean equals(Object that) {
|
||||
return super.equals(that);
|
||||
}
|
||||
|
||||
/**
|
||||
* NullSubstitutions don't show up in the textual representation
|
||||
* of a RuleBasedNumberFormat
|
||||
|
|
|
@ -543,12 +543,12 @@ public class RuleBasedNumberFormat extends NumberFormat {
|
|||
* The formatter's rule sets.
|
||||
*/
|
||||
private transient NFRuleSet[] ruleSets = null;
|
||||
|
||||
|
||||
/**
|
||||
* The formatter's rule sets' descriptions.
|
||||
* The formatter's rule names mapped to rule sets.
|
||||
*/
|
||||
private transient String[] ruleSetDescriptions = null;
|
||||
|
||||
private transient Map<String, NFRuleSet> ruleSetsMap = null;
|
||||
|
||||
/**
|
||||
* A pointer to the formatter's default rule set. This is always included
|
||||
* in ruleSets.
|
||||
|
@ -910,8 +910,8 @@ public class RuleBasedNumberFormat extends NumberFormat {
|
|||
// accumulate the descriptions of all the rule sets in a
|
||||
// StringBuffer, then cast it to a String and return it
|
||||
StringBuilder result = new StringBuilder();
|
||||
for (int i = 0; i < ruleSets.length; i++) {
|
||||
result.append(ruleSets[i].toString());
|
||||
for (NFRuleSet ruleSet : ruleSets) {
|
||||
result.append(ruleSet.toString());
|
||||
}
|
||||
return result.toString();
|
||||
}
|
||||
|
@ -951,6 +951,7 @@ public class RuleBasedNumberFormat extends NumberFormat {
|
|||
// get swept up by the garbage collector
|
||||
RuleBasedNumberFormat temp = new RuleBasedNumberFormat(description, loc);
|
||||
ruleSets = temp.ruleSets;
|
||||
ruleSetsMap = temp.ruleSetsMap;
|
||||
defaultRuleSet = temp.defaultRuleSet;
|
||||
publicRuleSetNames = temp.publicRuleSetNames;
|
||||
decimalFormatSymbols = temp.decimalFormatSymbols;
|
||||
|
@ -995,8 +996,7 @@ public class RuleBasedNumberFormat extends NumberFormat {
|
|||
private String[] getNameListForLocale(ULocale loc) {
|
||||
if (loc != null && ruleSetDisplayNames != null) {
|
||||
String[] localeNames = { loc.getBaseName(), ULocale.getDefault(Category.DISPLAY).getBaseName() };
|
||||
for (int i = 0; i < localeNames.length; ++i) {
|
||||
String lname = localeNames[i];
|
||||
for (String lname : localeNames) {
|
||||
while (lname.length() > 0) {
|
||||
String[] names = ruleSetDisplayNames.get(lname);
|
||||
if (names != null) {
|
||||
|
@ -1411,8 +1411,8 @@ public class RuleBasedNumberFormat extends NumberFormat {
|
|||
}
|
||||
|
||||
// Apply the new decimalFormatSymbols by reparsing the rulesets
|
||||
for (int i = 0; i < ruleSets.length; i++) {
|
||||
ruleSets[i].parseRules(ruleSetDescriptions[i], this);
|
||||
for (NFRuleSet ruleSet : ruleSets) {
|
||||
ruleSet.setDecimalFormatSymbols(decimalFormatSymbols);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
@ -1579,15 +1579,21 @@ public class RuleBasedNumberFormat extends NumberFormat {
|
|||
// pre-flight parsing the description and count the number of
|
||||
// rule sets (";%" marks the end of one rule set and the beginning
|
||||
// of the next)
|
||||
int numRuleSets = 0;
|
||||
for (int p = descBuf.indexOf(";%"); p != -1; p = descBuf.indexOf(";%", p)) {
|
||||
int numRuleSets = 1;
|
||||
int p = 0;
|
||||
while ((p = descBuf.indexOf(";%", p)) != -1) {
|
||||
++numRuleSets;
|
||||
++p;
|
||||
p += 2; // Skip the length of ";%"
|
||||
}
|
||||
++numRuleSets;
|
||||
|
||||
// our rule list is an array of the appropriate size
|
||||
ruleSets = new NFRuleSet[numRuleSets];
|
||||
ruleSetsMap = new HashMap<String, NFRuleSet>(numRuleSets * 2 + 1);
|
||||
defaultRuleSet = null;
|
||||
|
||||
// Used to count the number of public rule sets
|
||||
// Public rule sets have names that begin with % instead of %%.
|
||||
int publicRuleSetCount = 0;
|
||||
|
||||
// divide up the descriptions into individual rule-set descriptions
|
||||
// and store them in a temporary array. At each step, we also
|
||||
|
@ -1596,18 +1602,34 @@ public class RuleBasedNumberFormat extends NumberFormat {
|
|||
// the rest of the descriptions and finish initializing everything
|
||||
// because we have to know the names and locations of all the rule
|
||||
// sets before we can actually set everything up
|
||||
ruleSetDescriptions = new String[numRuleSets];
|
||||
String[] ruleSetDescriptions = new String[numRuleSets];
|
||||
|
||||
int curRuleSet = 0;
|
||||
int start = 0;
|
||||
for (int p = descBuf.indexOf(";%"); p != -1; p = descBuf.indexOf(";%", start)) {
|
||||
|
||||
while (curRuleSet < ruleSets.length) {
|
||||
p = descBuf.indexOf(";%", start);
|
||||
if (p < 0) {
|
||||
p = descBuf.length() - 1;
|
||||
}
|
||||
ruleSetDescriptions[curRuleSet] = descBuf.substring(start, p + 1);
|
||||
ruleSets[curRuleSet] = new NFRuleSet(ruleSetDescriptions, curRuleSet);
|
||||
NFRuleSet ruleSet = new NFRuleSet(ruleSetDescriptions, curRuleSet);
|
||||
ruleSets[curRuleSet] = ruleSet;
|
||||
String currentName = ruleSet.getName();
|
||||
ruleSetsMap.put(currentName, ruleSet);
|
||||
if (!currentName.startsWith("%%")) {
|
||||
++publicRuleSetCount;
|
||||
if (defaultRuleSet == null
|
||||
&& currentName.equals("%spellout-numbering")
|
||||
|| currentName.equals("%digits-ordinal")
|
||||
|| currentName.equals("%duration"))
|
||||
{
|
||||
defaultRuleSet = ruleSet;
|
||||
}
|
||||
}
|
||||
++curRuleSet;
|
||||
start = p + 1;
|
||||
}
|
||||
ruleSetDescriptions[curRuleSet] = descBuf.substring(start);
|
||||
ruleSets[curRuleSet] = new NFRuleSet(ruleSetDescriptions, curRuleSet);
|
||||
|
||||
// now we can take note of the formatter's default rule set, which
|
||||
// is the last public rule set in the description (it's the last
|
||||
|
@ -1622,20 +1644,7 @@ public class RuleBasedNumberFormat extends NumberFormat {
|
|||
// Set the default ruleset to the last public ruleset, unless one of the predefined
|
||||
// ruleset names %spellout-numbering, %digits-ordinal, or %duration is found
|
||||
|
||||
boolean defaultNameFound = false;
|
||||
int n = ruleSets.length;
|
||||
defaultRuleSet = ruleSets[ruleSets.length - 1];
|
||||
|
||||
while (--n >= 0) {
|
||||
String currentName = ruleSets[n].getName();
|
||||
if (currentName.equals("%spellout-numbering") || currentName.equals("%digits-ordinal") || currentName.equals("%duration")) {
|
||||
defaultRuleSet = ruleSets[n];
|
||||
defaultNameFound = true;
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
if ( !defaultNameFound ) {
|
||||
if (defaultRuleSet == null) {
|
||||
for (int i = ruleSets.length - 1; i >= 0; --i) {
|
||||
if (!ruleSets[i].getName().startsWith("%%")) {
|
||||
defaultRuleSet = ruleSets[i];
|
||||
|
@ -1643,6 +1652,9 @@ public class RuleBasedNumberFormat extends NumberFormat {
|
|||
}
|
||||
}
|
||||
}
|
||||
if (defaultRuleSet == null) {
|
||||
defaultRuleSet = ruleSets[ruleSets.length - 1];
|
||||
}
|
||||
|
||||
// finally, we can go back through the temporary descriptions
|
||||
// list and finish setting up the substructure
|
||||
|
@ -1653,15 +1665,6 @@ public class RuleBasedNumberFormat extends NumberFormat {
|
|||
// Now that the rules are initialized, the 'real' default rule
|
||||
// set can be adjusted by the localization data.
|
||||
|
||||
// count the number of public rule sets
|
||||
// (public rule sets have names that begin with % instead of %%)
|
||||
int publicRuleSetCount = 0;
|
||||
for (int i = 0; i < ruleSets.length; i++) {
|
||||
if (!ruleSets[i].getName().startsWith("%%")) {
|
||||
++publicRuleSetCount;
|
||||
}
|
||||
}
|
||||
|
||||
// prepare an array of the proper size and copy the names into it
|
||||
String[] publicRuleSetTemp = new String[publicRuleSetCount];
|
||||
publicRuleSetCount = 0;
|
||||
|
@ -1787,26 +1790,6 @@ public class RuleBasedNumberFormat extends NumberFormat {
|
|||
return result;
|
||||
}
|
||||
|
||||
// /**
|
||||
// * This function is called ONLY DURING CONSTRUCTION to fill in the
|
||||
// * defaultRuleSet variable once we've set up all the rule sets.
|
||||
// * The default rule set is the last public rule set in the description.
|
||||
// * (It's the last rather than the first so that a caller can append
|
||||
// * text to the end of an existing formatter description to change its
|
||||
// * behavior.)
|
||||
// */
|
||||
// private void initDefaultRuleSet() {
|
||||
// // seek backward from the end of the list until we reach a rule set
|
||||
// // whose name DOESN'T begin with %%. That's the default rule set
|
||||
// for (int i = ruleSets.length - 1; i >= 0; --i) {
|
||||
// if (!ruleSets[i].getName().startsWith("%%")) {
|
||||
// defaultRuleSet = ruleSets[i];
|
||||
// return;
|
||||
// }
|
||||
// }
|
||||
// defaultRuleSet = ruleSets[ruleSets.length - 1];
|
||||
// }
|
||||
|
||||
//-----------------------------------------------------------------------
|
||||
// formatting implementation
|
||||
//-----------------------------------------------------------------------
|
||||
|
@ -1826,7 +1809,7 @@ public class RuleBasedNumberFormat extends NumberFormat {
|
|||
// position of 0 and the number being formatted) to the rule set
|
||||
// for formatting
|
||||
StringBuffer result = new StringBuffer();
|
||||
ruleSet.format(number, result, 0);
|
||||
ruleSet.format(number, result, 0, 0);
|
||||
postProcess(result, ruleSet);
|
||||
return result.toString();
|
||||
}
|
||||
|
@ -1851,7 +1834,7 @@ public class RuleBasedNumberFormat extends NumberFormat {
|
|||
// position of 0 and the number being formatted) to the rule set
|
||||
// for formatting
|
||||
StringBuffer result = new StringBuffer();
|
||||
ruleSet.format(number, result, 0);
|
||||
ruleSet.format(number, result, 0, 0);
|
||||
postProcess(result, ruleSet);
|
||||
return result.toString();
|
||||
}
|
||||
|
@ -1913,11 +1896,10 @@ public class RuleBasedNumberFormat extends NumberFormat {
|
|||
* @return The rule set with that name
|
||||
*/
|
||||
NFRuleSet findRuleSet(String name) throws IllegalArgumentException {
|
||||
for (int i = 0; i < ruleSets.length; i++) {
|
||||
if (ruleSets[i].getName().equals(name)) {
|
||||
return ruleSets[i];
|
||||
}
|
||||
NFRuleSet result = ruleSetsMap.get(name);
|
||||
if (result == null) {
|
||||
throw new IllegalArgumentException("No rule set named " + name);
|
||||
}
|
||||
throw new IllegalArgumentException("No rule set named " + name);
|
||||
return result;
|
||||
}
|
||||
}
|
||||
|
|
Loading…
Add table
Reference in a new issue