diff options
Diffstat (limited to 'luni/src/main/java/libcore/icu/NativeDecimalFormat.java')
-rw-r--r-- | luni/src/main/java/libcore/icu/NativeDecimalFormat.java | 195 |
1 files changed, 95 insertions, 100 deletions
diff --git a/luni/src/main/java/libcore/icu/NativeDecimalFormat.java b/luni/src/main/java/libcore/icu/NativeDecimalFormat.java index 0e9ffc4..fd179c1 100644 --- a/luni/src/main/java/libcore/icu/NativeDecimalFormat.java +++ b/luni/src/main/java/libcore/icu/NativeDecimalFormat.java @@ -27,7 +27,6 @@ import java.text.Format; import java.text.NumberFormat; import java.text.ParsePosition; import java.util.Currency; -import java.util.NoSuchElementException; public final class NativeDecimalFormat implements Cloneable { /** @@ -92,6 +91,47 @@ public final class NativeDecimalFormat implements Cloneable { private static final int UNUM_PUBLIC_RULESETS = 7; /** + * A table for translating between NumberFormat.Field instances + * and icu4c UNUM_x_FIELD constants. + */ + private static final Format.Field[] ICU4C_FIELD_IDS = { + // The old java field values were 0 for integer and 1 for fraction. + // The new java field attributes are all objects. ICU assigns the values + // starting from 0 in the following order; note that integer and + // fraction positions match the old field values. + NumberFormat.Field.INTEGER, // 0 UNUM_INTEGER_FIELD + NumberFormat.Field.FRACTION, // 1 UNUM_FRACTION_FIELD + NumberFormat.Field.DECIMAL_SEPARATOR, // 2 UNUM_DECIMAL_SEPARATOR_FIELD + NumberFormat.Field.EXPONENT_SYMBOL, // 3 UNUM_EXPONENT_SYMBOL_FIELD + NumberFormat.Field.EXPONENT_SIGN, // 4 UNUM_EXPONENT_SIGN_FIELD + NumberFormat.Field.EXPONENT, // 5 UNUM_EXPONENT_FIELD + NumberFormat.Field.GROUPING_SEPARATOR, // 6 UNUM_GROUPING_SEPARATOR_FIELD + NumberFormat.Field.CURRENCY, // 7 UNUM_CURRENCY_FIELD + NumberFormat.Field.PERCENT, // 8 UNUM_PERCENT_FIELD + NumberFormat.Field.PERMILLE, // 9 UNUM_PERMILL_FIELD + NumberFormat.Field.SIGN, // 10 UNUM_SIGN_FIELD + }; + + private static int translateFieldId(FieldPosition fp) { + int id = fp.getField(); + if (id < -1 || id > 1) { + id = -1; + } + if (id == -1) { + Format.Field attr = fp.getFieldAttribute(); + if (attr != null) { + for (int i = 0; i < ICU4C_FIELD_IDS.length; ++i) { + if (ICU4C_FIELD_IDS[i].equals(attr)) { + id = i; + break; + } + } + } + } + return id; + } + + /** * The address of the ICU DecimalFormat* on the native heap. */ private long address; @@ -111,19 +151,12 @@ public final class NativeDecimalFormat implements Cloneable { private transient boolean parseBigDecimal; - /** - * Cache the BigDecimal form of the multiplier. This is null until we've - * formatted a BigDecimal (with a multiplier that is not 1), or the user has - * explicitly called {@link #setMultiplier(int)} with any multiplier. - */ - private BigDecimal multiplierBigDecimal = null; - public NativeDecimalFormat(String pattern, DecimalFormatSymbols dfs) { try { this.address = open(pattern, dfs.getCurrencySymbol(), dfs.getDecimalSeparator(), dfs.getDigit(), dfs.getExponentSeparator(), dfs.getGroupingSeparator(), dfs.getInfinity(), - dfs.getInternationalCurrencySymbol(), dfs.getMinusSign(), + dfs.getInternationalCurrencySymbol(), dfs.getMinusSignString(), dfs.getMonetaryDecimalSeparator(), dfs.getNaN(), dfs.getPatternSeparator(), dfs.getPercent(), dfs.getPerMill(), dfs.getZeroDigit()); this.lastPattern = pattern; @@ -211,13 +244,30 @@ public final class NativeDecimalFormat implements Cloneable { obj.isGroupingUsed() == this.isGroupingUsed(); } + public String toString() { + return getClass().getName() + "[\"" + toPattern() + "\"" + + ",isDecimalSeparatorAlwaysShown=" + isDecimalSeparatorAlwaysShown() + + ",groupingSize=" + getGroupingSize() + + ",multiplier=" + getMultiplier() + + ",negativePrefix=" + getNegativePrefix() + + ",negativeSuffix=" + getNegativeSuffix() + + ",positivePrefix=" + getPositivePrefix() + + ",positiveSuffix=" + getPositiveSuffix() + + ",maxIntegerDigits=" + getMaximumIntegerDigits() + + ",maxFractionDigits=" + getMaximumFractionDigits() + + ",minIntegerDigits=" + getMinimumIntegerDigits() + + ",minFractionDigits=" + getMinimumFractionDigits() + + ",grouping=" + isGroupingUsed() + + "]"; + } + /** * Copies the DecimalFormatSymbols settings into our native peer in bulk. */ public void setDecimalFormatSymbols(final DecimalFormatSymbols dfs) { setDecimalFormatSymbols(this.address, dfs.getCurrencySymbol(), dfs.getDecimalSeparator(), dfs.getDigit(), dfs.getExponentSeparator(), dfs.getGroupingSeparator(), - dfs.getInfinity(), dfs.getInternationalCurrencySymbol(), dfs.getMinusSign(), + dfs.getInfinity(), dfs.getInternationalCurrencySymbol(), dfs.getMinusSignString(), dfs.getMonetaryDecimalSeparator(), dfs.getNaN(), dfs.getPatternSeparator(), dfs.getPercent(), dfs.getPerMill(), dfs.getZeroDigit()); } @@ -233,8 +283,8 @@ public final class NativeDecimalFormat implements Cloneable { public char[] formatBigDecimal(BigDecimal value, FieldPosition field) { FieldPositionIterator fpi = FieldPositionIterator.forFieldPosition(field); char[] result = formatDigitList(this.address, value.toString(), fpi); - if (fpi != null) { - FieldPositionIterator.setFieldPosition(fpi, field); + if (fpi != null && field != null) { + updateFieldPosition(field, fpi); } return result; } @@ -242,8 +292,8 @@ public final class NativeDecimalFormat implements Cloneable { public char[] formatBigInteger(BigInteger value, FieldPosition field) { FieldPositionIterator fpi = FieldPositionIterator.forFieldPosition(field); char[] result = formatDigitList(this.address, value.toString(10), fpi); - if (fpi != null) { - FieldPositionIterator.setFieldPosition(fpi, field); + if (fpi != null && field != null) { + updateFieldPosition(field, fpi); } return result; } @@ -251,8 +301,8 @@ public final class NativeDecimalFormat implements Cloneable { public char[] formatLong(long value, FieldPosition field) { FieldPositionIterator fpi = FieldPositionIterator.forFieldPosition(field); char[] result = formatLong(this.address, value, fpi); - if (fpi != null) { - FieldPositionIterator.setFieldPosition(fpi, field); + if (fpi != null && field != null) { + updateFieldPosition(field, fpi); } return result; } @@ -260,12 +310,25 @@ public final class NativeDecimalFormat implements Cloneable { public char[] formatDouble(double value, FieldPosition field) { FieldPositionIterator fpi = FieldPositionIterator.forFieldPosition(field); char[] result = formatDouble(this.address, value, fpi); - if (fpi != null) { - FieldPositionIterator.setFieldPosition(fpi, field); + if (fpi != null && field != null) { + updateFieldPosition(field, fpi); } return result; } + private static void updateFieldPosition(FieldPosition fp, FieldPositionIterator fpi) { + int field = translateFieldId(fp); + if (field != -1) { + while (fpi.next()) { + if (fpi.fieldId() == field) { + fp.setBeginIndex(fpi.start()); + fp.setEndIndex(fpi.limit()); + return; + } + } + } + } + public void applyLocalizedPattern(String pattern) { applyPattern(this.address, true, pattern); lastPattern = null; @@ -352,6 +415,10 @@ public final class NativeDecimalFormat implements Cloneable { } public int getGroupingSize() { + // Work around http://bugs.icu-project.org/trac/ticket/10864 in icu4c 53. + if (!isGroupingUsed()) { + return 0; + } return getAttribute(this.address, UNUM_GROUPING_SIZE); } @@ -408,9 +475,9 @@ public final class NativeDecimalFormat implements Cloneable { setAttribute(this.address, UNUM_DECIMAL_ALWAYS_SHOWN, i); } - public void setCurrency(Currency currency) { - setSymbol(this.address, UNUM_CURRENCY_SYMBOL, currency.getSymbol()); - setSymbol(this.address, UNUM_INTL_CURRENCY_SYMBOL, currency.getCurrencyCode()); + public void setCurrency(String currencySymbol, String currencyCode) { + setSymbol(this.address, UNUM_CURRENCY_SYMBOL, currencySymbol); + setSymbol(this.address, UNUM_INTL_CURRENCY_SYMBOL, currencyCode); } public void setGroupingSize(int value) { @@ -440,8 +507,6 @@ public final class NativeDecimalFormat implements Cloneable { public void setMultiplier(int value) { setAttribute(this.address, UNUM_MULTIPLIER, value); - // Update the cached BigDecimal for multiplier. - multiplierBigDecimal = BigDecimal.valueOf(value); } public void setNegativePrefix(String value) { @@ -501,6 +566,7 @@ public final class NativeDecimalFormat implements Cloneable { case HALF_EVEN: nativeRoundingMode = 4; break; case HALF_DOWN: nativeRoundingMode = 5; break; case HALF_UP: nativeRoundingMode = 6; break; + case UNNECESSARY: nativeRoundingMode = 7; break; default: throw new AssertionError(); } setRoundingMode(address, nativeRoundingMode, roundingIncrement); @@ -515,104 +581,33 @@ public final class NativeDecimalFormat implements Cloneable { } public static FieldPositionIterator forFieldPosition(FieldPosition fp) { - if (fp != null && fp.getField() != -1) { - return new FieldPositionIterator(); - } - return null; - } - - private static int getNativeFieldPositionId(FieldPosition fp) { - // NOTE: -1, 0, and 1 were the only valid original java field values - // for NumberFormat. They take precedence. This assumes any other - // value is a mistake and the actual value is in the attribute. - // Clients can construct FieldPosition combining any attribute with any field - // value, which is just wrong, but there you go. - - int id = fp.getField(); - if (id < -1 || id > 1) { - id = -1; - } - if (id == -1) { - Format.Field attr = fp.getFieldAttribute(); - if (attr != null) { - for (int i = 0; i < fields.length; ++i) { - if (fields[i].equals(attr)) { - id = i; - break; - } - } - } - } - return id; - } - - private static void setFieldPosition(FieldPositionIterator fpi, FieldPosition fp) { - if (fpi != null && fp != null) { - int field = getNativeFieldPositionId(fp); - if (field != -1) { - while (fpi.next()) { - if (fpi.fieldId() == field) { - fp.setBeginIndex(fpi.start()); - fp.setEndIndex(fpi.limit()); - break; - } - } - } - } + return (fp != null) ? new FieldPositionIterator() : null; } public boolean next() { - // if pos == data.length, we've already returned false once - if (data == null || pos == data.length) { - throw new NoSuchElementException(); + if (data == null) { + return false; } pos += 3; return pos < data.length; } - private void checkValid() { - if (data == null || pos < 0 || pos == data.length) { - throw new NoSuchElementException(); - } - } - public int fieldId() { return data[pos]; } public Format.Field field() { - checkValid(); - return fields[data[pos]]; + return ICU4C_FIELD_IDS[data[pos]]; } public int start() { - checkValid(); return data[pos + 1]; } public int limit() { - checkValid(); return data[pos + 2]; } - private static Format.Field fields[] = { - // The old java field values were 0 for integer and 1 for fraction. - // The new java field attributes are all objects. ICU assigns the values - // starting from 0 in the following order; note that integer and - // fraction positions match the old field values. - NumberFormat.Field.INTEGER, - NumberFormat.Field.FRACTION, - NumberFormat.Field.DECIMAL_SEPARATOR, - NumberFormat.Field.EXPONENT_SYMBOL, - NumberFormat.Field.EXPONENT_SIGN, - NumberFormat.Field.EXPONENT, - NumberFormat.Field.GROUPING_SEPARATOR, - NumberFormat.Field.CURRENCY, - NumberFormat.Field.PERCENT, - NumberFormat.Field.PERMILLE, - NumberFormat.Field.SIGN, - }; - // called by native private void setData(int[] data) { this.data = data; @@ -630,13 +625,13 @@ public final class NativeDecimalFormat implements Cloneable { private static native String getTextAttribute(long addr, int symbol); private static native long open(String pattern, String currencySymbol, char decimalSeparator, char digit, String exponentSeparator, char groupingSeparator, - String infinity, String internationalCurrencySymbol, char minusSign, + String infinity, String internationalCurrencySymbol, String minusSign, char monetaryDecimalSeparator, String nan, char patternSeparator, char percent, char perMill, char zeroDigit); private static native Number parse(long addr, String string, ParsePosition position, boolean parseBigDecimal); private static native void setDecimalFormatSymbols(long addr, String currencySymbol, char decimalSeparator, char digit, String exponentSeparator, char groupingSeparator, - String infinity, String internationalCurrencySymbol, char minusSign, + String infinity, String internationalCurrencySymbol, String minusSign, char monetaryDecimalSeparator, String nan, char patternSeparator, char percent, char perMill, char zeroDigit); private static native void setSymbol(long addr, int symbol, String str); |