]> granicus.if.org Git - icu/commitdiff
ICU-13524 Reformatting ICU4J number files with 4 spaces.
authorShane Carr <shane@unicode.org>
Sat, 23 Dec 2017 01:07:53 +0000 (01:07 +0000)
committerShane Carr <shane@unicode.org>
Sat, 23 Dec 2017 01:07:53 +0000 (01:07 +0000)
X-SVN-Rev: 40749

46 files changed:
icu4j/main/classes/core/src/com/ibm/icu/impl/number/AffixPatternProvider.java
icu4j/main/classes/core/src/com/ibm/icu/impl/number/AffixUtils.java
icu4j/main/classes/core/src/com/ibm/icu/impl/number/CompactData.java
icu4j/main/classes/core/src/com/ibm/icu/impl/number/ConstantAffixModifier.java
icu4j/main/classes/core/src/com/ibm/icu/impl/number/ConstantMultiFieldModifier.java
icu4j/main/classes/core/src/com/ibm/icu/impl/number/CurrencySpacingEnabledModifier.java
icu4j/main/classes/core/src/com/ibm/icu/impl/number/CustomSymbolCurrency.java
icu4j/main/classes/core/src/com/ibm/icu/impl/number/DecimalFormatProperties.java
icu4j/main/classes/core/src/com/ibm/icu/impl/number/DecimalQuantity.java
icu4j/main/classes/core/src/com/ibm/icu/impl/number/DecimalQuantity_AbstractBCD.java
icu4j/main/classes/core/src/com/ibm/icu/impl/number/DecimalQuantity_DualStorageBCD.java
icu4j/main/classes/core/src/com/ibm/icu/impl/number/MacroProps.java
icu4j/main/classes/core/src/com/ibm/icu/impl/number/MicroProps.java
icu4j/main/classes/core/src/com/ibm/icu/impl/number/MicroPropsGenerator.java
icu4j/main/classes/core/src/com/ibm/icu/impl/number/Modifier.java
icu4j/main/classes/core/src/com/ibm/icu/impl/number/MultiplierImpl.java
icu4j/main/classes/core/src/com/ibm/icu/impl/number/MultiplierProducer.java
icu4j/main/classes/core/src/com/ibm/icu/impl/number/MutablePatternModifier.java
icu4j/main/classes/core/src/com/ibm/icu/impl/number/Padder.java
icu4j/main/classes/core/src/com/ibm/icu/impl/number/ParameterizedModifier.java
icu4j/main/classes/core/src/com/ibm/icu/impl/number/PatternStringParser.java
icu4j/main/classes/core/src/com/ibm/icu/impl/number/PatternStringUtils.java
icu4j/main/classes/core/src/com/ibm/icu/impl/number/Properties.java
icu4j/main/classes/core/src/com/ibm/icu/impl/number/RoundingUtils.java
icu4j/main/classes/core/src/com/ibm/icu/number/CompactNotation.java
icu4j/main/classes/core/src/com/ibm/icu/number/CurrencyRounder.java
icu4j/main/classes/core/src/com/ibm/icu/number/FractionRounder.java
icu4j/main/classes/core/src/com/ibm/icu/number/Grouper.java
icu4j/main/classes/core/src/com/ibm/icu/number/IntegerWidth.java
icu4j/main/classes/core/src/com/ibm/icu/number/LocalizedNumberFormatter.java
icu4j/main/classes/core/src/com/ibm/icu/number/Notation.java
icu4j/main/classes/core/src/com/ibm/icu/number/NumberFormatter.java
icu4j/main/classes/core/src/com/ibm/icu/number/NumberFormatterImpl.java
icu4j/main/classes/core/src/com/ibm/icu/number/NumberFormatterSettings.java
icu4j/main/classes/core/src/com/ibm/icu/number/NumberPropertyMapper.java
icu4j/main/classes/core/src/com/ibm/icu/number/Rounder.java
icu4j/main/classes/core/src/com/ibm/icu/number/ScientificNotation.java
icu4j/main/classes/core/src/com/ibm/icu/number/SimpleNotation.java
icu4j/main/classes/core/src/com/ibm/icu/number/UnlocalizedNumberFormatter.java
icu4j/main/tests/core/src/com/ibm/icu/dev/test/number/AffixUtilsTest.java
icu4j/main/tests/core/src/com/ibm/icu/dev/test/number/DecimalQuantityTest.java
icu4j/main/tests/core/src/com/ibm/icu/dev/test/number/ModifierTest.java
icu4j/main/tests/core/src/com/ibm/icu/dev/test/number/MutablePatternModifierTest.java
icu4j/main/tests/core/src/com/ibm/icu/dev/test/number/NumberStringBuilderTest.java
icu4j/main/tests/core/src/com/ibm/icu/dev/test/number/PatternStringTest.java
icu4j/main/tests/core/src/com/ibm/icu/dev/test/number/PropertiesTest.java

index 0cf547e341e2b8c1ac7881d3c1e4e4d214b7de37..02cda7dd551e09f89db211f1481327858fa15ab5 100644 (file)
@@ -3,24 +3,24 @@
 package com.ibm.icu.impl.number;
 
 public interface AffixPatternProvider {
-  public static final class Flags {
-    public static final int PLURAL_MASK = 0xff;
-    public static final int PREFIX = 0x100;
-    public static final int NEGATIVE_SUBPATTERN = 0x200;
-    public static final int PADDING = 0x400;
-  }
+    public static final class Flags {
+        public static final int PLURAL_MASK = 0xff;
+        public static final int PREFIX = 0x100;
+        public static final int NEGATIVE_SUBPATTERN = 0x200;
+        public static final int PADDING = 0x400;
+    }
 
-  public char charAt(int flags, int i);
+    public char charAt(int flags, int i);
 
-  public int length(int flags);
+    public int length(int flags);
 
-  public boolean hasCurrencySign();
+    public boolean hasCurrencySign();
 
-  public boolean positiveHasPlusSign();
+    public boolean positiveHasPlusSign();
 
-  public boolean hasNegativeSubpattern();
+    public boolean hasNegativeSubpattern();
 
-  public boolean negativeHasMinusSign();
+    public boolean negativeHasMinusSign();
 
-  public boolean containsSymbolType(int type);
+    public boolean containsSymbolType(int type);
 }
index bf32451468864b08ac4773c967e4d0e00e2adb6f..2cf6d06b74e346eda566169125a1966f5a28c08d 100644 (file)
@@ -9,608 +9,651 @@ import com.ibm.icu.text.NumberFormat;
  * format pattern. For example:
  *
  * <table>
- * <tr><th>Affix Pattern</th><th>Example Unescaped (Formatted) String</th></tr>
- * <tr><td>abc</td><td>abc</td></tr>
- * <tr><td>ab-</td><td>ab−</td></tr>
- * <tr><td>ab'-'</td><td>ab-</td></tr>
- * <tr><td>ab''</td><td>ab'</td></tr>
+ * <tr>
+ * <th>Affix Pattern</th>
+ * <th>Example Unescaped (Formatted) String</th>
+ * </tr>
+ * <tr>
+ * <td>abc</td>
+ * <td>abc</td>
+ * </tr>
+ * <tr>
+ * <td>ab-</td>
+ * <td>ab−</td>
+ * </tr>
+ * <tr>
+ * <td>ab'-'</td>
+ * <td>ab-</td>
+ * </tr>
+ * <tr>
+ * <td>ab''</td>
+ * <td>ab'</td>
+ * </tr>
  * </table>
  *
- * To manually iterate over tokens in a literal string, use the following pattern, which is designed
- * to be efficient.
+ * To manually iterate over tokens in a literal string, use the following pattern, which is designed to
+ * be efficient.
  *
  * <pre>
  * long tag = 0L;
  * while (AffixPatternUtils.hasNext(tag, patternString)) {
- *   tag = AffixPatternUtils.nextToken(tag, patternString);
- *   int typeOrCp = AffixPatternUtils.getTypeOrCp(tag);
- *   switch (typeOrCp) {
+ *     tag = AffixPatternUtils.nextToken(tag, patternString);
+ *     int typeOrCp = AffixPatternUtils.getTypeOrCp(tag);
+ *     switch (typeOrCp) {
  *     case AffixPatternUtils.TYPE_MINUS_SIGN:
- *       // Current token is a minus sign.
- *       break;
+ *         // Current token is a minus sign.
+ *         break;
  *     case AffixPatternUtils.TYPE_PLUS_SIGN:
- *       // Current token is a plus sign.
- *       break;
+ *         // Current token is a plus sign.
+ *         break;
  *     case AffixPatternUtils.TYPE_PERCENT:
- *       // Current token is a percent sign.
- *       break;
+ *         // Current token is a percent sign.
+ *         break;
  *     // ... other types ...
  *     default:
- *       // Current token is an arbitrary code point.
- *       // The variable typeOrCp is the code point.
- *       break;
- *   }
+ *         // Current token is an arbitrary code point.
+ *         // The variable typeOrCp is the code point.
+ *         break;
+ *     }
  * }
  * </pre>
  */
 public class AffixUtils {
 
-  private static final int STATE_BASE = 0;
-  private static final int STATE_FIRST_QUOTE = 1;
-  private static final int STATE_INSIDE_QUOTE = 2;
-  private static final int STATE_AFTER_QUOTE = 3;
-  private static final int STATE_FIRST_CURR = 4;
-  private static final int STATE_SECOND_CURR = 5;
-  private static final int STATE_THIRD_CURR = 6;
-  private static final int STATE_FOURTH_CURR = 7;
-  private static final int STATE_FIFTH_CURR = 8;
-  private static final int STATE_OVERFLOW_CURR = 9;
-
-  /** Represents a literal character; the value is stored in the code point field. */
-  private static final int TYPE_CODEPOINT = 0;
-
-  /** Represents a minus sign symbol '-'. */
-  public static final int TYPE_MINUS_SIGN = -1;
-
-  /** Represents a plus sign symbol '+'. */
-  public static final int TYPE_PLUS_SIGN = -2;
-
-  /** Represents a percent sign symbol '%'. */
-  public static final int TYPE_PERCENT = -3;
-
-  /** Represents a permille sign symbol '‰'. */
-  public static final int TYPE_PERMILLE = -4;
-
-  /** Represents a single currency symbol '¤'. */
-  public static final int TYPE_CURRENCY_SINGLE = -5;
-
-  /** Represents a double currency symbol '¤¤'. */
-  public static final int TYPE_CURRENCY_DOUBLE = -6;
-
-  /** Represents a triple currency symbol '¤¤¤'. */
-  public static final int TYPE_CURRENCY_TRIPLE = -7;
-
-  /** Represents a quadruple currency symbol '¤¤¤¤'. */
-  public static final int TYPE_CURRENCY_QUAD = -8;
-
-  /** Represents a quintuple currency symbol '¤¤¤¤¤'. */
-  public static final int TYPE_CURRENCY_QUINT = -9;
-
-  /** Represents a sequence of six or more currency symbols. */
-  public static final int TYPE_CURRENCY_OVERFLOW = -15;
-
-  public static interface SymbolProvider {
-    public CharSequence getSymbol(int type);
-  }
-
-  /**
-   * Estimates the number of code points present in an unescaped version of the affix pattern string
-   * (one that would be returned by {@link #unescape}), assuming that all interpolated symbols
-   * consume one code point and that currencies consume as many code points as their symbol width.
-   * Used for computing padding width.
-   *
-   * @param patternString The original string whose width will be estimated.
-   * @return The length of the unescaped string.
-   */
-  public static int estimateLength(CharSequence patternString) {
-    if (patternString == null) return 0;
-    int state = STATE_BASE;
-    int offset = 0;
-    int length = 0;
-    for (; offset < patternString.length(); ) {
-      int cp = Character.codePointAt(patternString, offset);
-
-      switch (state) {
-        case STATE_BASE:
-          if (cp == '\'') {
-            // First quote
-            state = STATE_FIRST_QUOTE;
-          } else {
-            // Unquoted symbol
-            length++;
-          }
-          break;
+    private static final int STATE_BASE = 0;
+    private static final int STATE_FIRST_QUOTE = 1;
+    private static final int STATE_INSIDE_QUOTE = 2;
+    private static final int STATE_AFTER_QUOTE = 3;
+    private static final int STATE_FIRST_CURR = 4;
+    private static final int STATE_SECOND_CURR = 5;
+    private static final int STATE_THIRD_CURR = 6;
+    private static final int STATE_FOURTH_CURR = 7;
+    private static final int STATE_FIFTH_CURR = 8;
+    private static final int STATE_OVERFLOW_CURR = 9;
+
+    /** Represents a literal character; the value is stored in the code point field. */
+    private static final int TYPE_CODEPOINT = 0;
+
+    /** Represents a minus sign symbol '-'. */
+    public static final int TYPE_MINUS_SIGN = -1;
+
+    /** Represents a plus sign symbol '+'. */
+    public static final int TYPE_PLUS_SIGN = -2;
+
+    /** Represents a percent sign symbol '%'. */
+    public static final int TYPE_PERCENT = -3;
+
+    /** Represents a permille sign symbol '‰'. */
+    public static final int TYPE_PERMILLE = -4;
+
+    /** Represents a single currency symbol '¤'. */
+    public static final int TYPE_CURRENCY_SINGLE = -5;
+
+    /** Represents a double currency symbol '¤¤'. */
+    public static final int TYPE_CURRENCY_DOUBLE = -6;
+
+    /** Represents a triple currency symbol '¤¤¤'. */
+    public static final int TYPE_CURRENCY_TRIPLE = -7;
+
+    /** Represents a quadruple currency symbol '¤¤¤¤'. */
+    public static final int TYPE_CURRENCY_QUAD = -8;
+
+    /** Represents a quintuple currency symbol '¤¤¤¤¤'. */
+    public static final int TYPE_CURRENCY_QUINT = -9;
+
+    /** Represents a sequence of six or more currency symbols. */
+    public static final int TYPE_CURRENCY_OVERFLOW = -15;
+
+    public static interface SymbolProvider {
+        public CharSequence getSymbol(int type);
+    }
+
+    /**
+     * Estimates the number of code points present in an unescaped version of the affix pattern string
+     * (one that would be returned by {@link #unescape}), assuming that all interpolated symbols consume
+     * one code point and that currencies consume as many code points as their symbol width. Used for
+     * computing padding width.
+     *
+     * @param patternString
+     *            The original string whose width will be estimated.
+     * @return The length of the unescaped string.
+     */
+    public static int estimateLength(CharSequence patternString) {
+        if (patternString == null)
+            return 0;
+        int state = STATE_BASE;
+        int offset = 0;
+        int length = 0;
+        for (; offset < patternString.length();) {
+            int cp = Character.codePointAt(patternString, offset);
+
+            switch (state) {
+            case STATE_BASE:
+                if (cp == '\'') {
+                    // First quote
+                    state = STATE_FIRST_QUOTE;
+                } else {
+                    // Unquoted symbol
+                    length++;
+                }
+                break;
+            case STATE_FIRST_QUOTE:
+                if (cp == '\'') {
+                    // Repeated quote
+                    length++;
+                    state = STATE_BASE;
+                } else {
+                    // Quoted code point
+                    length++;
+                    state = STATE_INSIDE_QUOTE;
+                }
+                break;
+            case STATE_INSIDE_QUOTE:
+                if (cp == '\'') {
+                    // End of quoted sequence
+                    state = STATE_AFTER_QUOTE;
+                } else {
+                    // Quoted code point
+                    length++;
+                }
+                break;
+            case STATE_AFTER_QUOTE:
+                if (cp == '\'') {
+                    // Double quote inside of quoted sequence
+                    length++;
+                    state = STATE_INSIDE_QUOTE;
+                } else {
+                    // Unquoted symbol
+                    length++;
+                }
+                break;
+            default:
+                throw new AssertionError();
+            }
+
+            offset += Character.charCount(cp);
+        }
+
+        switch (state) {
         case STATE_FIRST_QUOTE:
-          if (cp == '\'') {
-            // Repeated quote
-            length++;
-            state = STATE_BASE;
-          } else {
-            // Quoted code point
-            length++;
-            state = STATE_INSIDE_QUOTE;
-          }
-          break;
         case STATE_INSIDE_QUOTE:
-          if (cp == '\'') {
-            // End of quoted sequence
-            state = STATE_AFTER_QUOTE;
-          } else {
-            // Quoted code point
-            length++;
-          }
-          break;
-        case STATE_AFTER_QUOTE:
-          if (cp == '\'') {
-            // Double quote inside of quoted sequence
-            length++;
-            state = STATE_INSIDE_QUOTE;
-          } else {
-            // Unquoted symbol
-            length++;
-          }
-          break;
+            throw new IllegalArgumentException("Unterminated quote: \"" + patternString + "\"");
         default:
-          throw new AssertionError();
-      }
+            break;
+        }
 
-      offset += Character.charCount(cp);
+        return length;
     }
 
-    switch (state) {
-      case STATE_FIRST_QUOTE:
-      case STATE_INSIDE_QUOTE:
-        throw new IllegalArgumentException("Unterminated quote: \"" + patternString + "\"");
-      default:
-        break;
-    }
+    /**
+     * Takes a string and escapes (quotes) characters that have special meaning in the affix pattern
+     * syntax. This function does not reverse-lookup symbols.
+     *
+     * <p>
+     * Example input: "-$x"; example output: "'-'$x"
+     *
+     * @param input
+     *            The string to be escaped.
+     * @param output
+     *            The string builder to which to append the escaped string.
+     * @return The number of chars (UTF-16 code units) appended to the output.
+     */
+    public static int escape(CharSequence input, StringBuilder output) {
+        if (input == null)
+            return 0;
+        int state = STATE_BASE;
+        int offset = 0;
+        int startLength = output.length();
+        for (; offset < input.length();) {
+            int cp = Character.codePointAt(input, offset);
+
+            switch (cp) {
+            case '\'':
+                output.append("''");
+                break;
 
-    return length;
-  }
-
-  /**
-   * Takes a string and escapes (quotes) characters that have special meaning in the affix pattern
-   * syntax. This function does not reverse-lookup symbols.
-   *
-   * <p>Example input: "-$x"; example output: "'-'$x"
-   *
-   * @param input The string to be escaped.
-   * @param output The string builder to which to append the escaped string.
-   * @return The number of chars (UTF-16 code units) appended to the output.
-   */
-  public static int escape(CharSequence input, StringBuilder output) {
-    if (input == null) return 0;
-    int state = STATE_BASE;
-    int offset = 0;
-    int startLength = output.length();
-    for (; offset < input.length(); ) {
-      int cp = Character.codePointAt(input, offset);
-
-      switch (cp) {
-        case '\'':
-          output.append("''");
-          break;
-
-        case '-':
-        case '+':
-        case '%':
-        case '‰':
-        case '¤':
-          if (state == STATE_BASE) {
-            output.append('\'');
-            output.appendCodePoint(cp);
-            state = STATE_INSIDE_QUOTE;
-          } else {
-            output.appendCodePoint(cp);
-          }
-          break;
+            case '-':
+            case '+':
+            case '%':
+            case '‰':
+            case '¤':
+                if (state == STATE_BASE) {
+                    output.append('\'');
+                    output.appendCodePoint(cp);
+                    state = STATE_INSIDE_QUOTE;
+                } else {
+                    output.appendCodePoint(cp);
+                }
+                break;
 
-        default:
-          if (state == STATE_INSIDE_QUOTE) {
+            default:
+                if (state == STATE_INSIDE_QUOTE) {
+                    output.append('\'');
+                    output.appendCodePoint(cp);
+                    state = STATE_BASE;
+                } else {
+                    output.appendCodePoint(cp);
+                }
+                break;
+            }
+            offset += Character.charCount(cp);
+        }
+
+        if (state == STATE_INSIDE_QUOTE) {
             output.append('\'');
-            output.appendCodePoint(cp);
-            state = STATE_BASE;
-          } else {
-            output.appendCodePoint(cp);
-          }
-          break;
-      }
-      offset += Character.charCount(cp);
+        }
+
+        return output.length() - startLength;
     }
 
-    if (state == STATE_INSIDE_QUOTE) {
-      output.append('\'');
+    /** Version of {@link #escape} that returns a String, or null if input is null. */
+    public static String escape(CharSequence input) {
+        if (input == null)
+            return null;
+        StringBuilder sb = new StringBuilder();
+        escape(input, sb);
+        return sb.toString();
     }
 
-    return output.length() - startLength;
-  }
-
-  /** Version of {@link #escape} that returns a String, or null if input is null. */
-  public static String escape(CharSequence input) {
-    if (input == null) return null;
-    StringBuilder sb = new StringBuilder();
-    escape(input, sb);
-    return sb.toString();
-  }
-
-  public static final NumberFormat.Field getFieldForType(int type) {
-    switch (type) {
-      case TYPE_MINUS_SIGN:
-        return NumberFormat.Field.SIGN;
-      case TYPE_PLUS_SIGN:
-        return NumberFormat.Field.SIGN;
-      case TYPE_PERCENT:
-        return NumberFormat.Field.PERCENT;
-      case TYPE_PERMILLE:
-        return NumberFormat.Field.PERMILLE;
-      case TYPE_CURRENCY_SINGLE:
-        return NumberFormat.Field.CURRENCY;
-      case TYPE_CURRENCY_DOUBLE:
-        return NumberFormat.Field.CURRENCY;
-      case TYPE_CURRENCY_TRIPLE:
-        return NumberFormat.Field.CURRENCY;
-      case TYPE_CURRENCY_QUAD:
-        return NumberFormat.Field.CURRENCY;
-      case TYPE_CURRENCY_QUINT:
-        return NumberFormat.Field.CURRENCY;
-      case TYPE_CURRENCY_OVERFLOW:
-        return NumberFormat.Field.CURRENCY;
-      default:
-        throw new AssertionError();
+    public static final NumberFormat.Field getFieldForType(int type) {
+        switch (type) {
+        case TYPE_MINUS_SIGN:
+            return NumberFormat.Field.SIGN;
+        case TYPE_PLUS_SIGN:
+            return NumberFormat.Field.SIGN;
+        case TYPE_PERCENT:
+            return NumberFormat.Field.PERCENT;
+        case TYPE_PERMILLE:
+            return NumberFormat.Field.PERMILLE;
+        case TYPE_CURRENCY_SINGLE:
+            return NumberFormat.Field.CURRENCY;
+        case TYPE_CURRENCY_DOUBLE:
+            return NumberFormat.Field.CURRENCY;
+        case TYPE_CURRENCY_TRIPLE:
+            return NumberFormat.Field.CURRENCY;
+        case TYPE_CURRENCY_QUAD:
+            return NumberFormat.Field.CURRENCY;
+        case TYPE_CURRENCY_QUINT:
+            return NumberFormat.Field.CURRENCY;
+        case TYPE_CURRENCY_OVERFLOW:
+            return NumberFormat.Field.CURRENCY;
+        default:
+            throw new AssertionError();
+        }
     }
-  }
-
-  /**
-   * Executes the unescape state machine. Replaces the unquoted characters "-", "+", "%", "‰", and
-   * "¤" with the corresponding symbols provided by the {@link SymbolProvider}, and inserts the
-   * result into the NumberStringBuilder at the requested location.
-   *
-   * <p>Example input: "'-'¤x"; example output: "-$x"
-   *
-   * @param affixPattern The original string to be unescaped.
-   * @param output The NumberStringBuilder to mutate with the result.
-   * @param position The index into the NumberStringBuilder to insert the the string.
-   * @param provider An object to generate locale symbols.
-   * @return The length of the string added to affixPattern.
-   */
-  public static int unescape(
-      CharSequence affixPattern,
-      NumberStringBuilder output,
-      int position,
-      SymbolProvider provider) {
-    assert affixPattern != null;
-    int length = 0;
-    long tag = 0L;
-    while (hasNext(tag, affixPattern)) {
-      tag = nextToken(tag, affixPattern);
-      int typeOrCp = getTypeOrCp(tag);
-      if (typeOrCp == TYPE_CURRENCY_OVERFLOW) {
-        // Don't go to the provider for this special case
-        length += output.insertCodePoint(position + length, 0xFFFD, NumberFormat.Field.CURRENCY);
-      } else if (typeOrCp < 0) {
-        length += output.insert(position + length, provider.getSymbol(typeOrCp), getFieldForType(typeOrCp));
-      } else {
-        length += output.insertCodePoint(position + length, typeOrCp, null);
-      }
+
+    /**
+     * Executes the unescape state machine. Replaces the unquoted characters "-", "+", "%", "‰", and "¤"
+     * with the corresponding symbols provided by the {@link SymbolProvider}, and inserts the result into
+     * the NumberStringBuilder at the requested location.
+     *
+     * <p>
+     * Example input: "'-'¤x"; example output: "-$x"
+     *
+     * @param affixPattern
+     *            The original string to be unescaped.
+     * @param output
+     *            The NumberStringBuilder to mutate with the result.
+     * @param position
+     *            The index into the NumberStringBuilder to insert the the string.
+     * @param provider
+     *            An object to generate locale symbols.
+     * @return The length of the string added to affixPattern.
+     */
+    public static int unescape(
+            CharSequence affixPattern,
+            NumberStringBuilder output,
+            int position,
+            SymbolProvider provider) {
+        assert affixPattern != null;
+        int length = 0;
+        long tag = 0L;
+        while (hasNext(tag, affixPattern)) {
+            tag = nextToken(tag, affixPattern);
+            int typeOrCp = getTypeOrCp(tag);
+            if (typeOrCp == TYPE_CURRENCY_OVERFLOW) {
+                // Don't go to the provider for this special case
+                length += output.insertCodePoint(position + length, 0xFFFD, NumberFormat.Field.CURRENCY);
+            } else if (typeOrCp < 0) {
+                length += output.insert(position + length,
+                        provider.getSymbol(typeOrCp),
+                        getFieldForType(typeOrCp));
+            } else {
+                length += output.insertCodePoint(position + length, typeOrCp, null);
+            }
+        }
+        return length;
     }
-    return length;
-  }
-
-  /**
-   * Sames as {@link #unescape}, but only calculates the code point count.  More efficient than {@link #unescape}
-   * if you only need the length but not the string itself.
-   *
-   * @param affixPattern The original string to be unescaped.
-   * @param provider An object to generate locale symbols.
-   * @return The number of code points in the unescaped string.
-   */
-  public static int unescapedCodePointCount(CharSequence affixPattern, SymbolProvider provider) {
-    int length = 0;
-    long tag = 0L;
-    while (hasNext(tag, affixPattern)) {
-      tag = nextToken(tag, affixPattern);
-      int typeOrCp = getTypeOrCp(tag);
-      if (typeOrCp == TYPE_CURRENCY_OVERFLOW) {
-        length += 1;
-      } else if (typeOrCp < 0) {
-        CharSequence symbol = provider.getSymbol(typeOrCp);
-        length += Character.codePointCount(symbol, 0, symbol.length());
-      } else {
-        length += 1;
-      }
+
+    /**
+     * Sames as {@link #unescape}, but only calculates the code point count. More efficient than
+     * {@link #unescape} if you only need the length but not the string itself.
+     *
+     * @param affixPattern
+     *            The original string to be unescaped.
+     * @param provider
+     *            An object to generate locale symbols.
+     * @return The number of code points in the unescaped string.
+     */
+    public static int unescapedCodePointCount(CharSequence affixPattern, SymbolProvider provider) {
+        int length = 0;
+        long tag = 0L;
+        while (hasNext(tag, affixPattern)) {
+            tag = nextToken(tag, affixPattern);
+            int typeOrCp = getTypeOrCp(tag);
+            if (typeOrCp == TYPE_CURRENCY_OVERFLOW) {
+                length += 1;
+            } else if (typeOrCp < 0) {
+                CharSequence symbol = provider.getSymbol(typeOrCp);
+                length += Character.codePointCount(symbol, 0, symbol.length());
+            } else {
+                length += 1;
+            }
+        }
+        return length;
     }
-    return length;
-  }
-
-  /**
-   * Checks whether the given affix pattern contains at least one token of the given type, which is
-   * one of the constants "TYPE_" in {@link AffixUtils}.
-   *
-   * @param affixPattern The affix pattern to check.
-   * @param type The token type.
-   * @return true if the affix pattern contains the given token type; false otherwise.
-   */
-  public static boolean containsType(CharSequence affixPattern, int type) {
-    if (affixPattern == null || affixPattern.length() == 0) {
+
+    /**
+     * Checks whether the given affix pattern contains at least one token of the given type, which is one
+     * of the constants "TYPE_" in {@link AffixUtils}.
+     *
+     * @param affixPattern
+     *            The affix pattern to check.
+     * @param type
+     *            The token type.
+     * @return true if the affix pattern contains the given token type; false otherwise.
+     */
+    public static boolean containsType(CharSequence affixPattern, int type) {
+        if (affixPattern == null || affixPattern.length() == 0) {
+            return false;
+        }
+        long tag = 0L;
+        while (hasNext(tag, affixPattern)) {
+            tag = nextToken(tag, affixPattern);
+            if (getTypeOrCp(tag) == type) {
+                return true;
+            }
+        }
         return false;
     }
-    long tag = 0L;
-    while (hasNext(tag, affixPattern)) {
-      tag = nextToken(tag, affixPattern);
-      if (getTypeOrCp(tag) == type) {
-        return true;
-      }
+
+    /**
+     * Checks whether the specified affix pattern has any unquoted currency symbols ("¤").
+     *
+     * @param affixPattern
+     *            The string to check for currency symbols.
+     * @return true if the literal has at least one unquoted currency symbol; false otherwise.
+     */
+    public static boolean hasCurrencySymbols(CharSequence affixPattern) {
+        if (affixPattern == null || affixPattern.length() == 0)
+            return false;
+        long tag = 0L;
+        while (hasNext(tag, affixPattern)) {
+            tag = nextToken(tag, affixPattern);
+            int typeOrCp = getTypeOrCp(tag);
+            if (typeOrCp < 0 && getFieldForType(typeOrCp) == NumberFormat.Field.CURRENCY) {
+                return true;
+            }
+        }
+        return false;
     }
-    return false;
-  }
-
-  /**
-   * Checks whether the specified affix pattern has any unquoted currency symbols ("¤").
-   *
-   * @param affixPattern The string to check for currency symbols.
-   * @return true if the literal has at least one unquoted currency symbol; false otherwise.
-   */
-  public static boolean hasCurrencySymbols(CharSequence affixPattern) {
-    if (affixPattern == null || affixPattern.length() == 0) return false;
-    long tag = 0L;
-    while (hasNext(tag, affixPattern)) {
-      tag = nextToken(tag, affixPattern);
-      int typeOrCp = getTypeOrCp(tag);
-      if (typeOrCp < 0 && getFieldForType(typeOrCp) == NumberFormat.Field.CURRENCY) {
-        return true;
-      }
+
+    /**
+     * Replaces all occurrences of tokens with the given type with the given replacement char.
+     *
+     * @param affixPattern
+     *            The source affix pattern (does not get modified).
+     * @param type
+     *            The token type.
+     * @param replacementChar
+     *            The char to substitute in place of chars of the given token type.
+     * @return A string containing the new affix pattern.
+     */
+    public static String replaceType(CharSequence affixPattern, int type, char replacementChar) {
+        if (affixPattern == null || affixPattern.length() == 0)
+            return "";
+        char[] chars = affixPattern.toString().toCharArray();
+        long tag = 0L;
+        while (hasNext(tag, affixPattern)) {
+            tag = nextToken(tag, affixPattern);
+            if (getTypeOrCp(tag) == type) {
+                int offset = getOffset(tag);
+                chars[offset - 1] = replacementChar;
+            }
+        }
+        return new String(chars);
     }
-    return false;
-  }
-
-  /**
-   * Replaces all occurrences of tokens with the given type with the given replacement char.
-   *
-   * @param affixPattern The source affix pattern (does not get modified).
-   * @param type The token type.
-   * @param replacementChar The char to substitute in place of chars of the given token type.
-   * @return A string containing the new affix pattern.
-   */
-  public static String replaceType(CharSequence affixPattern, int type, char replacementChar) {
-    if (affixPattern == null || affixPattern.length() == 0) return "";
-    char[] chars = affixPattern.toString().toCharArray();
-    long tag = 0L;
-    while (hasNext(tag, affixPattern)) {
-      tag = nextToken(tag, affixPattern);
-      if (getTypeOrCp(tag) == type) {
+
+    /**
+     * Returns the next token from the affix pattern.
+     *
+     * @param tag
+     *            A bitmask used for keeping track of state from token to token. The initial value should
+     *            be 0L.
+     * @param patternString
+     *            The affix pattern.
+     * @return The bitmask tag to pass to the next call of this method to retrieve the following token
+     *         (never negative), or -1 if there were no more tokens in the affix pattern.
+     * @see #hasNext
+     */
+    public static long nextToken(long tag, CharSequence patternString) {
         int offset = getOffset(tag);
-        chars[offset - 1] = replacementChar;
-      }
-    }
-    return new String(chars);
-  }
-
-  /**
-   * Returns the next token from the affix pattern.
-   *
-   * @param tag A bitmask used for keeping track of state from token to token. The initial value
-   *     should be 0L.
-   * @param patternString The affix pattern.
-   * @return The bitmask tag to pass to the next call of this method to retrieve the following token
-   *     (never negative), or -1 if there were no more tokens in the affix pattern.
-   * @see #hasNext
-   */
-  public static long nextToken(long tag, CharSequence patternString) {
-    int offset = getOffset(tag);
-    int state = getState(tag);
-    for (; offset < patternString.length(); ) {
-      int cp = Character.codePointAt(patternString, offset);
-      int count = Character.charCount(cp);
-
-      switch (state) {
-        case STATE_BASE:
-          switch (cp) {
-            case '\'':
-              state = STATE_FIRST_QUOTE;
-              offset += count;
-              // continue to the next code point
-              break;
-            case '-':
-              return makeTag(offset + count, TYPE_MINUS_SIGN, STATE_BASE, 0);
-            case '+':
-              return makeTag(offset + count, TYPE_PLUS_SIGN, STATE_BASE, 0);
-            case '%':
-              return makeTag(offset + count, TYPE_PERCENT, STATE_BASE, 0);
-            case '‰':
-              return makeTag(offset + count, TYPE_PERMILLE, STATE_BASE, 0);
-            case '¤':
-              state = STATE_FIRST_CURR;
-              offset += count;
-              // continue to the next code point
-              break;
+        int state = getState(tag);
+        for (; offset < patternString.length();) {
+            int cp = Character.codePointAt(patternString, offset);
+            int count = Character.charCount(cp);
+
+            switch (state) {
+            case STATE_BASE:
+                switch (cp) {
+                case '\'':
+                    state = STATE_FIRST_QUOTE;
+                    offset += count;
+                    // continue to the next code point
+                    break;
+                case '-':
+                    return makeTag(offset + count, TYPE_MINUS_SIGN, STATE_BASE, 0);
+                case '+':
+                    return makeTag(offset + count, TYPE_PLUS_SIGN, STATE_BASE, 0);
+                case '%':
+                    return makeTag(offset + count, TYPE_PERCENT, STATE_BASE, 0);
+                case '‰':
+                    return makeTag(offset + count, TYPE_PERMILLE, STATE_BASE, 0);
+                case '¤':
+                    state = STATE_FIRST_CURR;
+                    offset += count;
+                    // continue to the next code point
+                    break;
+                default:
+                    return makeTag(offset + count, TYPE_CODEPOINT, STATE_BASE, cp);
+                }
+                break;
+            case STATE_FIRST_QUOTE:
+                if (cp == '\'') {
+                    return makeTag(offset + count, TYPE_CODEPOINT, STATE_BASE, cp);
+                } else {
+                    return makeTag(offset + count, TYPE_CODEPOINT, STATE_INSIDE_QUOTE, cp);
+                }
+            case STATE_INSIDE_QUOTE:
+                if (cp == '\'') {
+                    state = STATE_AFTER_QUOTE;
+                    offset += count;
+                    // continue to the next code point
+                    break;
+                } else {
+                    return makeTag(offset + count, TYPE_CODEPOINT, STATE_INSIDE_QUOTE, cp);
+                }
+            case STATE_AFTER_QUOTE:
+                if (cp == '\'') {
+                    return makeTag(offset + count, TYPE_CODEPOINT, STATE_INSIDE_QUOTE, cp);
+                } else {
+                    state = STATE_BASE;
+                    // re-evaluate this code point
+                    break;
+                }
+            case STATE_FIRST_CURR:
+                if (cp == '¤') {
+                    state = STATE_SECOND_CURR;
+                    offset += count;
+                    // continue to the next code point
+                    break;
+                } else {
+                    return makeTag(offset, TYPE_CURRENCY_SINGLE, STATE_BASE, 0);
+                }
+            case STATE_SECOND_CURR:
+                if (cp == '¤') {
+                    state = STATE_THIRD_CURR;
+                    offset += count;
+                    // continue to the next code point
+                    break;
+                } else {
+                    return makeTag(offset, TYPE_CURRENCY_DOUBLE, STATE_BASE, 0);
+                }
+            case STATE_THIRD_CURR:
+                if (cp == '¤') {
+                    state = STATE_FOURTH_CURR;
+                    offset += count;
+                    // continue to the next code point
+                    break;
+                } else {
+                    return makeTag(offset, TYPE_CURRENCY_TRIPLE, STATE_BASE, 0);
+                }
+            case STATE_FOURTH_CURR:
+                if (cp == '¤') {
+                    state = STATE_FIFTH_CURR;
+                    offset += count;
+                    // continue to the next code point
+                    break;
+                } else {
+                    return makeTag(offset, TYPE_CURRENCY_QUAD, STATE_BASE, 0);
+                }
+            case STATE_FIFTH_CURR:
+                if (cp == '¤') {
+                    state = STATE_OVERFLOW_CURR;
+                    offset += count;
+                    // continue to the next code point
+                    break;
+                } else {
+                    return makeTag(offset, TYPE_CURRENCY_QUINT, STATE_BASE, 0);
+                }
+            case STATE_OVERFLOW_CURR:
+                if (cp == '¤') {
+                    offset += count;
+                    // continue to the next code point and loop back to this state
+                    break;
+                } else {
+                    return makeTag(offset, TYPE_CURRENCY_OVERFLOW, STATE_BASE, 0);
+                }
             default:
-              return makeTag(offset + count, TYPE_CODEPOINT, STATE_BASE, cp);
-          }
-          break;
+                throw new AssertionError();
+            }
+        }
+        // End of string
+        switch (state) {
+        case STATE_BASE:
+            // No more tokens in string.
+            return -1L;
         case STATE_FIRST_QUOTE:
-          if (cp == '\'') {
-            return makeTag(offset + count, TYPE_CODEPOINT, STATE_BASE, cp);
-          } else {
-            return makeTag(offset + count, TYPE_CODEPOINT, STATE_INSIDE_QUOTE, cp);
-          }
         case STATE_INSIDE_QUOTE:
-          if (cp == '\'') {
-            state = STATE_AFTER_QUOTE;
-            offset += count;
-            // continue to the next code point
-            break;
-          } else {
-            return makeTag(offset + count, TYPE_CODEPOINT, STATE_INSIDE_QUOTE, cp);
-          }
+            // For consistent behavior with the JDK and ICU 58, throw an exception here.
+            throw new IllegalArgumentException(
+                    "Unterminated quote in pattern affix: \"" + patternString + "\"");
         case STATE_AFTER_QUOTE:
-          if (cp == '\'') {
-            return makeTag(offset + count, TYPE_CODEPOINT, STATE_INSIDE_QUOTE, cp);
-          } else {
-            state = STATE_BASE;
-            // re-evaluate this code point
-            break;
-          }
+            // No more tokens in string.
+            return -1L;
         case STATE_FIRST_CURR:
-          if (cp == '¤') {
-            state = STATE_SECOND_CURR;
-            offset += count;
-            // continue to the next code point
-            break;
-          } else {
             return makeTag(offset, TYPE_CURRENCY_SINGLE, STATE_BASE, 0);
-          }
         case STATE_SECOND_CURR:
-          if (cp == '¤') {
-            state = STATE_THIRD_CURR;
-            offset += count;
-            // continue to the next code point
-            break;
-          } else {
             return makeTag(offset, TYPE_CURRENCY_DOUBLE, STATE_BASE, 0);
-          }
         case STATE_THIRD_CURR:
-          if (cp == '¤') {
-            state = STATE_FOURTH_CURR;
-            offset += count;
-            // continue to the next code point
-            break;
-          } else {
             return makeTag(offset, TYPE_CURRENCY_TRIPLE, STATE_BASE, 0);
-          }
         case STATE_FOURTH_CURR:
-          if (cp == '¤') {
-            state = STATE_FIFTH_CURR;
-            offset += count;
-            // continue to the next code point
-            break;
-          } else {
             return makeTag(offset, TYPE_CURRENCY_QUAD, STATE_BASE, 0);
-          }
         case STATE_FIFTH_CURR:
-          if (cp == '¤') {
-            state = STATE_OVERFLOW_CURR;
-            offset += count;
-            // continue to the next code point
-            break;
-          } else {
             return makeTag(offset, TYPE_CURRENCY_QUINT, STATE_BASE, 0);
-          }
         case STATE_OVERFLOW_CURR:
-          if (cp == '¤') {
-            offset += count;
-            // continue to the next code point and loop back to this state
-            break;
-          } else {
             return makeTag(offset, TYPE_CURRENCY_OVERFLOW, STATE_BASE, 0);
-          }
         default:
-          throw new AssertionError();
-      }
+            throw new AssertionError();
+        }
     }
-    // End of string
-    switch (state) {
-      case STATE_BASE:
-        // No more tokens in string.
-        return -1L;
-      case STATE_FIRST_QUOTE:
-      case STATE_INSIDE_QUOTE:
-        // For consistent behavior with the JDK and ICU 58, throw an exception here.
-        throw new IllegalArgumentException(
-            "Unterminated quote in pattern affix: \"" + patternString + "\"");
-      case STATE_AFTER_QUOTE:
-        // No more tokens in string.
-        return -1L;
-      case STATE_FIRST_CURR:
-        return makeTag(offset, TYPE_CURRENCY_SINGLE, STATE_BASE, 0);
-      case STATE_SECOND_CURR:
-        return makeTag(offset, TYPE_CURRENCY_DOUBLE, STATE_BASE, 0);
-      case STATE_THIRD_CURR:
-        return makeTag(offset, TYPE_CURRENCY_TRIPLE, STATE_BASE, 0);
-      case STATE_FOURTH_CURR:
-        return makeTag(offset, TYPE_CURRENCY_QUAD, STATE_BASE, 0);
-      case STATE_FIFTH_CURR:
-        return makeTag(offset, TYPE_CURRENCY_QUINT, STATE_BASE, 0);
-      case STATE_OVERFLOW_CURR:
-        return makeTag(offset, TYPE_CURRENCY_OVERFLOW, STATE_BASE, 0);
-      default:
-        throw new AssertionError();
+
+    /**
+     * Returns whether the affix pattern string has any more tokens to be retrieved from a call to
+     * {@link #nextToken}.
+     *
+     * @param tag
+     *            The bitmask tag of the previous token, as returned by {@link #nextToken}.
+     * @param string
+     *            The affix pattern.
+     * @return true if there are more tokens to consume; false otherwise.
+     */
+    public static boolean hasNext(long tag, CharSequence string) {
+        assert tag >= 0;
+        int state = getState(tag);
+        int offset = getOffset(tag);
+        // Special case: the last character in string is an end quote.
+        if (state == STATE_INSIDE_QUOTE
+                && offset == string.length() - 1
+                && string.charAt(offset) == '\'') {
+            return false;
+        } else if (state != STATE_BASE) {
+            return true;
+        } else {
+            return offset < string.length();
+        }
+    }
+
+    /**
+     * This function helps determine the identity of the token consumed by {@link #nextToken}. Converts
+     * from a bitmask tag, based on a call to {@link #nextToken}, to its corresponding symbol type or
+     * code point.
+     *
+     * @param tag
+     *            The bitmask tag of the current token, as returned by {@link #nextToken}.
+     * @return If less than zero, a symbol type corresponding to one of the <code>TYPE_</code> constants,
+     *         such as {@link #TYPE_MINUS_SIGN}. If greater than or equal to zero, a literal code point.
+     */
+    public static int getTypeOrCp(long tag) {
+        assert tag >= 0;
+        int type = getType(tag);
+        return (type == TYPE_CODEPOINT) ? getCodePoint(tag) : -type;
     }
-  }
-
-  /**
-   * Returns whether the affix pattern string has any more tokens to be retrieved from a call to
-   * {@link #nextToken}.
-   *
-   * @param tag The bitmask tag of the previous token, as returned by {@link #nextToken}.
-   * @param string The affix pattern.
-   * @return true if there are more tokens to consume; false otherwise.
-   */
-  public static boolean hasNext(long tag, CharSequence string) {
-    assert tag >= 0;
-    int state = getState(tag);
-    int offset = getOffset(tag);
-    // Special case: the last character in string is an end quote.
-    if (state == STATE_INSIDE_QUOTE
-        && offset == string.length() - 1
-        && string.charAt(offset) == '\'') {
-      return false;
-    } else if (state != STATE_BASE) {
-      return true;
-    } else {
-      return offset < string.length();
+
+    /**
+     * Encodes the given values into a 64-bit tag.
+     *
+     * <ul>
+     * <li>Bits 0-31 => offset (int32)
+     * <li>Bits 32-35 => type (uint4)
+     * <li>Bits 36-39 => state (uint4)
+     * <li>Bits 40-60 => code point (uint21)
+     * <li>Bits 61-63 => unused
+     * </ul>
+     */
+    private static long makeTag(int offset, int type, int state, int cp) {
+        long tag = 0L;
+        tag |= offset;
+        tag |= (-(long) type) << 32;
+        tag |= ((long) state) << 36;
+        tag |= ((long) cp) << 40;
+        assert tag >= 0;
+        return tag;
+    }
+
+    static int getOffset(long tag) {
+        return (int) (tag & 0xffffffff);
+    }
+
+    static int getType(long tag) {
+        return (int) ((tag >>> 32) & 0xf);
+    }
+
+    static int getState(long tag) {
+        return (int) ((tag >>> 36) & 0xf);
+    }
+
+    static int getCodePoint(long tag) {
+        return (int) (tag >>> 40);
     }
-  }
-
-  /**
-   * This function helps determine the identity of the token consumed by {@link #nextToken}.
-   * Converts from a bitmask tag, based on a call to {@link #nextToken}, to its corresponding symbol
-   * type or code point.
-   *
-   * @param tag The bitmask tag of the current token, as returned by {@link #nextToken}.
-   * @return If less than zero, a symbol type corresponding to one of the <code>TYPE_</code>
-   *     constants, such as {@link #TYPE_MINUS_SIGN}. If greater than or equal to zero, a literal
-   *     code point.
-   */
-  public static int getTypeOrCp(long tag) {
-    assert tag >= 0;
-    int type = getType(tag);
-    return (type == TYPE_CODEPOINT) ? getCodePoint(tag) : -type;
-  }
-
-  /**
-   * Encodes the given values into a 64-bit tag.
-   *
-   * <ul>
-   *   <li>Bits 0-31 => offset (int32)
-   *   <li>Bits 32-35 => type (uint4)
-   *   <li>Bits 36-39 => state (uint4)
-   *   <li>Bits 40-60 => code point (uint21)
-   *   <li>Bits 61-63 => unused
-   * </ul>
-   */
-  private static long makeTag(int offset, int type, int state, int cp) {
-    long tag = 0L;
-    tag |= offset;
-    tag |= (-(long) type) << 32;
-    tag |= ((long) state) << 36;
-    tag |= ((long) cp) << 40;
-    assert tag >= 0;
-    return tag;
-  }
-
-  static int getOffset(long tag) {
-    return (int) (tag & 0xffffffff);
-  }
-
-  static int getType(long tag) {
-    return (int) ((tag >>> 32) & 0xf);
-  }
-
-  static int getState(long tag) {
-    return (int) ((tag >>> 36) & 0xf);
-  }
-
-  static int getCodePoint(long tag) {
-    return (int) (tag >>> 40);
-  }
 }
index ed524b3ab4e0cc60636a4c54a9d6fddc846ebf1f..8b66e18fd6fd06297aeaa44702031d3cf09eeee3 100644 (file)
@@ -39,10 +39,15 @@ public class CompactData implements MultiplierProducer {
         isEmpty = true;
     }
 
-    public void populate(ULocale locale, String nsName, CompactStyle compactStyle, CompactType compactType) {
+    public void populate(
+            ULocale locale,
+            String nsName,
+            CompactStyle compactStyle,
+            CompactType compactType) {
         assert isEmpty;
         CompactDataSink sink = new CompactDataSink(this);
-        ICUResourceBundle rb = (ICUResourceBundle) UResourceBundle.getBundleInstance(ICUData.ICU_BASE_NAME, locale);
+        ICUResourceBundle rb = (ICUResourceBundle) UResourceBundle
+                .getBundleInstance(ICUData.ICU_BASE_NAME, locale);
 
         boolean nsIsLatn = nsName.equals("latn");
         boolean compactIsShort = compactStyle == CompactStyle.SHORT;
@@ -71,7 +76,11 @@ public class CompactData implements MultiplierProducer {
     }
 
     /** Produces a string like "NumberElements/latn/patternsShort/decimalFormat". */
-    private static void getResourceBundleKey(String nsName, CompactStyle compactStyle, CompactType compactType, StringBuilder sb) {
+    private static void getResourceBundleKey(
+            String nsName,
+            CompactStyle compactStyle,
+            CompactType compactType,
+            StringBuilder sb) {
         sb.setLength(0);
         sb.append("NumberElements/");
         sb.append(nsName);
@@ -82,7 +91,8 @@ public class CompactData implements MultiplierProducer {
     /** Java-only method used by CLDR tooling. */
     public void populate(Map<String, Map<String, String>> powersToPluralsToPatterns) {
         assert isEmpty;
-        for (Map.Entry<String, Map<String, String>> magnitudeEntry : powersToPluralsToPatterns.entrySet()) {
+        for (Map.Entry<String, Map<String, String>> magnitudeEntry : powersToPluralsToPatterns
+                .entrySet()) {
             byte magnitude = (byte) (magnitudeEntry.getKey().length() - 1);
             for (Map.Entry<String, String> pluralEntry : magnitudeEntry.getValue().entrySet()) {
                 StandardPlural plural = StandardPlural.fromString(pluralEntry.getKey().toString());
@@ -155,7 +165,7 @@ public class CompactData implements MultiplierProducer {
             for (int i3 = 0; powersOfTenTable.getKeyAndValue(i3, key, value); ++i3) {
 
                 // Assumes that the keys are always of the form "10000" where the magnitude is the
-                // length of the key minus one.  We expect magnitudes to be less than MAX_DIGITS.
+                // length of the key minus one. We expect magnitudes to be less than MAX_DIGITS.
                 byte magnitude = (byte) (key.length() - 1);
                 byte multiplier = data.multipliers[magnitude];
                 assert magnitude < COMPACT_MAX_DIGITS;
index 53f79096fe5d0f0b1719d7ba8d9ec7916efcf037..4ebb3d0cc632ac431b1b876236b0ae5278185ca4 100644 (file)
@@ -21,7 +21,8 @@ public class ConstantAffixModifier implements Modifier {
      * Constructs an instance with the given strings.
      *
      * <p>
-     * The arguments need to be Strings, not CharSequences, because Strings are immutable but CharSequences are not.
+     * The arguments need to be Strings, not CharSequences, because Strings are immutable but
+     * CharSequences are not.
      *
      * @param prefix
      *            The prefix string.
index c6c38e07b9ec48602f38d2d7408e38a753ec8e4a..557d0b80f83bbbe9fd33ac010a37108d55e3e1bd 100644 (file)
@@ -5,8 +5,9 @@ package com.ibm.icu.impl.number;
 import com.ibm.icu.text.NumberFormat.Field;
 
 /**
- * An implementation of {@link Modifier} that allows for multiple types of fields in the same modifier. Constructed
- * based on the contents of two {@link NumberStringBuilder} instances (one for the prefix, one for the suffix).
+ * An implementation of {@link Modifier} that allows for multiple types of fields in the same modifier.
+ * Constructed based on the contents of two {@link NumberStringBuilder} instances (one for the prefix,
+ * one for the suffix).
  */
 public class ConstantMultiFieldModifier implements Modifier {
 
@@ -18,7 +19,10 @@ public class ConstantMultiFieldModifier implements Modifier {
     protected final Field[] suffixFields;
     private final boolean strong;
 
-    public ConstantMultiFieldModifier(NumberStringBuilder prefix, NumberStringBuilder suffix, boolean strong) {
+    public ConstantMultiFieldModifier(
+            NumberStringBuilder prefix,
+            NumberStringBuilder suffix,
+            boolean strong) {
         prefixChars = prefix.toCharArray();
         suffixChars = suffix.toCharArray();
         prefixFields = prefix.toFieldArray();
@@ -55,7 +59,8 @@ public class ConstantMultiFieldModifier implements Modifier {
         NumberStringBuilder temp = new NumberStringBuilder();
         apply(temp, 0, 0);
         int prefixLength = getPrefixLength();
-        return String.format("<ConstantMultiFieldModifier prefix:'%s' suffix:'%s'>", temp.subSequence(0, prefixLength),
+        return String.format("<ConstantMultiFieldModifier prefix:'%s' suffix:'%s'>",
+                temp.subSequence(0, prefixLength),
                 temp.subSequence(prefixLength, temp.length()));
     }
 }
index 5aff0f3630460d381e7d1f22c94fb161db8b6ac5..9fb35f7546a4ad9ca7610a2282cb8fb6a65c3397 100644 (file)
@@ -27,7 +27,10 @@ public class CurrencySpacingEnabledModifier extends ConstantMultiFieldModifier {
     private final String beforeSuffixInsert;
 
     /** Safe code path */
-    public CurrencySpacingEnabledModifier(NumberStringBuilder prefix, NumberStringBuilder suffix, boolean strong,
+    public CurrencySpacingEnabledModifier(
+            NumberStringBuilder prefix,
+            NumberStringBuilder suffix,
+            boolean strong,
             DecimalFormatSymbols symbols) {
         super(prefix, suffix, strong);
 
@@ -70,12 +73,14 @@ public class CurrencySpacingEnabledModifier extends ConstantMultiFieldModifier {
     public int apply(NumberStringBuilder output, int leftIndex, int rightIndex) {
         // Currency spacing logic
         int length = 0;
-        if (rightIndex - leftIndex > 0 && afterPrefixUnicodeSet != null
+        if (rightIndex - leftIndex > 0
+                && afterPrefixUnicodeSet != null
                 && afterPrefixUnicodeSet.contains(output.codePointAt(leftIndex))) {
             // TODO: Should we use the CURRENCY field here?
             length += output.insert(leftIndex, afterPrefixInsert, null);
         }
-        if (rightIndex - leftIndex > 0 && beforeSuffixUnicodeSet != null
+        if (rightIndex - leftIndex > 0
+                && beforeSuffixUnicodeSet != null
                 && beforeSuffixUnicodeSet.contains(output.codePointBefore(rightIndex))) {
             // TODO: Should we use the CURRENCY field here?
             length += output.insert(rightIndex + length, beforeSuffixInsert, null);
@@ -87,8 +92,13 @@ public class CurrencySpacingEnabledModifier extends ConstantMultiFieldModifier {
     }
 
     /** Unsafe code path */
-    public static int applyCurrencySpacing(NumberStringBuilder output, int prefixStart, int prefixLen, int suffixStart,
-            int suffixLen, DecimalFormatSymbols symbols) {
+    public static int applyCurrencySpacing(
+            NumberStringBuilder output,
+            int prefixStart,
+            int prefixLen,
+            int suffixStart,
+            int suffixLen,
+            DecimalFormatSymbols symbols) {
         int length = 0;
         boolean hasPrefix = (prefixLen > 0);
         boolean hasSuffix = (suffixLen > 0);
@@ -103,12 +113,16 @@ public class CurrencySpacingEnabledModifier extends ConstantMultiFieldModifier {
     }
 
     /** Unsafe code path */
-    private static int applyCurrencySpacingAffix(NumberStringBuilder output, int index, byte affix,
+    private static int applyCurrencySpacingAffix(
+            NumberStringBuilder output,
+            int index,
+            byte affix,
             DecimalFormatSymbols symbols) {
         // NOTE: For prefix, output.fieldAt(index-1) gets the last field type in the prefix.
         // This works even if the last code point in the prefix is 2 code units because the
         // field value gets populated to both indices in the field array.
-        NumberFormat.Field affixField = (affix == PREFIX) ? output.fieldAt(index - 1) : output.fieldAt(index);
+        NumberFormat.Field affixField = (affix == PREFIX) ? output.fieldAt(index - 1)
+                : output.fieldAt(index);
         if (affixField != NumberFormat.Field.CURRENCY) {
             return 0;
         }
@@ -135,8 +149,10 @@ public class CurrencySpacingEnabledModifier extends ConstantMultiFieldModifier {
 
     private static UnicodeSet getUnicodeSet(DecimalFormatSymbols symbols, short position, byte affix) {
         String pattern = symbols
-                .getPatternForCurrencySpacing(position == IN_CURRENCY ? DecimalFormatSymbols.CURRENCY_SPC_CURRENCY_MATCH
-                        : DecimalFormatSymbols.CURRENCY_SPC_SURROUNDING_MATCH, affix == SUFFIX);
+                .getPatternForCurrencySpacing(
+                        position == IN_CURRENCY ? DecimalFormatSymbols.CURRENCY_SPC_CURRENCY_MATCH
+                                : DecimalFormatSymbols.CURRENCY_SPC_SURROUNDING_MATCH,
+                        affix == SUFFIX);
         if (pattern.equals("[:digit:]")) {
             return UNISET_DIGIT;
         } else if (pattern.equals("[:^S:]")) {
@@ -147,6 +163,7 @@ public class CurrencySpacingEnabledModifier extends ConstantMultiFieldModifier {
     }
 
     private static String getInsertString(DecimalFormatSymbols symbols, byte affix) {
-        return symbols.getPatternForCurrencySpacing(DecimalFormatSymbols.CURRENCY_SPC_INSERT, affix == SUFFIX);
+        return symbols.getPatternForCurrencySpacing(DecimalFormatSymbols.CURRENCY_SPC_INSERT,
+                affix == SUFFIX);
     }
 }
index e8549096eeaef3c2ebd6abeb0679e5d1f6e5d6f1..b794aebe5344ba6af9241cbe57b148f51c72cf5d 100644 (file)
@@ -7,70 +7,69 @@ import com.ibm.icu.util.Currency;
 import com.ibm.icu.util.ULocale;
 
 public class CustomSymbolCurrency extends Currency {
-  private static final long serialVersionUID = 2497493016770137670L;
-  // TODO: Serialization methods?
+    private static final long serialVersionUID = 2497493016770137670L;
+    // TODO: Serialization methods?
 
-  private String symbol1;
-  private String symbol2;
+    private String symbol1;
+    private String symbol2;
 
-  public static Currency resolve(Currency currency, ULocale locale, DecimalFormatSymbols symbols) {
-    if (currency == null) {
-      currency = symbols.getCurrency();
+    public static Currency resolve(Currency currency, ULocale locale, DecimalFormatSymbols symbols) {
+        if (currency == null) {
+            currency = symbols.getCurrency();
+        }
+        String currency1Sym = symbols.getCurrencySymbol();
+        String currency2Sym = symbols.getInternationalCurrencySymbol();
+        if (currency == null) {
+            return new CustomSymbolCurrency("XXX", currency1Sym, currency2Sym);
+        }
+        if (!currency.equals(symbols.getCurrency())) {
+            return currency;
+        }
+        String currency1 = currency.getName(symbols.getULocale(), Currency.SYMBOL_NAME, null);
+        String currency2 = currency.getCurrencyCode();
+        if (!currency1.equals(currency1Sym) || !currency2.equals(currency2Sym)) {
+            return new CustomSymbolCurrency(currency2, currency1Sym, currency2Sym);
+        }
+        return currency;
     }
-    String currency1Sym = symbols.getCurrencySymbol();
-    String currency2Sym = symbols.getInternationalCurrencySymbol();
-    if (currency == null) {
-      return new CustomSymbolCurrency("XXX", currency1Sym, currency2Sym);
-    }
-    if (!currency.equals(symbols.getCurrency())) {
-      return currency;
-    }
-    String currency1 = currency.getName(symbols.getULocale(), Currency.SYMBOL_NAME, null);
-    String currency2 = currency.getCurrencyCode();
-    if (!currency1.equals(currency1Sym) || !currency2.equals(currency2Sym)) {
-      return new CustomSymbolCurrency(currency2, currency1Sym, currency2Sym);
-    }
-    return currency;
-  }
 
-  public CustomSymbolCurrency(String isoCode, String currency1Sym, String currency2Sym) {
-    super(isoCode);
-    this.symbol1 = currency1Sym;
-    this.symbol2 = currency2Sym;
-  }
+    public CustomSymbolCurrency(String isoCode, String currency1Sym, String currency2Sym) {
+        super(isoCode);
+        this.symbol1 = currency1Sym;
+        this.symbol2 = currency2Sym;
+    }
 
-  @Override
-  public String getName(ULocale locale, int nameStyle, boolean[] isChoiceFormat) {
-    if (nameStyle == SYMBOL_NAME) {
-      return symbol1;
+    @Override
+    public String getName(ULocale locale, int nameStyle, boolean[] isChoiceFormat) {
+        if (nameStyle == SYMBOL_NAME) {
+            return symbol1;
+        }
+        return super.getName(locale, nameStyle, isChoiceFormat);
     }
-    return super.getName(locale, nameStyle, isChoiceFormat);
-  }
 
-  @Override
-  public String getName(
-      ULocale locale, int nameStyle, String pluralCount, boolean[] isChoiceFormat) {
-    if (nameStyle == PLURAL_LONG_NAME && subType.equals("XXX")) {
-      // Plural in absence of a currency should return the symbol
-      return symbol1;
+    @Override
+    public String getName(ULocale locale, int nameStyle, String pluralCount, boolean[] isChoiceFormat) {
+        if (nameStyle == PLURAL_LONG_NAME && subType.equals("XXX")) {
+            // Plural in absence of a currency should return the symbol
+            return symbol1;
+        }
+        return super.getName(locale, nameStyle, pluralCount, isChoiceFormat);
     }
-    return super.getName(locale, nameStyle, pluralCount, isChoiceFormat);
-  }
 
-  @Override
-  public String getCurrencyCode() {
-    return symbol2;
-  }
+    @Override
+    public String getCurrencyCode() {
+        return symbol2;
+    }
 
-  @Override
-  public int hashCode() {
-    return super.hashCode() ^ symbol1.hashCode() ^ symbol2.hashCode();
-  }
+    @Override
+    public int hashCode() {
+        return super.hashCode() ^ symbol1.hashCode() ^ symbol2.hashCode();
+    }
 
-  @Override
-  public boolean equals(Object other) {
-    return super.equals(other)
-            && ((CustomSymbolCurrency)other).symbol1.equals(symbol1)
-            && ((CustomSymbolCurrency)other).symbol2.equals(symbol2);
-  }
+    @Override
+    public boolean equals(Object other) {
+        return super.equals(other)
+                && ((CustomSymbolCurrency) other).symbol1.equals(symbol1)
+                && ((CustomSymbolCurrency) other).symbol2.equals(symbol2);
+    }
 }
index 26859abe166c0997721067e8fc11bb8d76a0304e..73d41e5b2fb9ae01e6efaf2a46525443a8a9f87e 100644 (file)
@@ -105,8 +105,8 @@ public class DecimalFormatProperties implements Cloneable, Serializable {
      * Sets all properties to their defaults (unset).
      *
      * <p>
-     * All integers default to -1 EXCEPT FOR MAGNITUDE MULTIPLIER which has a default of 0 (since negative numbers are
-     * important).
+     * All integers default to -1 EXCEPT FOR MAGNITUDE MULTIPLIER which has a default of 0 (since
+     * negative numbers are important).
      *
      * <p>
      * All booleans default to false.
@@ -550,7 +550,8 @@ public class DecimalFormatProperties implements Cloneable, Serializable {
         readObjectImpl(ois);
     }
 
-    /* package-private */ void readObjectImpl(ObjectInputStream ois) throws IOException, ClassNotFoundException {
+    /* package-private */ void readObjectImpl(ObjectInputStream ois)
+            throws IOException, ClassNotFoundException {
         ois.defaultReadObject();
 
         // Initialize to empty
@@ -596,8 +597,8 @@ public class DecimalFormatProperties implements Cloneable, Serializable {
     }
 
     /**
-     * Specifies custom data to be used instead of CLDR data when constructing a CompactDecimalFormat. The argument
-     * should be a map with the following structure:
+     * Specifies custom data to be used instead of CLDR data when constructing a CompactDecimalFormat.
+     * The argument should be a map with the following structure:
      *
      * <pre>
      * {
@@ -619,15 +620,17 @@ public class DecimalFormatProperties implements Cloneable, Serializable {
      *            A map with the above structure.
      * @return The property bag, for chaining.
      */
-    public DecimalFormatProperties setCompactCustomData(Map<String, Map<String, String>> compactCustomData) {
+    public DecimalFormatProperties setCompactCustomData(
+            Map<String, Map<String, String>> compactCustomData) {
         // TODO: compactCustomData is not immutable.
         this.compactCustomData = compactCustomData;
         return this;
     }
 
     /**
-     * Use compact decimal formatting with the specified {@link CompactStyle}. CompactStyle.SHORT produces output like
-     * "10K" in locale <em>en-US</em>, whereas CompactStyle.LONG produces output like "10 thousand" in that locale.
+     * Use compact decimal formatting with the specified {@link CompactStyle}. CompactStyle.SHORT
+     * produces output like "10K" in locale <em>en-US</em>, whereas CompactStyle.LONG produces output
+     * like "10 thousand" in that locale.
      *
      * @param compactStyle
      *            The style of prefixes/suffixes to append.
@@ -668,11 +671,12 @@ public class DecimalFormatProperties implements Cloneable, Serializable {
     }
 
     /**
-     * Use the specified {@link CurrencyUsage} instance, which provides default rounding rules for the currency in two
-     * styles, CurrencyUsage.CASH and CurrencyUsage.STANDARD.
+     * Use the specified {@link CurrencyUsage} instance, which provides default rounding rules for the
+     * currency in two styles, CurrencyUsage.CASH and CurrencyUsage.STANDARD.
      *
      * <p>
-     * The CurrencyUsage specified here will not be used unless there is a currency placeholder in the pattern.
+     * The CurrencyUsage specified here will not be used unless there is a currency placeholder in the
+     * pattern.
      *
      * @param currencyUsage
      *            The currency usage. Defaults to CurrencyUsage.STANDARD.
@@ -684,9 +688,10 @@ public class DecimalFormatProperties implements Cloneable, Serializable {
     }
 
     /**
-     * PARSING: Whether to require that the presence of decimal point matches the pattern. If a decimal point is not
-     * present, but the pattern contained a decimal point, parse will not succeed: null will be returned from
-     * <code>parse()</code>, and an error index will be set in the {@link ParsePosition}.
+     * PARSING: Whether to require that the presence of decimal point matches the pattern. If a decimal
+     * point is not present, but the pattern contained a decimal point, parse will not succeed: null will
+     * be returned from <code>parse()</code>, and an error index will be set in the
+     * {@link ParsePosition}.
      *
      * @param decimalPatternMatchRequired
      *            true to set an error if decimal is not present
@@ -698,8 +703,9 @@ public class DecimalFormatProperties implements Cloneable, Serializable {
     }
 
     /**
-     * Sets whether to always show the decimal point, even if the number doesn't require one. For example, if always
-     * show decimal is true, the number 123 would be formatted as "123." in locale <em>en-US</em>.
+     * Sets whether to always show the decimal point, even if the number doesn't require one. For
+     * example, if always show decimal is true, the number 123 would be formatted as "123." in locale
+     * <em>en-US</em>.
      *
      * @param alwaysShowDecimal
      *            Whether to show the decimal point when it is optional.
@@ -711,8 +717,9 @@ public class DecimalFormatProperties implements Cloneable, Serializable {
     }
 
     /**
-     * Sets whether to show the plus sign in the exponent part of numbers with a zero or positive exponent. For example,
-     * the number "1200" with the pattern "0.0E0" would be formatted as "1.2E+3" instead of "1.2E3" in <em>en-US</em>.
+     * Sets whether to show the plus sign in the exponent part of numbers with a zero or positive
+     * exponent. For example, the number "1200" with the pattern "0.0E0" would be formatted as "1.2E+3"
+     * instead of "1.2E3" in <em>en-US</em>.
      *
      * @param exponentSignAlwaysShown
      *            Whether to show the plus sign in positive exponents.
@@ -724,13 +731,13 @@ public class DecimalFormatProperties implements Cloneable, Serializable {
     }
 
     /**
-     * Sets the minimum width of the string output by the formatting pipeline. For example, if padding is enabled and
-     * paddingWidth is set to 6, formatting the number "3.14159" with the pattern "0.00" will result in "··3.14" if '·'
-     * is your padding string.
+     * Sets the minimum width of the string output by the formatting pipeline. For example, if padding is
+     * enabled and paddingWidth is set to 6, formatting the number "3.14159" with the pattern "0.00" will
+     * result in "··3.14" if '·' is your padding string.
      *
      * <p>
-     * If the number is longer than your padding width, the number will display as if no padding width had been
-     * specified, which may result in strings longer than the padding width.
+     * If the number is longer than your padding width, the number will display as if no padding width
+     * had been specified, which may result in strings longer than the padding width.
      *
      * <p>
      * Width is counted in UTF-16 code units.
@@ -747,9 +754,9 @@ public class DecimalFormatProperties implements Cloneable, Serializable {
     }
 
     /**
-     * Sets the number of digits between grouping separators. For example, the <em>en-US</em> locale uses a grouping
-     * size of 3, so the number 1234567 would be formatted as "1,234,567". For locales whose grouping sizes vary with
-     * magnitude, see {@link #setSecondaryGroupingSize(int)}.
+     * Sets the number of digits between grouping separators. For example, the <em>en-US</em> locale uses
+     * a grouping size of 3, so the number 1234567 would be formatted as "1,234,567". For locales whose
+     * grouping sizes vary with magnitude, see {@link #setSecondaryGroupingSize(int)}.
      *
      * @param groupingSize
      *            The primary grouping size.
@@ -761,8 +768,8 @@ public class DecimalFormatProperties implements Cloneable, Serializable {
     }
 
     /**
-     * Multiply all numbers by this power of ten before formatting. Negative multipliers reduce the magnitude and make
-     * numbers smaller (closer to zero).
+     * Multiply all numbers by this power of ten before formatting. Negative multipliers reduce the
+     * magnitude and make numbers smaller (closer to zero).
      *
      * @param magnitudeMultiplier
      *            The number of powers of ten to scale.
@@ -775,8 +782,8 @@ public class DecimalFormatProperties implements Cloneable, Serializable {
     }
 
     /**
-     * Sets the {@link MathContext} to be used during math and rounding operations. A MathContext encapsulates a
-     * RoundingMode and the number of significant digits in the output.
+     * Sets the {@link MathContext} to be used during math and rounding operations. A MathContext
+     * encapsulates a RoundingMode and the number of significant digits in the output.
      *
      * @param mathContext
      *            The math context to use when rounding is required.
@@ -790,11 +797,12 @@ public class DecimalFormatProperties implements Cloneable, Serializable {
     }
 
     /**
-     * Sets the maximum number of digits to display after the decimal point. If the number has fewer than this number of
-     * digits, the number will be rounded off using the rounding mode specified by
-     * {@link #setRoundingMode(RoundingMode)}. The pattern "#00.0#", for example, corresponds to 2 maximum fraction
-     * digits, and the number 456.789 would be formatted as "456.79" in locale <em>en-US</em> with the default rounding
-     * mode. Note that the number 456.999 would be formatted as "457.0" given the same configurations.
+     * Sets the maximum number of digits to display after the decimal point. If the number has fewer than
+     * this number of digits, the number will be rounded off using the rounding mode specified by
+     * {@link #setRoundingMode(RoundingMode)}. The pattern "#00.0#", for example, corresponds to 2
+     * maximum fraction digits, and the number 456.789 would be formatted as "456.79" in locale
+     * <em>en-US</em> with the default rounding mode. Note that the number 456.999 would be formatted as
+     * "457.0" given the same configurations.
      *
      * @param maximumFractionDigits
      *            The maximum number of fraction digits to output.
@@ -806,10 +814,11 @@ public class DecimalFormatProperties implements Cloneable, Serializable {
     }
 
     /**
-     * Sets the maximum number of digits to display before the decimal point. If the number has more than this number of
-     * digits, the extra digits will be truncated. For example, if maximum integer digits is 2, and you attempt to
-     * format the number 1970, you will get "70" in locale <em>en-US</em>. It is not possible to specify the maximum
-     * integer digits using a pattern string, except in the special case of a scientific format pattern.
+     * Sets the maximum number of digits to display before the decimal point. If the number has more than
+     * this number of digits, the extra digits will be truncated. For example, if maximum integer digits
+     * is 2, and you attempt to format the number 1970, you will get "70" in locale <em>en-US</em>. It is
+     * not possible to specify the maximum integer digits using a pattern string, except in the special
+     * case of a scientific format pattern.
      *
      * @param maximumIntegerDigits
      *            The maximum number of integer digits to output.
@@ -821,20 +830,21 @@ public class DecimalFormatProperties implements Cloneable, Serializable {
     }
 
     /**
-     * Sets the maximum number of significant digits to display. The number of significant digits is equal to the number
-     * of digits counted from the leftmost nonzero digit through the rightmost nonzero digit; for example, the number
-     * "2010" has 3 significant digits. If the number has more significant digits than specified here, the extra
-     * significant digits will be rounded off using the rounding mode specified by
-     * {@link #setRoundingMode(RoundingMode)}. For example, if maximum significant digits is 3, the number 1234.56 will
-     * be formatted as "1230" in locale <em>en-US</em> with the default rounding mode.
+     * Sets the maximum number of significant digits to display. The number of significant digits is
+     * equal to the number of digits counted from the leftmost nonzero digit through the rightmost
+     * nonzero digit; for example, the number "2010" has 3 significant digits. If the number has more
+     * significant digits than specified here, the extra significant digits will be rounded off using the
+     * rounding mode specified by {@link #setRoundingMode(RoundingMode)}. For example, if maximum
+     * significant digits is 3, the number 1234.56 will be formatted as "1230" in locale <em>en-US</em>
+     * with the default rounding mode.
      *
      * <p>
-     * If both maximum significant digits and maximum integer/fraction digits are set at the same time, the behavior is
-     * undefined.
+     * If both maximum significant digits and maximum integer/fraction digits are set at the same time,
+     * the behavior is undefined.
      *
      * <p>
-     * The number of significant digits can be specified in a pattern string using the '@' character. For example, the
-     * pattern "@@#" corresponds to a minimum of 2 and a maximum of 3 significant digits.
+     * The number of significant digits can be specified in a pattern string using the '@' character. For
+     * example, the pattern "@@#" corresponds to a minimum of 2 and a maximum of 3 significant digits.
      *
      * @param maximumSignificantDigits
      *            The maximum number of significant digits to display.
@@ -846,8 +856,9 @@ public class DecimalFormatProperties implements Cloneable, Serializable {
     }
 
     /**
-     * Sets the minimum number of digits to display in the exponent. For example, the number "1200" with the pattern
-     * "0.0E00", which has 2 exponent digits, would be formatted as "1.2E03" in <em>en-US</em>.
+     * Sets the minimum number of digits to display in the exponent. For example, the number "1200" with
+     * the pattern "0.0E00", which has 2 exponent digits, would be formatted as "1.2E03" in
+     * <em>en-US</em>.
      *
      * @param minimumExponentDigits
      *            The minimum number of digits to display in the exponent field.
@@ -859,9 +870,10 @@ public class DecimalFormatProperties implements Cloneable, Serializable {
     }
 
     /**
-     * Sets the minimum number of digits to display after the decimal point. If the number has fewer than this number of
-     * digits, the number will be padded with zeros. The pattern "#00.0#", for example, corresponds to 1 minimum
-     * fraction digit, and the number 456 would be formatted as "456.0" in locale <em>en-US</em>.
+     * Sets the minimum number of digits to display after the decimal point. If the number has fewer than
+     * this number of digits, the number will be padded with zeros. The pattern "#00.0#", for example,
+     * corresponds to 1 minimum fraction digit, and the number 456 would be formatted as "456.0" in
+     * locale <em>en-US</em>.
      *
      * @param minimumFractionDigits
      *            The minimum number of fraction digits to output.
@@ -873,10 +885,10 @@ public class DecimalFormatProperties implements Cloneable, Serializable {
     }
 
     /**
-     * Sets the minimum number of digits required to be beyond the first grouping separator in order to enable grouping.
-     * For example, if the minimum grouping digits is 2, then 1234 would be formatted as "1234" but 12345 would be
-     * formatted as "12,345" in <em>en-US</em>. Note that 1234567 would still be formatted as "1,234,567", not
-     * "1234,567".
+     * Sets the minimum number of digits required to be beyond the first grouping separator in order to
+     * enable grouping. For example, if the minimum grouping digits is 2, then 1234 would be formatted as
+     * "1234" but 12345 would be formatted as "12,345" in <em>en-US</em>. Note that 1234567 would still
+     * be formatted as "1,234,567", not "1234,567".
      *
      * @param minimumGroupingDigits
      *            How many digits must appear before a grouping separator before enabling grouping.
@@ -888,9 +900,10 @@ public class DecimalFormatProperties implements Cloneable, Serializable {
     }
 
     /**
-     * Sets the minimum number of digits to display before the decimal point. If the number has fewer than this number
-     * of digits, the number will be padded with zeros. The pattern "#00.0#", for example, corresponds to 2 minimum
-     * integer digits, and the number 5.3 would be formatted as "05.3" in locale <em>en-US</em>.
+     * Sets the minimum number of digits to display before the decimal point. If the number has fewer
+     * than this number of digits, the number will be padded with zeros. The pattern "#00.0#", for
+     * example, corresponds to 2 minimum integer digits, and the number 5.3 would be formatted as "05.3"
+     * in locale <em>en-US</em>.
      *
      * @param minimumIntegerDigits
      *            The minimum number of integer digits to output.
@@ -902,20 +915,22 @@ public class DecimalFormatProperties implements Cloneable, Serializable {
     }
 
     /**
-     * Sets the minimum number of significant digits to display. If, after rounding to the number of significant digits
-     * specified by {@link #setMaximumSignificantDigits}, the number of remaining significant digits is less than the
-     * minimum, the number will be padded with zeros. For example, if minimum significant digits is 3, the number 5.8
-     * will be formatted as "5.80" in locale <em>en-US</em>. Note that minimum significant digits is relevant only when
-     * numbers have digits after the decimal point.
+     * Sets the minimum number of significant digits to display. If, after rounding to the number of
+     * significant digits specified by {@link #setMaximumSignificantDigits}, the number of remaining
+     * significant digits is less than the minimum, the number will be padded with zeros. For example, if
+     * minimum significant digits is 3, the number 5.8 will be formatted as "5.80" in locale
+     * <em>en-US</em>. Note that minimum significant digits is relevant only when numbers have digits
+     * after the decimal point.
      *
      * <p>
-     * If both minimum significant digits and minimum integer/fraction digits are set at the same time, both values will
-     * be respected, and the one that results in the greater number of padding zeros will be used. For example,
-     * formatting the number 73 with 3 minimum significant digits and 2 minimum fraction digits will produce "73.00".
+     * If both minimum significant digits and minimum integer/fraction digits are set at the same time,
+     * both values will be respected, and the one that results in the greater number of padding zeros
+     * will be used. For example, formatting the number 73 with 3 minimum significant digits and 2
+     * minimum fraction digits will produce "73.00".
      *
      * <p>
-     * The number of significant digits can be specified in a pattern string using the '@' character. For example, the
-     * pattern "@@#" corresponds to a minimum of 2 and a maximum of 3 significant digits.
+     * The number of significant digits can be specified in a pattern string using the '@' character. For
+     * example, the pattern "@@#" corresponds to a minimum of 2 and a maximum of 3 significant digits.
      *
      * @param minimumSignificantDigits
      *            The minimum number of significant digits to display.
@@ -940,9 +955,10 @@ public class DecimalFormatProperties implements Cloneable, Serializable {
     }
 
     /**
-     * Sets the prefix to prepend to negative numbers. The prefix will be interpreted literally. For example, if you set
-     * a negative prefix of <code>n</code>, then the number -123 will be formatted as "n123" in the locale
-     * <em>en-US</em>. Note that if the negative prefix is left unset, the locale's minus sign is used.
+     * Sets the prefix to prepend to negative numbers. The prefix will be interpreted literally. For
+     * example, if you set a negative prefix of <code>n</code>, then the number -123 will be formatted as
+     * "n123" in the locale <em>en-US</em>. Note that if the negative prefix is left unset, the locale's
+     * minus sign is used.
      *
      * <p>
      * For more information on prefixes and suffixes, see {@link MutablePatternModifier}.
@@ -958,14 +974,15 @@ public class DecimalFormatProperties implements Cloneable, Serializable {
     }
 
     /**
-     * Sets the prefix to prepend to negative numbers. Locale-specific symbols will be substituted into the string
-     * according to Unicode Technical Standard #35 (LDML).
+     * Sets the prefix to prepend to negative numbers. Locale-specific symbols will be substituted into
+     * the string according to Unicode Technical Standard #35 (LDML).
      *
      * <p>
      * For more information on prefixes and suffixes, see {@link MutablePatternModifier}.
      *
      * @param negativePrefixPattern
-     *            The CharSequence to prepend to negative numbers after locale symbol substitutions take place.
+     *            The CharSequence to prepend to negative numbers after locale symbol substitutions take
+     *            place.
      * @return The property bag, for chaining.
      * @see #setNegativePrefix
      */
@@ -975,10 +992,11 @@ public class DecimalFormatProperties implements Cloneable, Serializable {
     }
 
     /**
-     * Sets the suffix to append to negative numbers. The suffix will be interpreted literally. For example, if you set
-     * a suffix prefix of <code>n</code>, then the number -123 will be formatted as "-123n" in the locale
-     * <em>en-US</em>. Note that the minus sign is prepended by default unless otherwise specified in either the pattern
-     * string or in one of the {@link #setNegativePrefix} methods.
+     * Sets the suffix to append to negative numbers. The suffix will be interpreted literally. For
+     * example, if you set a suffix prefix of <code>n</code>, then the number -123 will be formatted as
+     * "-123n" in the locale <em>en-US</em>. Note that the minus sign is prepended by default unless
+     * otherwise specified in either the pattern string or in one of the {@link #setNegativePrefix}
+     * methods.
      *
      * <p>
      * For more information on prefixes and suffixes, see {@link MutablePatternModifier}.
@@ -994,14 +1012,15 @@ public class DecimalFormatProperties implements Cloneable, Serializable {
     }
 
     /**
-     * Sets the suffix to append to negative numbers. Locale-specific symbols will be substituted into the string
-     * according to Unicode Technical Standard #35 (LDML).
+     * Sets the suffix to append to negative numbers. Locale-specific symbols will be substituted into
+     * the string according to Unicode Technical Standard #35 (LDML).
      *
      * <p>
      * For more information on prefixes and suffixes, see {@link MutablePatternModifier}.
      *
      * @param negativeSuffixPattern
-     *            The CharSequence to append to negative numbers after locale symbol substitutions take place.
+     *            The CharSequence to append to negative numbers after locale symbol substitutions take
+     *            place.
      * @return The property bag, for chaining.
      * @see #setNegativeSuffix
      */
@@ -1011,8 +1030,8 @@ public class DecimalFormatProperties implements Cloneable, Serializable {
     }
 
     /**
-     * Sets the location where the padding string is to be inserted to maintain the padding width: one of BEFORE_PREFIX,
-     * AFTER_PREFIX, BEFORE_SUFFIX, or AFTER_SUFFIX.
+     * Sets the location where the padding string is to be inserted to maintain the padding width: one of
+     * BEFORE_PREFIX, AFTER_PREFIX, BEFORE_SUFFIX, or AFTER_SUFFIX.
      *
      * <p>
      * Must be used in conjunction with {@link #setFormatWidth}.
@@ -1028,7 +1047,8 @@ public class DecimalFormatProperties implements Cloneable, Serializable {
     }
 
     /**
-     * Sets the string used for padding. The string should contain a single character or grapheme cluster.
+     * Sets the string used for padding. The string should contain a single character or grapheme
+     * cluster.
      *
      * <p>
      * Must be used in conjunction with {@link #setFormatWidth}.
@@ -1044,12 +1064,14 @@ public class DecimalFormatProperties implements Cloneable, Serializable {
     }
 
     /**
-     * Whether to require cases to match when parsing strings; default is true. Case sensitivity applies to prefixes,
-     * suffixes, the exponent separator, the symbol "NaN", and the infinity symbol. Grouping separators, decimal
-     * separators, and padding are always case-sensitive. Currencies are always case-insensitive.
+     * Whether to require cases to match when parsing strings; default is true. Case sensitivity applies
+     * to prefixes, suffixes, the exponent separator, the symbol "NaN", and the infinity symbol. Grouping
+     * separators, decimal separators, and padding are always case-sensitive. Currencies are always
+     * case-insensitive.
      *
      * <p>
-     * This setting is ignored in fast mode. In fast mode, strings are always compared in a case-sensitive way.
+     * This setting is ignored in fast mode. In fast mode, strings are always compared in a
+     * case-sensitive way.
      *
      * @param parseCaseSensitive
      *            true to be case-sensitive when parsing; false to allow any case.
@@ -1061,23 +1083,23 @@ public class DecimalFormatProperties implements Cloneable, Serializable {
     }
 
     /**
-     * Sets the strategy used during parsing when a code point needs to be interpreted as either a decimal separator or
-     * a grouping separator.
+     * Sets the strategy used during parsing when a code point needs to be interpreted as either a
+     * decimal separator or a grouping separator.
      *
      * <p>
-     * The comma, period, space, and apostrophe have different meanings in different locales. For example, in
-     * <em>en-US</em> and most American locales, the period is used as a decimal separator, but in <em>es-PY</em> and
-     * most European locales, it is used as a grouping separator.
+     * The comma, period, space, and apostrophe have different meanings in different locales. For
+     * example, in <em>en-US</em> and most American locales, the period is used as a decimal separator,
+     * but in <em>es-PY</em> and most European locales, it is used as a grouping separator.
      *
      * <p>
-     * Suppose you are in <em>fr-FR</em> the parser encounters the string "1.234". In <em>fr-FR</em>, the grouping is a
-     * space and the decimal is a comma. The <em>grouping mode</em> is a mechanism to let you specify whether to accept
-     * the string as 1234 (GroupingMode.DEFAULT) or whether to reject it since the separators don't match
-     * (GroupingMode.RESTRICTED).
+     * Suppose you are in <em>fr-FR</em> the parser encounters the string "1.234". In <em>fr-FR</em>, the
+     * grouping is a space and the decimal is a comma. The <em>grouping mode</em> is a mechanism to let
+     * you specify whether to accept the string as 1234 (GroupingMode.DEFAULT) or whether to reject it
+     * since the separators don't match (GroupingMode.RESTRICTED).
      *
      * <p>
-     * When resolving grouping separators, it is the <em>equivalence class</em> of separators that is considered. For
-     * example, a period is seen as equal to a fixed set of other period-like characters.
+     * When resolving grouping separators, it is the <em>equivalence class</em> of separators that is
+     * considered. For example, a period is seen as equal to a fixed set of other period-like characters.
      *
      * @param parseGroupingMode
      *            The {@link GroupingMode} to use; either DEFAULT or RESTRICTED.
@@ -1089,7 +1111,8 @@ public class DecimalFormatProperties implements Cloneable, Serializable {
     }
 
     /**
-     * Whether to ignore the fractional part of numbers. For example, parses "123.4" to "123" instead of "123.4".
+     * Whether to ignore the fractional part of numbers. For example, parses "123.4" to "123" instead of
+     * "123.4".
      *
      * @param parseIntegerOnly
      *            true to parse integers only; false to parse integers with their fraction parts
@@ -1101,8 +1124,8 @@ public class DecimalFormatProperties implements Cloneable, Serializable {
     }
 
     /**
-     * Controls certain rules for how strict this parser is when reading strings. See {@link ParseMode#LENIENT} and
-     * {@link ParseMode#STRICT}.
+     * Controls certain rules for how strict this parser is when reading strings. See
+     * {@link ParseMode#LENIENT} and {@link ParseMode#STRICT}.
      *
      * @param parseMode
      *            Either {@link ParseMode#LENIENT} or {@link ParseMode#STRICT}.
@@ -1114,7 +1137,8 @@ public class DecimalFormatProperties implements Cloneable, Serializable {
     }
 
     /**
-     * Whether to ignore the exponential part of numbers. For example, parses "123E4" to "123" instead of "1230000".
+     * Whether to ignore the exponential part of numbers. For example, parses "123E4" to "123" instead of
+     * "1230000".
      *
      * @param parseNoExponent
      *            true to ignore exponents; false to parse them.
@@ -1126,11 +1150,12 @@ public class DecimalFormatProperties implements Cloneable, Serializable {
     }
 
     /**
-     * Whether to always return a BigDecimal from {@link Parse#parse} and all other parse methods. By default, a Long or
-     * a BigInteger are returned when possible.
+     * Whether to always return a BigDecimal from {@link Parse#parse} and all other parse methods. By
+     * default, a Long or a BigInteger are returned when possible.
      *
      * @param parseToBigDecimal
-     *            true to always return a BigDecimal; false to return a Long or a BigInteger when possible.
+     *            true to always return a BigDecimal; false to return a Long or a BigInteger when
+     *            possible.
      * @return The property bag, for chaining.
      */
     public DecimalFormatProperties setParseToBigDecimal(boolean parseToBigDecimal) {
@@ -1151,9 +1176,9 @@ public class DecimalFormatProperties implements Cloneable, Serializable {
     }
 
     /**
-     * Sets the prefix to prepend to positive numbers. The prefix will be interpreted literally. For example, if you set
-     * a positive prefix of <code>p</code>, then the number 123 will be formatted as "p123" in the locale
-     * <em>en-US</em>.
+     * Sets the prefix to prepend to positive numbers. The prefix will be interpreted literally. For
+     * example, if you set a positive prefix of <code>p</code>, then the number 123 will be formatted as
+     * "p123" in the locale <em>en-US</em>.
      *
      * <p>
      * For more information on prefixes and suffixes, see {@link MutablePatternModifier}.
@@ -1169,14 +1194,15 @@ public class DecimalFormatProperties implements Cloneable, Serializable {
     }
 
     /**
-     * Sets the prefix to prepend to positive numbers. Locale-specific symbols will be substituted into the string
-     * according to Unicode Technical Standard #35 (LDML).
+     * Sets the prefix to prepend to positive numbers. Locale-specific symbols will be substituted into
+     * the string according to Unicode Technical Standard #35 (LDML).
      *
      * <p>
      * For more information on prefixes and suffixes, see {@link MutablePatternModifier}.
      *
      * @param positivePrefixPattern
-     *            The CharSequence to prepend to positive numbers after locale symbol substitutions take place.
+     *            The CharSequence to prepend to positive numbers after locale symbol substitutions take
+     *            place.
      * @return The property bag, for chaining.
      * @see #setPositivePrefix
      */
@@ -1186,9 +1212,9 @@ public class DecimalFormatProperties implements Cloneable, Serializable {
     }
 
     /**
-     * Sets the suffix to append to positive numbers. The suffix will be interpreted literally. For example, if you set
-     * a positive suffix of <code>p</code>, then the number 123 will be formatted as "123p" in the locale
-     * <em>en-US</em>.
+     * Sets the suffix to append to positive numbers. The suffix will be interpreted literally. For
+     * example, if you set a positive suffix of <code>p</code>, then the number 123 will be formatted as
+     * "123p" in the locale <em>en-US</em>.
      *
      * <p>
      * For more information on prefixes and suffixes, see {@link MutablePatternModifier}.
@@ -1204,14 +1230,15 @@ public class DecimalFormatProperties implements Cloneable, Serializable {
     }
 
     /**
-     * Sets the suffix to append to positive numbers. Locale-specific symbols will be substituted into the string
-     * according to Unicode Technical Standard #35 (LDML).
+     * Sets the suffix to append to positive numbers. Locale-specific symbols will be substituted into
+     * the string according to Unicode Technical Standard #35 (LDML).
      *
      * <p>
      * For more information on prefixes and suffixes, see {@link MutablePatternModifier}.
      *
      * @param positiveSuffixPattern
-     *            The CharSequence to append to positive numbers after locale symbol substitutions take place.
+     *            The CharSequence to append to positive numbers after locale symbol substitutions take
+     *            place.
      * @return The property bag, for chaining.
      * @see #setPositiveSuffix
      */
@@ -1221,15 +1248,16 @@ public class DecimalFormatProperties implements Cloneable, Serializable {
     }
 
     /**
-     * Sets the increment to which to round numbers. For example, with a rounding interval of 0.05, the number 11.17
-     * would be formatted as "11.15" in locale <em>en-US</em> with the default rounding mode.
+     * Sets the increment to which to round numbers. For example, with a rounding interval of 0.05, the
+     * number 11.17 would be formatted as "11.15" in locale <em>en-US</em> with the default rounding
+     * mode.
      *
      * <p>
      * You can use either a rounding increment or significant digits, but not both at the same time.
      *
      * <p>
-     * The rounding increment can be specified in a pattern string. For example, the pattern "#,##0.05" corresponds to a
-     * rounding interval of 0.05 with 1 minimum integer digit and a grouping size of 3.
+     * The rounding increment can be specified in a pattern string. For example, the pattern "#,##0.05"
+     * corresponds to a rounding interval of 0.05 with 1 minimum integer digit and a grouping size of 3.
      *
      * @param roundingIncrement
      *            The interval to which to round.
@@ -1241,9 +1269,9 @@ public class DecimalFormatProperties implements Cloneable, Serializable {
     }
 
     /**
-     * Sets the rounding mode, which determines under which conditions extra decimal places are rounded either up or
-     * down. See {@link RoundingMode} for details on the choices of rounding mode. The default if not set explicitly is
-     * {@link RoundingMode#HALF_EVEN}.
+     * Sets the rounding mode, which determines under which conditions extra decimal places are rounded
+     * either up or down. See {@link RoundingMode} for details on the choices of rounding mode. The
+     * default if not set explicitly is {@link RoundingMode#HALF_EVEN}.
      *
      * <p>
      * This setting is ignored if {@link #setMathContext} is used.
@@ -1260,13 +1288,13 @@ public class DecimalFormatProperties implements Cloneable, Serializable {
     }
 
     /**
-     * Sets the number of digits between grouping separators higher than the least-significant grouping separator. For
-     * example, the locale <em>hi</em> uses a primary grouping size of 3 and a secondary grouping size of 2, so the
-     * number 1234567 would be formatted as "12,34,567".
+     * Sets the number of digits between grouping separators higher than the least-significant grouping
+     * separator. For example, the locale <em>hi</em> uses a primary grouping size of 3 and a secondary
+     * grouping size of 2, so the number 1234567 would be formatted as "12,34,567".
      *
      * <p>
-     * The two levels of grouping separators can be specified in the pattern string. For example, the <em>hi</em>
-     * locale's default decimal format pattern is "#,##,##0.###".
+     * The two levels of grouping separators can be specified in the pattern string. For example, the
+     * <em>hi</em> locale's default decimal format pattern is "#,##,##0.###".
      *
      * @param secondaryGroupingSize
      *            The secondary grouping size.
@@ -1281,14 +1309,16 @@ public class DecimalFormatProperties implements Cloneable, Serializable {
      * Sets whether to always display of a plus sign on positive numbers.
      *
      * <p>
-     * If the location of the negative sign is specified by the decimal format pattern (or by the negative prefix/suffix
-     * pattern methods), a plus sign is substituted into that location, in accordance with Unicode Technical Standard
-     * #35 (LDML) section 3.2.1. Otherwise, the plus sign is prepended to the number. For example, if the decimal format
-     * pattern <code>#;#-</code> is used, then formatting 123 would result in "123+" in the locale <em>en-US</em>.
+     * If the location of the negative sign is specified by the decimal format pattern (or by the
+     * negative prefix/suffix pattern methods), a plus sign is substituted into that location, in
+     * accordance with Unicode Technical Standard #35 (LDML) section 3.2.1. Otherwise, the plus sign is
+     * prepended to the number. For example, if the decimal format pattern <code>#;#-</code> is used,
+     * then formatting 123 would result in "123+" in the locale <em>en-US</em>.
      *
      * <p>
-     * This method should be used <em>instead of</em> setting the positive prefix/suffix. The behavior is undefined if
-     * alwaysShowPlusSign is set but the positive prefix/suffix already contains a plus sign.
+     * This method should be used <em>instead of</em> setting the positive prefix/suffix. The behavior is
+     * undefined if alwaysShowPlusSign is set but the positive prefix/suffix already contains a plus
+     * sign.
      *
      * @param signAlwaysShown
      *            Whether positive numbers should display a plus sign.
@@ -1309,8 +1339,8 @@ public class DecimalFormatProperties implements Cloneable, Serializable {
     }
 
     /**
-     * Appends a string containing properties that differ from the default, but without being surrounded by
-     * &lt;Properties&gt;.
+     * Appends a string containing properties that differ from the default, but without being surrounded
+     * by &lt;Properties&gt;.
      */
     public void toStringBare(StringBuilder result) {
         Field[] fields = DecimalFormatProperties.class.getDeclaredFields();
@@ -1337,8 +1367,8 @@ public class DecimalFormatProperties implements Cloneable, Serializable {
     }
 
     /**
-     * Custom serialization: save fields along with their name, so that fields can be easily added in the future in any
-     * order. Only save fields that differ from their default value.
+     * Custom serialization: save fields along with their name, so that fields can be easily added in the
+     * future in any order. Only save fields that differ from their default value.
      */
     private void writeObject(ObjectOutputStream oos) throws IOException {
         writeObjectImpl(oos);
index 368dcfbec17409892adf1b3b4dfb9115b1abb6ad..4d34b38133f19401a8bc5d0d5f008f351cb25fef 100644 (file)
@@ -14,167 +14,183 @@ import com.ibm.icu.text.UFieldPosition;
  * An interface representing a number to be processed by the decimal formatting pipeline. Includes
  * methods for rounding, plural rules, and decimal digit extraction.
  *
- * <p>By design, this is NOT IMMUTABLE and NOT THREAD SAFE. It is intended to be an intermediate
- * object holding state during a pass through the decimal formatting pipeline.
+ * <p>
+ * By design, this is NOT IMMUTABLE and NOT THREAD SAFE. It is intended to be an intermediate object
+ * holding state during a pass through the decimal formatting pipeline.
  *
- * <p>Implementations of this interface are free to use any internal storage mechanism.
+ * <p>
+ * Implementations of this interface are free to use any internal storage mechanism.
  *
- * <p>TODO: Should I change this to an abstract class so that logic for min/max digits doesn't need
- * to be copied to every implementation?
+ * <p>
+ * TODO: Should I change this to an abstract class so that logic for min/max digits doesn't need to be
+ * copied to every implementation?
  */
 public interface DecimalQuantity extends PluralRules.IFixedDecimal {
-  /**
-   * Sets the minimum and maximum integer digits that this {@link DecimalQuantity} should generate.
-   * This method does not perform rounding.
-   *
-   * @param minInt The minimum number of integer digits.
-   * @param maxInt The maximum number of integer digits.
-   */
-  public void setIntegerLength(int minInt, int maxInt);
-
-  /**
-   * Sets the minimum and maximum fraction digits that this {@link DecimalQuantity} should generate.
-   * This method does not perform rounding.
-   *
-   * @param minFrac The minimum number of fraction digits.
-   * @param maxFrac The maximum number of fraction digits.
-   */
-  public void setFractionLength(int minFrac, int maxFrac);
-
-  /**
-   * Rounds the number to a specified interval, such as 0.05.
-   *
-   * <p>If rounding to a power of ten, use the more efficient {@link #roundToMagnitude} instead.
-   *
-   * @param roundingInterval The increment to which to round.
-   * @param mathContext The {@link MathContext} to use if rounding is necessary. Undefined behavior
-   *     if null.
-   */
-  public void roundToIncrement(BigDecimal roundingInterval, MathContext mathContext);
-
-  /**
-   * Rounds the number to a specified magnitude (power of ten).
-   *
-   * @param roundingMagnitude The power of ten to which to round. For example, a value of -2 will
-   *     round to 2 decimal places.
-   * @param mathContext The {@link MathContext} to use if rounding is necessary. Undefined behavior
-   *     if null.
-   */
-  public void roundToMagnitude(int roundingMagnitude, MathContext mathContext);
-
-  /**
-   * Rounds the number to an infinite number of decimal points. This has no effect except for
-   * forcing the double in {@link DecimalQuantity_AbstractBCD} to adopt its exact representation.
-   */
-  public void roundToInfinity();
-
-  /**
-   * Multiply the internal value.
-   *
-   * @param multiplicand The value by which to multiply.
-   */
-  public void multiplyBy(BigDecimal multiplicand);
-
-  /**
-   * Scales the number by a power of ten. For example, if the value is currently "1234.56", calling
-   * this method with delta=-3 will change the value to "1.23456".
-   *
-   * @param delta The number of magnitudes of ten to change by.
-   */
-  public void adjustMagnitude(int delta);
-
-  /**
-   * @return The power of ten corresponding to the most significant nonzero digit.
-   * @throws ArithmeticException If the value represented is zero.
-   */
-  public int getMagnitude() throws ArithmeticException;
-
-  /** @return Whether the value represented by this {@link DecimalQuantity} is zero. */
-  public boolean isZero();
-
-  /** @return Whether the value represented by this {@link DecimalQuantity} is less than zero. */
-  public boolean isNegative();
-
-  /** @return Whether the value represented by this {@link DecimalQuantity} is infinite. */
-  @Override
-  public boolean isInfinite();
-
-  /** @return Whether the value represented by this {@link DecimalQuantity} is not a number. */
-  @Override
-  public boolean isNaN();
-
-  /** @return The value contained in this {@link DecimalQuantity} approximated as a double. */
-  public double toDouble();
-
-  public BigDecimal toBigDecimal();
-
-  public void setToBigDecimal(BigDecimal input);
-
-  public int maxRepresentableDigits();
-
-  // TODO: Should this method be removed, since DecimalQuantity implements IFixedDecimal now?
-  /**
-   * Computes the plural form for this number based on the specified set of rules.
-   *
-   * @param rules A {@link PluralRules} object representing the set of rules.
-   * @return The {@link StandardPlural} according to the PluralRules. If the plural form is not in
-   *     the set of standard plurals, {@link StandardPlural#OTHER} is returned instead.
-   */
-  public StandardPlural getStandardPlural(PluralRules rules);
-
-  /**
-   * Gets the digit at the specified magnitude. For example, if the represented number is 12.3,
-   * getDigit(-1) returns 3, since 3 is the digit corresponding to 10^-1.
-   *
-   * @param magnitude The magnitude of the digit.
-   * @return The digit at the specified magnitude.
-   */
-  public byte getDigit(int magnitude);
-
-  /**
-   * Gets the largest power of ten that needs to be displayed. The value returned by this function
-   * will be bounded between minInt and maxInt.
-   *
-   * @return The highest-magnitude digit to be displayed.
-   */
-  public int getUpperDisplayMagnitude();
-
-  /**
-   * Gets the smallest power of ten that needs to be displayed. The value returned by this function
-   * will be bounded between -minFrac and -maxFrac.
-   *
-   * @return The lowest-magnitude digit to be displayed.
-   */
-  public int getLowerDisplayMagnitude();
-
-  /**
-   * Returns the string in "plain" format (no exponential notation) using ASCII digits.
-   */
-  public String toPlainString();
-
-  /**
-   * Like clone, but without the restrictions of the Cloneable interface clone.
-   *
-   * @return A copy of this instance which can be mutated without affecting this instance.
-   */
-  public DecimalQuantity createCopy();
-
-  /**
-   * Sets this instance to be equal to another instance.
-   *
-   * @param other The instance to copy from.
-   */
-  public void copyFrom(DecimalQuantity other);
-
-  /** This method is for internal testing only. */
-  public long getPositionFingerprint();
-
-  /**
-   * If the given {@link FieldPosition} is a {@link UFieldPosition}, populates it with the fraction
-   * length and fraction long value. If the argument is not a {@link UFieldPosition}, nothing
-   * happens.
-   *
-   * @param fp The {@link UFieldPosition} to populate.
-   */
-  public void populateUFieldPosition(FieldPosition fp);
+    /**
+     * Sets the minimum and maximum integer digits that this {@link DecimalQuantity} should generate.
+     * This method does not perform rounding.
+     *
+     * @param minInt
+     *            The minimum number of integer digits.
+     * @param maxInt
+     *            The maximum number of integer digits.
+     */
+    public void setIntegerLength(int minInt, int maxInt);
+
+    /**
+     * Sets the minimum and maximum fraction digits that this {@link DecimalQuantity} should generate.
+     * This method does not perform rounding.
+     *
+     * @param minFrac
+     *            The minimum number of fraction digits.
+     * @param maxFrac
+     *            The maximum number of fraction digits.
+     */
+    public void setFractionLength(int minFrac, int maxFrac);
+
+    /**
+     * Rounds the number to a specified interval, such as 0.05.
+     *
+     * <p>
+     * If rounding to a power of ten, use the more efficient {@link #roundToMagnitude} instead.
+     *
+     * @param roundingInterval
+     *            The increment to which to round.
+     * @param mathContext
+     *            The {@link MathContext} to use if rounding is necessary. Undefined behavior if null.
+     */
+    public void roundToIncrement(BigDecimal roundingInterval, MathContext mathContext);
+
+    /**
+     * Rounds the number to a specified magnitude (power of ten).
+     *
+     * @param roundingMagnitude
+     *            The power of ten to which to round. For example, a value of -2 will round to 2 decimal
+     *            places.
+     * @param mathContext
+     *            The {@link MathContext} to use if rounding is necessary. Undefined behavior if null.
+     */
+    public void roundToMagnitude(int roundingMagnitude, MathContext mathContext);
+
+    /**
+     * Rounds the number to an infinite number of decimal points. This has no effect except for forcing
+     * the double in {@link DecimalQuantity_AbstractBCD} to adopt its exact representation.
+     */
+    public void roundToInfinity();
+
+    /**
+     * Multiply the internal value.
+     *
+     * @param multiplicand
+     *            The value by which to multiply.
+     */
+    public void multiplyBy(BigDecimal multiplicand);
+
+    /**
+     * Scales the number by a power of ten. For example, if the value is currently "1234.56", calling
+     * this method with delta=-3 will change the value to "1.23456".
+     *
+     * @param delta
+     *            The number of magnitudes of ten to change by.
+     */
+    public void adjustMagnitude(int delta);
+
+    /**
+     * @return The power of ten corresponding to the most significant nonzero digit.
+     * @throws ArithmeticException
+     *             If the value represented is zero.
+     */
+    public int getMagnitude() throws ArithmeticException;
+
+    /** @return Whether the value represented by this {@link DecimalQuantity} is zero. */
+    public boolean isZero();
+
+    /** @return Whether the value represented by this {@link DecimalQuantity} is less than zero. */
+    public boolean isNegative();
+
+    /** @return Whether the value represented by this {@link DecimalQuantity} is infinite. */
+    @Override
+    public boolean isInfinite();
+
+    /** @return Whether the value represented by this {@link DecimalQuantity} is not a number. */
+    @Override
+    public boolean isNaN();
+
+    /** @return The value contained in this {@link DecimalQuantity} approximated as a double. */
+    public double toDouble();
+
+    public BigDecimal toBigDecimal();
+
+    public void setToBigDecimal(BigDecimal input);
+
+    public int maxRepresentableDigits();
+
+    // TODO: Should this method be removed, since DecimalQuantity implements IFixedDecimal now?
+    /**
+     * Computes the plural form for this number based on the specified set of rules.
+     *
+     * @param rules
+     *            A {@link PluralRules} object representing the set of rules.
+     * @return The {@link StandardPlural} according to the PluralRules. If the plural form is not in the
+     *         set of standard plurals, {@link StandardPlural#OTHER} is returned instead.
+     */
+    public StandardPlural getStandardPlural(PluralRules rules);
+
+    /**
+     * Gets the digit at the specified magnitude. For example, if the represented number is 12.3,
+     * getDigit(-1) returns 3, since 3 is the digit corresponding to 10^-1.
+     *
+     * @param magnitude
+     *            The magnitude of the digit.
+     * @return The digit at the specified magnitude.
+     */
+    public byte getDigit(int magnitude);
+
+    /**
+     * Gets the largest power of ten that needs to be displayed. The value returned by this function will
+     * be bounded between minInt and maxInt.
+     *
+     * @return The highest-magnitude digit to be displayed.
+     */
+    public int getUpperDisplayMagnitude();
+
+    /**
+     * Gets the smallest power of ten that needs to be displayed. The value returned by this function
+     * will be bounded between -minFrac and -maxFrac.
+     *
+     * @return The lowest-magnitude digit to be displayed.
+     */
+    public int getLowerDisplayMagnitude();
+
+    /**
+     * Returns the string in "plain" format (no exponential notation) using ASCII digits.
+     */
+    public String toPlainString();
+
+    /**
+     * Like clone, but without the restrictions of the Cloneable interface clone.
+     *
+     * @return A copy of this instance which can be mutated without affecting this instance.
+     */
+    public DecimalQuantity createCopy();
+
+    /**
+     * Sets this instance to be equal to another instance.
+     *
+     * @param other
+     *            The instance to copy from.
+     */
+    public void copyFrom(DecimalQuantity other);
+
+    /** This method is for internal testing only. */
+    public long getPositionFingerprint();
+
+    /**
+     * If the given {@link FieldPosition} is a {@link UFieldPosition}, populates it with the fraction
+     * length and fraction long value. If the argument is not a {@link UFieldPosition}, nothing happens.
+     *
+     * @param fp
+     *            The {@link UFieldPosition} to populate.
+     */
+    public void populateUFieldPosition(FieldPosition fp);
 }
index b442cf1f3ee5b03f278ab9e12075136e9711ac0d..a242d7eac00729b60ff94d81234b4d483115fb61 100644 (file)
@@ -19,911 +19,957 @@ import com.ibm.icu.text.UFieldPosition;
  */
 public abstract class DecimalQuantity_AbstractBCD implements DecimalQuantity {
 
-  /**
-   * The power of ten corresponding to the least significant digit in the BCD. For example, if this
-   * object represents the number "3.14", the BCD will be "0x314" and the scale will be -2.
-   *
-   * <p>Note that in {@link java.math.BigDecimal}, the scale is defined differently: the number of
-   * digits after the decimal place, which is the negative of our definition of scale.
-   */
-  protected int scale;
-
-  /**
-   * The number of digits in the BCD. For example, "1007" has BCD "0x1007" and precision 4. The
-   * maximum precision is 16 since a long can hold only 16 digits.
-   *
-   * <p>This value must be re-calculated whenever the value in bcd changes by using {@link
-   * #computePrecisionAndCompact()}.
-   */
-  protected int precision;
-
-  /**
-   * A bitmask of properties relating to the number represented by this object.
-   *
-   * @see #NEGATIVE_FLAG
-   * @see #INFINITY_FLAG
-   * @see #NAN_FLAG
-   */
-  protected byte flags;
-
-  protected static final int NEGATIVE_FLAG = 1;
-  protected static final int INFINITY_FLAG = 2;
-  protected static final int NAN_FLAG = 4;
-
-  // The following three fields relate to the double-to-ascii fast path algorithm.
-  // When a double is given to DecimalQuantityBCD, it is converted to using a fast algorithm. The
-  // fast algorithm guarantees correctness to only the first ~12 digits of the double. The process
-  // of rounding the number ensures that the converted digits are correct, falling back to a slow-
-  // path algorithm if required.  Therefore, if a DecimalQuantity is constructed from a double, it
-  // is *required* that roundToMagnitude(), roundToIncrement(), or roundToInfinity() is called. If
-  // you don't round, assertions will fail in certain other methods if you try calling them.
-
-  /**
-   * The original number provided by the user and which is represented in BCD. Used when we need to
-   * re-compute the BCD for an exact double representation.
-   */
-  protected double origDouble;
-
-  /**
-   * The change in magnitude relative to the original double. Used when we need to re-compute the
-   * BCD for an exact double representation.
-   */
-  protected int origDelta;
-
-  /**
-   * Whether the value in the BCD comes from the double fast path without having been rounded to
-   * ensure correctness
-   */
-  protected boolean isApproximate;
-
-  // Four positions: left optional '(', left required '[', right required ']', right optional ')'.
-  // These four positions determine which digits are displayed in the output string.  They do NOT
-  // affect rounding.  These positions are internal-only and can be specified only by the public
-  // endpoints like setFractionLength, setIntegerLength, and setSignificantDigits, among others.
-  //
-  //   * Digits between lReqPos and rReqPos are in the "required zone" and are always displayed.
-  //   * Digits between lOptPos and rOptPos but outside the required zone are in the "optional zone"
-  //     and are displayed unless they are trailing off the left or right edge of the number and
-  //     have a numerical value of zero.  In order to be "trailing", the digits need to be beyond
-  //     the decimal point in their respective directions.
-  //   * Digits outside of the "optional zone" are never displayed.
-  //
-  // See the table below for illustrative examples.
-  //
-  // +---------+---------+---------+---------+------------+------------------------+--------------+
-  // | lOptPos | lReqPos | rReqPos | rOptPos |   number   |        positions       | en-US string |
-  // +---------+---------+---------+---------+------------+------------------------+--------------+
-  // |    5    |    2    |   -1    |   -5    |   1234.567 |     ( 12[34.5]67  )    |   1,234.567  |
-  // |    3    |    2    |   -1    |   -5    |   1234.567 |      1(2[34.5]67  )    |     234.567  |
-  // |    3    |    2    |   -1    |   -2    |   1234.567 |      1(2[34.5]6)7      |     234.56   |
-  // |    6    |    4    |    2    |   -5    | 123456789. |  123(45[67]89.     )   | 456,789.     |
-  // |    6    |    4    |    2    |    1    | 123456789. |     123(45[67]8)9.     | 456,780.     |
-  // |   -1    |   -1    |   -3    |   -4    | 0.123456   |     0.1([23]4)56       |        .0234 |
-  // |    6    |    4    |   -2    |   -2    |     12.3   |     (  [  12.3 ])      |    0012.30   |
-  // +---------+---------+---------+---------+------------+------------------------+--------------+
-  //
-  protected int lOptPos = Integer.MAX_VALUE;
-  protected int lReqPos = 0;
-  protected int rReqPos = 0;
-  protected int rOptPos = Integer.MIN_VALUE;
-
-  @Override
-  public void copyFrom(DecimalQuantity _other) {
-    copyBcdFrom(_other);
-    DecimalQuantity_AbstractBCD other = (DecimalQuantity_AbstractBCD) _other;
-    lOptPos = other.lOptPos;
-    lReqPos = other.lReqPos;
-    rReqPos = other.rReqPos;
-    rOptPos = other.rOptPos;
-    scale = other.scale;
-    precision = other.precision;
-    flags = other.flags;
-    origDouble = other.origDouble;
-    origDelta = other.origDelta;
-    isApproximate = other.isApproximate;
-  }
-
-  public DecimalQuantity_AbstractBCD clear() {
-    lOptPos = Integer.MAX_VALUE;
-    lReqPos = 0;
-    rReqPos = 0;
-    rOptPos = Integer.MIN_VALUE;
-    flags = 0;
-    setBcdToZero(); // sets scale, precision, hasDouble, origDouble, origDelta, and BCD data
-    return this;
-  }
-
-  @Override
-  public void setIntegerLength(int minInt, int maxInt) {
-    // Validation should happen outside of DecimalQuantity, e.g., in the Rounder class.
-    assert minInt >= 0;
-    assert maxInt >= minInt;
-
-    // Save values into internal state
-    // Negation is safe for minFrac/maxFrac because -Integer.MAX_VALUE > Integer.MIN_VALUE
-    lOptPos = maxInt;
-    lReqPos = minInt;
-  }
-
-  @Override
-  public void setFractionLength(int minFrac, int maxFrac) {
-    // Validation should happen outside of DecimalQuantity, e.g., in the Rounder class.
-    assert minFrac >= 0;
-    assert maxFrac >= minFrac;
-
-    // Save values into internal state
-    // Negation is safe for minFrac/maxFrac because -Integer.MAX_VALUE > Integer.MIN_VALUE
-    rReqPos = -minFrac;
-    rOptPos = -maxFrac;
-  }
-
-  @Override
-  public long getPositionFingerprint() {
-    long fingerprint = 0;
-    fingerprint ^= lOptPos;
-    fingerprint ^= (lReqPos << 16);
-    fingerprint ^= ((long) rReqPos << 32);
-    fingerprint ^= ((long) rOptPos << 48);
-    return fingerprint;
-  }
-
-  @Override
-  public void roundToIncrement(BigDecimal roundingIncrement, MathContext mathContext) {
-    // TODO: Avoid converting back and forth to BigDecimal.
-    BigDecimal temp = toBigDecimal();
-    temp =
-        temp.divide(roundingIncrement, 0, mathContext.getRoundingMode())
-            .multiply(roundingIncrement)
-            .round(mathContext);
-    if (temp.signum() == 0) {
-      setBcdToZero(); // keeps negative flag for -0.0
-    } else {
-      setToBigDecimal(temp);
-    }
-  }
-
-  @Override
-  public void multiplyBy(BigDecimal multiplicand) {
-    if (isInfinite() || isZero() || isNaN()) {
-      return;
-    }
-    BigDecimal temp = toBigDecimal();
-    temp = temp.multiply(multiplicand);
-    setToBigDecimal(temp);
-  }
-
-  @Override
-  public int getMagnitude() throws ArithmeticException {
-    if (precision == 0) {
-      throw new ArithmeticException("Magnitude is not well-defined for zero");
-    } else {
-      return scale + precision - 1;
-    }
-  }
-
-  @Override
-  public void adjustMagnitude(int delta) {
-    if (precision != 0) {
-      scale += delta;
-      origDelta += delta;
-    }
-  }
-
-  @Override
-  public StandardPlural getStandardPlural(PluralRules rules) {
-    if (rules == null) {
-      // Fail gracefully if the user didn't provide a PluralRules
-      return StandardPlural.OTHER;
-    } else {
-      @SuppressWarnings("deprecation")
-      String ruleString = rules.select(this);
-      return StandardPlural.orOtherFromString(ruleString);
-    }
-  }
-
-  @Override
-  public double getPluralOperand(Operand operand) {
-    // If this assertion fails, you need to call roundToInfinity() or some other rounding method.
-    // See the comment at the top of this file explaining the "isApproximate" field.
-    assert !isApproximate;
-
-    switch (operand) {
-      case i:
-        return toLong();
-      case f:
-        return toFractionLong(true);
-      case t:
-        return toFractionLong(false);
-      case v:
-        return fractionCount();
-      case w:
-        return fractionCountWithoutTrailingZeros();
-      default:
-        return Math.abs(toDouble());
-    }
-  }
-
-  @Override
-  public void populateUFieldPosition(FieldPosition fp) {
-    if (fp instanceof UFieldPosition) {
-      ((UFieldPosition) fp)
-          .setFractionDigits((int) getPluralOperand(Operand.v), (long) getPluralOperand(Operand.f));
-    }
-  }
-
-  @Override
-  public int getUpperDisplayMagnitude() {
-    // If this assertion fails, you need to call roundToInfinity() or some other rounding method.
-    // See the comment at the top of this file explaining the "isApproximate" field.
-    assert !isApproximate;
-
-    int magnitude = scale + precision;
-    int result = (lReqPos > magnitude) ? lReqPos : (lOptPos < magnitude) ? lOptPos : magnitude;
-    return result - 1;
-  }
-
-  @Override
-  public int getLowerDisplayMagnitude() {
-    // If this assertion fails, you need to call roundToInfinity() or some other rounding method.
-    // See the comment at the top of this file explaining the "isApproximate" field.
-    assert !isApproximate;
-
-    int magnitude = scale;
-    int result = (rReqPos < magnitude) ? rReqPos : (rOptPos > magnitude) ? rOptPos : magnitude;
-    return result;
-  }
-
-  @Override
-  public byte getDigit(int magnitude) {
-    // If this assertion fails, you need to call roundToInfinity() or some other rounding method.
-    // See the comment at the top of this file explaining the "isApproximate" field.
-    assert !isApproximate;
-
-    return getDigitPos(magnitude - scale);
-  }
-
-  private int fractionCount() {
-    return -getLowerDisplayMagnitude();
-  }
-
-  private int fractionCountWithoutTrailingZeros() {
-    return Math.max(-scale, 0);
-  }
-
-  @Override
-  public boolean isNegative() {
-    return (flags & NEGATIVE_FLAG) != 0;
-  }
-
-  @Override
-  public boolean isInfinite() {
-    return (flags & INFINITY_FLAG) != 0;
-  }
-
-  @Override
-  public boolean isNaN() {
-    return (flags & NAN_FLAG) != 0;
-  }
-
-  @Override
-  public boolean isZero() {
-    return precision == 0;
-  }
-
-  public void setToInt(int n) {
-    setBcdToZero();
-    flags = 0;
-    if (n < 0) {
-      flags |= NEGATIVE_FLAG;
-      n = -n;
-    }
-    if (n != 0) {
-      _setToInt(n);
-      compact();
-    }
-  }
-
-  private void _setToInt(int n) {
-    if (n == Integer.MIN_VALUE) {
-      readLongToBcd(-(long) n);
-    } else {
-      readIntToBcd(n);
-    }
-  }
-
-  public void setToLong(long n) {
-    setBcdToZero();
-    flags = 0;
-    if (n < 0) {
-      flags |= NEGATIVE_FLAG;
-      n = -n;
-    }
-    if (n != 0) {
-      _setToLong(n);
-      compact();
-    }
-  }
-
-  private void _setToLong(long n) {
-    if (n == Long.MIN_VALUE) {
-      readBigIntegerToBcd(BigInteger.valueOf(n).negate());
-    } else if (n <= Integer.MAX_VALUE) {
-      readIntToBcd((int) n);
-    } else {
-      readLongToBcd(n);
-    }
-  }
-
-  public void setToBigInteger(BigInteger n) {
-    setBcdToZero();
-    flags = 0;
-    if (n.signum() == -1) {
-      flags |= NEGATIVE_FLAG;
-      n = n.negate();
-    }
-    if (n.signum() != 0) {
-      _setToBigInteger(n);
-      compact();
-    }
-  }
-
-  private void _setToBigInteger(BigInteger n) {
-    if (n.bitLength() < 32) {
-      readIntToBcd(n.intValue());
-    } else if (n.bitLength() < 64) {
-      readLongToBcd(n.longValue());
-    } else {
-      readBigIntegerToBcd(n);
-    }
-  }
-
-  /**
-   * Sets the internal BCD state to represent the value in the given double.
-   *
-   * @param n The value to consume.
-   */
-  public void setToDouble(double n) {
-    setBcdToZero();
-    flags = 0;
-    // Double.compare() handles +0.0 vs -0.0
-    if (Double.compare(n, 0.0) < 0) {
-      flags |= NEGATIVE_FLAG;
-      n = -n;
-    }
-    if (Double.isNaN(n)) {
-      flags |= NAN_FLAG;
-    } else if (Double.isInfinite(n)) {
-      flags |= INFINITY_FLAG;
-    } else if (n != 0) {
-      _setToDoubleFast(n);
-      compact();
-    }
-  }
-
-  private static final double[] DOUBLE_MULTIPLIERS = {
-    1e0, 1e1, 1e2, 1e3, 1e4, 1e5, 1e6, 1e7, 1e8, 1e9, 1e10, 1e11, 1e12, 1e13, 1e14, 1e15, 1e16,
-    1e17, 1e18, 1e19, 1e20, 1e21
-  };
-
-  /**
-   * Uses double multiplication and division to get the number into integer space before converting
-   * to digits. Since double arithmetic is inexact, the resulting digits may not be accurate.
-   */
-  private void _setToDoubleFast(double n) {
-    isApproximate = true;
-    origDouble = n;
-    origDelta = 0;
-
-    // NOTE: Unlike ICU4C, doubles are always IEEE 754 doubles.
-    long ieeeBits = Double.doubleToLongBits(n);
-    int exponent = (int) ((ieeeBits & 0x7ff0000000000000L) >> 52) - 0x3ff;
-
-    // Not all integers can be represented exactly for exponent > 52
-    if (exponent <= 52 && (long) n == n) {
-      _setToLong((long) n);
-      return;
-    }
-
-    // 3.3219... is log2(10)
-    int fracLength = (int) ((52 - exponent) / 3.32192809489);
-    if (fracLength >= 0) {
-      int i = fracLength;
-      // 1e22 is the largest exact double.
-      for (; i >= 22; i -= 22) n *= 1e22;
-      n *= DOUBLE_MULTIPLIERS[i];
-    } else {
-      int i = fracLength;
-      // 1e22 is the largest exact double.
-      for (; i <= -22; i += 22) n /= 1e22;
-      n /= DOUBLE_MULTIPLIERS[-i];
-    }
-    long result = Math.round(n);
-    if (result != 0) {
-      _setToLong(result);
-      scale -= fracLength;
-    }
-  }
-
-  /**
-   * Uses Double.toString() to obtain an exact accurate representation of the double, overwriting it
-   * into the BCD. This method can be called at any point after {@link #_setToDoubleFast} while
-   * {@link #isApproximate} is still true.
-   */
-  private void convertToAccurateDouble() {
-    double n = origDouble;
-    assert n != 0;
-    int delta = origDelta;
-    setBcdToZero();
-
-    // Call the slow oracle function (Double.toString in Java, sprintf in C++).
-    String dstr = Double.toString(n);
-
-    if (dstr.indexOf('E') != -1) {
-      // Case 1: Exponential notation.
-      assert dstr.indexOf('.') == 1;
-      int expPos = dstr.indexOf('E');
-      _setToLong(Long.parseLong(dstr.charAt(0) + dstr.substring(2, expPos)));
-      scale += Integer.parseInt(dstr.substring(expPos + 1)) - (expPos - 1) + 1;
-    } else if (dstr.charAt(0) == '0') {
-      // Case 2: Fraction-only number.
-      assert dstr.indexOf('.') == 1;
-      _setToLong(Long.parseLong(dstr.substring(2)));
-      scale += 2 - dstr.length();
-    } else if (dstr.charAt(dstr.length() - 1) == '0') {
-      // Case 3: Integer-only number.
-      // Note: this path should not normally happen, because integer-only numbers are captured
-      // before the approximate double logic is performed.
-      assert dstr.indexOf('.') == dstr.length() - 2;
-      assert dstr.length() - 2 <= 18;
-      _setToLong(Long.parseLong(dstr.substring(0, dstr.length() - 2)));
-      // no need to adjust scale
-    } else {
-      // Case 4: Number with both a fraction and an integer.
-      int decimalPos = dstr.indexOf('.');
-      _setToLong(Long.parseLong(dstr.substring(0, decimalPos) + dstr.substring(decimalPos + 1)));
-      scale += decimalPos - dstr.length() + 1;
-    }
-
-    scale += delta;
-    compact();
-    explicitExactDouble = true;
-  }
-
-  /**
-   * Whether this {@link DecimalQuantity_DualStorageBCD} has been explicitly converted to an exact double. true if
-   * backed by a double that was explicitly converted via convertToAccurateDouble; false otherwise.
-   * Used for testing.
-   *
-   * @internal
-   * @deprecated This API is ICU internal only.
-   */
-  @Deprecated public boolean explicitExactDouble = false;
-
-  /**
-   * Sets the internal BCD state to represent the value in the given BigDecimal.
-   *
-   * @param n The value to consume.
-   */
-  @Override
-  public void setToBigDecimal(BigDecimal n) {
-    setBcdToZero();
-    flags = 0;
-    if (n.signum() == -1) {
-      flags |= NEGATIVE_FLAG;
-      n = n.negate();
-    }
-    if (n.signum() != 0) {
-      _setToBigDecimal(n);
-      compact();
-    }
-  }
-
-  private void _setToBigDecimal(BigDecimal n) {
-    int fracLength = n.scale();
-    n = n.scaleByPowerOfTen(fracLength);
-    BigInteger bi = n.toBigInteger();
-    _setToBigInteger(bi);
-    scale -= fracLength;
-  }
-
-  /**
-   * Returns a long approximating the internal BCD. A long can only represent the integral part of
-   * the number.
-   *
-   * @return A double representation of the internal BCD.
-   */
-  protected long toLong() {
-    long result = 0L;
-    for (int magnitude = scale + precision - 1; magnitude >= 0; magnitude--) {
-      result = result * 10 + getDigitPos(magnitude - scale);
-    }
-    return result;
-  }
-
-  /**
-   * This returns a long representing the fraction digits of the number, as required by PluralRules.
-   * For example, if we represent the number "1.20" (including optional and required digits), then
-   * this function returns "20" if includeTrailingZeros is true or "2" if false.
-   */
-  protected long toFractionLong(boolean includeTrailingZeros) {
-    long result = 0L;
-    int magnitude = -1;
-    for (;
-        (magnitude >= scale || (includeTrailingZeros && magnitude >= rReqPos))
-            && magnitude >= rOptPos;
-        magnitude--) {
-      result = result * 10 + getDigitPos(magnitude - scale);
-    }
-    return result;
-  }
-
-  /**
-   * Returns a double approximating the internal BCD. The double may not retain all of the
-   * information encoded in the BCD if the BCD represents a number out of range of a double.
-   *
-   * @return A double representation of the internal BCD.
-   */
-  @Override
-  public double toDouble() {
-    if (isApproximate) {
-      return toDoubleFromOriginal();
-    }
-
-    if (isNaN()) {
-      return Double.NaN;
-    } else if (isInfinite()) {
-      return isNegative() ? Double.NEGATIVE_INFINITY : Double.POSITIVE_INFINITY;
-    }
-
-    long tempLong = 0L;
-    int lostDigits = precision - Math.min(precision, 17);
-    for (int shift = precision - 1; shift >= lostDigits; shift--) {
-      tempLong = tempLong * 10 + getDigitPos(shift);
-    }
-    double result = tempLong;
-    int _scale = scale + lostDigits;
-    if (_scale >= 0) {
-      // 1e22 is the largest exact double.
-      int i = _scale;
-      for (; i >= 22; i -= 22) result *= 1e22;
-      result *= DOUBLE_MULTIPLIERS[i];
-    } else {
-      // 1e22 is the largest exact double.
-      int i = _scale;
-      for (; i <= -22; i += 22) result /= 1e22;
-      result /= DOUBLE_MULTIPLIERS[-i];
-    }
-    if (isNegative()) result = -result;
-    return result;
-  }
-
-  @Override
-  public BigDecimal toBigDecimal() {
-    if (isApproximate) {
-      // Converting to a BigDecimal requires Double.toString().
-      convertToAccurateDouble();
-    }
-    return bcdToBigDecimal();
-  }
-
-  protected double toDoubleFromOriginal() {
-    double result = origDouble;
-    int delta = origDelta;
-    if (delta >= 0) {
-      // 1e22 is the largest exact double.
-      for (; delta >= 22; delta -= 22) result *= 1e22;
-      result *= DOUBLE_MULTIPLIERS[delta];
-    } else {
-      // 1e22 is the largest exact double.
-      for (; delta <= -22; delta += 22) result /= 1e22;
-      result /= DOUBLE_MULTIPLIERS[-delta];
-    }
-    if (isNegative()) result *= -1;
-    return result;
-  }
-
-  private static int safeSubtract(int a, int b) {
-    int diff = a - b;
-    if (b < 0 && diff < a) return Integer.MAX_VALUE;
-    if (b > 0 && diff > a) return Integer.MIN_VALUE;
-    return diff;
-  }
-
-  private static final int SECTION_LOWER_EDGE = -1;
-  private static final int SECTION_UPPER_EDGE = -2;
-
-  @Override
-  public void roundToMagnitude(int magnitude, MathContext mathContext) {
-    // The position in the BCD at which rounding will be performed; digits to the right of position
-    // will be rounded away.
-    // TODO: Andy: There was a test failure because of integer overflow here. Should I do
-    // "safe subtraction" everywhere in the code?  What's the nicest way to do it?
-    int position = safeSubtract(magnitude, scale);
-
-    // Enforce the number of digits required by the MathContext.
-    int _mcPrecision = mathContext.getPrecision();
-    if (magnitude == Integer.MAX_VALUE
-        || (_mcPrecision > 0 && precision - position > _mcPrecision)) {
-      position = precision - _mcPrecision;
-    }
-
-    if (position <= 0 && !isApproximate) {
-      // All digits are to the left of the rounding magnitude.
-    } else if (precision == 0) {
-      // No rounding for zero.
-    } else {
-      // Perform rounding logic.
-      // "leading" = most significant digit to the right of rounding
-      // "trailing" = least significant digit to the left of rounding
-      byte leadingDigit = getDigitPos(safeSubtract(position, 1));
-      byte trailingDigit = getDigitPos(position);
-
-      // Compute which section of the number we are in.
-      // EDGE means we are at the bottom or top edge, like 1.000 or 1.999 (used by doubles)
-      // LOWER means we are between the bottom edge and the midpoint, like 1.391
-      // MIDPOINT means we are exactly in the middle, like 1.500
-      // UPPER means we are between the midpoint and the top edge, like 1.916
-      int section = RoundingUtils.SECTION_MIDPOINT;
-      if (!isApproximate) {
-        if (leadingDigit < 5) {
-          section = RoundingUtils.SECTION_LOWER;
-        } else if (leadingDigit > 5) {
-          section = RoundingUtils.SECTION_UPPER;
+    /**
+     * The power of ten corresponding to the least significant digit in the BCD. For example, if this
+     * object represents the number "3.14", the BCD will be "0x314" and the scale will be -2.
+     *
+     * <p>
+     * Note that in {@link java.math.BigDecimal}, the scale is defined differently: the number of digits
+     * after the decimal place, which is the negative of our definition of scale.
+     */
+    protected int scale;
+
+    /**
+     * The number of digits in the BCD. For example, "1007" has BCD "0x1007" and precision 4. The maximum
+     * precision is 16 since a long can hold only 16 digits.
+     *
+     * <p>
+     * This value must be re-calculated whenever the value in bcd changes by using
+     * {@link #computePrecisionAndCompact()}.
+     */
+    protected int precision;
+
+    /**
+     * A bitmask of properties relating to the number represented by this object.
+     *
+     * @see #NEGATIVE_FLAG
+     * @see #INFINITY_FLAG
+     * @see #NAN_FLAG
+     */
+    protected byte flags;
+
+    protected static final int NEGATIVE_FLAG = 1;
+    protected static final int INFINITY_FLAG = 2;
+    protected static final int NAN_FLAG = 4;
+
+    // The following three fields relate to the double-to-ascii fast path algorithm.
+    // When a double is given to DecimalQuantityBCD, it is converted to using a fast algorithm. The
+    // fast algorithm guarantees correctness to only the first ~12 digits of the double. The process
+    // of rounding the number ensures that the converted digits are correct, falling back to a slow-
+    // path algorithm if required. Therefore, if a DecimalQuantity is constructed from a double, it
+    // is *required* that roundToMagnitude(), roundToIncrement(), or roundToInfinity() is called. If
+    // you don't round, assertions will fail in certain other methods if you try calling them.
+
+    /**
+     * The original number provided by the user and which is represented in BCD. Used when we need to
+     * re-compute the BCD for an exact double representation.
+     */
+    protected double origDouble;
+
+    /**
+     * The change in magnitude relative to the original double. Used when we need to re-compute the BCD
+     * for an exact double representation.
+     */
+    protected int origDelta;
+
+    /**
+     * Whether the value in the BCD comes from the double fast path without having been rounded to ensure
+     * correctness
+     */
+    protected boolean isApproximate;
+
+    // Four positions: left optional '(', left required '[', right required ']', right optional ')'.
+    // These four positions determine which digits are displayed in the output string. They do NOT
+    // affect rounding. These positions are internal-only and can be specified only by the public
+    // endpoints like setFractionLength, setIntegerLength, and setSignificantDigits, among others.
+    //
+    // * Digits between lReqPos and rReqPos are in the "required zone" and are always displayed.
+    // * Digits between lOptPos and rOptPos but outside the required zone are in the "optional zone"
+    // and are displayed unless they are trailing off the left or right edge of the number and
+    // have a numerical value of zero. In order to be "trailing", the digits need to be beyond
+    // the decimal point in their respective directions.
+    // * Digits outside of the "optional zone" are never displayed.
+    //
+    // See the table below for illustrative examples.
+    //
+    // +---------+---------+---------+---------+------------+------------------------+--------------+
+    // | lOptPos | lReqPos | rReqPos | rOptPos |   number   |        positions       | en-US string |
+    // +---------+---------+---------+---------+------------+------------------------+--------------+
+    // |    5    |    2    |   -1    |   -5    |   1234.567 |     ( 12[34.5]67  )    |   1,234.567  |
+    // |    3    |    2    |   -1    |   -5    |   1234.567 |      1(2[34.5]67  )    |     234.567  |
+    // |    3    |    2    |   -1    |   -2    |   1234.567 |      1(2[34.5]6)7      |     234.56   |
+    // |    6    |    4    |    2    |   -5    | 123456789. |  123(45[67]89.     )   | 456,789.     |
+    // |    6    |    4    |    2    |    1    | 123456789. |     123(45[67]8)9.     | 456,780.     |
+    // |   -1    |   -1    |   -3    |   -4    | 0.123456   |     0.1([23]4)56       |        .0234 |
+    // |    6    |    4    |   -2    |   -2    |     12.3   |     (  [  12.3 ])      |    0012.30   |
+    // +---------+---------+---------+---------+------------+------------------------+--------------+
+    //
+    protected int lOptPos = Integer.MAX_VALUE;
+    protected int lReqPos = 0;
+    protected int rReqPos = 0;
+    protected int rOptPos = Integer.MIN_VALUE;
+
+    @Override
+    public void copyFrom(DecimalQuantity _other) {
+        copyBcdFrom(_other);
+        DecimalQuantity_AbstractBCD other = (DecimalQuantity_AbstractBCD) _other;
+        lOptPos = other.lOptPos;
+        lReqPos = other.lReqPos;
+        rReqPos = other.rReqPos;
+        rOptPos = other.rOptPos;
+        scale = other.scale;
+        precision = other.precision;
+        flags = other.flags;
+        origDouble = other.origDouble;
+        origDelta = other.origDelta;
+        isApproximate = other.isApproximate;
+    }
+
+    public DecimalQuantity_AbstractBCD clear() {
+        lOptPos = Integer.MAX_VALUE;
+        lReqPos = 0;
+        rReqPos = 0;
+        rOptPos = Integer.MIN_VALUE;
+        flags = 0;
+        setBcdToZero(); // sets scale, precision, hasDouble, origDouble, origDelta, and BCD data
+        return this;
+    }
+
+    @Override
+    public void setIntegerLength(int minInt, int maxInt) {
+        // Validation should happen outside of DecimalQuantity, e.g., in the Rounder class.
+        assert minInt >= 0;
+        assert maxInt >= minInt;
+
+        // Save values into internal state
+        // Negation is safe for minFrac/maxFrac because -Integer.MAX_VALUE > Integer.MIN_VALUE
+        lOptPos = maxInt;
+        lReqPos = minInt;
+    }
+
+    @Override
+    public void setFractionLength(int minFrac, int maxFrac) {
+        // Validation should happen outside of DecimalQuantity, e.g., in the Rounder class.
+        assert minFrac >= 0;
+        assert maxFrac >= minFrac;
+
+        // Save values into internal state
+        // Negation is safe for minFrac/maxFrac because -Integer.MAX_VALUE > Integer.MIN_VALUE
+        rReqPos = -minFrac;
+        rOptPos = -maxFrac;
+    }
+
+    @Override
+    public long getPositionFingerprint() {
+        long fingerprint = 0;
+        fingerprint ^= lOptPos;
+        fingerprint ^= (lReqPos << 16);
+        fingerprint ^= ((long) rReqPos << 32);
+        fingerprint ^= ((long) rOptPos << 48);
+        return fingerprint;
+    }
+
+    @Override
+    public void roundToIncrement(BigDecimal roundingIncrement, MathContext mathContext) {
+        // TODO: Avoid converting back and forth to BigDecimal.
+        BigDecimal temp = toBigDecimal();
+        temp = temp.divide(roundingIncrement, 0, mathContext.getRoundingMode())
+                .multiply(roundingIncrement).round(mathContext);
+        if (temp.signum() == 0) {
+            setBcdToZero(); // keeps negative flag for -0.0
         } else {
-          for (int p = safeSubtract(position, 2); p >= 0; p--) {
-            if (getDigitPos(p) != 0) {
-              section = RoundingUtils.SECTION_UPPER;
-              break;
-            }
-          }
-        }
-      } else {
-        int p = safeSubtract(position, 2);
-        int minP = Math.max(0, precision - 14);
-        if (leadingDigit == 0) {
-          section = SECTION_LOWER_EDGE;
-          for (; p >= minP; p--) {
-            if (getDigitPos(p) != 0) {
-              section = RoundingUtils.SECTION_LOWER;
-              break;
-            }
-          }
-        } else if (leadingDigit == 4) {
-          for (; p >= minP; p--) {
-            if (getDigitPos(p) != 9) {
-              section = RoundingUtils.SECTION_LOWER;
-              break;
-            }
-          }
-        } else if (leadingDigit == 5) {
-          for (; p >= minP; p--) {
-            if (getDigitPos(p) != 0) {
-              section = RoundingUtils.SECTION_UPPER;
-              break;
-            }
-          }
-        } else if (leadingDigit == 9) {
-          section = SECTION_UPPER_EDGE;
-          for (; p >= minP; p--) {
-            if (getDigitPos(p) != 9) {
-              section = RoundingUtils.SECTION_UPPER;
-              break;
-            }
-          }
-        } else if (leadingDigit < 5) {
-          section = RoundingUtils.SECTION_LOWER;
+            setToBigDecimal(temp);
+        }
+    }
+
+    @Override
+    public void multiplyBy(BigDecimal multiplicand) {
+        if (isInfinite() || isZero() || isNaN()) {
+            return;
+        }
+        BigDecimal temp = toBigDecimal();
+        temp = temp.multiply(multiplicand);
+        setToBigDecimal(temp);
+    }
+
+    @Override
+    public int getMagnitude() throws ArithmeticException {
+        if (precision == 0) {
+            throw new ArithmeticException("Magnitude is not well-defined for zero");
+        } else {
+            return scale + precision - 1;
+        }
+    }
+
+    @Override
+    public void adjustMagnitude(int delta) {
+        if (precision != 0) {
+            scale += delta;
+            origDelta += delta;
+        }
+    }
+
+    @Override
+    public StandardPlural getStandardPlural(PluralRules rules) {
+        if (rules == null) {
+            // Fail gracefully if the user didn't provide a PluralRules
+            return StandardPlural.OTHER;
+        } else {
+            @SuppressWarnings("deprecation")
+            String ruleString = rules.select(this);
+            return StandardPlural.orOtherFromString(ruleString);
+        }
+    }
+
+    @Override
+    public double getPluralOperand(Operand operand) {
+        // If this assertion fails, you need to call roundToInfinity() or some other rounding method.
+        // See the comment at the top of this file explaining the "isApproximate" field.
+        assert !isApproximate;
+
+        switch (operand) {
+        case i:
+            return toLong();
+        case f:
+            return toFractionLong(true);
+        case t:
+            return toFractionLong(false);
+        case v:
+            return fractionCount();
+        case w:
+            return fractionCountWithoutTrailingZeros();
+        default:
+            return Math.abs(toDouble());
+        }
+    }
+
+    @Override
+    public void populateUFieldPosition(FieldPosition fp) {
+        if (fp instanceof UFieldPosition) {
+            ((UFieldPosition) fp).setFractionDigits((int) getPluralOperand(Operand.v),
+                    (long) getPluralOperand(Operand.f));
+        }
+    }
+
+    @Override
+    public int getUpperDisplayMagnitude() {
+        // If this assertion fails, you need to call roundToInfinity() or some other rounding method.
+        // See the comment at the top of this file explaining the "isApproximate" field.
+        assert !isApproximate;
+
+        int magnitude = scale + precision;
+        int result = (lReqPos > magnitude) ? lReqPos : (lOptPos < magnitude) ? lOptPos : magnitude;
+        return result - 1;
+    }
+
+    @Override
+    public int getLowerDisplayMagnitude() {
+        // If this assertion fails, you need to call roundToInfinity() or some other rounding method.
+        // See the comment at the top of this file explaining the "isApproximate" field.
+        assert !isApproximate;
+
+        int magnitude = scale;
+        int result = (rReqPos < magnitude) ? rReqPos : (rOptPos > magnitude) ? rOptPos : magnitude;
+        return result;
+    }
+
+    @Override
+    public byte getDigit(int magnitude) {
+        // If this assertion fails, you need to call roundToInfinity() or some other rounding method.
+        // See the comment at the top of this file explaining the "isApproximate" field.
+        assert !isApproximate;
+
+        return getDigitPos(magnitude - scale);
+    }
+
+    private int fractionCount() {
+        return -getLowerDisplayMagnitude();
+    }
+
+    private int fractionCountWithoutTrailingZeros() {
+        return Math.max(-scale, 0);
+    }
+
+    @Override
+    public boolean isNegative() {
+        return (flags & NEGATIVE_FLAG) != 0;
+    }
+
+    @Override
+    public boolean isInfinite() {
+        return (flags & INFINITY_FLAG) != 0;
+    }
+
+    @Override
+    public boolean isNaN() {
+        return (flags & NAN_FLAG) != 0;
+    }
+
+    @Override
+    public boolean isZero() {
+        return precision == 0;
+    }
+
+    public void setToInt(int n) {
+        setBcdToZero();
+        flags = 0;
+        if (n < 0) {
+            flags |= NEGATIVE_FLAG;
+            n = -n;
+        }
+        if (n != 0) {
+            _setToInt(n);
+            compact();
+        }
+    }
+
+    private void _setToInt(int n) {
+        if (n == Integer.MIN_VALUE) {
+            readLongToBcd(-(long) n);
+        } else {
+            readIntToBcd(n);
+        }
+    }
+
+    public void setToLong(long n) {
+        setBcdToZero();
+        flags = 0;
+        if (n < 0) {
+            flags |= NEGATIVE_FLAG;
+            n = -n;
+        }
+        if (n != 0) {
+            _setToLong(n);
+            compact();
+        }
+    }
+
+    private void _setToLong(long n) {
+        if (n == Long.MIN_VALUE) {
+            readBigIntegerToBcd(BigInteger.valueOf(n).negate());
+        } else if (n <= Integer.MAX_VALUE) {
+            readIntToBcd((int) n);
+        } else {
+            readLongToBcd(n);
+        }
+    }
+
+    public void setToBigInteger(BigInteger n) {
+        setBcdToZero();
+        flags = 0;
+        if (n.signum() == -1) {
+            flags |= NEGATIVE_FLAG;
+            n = n.negate();
+        }
+        if (n.signum() != 0) {
+            _setToBigInteger(n);
+            compact();
+        }
+    }
+
+    private void _setToBigInteger(BigInteger n) {
+        if (n.bitLength() < 32) {
+            readIntToBcd(n.intValue());
+        } else if (n.bitLength() < 64) {
+            readLongToBcd(n.longValue());
         } else {
-          section = RoundingUtils.SECTION_UPPER;
+            readBigIntegerToBcd(n);
         }
+    }
 
-        boolean roundsAtMidpoint =
-            RoundingUtils.roundsAtMidpoint(mathContext.getRoundingMode().ordinal());
-        if (safeSubtract(position, 1) < precision - 14
-            || (roundsAtMidpoint && section == RoundingUtils.SECTION_MIDPOINT)
-            || (!roundsAtMidpoint && section < 0 /* i.e. at upper or lower edge */)) {
-          // Oops! This means that we have to get the exact representation of the double, because
-          // the zone of uncertainty is along the rounding boundary.
-          convertToAccurateDouble();
-          roundToMagnitude(magnitude, mathContext); // start over
-          return;
+    /**
+     * Sets the internal BCD state to represent the value in the given double.
+     *
+     * @param n
+     *            The value to consume.
+     */
+    public void setToDouble(double n) {
+        setBcdToZero();
+        flags = 0;
+        // Double.compare() handles +0.0 vs -0.0
+        if (Double.compare(n, 0.0) < 0) {
+            flags |= NEGATIVE_FLAG;
+            n = -n;
+        }
+        if (Double.isNaN(n)) {
+            flags |= NAN_FLAG;
+        } else if (Double.isInfinite(n)) {
+            flags |= INFINITY_FLAG;
+        } else if (n != 0) {
+            _setToDoubleFast(n);
+            compact();
         }
+    }
 
-        // Turn off the approximate double flag, since the value is now confirmed to be exact.
-        isApproximate = false;
-        origDouble = 0.0;
+    private static final double[] DOUBLE_MULTIPLIERS = {
+            1e0,
+            1e1,
+            1e2,
+            1e3,
+            1e4,
+            1e5,
+            1e6,
+            1e7,
+            1e8,
+            1e9,
+            1e10,
+            1e11,
+            1e12,
+            1e13,
+            1e14,
+            1e15,
+            1e16,
+            1e17,
+            1e18,
+            1e19,
+            1e20,
+            1e21 };
+
+    /**
+     * Uses double multiplication and division to get the number into integer space before converting to
+     * digits. Since double arithmetic is inexact, the resulting digits may not be accurate.
+     */
+    private void _setToDoubleFast(double n) {
+        isApproximate = true;
+        origDouble = n;
         origDelta = 0;
 
-        if (position <= 0) {
-          // All digits are to the left of the rounding magnitude.
-          return;
+        // NOTE: Unlike ICU4C, doubles are always IEEE 754 doubles.
+        long ieeeBits = Double.doubleToLongBits(n);
+        int exponent = (int) ((ieeeBits & 0x7ff0000000000000L) >> 52) - 0x3ff;
+
+        // Not all integers can be represented exactly for exponent > 52
+        if (exponent <= 52 && (long) n == n) {
+            _setToLong((long) n);
+            return;
         }
 
-        // Good to continue rounding.
-        if (section == SECTION_LOWER_EDGE) section = RoundingUtils.SECTION_LOWER;
-        if (section == SECTION_UPPER_EDGE) section = RoundingUtils.SECTION_UPPER;
-      }
+        // 3.3219... is log2(10)
+        int fracLength = (int) ((52 - exponent) / 3.32192809489);
+        if (fracLength >= 0) {
+            int i = fracLength;
+            // 1e22 is the largest exact double.
+            for (; i >= 22; i -= 22)
+                n *= 1e22;
+            n *= DOUBLE_MULTIPLIERS[i];
+        } else {
+            int i = fracLength;
+            // 1e22 is the largest exact double.
+            for (; i <= -22; i += 22)
+                n /= 1e22;
+            n /= DOUBLE_MULTIPLIERS[-i];
+        }
+        long result = Math.round(n);
+        if (result != 0) {
+            _setToLong(result);
+            scale -= fracLength;
+        }
+    }
 
-      boolean roundDown =
-          RoundingUtils.getRoundingDirection(
-              (trailingDigit % 2) == 0,
-              isNegative(),
-              section,
-              mathContext.getRoundingMode().ordinal(),
-              this);
+    /**
+     * Uses Double.toString() to obtain an exact accurate representation of the double, overwriting it
+     * into the BCD. This method can be called at any point after {@link #_setToDoubleFast} while
+     * {@link #isApproximate} is still true.
+     */
+    private void convertToAccurateDouble() {
+        double n = origDouble;
+        assert n != 0;
+        int delta = origDelta;
+        setBcdToZero();
 
-      // Perform truncation
-      if (position >= precision) {
+        // Call the slow oracle function (Double.toString in Java, sprintf in C++).
+        String dstr = Double.toString(n);
+
+        if (dstr.indexOf('E') != -1) {
+            // Case 1: Exponential notation.
+            assert dstr.indexOf('.') == 1;
+            int expPos = dstr.indexOf('E');
+            _setToLong(Long.parseLong(dstr.charAt(0) + dstr.substring(2, expPos)));
+            scale += Integer.parseInt(dstr.substring(expPos + 1)) - (expPos - 1) + 1;
+        } else if (dstr.charAt(0) == '0') {
+            // Case 2: Fraction-only number.
+            assert dstr.indexOf('.') == 1;
+            _setToLong(Long.parseLong(dstr.substring(2)));
+            scale += 2 - dstr.length();
+        } else if (dstr.charAt(dstr.length() - 1) == '0') {
+            // Case 3: Integer-only number.
+            // Note: this path should not normally happen, because integer-only numbers are captured
+            // before the approximate double logic is performed.
+            assert dstr.indexOf('.') == dstr.length() - 2;
+            assert dstr.length() - 2 <= 18;
+            _setToLong(Long.parseLong(dstr.substring(0, dstr.length() - 2)));
+            // no need to adjust scale
+        } else {
+            // Case 4: Number with both a fraction and an integer.
+            int decimalPos = dstr.indexOf('.');
+            _setToLong(Long.parseLong(dstr.substring(0, decimalPos) + dstr.substring(decimalPos + 1)));
+            scale += decimalPos - dstr.length() + 1;
+        }
+
+        scale += delta;
+        compact();
+        explicitExactDouble = true;
+    }
+
+    /**
+     * Whether this {@link DecimalQuantity_DualStorageBCD} has been explicitly converted to an exact
+     * double. true if backed by a double that was explicitly converted via convertToAccurateDouble;
+     * false otherwise. Used for testing.
+     *
+     * @internal
+     * @deprecated This API is ICU internal only.
+     */
+    @Deprecated
+    public boolean explicitExactDouble = false;
+
+    /**
+     * Sets the internal BCD state to represent the value in the given BigDecimal.
+     *
+     * @param n
+     *            The value to consume.
+     */
+    @Override
+    public void setToBigDecimal(BigDecimal n) {
         setBcdToZero();
-        scale = magnitude;
-      } else {
-        shiftRight(position);
-      }
-
-      // Bubble the result to the higher digits
-      if (!roundDown) {
-        if (trailingDigit == 9) {
-          int bubblePos = 0;
-          // Note: in the long implementation, the most digits BCD can have at this point is 15,
-          // so bubblePos <= 15 and getDigitPos(bubblePos) is safe.
-          for (; getDigitPos(bubblePos) == 9; bubblePos++) {}
-          shiftRight(bubblePos); // shift off the trailing 9s
-        }
-        byte digit0 = getDigitPos(0);
-        assert digit0 != 9;
-        setDigitPos(0, (byte) (digit0 + 1));
-        precision += 1; // in case an extra digit got added
-      }
-
-      compact();
-    }
-  }
-
-  @Override
-  public void roundToInfinity() {
-    if (isApproximate) {
-      convertToAccurateDouble();
-    }
-  }
-
-  /**
-   * Appends a digit, optionally with one or more leading zeros, to the end of the value represented
-   * by this DecimalQuantity.
-   *
-   * <p>The primary use of this method is to construct numbers during a parsing loop. It allows
-   * parsing to take advantage of the digit list infrastructure primarily designed for formatting.
-   *
-   * @param value The digit to append.
-   * @param leadingZeros The number of zeros to append before the digit. For example, if the value
-   *     in this instance starts as 12.3, and you append a 4 with 1 leading zero, the value becomes
-   *     12.304.
-   * @param appendAsInteger If true, increase the magnitude of existing digits to make room for the
-   *     new digit. If false, append to the end like a fraction digit. If true, there must not be
-   *     any fraction digits already in the number.
-   * @internal
-   * @deprecated This API is ICU internal only.
-   */
-  @Deprecated
-  public void appendDigit(byte value, int leadingZeros, boolean appendAsInteger) {
-    assert leadingZeros >= 0;
-
-    // Zero requires special handling to maintain the invariant that the least-significant digit
-    // in the BCD is nonzero.
-    if (value == 0) {
-      if (appendAsInteger && precision != 0) {
-        scale += leadingZeros + 1;
-      }
-      return;
-    }
-
-    // Deal with trailing zeros
-    if (scale > 0) {
-      leadingZeros += scale;
-      if (appendAsInteger) {
-        scale = 0;
-      }
-    }
-
-    // Append digit
-    shiftLeft(leadingZeros + 1);
-    setDigitPos(0, value);
-
-    // Fix scale if in integer mode
-    if (appendAsInteger) {
-      scale += leadingZeros + 1;
-    }
-  }
-
-  @Override
-  public String toPlainString() {
-      // NOTE: This logic is duplicated between here and DecimalQuantity_SimpleStorage.
-      StringBuilder sb = new StringBuilder();
-      if (isNegative()) {
-          sb.append('-');
-      }
-      for (int m = getUpperDisplayMagnitude(); m >= getLowerDisplayMagnitude(); m--) {
-        sb.append(getDigit(m));
-        if (m == 0) sb.append('.');
-      }
-      return sb.toString();
-  }
-
-  /**
-   * Returns a single digit from the BCD list. No internal state is changed by calling this method.
-   *
-   * @param position The position of the digit to pop, counted in BCD units from the least
-   *     significant digit. If outside the range supported by the implementation, zero is returned.
-   * @return The digit at the specified location.
-   */
-  protected abstract byte getDigitPos(int position);
-
-  /**
-   * Sets the digit in the BCD list. This method only sets the digit; it is the caller's
-   * responsibility to call {@link #compact} after setting the digit.
-   *
-   * @param position The position of the digit to pop, counted in BCD units from the least
-   *     significant digit. If outside the range supported by the implementation, an AssertionError
-   *     is thrown.
-   * @param value The digit to set at the specified location.
-   */
-  protected abstract void setDigitPos(int position, byte value);
-
-  /**
-   * Adds zeros to the end of the BCD list. This will result in an invalid BCD representation; it is
-   * the caller's responsibility to do further manipulation and then call {@link #compact}.
-   *
-   * @param numDigits The number of zeros to add.
-   */
-  protected abstract void shiftLeft(int numDigits);
-
-  protected abstract void shiftRight(int numDigits);
-
-  /**
-   * Sets the internal representation to zero. Clears any values stored in scale, precision,
-   * hasDouble, origDouble, origDelta, and BCD data.
-   */
-  protected abstract void setBcdToZero();
-
-  /**
-   * Sets the internal BCD state to represent the value in the given int. The int is guaranteed to
-   * be either positive. The internal state is guaranteed to be empty when this method is called.
-   *
-   * @param n The value to consume.
-   */
-  protected abstract void readIntToBcd(int input);
-
-  /**
-   * Sets the internal BCD state to represent the value in the given long. The long is guaranteed to
-   * be either positive. The internal state is guaranteed to be empty when this method is called.
-   *
-   * @param n The value to consume.
-   */
-  protected abstract void readLongToBcd(long input);
-
-  /**
-   * Sets the internal BCD state to represent the value in the given BigInteger. The BigInteger is
-   * guaranteed to be positive, and it is guaranteed to be larger than Long.MAX_VALUE. The internal
-   * state is guaranteed to be empty when this method is called.
-   *
-   * @param n The value to consume.
-   */
-  protected abstract void readBigIntegerToBcd(BigInteger input);
-
-  /**
-   * Returns a BigDecimal encoding the internal BCD value.
-   *
-   * @return A BigDecimal representation of the internal BCD.
-   */
-  protected abstract BigDecimal bcdToBigDecimal();
-
-  protected abstract void copyBcdFrom(DecimalQuantity _other);
-
-  /**
-   * Removes trailing zeros from the BCD (adjusting the scale as required) and then computes the
-   * precision. The precision is the number of digits in the number up through the greatest nonzero
-   * digit.
-   *
-   * <p>This method must always be called when bcd changes in order for assumptions to be correct in
-   * methods like {@link #fractionCount()}.
-   */
-  protected abstract void compact();
+        flags = 0;
+        if (n.signum() == -1) {
+            flags |= NEGATIVE_FLAG;
+            n = n.negate();
+        }
+        if (n.signum() != 0) {
+            _setToBigDecimal(n);
+            compact();
+        }
+    }
+
+    private void _setToBigDecimal(BigDecimal n) {
+        int fracLength = n.scale();
+        n = n.scaleByPowerOfTen(fracLength);
+        BigInteger bi = n.toBigInteger();
+        _setToBigInteger(bi);
+        scale -= fracLength;
+    }
+
+    /**
+     * Returns a long approximating the internal BCD. A long can only represent the integral part of the
+     * number.
+     *
+     * @return A double representation of the internal BCD.
+     */
+    protected long toLong() {
+        long result = 0L;
+        for (int magnitude = scale + precision - 1; magnitude >= 0; magnitude--) {
+            result = result * 10 + getDigitPos(magnitude - scale);
+        }
+        return result;
+    }
+
+    /**
+     * This returns a long representing the fraction digits of the number, as required by PluralRules.
+     * For example, if we represent the number "1.20" (including optional and required digits), then this
+     * function returns "20" if includeTrailingZeros is true or "2" if false.
+     */
+    protected long toFractionLong(boolean includeTrailingZeros) {
+        long result = 0L;
+        int magnitude = -1;
+        for (; (magnitude >= scale || (includeTrailingZeros && magnitude >= rReqPos))
+                && magnitude >= rOptPos; magnitude--) {
+            result = result * 10 + getDigitPos(magnitude - scale);
+        }
+        return result;
+    }
+
+    /**
+     * Returns a double approximating the internal BCD. The double may not retain all of the information
+     * encoded in the BCD if the BCD represents a number out of range of a double.
+     *
+     * @return A double representation of the internal BCD.
+     */
+    @Override
+    public double toDouble() {
+        if (isApproximate) {
+            return toDoubleFromOriginal();
+        }
+
+        if (isNaN()) {
+            return Double.NaN;
+        } else if (isInfinite()) {
+            return isNegative() ? Double.NEGATIVE_INFINITY : Double.POSITIVE_INFINITY;
+        }
+
+        long tempLong = 0L;
+        int lostDigits = precision - Math.min(precision, 17);
+        for (int shift = precision - 1; shift >= lostDigits; shift--) {
+            tempLong = tempLong * 10 + getDigitPos(shift);
+        }
+        double result = tempLong;
+        int _scale = scale + lostDigits;
+        if (_scale >= 0) {
+            // 1e22 is the largest exact double.
+            int i = _scale;
+            for (; i >= 22; i -= 22)
+                result *= 1e22;
+            result *= DOUBLE_MULTIPLIERS[i];
+        } else {
+            // 1e22 is the largest exact double.
+            int i = _scale;
+            for (; i <= -22; i += 22)
+                result /= 1e22;
+            result /= DOUBLE_MULTIPLIERS[-i];
+        }
+        if (isNegative())
+            result = -result;
+        return result;
+    }
+
+    @Override
+    public BigDecimal toBigDecimal() {
+        if (isApproximate) {
+            // Converting to a BigDecimal requires Double.toString().
+            convertToAccurateDouble();
+        }
+        return bcdToBigDecimal();
+    }
+
+    protected double toDoubleFromOriginal() {
+        double result = origDouble;
+        int delta = origDelta;
+        if (delta >= 0) {
+            // 1e22 is the largest exact double.
+            for (; delta >= 22; delta -= 22)
+                result *= 1e22;
+            result *= DOUBLE_MULTIPLIERS[delta];
+        } else {
+            // 1e22 is the largest exact double.
+            for (; delta <= -22; delta += 22)
+                result /= 1e22;
+            result /= DOUBLE_MULTIPLIERS[-delta];
+        }
+        if (isNegative())
+            result *= -1;
+        return result;
+    }
+
+    private static int safeSubtract(int a, int b) {
+        int diff = a - b;
+        if (b < 0 && diff < a)
+            return Integer.MAX_VALUE;
+        if (b > 0 && diff > a)
+            return Integer.MIN_VALUE;
+        return diff;
+    }
+
+    private static final int SECTION_LOWER_EDGE = -1;
+    private static final int SECTION_UPPER_EDGE = -2;
+
+    @Override
+    public void roundToMagnitude(int magnitude, MathContext mathContext) {
+        // The position in the BCD at which rounding will be performed; digits to the right of position
+        // will be rounded away.
+        // TODO: Andy: There was a test failure because of integer overflow here. Should I do
+        // "safe subtraction" everywhere in the code? What's the nicest way to do it?
+        int position = safeSubtract(magnitude, scale);
+
+        // Enforce the number of digits required by the MathContext.
+        int _mcPrecision = mathContext.getPrecision();
+        if (magnitude == Integer.MAX_VALUE
+                || (_mcPrecision > 0 && precision - position > _mcPrecision)) {
+            position = precision - _mcPrecision;
+        }
+
+        if (position <= 0 && !isApproximate) {
+            // All digits are to the left of the rounding magnitude.
+        } else if (precision == 0) {
+            // No rounding for zero.
+        } else {
+            // Perform rounding logic.
+            // "leading" = most significant digit to the right of rounding
+            // "trailing" = least significant digit to the left of rounding
+            byte leadingDigit = getDigitPos(safeSubtract(position, 1));
+            byte trailingDigit = getDigitPos(position);
+
+            // Compute which section of the number we are in.
+            // EDGE means we are at the bottom or top edge, like 1.000 or 1.999 (used by doubles)
+            // LOWER means we are between the bottom edge and the midpoint, like 1.391
+            // MIDPOINT means we are exactly in the middle, like 1.500
+            // UPPER means we are between the midpoint and the top edge, like 1.916
+            int section = RoundingUtils.SECTION_MIDPOINT;
+            if (!isApproximate) {
+                if (leadingDigit < 5) {
+                    section = RoundingUtils.SECTION_LOWER;
+                } else if (leadingDigit > 5) {
+                    section = RoundingUtils.SECTION_UPPER;
+                } else {
+                    for (int p = safeSubtract(position, 2); p >= 0; p--) {
+                        if (getDigitPos(p) != 0) {
+                            section = RoundingUtils.SECTION_UPPER;
+                            break;
+                        }
+                    }
+                }
+            } else {
+                int p = safeSubtract(position, 2);
+                int minP = Math.max(0, precision - 14);
+                if (leadingDigit == 0) {
+                    section = SECTION_LOWER_EDGE;
+                    for (; p >= minP; p--) {
+                        if (getDigitPos(p) != 0) {
+                            section = RoundingUtils.SECTION_LOWER;
+                            break;
+                        }
+                    }
+                } else if (leadingDigit == 4) {
+                    for (; p >= minP; p--) {
+                        if (getDigitPos(p) != 9) {
+                            section = RoundingUtils.SECTION_LOWER;
+                            break;
+                        }
+                    }
+                } else if (leadingDigit == 5) {
+                    for (; p >= minP; p--) {
+                        if (getDigitPos(p) != 0) {
+                            section = RoundingUtils.SECTION_UPPER;
+                            break;
+                        }
+                    }
+                } else if (leadingDigit == 9) {
+                    section = SECTION_UPPER_EDGE;
+                    for (; p >= minP; p--) {
+                        if (getDigitPos(p) != 9) {
+                            section = RoundingUtils.SECTION_UPPER;
+                            break;
+                        }
+                    }
+                } else if (leadingDigit < 5) {
+                    section = RoundingUtils.SECTION_LOWER;
+                } else {
+                    section = RoundingUtils.SECTION_UPPER;
+                }
+
+                boolean roundsAtMidpoint = RoundingUtils
+                        .roundsAtMidpoint(mathContext.getRoundingMode().ordinal());
+                if (safeSubtract(position, 1) < precision - 14
+                        || (roundsAtMidpoint && section == RoundingUtils.SECTION_MIDPOINT)
+                        || (!roundsAtMidpoint && section < 0 /* i.e. at upper or lower edge */)) {
+                    // Oops! This means that we have to get the exact representation of the double,
+                    // because
+                    // the zone of uncertainty is along the rounding boundary.
+                    convertToAccurateDouble();
+                    roundToMagnitude(magnitude, mathContext); // start over
+                    return;
+                }
+
+                // Turn off the approximate double flag, since the value is now confirmed to be exact.
+                isApproximate = false;
+                origDouble = 0.0;
+                origDelta = 0;
+
+                if (position <= 0) {
+                    // All digits are to the left of the rounding magnitude.
+                    return;
+                }
+
+                // Good to continue rounding.
+                if (section == SECTION_LOWER_EDGE)
+                    section = RoundingUtils.SECTION_LOWER;
+                if (section == SECTION_UPPER_EDGE)
+                    section = RoundingUtils.SECTION_UPPER;
+            }
+
+            boolean roundDown = RoundingUtils.getRoundingDirection((trailingDigit % 2) == 0,
+                    isNegative(),
+                    section,
+                    mathContext.getRoundingMode().ordinal(),
+                    this);
+
+            // Perform truncation
+            if (position >= precision) {
+                setBcdToZero();
+                scale = magnitude;
+            } else {
+                shiftRight(position);
+            }
+
+            // Bubble the result to the higher digits
+            if (!roundDown) {
+                if (trailingDigit == 9) {
+                    int bubblePos = 0;
+                    // Note: in the long implementation, the most digits BCD can have at this point is
+                    // 15,
+                    // so bubblePos <= 15 and getDigitPos(bubblePos) is safe.
+                    for (; getDigitPos(bubblePos) == 9; bubblePos++) {
+                    }
+                    shiftRight(bubblePos); // shift off the trailing 9s
+                }
+                byte digit0 = getDigitPos(0);
+                assert digit0 != 9;
+                setDigitPos(0, (byte) (digit0 + 1));
+                precision += 1; // in case an extra digit got added
+            }
+
+            compact();
+        }
+    }
+
+    @Override
+    public void roundToInfinity() {
+        if (isApproximate) {
+            convertToAccurateDouble();
+        }
+    }
+
+    /**
+     * Appends a digit, optionally with one or more leading zeros, to the end of the value represented by
+     * this DecimalQuantity.
+     *
+     * <p>
+     * The primary use of this method is to construct numbers during a parsing loop. It allows parsing to
+     * take advantage of the digit list infrastructure primarily designed for formatting.
+     *
+     * @param value
+     *            The digit to append.
+     * @param leadingZeros
+     *            The number of zeros to append before the digit. For example, if the value in this
+     *            instance starts as 12.3, and you append a 4 with 1 leading zero, the value becomes
+     *            12.304.
+     * @param appendAsInteger
+     *            If true, increase the magnitude of existing digits to make room for the new digit. If
+     *            false, append to the end like a fraction digit. If true, there must not be any fraction
+     *            digits already in the number.
+     * @internal
+     * @deprecated This API is ICU internal only.
+     */
+    @Deprecated
+    public void appendDigit(byte value, int leadingZeros, boolean appendAsInteger) {
+        assert leadingZeros >= 0;
+
+        // Zero requires special handling to maintain the invariant that the least-significant digit
+        // in the BCD is nonzero.
+        if (value == 0) {
+            if (appendAsInteger && precision != 0) {
+                scale += leadingZeros + 1;
+            }
+            return;
+        }
+
+        // Deal with trailing zeros
+        if (scale > 0) {
+            leadingZeros += scale;
+            if (appendAsInteger) {
+                scale = 0;
+            }
+        }
+
+        // Append digit
+        shiftLeft(leadingZeros + 1);
+        setDigitPos(0, value);
+
+        // Fix scale if in integer mode
+        if (appendAsInteger) {
+            scale += leadingZeros + 1;
+        }
+    }
+
+    @Override
+    public String toPlainString() {
+        // NOTE: This logic is duplicated between here and DecimalQuantity_SimpleStorage.
+        StringBuilder sb = new StringBuilder();
+        if (isNegative()) {
+            sb.append('-');
+        }
+        for (int m = getUpperDisplayMagnitude(); m >= getLowerDisplayMagnitude(); m--) {
+            sb.append(getDigit(m));
+            if (m == 0)
+                sb.append('.');
+        }
+        return sb.toString();
+    }
+
+    /**
+     * Returns a single digit from the BCD list. No internal state is changed by calling this method.
+     *
+     * @param position
+     *            The position of the digit to pop, counted in BCD units from the least significant
+     *            digit. If outside the range supported by the implementation, zero is returned.
+     * @return The digit at the specified location.
+     */
+    protected abstract byte getDigitPos(int position);
+
+    /**
+     * Sets the digit in the BCD list. This method only sets the digit; it is the caller's responsibility
+     * to call {@link #compact} after setting the digit.
+     *
+     * @param position
+     *            The position of the digit to pop, counted in BCD units from the least significant
+     *            digit. If outside the range supported by the implementation, an AssertionError is
+     *            thrown.
+     * @param value
+     *            The digit to set at the specified location.
+     */
+    protected abstract void setDigitPos(int position, byte value);
+
+    /**
+     * Adds zeros to the end of the BCD list. This will result in an invalid BCD representation; it is
+     * the caller's responsibility to do further manipulation and then call {@link #compact}.
+     *
+     * @param numDigits
+     *            The number of zeros to add.
+     */
+    protected abstract void shiftLeft(int numDigits);
+
+    protected abstract void shiftRight(int numDigits);
+
+    /**
+     * Sets the internal representation to zero. Clears any values stored in scale, precision, hasDouble,
+     * origDouble, origDelta, and BCD data.
+     */
+    protected abstract void setBcdToZero();
+
+    /**
+     * Sets the internal BCD state to represent the value in the given int. The int is guaranteed to be
+     * either positive. The internal state is guaranteed to be empty when this method is called.
+     *
+     * @param n
+     *            The value to consume.
+     */
+    protected abstract void readIntToBcd(int input);
+
+    /**
+     * Sets the internal BCD state to represent the value in the given long. The long is guaranteed to be
+     * either positive. The internal state is guaranteed to be empty when this method is called.
+     *
+     * @param n
+     *            The value to consume.
+     */
+    protected abstract void readLongToBcd(long input);
+
+    /**
+     * Sets the internal BCD state to represent the value in the given BigInteger. The BigInteger is
+     * guaranteed to be positive, and it is guaranteed to be larger than Long.MAX_VALUE. The internal
+     * state is guaranteed to be empty when this method is called.
+     *
+     * @param n
+     *            The value to consume.
+     */
+    protected abstract void readBigIntegerToBcd(BigInteger input);
+
+    /**
+     * Returns a BigDecimal encoding the internal BCD value.
+     *
+     * @return A BigDecimal representation of the internal BCD.
+     */
+    protected abstract BigDecimal bcdToBigDecimal();
+
+    protected abstract void copyBcdFrom(DecimalQuantity _other);
+
+    /**
+     * Removes trailing zeros from the BCD (adjusting the scale as required) and then computes the
+     * precision. The precision is the number of digits in the number up through the greatest nonzero
+     * digit.
+     *
+     * <p>
+     * This method must always be called when bcd changes in order for assumptions to be correct in
+     * methods like {@link #fractionCount()}.
+     */
+    protected abstract void compact();
 }
index 2ea374b6b50a4484c60e1388a3b9352fe6515701..92e660df28a280059016bfe2d5ce78fde9bdd887 100644 (file)
@@ -6,412 +6,433 @@ import java.math.BigDecimal;
 import java.math.BigInteger;
 
 /**
- * A DecimalQuantity with internal storage as a 64-bit BCD, with fallback to a byte array
- * for numbers that don't fit into the standard BCD.
+ * A DecimalQuantity with internal storage as a 64-bit BCD, with fallback to a byte array for numbers
+ * that don't fit into the standard BCD.
  */
 public final class DecimalQuantity_DualStorageBCD extends DecimalQuantity_AbstractBCD {
 
-  /**
-   * The BCD of the 16 digits of the number represented by this object. Every 4 bits of the long map
-   * to one digit. For example, the number "12345" in BCD is "0x12345".
-   *
-   * <p>Whenever bcd changes internally, {@link #compact()} must be called, except in special cases
-   * like setting the digit to zero.
-   */
-  private byte[] bcdBytes;
-
-  private long bcdLong = 0L;
-
-  private boolean usingBytes = false;
-
-  @Override
-  public int maxRepresentableDigits() {
-    return Integer.MAX_VALUE;
-  }
-
-  public DecimalQuantity_DualStorageBCD() {
-    setBcdToZero();
-    flags = 0;
-  }
-
-  public DecimalQuantity_DualStorageBCD(long input) {
-    setToLong(input);
-  }
-
-  public DecimalQuantity_DualStorageBCD(int input) {
-    setToInt(input);
-  }
-
-  public DecimalQuantity_DualStorageBCD(double input) {
-    setToDouble(input);
-  }
-
-  public DecimalQuantity_DualStorageBCD(BigInteger input) {
-    setToBigInteger(input);
-  }
-
-  public DecimalQuantity_DualStorageBCD(BigDecimal input) {
-    setToBigDecimal(input);
-  }
-
-  public DecimalQuantity_DualStorageBCD(DecimalQuantity_DualStorageBCD other) {
-    copyFrom(other);
-  }
-
-  public DecimalQuantity_DualStorageBCD(Number number) {
-    if (number instanceof Long) {
-      setToLong(number.longValue());
-    } else if (number instanceof Integer) {
-      setToInt(number.intValue());
-    } else if (number instanceof Double) {
-      setToDouble(number.doubleValue());
-    } else if (number instanceof BigInteger) {
-      setToBigInteger((BigInteger) number);
-    } else if (number instanceof BigDecimal) {
-      setToBigDecimal((BigDecimal) number);
-    } else if (number instanceof com.ibm.icu.math.BigDecimal) {
-      setToBigDecimal(((com.ibm.icu.math.BigDecimal) number).toBigDecimal());
-    } else {
-      throw new IllegalArgumentException(
-          "Number is of an unsupported type: " + number.getClass().getName());
+    /**
+     * The BCD of the 16 digits of the number represented by this object. Every 4 bits of the long map to
+     * one digit. For example, the number "12345" in BCD is "0x12345".
+     *
+     * <p>
+     * Whenever bcd changes internally, {@link #compact()} must be called, except in special cases like
+     * setting the digit to zero.
+     */
+    private byte[] bcdBytes;
+
+    private long bcdLong = 0L;
+
+    private boolean usingBytes = false;
+
+    @Override
+    public int maxRepresentableDigits() {
+        return Integer.MAX_VALUE;
     }
-  }
-
-  @Override
-  public DecimalQuantity createCopy() {
-    return new DecimalQuantity_DualStorageBCD(this);
-  }
-
-  @Override
-  protected byte getDigitPos(int position) {
-    if (usingBytes) {
-      if (position < 0 || position > precision) return 0;
-      return bcdBytes[position];
-    } else {
-      if (position < 0 || position >= 16) return 0;
-      return (byte) ((bcdLong >>> (position * 4)) & 0xf);
+
+    public DecimalQuantity_DualStorageBCD() {
+        setBcdToZero();
+        flags = 0;
     }
-  }
-
-  @Override
-  protected void setDigitPos(int position, byte value) {
-    assert position >= 0;
-    if (usingBytes) {
-      ensureCapacity(position + 1);
-      bcdBytes[position] = value;
-    } else if (position >= 16) {
-      switchStorage();
-      ensureCapacity(position + 1);
-      bcdBytes[position] = value;
-    } else {
-      int shift = position * 4;
-      bcdLong = bcdLong & ~(0xfL << shift) | ((long) value << shift);
+
+    public DecimalQuantity_DualStorageBCD(long input) {
+        setToLong(input);
     }
-  }
 
-  @Override
-  protected void shiftLeft(int numDigits) {
-    if (!usingBytes && precision + numDigits > 16) {
-      switchStorage();
+    public DecimalQuantity_DualStorageBCD(int input) {
+        setToInt(input);
     }
-    if (usingBytes) {
-      ensureCapacity(precision + numDigits);
-      int i = precision + numDigits - 1;
-      for (; i >= numDigits; i--) {
-        bcdBytes[i] = bcdBytes[i - numDigits];
-      }
-      for (; i >= 0; i--) {
-        bcdBytes[i] = 0;
-      }
-    } else {
-      bcdLong <<= (numDigits * 4);
+
+    public DecimalQuantity_DualStorageBCD(double input) {
+        setToDouble(input);
     }
-    scale -= numDigits;
-    precision += numDigits;
-  }
-
-  @Override
-  protected void shiftRight(int numDigits) {
-    if (usingBytes) {
-      int i = 0;
-      for (; i < precision - numDigits; i++) {
-        bcdBytes[i] = bcdBytes[i + numDigits];
-      }
-      for (; i < precision; i++) {
-        bcdBytes[i] = 0;
-      }
-    } else {
-      bcdLong >>>= (numDigits * 4);
+
+    public DecimalQuantity_DualStorageBCD(BigInteger input) {
+        setToBigInteger(input);
     }
-    scale += numDigits;
-    precision -= numDigits;
-  }
-
-  @Override
-  protected void setBcdToZero() {
-    if (usingBytes) {
-        bcdBytes = null;
-        usingBytes = false;
+
+    public DecimalQuantity_DualStorageBCD(BigDecimal input) {
+        setToBigDecimal(input);
     }
-    bcdLong = 0L;
-    scale = 0;
-    precision = 0;
-    isApproximate = false;
-    origDouble = 0;
-    origDelta = 0;
-  }
-
-  @Override
-  protected void readIntToBcd(int n) {
-    assert n != 0;
-    // ints always fit inside the long implementation.
-    long result = 0L;
-    int i = 16;
-    for (; n != 0; n /= 10, i--) {
-      result = (result >>> 4) + (((long) n % 10) << 60);
+
+    public DecimalQuantity_DualStorageBCD(DecimalQuantity_DualStorageBCD other) {
+        copyFrom(other);
     }
-    assert !usingBytes;
-    bcdLong = result >>> (i * 4);
-    scale = 0;
-    precision = 16 - i;
-  }
-
-  @Override
-  protected void readLongToBcd(long n) {
-    assert n != 0;
-    if (n >= 10000000000000000L) {
-      ensureCapacity();
-      int i = 0;
-      for (; n != 0L; n /= 10L, i++) {
-        bcdBytes[i] = (byte) (n % 10);
-      }
-      assert usingBytes;
-      scale = 0;
-      precision = i;
-    } else {
-      long result = 0L;
-      int i = 16;
-      for (; n != 0L; n /= 10L, i--) {
-        result = (result >>> 4) + ((n % 10) << 60);
-      }
-      assert i >= 0;
-      assert !usingBytes;
-      bcdLong = result >>> (i * 4);
-      scale = 0;
-      precision = 16 - i;
+
+    public DecimalQuantity_DualStorageBCD(Number number) {
+        if (number instanceof Long) {
+            setToLong(number.longValue());
+        } else if (number instanceof Integer) {
+            setToInt(number.intValue());
+        } else if (number instanceof Double) {
+            setToDouble(number.doubleValue());
+        } else if (number instanceof BigInteger) {
+            setToBigInteger((BigInteger) number);
+        } else if (number instanceof BigDecimal) {
+            setToBigDecimal((BigDecimal) number);
+        } else if (number instanceof com.ibm.icu.math.BigDecimal) {
+            setToBigDecimal(((com.ibm.icu.math.BigDecimal) number).toBigDecimal());
+        } else {
+            throw new IllegalArgumentException(
+                    "Number is of an unsupported type: " + number.getClass().getName());
+        }
     }
-  }
-
-  @Override
-  protected void readBigIntegerToBcd(BigInteger n) {
-    assert n.signum() != 0;
-    ensureCapacity(); // allocate initial byte array
-    int i = 0;
-    for (; n.signum() != 0; i++) {
-      BigInteger[] temp = n.divideAndRemainder(BigInteger.TEN);
-      ensureCapacity(i + 1);
-      bcdBytes[i] = temp[1].byteValue();
-      n = temp[0];
+
+    @Override
+    public DecimalQuantity createCopy() {
+        return new DecimalQuantity_DualStorageBCD(this);
     }
-    scale = 0;
-    precision = i;
-  }
-
-  @Override
-  protected BigDecimal bcdToBigDecimal() {
-    if (usingBytes) {
-      // Converting to a string here is faster than doing BigInteger/BigDecimal arithmetic.
-      BigDecimal result = new BigDecimal(toNumberString());
-      if (isNegative()) {
-          result = result.negate();
-      }
-      return result;
-    } else {
-      long tempLong = 0L;
-      for (int shift = (precision - 1); shift >= 0; shift--) {
-        tempLong = tempLong * 10 + getDigitPos(shift);
-      }
-      BigDecimal result = BigDecimal.valueOf(tempLong);
-      result = result.scaleByPowerOfTen(scale);
-      if (isNegative()) result = result.negate();
-      return result;
+
+    @Override
+    protected byte getDigitPos(int position) {
+        if (usingBytes) {
+            if (position < 0 || position > precision)
+                return 0;
+            return bcdBytes[position];
+        } else {
+            if (position < 0 || position >= 16)
+                return 0;
+            return (byte) ((bcdLong >>> (position * 4)) & 0xf);
+        }
+    }
+
+    @Override
+    protected void setDigitPos(int position, byte value) {
+        assert position >= 0;
+        if (usingBytes) {
+            ensureCapacity(position + 1);
+            bcdBytes[position] = value;
+        } else if (position >= 16) {
+            switchStorage();
+            ensureCapacity(position + 1);
+            bcdBytes[position] = value;
+        } else {
+            int shift = position * 4;
+            bcdLong = bcdLong & ~(0xfL << shift) | ((long) value << shift);
+        }
+    }
+
+    @Override
+    protected void shiftLeft(int numDigits) {
+        if (!usingBytes && precision + numDigits > 16) {
+            switchStorage();
+        }
+        if (usingBytes) {
+            ensureCapacity(precision + numDigits);
+            int i = precision + numDigits - 1;
+            for (; i >= numDigits; i--) {
+                bcdBytes[i] = bcdBytes[i - numDigits];
+            }
+            for (; i >= 0; i--) {
+                bcdBytes[i] = 0;
+            }
+        } else {
+            bcdLong <<= (numDigits * 4);
+        }
+        scale -= numDigits;
+        precision += numDigits;
+    }
+
+    @Override
+    protected void shiftRight(int numDigits) {
+        if (usingBytes) {
+            int i = 0;
+            for (; i < precision - numDigits; i++) {
+                bcdBytes[i] = bcdBytes[i + numDigits];
+            }
+            for (; i < precision; i++) {
+                bcdBytes[i] = 0;
+            }
+        } else {
+            bcdLong >>>= (numDigits * 4);
+        }
+        scale += numDigits;
+        precision -= numDigits;
+    }
+
+    @Override
+    protected void setBcdToZero() {
+        if (usingBytes) {
+            bcdBytes = null;
+            usingBytes = false;
+        }
+        bcdLong = 0L;
+        scale = 0;
+        precision = 0;
+        isApproximate = false;
+        origDouble = 0;
+        origDelta = 0;
     }
-  }
-
-  @Override
-  protected void compact() {
-    if (usingBytes) {
-      int delta = 0;
-      for (; delta < precision && bcdBytes[delta] == 0; delta++) ;
-      if (delta == precision) {
-        // Number is zero
-        setBcdToZero();
-        return;
-      } else {
-        // Remove trailing zeros
-        shiftRight(delta);
-      }
-
-      // Compute precision
-      int leading = precision - 1;
-      for (; leading >= 0 && bcdBytes[leading] == 0; leading--) ;
-      precision = leading + 1;
-
-      // Switch storage mechanism if possible
-      if (precision <= 16) {
-        switchStorage();
-      }
-
-    } else {
-      if (bcdLong == 0L) {
-        // Number is zero
-        setBcdToZero();
-        return;
-      }
 
-      // Compact the number (remove trailing zeros)
-      int delta = Long.numberOfTrailingZeros(bcdLong) / 4;
-      bcdLong >>>= delta * 4;
-      scale += delta;
+    @Override
+    protected void readIntToBcd(int n) {
+        assert n != 0;
+        // ints always fit inside the long implementation.
+        long result = 0L;
+        int i = 16;
+        for (; n != 0; n /= 10, i--) {
+            result = (result >>> 4) + (((long) n % 10) << 60);
+        }
+        assert !usingBytes;
+        bcdLong = result >>> (i * 4);
+        scale = 0;
+        precision = 16 - i;
+    }
 
-      // Compute precision
-      precision = 16 - (Long.numberOfLeadingZeros(bcdLong) / 4);
+    @Override
+    protected void readLongToBcd(long n) {
+        assert n != 0;
+        if (n >= 10000000000000000L) {
+            ensureCapacity();
+            int i = 0;
+            for (; n != 0L; n /= 10L, i++) {
+                bcdBytes[i] = (byte) (n % 10);
+            }
+            assert usingBytes;
+            scale = 0;
+            precision = i;
+        } else {
+            long result = 0L;
+            int i = 16;
+            for (; n != 0L; n /= 10L, i--) {
+                result = (result >>> 4) + ((n % 10) << 60);
+            }
+            assert i >= 0;
+            assert !usingBytes;
+            bcdLong = result >>> (i * 4);
+            scale = 0;
+            precision = 16 - i;
+        }
     }
-  }
-
-  /** Ensure that a byte array of at least 40 digits is allocated. */
-  private void ensureCapacity() {
-    ensureCapacity(40);
-  }
-
-  private void ensureCapacity(int capacity) {
-    if (capacity == 0) return;
-    int oldCapacity = usingBytes ? bcdBytes.length : 0;
-    if (!usingBytes) {
-      bcdBytes = new byte[capacity];
-    } else if (oldCapacity < capacity) {
-      byte[] bcd1 = new byte[capacity * 2];
-      System.arraycopy(bcdBytes, 0, bcd1, 0, oldCapacity);
-      bcdBytes = bcd1;
+
+    @Override
+    protected void readBigIntegerToBcd(BigInteger n) {
+        assert n.signum() != 0;
+        ensureCapacity(); // allocate initial byte array
+        int i = 0;
+        for (; n.signum() != 0; i++) {
+            BigInteger[] temp = n.divideAndRemainder(BigInteger.TEN);
+            ensureCapacity(i + 1);
+            bcdBytes[i] = temp[1].byteValue();
+            n = temp[0];
+        }
+        scale = 0;
+        precision = i;
     }
-    usingBytes = true;
-  }
-
-  /** Switches the internal storage mechanism between the 64-bit long and the byte array. */
-  private void switchStorage() {
-    if (usingBytes) {
-      // Change from bytes to long
-      bcdLong = 0L;
-      for (int i = precision - 1; i >= 0; i--) {
-        bcdLong <<= 4;
-        bcdLong |= bcdBytes[i];
-      }
-      bcdBytes = null;
-      usingBytes = false;
-    } else {
-      // Change from long to bytes
-      ensureCapacity();
-      for (int i = 0; i < precision; i++) {
-        bcdBytes[i] = (byte) (bcdLong & 0xf);
-        bcdLong >>>= 4;
-      }
-      assert usingBytes;
+
+    @Override
+    protected BigDecimal bcdToBigDecimal() {
+        if (usingBytes) {
+            // Converting to a string here is faster than doing BigInteger/BigDecimal arithmetic.
+            BigDecimal result = new BigDecimal(toNumberString());
+            if (isNegative()) {
+                result = result.negate();
+            }
+            return result;
+        } else {
+            long tempLong = 0L;
+            for (int shift = (precision - 1); shift >= 0; shift--) {
+                tempLong = tempLong * 10 + getDigitPos(shift);
+            }
+            BigDecimal result = BigDecimal.valueOf(tempLong);
+            result = result.scaleByPowerOfTen(scale);
+            if (isNegative())
+                result = result.negate();
+            return result;
+        }
     }
-  }
-
-  @Override
-  protected void copyBcdFrom(DecimalQuantity _other) {
-    DecimalQuantity_DualStorageBCD other = (DecimalQuantity_DualStorageBCD) _other;
-    setBcdToZero();
-    if (other.usingBytes) {
-      ensureCapacity(other.precision);
-      System.arraycopy(other.bcdBytes, 0, bcdBytes, 0, other.precision);
-    } else {
-      bcdLong = other.bcdLong;
+
+    @Override
+    protected void compact() {
+        if (usingBytes) {
+            int delta = 0;
+            for (; delta < precision && bcdBytes[delta] == 0; delta++)
+                ;
+            if (delta == precision) {
+                // Number is zero
+                setBcdToZero();
+                return;
+            } else {
+                // Remove trailing zeros
+                shiftRight(delta);
+            }
+
+            // Compute precision
+            int leading = precision - 1;
+            for (; leading >= 0 && bcdBytes[leading] == 0; leading--)
+                ;
+            precision = leading + 1;
+
+            // Switch storage mechanism if possible
+            if (precision <= 16) {
+                switchStorage();
+            }
+
+        } else {
+            if (bcdLong == 0L) {
+                // Number is zero
+                setBcdToZero();
+                return;
+            }
+
+            // Compact the number (remove trailing zeros)
+            int delta = Long.numberOfTrailingZeros(bcdLong) / 4;
+            bcdLong >>>= delta * 4;
+            scale += delta;
+
+            // Compute precision
+            precision = 16 - (Long.numberOfLeadingZeros(bcdLong) / 4);
+        }
+    }
+
+    /** Ensure that a byte array of at least 40 digits is allocated. */
+    private void ensureCapacity() {
+        ensureCapacity(40);
     }
-  }
-
-  /**
-   * Checks whether the bytes stored in this instance are all valid. For internal unit testing only.
-   *
-   * @return An error message if this instance is invalid, or null if this instance is healthy.
-   * @internal
-   * @deprecated This API is for ICU internal use only.
-   */
-  @Deprecated
-  public String checkHealth() {
-    if (usingBytes) {
-      if (bcdLong != 0) return "Value in bcdLong but we are in byte mode";
-      if (precision == 0) return "Zero precision but we are in byte mode";
-      if (precision > bcdBytes.length) return "Precision exceeds length of byte array";
-      if (getDigitPos(precision - 1) == 0) return "Most significant digit is zero in byte mode";
-      if (getDigitPos(0) == 0) return "Least significant digit is zero in long mode";
-      for (int i = 0; i < precision; i++) {
-        if (getDigitPos(i) >= 10) return "Digit exceeding 10 in byte array";
-        if (getDigitPos(i) < 0) return "Digit below 0 in byte array";
-      }
-      for (int i = precision; i < bcdBytes.length; i++) {
-        if (getDigitPos(i) != 0) return "Nonzero digits outside of range in byte array";
-      }
-    } else {
-      if (bcdBytes != null) {
-        for (int i = 0; i < bcdBytes.length; i++) {
-          if (bcdBytes[i] != 0) return "Nonzero digits in byte array but we are in long mode";
+
+    private void ensureCapacity(int capacity) {
+        if (capacity == 0)
+            return;
+        int oldCapacity = usingBytes ? bcdBytes.length : 0;
+        if (!usingBytes) {
+            bcdBytes = new byte[capacity];
+        } else if (oldCapacity < capacity) {
+            byte[] bcd1 = new byte[capacity * 2];
+            System.arraycopy(bcdBytes, 0, bcd1, 0, oldCapacity);
+            bcdBytes = bcd1;
         }
-      }
-      if (precision == 0 && bcdLong != 0) return "Value in bcdLong even though precision is zero";
-      if (precision > 16) return "Precision exceeds length of long";
-      if (precision != 0 && getDigitPos(precision - 1) == 0)
-        return "Most significant digit is zero in long mode";
-      if (precision != 0 && getDigitPos(0) == 0)
-        return "Least significant digit is zero in long mode";
-      for (int i = 0; i < precision; i++) {
-        if (getDigitPos(i) >= 10) return "Digit exceeding 10 in long";
-        if (getDigitPos(i) < 0) return "Digit below 0 in long (?!)";
-      }
-      for (int i = precision; i < 16; i++) {
-        if (getDigitPos(i) != 0) return "Nonzero digits outside of range in long";
-      }
+        usingBytes = true;
     }
 
-    return null;
-  }
-
-  /**
-   * Checks whether this {@link DecimalQuantity_DualStorageBCD} is using its internal byte array storage mechanism.
-   *
-   * @return true if an internal byte array is being used; false if a long is being used.
-   * @internal
-   * @deprecated This API is ICU internal only.
-   */
-  @Deprecated
-  public boolean isUsingBytes() {
-    return usingBytes;
-  }
-
-  @Override
-  public String toString() {
-    return String.format(
-        "<DecimalQuantity %s:%d:%d:%s %s %s>",
-        (lOptPos > 1000 ? "999" : String.valueOf(lOptPos)),
-        lReqPos,
-        rReqPos,
-        (rOptPos < -1000 ? "-999" : String.valueOf(rOptPos)),
-        (usingBytes ? "bytes" : "long"),
-        toNumberString());
-  }
-
-  public String toNumberString() {
-      StringBuilder sb = new StringBuilder();
-      if (usingBytes) {
-        for (int i = precision - 1; i >= 0; i--) {
-          sb.append(bcdBytes[i]);
+    /** Switches the internal storage mechanism between the 64-bit long and the byte array. */
+    private void switchStorage() {
+        if (usingBytes) {
+            // Change from bytes to long
+            bcdLong = 0L;
+            for (int i = precision - 1; i >= 0; i--) {
+                bcdLong <<= 4;
+                bcdLong |= bcdBytes[i];
+            }
+            bcdBytes = null;
+            usingBytes = false;
+        } else {
+            // Change from long to bytes
+            ensureCapacity();
+            for (int i = 0; i < precision; i++) {
+                bcdBytes[i] = (byte) (bcdLong & 0xf);
+                bcdLong >>>= 4;
+            }
+            assert usingBytes;
         }
-      } else {
-        sb.append(Long.toHexString(bcdLong));
-      }
-      sb.append("E");
-      sb.append(scale);
-      return sb.toString();
-  }
+    }
+
+    @Override
+    protected void copyBcdFrom(DecimalQuantity _other) {
+        DecimalQuantity_DualStorageBCD other = (DecimalQuantity_DualStorageBCD) _other;
+        setBcdToZero();
+        if (other.usingBytes) {
+            ensureCapacity(other.precision);
+            System.arraycopy(other.bcdBytes, 0, bcdBytes, 0, other.precision);
+        } else {
+            bcdLong = other.bcdLong;
+        }
+    }
+
+    /**
+     * Checks whether the bytes stored in this instance are all valid. For internal unit testing only.
+     *
+     * @return An error message if this instance is invalid, or null if this instance is healthy.
+     * @internal
+     * @deprecated This API is for ICU internal use only.
+     */
+    @Deprecated
+    public String checkHealth() {
+        if (usingBytes) {
+            if (bcdLong != 0)
+                return "Value in bcdLong but we are in byte mode";
+            if (precision == 0)
+                return "Zero precision but we are in byte mode";
+            if (precision > bcdBytes.length)
+                return "Precision exceeds length of byte array";
+            if (getDigitPos(precision - 1) == 0)
+                return "Most significant digit is zero in byte mode";
+            if (getDigitPos(0) == 0)
+                return "Least significant digit is zero in long mode";
+            for (int i = 0; i < precision; i++) {
+                if (getDigitPos(i) >= 10)
+                    return "Digit exceeding 10 in byte array";
+                if (getDigitPos(i) < 0)
+                    return "Digit below 0 in byte array";
+            }
+            for (int i = precision; i < bcdBytes.length; i++) {
+                if (getDigitPos(i) != 0)
+                    return "Nonzero digits outside of range in byte array";
+            }
+        } else {
+            if (bcdBytes != null) {
+                for (int i = 0; i < bcdBytes.length; i++) {
+                    if (bcdBytes[i] != 0)
+                        return "Nonzero digits in byte array but we are in long mode";
+                }
+            }
+            if (precision == 0 && bcdLong != 0)
+                return "Value in bcdLong even though precision is zero";
+            if (precision > 16)
+                return "Precision exceeds length of long";
+            if (precision != 0 && getDigitPos(precision - 1) == 0)
+                return "Most significant digit is zero in long mode";
+            if (precision != 0 && getDigitPos(0) == 0)
+                return "Least significant digit is zero in long mode";
+            for (int i = 0; i < precision; i++) {
+                if (getDigitPos(i) >= 10)
+                    return "Digit exceeding 10 in long";
+                if (getDigitPos(i) < 0)
+                    return "Digit below 0 in long (?!)";
+            }
+            for (int i = precision; i < 16; i++) {
+                if (getDigitPos(i) != 0)
+                    return "Nonzero digits outside of range in long";
+            }
+        }
+
+        return null;
+    }
+
+    /**
+     * Checks whether this {@link DecimalQuantity_DualStorageBCD} is using its internal byte array
+     * storage mechanism.
+     *
+     * @return true if an internal byte array is being used; false if a long is being used.
+     * @internal
+     * @deprecated This API is ICU internal only.
+     */
+    @Deprecated
+    public boolean isUsingBytes() {
+        return usingBytes;
+    }
+
+    @Override
+    public String toString() {
+        return String.format("<DecimalQuantity %s:%d:%d:%s %s %s>",
+                (lOptPos > 1000 ? "999" : String.valueOf(lOptPos)),
+                lReqPos,
+                rReqPos,
+                (rOptPos < -1000 ? "-999" : String.valueOf(rOptPos)),
+                (usingBytes ? "bytes" : "long"),
+                toNumberString());
+    }
+
+    public String toNumberString() {
+        StringBuilder sb = new StringBuilder();
+        if (usingBytes) {
+            for (int i = precision - 1; i >= 0; i--) {
+                sb.append(bcdBytes[i]);
+            }
+        } else {
+            sb.append(Long.toHexString(bcdLong));
+        }
+        sb.append("E");
+        sb.append(scale);
+        return sb.toString();
+    }
 }
index 43bde7b4de176ed5299a6cbe73c9fd7c689c2be8..e1f1cf7794a14238dbcd79c481c8bf7a0ed933f4 100644 (file)
@@ -15,96 +15,114 @@ import com.ibm.icu.util.MeasureUnit;
 import com.ibm.icu.util.ULocale;
 
 public class MacroProps implements Cloneable {
-  public Notation notation;
-  public MeasureUnit unit;
-  public MeasureUnit perUnit;
-  public Rounder rounder;
-  public Grouper grouper;
-  public Padder padder;
-  public IntegerWidth integerWidth;
-  public Object symbols;
-  public UnitWidth unitWidth;
-  public SignDisplay sign;
-  public DecimalSeparatorDisplay decimal;
-  public AffixPatternProvider affixProvider; // not in API; for JDK compatibility mode only
-  public MultiplierImpl multiplier; // not in API; for JDK compatibility mode only
-  public PluralRules rules; // not in API; could be made public in the future
-  public Long threshold; // not in API; controls internal self-regulation threshold
-  public ULocale loc;
+    public Notation notation;
+    public MeasureUnit unit;
+    public MeasureUnit perUnit;
+    public Rounder rounder;
+    public Grouper grouper;
+    public Padder padder;
+    public IntegerWidth integerWidth;
+    public Object symbols;
+    public UnitWidth unitWidth;
+    public SignDisplay sign;
+    public DecimalSeparatorDisplay decimal;
+    public AffixPatternProvider affixProvider; // not in API; for JDK compatibility mode only
+    public MultiplierImpl multiplier; // not in API; for JDK compatibility mode only
+    public PluralRules rules; // not in API; could be made public in the future
+    public Long threshold; // not in API; controls internal self-regulation threshold
+    public ULocale loc;
 
-  /**
-   * Copies values from fallback into this instance if they are null in this instance.
-   *
-   * @param fallback The instance to copy from; not modified by this operation.
-   */
-  public void fallback(MacroProps fallback) {
-    if (notation == null) notation = fallback.notation;
-    if (unit == null) unit = fallback.unit;
-    if (perUnit == null) perUnit = fallback.perUnit;
-    if (rounder == null) rounder = fallback.rounder;
-    if (grouper == null) grouper = fallback.grouper;
-    if (padder == null) padder = fallback.padder;
-    if (integerWidth == null) integerWidth = fallback.integerWidth;
-    if (symbols == null) symbols = fallback.symbols;
-    if (unitWidth == null) unitWidth = fallback.unitWidth;
-    if (sign == null) sign = fallback.sign;
-    if (decimal == null) decimal = fallback.decimal;
-    if (affixProvider == null) affixProvider = fallback.affixProvider;
-    if (multiplier == null) multiplier = fallback.multiplier;
-    if (rules == null) rules = fallback.rules;
-    if (loc == null) loc = fallback.loc;
-  }
+    /**
+     * Copies values from fallback into this instance if they are null in this instance.
+     *
+     * @param fallback
+     *            The instance to copy from; not modified by this operation.
+     */
+    public void fallback(MacroProps fallback) {
+        if (notation == null)
+            notation = fallback.notation;
+        if (unit == null)
+            unit = fallback.unit;
+        if (perUnit == null)
+            perUnit = fallback.perUnit;
+        if (rounder == null)
+            rounder = fallback.rounder;
+        if (grouper == null)
+            grouper = fallback.grouper;
+        if (padder == null)
+            padder = fallback.padder;
+        if (integerWidth == null)
+            integerWidth = fallback.integerWidth;
+        if (symbols == null)
+            symbols = fallback.symbols;
+        if (unitWidth == null)
+            unitWidth = fallback.unitWidth;
+        if (sign == null)
+            sign = fallback.sign;
+        if (decimal == null)
+            decimal = fallback.decimal;
+        if (affixProvider == null)
+            affixProvider = fallback.affixProvider;
+        if (multiplier == null)
+            multiplier = fallback.multiplier;
+        if (rules == null)
+            rules = fallback.rules;
+        if (loc == null)
+            loc = fallback.loc;
+    }
 
-  @Override
-  public int hashCode() {
-    return Utility.hash(
-        notation,
-        unit,
-        perUnit,
-        rounder,
-        grouper,
-        padder,
-        integerWidth,
-        symbols,
-        unitWidth,
-        sign,
-        decimal,
-        affixProvider,
-        multiplier,
-        rules,
-        loc);
-  }
+    @Override
+    public int hashCode() {
+        return Utility.hash(notation,
+                unit,
+                perUnit,
+                rounder,
+                grouper,
+                padder,
+                integerWidth,
+                symbols,
+                unitWidth,
+                sign,
+                decimal,
+                affixProvider,
+                multiplier,
+                rules,
+                loc);
+    }
 
-  @Override
-  public boolean equals(Object _other) {
-    if (_other == null) return false;
-    if (this == _other) return true;
-    if (!(_other instanceof MacroProps)) return false;
-    MacroProps other = (MacroProps) _other;
-    return Utility.equals(notation, other.notation)
-        && Utility.equals(unit, other.unit)
-        && Utility.equals(perUnit, other.perUnit)
-        && Utility.equals(rounder, other.rounder)
-        && Utility.equals(grouper, other.grouper)
-        && Utility.equals(padder, other.padder)
-        && Utility.equals(integerWidth, other.integerWidth)
-        && Utility.equals(symbols, other.symbols)
-        && Utility.equals(unitWidth, other.unitWidth)
-        && Utility.equals(sign, other.sign)
-        && Utility.equals(decimal, other.decimal)
-        && Utility.equals(affixProvider, other.affixProvider)
-        && Utility.equals(multiplier, other.multiplier)
-        && Utility.equals(rules, other.rules)
-        && Utility.equals(loc, other.loc);
-  }
+    @Override
+    public boolean equals(Object _other) {
+        if (_other == null)
+            return false;
+        if (this == _other)
+            return true;
+        if (!(_other instanceof MacroProps))
+            return false;
+        MacroProps other = (MacroProps) _other;
+        return Utility.equals(notation, other.notation)
+                && Utility.equals(unit, other.unit)
+                && Utility.equals(perUnit, other.perUnit)
+                && Utility.equals(rounder, other.rounder)
+                && Utility.equals(grouper, other.grouper)
+                && Utility.equals(padder, other.padder)
+                && Utility.equals(integerWidth, other.integerWidth)
+                && Utility.equals(symbols, other.symbols)
+                && Utility.equals(unitWidth, other.unitWidth)
+                && Utility.equals(sign, other.sign)
+                && Utility.equals(decimal, other.decimal)
+                && Utility.equals(affixProvider, other.affixProvider)
+                && Utility.equals(multiplier, other.multiplier)
+                && Utility.equals(rules, other.rules)
+                && Utility.equals(loc, other.loc);
+    }
 
-  @Override
-  public Object clone() {
-    // TODO: Remove this method?
-    try {
-      return super.clone();
-    } catch (CloneNotSupportedException e) {
-      throw new AssertionError(e);
+    @Override
+    public Object clone() {
+        // TODO: Remove this method?
+        try {
+            return super.clone();
+        } catch (CloneNotSupportedException e) {
+            throw new AssertionError(e);
+        }
     }
-  }
 }
index 6d5a33aec8a5d0aa0b745bdf3ef73446fa917d9b..019a10168abf55110acfff47f9f87d8ea0ced8f3 100644 (file)
@@ -31,8 +31,8 @@ public class MicroProps implements Cloneable, MicroPropsGenerator {
 
     /**
      * @param immutable
-     *            Whether this MicroProps should behave as an immutable after construction with respect to the quantity
-     *            chain.
+     *            Whether this MicroProps should behave as an immutable after construction with respect
+     *            to the quantity chain.
      */
     public MicroProps(boolean immutable) {
         this.immutable = immutable;
index c633ce7ec706e103bba2c1c095e086daadfffb7e..12ce18db49047f8ad0866bb1367c1ba051975f8b 100644 (file)
@@ -3,19 +3,21 @@
 package com.ibm.icu.impl.number;
 
 /**
- * This interface is used when all number formatting settings, including the locale, are known, except for the quantity
- * itself. The {@link #processQuantity} method performs the final step in the number processing pipeline: it uses the
- * quantity to generate a finalized {@link MicroProps}, which can be used to render the number to output.
+ * This interface is used when all number formatting settings, including the locale, are known, except
+ * for the quantity itself. The {@link #processQuantity} method performs the final step in the number
+ * processing pipeline: it uses the quantity to generate a finalized {@link MicroProps}, which can be
+ * used to render the number to output.
  *
  * <p>
- * In other words, this interface is used for the parts of number processing that are <em>quantity-dependent</em>.
+ * In other words, this interface is used for the parts of number processing that are
+ * <em>quantity-dependent</em>.
  *
  * <p>
- * In order to allow for multiple different objects to all mutate the same MicroProps, a "chain" of MicroPropsGenerators
- * are linked together, and each one is responsible for manipulating a certain quantity-dependent part of the
- * MicroProps. At the top of the linked list is a base instance of {@link MicroProps} with properties that are not
- * quantity-dependent. Each element in the linked list calls {@link #processQuantity} on its "parent", then does its
- * work, and then returns the result.
+ * In order to allow for multiple different objects to all mutate the same MicroProps, a "chain" of
+ * MicroPropsGenerators are linked together, and each one is responsible for manipulating a certain
+ * quantity-dependent part of the MicroProps. At the top of the linked list is a base instance of
+ * {@link MicroProps} with properties that are not quantity-dependent. Each element in the linked list
+ * calls {@link #processQuantity} on its "parent", then does its work, and then returns the result.
  *
  * <p>
  * A class implementing MicroPropsGenerator looks something like this:
@@ -42,7 +44,8 @@ package com.ibm.icu.impl.number;
  */
 public interface MicroPropsGenerator {
     /**
-     * Considers the given {@link DecimalQuantity}, optionally mutates it, and returns a {@link MicroProps}.
+     * Considers the given {@link DecimalQuantity}, optionally mutates it, and returns a
+     * {@link MicroProps}.
      *
      * @param quantity
      *            The quantity for consideration and optional mutation.
index b37e4d740fafbef536efbc4094dfc996ccf49984..a7ab9b98a890717239cabf40f639b971ab279002 100644 (file)
@@ -3,12 +3,12 @@
 package com.ibm.icu.impl.number;
 
 /**
- * A Modifier is an object that can be passed through the formatting pipeline until it is finally applied to the string
- * builder. A Modifier usually contains a prefix and a suffix that are applied, but it could contain something else,
- * like a {@link com.ibm.icu.text.SimpleFormatter} pattern.
+ * A Modifier is an object that can be passed through the formatting pipeline until it is finally applied
+ * to the string builder. A Modifier usually contains a prefix and a suffix that are applied, but it
+ * could contain something else, like a {@link com.ibm.icu.text.SimpleFormatter} pattern.
  *
- * A Modifier is usually immutable, except in cases such as {@link MutablePatternModifier}, which are mutable for performance
- * reasons.
+ * A Modifier is usually immutable, except in cases such as {@link MutablePatternModifier}, which are
+ * mutable for performance reasons.
  */
 public interface Modifier {
 
@@ -18,17 +18,18 @@ public interface Modifier {
      * @param output
      *            The string builder to which to apply this modifier.
      * @param leftIndex
-     *            The left index of the string within the builder. Equal to 0 when only one number is being formatted.
+     *            The left index of the string within the builder. Equal to 0 when only one number is
+     *            being formatted.
      * @param rightIndex
-     *            The right index of the string within the string builder. Equal to length when only one number is being
-     *            formatted.
+     *            The right index of the string within the string builder. Equal to length when only one
+     *            number is being formatted.
      * @return The number of characters (UTF-16 code units) that were added to the string builder.
      */
     public int apply(NumberStringBuilder output, int leftIndex, int rightIndex);
 
     /**
-     * Gets the length of the prefix. This information can be used in combination with {@link #apply} to extract the
-     * prefix and suffix strings.
+     * Gets the length of the prefix. This information can be used in combination with {@link #apply} to
+     * extract the prefix and suffix strings.
      *
      * @return The number of characters (UTF-16 code units) in the prefix.
      */
@@ -40,9 +41,9 @@ public interface Modifier {
     public int getCodePointCount();
 
     /**
-     * Whether this modifier is strong. If a modifier is strong, it should always be applied immediately and not allowed
-     * to bubble up. With regard to padding, strong modifiers are considered to be on the inside of the prefix and
-     * suffix.
+     * Whether this modifier is strong. If a modifier is strong, it should always be applied immediately
+     * and not allowed to bubble up. With regard to padding, strong modifiers are considered to be on the
+     * inside of the prefix and suffix.
      *
      * @return Whether the modifier is strong.
      */
index 0533ebf4e98f7a8c52ce98a505142a244f884d31..dd495d1a795007df2fbb4aba256026437703c304 100644 (file)
@@ -5,39 +5,39 @@ package com.ibm.icu.impl.number;
 import java.math.BigDecimal;
 
 public class MultiplierImpl implements MicroPropsGenerator {
-  final int magnitudeMultiplier;
-  final BigDecimal bigDecimalMultiplier;
-  final MicroPropsGenerator parent;
+    final int magnitudeMultiplier;
+    final BigDecimal bigDecimalMultiplier;
+    final MicroPropsGenerator parent;
 
-  public MultiplierImpl(int magnitudeMultiplier) {
-    this.magnitudeMultiplier = magnitudeMultiplier;
-    this.bigDecimalMultiplier = null;
-    parent = null;
-  }
+    public MultiplierImpl(int magnitudeMultiplier) {
+        this.magnitudeMultiplier = magnitudeMultiplier;
+        this.bigDecimalMultiplier = null;
+        parent = null;
+    }
 
-  public MultiplierImpl(BigDecimal bigDecimalMultiplier) {
-    this.magnitudeMultiplier = 0;
-    this.bigDecimalMultiplier = bigDecimalMultiplier;
-    parent = null;
-  }
+    public MultiplierImpl(BigDecimal bigDecimalMultiplier) {
+        this.magnitudeMultiplier = 0;
+        this.bigDecimalMultiplier = bigDecimalMultiplier;
+        parent = null;
+    }
 
-  private MultiplierImpl(MultiplierImpl base, MicroPropsGenerator parent) {
-    this.magnitudeMultiplier = base.magnitudeMultiplier;
-    this.bigDecimalMultiplier = base.bigDecimalMultiplier;
-    this.parent = parent;
-  }
+    private MultiplierImpl(MultiplierImpl base, MicroPropsGenerator parent) {
+        this.magnitudeMultiplier = base.magnitudeMultiplier;
+        this.bigDecimalMultiplier = base.bigDecimalMultiplier;
+        this.parent = parent;
+    }
 
-  public MicroPropsGenerator copyAndChain(MicroPropsGenerator parent) {
-    return new MultiplierImpl(this, parent);
-  }
+    public MicroPropsGenerator copyAndChain(MicroPropsGenerator parent) {
+        return new MultiplierImpl(this, parent);
+    }
 
-  @Override
-  public MicroProps processQuantity(DecimalQuantity quantity) {
-    MicroProps micros = parent.processQuantity(quantity);
-    quantity.adjustMagnitude(magnitudeMultiplier);
-    if (bigDecimalMultiplier != null) {
-      quantity.multiplyBy(bigDecimalMultiplier);
+    @Override
+    public MicroProps processQuantity(DecimalQuantity quantity) {
+        MicroProps micros = parent.processQuantity(quantity);
+        quantity.adjustMagnitude(magnitudeMultiplier);
+        if (bigDecimalMultiplier != null) {
+            quantity.multiplyBy(bigDecimalMultiplier);
+        }
+        return micros;
     }
-    return micros;
-  }
 }
index e39150ae832835ee62a19e611efb80849ee033d2..708481d6c98acc223c6dcb2fc29ef7e8f6b5ee42 100644 (file)
@@ -7,8 +7,9 @@ package com.ibm.icu.impl.number;
  */
 public interface MultiplierProducer {
     /**
-     * Maps a magnitude to a multiplier in powers of ten. For example, in compact notation in English, a magnitude of 5
-     * (e.g., 100,000) should return a multiplier of -3, since the number is displayed in thousands.
+     * Maps a magnitude to a multiplier in powers of ten. For example, in compact notation in English, a
+     * magnitude of 5 (e.g., 100,000) should return a multiplier of -3, since the number is displayed in
+     * thousands.
      *
      * @param magnitude
      *            The power of ten of the input number.
index df1fa909930ed426f0ef01b1667d47da8c030bc8..9f8ea1fcd27709ab9c1492f9a5daa4b7990aab70 100644 (file)
@@ -11,25 +11,27 @@ import com.ibm.icu.text.PluralRules;
 import com.ibm.icu.util.Currency;
 
 /**
- * This class is a {@link Modifier} that wraps a decimal format pattern. It applies the pattern's affixes in
- * {@link Modifier#apply}.
+ * This class is a {@link Modifier} that wraps a decimal format pattern. It applies the pattern's affixes
+ * in {@link Modifier#apply}.
  *
  * <p>
- * In addition to being a Modifier, this class contains the business logic for substituting the correct locale symbols
- * into the affixes of the decimal format pattern.
+ * In addition to being a Modifier, this class contains the business logic for substituting the correct
+ * locale symbols into the affixes of the decimal format pattern.
  *
  * <p>
- * In order to use this class, create a new instance and call the following four setters: {@link #setPatternInfo},
- * {@link #setPatternAttributes}, {@link #setSymbols}, and {@link #setNumberProperties}. After calling these four
- * setters, the instance will be ready for use as a Modifier.
+ * In order to use this class, create a new instance and call the following four setters:
+ * {@link #setPatternInfo}, {@link #setPatternAttributes}, {@link #setSymbols}, and
+ * {@link #setNumberProperties}. After calling these four setters, the instance will be ready for use as
+ * a Modifier.
  *
  * <p>
- * This is a MUTABLE, NON-THREAD-SAFE class designed for performance. Do NOT save references to this or attempt to use
- * it from multiple threads! Instead, you can obtain a safe, immutable decimal format pattern modifier by calling
- * {@link MutablePatternModifier#createImmutable}, in effect treating this instance as a builder for the immutable
- * variant.
+ * This is a MUTABLE, NON-THREAD-SAFE class designed for performance. Do NOT save references to this or
+ * attempt to use it from multiple threads! Instead, you can obtain a safe, immutable decimal format
+ * pattern modifier by calling {@link MutablePatternModifier#createImmutable}, in effect treating this
+ * instance as a builder for the immutable variant.
  */
-public class MutablePatternModifier implements Modifier, SymbolProvider, CharSequence, MicroPropsGenerator {
+public class MutablePatternModifier
+        implements Modifier, SymbolProvider, CharSequence, MicroPropsGenerator {
 
     // Modifier details
     final boolean isStrong;
@@ -62,8 +64,8 @@ public class MutablePatternModifier implements Modifier, SymbolProvider, CharSeq
     /**
      * @param isStrong
      *            Whether the modifier should be considered strong. For more information, see
-     *            {@link Modifier#isStrong()}. Most of the time, decimal format pattern modifiers should be considered
-     *            as non-strong.
+     *            {@link Modifier#isStrong()}. Most of the time, decimal format pattern modifiers should
+     *            be considered as non-strong.
      */
     public MutablePatternModifier(boolean isStrong) {
         this.isStrong = isStrong;
@@ -71,8 +73,8 @@ public class MutablePatternModifier implements Modifier, SymbolProvider, CharSeq
 
     /**
      * Sets a reference to the parsed decimal format pattern, usually obtained from
-     * {@link PatternStringParser#parseToPatternInfo(String)}, but any implementation of {@link AffixPatternProvider} is
-     * accepted.
+     * {@link PatternStringParser#parseToPatternInfo(String)}, but any implementation of
+     * {@link AffixPatternProvider} is accepted.
      */
     public void setPatternInfo(AffixPatternProvider patternInfo) {
         this.patternInfo = patternInfo;
@@ -101,10 +103,14 @@ public class MutablePatternModifier implements Modifier, SymbolProvider, CharSeq
      * @param unitWidth
      *            The width used to render currencies.
      * @param rules
-     *            Required if the triple currency sign, "¤¤¤", appears in the pattern, which can be determined from the
-     *            convenience method {@link #needsPlurals()}.
+     *            Required if the triple currency sign, "¤¤¤", appears in the pattern, which can be
+     *            determined from the convenience method {@link #needsPlurals()}.
      */
-    public void setSymbols(DecimalFormatSymbols symbols, Currency currency, UnitWidth unitWidth, PluralRules rules) {
+    public void setSymbols(
+            DecimalFormatSymbols symbols,
+            Currency currency,
+            UnitWidth unitWidth,
+            PluralRules rules) {
         assert (rules != null) == needsPlurals();
         this.symbols = symbols;
         this.currency = currency;
@@ -118,8 +124,8 @@ public class MutablePatternModifier implements Modifier, SymbolProvider, CharSeq
      * @param isNegative
      *            Whether the number is negative.
      * @param plural
-     *            The plural form of the number, required only if the pattern contains the triple currency sign, "¤¤¤"
-     *            (and as indicated by {@link #needsPlurals()}).
+     *            The plural form of the number, required only if the pattern contains the triple
+     *            currency sign, "¤¤¤" (and as indicated by {@link #needsPlurals()}).
      */
     public void setNumberProperties(boolean isNegative, StandardPlural plural) {
         assert (plural != null) == needsPlurals();
@@ -128,17 +134,18 @@ public class MutablePatternModifier implements Modifier, SymbolProvider, CharSeq
     }
 
     /**
-     * Returns true if the pattern represented by this MurkyModifier requires a plural keyword in order to localize.
-     * This is currently true only if there is a currency long name placeholder in the pattern ("¤¤¤").
+     * Returns true if the pattern represented by this MurkyModifier requires a plural keyword in order
+     * to localize. This is currently true only if there is a currency long name placeholder in the
+     * pattern ("¤¤¤").
      */
     public boolean needsPlurals() {
         return patternInfo.containsSymbolType(AffixUtils.TYPE_CURRENCY_TRIPLE);
     }
 
     /**
-     * Creates a new quantity-dependent Modifier that behaves the same as the current instance, but which is immutable
-     * and can be saved for future use. The number properties in the current instance are mutated; all other properties
-     * are left untouched.
+     * Creates a new quantity-dependent Modifier that behaves the same as the current instance, but which
+     * is immutable and can be saved for future use. The number properties in the current instance are
+     * mutated; all other properties are left untouched.
      *
      * <p>
      * The resulting modifier cannot be used in a QuantityChain.
@@ -150,9 +157,9 @@ public class MutablePatternModifier implements Modifier, SymbolProvider, CharSeq
     }
 
     /**
-     * Creates a new quantity-dependent Modifier that behaves the same as the current instance, but which is immutable
-     * and can be saved for future use. The number properties in the current instance are mutated; all other properties
-     * are left untouched.
+     * Creates a new quantity-dependent Modifier that behaves the same as the current instance, but which
+     * is immutable and can be saved for future use. The number properties in the current instance are
+     * mutated; all other properties are left untouched.
      *
      * @param parent
      *            The QuantityChain to which to chain this immutable.
@@ -184,17 +191,19 @@ public class MutablePatternModifier implements Modifier, SymbolProvider, CharSeq
     }
 
     /**
-     * Uses the current properties to create a single {@link ConstantMultiFieldModifier} with currency spacing support
-     * if required.
+     * Uses the current properties to create a single {@link ConstantMultiFieldModifier} with currency
+     * spacing support if required.
      *
      * @param a
-     *            A working NumberStringBuilder object; passed from the outside to prevent the need to create many new
-     *            instances if this method is called in a loop.
+     *            A working NumberStringBuilder object; passed from the outside to prevent the need to
+     *            create many new instances if this method is called in a loop.
      * @param b
      *            Another working NumberStringBuilder object.
      * @return The constant modifier object.
      */
-    private ConstantMultiFieldModifier createConstantModifier(NumberStringBuilder a, NumberStringBuilder b) {
+    private ConstantMultiFieldModifier createConstantModifier(
+            NumberStringBuilder a,
+            NumberStringBuilder b) {
         insertPrefix(a.clear(), 0);
         insertSuffix(b.clear(), 0);
         if (patternInfo.hasCurrencySign()) {
@@ -209,7 +218,10 @@ public class MutablePatternModifier implements Modifier, SymbolProvider, CharSeq
         final PluralRules rules;
         final MicroPropsGenerator parent;
 
-        ImmutablePatternModifier(ParameterizedModifier pm, PluralRules rules, MicroPropsGenerator parent) {
+        ImmutablePatternModifier(
+                ParameterizedModifier pm,
+                PluralRules rules,
+                MicroPropsGenerator parent) {
             this.pm = pm;
             this.rules = rules;
             this.parent = parent;
@@ -260,8 +272,12 @@ public class MutablePatternModifier implements Modifier, SymbolProvider, CharSeq
     public int apply(NumberStringBuilder output, int leftIndex, int rightIndex) {
         int prefixLen = insertPrefix(output, leftIndex);
         int suffixLen = insertSuffix(output, rightIndex + prefixLen);
-        CurrencySpacingEnabledModifier.applyCurrencySpacing(output, leftIndex, prefixLen, rightIndex + prefixLen,
-                suffixLen, symbols);
+        CurrencySpacingEnabledModifier.applyCurrencySpacing(output,
+                leftIndex,
+                prefixLen,
+                rightIndex + prefixLen,
+                suffixLen,
+                symbols);
         return prefixLen + suffixLen;
     }
 
@@ -269,7 +285,7 @@ public class MutablePatternModifier implements Modifier, SymbolProvider, CharSeq
     public int getPrefixLength() {
         // Enter and exit CharSequence Mode to get the length.
         enterCharSequenceMode(true);
-        int result = AffixUtils.unescapedCodePointCount(this, this);  // prefix length
+        int result = AffixUtils.unescapedCodePointCount(this, this); // prefix length
         exitCharSequenceMode();
         return result;
     }
@@ -278,10 +294,10 @@ public class MutablePatternModifier implements Modifier, SymbolProvider, CharSeq
     public int getCodePointCount() {
         // Enter and exit CharSequence Mode to get the length.
         enterCharSequenceMode(true);
-        int result = AffixUtils.unescapedCodePointCount(this, this);  // prefix length
+        int result = AffixUtils.unescapedCodePointCount(this, this); // prefix length
         exitCharSequenceMode();
         enterCharSequenceMode(false);
-        result += AffixUtils.unescapedCodePointCount(this, this);  // suffix length
+        result += AffixUtils.unescapedCodePointCount(this, this); // suffix length
         exitCharSequenceMode();
         return result;
     }
@@ -337,7 +353,8 @@ public class MutablePatternModifier implements Modifier, SymbolProvider, CharSeq
             // Plural currencies set via the API are formatted in LongNameHandler.
             // This code path is used by DecimalFormat via CurrencyPluralInfo.
             assert plural != null;
-            return currency.getName(symbols.getULocale(), Currency.PLURAL_LONG_NAME, plural.getKeyword(), null);
+            return currency
+                    .getName(symbols.getULocale(), Currency.PLURAL_LONG_NAME, plural.getKeyword(), null);
         case AffixUtils.TYPE_CURRENCY_QUAD:
             return "\uFFFD";
         case AffixUtils.TYPE_CURRENCY_QUINT:
@@ -357,7 +374,8 @@ public class MutablePatternModifier implements Modifier, SymbolProvider, CharSeq
                 && (signDisplay == SignDisplay.ALWAYS || signDisplay == SignDisplay.ACCOUNTING_ALWAYS)
                 && patternInfo.positiveHasPlusSign() == false;
 
-        // Should we use the affix from the negative subpattern? (If not, we will use the positive subpattern.)
+        // Should we use the affix from the negative subpattern? (If not, we will use the positive
+        // subpattern.)
         boolean useNegativeAffixPattern = patternInfo.hasNegativeSubpattern()
                 && (isNegative || (patternInfo.negativeHasMinusSign() && plusReplacesMinusSign));
 
index c1be7034d4c81596bf70cf6827195b8806e9ffeb..efb4cec0951f1ab80bdffa3b08e00307fff1ab99 100644 (file)
@@ -6,40 +6,37 @@ public class Padder {
     public static final String FALLBACK_PADDING_STRING = "\u0020"; // i.e. a space
 
     public enum PadPosition {
-      BEFORE_PREFIX,
-      AFTER_PREFIX,
-      BEFORE_SUFFIX,
-      AFTER_SUFFIX;
+        BEFORE_PREFIX, AFTER_PREFIX, BEFORE_SUFFIX, AFTER_SUFFIX;
 
-      public static PadPosition fromOld(int old) {
-        switch (old) {
-          case com.ibm.icu.text.DecimalFormat.PAD_BEFORE_PREFIX:
-            return PadPosition.BEFORE_PREFIX;
-          case com.ibm.icu.text.DecimalFormat.PAD_AFTER_PREFIX:
-            return PadPosition.AFTER_PREFIX;
-          case com.ibm.icu.text.DecimalFormat.PAD_BEFORE_SUFFIX:
-            return PadPosition.BEFORE_SUFFIX;
-          case com.ibm.icu.text.DecimalFormat.PAD_AFTER_SUFFIX:
-            return PadPosition.AFTER_SUFFIX;
-          default:
-            throw new IllegalArgumentException("Don't know how to map " + old);
+        public static PadPosition fromOld(int old) {
+            switch (old) {
+            case com.ibm.icu.text.DecimalFormat.PAD_BEFORE_PREFIX:
+                return PadPosition.BEFORE_PREFIX;
+            case com.ibm.icu.text.DecimalFormat.PAD_AFTER_PREFIX:
+                return PadPosition.AFTER_PREFIX;
+            case com.ibm.icu.text.DecimalFormat.PAD_BEFORE_SUFFIX:
+                return PadPosition.BEFORE_SUFFIX;
+            case com.ibm.icu.text.DecimalFormat.PAD_AFTER_SUFFIX:
+                return PadPosition.AFTER_SUFFIX;
+            default:
+                throw new IllegalArgumentException("Don't know how to map " + old);
+            }
         }
-      }
 
-      public int toOld() {
-        switch (this) {
-          case BEFORE_PREFIX:
-            return com.ibm.icu.text.DecimalFormat.PAD_BEFORE_PREFIX;
-          case AFTER_PREFIX:
-            return com.ibm.icu.text.DecimalFormat.PAD_AFTER_PREFIX;
-          case BEFORE_SUFFIX:
-            return com.ibm.icu.text.DecimalFormat.PAD_BEFORE_SUFFIX;
-          case AFTER_SUFFIX:
-            return com.ibm.icu.text.DecimalFormat.PAD_AFTER_SUFFIX;
-          default:
-            return -1; // silence compiler errors
+        public int toOld() {
+            switch (this) {
+            case BEFORE_PREFIX:
+                return com.ibm.icu.text.DecimalFormat.PAD_BEFORE_PREFIX;
+            case AFTER_PREFIX:
+                return com.ibm.icu.text.DecimalFormat.PAD_AFTER_PREFIX;
+            case BEFORE_SUFFIX:
+                return com.ibm.icu.text.DecimalFormat.PAD_BEFORE_SUFFIX;
+            case AFTER_SUFFIX:
+                return com.ibm.icu.text.DecimalFormat.PAD_AFTER_SUFFIX;
+            default:
+                return -1; // silence compiler errors
+            }
         }
-      }
     }
 
     /* like package-private */ public static final Padder NONE = new Padder(null, -1, null);
@@ -73,10 +70,16 @@ public class Padder {
         return targetWidth > 0;
     }
 
-    public int padAndApply(Modifier mod1, Modifier mod2, NumberStringBuilder string, int leftIndex, int rightIndex) {
+    public int padAndApply(
+            Modifier mod1,
+            Modifier mod2,
+            NumberStringBuilder string,
+            int leftIndex,
+            int rightIndex) {
         int modLength = mod1.getCodePointCount() + mod2.getCodePointCount();
         int requiredPadding = targetWidth - modLength - string.codePointCount();
-        assert leftIndex == 0 && rightIndex == string.length(); // fix the previous line to remove this assertion
+        assert leftIndex == 0 && rightIndex == string.length(); // fix the previous line to remove this
+                                                                // assertion
 
         int length = 0;
         if (requiredPadding <= 0) {
@@ -102,7 +105,10 @@ public class Padder {
         return length;
     }
 
-    private static int addPaddingHelper(String paddingString, int requiredPadding, NumberStringBuilder string,
+    private static int addPaddingHelper(
+            String paddingString,
+            int requiredPadding,
+            NumberStringBuilder string,
             int index) {
         for (int i = 0; i < requiredPadding; i++) {
             // TODO: If appending to the end, this will cause actual insertion operations. Improve.
index 5a7191af67cd090428cf2f0467b14851813f19e4..3ccf5080490f9d0b1fcd3d0b10bf37e9efee60e1 100644 (file)
@@ -5,8 +5,8 @@ package com.ibm.icu.impl.number;
 import com.ibm.icu.impl.StandardPlural;
 
 /**
- * A ParameterizedModifier by itself is NOT a Modifier. Rather, it wraps a data structure containing two or more
- * Modifiers and returns the modifier appropriate for the current situation.
+ * A ParameterizedModifier by itself is NOT a Modifier. Rather, it wraps a data structure containing two
+ * or more Modifiers and returns the modifier appropriate for the current situation.
  */
 public class ParameterizedModifier {
     private final Modifier positive;
@@ -28,8 +28,8 @@ public class ParameterizedModifier {
     }
 
     /**
-     * This constructor prepares the ParameterizedModifier to be populated with a positive and negative Modifier for
-     * multiple plural forms.
+     * This constructor prepares the ParameterizedModifier to be populated with a positive and negative
+     * Modifier for multiple plural forms.
      *
      * <p>
      * If this constructor is used, a plural form MUST be passed to {@link #getModifier}.
index 50336bc09b76768d091a2e6e498192e123c6393f..80c2c23e104a7f476b28e427c2f6c7bc2a4af3ac 100644 (file)
@@ -12,8 +12,8 @@ public class PatternStringParser {
     public static final int IGNORE_ROUNDING_ALWAYS = 2;
 
     /**
-     * Runs the recursive descent parser on the given pattern string, returning a data structure with raw information
-     * about the pattern string.
+     * Runs the recursive descent parser on the given pattern string, returning a data structure with raw
+     * information about the pattern string.
      *
      * <p>
      * To obtain a more useful form of the data, consider using {@link #parseToProperties} instead.
@@ -35,9 +35,10 @@ public class PatternStringParser {
      * @param pattern
      *            The pattern string, like "#,##0.00"
      * @param ignoreRounding
-     *            Whether to leave out rounding information (minFrac, maxFrac, and rounding increment) when parsing the
-     *            pattern. This may be desirable if a custom rounding mode, such as CurrencyUsage, is to be used
-     *            instead. One of {@link PatternStringParser#IGNORE_ROUNDING_ALWAYS},
+     *            Whether to leave out rounding information (minFrac, maxFrac, and rounding increment)
+     *            when parsing the pattern. This may be desirable if a custom rounding mode, such as
+     *            CurrencyUsage, is to be used instead. One of
+     *            {@link PatternStringParser#IGNORE_ROUNDING_ALWAYS},
      *            {@link PatternStringParser#IGNORE_ROUNDING_IF_CURRENCY}, or
      *            {@link PatternStringParser#IGNORE_ROUNDING_NEVER}.
      * @return A property bag object.
@@ -55,9 +56,10 @@ public class PatternStringParser {
     }
 
     /**
-     * Parses a pattern string into an existing property bag. All properties that can be encoded into a pattern string
-     * will be overwritten with either their default value or with the value coming from the pattern string. Properties
-     * that cannot be encoded into a pattern string, such as rounding mode, are not modified.
+     * Parses a pattern string into an existing property bag. All properties that can be encoded into a
+     * pattern string will be overwritten with either their default value or with the value coming from
+     * the pattern string. Properties that cannot be encoded into a pattern string, such as rounding
+     * mode, are not modified.
      *
      * @param pattern
      *            The pattern string, like "#,##0.00"
@@ -68,7 +70,9 @@ public class PatternStringParser {
      * @throws IllegalArgumentException
      *             If there was a syntax error in the pattern string.
      */
-    public static void parseToExistingProperties(String pattern, DecimalFormatProperties properties,
+    public static void parseToExistingProperties(
+            String pattern,
+            DecimalFormatProperties properties,
             int ignoreRounding) {
         parseToExistingPropertiesImpl(pattern, properties, ignoreRounding);
     }
@@ -262,7 +266,10 @@ public class PatternStringParser {
         consumePadding(state, result, PadPosition.AFTER_SUFFIX);
     }
 
-    private static void consumePadding(ParserState state, ParsedSubpatternInfo result, PadPosition paddingLocation) {
+    private static void consumePadding(
+            ParserState state,
+            ParsedSubpatternInfo result,
+            PadPosition paddingLocation) {
         if (state.peek() != '*') {
             return;
         }
@@ -504,7 +511,10 @@ public class PatternStringParser {
     /// END RECURSIVE DESCENT PARSER IMPLEMENTATION ///
     ///////////////////////////////////////////////////
 
-    private static void parseToExistingPropertiesImpl(String pattern, DecimalFormatProperties properties, int ignoreRounding) {
+    private static void parseToExistingPropertiesImpl(
+            String pattern,
+            DecimalFormatProperties properties,
+            int ignoreRounding) {
         if (pattern == null || pattern.length() == 0) {
             // Backwards compatibility requires that we reset to the default values.
             // TODO: Only overwrite the properties that "saveToProperties" normally touches?
@@ -518,7 +528,9 @@ public class PatternStringParser {
     }
 
     /** Finalizes the temporary data stored in the ParsedPatternInfo to the Properties. */
-    private static void patternInfoToProperties(DecimalFormatProperties properties, ParsedPatternInfo patternInfo,
+    private static void patternInfoToProperties(
+            DecimalFormatProperties properties,
+            ParsedPatternInfo patternInfo,
             int _ignoreRounding) {
         // Translate from PatternParseResult to Properties.
         // Note that most data from "negative" is ignored per the specification of DecimalFormat.
@@ -572,12 +584,14 @@ public class PatternStringParser {
             properties.setMaximumFractionDigits(-1);
             properties.setRoundingIncrement(null);
             properties.setMinimumSignificantDigits(positive.integerAtSigns);
-            properties.setMaximumSignificantDigits(positive.integerAtSigns + positive.integerTrailingHashSigns);
+            properties.setMaximumSignificantDigits(
+                    positive.integerAtSigns + positive.integerTrailingHashSigns);
         } else if (positive.rounding != null) {
             if (!ignoreRounding) {
                 properties.setMinimumFractionDigits(minFrac);
                 properties.setMaximumFractionDigits(positive.fractionTotal);
-                properties.setRoundingIncrement(positive.rounding.toBigDecimal().setScale(positive.fractionNumerals));
+                properties.setRoundingIncrement(
+                        positive.rounding.toBigDecimal().setScale(positive.fractionNumerals));
             } else {
                 properties.setMinimumFractionDigits(-1);
                 properties.setMaximumFractionDigits(-1);
@@ -633,7 +647,8 @@ public class PatternStringParser {
         // Padding settings
         if (positive.paddingLocation != null) {
             // The width of the positive prefix and suffix templates are included in the padding
-            int paddingWidth = positive.widthExceptAffixes + AffixUtils.estimateLength(posPrefix)
+            int paddingWidth = positive.widthExceptAffixes
+                    + AffixUtils.estimateLength(posPrefix)
                     + AffixUtils.estimateLength(posSuffix);
             properties.setFormatWidth(paddingWidth);
             String rawPaddingString = patternInfo.getString(AffixPatternProvider.Flags.PADDING);
@@ -662,9 +677,10 @@ public class PatternStringParser {
         properties.setPositivePrefixPattern(posPrefix);
         properties.setPositiveSuffixPattern(posSuffix);
         if (patternInfo.negative != null) {
-            properties.setNegativePrefixPattern(patternInfo
-                    .getString(AffixPatternProvider.Flags.NEGATIVE_SUBPATTERN | AffixPatternProvider.Flags.PREFIX));
-            properties.setNegativeSuffixPattern(patternInfo.getString(AffixPatternProvider.Flags.NEGATIVE_SUBPATTERN));
+            properties.setNegativePrefixPattern(patternInfo.getString(
+                    AffixPatternProvider.Flags.NEGATIVE_SUBPATTERN | AffixPatternProvider.Flags.PREFIX));
+            properties.setNegativeSuffixPattern(
+                    patternInfo.getString(AffixPatternProvider.Flags.NEGATIVE_SUBPATTERN));
         } else {
             properties.setNegativePrefixPattern(null);
             properties.setNegativeSuffixPattern(null);
index 4bed35f1f56d71b74d33216d613acdce17c0a6ef..7a16b5e5230ec43704f9f1bb10eb3540c7505e51 100644 (file)
@@ -16,8 +16,9 @@ public class PatternStringUtils {
      * Creates a pattern string from a property bag.
      *
      * <p>
-     * Since pattern strings support only a subset of the functionality available in a property bag, a new property bag
-     * created from the string returned by this function may not be the same as the original property bag.
+     * Since pattern strings support only a subset of the functionality available in a property bag, a
+     * new property bag created from the string returned by this function may not be the same as the
+     * original property bag.
      *
      * @param properties
      *            The property bag to serialize.
@@ -61,7 +62,8 @@ public class PatternStringUtils {
 
         // Figure out the grouping sizes.
         int grouping1, grouping2, grouping;
-        if (groupingSize != Math.min(dosMax, -1) && firstGroupingSize != Math.min(dosMax, -1)
+        if (groupingSize != Math.min(dosMax, -1)
+                && firstGroupingSize != Math.min(dosMax, -1)
                 && groupingSize != firstGroupingSize) {
             grouping = groupingSize;
             grouping1 = groupingSize;
@@ -184,7 +186,9 @@ public class PatternStringUtils {
 
         // Negative affixes
         // Ignore if the negative prefix pattern is "-" and the negative suffix is empty
-        if (np != null || ns != null || (npp == null && nsp != null)
+        if (np != null
+                || ns != null
+                || (npp == null && nsp != null)
                 || (npp != null && (npp.length() != 1 || npp.charAt(0) != '-' || nsp.length() != 0))) {
             sb.append(';');
             if (npp != null)
@@ -232,14 +236,15 @@ public class PatternStringUtils {
     }
 
     /**
-     * Converts a pattern between standard notation and localized notation. Localized notation means that instead of
-     * using generic placeholders in the pattern, you use the corresponding locale-specific characters instead. For
-     * example, in locale <em>fr-FR</em>, the period in the pattern "0.000" means "decimal" in standard notation (as it
-     * does in every other locale), but it means "grouping" in localized notation.
+     * Converts a pattern between standard notation and localized notation. Localized notation means that
+     * instead of using generic placeholders in the pattern, you use the corresponding locale-specific
+     * characters instead. For example, in locale <em>fr-FR</em>, the period in the pattern "0.000" means
+     * "decimal" in standard notation (as it does in every other locale), but it means "grouping" in
+     * localized notation.
      *
      * <p>
-     * A greedy string-substitution strategy is used to substitute locale symbols. If two symbols are ambiguous or have
-     * the same prefix, the result is not well-defined.
+     * A greedy string-substitution strategy is used to substitute locale symbols. If two symbols are
+     * ambiguous or have the same prefix, the result is not well-defined.
      *
      * <p>
      * Locale symbols are not allowed to contain the ASCII quote character.
@@ -252,11 +257,14 @@ public class PatternStringUtils {
      * @param symbols
      *            The symbols corresponding to the localized pattern.
      * @param toLocalized
-     *            true to convert from standard to localized notation; false to convert from localized to standard
-     *            notation.
+     *            true to convert from standard to localized notation; false to convert from localized to
+     *            standard notation.
      * @return The pattern expressed in the other notation.
      */
-    public static String convertLocalized(String input, DecimalFormatSymbols symbols, boolean toLocalized) {
+    public static String convertLocalized(
+            String input,
+            DecimalFormatSymbols symbols,
+            boolean toLocalized) {
         if (input == null)
             return null;
 
index bb635cdc70ae8d5f44fd9f55376f5d29cffce79d..59197b6a3bc087fdb01933faf2f6ae23e6c63110 100644 (file)
@@ -8,8 +8,8 @@ import java.io.ObjectOutputStream;
 import java.io.Serializable;
 
 /**
- * ICU 59 called the class DecimalFormatProperties as just Properties. We need to keep a thin implementation for the
- * purposes of serialization.
+ * ICU 59 called the class DecimalFormatProperties as just Properties. We need to keep a thin
+ * implementation for the purposes of serialization.
  */
 public class Properties implements Serializable {
 
index 0c97552c487250e178d3fd113632cb6198538ca2..9098d8c6aa2ac0ab34a6ae3dadab91752bcfa6a7 100644 (file)
@@ -9,177 +9,193 @@ import java.math.RoundingMode;
 /** @author sffc */
 public class RoundingUtils {
 
-  public static final int SECTION_LOWER = 1;
-  public static final int SECTION_MIDPOINT = 2;
-  public static final int SECTION_UPPER = 3;
-
-  /**
-   * The default rounding mode.
-   */
-  public static final RoundingMode DEFAULT_ROUNDING_MODE = RoundingMode.HALF_EVEN;
-
-  /**
-   * The maximum number of fraction places, integer numerals, or significant digits.
-   * TODO: This does not feel like the best home for this value.
-   */
-  public static final int MAX_INT_FRAC_SIG = 100;
-
-  /**
-   * Converts a rounding mode and metadata about the quantity being rounded to a boolean determining
-   * whether the value should be rounded toward infinity or toward zero.
-   *
-   * <p>The parameters are of type int because benchmarks on an x86-64 processor against OpenJDK
-   * showed that ints were demonstrably faster than enums in switch statements.
-   *
-   * @param isEven Whether the digit immediately before the rounding magnitude is even.
-   * @param isNegative Whether the quantity is negative.
-   * @param section Whether the part of the quantity to the right of the rounding magnitude is
-   *     exactly halfway between two digits, whether it is in the lower part (closer to zero), or
-   *     whether it is in the upper part (closer to infinity). See {@link #SECTION_LOWER}, {@link
-   *     #SECTION_MIDPOINT}, and {@link #SECTION_UPPER}.
-   * @param roundingMode The integer version of the {@link RoundingMode}, which you can get via
-   *     {@link RoundingMode#ordinal}.
-   * @param reference A reference object to be used when throwing an ArithmeticException.
-   * @return true if the number should be rounded toward zero; false if it should be rounded toward
-   *     infinity.
-   */
-  public static boolean getRoundingDirection(
-      boolean isEven, boolean isNegative, int section, int roundingMode, Object reference) {
-    switch (roundingMode) {
-      case BigDecimal.ROUND_UP:
-        // round away from zero
-        return false;
-
-      case BigDecimal.ROUND_DOWN:
-        // round toward zero
-        return true;
-
-      case BigDecimal.ROUND_CEILING:
-        // round toward positive infinity
-        return isNegative;
-
-      case BigDecimal.ROUND_FLOOR:
-        // round toward negative infinity
-        return !isNegative;
-
-      case BigDecimal.ROUND_HALF_UP:
-        switch (section) {
-          case SECTION_MIDPOINT:
+    public static final int SECTION_LOWER = 1;
+    public static final int SECTION_MIDPOINT = 2;
+    public static final int SECTION_UPPER = 3;
+
+    /**
+     * The default rounding mode.
+     */
+    public static final RoundingMode DEFAULT_ROUNDING_MODE = RoundingMode.HALF_EVEN;
+
+    /**
+     * The maximum number of fraction places, integer numerals, or significant digits. TODO: This does
+     * not feel like the best home for this value.
+     */
+    public static final int MAX_INT_FRAC_SIG = 100;
+
+    /**
+     * Converts a rounding mode and metadata about the quantity being rounded to a boolean determining
+     * whether the value should be rounded toward infinity or toward zero.
+     *
+     * <p>
+     * The parameters are of type int because benchmarks on an x86-64 processor against OpenJDK showed
+     * that ints were demonstrably faster than enums in switch statements.
+     *
+     * @param isEven
+     *            Whether the digit immediately before the rounding magnitude is even.
+     * @param isNegative
+     *            Whether the quantity is negative.
+     * @param section
+     *            Whether the part of the quantity to the right of the rounding magnitude is exactly
+     *            halfway between two digits, whether it is in the lower part (closer to zero), or
+     *            whether it is in the upper part (closer to infinity). See {@link #SECTION_LOWER},
+     *            {@link #SECTION_MIDPOINT}, and {@link #SECTION_UPPER}.
+     * @param roundingMode
+     *            The integer version of the {@link RoundingMode}, which you can get via
+     *            {@link RoundingMode#ordinal}.
+     * @param reference
+     *            A reference object to be used when throwing an ArithmeticException.
+     * @return true if the number should be rounded toward zero; false if it should be rounded toward
+     *         infinity.
+     */
+    public static boolean getRoundingDirection(
+            boolean isEven,
+            boolean isNegative,
+            int section,
+            int roundingMode,
+            Object reference) {
+        switch (roundingMode) {
+        case BigDecimal.ROUND_UP:
+            // round away from zero
             return false;
-          case SECTION_LOWER:
+
+        case BigDecimal.ROUND_DOWN:
+            // round toward zero
             return true;
-          case SECTION_UPPER:
-            return false;
+
+        case BigDecimal.ROUND_CEILING:
+            // round toward positive infinity
+            return isNegative;
+
+        case BigDecimal.ROUND_FLOOR:
+            // round toward negative infinity
+            return !isNegative;
+
+        case BigDecimal.ROUND_HALF_UP:
+            switch (section) {
+            case SECTION_MIDPOINT:
+                return false;
+            case SECTION_LOWER:
+                return true;
+            case SECTION_UPPER:
+                return false;
+            }
+            break;
+
+        case BigDecimal.ROUND_HALF_DOWN:
+            switch (section) {
+            case SECTION_MIDPOINT:
+                return true;
+            case SECTION_LOWER:
+                return true;
+            case SECTION_UPPER:
+                return false;
+            }
+            break;
+
+        case BigDecimal.ROUND_HALF_EVEN:
+            switch (section) {
+            case SECTION_MIDPOINT:
+                return isEven;
+            case SECTION_LOWER:
+                return true;
+            case SECTION_UPPER:
+                return false;
+            }
+            break;
         }
-        break;
 
-      case BigDecimal.ROUND_HALF_DOWN:
-        switch (section) {
-          case SECTION_MIDPOINT:
-            return true;
-          case SECTION_LOWER:
-            return true;
-          case SECTION_UPPER:
+        // Rounding mode UNNECESSARY
+        throw new ArithmeticException("Rounding is required on " + reference.toString());
+    }
+
+    /**
+     * Gets whether the given rounding mode's rounding boundary is at the midpoint. The rounding boundary
+     * is the point at which a number switches from being rounded down to being rounded up. For example,
+     * with rounding mode HALF_EVEN, HALF_UP, or HALF_DOWN, the rounding boundary is at the midpoint, and
+     * this function would return true. However, for UP, DOWN, CEILING, and FLOOR, the rounding boundary
+     * is at the "edge", and this function would return false.
+     *
+     * @param roundingMode
+     *            The integer version of the {@link RoundingMode}.
+     * @return true if rounding mode is HALF_EVEN, HALF_UP, or HALF_DOWN; false otherwise.
+     */
+    public static boolean roundsAtMidpoint(int roundingMode) {
+        switch (roundingMode) {
+        case BigDecimal.ROUND_UP:
+        case BigDecimal.ROUND_DOWN:
+        case BigDecimal.ROUND_CEILING:
+        case BigDecimal.ROUND_FLOOR:
             return false;
-        }
-        break;
 
-      case BigDecimal.ROUND_HALF_EVEN:
-        switch (section) {
-          case SECTION_MIDPOINT:
-            return isEven;
-          case SECTION_LOWER:
+        default:
             return true;
-          case SECTION_UPPER:
-            return false;
         }
-        break;
     }
 
-    // Rounding mode UNNECESSARY
-    throw new ArithmeticException("Rounding is required on " + reference.toString());
-  }
-
-  /**
-   * Gets whether the given rounding mode's rounding boundary is at the midpoint. The rounding
-   * boundary is the point at which a number switches from being rounded down to being rounded up.
-   * For example, with rounding mode HALF_EVEN, HALF_UP, or HALF_DOWN, the rounding boundary is at
-   * the midpoint, and this function would return true. However, for UP, DOWN, CEILING, and FLOOR,
-   * the rounding boundary is at the "edge", and this function would return false.
-   *
-   * @param roundingMode The integer version of the {@link RoundingMode}.
-   * @return true if rounding mode is HALF_EVEN, HALF_UP, or HALF_DOWN; false otherwise.
-   */
-  public static boolean roundsAtMidpoint(int roundingMode) {
-    switch (roundingMode) {
-      case BigDecimal.ROUND_UP:
-      case BigDecimal.ROUND_DOWN:
-      case BigDecimal.ROUND_CEILING:
-      case BigDecimal.ROUND_FLOOR:
-        return false;
-
-      default:
-        return true;
-    }
-  }
+    private static final MathContext[] MATH_CONTEXT_BY_ROUNDING_MODE_UNLIMITED = new MathContext[RoundingMode
+            .values().length];
 
-  private static final MathContext[] MATH_CONTEXT_BY_ROUNDING_MODE_UNLIMITED =
-      new MathContext[RoundingMode.values().length];
+    private static final MathContext[] MATH_CONTEXT_BY_ROUNDING_MODE_34_DIGITS = new MathContext[RoundingMode
+            .values().length];
 
-  private static final MathContext[] MATH_CONTEXT_BY_ROUNDING_MODE_34_DIGITS =
-      new MathContext[RoundingMode.values().length];
+    static {
+        for (int i = 0; i < MATH_CONTEXT_BY_ROUNDING_MODE_34_DIGITS.length; i++) {
+            MATH_CONTEXT_BY_ROUNDING_MODE_UNLIMITED[i] = new MathContext(0, RoundingMode.valueOf(i));
+            MATH_CONTEXT_BY_ROUNDING_MODE_34_DIGITS[i] = new MathContext(34);
+        }
+    }
 
-  static {
-    for (int i = 0; i < MATH_CONTEXT_BY_ROUNDING_MODE_34_DIGITS.length; i++) {
-      MATH_CONTEXT_BY_ROUNDING_MODE_UNLIMITED[i] = new MathContext(0, RoundingMode.valueOf(i));
-      MATH_CONTEXT_BY_ROUNDING_MODE_34_DIGITS[i] = new MathContext(34);
+    /**
+     * Gets the user-specified math context out of the property bag. If there is none, falls back to a
+     * math context with unlimited precision and the user-specified rounding mode, which defaults to
+     * HALF_EVEN (the IEEE 754R default).
+     *
+     * @param properties
+     *            The property bag.
+     * @return A {@link MathContext}. Never null.
+     */
+    public static MathContext getMathContextOrUnlimited(DecimalFormatProperties properties) {
+        MathContext mathContext = properties.getMathContext();
+        if (mathContext == null) {
+            RoundingMode roundingMode = properties.getRoundingMode();
+            if (roundingMode == null)
+                roundingMode = RoundingMode.HALF_EVEN;
+            mathContext = MATH_CONTEXT_BY_ROUNDING_MODE_UNLIMITED[roundingMode.ordinal()];
+        }
+        return mathContext;
     }
-  }
-
-  /**
-   * Gets the user-specified math context out of the property bag. If there is none, falls back to a
-   * math context with unlimited precision and the user-specified rounding mode, which defaults to
-   * HALF_EVEN (the IEEE 754R default).
-   *
-   * @param properties The property bag.
-   * @return A {@link MathContext}. Never null.
-   */
-  public static MathContext getMathContextOrUnlimited(DecimalFormatProperties properties) {
-    MathContext mathContext = properties.getMathContext();
-    if (mathContext == null) {
-      RoundingMode roundingMode = properties.getRoundingMode();
-      if (roundingMode == null) roundingMode = RoundingMode.HALF_EVEN;
-      mathContext = MATH_CONTEXT_BY_ROUNDING_MODE_UNLIMITED[roundingMode.ordinal()];
+
+    /**
+     * Gets the user-specified math context out of the property bag. If there is none, falls back to a
+     * math context with 34 digits of precision (the 128-bit IEEE 754R default) and the user-specified
+     * rounding mode, which defaults to HALF_EVEN (the IEEE 754R default).
+     *
+     * @param properties
+     *            The property bag.
+     * @return A {@link MathContext}. Never null.
+     */
+    public static MathContext getMathContextOr34Digits(DecimalFormatProperties properties) {
+        MathContext mathContext = properties.getMathContext();
+        if (mathContext == null) {
+            RoundingMode roundingMode = properties.getRoundingMode();
+            if (roundingMode == null)
+                roundingMode = RoundingMode.HALF_EVEN;
+            mathContext = MATH_CONTEXT_BY_ROUNDING_MODE_34_DIGITS[roundingMode.ordinal()];
+        }
+        return mathContext;
     }
-    return mathContext;
-  }
-
-  /**
-   * Gets the user-specified math context out of the property bag. If there is none, falls back to a
-   * math context with 34 digits of precision (the 128-bit IEEE 754R default) and the user-specified
-   * rounding mode, which defaults to HALF_EVEN (the IEEE 754R default).
-   *
-   * @param properties The property bag.
-   * @return A {@link MathContext}. Never null.
-   */
-  public static MathContext getMathContextOr34Digits(DecimalFormatProperties properties) {
-    MathContext mathContext = properties.getMathContext();
-    if (mathContext == null) {
-      RoundingMode roundingMode = properties.getRoundingMode();
-      if (roundingMode == null) roundingMode = RoundingMode.HALF_EVEN;
-      mathContext = MATH_CONTEXT_BY_ROUNDING_MODE_34_DIGITS[roundingMode.ordinal()];
+
+    /**
+     * Gets a MathContext with unlimited precision and the specified RoundingMode. Equivalent to "new
+     * MathContext(0, roundingMode)", but pulls from a singleton to prevent object thrashing.
+     *
+     * @param roundingMode
+     *            The {@link RoundingMode} to use.
+     * @return The corresponding {@link MathContext}.
+     */
+    public static MathContext mathContextUnlimited(RoundingMode roundingMode) {
+        return MATH_CONTEXT_BY_ROUNDING_MODE_UNLIMITED[roundingMode.ordinal()];
     }
-    return mathContext;
-  }
-
-  /**
-   * Gets a MathContext with unlimited precision and the specified RoundingMode. Equivalent to "new
-   * MathContext(0, roundingMode)", but pulls from a singleton to prevent object thrashing.
-   *
-   * @param roundingMode The {@link RoundingMode} to use.
-   * @return The corresponding {@link MathContext}.
-   */
-  public static MathContext mathContextUnlimited(RoundingMode roundingMode) {
-    return MATH_CONTEXT_BY_ROUNDING_MODE_UNLIMITED[roundingMode.ordinal()];
-  }
 }
index f9a383525ee117c8875c7d21e586e7d8e30b7acf..c176ee2501879c359c3ee32032565878bb0eeda2 100644 (file)
@@ -21,13 +21,13 @@ import com.ibm.icu.text.CompactDecimalFormat.CompactStyle;
 import com.ibm.icu.text.PluralRules;
 import com.ibm.icu.util.ULocale;
 
-
 /**
- * A class that defines the scientific notation style to be used when formatting numbers in NumberFormatter.
+ * A class that defines the scientific notation style to be used when formatting numbers in
+ * NumberFormatter.
  *
  * <p>
- * This class exposes no public functionality. To create a CompactNotation, use one of the factory methods in
- * {@link Notation}.
+ * This class exposes no public functionality. To create a CompactNotation, use one of the factory
+ * methods in {@link Notation}.
  *
  * @draft ICU 60
  * @provisional This API might change or be removed in a future release.
@@ -48,8 +48,13 @@ public class CompactNotation extends Notation {
         this.compactCustomData = compactCustomData;
     }
 
-    /* package-private */ MicroPropsGenerator withLocaleData(ULocale locale, String nsName, CompactType compactType,
-            PluralRules rules, MutablePatternModifier buildReference, MicroPropsGenerator parent) {
+    /* package-private */ MicroPropsGenerator withLocaleData(
+            ULocale locale,
+            String nsName,
+            CompactType compactType,
+            PluralRules rules,
+            MutablePatternModifier buildReference,
+            MicroPropsGenerator parent) {
         // TODO: Add a data cache? It would be keyed by locale, nsName, compact type, and compact style.
         return new CompactHandler(this, locale, nsName, compactType, rules, buildReference, parent);
     }
@@ -66,8 +71,14 @@ public class CompactNotation extends Notation {
         final Map<String, CompactModInfo> precomputedMods;
         final CompactData data;
 
-        private CompactHandler(CompactNotation notation, ULocale locale, String nsName, CompactType compactType,
-                PluralRules rules, MutablePatternModifier buildReference, MicroPropsGenerator parent) {
+        private CompactHandler(
+                CompactNotation notation,
+                ULocale locale,
+                String nsName,
+                CompactType compactType,
+                PluralRules rules,
+                MutablePatternModifier buildReference,
+                MicroPropsGenerator parent) {
             this.rules = rules;
             this.parent = parent;
             this.data = new CompactData();
index 97e36314a0c89a381b44b054f28fd78e7efc5023..dd0d0f02ab30436618d954fded00577c075cfbca 100644 (file)
@@ -5,8 +5,8 @@ package com.ibm.icu.number;
 import com.ibm.icu.util.Currency;
 
 /**
- * A class that defines a rounding strategy parameterized by a currency to be used when formatting numbers in
- * NumberFormatter.
+ * A class that defines a rounding strategy parameterized by a currency to be used when formatting
+ * numbers in NumberFormatter.
  *
  * <p>
  * To create a CurrencyRounder, use one of the factory methods on Rounder.
@@ -24,13 +24,13 @@ public abstract class CurrencyRounder extends Rounder {
      * Associates a currency with this rounding strategy.
      *
      * <p>
-     * <strong>Calling this method is <em>not required</em></strong>, because the currency specified in unit() or via a
-     * CurrencyAmount passed into format(Measure) is automatically applied to currency rounding strategies. However,
-     * this method enables you to override that automatic association.
+     * <strong>Calling this method is <em>not required</em></strong>, because the currency specified in
+     * unit() or via a CurrencyAmount passed into format(Measure) is automatically applied to currency
+     * rounding strategies. However, this method enables you to override that automatic association.
      *
      * <p>
-     * This method also enables numbers to be formatted using currency rounding rules without explicitly using a
-     * currency format.
+     * This method also enables numbers to be formatted using currency rounding rules without explicitly
+     * using a currency format.
      *
      * @param currency
      *            The currency to associate with this rounding strategy.
index 2ced2a44bad4d3305597a0f0045ef903439ac7c7..61ed736cb7e5a960fbee8db8a6a4dd9ee7769bfa 100644 (file)
@@ -5,8 +5,8 @@ package com.ibm.icu.number;
 import com.ibm.icu.impl.number.RoundingUtils;
 
 /**
- * A class that defines a rounding strategy based on a number of fraction places and optionally significant digits to be
- * used when formatting numbers in NumberFormatter.
+ * A class that defines a rounding strategy based on a number of fraction places and optionally
+ * significant digits to be used when formatting numbers in NumberFormatter.
  *
  * <p>
  * To create a FractionRounder, use one of the factory methods on Rounder.
@@ -21,15 +21,16 @@ public abstract class FractionRounder extends Rounder {
     }
 
     /**
-     * Ensure that no less than this number of significant digits are retained when rounding according to fraction
-     * rules.
+     * Ensure that no less than this number of significant digits are retained when rounding according to
+     * fraction rules.
      *
      * <p>
-     * For example, with integer rounding, the number 3.141 becomes "3". However, with minimum figures set to 2, 3.141
-     * becomes "3.1" instead.
+     * For example, with integer rounding, the number 3.141 becomes "3". However, with minimum figures
+     * set to 2, 3.141 becomes "3.1" instead.
      *
      * <p>
-     * This setting does not affect the number of trailing zeros. For example, 3.01 would print as "3", not "3.0".
+     * This setting does not affect the number of trailing zeros. For example, 3.01 would print as "3",
+     * not "3.0".
      *
      * @param minSignificantDigits
      *            The number of significant figures to guarantee.
@@ -42,22 +43,23 @@ public abstract class FractionRounder extends Rounder {
         if (minSignificantDigits >= 1 && minSignificantDigits <= RoundingUtils.MAX_INT_FRAC_SIG) {
             return constructFractionSignificant(this, minSignificantDigits, -1);
         } else {
-            throw new IllegalArgumentException(
-                    "Significant digits must be between 1 and " + RoundingUtils.MAX_INT_FRAC_SIG + " (inclusive)");
+            throw new IllegalArgumentException("Significant digits must be between 1 and "
+                    + RoundingUtils.MAX_INT_FRAC_SIG
+                    + " (inclusive)");
         }
     }
 
     /**
-     * Ensure that no more than this number of significant digits are retained when rounding according to fraction
-     * rules.
+     * Ensure that no more than this number of significant digits are retained when rounding according to
+     * fraction rules.
      *
      * <p>
-     * For example, with integer rounding, the number 123.4 becomes "123". However, with maximum figures set to 2, 123.4
-     * becomes "120" instead.
+     * For example, with integer rounding, the number 123.4 becomes "123". However, with maximum figures
+     * set to 2, 123.4 becomes "120" instead.
      *
      * <p>
-     * This setting does not affect the number of trailing zeros. For example, with fixed fraction of 2, 123.4 would
-     * become "120.00".
+     * This setting does not affect the number of trailing zeros. For example, with fixed fraction of 2,
+     * 123.4 would become "120.00".
      *
      * @param maxSignificantDigits
      *            Round the number to no more than this number of significant figures.
@@ -70,8 +72,9 @@ public abstract class FractionRounder extends Rounder {
         if (maxSignificantDigits >= 1 && maxSignificantDigits <= RoundingUtils.MAX_INT_FRAC_SIG) {
             return constructFractionSignificant(this, -1, maxSignificantDigits);
         } else {
-            throw new IllegalArgumentException(
-                    "Significant digits must be between 1 and " + RoundingUtils.MAX_INT_FRAC_SIG + " (inclusive)");
+            throw new IllegalArgumentException("Significant digits must be between 1 and "
+                    + RoundingUtils.MAX_INT_FRAC_SIG
+                    + " (inclusive)");
         }
     }
 }
\ No newline at end of file
index 6d1c1935c4c28324d671f00b256321ebec7dab3a..b3e4318c871a815e08feaf326cfd5300da1c9de7 100644 (file)
@@ -108,7 +108,8 @@ public class Grouper {
             return false;
         }
         position -= grouping1;
-        return position >= 0 && (position % grouping2) == 0
+        return position >= 0
+                && (position % grouping2) == 0
                 && value.getUpperDisplayMagnitude() - grouping1 + 1 >= (min2 ? 2 : 1);
     }
 }
\ No newline at end of file
index 4d75894fad3f970da0b2370e4aae11e801d6d603..db59f234c985ab7b2e03b5799543b785f57f9e4c 100644 (file)
@@ -27,7 +27,8 @@ public class IntegerWidth {
     }
 
     /**
-     * Pad numbers at the beginning with zeros to guarantee a certain number of numerals before the decimal separator.
+     * Pad numbers at the beginning with zeros to guarantee a certain number of numerals before the
+     * decimal separator.
      *
      * <p>
      * For example, with minInt=3, the number 55 will get printed as "055".
@@ -45,8 +46,9 @@ public class IntegerWidth {
         } else if (minInt >= 0 && minInt <= RoundingUtils.MAX_INT_FRAC_SIG) {
             return new IntegerWidth(minInt, -1);
         } else {
-            throw new IllegalArgumentException(
-                    "Integer digits must be between 0 and " + RoundingUtils.MAX_INT_FRAC_SIG + " (inclusive)");
+            throw new IllegalArgumentException("Integer digits must be between 0 and "
+                    + RoundingUtils.MAX_INT_FRAC_SIG
+                    + " (inclusive)");
         }
     }
 
@@ -56,7 +58,8 @@ public class IntegerWidth {
      * For example, with maxInt=3, the number 1234 will get printed as "234".
      *
      * @param maxInt
-     *            The maximum number of places before the decimal separator. maxInt == -1 means no truncation.
+     *            The maximum number of places before the decimal separator. maxInt == -1 means no
+     *            truncation.
      * @return An IntegerWidth for passing to the NumberFormatter integerWidth() setter.
      * @draft ICU 60
      * @provisional This API might change or be removed in a future release.
@@ -70,8 +73,9 @@ public class IntegerWidth {
         } else if (maxInt == -1) {
             return new IntegerWidth(minInt, -1);
         } else {
-            throw new IllegalArgumentException(
-                    "Integer digits must be between -1 and " + RoundingUtils.MAX_INT_FRAC_SIG + " (inclusive)");
+            throw new IllegalArgumentException("Integer digits must be between -1 and "
+                    + RoundingUtils.MAX_INT_FRAC_SIG
+                    + " (inclusive)");
         }
     }
 }
\ No newline at end of file
index 3be9101fb25a90e80968a5bae2929ca2d023410d..f614d1d70d5608b8fd3a4c31b50fa25d61d3b8c1 100644 (file)
@@ -38,8 +38,8 @@ public class LocalizedNumberFormatter extends NumberFormatterSettings<LocalizedN
     }
 
     /**
-     * Format the given byte, short, int, or long to a string using the settings specified in the NumberFormatter fluent
-     * setting chain.
+     * Format the given byte, short, int, or long to a string using the settings specified in the
+     * NumberFormatter fluent setting chain.
      *
      * @param input
      *            The number to format.
@@ -53,8 +53,8 @@ public class LocalizedNumberFormatter extends NumberFormatterSettings<LocalizedN
     }
 
     /**
-     * Format the given float or double to a string using the settings specified in the NumberFormatter fluent setting
-     * chain.
+     * Format the given float or double to a string using the settings specified in the NumberFormatter
+     * fluent setting chain.
      *
      * @param input
      *            The number to format.
@@ -68,8 +68,8 @@ public class LocalizedNumberFormatter extends NumberFormatterSettings<LocalizedN
     }
 
     /**
-     * Format the given {@link BigInteger}, {@link BigDecimal}, or other {@link Number} to a string using the settings
-     * specified in the NumberFormatter fluent setting chain.
+     * Format the given {@link BigInteger}, {@link BigDecimal}, or other {@link Number} to a string using
+     * the settings specified in the NumberFormatter fluent setting chain.
      *
      * @param input
      *            The number to format.
@@ -83,12 +83,12 @@ public class LocalizedNumberFormatter extends NumberFormatterSettings<LocalizedN
     }
 
     /**
-     * Format the given {@link Measure} or {@link CurrencyAmount} to a string using the settings specified in the
-     * NumberFormatter fluent setting chain.
+     * Format the given {@link Measure} or {@link CurrencyAmount} to a string using the settings
+     * specified in the NumberFormatter fluent setting chain.
      *
      * <p>
-     * The unit specified here overrides any unit that may have been specified in the setter chain. This method is
-     * intended for cases when each input to the number formatter has a different unit.
+     * The unit specified here overrides any unit that may have been specified in the setter chain. This
+     * method is intended for cases when each input to the number formatter has a different unit.
      *
      * @param input
      *            The number to format.
@@ -115,8 +115,9 @@ public class LocalizedNumberFormatter extends NumberFormatterSettings<LocalizedN
     }
 
     /**
-     * This is the core entrypoint to the number formatting pipeline. It performs self-regulation: a static code path
-     * for the first few calls, and compiling a more efficient data structure if called repeatedly.
+     * This is the core entrypoint to the number formatting pipeline. It performs self-regulation: a
+     * static code path for the first few calls, and compiling a more efficient data structure if called
+     * repeatedly.
      *
      * <p>
      * This function is very hot, being called in every call to the number formatting pipeline.
index c1ec6c988599b2d1eb5b764fc989c34eebb146e8..409a4e9e0ce1eb9e33ced1ec29072d09db990840 100644 (file)
@@ -15,8 +15,14 @@ import com.ibm.icu.text.CompactDecimalFormat.CompactStyle;
 public class Notation {
 
     // TODO: Support engineering intervals other than 3?
-    private static final ScientificNotation SCIENTIFIC = new ScientificNotation(1, false, 1, SignDisplay.AUTO);
-    private static final ScientificNotation ENGINEERING = new ScientificNotation(3, false, 1, SignDisplay.AUTO);
+    private static final ScientificNotation SCIENTIFIC = new ScientificNotation(1,
+            false,
+            1,
+            SignDisplay.AUTO);
+    private static final ScientificNotation ENGINEERING = new ScientificNotation(3,
+            false,
+            1,
+            SignDisplay.AUTO);
     private static final CompactNotation COMPACT_SHORT = new CompactNotation(CompactStyle.SHORT);
     private static final CompactNotation COMPACT_LONG = new CompactNotation(CompactStyle.LONG);
     private static final SimpleNotation SIMPLE = new SimpleNotation();
@@ -25,10 +31,11 @@ public class Notation {
     }
 
     /**
-     * Print the number using scientific notation (also known as scientific form, standard index form, or standard form
-     * in the UK). The format for scientific notation varies by locale; for example, many Western locales display the
-     * number in the form "#E0", where the number is displayed with one digit before the decimal separator, zero or more
-     * digits after the decimal separator, and the corresponding power of 10 displayed after the "E".
+     * Print the number using scientific notation (also known as scientific form, standard index form, or
+     * standard form in the UK). The format for scientific notation varies by locale; for example, many
+     * Western locales display the number in the form "#E0", where the number is displayed with one digit
+     * before the decimal separator, zero or more digits after the decimal separator, and the
+     * corresponding power of 10 displayed after the "E".
      *
      * <p>
      * Example outputs in <em>en-US</em> when printing 8.765E4 through 8.765E-3:
@@ -55,8 +62,8 @@ public class Notation {
     }
 
     /**
-     * Print the number using engineering notation, a variant of scientific notation in which the exponent must be
-     * divisible by 3.
+     * Print the number using engineering notation, a variant of scientific notation in which the
+     * exponent must be divisible by 3.
      *
      * <p>
      * Example outputs in <em>en-US</em> when printing 8.765E4 through 8.765E-3:
@@ -86,18 +93,18 @@ public class Notation {
      * Print the number using short-form compact notation.
      *
      * <p>
-     * <em>Compact notation</em>, defined in Unicode Technical Standard #35 Part 3 Section 2.4.1, prints numbers with
-     * localized prefixes or suffixes corresponding to different powers of ten. Compact notation is similar to
-     * engineering notation in how it scales numbers.
+     * <em>Compact notation</em>, defined in Unicode Technical Standard #35 Part 3 Section 2.4.1, prints
+     * numbers with localized prefixes or suffixes corresponding to different powers of ten. Compact
+     * notation is similar to engineering notation in how it scales numbers.
      *
      * <p>
-     * Compact notation is ideal for displaying large numbers (over ~1000) to humans while at the same time minimizing
-     * screen real estate.
+     * Compact notation is ideal for displaying large numbers (over ~1000) to humans while at the same
+     * time minimizing screen real estate.
      *
      * <p>
-     * In short form, the powers of ten are abbreviated. In <em>en-US</em>, the abbreviations are "K" for thousands, "M"
-     * for millions, "B" for billions, and "T" for trillions. Example outputs in <em>en-US</em> when printing 8.765E7
-     * through 8.765E0:
+     * In short form, the powers of ten are abbreviated. In <em>en-US</em>, the abbreviations are "K" for
+     * thousands, "M" for millions, "B" for billions, and "T" for trillions. Example outputs in
+     * <em>en-US</em> when printing 8.765E7 through 8.765E0:
      *
      * <pre>
      * 88M
@@ -111,10 +118,10 @@ public class Notation {
      * </pre>
      *
      * <p>
-     * When compact notation is specified without an explicit rounding strategy, numbers are rounded off to the closest
-     * integer after scaling the number by the corresponding power of 10, but with a digit shown after the decimal
-     * separator if there is only one digit before the decimal separator. The default compact notation rounding strategy
-     * is equivalent to:
+     * When compact notation is specified without an explicit rounding strategy, numbers are rounded off
+     * to the closest integer after scaling the number by the corresponding power of 10, but with a digit
+     * shown after the decimal separator if there is only one digit before the decimal separator. The
+     * default compact notation rounding strategy is equivalent to:
      *
      * <pre>
      * Rounder.integer().withMinDigits(2)
@@ -134,8 +141,8 @@ public class Notation {
      * {@link #compactShort}.
      *
      * <p>
-     * In long form, the powers of ten are spelled out fully. Example outputs in <em>en-US</em> when printing 8.765E7
-     * through 8.765E0:
+     * In long form, the powers of ten are spelled out fully. Example outputs in <em>en-US</em> when
+     * printing 8.765E7 through 8.765E0:
      *
      * <pre>
      * 88 million
@@ -158,11 +165,12 @@ public class Notation {
     }
 
     /**
-     * Print the number using simple notation without any scaling by powers of ten. This is the default behavior.
+     * Print the number using simple notation without any scaling by powers of ten. This is the default
+     * behavior.
      *
      * <p>
-     * Since this is the default behavior, this method needs to be called only when it is necessary to override a
-     * previous setting.
+     * Since this is the default behavior, this method needs to be called only when it is necessary to
+     * override a previous setting.
      *
      * <p>
      * Example outputs in <em>en-US</em> when printing 8.765E7 through 8.765E0:
index 2b788a4165b3fb042d417bb1ebe8657e8a10904c..5aece9b81b763979f47ef5eeb9b940bc59e94a49 100644 (file)
@@ -10,7 +10,8 @@ import com.ibm.icu.text.DecimalFormatSymbols;
 import com.ibm.icu.util.ULocale;
 
 /**
- * The main entrypoint to the localized number formatting library introduced in ICU 60. Basic usage examples:
+ * The main entrypoint to the localized number formatting library introduced in ICU 60. Basic usage
+ * examples:
  *
  * <pre>
  * // Most basic usage:
@@ -39,21 +40,25 @@ import com.ibm.icu.util.ULocale;
  * </pre>
  *
  * <p>
- * This API offers more features than {@link com.ibm.icu.text.DecimalFormat} and is geared toward new users of ICU.
+ * This API offers more features than {@link com.ibm.icu.text.DecimalFormat} and is geared toward new
+ * users of ICU.
  *
  * <p>
- * NumberFormatter instances are immutable and thread safe. This means that invoking a configuration method has no
- * effect on the receiving instance; you must store and use the new number formatter instance it returns instead.
+ * NumberFormatter instances are immutable and thread safe. This means that invoking a configuration
+ * method has no effect on the receiving instance; you must store and use the new number formatter
+ * instance it returns instead.
  *
  * <pre>
- * UnlocalizedNumberFormatter formatter = UnlocalizedNumberFormatter.with().notation(Notation.scientific());
+ * UnlocalizedNumberFormatter formatter = UnlocalizedNumberFormatter.with()
+ *         .notation(Notation.scientific());
  * formatter.rounding(Rounder.maxFraction(2)); // does nothing!
  * formatter.locale(ULocale.ENGLISH).format(9.8765).toString(); // prints "9.8765E0", not "9.88E0"
  * </pre>
  *
  * <p>
- * This API is based on the <em>fluent</em> design pattern popularized by libraries such as Google's Guava. For
- * extensive details on the design of this API, read <a href="https://goo.gl/szi5VB">the design doc</a>.
+ * This API is based on the <em>fluent</em> design pattern popularized by libraries such as Google's
+ * Guava. For extensive details on the design of this API, read <a href="https://goo.gl/szi5VB">the
+ * design doc</a>.
  *
  * @author Shane Carr
  * @draft ICU 60
@@ -64,8 +69,8 @@ public final class NumberFormatter {
     private static final UnlocalizedNumberFormatter BASE = new UnlocalizedNumberFormatter();
 
     /**
-     * An enum declaring how to render units, including currencies. Example outputs when formatting 123 USD and 123
-     * meters in <em>en-CA</em>:
+     * An enum declaring how to render units, including currencies. Example outputs when formatting 123
+     * USD and 123 meters in <em>en-CA</em>:
      *
      * <ul>
      * <li>NARROW: "$123.00" and "123 m"
@@ -84,13 +89,14 @@ public final class NumberFormatter {
      */
     public static enum UnitWidth {
         /**
-         * Print an abbreviated version of the unit name. Similar to SHORT, but always use the shortest available
-         * abbreviation or symbol. This option can be used when the context hints at the identity of the unit. For more
-         * information on the difference between NARROW and SHORT, see SHORT.
+         * Print an abbreviated version of the unit name. Similar to SHORT, but always use the shortest
+         * available abbreviation or symbol. This option can be used when the context hints at the
+         * identity of the unit. For more information on the difference between NARROW and SHORT, see
+         * SHORT.
          *
          * <p>
-         * In CLDR, this option corresponds to the "Narrow" format for measure units and the "¤¤¤¤¤" placeholder for
-         * currencies.
+         * In CLDR, this option corresponds to the "Narrow" format for measure units and the "¤¤¤¤¤"
+         * placeholder for currencies.
          *
          * @draft ICU 60
          * @provisional This API might change or be removed in a future release.
@@ -99,16 +105,16 @@ public final class NumberFormatter {
         NARROW,
 
         /**
-         * Print an abbreviated version of the unit name. Similar to NARROW, but use a slightly wider abbreviation or
-         * symbol when there may be ambiguity. This is the default behavior.
+         * Print an abbreviated version of the unit name. Similar to NARROW, but use a slightly wider
+         * abbreviation or symbol when there may be ambiguity. This is the default behavior.
          *
          * <p>
-         * For example, in <em>es-US</em>, the SHORT form for Fahrenheit is "{0} °F", but the NARROW form is "{0}°",
-         * since Fahrenheit is the customary unit for temperature in that locale.
+         * For example, in <em>es-US</em>, the SHORT form for Fahrenheit is "{0} °F", but the NARROW form
+         * is "{0}°", since Fahrenheit is the customary unit for temperature in that locale.
          *
          * <p>
-         * In CLDR, this option corresponds to the "Short" format for measure units and the "¤" placeholder for
-         * currencies.
+         * In CLDR, this option corresponds to the "Short" format for measure units and the "¤"
+         * placeholder for currencies.
          *
          * @draft ICU 60
          * @provisional This API might change or be removed in a future release.
@@ -120,8 +126,8 @@ public final class NumberFormatter {
          * Print the full name of the unit, without any abbreviations.
          *
          * <p>
-         * In CLDR, this option corresponds to the default format for measure units and the "¤¤¤" placeholder for
-         * currencies.
+         * In CLDR, this option corresponds to the default format for measure units and the "¤¤¤"
+         * placeholder for currencies.
          *
          * @draft ICU 60
          * @provisional This API might change or be removed in a future release.
@@ -130,8 +136,8 @@ public final class NumberFormatter {
         FULL_NAME,
 
         /**
-         * Use the three-digit ISO XXX code in place of the symbol for displaying currencies. The behavior of this
-         * option is currently undefined for use with measure units.
+         * Use the three-digit ISO XXX code in place of the symbol for displaying currencies. The
+         * behavior of this option is currently undefined for use with measure units.
          *
          * <p>
          * In CLDR, this option corresponds to the "¤¤" placeholder for currencies.
@@ -143,9 +149,9 @@ public final class NumberFormatter {
         ISO_CODE,
 
         /**
-         * Format the number according to the specified unit, but do not display the unit. For currencies, apply
-         * monetary symbols and formats as with SHORT, but omit the currency symbol. For measure units, the behavior is
-         * equivalent to not specifying the unit at all.
+         * Format the number according to the specified unit, but do not display the unit. For
+         * currencies, apply monetary symbols and formats as with SHORT, but omit the currency symbol.
+         * For measure units, the behavior is equivalent to not specifying the unit at all.
          *
          * @draft ICU 60
          * @provisional This API might change or be removed in a future release.
@@ -155,8 +161,8 @@ public final class NumberFormatter {
     }
 
     /**
-     * An enum declaring how to denote positive and negative numbers. Example outputs when formatting 123 and -123 in
-     * <em>en-US</em>:
+     * An enum declaring how to denote positive and negative numbers. Example outputs when formatting 123
+     * and -123 in <em>en-US</em>:
      *
      * <ul>
      * <li>AUTO: "123" and "-123"
@@ -175,8 +181,8 @@ public final class NumberFormatter {
      */
     public static enum SignDisplay {
         /**
-         * Show the minus sign on negative numbers, and do not show the sign on positive numbers. This is the default
-         * behavior.
+         * Show the minus sign on negative numbers, and do not show the sign on positive numbers. This is
+         * the default behavior.
          *
          * @draft ICU 60
          * @provisional This API might change or be removed in a future release.
@@ -203,16 +209,17 @@ public final class NumberFormatter {
         NEVER,
 
         /**
-         * Use the locale-dependent accounting format on negative numbers, and do not show the sign on positive numbers.
+         * Use the locale-dependent accounting format on negative numbers, and do not show the sign on
+         * positive numbers.
          *
          * <p>
-         * The accounting format is defined in CLDR and varies by locale; in many Western locales, the format is a pair
-         * of parentheses around the number.
+         * The accounting format is defined in CLDR and varies by locale; in many Western locales, the
+         * format is a pair of parentheses around the number.
          *
          * <p>
-         * Note: Since CLDR defines the accounting format in the monetary context only, this option falls back to the
-         * AUTO sign display strategy when formatting without a currency unit. This limitation may be lifted in the
-         * future.
+         * Note: Since CLDR defines the accounting format in the monetary context only, this option falls
+         * back to the AUTO sign display strategy when formatting without a currency unit. This
+         * limitation may be lifted in the future.
          *
          * @draft ICU 60
          * @provisional This API might change or be removed in a future release.
@@ -221,8 +228,9 @@ public final class NumberFormatter {
         ACCOUNTING,
 
         /**
-         * Use the locale-dependent accounting format on negative numbers, and show the plus sign on positive numbers.
-         * For more information on the accounting format, see the ACCOUNTING sign display strategy.
+         * Use the locale-dependent accounting format on negative numbers, and show the plus sign on
+         * positive numbers. For more information on the accounting format, see the ACCOUNTING sign
+         * display strategy.
          *
          * @draft ICU 60
          * @provisional This API might change or be removed in a future release.
@@ -232,8 +240,8 @@ public final class NumberFormatter {
     }
 
     /**
-     * An enum declaring how to render the decimal separator. Example outputs when formatting 1 and 1.1 in
-     * <em>en-US</em>:
+     * An enum declaring how to render the decimal separator. Example outputs when formatting 1 and 1.1
+     * in <em>en-US</em>:
      *
      * <ul>
      * <li>AUTO: "1" and "1.1"
@@ -246,8 +254,8 @@ public final class NumberFormatter {
      */
     public static enum DecimalSeparatorDisplay {
         /**
-         * Show the decimal separator when there are one or more digits to display after the separator, and do not show
-         * it otherwise. This is the default behavior.
+         * Show the decimal separator when there are one or more digits to display after the separator,
+         * and do not show it otherwise. This is the default behavior.
          *
          * @draft ICU 60
          * @provisional This API might change or be removed in a future release.
@@ -266,8 +274,9 @@ public final class NumberFormatter {
     }
 
     /**
-     * Use a default threshold of 3. This means that the third time .format() is called, the data structures get built
-     * using the "safe" code path. The first two calls to .format() will trigger the unsafe code path.
+     * Use a default threshold of 3. This means that the third time .format() is called, the data
+     * structures get built using the "safe" code path. The first two calls to .format() will trigger the
+     * unsafe code path.
      */
     static final long DEFAULT_THRESHOLD = 3;
 
@@ -278,8 +287,8 @@ public final class NumberFormatter {
     }
 
     /**
-     * Call this method at the beginning of a NumberFormatter fluent chain in which the locale is not currently known at
-     * the call site.
+     * Call this method at the beginning of a NumberFormatter fluent chain in which the locale is not
+     * currently known at the call site.
      *
      * @return An {@link UnlocalizedNumberFormatter}, to be used for chaining.
      * @draft ICU 60
@@ -290,8 +299,8 @@ public final class NumberFormatter {
     }
 
     /**
-     * Call this method at the beginning of a NumberFormatter fluent chain in which the locale is known at the call
-     * site.
+     * Call this method at the beginning of a NumberFormatter fluent chain in which the locale is known
+     * at the call site.
      *
      * @param locale
      *            The locale from which to load formats and symbols for number formatting.
@@ -304,8 +313,8 @@ public final class NumberFormatter {
     }
 
     /**
-     * Call this method at the beginning of a NumberFormatter fluent chain in which the locale is known at the call
-     * site.
+     * Call this method at the beginning of a NumberFormatter fluent chain in which the locale is known
+     * at the call site.
      *
      * @param locale
      *            The locale from which to load formats and symbols for number formatting.
@@ -322,8 +331,10 @@ public final class NumberFormatter {
      * @deprecated ICU 60 This API is ICU internal only.
      */
     @Deprecated
-    public static UnlocalizedNumberFormatter fromDecimalFormat(DecimalFormatProperties properties,
-            DecimalFormatSymbols symbols, DecimalFormatProperties exportedProperties) {
+    public static UnlocalizedNumberFormatter fromDecimalFormat(
+            DecimalFormatProperties properties,
+            DecimalFormatSymbols symbols,
+            DecimalFormatProperties exportedProperties) {
         MacroProps macros = NumberPropertyMapper.oldToNew(properties, symbols, exportedProperties);
         return NumberFormatter.with().macros(macros);
     }
index bb07017ecd1aa396ca3cf290e66a836c1855383d..0702398bfb210b0749e9ec4ad8f1c207facfd88f 100644 (file)
@@ -25,12 +25,12 @@ import com.ibm.icu.util.Currency;
 import com.ibm.icu.util.MeasureUnit;
 
 /**
- * This is the "brain" of the number formatting pipeline. It ties all the pieces together, taking in a MacroProps and a
- * DecimalQuantity and outputting a properly formatted number string.
+ * This is the "brain" of the number formatting pipeline. It ties all the pieces together, taking in a
+ * MacroProps and a DecimalQuantity and outputting a properly formatted number string.
  *
  * <p>
- * This class, as well as NumberPropertyMapper, could go into the impl package, but they depend on too many
- * package-private members of the public APIs.
+ * This class, as well as NumberPropertyMapper, could go into the impl package, but they depend on too
+ * many package-private members of the public APIs.
  */
 class NumberFormatterImpl {
 
@@ -40,8 +40,13 @@ class NumberFormatterImpl {
         return new NumberFormatterImpl(microPropsGenerator);
     }
 
-    /** Builds and evaluates an "unsafe" MicroPropsGenerator, which is cheaper but can be used only once. */
-    public static MicroProps applyStatic(MacroProps macros, DecimalQuantity inValue, NumberStringBuilder outString) {
+    /**
+     * Builds and evaluates an "unsafe" MicroPropsGenerator, which is cheaper but can be used only once.
+     */
+    public static MicroProps applyStatic(
+            MacroProps macros,
+            DecimalQuantity inValue,
+            NumberStringBuilder outString) {
         MicroPropsGenerator microPropsGenerator = macrosToMicroGenerator(macros, false);
         MicroProps micros = microPropsGenerator.processQuantity(inValue);
         microsToString(micros, inValue, outString);
@@ -84,17 +89,17 @@ class NumberFormatterImpl {
     }
 
     /**
-     * Synthesizes the MacroProps into a MicroPropsGenerator. All information, including the locale, is encoded into the
-     * MicroPropsGenerator, except for the quantity itself, which is left abstract and must be provided to the returned
-     * MicroPropsGenerator instance.
+     * Synthesizes the MacroProps into a MicroPropsGenerator. All information, including the locale, is
+     * encoded into the MicroPropsGenerator, except for the quantity itself, which is left abstract and
+     * must be provided to the returned MicroPropsGenerator instance.
      *
      * @see MicroPropsGenerator
      * @param macros
      *            The {@link MacroProps} to consume. This method does not mutate the MacroProps instance.
      * @param safe
-     *            If true, the returned MicroPropsGenerator will be thread-safe. If false, the returned value will
-     *            <em>not</em> be thread-safe, intended for a single "one-shot" use only. Building the thread-safe
-     *            object is more expensive.
+     *            If true, the returned MicroPropsGenerator will be thread-safe. If false, the returned
+     *            value will <em>not</em> be thread-safe, intended for a single "one-shot" use only.
+     *            Building the thread-safe object is more expensive.
      */
     private static MicroPropsGenerator macrosToMicroGenerator(MacroProps macros, boolean safe) {
         MicroProps micros = new MicroProps(safe);
@@ -109,7 +114,8 @@ class NumberFormatterImpl {
         boolean isPercent = isNoUnit && unitIsPercent(macros.unit);
         boolean isPermille = isNoUnit && unitIsPermille(macros.unit);
         boolean isCldrUnit = !isCurrency && !isNoUnit;
-        boolean isAccounting = macros.sign == SignDisplay.ACCOUNTING || macros.sign == SignDisplay.ACCOUNTING_ALWAYS;
+        boolean isAccounting = macros.sign == SignDisplay.ACCOUNTING
+                || macros.sign == SignDisplay.ACCOUNTING_ALWAYS;
         Currency currency = isCurrency ? (Currency) macros.unit : DEFAULT_CURRENCY;
         UnitWidth unitWidth = UnitWidth.SHORT;
         if (macros.unitWidth != null) {
@@ -134,13 +140,15 @@ class NumberFormatterImpl {
         } else if (!isCurrency || unitWidth == UnitWidth.FULL_NAME) {
             patternStyle = NumberFormat.NUMBERSTYLE;
         } else if (isAccounting) {
-            // NOTE: Although ACCOUNTING and ACCOUNTING_ALWAYS are only supported in currencies right now,
+            // NOTE: Although ACCOUNTING and ACCOUNTING_ALWAYS are only supported in currencies right
+            // now,
             // the API contract allows us to add support to other units in the future.
             patternStyle = NumberFormat.ACCOUNTINGCURRENCYSTYLE;
         } else {
             patternStyle = NumberFormat.CURRENCYSTYLE;
         }
-        String pattern = NumberFormat.getPatternForStyleAndNumberingSystem(macros.loc, nsName, patternStyle);
+        String pattern = NumberFormat
+                .getPatternForStyleAndNumberingSystem(macros.loc, nsName, patternStyle);
         ParsedPatternInfo patternInfo = PatternStringParser.parseToPatternInfo(pattern);
 
         /////////////////////////////////////////////////////////////////////////////////////
@@ -247,7 +255,8 @@ class NumberFormatterImpl {
                 // Lazily create PluralRules
                 rules = PluralRules.forLocale(macros.loc);
             }
-            chain = LongNameHandler.forMeasureUnit(macros.loc, macros.unit, macros.perUnit, unitWidth, rules, chain);
+            chain = LongNameHandler
+                    .forMeasureUnit(macros.loc, macros.unit, macros.perUnit, unitWidth, rules, chain);
         } else if (isCurrency && unitWidth == UnitWidth.FULL_NAME) {
             if (rules == null) {
                 // Lazily create PluralRules
@@ -267,11 +276,15 @@ class NumberFormatterImpl {
                 // Lazily create PluralRules
                 rules = PluralRules.forLocale(macros.loc);
             }
-            CompactType compactType = (macros.unit instanceof Currency && macros.unitWidth != UnitWidth.FULL_NAME)
-                    ? CompactType.CURRENCY
-                    : CompactType.DECIMAL;
-            chain = ((CompactNotation) macros.notation).withLocaleData(macros.loc, nsName, compactType, rules,
-                    safe ? patternMod : null, chain);
+            CompactType compactType = (macros.unit instanceof Currency
+                    && macros.unitWidth != UnitWidth.FULL_NAME) ? CompactType.CURRENCY
+                            : CompactType.DECIMAL;
+            chain = ((CompactNotation) macros.notation).withLocaleData(macros.loc,
+                    nsName,
+                    compactType,
+                    rules,
+                    safe ? patternMod : null,
+                    chain);
         }
 
         return chain;
@@ -289,7 +302,10 @@ class NumberFormatterImpl {
      * @param string
      *            The output string. Will be mutated.
      */
-    private static void microsToString(MicroProps micros, DecimalQuantity quantity, NumberStringBuilder string) {
+    private static void microsToString(
+            MicroProps micros,
+            DecimalQuantity quantity,
+            NumberStringBuilder string) {
         micros.rounding.apply(quantity);
         if (micros.integerWidth.maxInt == -1) {
             quantity.setIntegerLength(micros.integerWidth.minInt, Integer.MAX_VALUE);
@@ -309,7 +325,10 @@ class NumberFormatterImpl {
         }
     }
 
-    private static int writeNumber(MicroProps micros, DecimalQuantity quantity, NumberStringBuilder string) {
+    private static int writeNumber(
+            MicroProps micros,
+            DecimalQuantity quantity,
+            NumberStringBuilder string) {
         int length = 0;
         if (quantity.isInfinite()) {
             length += string.insert(length, micros.symbols.getInfinity(), NumberFormat.Field.INTEGER);
@@ -322,9 +341,12 @@ class NumberFormatterImpl {
             length += writeIntegerDigits(micros, quantity, string);
 
             // Add the decimal point
-            if (quantity.getLowerDisplayMagnitude() < 0 || micros.decimal == DecimalSeparatorDisplay.ALWAYS) {
-                length += string.insert(length, micros.useCurrency ? micros.symbols.getMonetaryDecimalSeparatorString()
-                        : micros.symbols.getDecimalSeparatorString(), NumberFormat.Field.DECIMAL_SEPARATOR);
+            if (quantity.getLowerDisplayMagnitude() < 0
+                    || micros.decimal == DecimalSeparatorDisplay.ALWAYS) {
+                length += string.insert(length,
+                        micros.useCurrency ? micros.symbols.getMonetaryDecimalSeparatorString()
+                                : micros.symbols.getDecimalSeparatorString(),
+                        NumberFormat.Field.DECIMAL_SEPARATOR);
             }
 
             // Add the fraction digits
@@ -334,30 +356,40 @@ class NumberFormatterImpl {
         return length;
     }
 
-    private static int writeIntegerDigits(MicroProps micros, DecimalQuantity quantity, NumberStringBuilder string) {
+    private static int writeIntegerDigits(
+            MicroProps micros,
+            DecimalQuantity quantity,
+            NumberStringBuilder string) {
         int length = 0;
         int integerCount = quantity.getUpperDisplayMagnitude() + 1;
         for (int i = 0; i < integerCount; i++) {
             // Add grouping separator
             if (micros.grouping.groupAtPosition(i, quantity)) {
-                length += string.insert(0, micros.useCurrency ? micros.symbols.getMonetaryGroupingSeparatorString()
-                        : micros.symbols.getGroupingSeparatorString(), NumberFormat.Field.GROUPING_SEPARATOR);
+                length += string.insert(0,
+                        micros.useCurrency ? micros.symbols.getMonetaryGroupingSeparatorString()
+                                : micros.symbols.getGroupingSeparatorString(),
+                        NumberFormat.Field.GROUPING_SEPARATOR);
             }
 
             // Get and append the next digit value
             byte nextDigit = quantity.getDigit(i);
             if (micros.symbols.getCodePointZero() != -1) {
-                length += string.insertCodePoint(0, micros.symbols.getCodePointZero() + nextDigit,
+                length += string.insertCodePoint(0,
+                        micros.symbols.getCodePointZero() + nextDigit,
                         NumberFormat.Field.INTEGER);
             } else {
-                length += string.insert(0, micros.symbols.getDigitStringsLocal()[nextDigit],
+                length += string.insert(0,
+                        micros.symbols.getDigitStringsLocal()[nextDigit],
                         NumberFormat.Field.INTEGER);
             }
         }
         return length;
     }
 
-    private static int writeFractionDigits(MicroProps micros, DecimalQuantity quantity, NumberStringBuilder string) {
+    private static int writeFractionDigits(
+            MicroProps micros,
+            DecimalQuantity quantity,
+            NumberStringBuilder string) {
         int length = 0;
         int fractionCount = -quantity.getLowerDisplayMagnitude();
         for (int i = 0; i < fractionCount; i++) {
@@ -367,7 +399,8 @@ class NumberFormatterImpl {
                 length += string.appendCodePoint(micros.symbols.getCodePointZero() + nextDigit,
                         NumberFormat.Field.FRACTION);
             } else {
-                length += string.append(micros.symbols.getDigitStringsLocal()[nextDigit], NumberFormat.Field.FRACTION);
+                length += string.append(micros.symbols.getDigitStringsLocal()[nextDigit],
+                        NumberFormat.Field.FRACTION);
             }
         }
         return length;
index 05adfa7ce35ec8880e407a082852f4200d144f5b..df5d94bca9f30207effe07772b6d4bab232a57e2 100644 (file)
@@ -16,9 +16,9 @@ import com.ibm.icu.util.NoUnit;
 import com.ibm.icu.util.ULocale;
 
 /**
- * An abstract base class for specifying settings related to number formatting. This class is implemented by
- * {@link UnlocalizedNumberFormatter} and {@link LocalizedNumberFormatter}. This class is not intended for public
- * subclassing.
+ * An abstract base class for specifying settings related to number formatting. This class is implemented
+ * by {@link UnlocalizedNumberFormatter} and {@link LocalizedNumberFormatter}. This class is not intended
+ * for public subclassing.
  *
  * @draft ICU 60
  * @provisional This API might change or be removed in a future release.
@@ -63,8 +63,8 @@ public abstract class NumberFormatterSettings<T extends NumberFormatterSettings<
      * </ul>
      *
      * <p>
-     * All notation styles will be properly localized with locale data, and all notation styles are compatible with
-     * units, rounding strategies, and other number formatter settings.
+     * All notation styles will be properly localized with locale data, and all notation styles are
+     * compatible with units, rounding strategies, and other number formatter settings.
      *
      * <p>
      * Pass this method the return value of a {@link Notation} factory method. For example:
@@ -97,13 +97,13 @@ public abstract class NumberFormatterSettings<T extends NumberFormatterSettings<
      *
      * <p>
      * <strong>Note:</strong> The unit can also be specified by passing a {@link Measure} to
-     * {@link LocalizedNumberFormatter#format(Measure)}. Units specified via the format method take precedence over
-     * units specified here. This setter is designed for situations when the unit is constant for the duration of the
-     * number formatting process.
+     * {@link LocalizedNumberFormatter#format(Measure)}. Units specified via the format method take
+     * precedence over units specified here. This setter is designed for situations when the unit is
+     * constant for the duration of the number formatting process.
      *
      * <p>
-     * All units will be properly localized with locale data, and all units are compatible with notation styles,
-     * rounding strategies, and other number formatter settings.
+     * All units will be properly localized with locale data, and all units are compatible with notation
+     * styles, rounding strategies, and other number formatter settings.
      *
      * <p>
      * Pass this method any instance of {@link MeasureUnit}. For units of measure:
@@ -145,8 +145,8 @@ public abstract class NumberFormatterSettings<T extends NumberFormatterSettings<
     }
 
     /**
-     * Sets a unit to be used in the denominator. For example, to format "3 m/s", pass METER to the unit and SECOND to
-     * the perUnit.
+     * Sets a unit to be used in the denominator. For example, to format "3 m/s", pass METER to the unit
+     * and SECOND to the perUnit.
      *
      * <p>
      * Pass this method any instance of {@link MeasureUnit}. For example:
@@ -191,10 +191,10 @@ public abstract class NumberFormatterSettings<T extends NumberFormatterSettings<
      *
      * <p>
      * In most cases, the default rounding strategy is to round to 6 fraction places; i.e.,
-     * <code>Rounder.maxFraction(6)</code>. The exceptions are if compact notation is being used, then the compact
-     * notation rounding strategy is used (see {@link Notation#compactShort} for details), or if the unit is a currency,
-     * then standard currency rounding is used, which varies from currency to currency (see {@link Rounder#currency} for
-     * details).
+     * <code>Rounder.maxFraction(6)</code>. The exceptions are if compact notation is being used, then
+     * the compact notation rounding strategy is used (see {@link Notation#compactShort} for details), or
+     * if the unit is a currency, then standard currency rounding is used, which varies from currency to
+     * currency (see {@link Rounder#currency} for details).
      *
      * @param rounder
      *            The rounding strategy to use.
@@ -271,8 +271,8 @@ public abstract class NumberFormatterSettings<T extends NumberFormatterSettings<
     }
 
     /**
-     * Specifies the symbols (decimal separator, grouping separator, percent sign, numerals, etc.) to use when rendering
-     * numbers.
+     * Specifies the symbols (decimal separator, grouping separator, percent sign, numerals, etc.) to use
+     * when rendering numbers.
      *
      * <ul>
      * <li><em>en_US</em> symbols: "12,345.67"
@@ -289,17 +289,17 @@ public abstract class NumberFormatterSettings<T extends NumberFormatterSettings<
      * </pre>
      *
      * <p>
-     * <strong>Note:</strong> DecimalFormatSymbols automatically chooses the best numbering system based on the locale.
-     * In the examples above, the first three are using the Latin numbering system, and the fourth is using the Myanmar
-     * numbering system.
+     * <strong>Note:</strong> DecimalFormatSymbols automatically chooses the best numbering system based
+     * on the locale. In the examples above, the first three are using the Latin numbering system, and
+     * the fourth is using the Myanmar numbering system.
      *
      * <p>
-     * <strong>Note:</strong> The instance of DecimalFormatSymbols will be copied: changes made to the symbols object
-     * after passing it into the fluent chain will not be seen.
+     * <strong>Note:</strong> The instance of DecimalFormatSymbols will be copied: changes made to the
+     * symbols object after passing it into the fluent chain will not be seen.
      *
      * <p>
-     * <strong>Note:</strong> Calling this method will override the NumberingSystem previously specified in
-     * {@link #symbols(NumberingSystem)}.
+     * <strong>Note:</strong> Calling this method will override the NumberingSystem previously specified
+     * in {@link #symbols(NumberingSystem)}.
      *
      * <p>
      * The default is to choose the symbols based on the locale specified in the fluent chain.
@@ -326,16 +326,16 @@ public abstract class NumberFormatterSettings<T extends NumberFormatterSettings<
      * </ul>
      *
      * <p>
-     * Pass this method an instance of {@link NumberingSystem}. For example, to force the locale to always use the Latin
-     * alphabet numbering system (ASCII digits):
+     * Pass this method an instance of {@link NumberingSystem}. For example, to force the locale to
+     * always use the Latin alphabet numbering system (ASCII digits):
      *
      * <pre>
      * NumberFormatter.with().symbols(NumberingSystem.LATIN)
      * </pre>
      *
      * <p>
-     * <strong>Note:</strong> Calling this method will override the DecimalFormatSymbols previously specified in
-     * {@link #symbols(DecimalFormatSymbols)}.
+     * <strong>Note:</strong> Calling this method will override the DecimalFormatSymbols previously
+     * specified in {@link #symbols(DecimalFormatSymbols)}.
      *
      * <p>
      * The default is to choose the best numbering system for the locale.
@@ -412,8 +412,8 @@ public abstract class NumberFormatterSettings<T extends NumberFormatterSettings<
     }
 
     /**
-     * Sets the decimal separator display strategy. This affects integer numbers with no fraction part. Most common
-     * values:
+     * Sets the decimal separator display strategy. This affects integer numbers with no fraction part.
+     * Most common values:
      *
      * <ul>
      * <li>Auto: "1"
@@ -464,8 +464,8 @@ public abstract class NumberFormatterSettings<T extends NumberFormatterSettings<
     }
 
     /**
-     * Internal fluent setter to support a custom regulation threshold. A threshold of 1 causes the data structures to
-     * be built right away. A threshold of 0 prevents the data structures from being built.
+     * Internal fluent setter to support a custom regulation threshold. A threshold of 1 causes the data
+     * structures to be built right away. A threshold of 0 prevents the data structures from being built.
      *
      * @internal
      * @deprecated ICU 60 This API is ICU internal only.
index f1cdafe1dec9663ea86fadd178ea892ee0ac056b..49f1f1e0aafe08448103d4c62ede79965bc6c48d 100644 (file)
@@ -30,20 +30,22 @@ import com.ibm.icu.util.ULocale;
 
 /**
  * <p>
- * This class, as well as NumberFormatterImpl, could go into the impl package, but they depend on too many
- * package-private members of the public APIs.
+ * This class, as well as NumberFormatterImpl, could go into the impl package, but they depend on too
+ * many package-private members of the public APIs.
  */
 final class NumberPropertyMapper {
 
     /** Convenience method to create a NumberFormatter directly from Properties. */
-    public static UnlocalizedNumberFormatter create(DecimalFormatProperties properties, DecimalFormatSymbols symbols) {
+    public static UnlocalizedNumberFormatter create(
+            DecimalFormatProperties properties,
+            DecimalFormatSymbols symbols) {
         MacroProps macros = oldToNew(properties, symbols, null);
         return NumberFormatter.with().macros(macros);
     }
 
     /**
-     * Convenience method to create a NumberFormatter directly from a pattern string. Something like this could become
-     * public API if there is demand.
+     * Convenience method to create a NumberFormatter directly from a pattern string. Something like this
+     * could become public API if there is demand.
      */
     public static UnlocalizedNumberFormatter create(String pattern, DecimalFormatSymbols symbols) {
         DecimalFormatProperties properties = PatternStringParser.parseToProperties(pattern);
@@ -51,9 +53,9 @@ final class NumberPropertyMapper {
     }
 
     /**
-     * Creates a new {@link MacroProps} object based on the content of a {@link DecimalFormatProperties} object. In
-     * other words, maps Properties to MacroProps. This function is used by the JDK-compatibility API to call into the
-     * ICU 60 fluent number formatting pipeline.
+     * Creates a new {@link MacroProps} object based on the content of a {@link DecimalFormatProperties}
+     * object. In other words, maps Properties to MacroProps. This function is used by the
+     * JDK-compatibility API to call into the ICU 60 fluent number formatting pipeline.
      *
      * @param properties
      *            The property bag to be mapped.
@@ -63,7 +65,9 @@ final class NumberPropertyMapper {
      *            A property bag in which to store validated properties.
      * @return A new MacroProps containing all of the information in the Properties.
      */
-    public static MacroProps oldToNew(DecimalFormatProperties properties, DecimalFormatSymbols symbols,
+    public static MacroProps oldToNew(
+            DecimalFormatProperties properties,
+            DecimalFormatSymbols symbols,
             DecimalFormatProperties exportedProperties) {
         MacroProps macros = new MacroProps();
         ULocale locale = symbols.getULocale();
@@ -96,8 +100,10 @@ final class NumberPropertyMapper {
         // UNITS //
         ///////////
 
-        boolean useCurrency = ((properties.getCurrency() != null) || properties.getCurrencyPluralInfo() != null
-                || properties.getCurrencyUsage() != null || affixProvider.hasCurrencySign());
+        boolean useCurrency = ((properties.getCurrency() != null)
+                || properties.getCurrencyPluralInfo() != null
+                || properties.getCurrencyUsage() != null
+                || affixProvider.hasCurrencySign());
         Currency currency = CustomSymbolCurrency.resolve(properties.getCurrency(), locale, symbols);
         CurrencyUsage currencyUsage = properties.getCurrencyUsage();
         boolean explicitCurrencyUsage = currencyUsage != null;
@@ -122,7 +128,8 @@ final class NumberPropertyMapper {
         MathContext mathContext = RoundingUtils.getMathContextOrUnlimited(properties);
         boolean explicitMinMaxFrac = minFrac != -1 || maxFrac != -1;
         boolean explicitMinMaxSig = minSig != -1 || maxSig != -1;
-        // Resolve min/max frac for currencies, required for the validation logic and for when minFrac or maxFrac was
+        // Resolve min/max frac for currencies, required for the validation logic and for when minFrac or
+        // maxFrac was
         // set (but not both) on a currency instance.
         // NOTE: Increments are handled in "Rounder.constructCurrency()".
         if (useCurrency) {
@@ -151,7 +158,8 @@ final class NumberPropertyMapper {
             minFrac = minFrac < 0 ? 0 : minFrac;
             maxFrac = maxFrac < 0 ? Integer.MAX_VALUE : maxFrac < minFrac ? minFrac : maxFrac;
             minInt = minInt <= 0 ? 1 : minInt > RoundingUtils.MAX_INT_FRAC_SIG ? 1 : minInt;
-            maxInt = maxInt < 0 ? -1 : maxInt < minInt ? minInt : maxInt > RoundingUtils.MAX_INT_FRAC_SIG ? -1 : maxInt;
+            maxInt = maxInt < 0 ? -1
+                    : maxInt < minInt ? minInt : maxInt > RoundingUtils.MAX_INT_FRAC_SIG ? -1 : maxInt;
         }
         Rounder rounding = null;
         if (explicitCurrencyUsage) {
@@ -159,10 +167,12 @@ final class NumberPropertyMapper {
         } else if (roundingIncrement != null) {
             rounding = Rounder.constructIncrement(roundingIncrement);
         } else if (explicitMinMaxSig) {
-            minSig = minSig < 1 ? 1 : minSig > RoundingUtils.MAX_INT_FRAC_SIG ? RoundingUtils.MAX_INT_FRAC_SIG : minSig;
+            minSig = minSig < 1 ? 1
+                    : minSig > RoundingUtils.MAX_INT_FRAC_SIG ? RoundingUtils.MAX_INT_FRAC_SIG : minSig;
             maxSig = maxSig < 0 ? RoundingUtils.MAX_INT_FRAC_SIG
                     : maxSig < minSig ? minSig
-                            : maxSig > RoundingUtils.MAX_INT_FRAC_SIG ? RoundingUtils.MAX_INT_FRAC_SIG : maxSig;
+                            : maxSig > RoundingUtils.MAX_INT_FRAC_SIG ? RoundingUtils.MAX_INT_FRAC_SIG
+                                    : maxSig;
             rounding = Rounder.constructSignificant(minSig, maxSig);
         } else if (explicitMinMaxFrac) {
             rounding = Rounder.constructFraction(minFrac, maxFrac);
@@ -198,7 +208,8 @@ final class NumberPropertyMapper {
         /////////////
 
         if (properties.getFormatWidth() != -1) {
-            macros.padder = new Padder(properties.getPadString(), properties.getFormatWidth(),
+            macros.padder = new Padder(properties.getPadString(),
+                    properties.getFormatWidth(),
                     properties.getPadPosition());
         }
 
@@ -246,7 +257,8 @@ final class NumberPropertyMapper {
             // Scientific notation also involves overriding the rounding mode.
             // TODO: Overriding here is a bit of a hack. Should this logic go earlier?
             if (macros.rounder instanceof FractionRounder) {
-                // For the purposes of rounding, get the original min/max int/frac, since the local variables
+                // For the purposes of rounding, get the original min/max int/frac, since the local
+                // variables
                 // have been manipulated for display purposes.
                 int minInt_ = properties.getMinimumIntegerDigits();
                 int minFrac_ = properties.getMinimumFractionDigits();
@@ -342,15 +354,20 @@ final class NumberPropertyMapper {
         private final String negSuffix;
 
         public PropertiesAffixPatternProvider(DecimalFormatProperties properties) {
-            // There are two ways to set affixes in DecimalFormat: via the pattern string (applyPattern), and via the
-            // explicit setters (setPositivePrefix and friends).  The way to resolve the settings is as follows:
+            // There are two ways to set affixes in DecimalFormat: via the pattern string (applyPattern),
+            // and via the
+            // explicit setters (setPositivePrefix and friends). The way to resolve the settings is as
+            // follows:
             //
             // 1) If the explicit setting is present for the field, use it.
             // 2) Otherwise, follows UTS 35 rules based on the pattern string.
             //
-            // Importantly, the explicit setters affect only the one field they override.  If you set the positive
-            // prefix, that should not affect the negative prefix.  Since it is impossible for the user of this class
-            // to know whether the origin for a string was the override or the pattern, we have to say that we always
+            // Importantly, the explicit setters affect only the one field they override. If you set the
+            // positive
+            // prefix, that should not affect the negative prefix. Since it is impossible for the user of
+            // this class
+            // to know whether the origin for a string was the override or the pattern, we have to say
+            // that we always
             // have a negative subpattern and perform all resolution logic here.
 
             // Convenience: Extract the properties into local variables.
@@ -449,14 +466,18 @@ final class NumberPropertyMapper {
 
         @Override
         public boolean hasCurrencySign() {
-            return AffixUtils.hasCurrencySymbols(posPrefix) || AffixUtils.hasCurrencySymbols(posSuffix)
-                    || AffixUtils.hasCurrencySymbols(negPrefix) || AffixUtils.hasCurrencySymbols(negSuffix);
+            return AffixUtils.hasCurrencySymbols(posPrefix)
+                    || AffixUtils.hasCurrencySymbols(posSuffix)
+                    || AffixUtils.hasCurrencySymbols(negPrefix)
+                    || AffixUtils.hasCurrencySymbols(negSuffix);
         }
 
         @Override
         public boolean containsSymbolType(int type) {
-            return AffixUtils.containsType(posPrefix, type) || AffixUtils.containsType(posSuffix, type)
-                    || AffixUtils.containsType(negPrefix, type) || AffixUtils.containsType(negSuffix, type);
+            return AffixUtils.containsType(posPrefix, type)
+                    || AffixUtils.containsType(posSuffix, type)
+                    || AffixUtils.containsType(negPrefix, type)
+                    || AffixUtils.containsType(negSuffix, type);
         }
     }
 
index 38db8c861fba0b23e6bce6b217289cacc76f201e..783adf35c5260c6019176dbbb8ac0ef86369c177 100644 (file)
@@ -34,11 +34,12 @@ public abstract class Rounder implements Cloneable {
      * Show all available digits to full precision.
      *
      * <p>
-     * <strong>NOTE:</strong> When formatting a <em>double</em>, this method, along with {@link #minFraction} and
-     * {@link #minDigits}, will trigger complex algorithm similar to <em>Dragon4</em> to determine the low-order digits
-     * and the number of digits to display based on the value of the double. If the number of fraction places or
-     * significant digits can be bounded, consider using {@link #maxFraction} or {@link #maxDigits} instead to maximize
-     * performance. For more information, read the following blog post.
+     * <strong>NOTE:</strong> When formatting a <em>double</em>, this method, along with
+     * {@link #minFraction} and {@link #minDigits}, will trigger complex algorithm similar to
+     * <em>Dragon4</em> to determine the low-order digits and the number of digits to display based on
+     * the value of the double. If the number of fraction places or significant digits can be bounded,
+     * consider using {@link #maxFraction} or {@link #maxDigits} instead to maximize performance. For
+     * more information, read the following blog post.
      *
      * <p>
      * http://www.serpentine.com/blog/2011/06/29/here-be-dragons-advances-in-problems-you-didnt-even-know-you-had/
@@ -65,8 +66,9 @@ public abstract class Rounder implements Cloneable {
     }
 
     /**
-     * Show numbers rounded if necessary to a certain number of fraction places (numerals after the decimal separator).
-     * Additionally, pad with zeros to ensure that this number of places are always shown.
+     * Show numbers rounded if necessary to a certain number of fraction places (numerals after the
+     * decimal separator). Additionally, pad with zeros to ensure that this number of places are always
+     * shown.
      *
      * <p>
      * Example output with minMaxFractionPlaces = 3:
@@ -86,8 +88,8 @@ public abstract class Rounder implements Cloneable {
      * This method is equivalent to {@link #minMaxFraction} with both arguments equal.
      *
      * @param minMaxFractionPlaces
-     *            The minimum and maximum number of numerals to display after the decimal separator (rounding if too
-     *            long or padding with zeros if too short).
+     *            The minimum and maximum number of numerals to display after the decimal separator
+     *            (rounding if too long or padding with zeros if too short).
      * @return A FractionRounder for chaining or passing to the NumberFormatter rounding() setter.
      * @draft ICU 60
      * @provisional This API might change or be removed in a future release.
@@ -97,21 +99,23 @@ public abstract class Rounder implements Cloneable {
         if (minMaxFractionPlaces >= 0 && minMaxFractionPlaces <= RoundingUtils.MAX_INT_FRAC_SIG) {
             return constructFraction(minMaxFractionPlaces, minMaxFractionPlaces);
         } else {
-            throw new IllegalArgumentException(
-                    "Fraction length must be between 0 and " + RoundingUtils.MAX_INT_FRAC_SIG + " (inclusive)");
+            throw new IllegalArgumentException("Fraction length must be between 0 and "
+                    + RoundingUtils.MAX_INT_FRAC_SIG
+                    + " (inclusive)");
         }
     }
 
     /**
-     * Always show at least a certain number of fraction places after the decimal separator, padding with zeros if
-     * necessary. Do not perform rounding (display numbers to their full precision).
+     * Always show at least a certain number of fraction places after the decimal separator, padding with
+     * zeros if necessary. Do not perform rounding (display numbers to their full precision).
      *
      * <p>
-     * <strong>NOTE:</strong> If you are formatting <em>doubles</em>, see the performance note in {@link #unlimited}.
+     * <strong>NOTE:</strong> If you are formatting <em>doubles</em>, see the performance note in
+     * {@link #unlimited}.
      *
      * @param minFractionPlaces
-     *            The minimum number of numerals to display after the decimal separator (padding with zeros if
-     *            necessary).
+     *            The minimum number of numerals to display after the decimal separator (padding with
+     *            zeros if necessary).
      * @return A FractionRounder for chaining or passing to the NumberFormatter rounding() setter.
      * @draft ICU 60
      * @provisional This API might change or be removed in a future release.
@@ -121,18 +125,20 @@ public abstract class Rounder implements Cloneable {
         if (minFractionPlaces >= 0 && minFractionPlaces <= RoundingUtils.MAX_INT_FRAC_SIG) {
             return constructFraction(minFractionPlaces, -1);
         } else {
-            throw new IllegalArgumentException(
-                    "Fraction length must be between 0 and " + RoundingUtils.MAX_INT_FRAC_SIG + " (inclusive)");
+            throw new IllegalArgumentException("Fraction length must be between 0 and "
+                    + RoundingUtils.MAX_INT_FRAC_SIG
+                    + " (inclusive)");
         }
     }
 
     /**
-     * Show numbers rounded if necessary to a certain number of fraction places (numerals after the decimal separator).
-     * Unlike the other fraction rounding strategies, this strategy does <em>not</em> pad zeros to the end of the
-     * number.
+     * Show numbers rounded if necessary to a certain number of fraction places (numerals after the
+     * decimal separator). Unlike the other fraction rounding strategies, this strategy does <em>not</em>
+     * pad zeros to the end of the number.
      *
      * @param maxFractionPlaces
-     *            The maximum number of numerals to display after the decimal mark (rounding if necessary).
+     *            The maximum number of numerals to display after the decimal mark (rounding if
+     *            necessary).
      * @return A FractionRounder for chaining or passing to the NumberFormatter rounding() setter.
      * @draft ICU 60
      * @provisional This API might change or be removed in a future release.
@@ -142,46 +148,51 @@ public abstract class Rounder implements Cloneable {
         if (maxFractionPlaces >= 0 && maxFractionPlaces <= RoundingUtils.MAX_INT_FRAC_SIG) {
             return constructFraction(0, maxFractionPlaces);
         } else {
-            throw new IllegalArgumentException(
-                    "Fraction length must be between 0 and " + RoundingUtils.MAX_INT_FRAC_SIG + " (inclusive)");
+            throw new IllegalArgumentException("Fraction length must be between 0 and "
+                    + RoundingUtils.MAX_INT_FRAC_SIG
+                    + " (inclusive)");
         }
     }
 
     /**
-     * Show numbers rounded if necessary to a certain number of fraction places (numerals after the decimal separator);
-     * in addition, always show at least a certain number of places after the decimal separator, padding with zeros if
-     * necessary.
+     * Show numbers rounded if necessary to a certain number of fraction places (numerals after the
+     * decimal separator); in addition, always show at least a certain number of places after the decimal
+     * separator, padding with zeros if necessary.
      *
      * @param minFractionPlaces
-     *            The minimum number of numerals to display after the decimal separator (padding with zeros if
-     *            necessary).
+     *            The minimum number of numerals to display after the decimal separator (padding with
+     *            zeros if necessary).
      * @param maxFractionPlaces
-     *            The maximum number of numerals to display after the decimal separator (rounding if necessary).
+     *            The maximum number of numerals to display after the decimal separator (rounding if
+     *            necessary).
      * @return A FractionRounder for chaining or passing to the NumberFormatter rounding() setter.
      * @draft ICU 60
      * @provisional This API might change or be removed in a future release.
      * @see NumberFormatter
      */
     public static FractionRounder minMaxFraction(int minFractionPlaces, int maxFractionPlaces) {
-        if (minFractionPlaces >= 0 && maxFractionPlaces <= RoundingUtils.MAX_INT_FRAC_SIG
+        if (minFractionPlaces >= 0
+                && maxFractionPlaces <= RoundingUtils.MAX_INT_FRAC_SIG
                 && minFractionPlaces <= maxFractionPlaces) {
             return constructFraction(minFractionPlaces, maxFractionPlaces);
         } else {
-            throw new IllegalArgumentException(
-                    "Fraction length must be between 0 and " + RoundingUtils.MAX_INT_FRAC_SIG + " (inclusive)");
+            throw new IllegalArgumentException("Fraction length must be between 0 and "
+                    + RoundingUtils.MAX_INT_FRAC_SIG
+                    + " (inclusive)");
         }
     }
 
     /**
-     * Show numbers rounded if necessary to a certain number of significant digits or significant figures. Additionally,
-     * pad with zeros to ensure that this number of significant digits/figures are always shown.
+     * Show numbers rounded if necessary to a certain number of significant digits or significant
+     * figures. Additionally, pad with zeros to ensure that this number of significant digits/figures are
+     * always shown.
      *
      * <p>
      * This method is equivalent to {@link #minMaxDigits} with both arguments equal.
      *
      * @param minMaxSignificantDigits
-     *            The minimum and maximum number of significant digits to display (rounding if too long or padding with
-     *            zeros if too short).
+     *            The minimum and maximum number of significant digits to display (rounding if too long
+     *            or padding with zeros if too short).
      * @return A Rounder for chaining or passing to the NumberFormatter rounding() setter.
      * @draft ICU 60
      * @provisional This API might change or be removed in a future release.
@@ -191,17 +202,19 @@ public abstract class Rounder implements Cloneable {
         if (minMaxSignificantDigits >= 1 && minMaxSignificantDigits <= RoundingUtils.MAX_INT_FRAC_SIG) {
             return constructSignificant(minMaxSignificantDigits, minMaxSignificantDigits);
         } else {
-            throw new IllegalArgumentException(
-                    "Significant digits must be between 1 and " + RoundingUtils.MAX_INT_FRAC_SIG + " (inclusive)");
+            throw new IllegalArgumentException("Significant digits must be between 1 and "
+                    + RoundingUtils.MAX_INT_FRAC_SIG
+                    + " (inclusive)");
         }
     }
 
     /**
-     * Always show at least a certain number of significant digits/figures, padding with zeros if necessary. Do not
-     * perform rounding (display numbers to their full precision).
+     * Always show at least a certain number of significant digits/figures, padding with zeros if
+     * necessary. Do not perform rounding (display numbers to their full precision).
      *
      * <p>
-     * <strong>NOTE:</strong> If you are formatting <em>doubles</em>, see the performance note in {@link #unlimited}.
+     * <strong>NOTE:</strong> If you are formatting <em>doubles</em>, see the performance note in
+     * {@link #unlimited}.
      *
      * @param minSignificantDigits
      *            The minimum number of significant digits to display (padding with zeros if too short).
@@ -214,8 +227,9 @@ public abstract class Rounder implements Cloneable {
         if (minSignificantDigits >= 1 && minSignificantDigits <= RoundingUtils.MAX_INT_FRAC_SIG) {
             return constructSignificant(minSignificantDigits, -1);
         } else {
-            throw new IllegalArgumentException(
-                    "Significant digits must be between 1 and " + RoundingUtils.MAX_INT_FRAC_SIG + " (inclusive)");
+            throw new IllegalArgumentException("Significant digits must be between 1 and "
+                    + RoundingUtils.MAX_INT_FRAC_SIG
+                    + " (inclusive)");
         }
     }
 
@@ -233,14 +247,15 @@ public abstract class Rounder implements Cloneable {
         if (maxSignificantDigits >= 1 && maxSignificantDigits <= RoundingUtils.MAX_INT_FRAC_SIG) {
             return constructSignificant(0, maxSignificantDigits);
         } else {
-            throw new IllegalArgumentException(
-                    "Significant digits must be between 1 and " + RoundingUtils.MAX_INT_FRAC_SIG + " (inclusive)");
+            throw new IllegalArgumentException("Significant digits must be between 1 and "
+                    + RoundingUtils.MAX_INT_FRAC_SIG
+                    + " (inclusive)");
         }
     }
 
     /**
-     * Show numbers rounded if necessary to a certain number of significant digits/figures; in addition, always show at
-     * least a certain number of significant digits, padding with zeros if necessary.
+     * Show numbers rounded if necessary to a certain number of significant digits/figures; in addition,
+     * always show at least a certain number of significant digits, padding with zeros if necessary.
      *
      * @param minSignificantDigits
      *            The minimum number of significant digits to display (padding with zeros if necessary).
@@ -252,23 +267,26 @@ public abstract class Rounder implements Cloneable {
      * @see NumberFormatter
      */
     public static Rounder minMaxDigits(int minSignificantDigits, int maxSignificantDigits) {
-        if (minSignificantDigits >= 1 && maxSignificantDigits <= RoundingUtils.MAX_INT_FRAC_SIG
+        if (minSignificantDigits >= 1
+                && maxSignificantDigits <= RoundingUtils.MAX_INT_FRAC_SIG
                 && minSignificantDigits <= maxSignificantDigits) {
             return constructSignificant(minSignificantDigits, maxSignificantDigits);
         } else {
-            throw new IllegalArgumentException(
-                    "Significant digits must be between 1 and " + RoundingUtils.MAX_INT_FRAC_SIG + " (inclusive)");
+            throw new IllegalArgumentException("Significant digits must be between 1 and "
+                    + RoundingUtils.MAX_INT_FRAC_SIG
+                    + " (inclusive)");
         }
     }
 
     /**
-     * Show numbers rounded if necessary to the closest multiple of a certain rounding increment. For example, if the
-     * rounding increment is 0.5, then round 1.2 to 1 and round 1.3 to 1.5.
+     * Show numbers rounded if necessary to the closest multiple of a certain rounding increment. For
+     * example, if the rounding increment is 0.5, then round 1.2 to 1 and round 1.3 to 1.5.
      *
      * <p>
-     * In order to ensure that numbers are padded to the appropriate number of fraction places, set the scale on the
-     * rounding increment BigDecimal. For example, to round to the nearest 0.5 and always display 2 numerals after the
-     * decimal separator (to display 1.2 as "1.00" and 1.3 as "1.50"), you can run:
+     * In order to ensure that numbers are padded to the appropriate number of fraction places, set the
+     * scale on the rounding increment BigDecimal. For example, to round to the nearest 0.5 and always
+     * display 2 numerals after the decimal separator (to display 1.2 as "1.00" and 1.3 as "1.50"), you
+     * can run:
      *
      * <pre>
      * Rounder.increment(new BigDecimal("0.50"))
@@ -293,18 +311,20 @@ public abstract class Rounder implements Cloneable {
     }
 
     /**
-     * Show numbers rounded and padded according to the rules for the currency unit. The most common rounding settings
-     * for currencies include <code>Rounder.fixedFraction(2)</code>, <code>Rounder.integer()</code>, and
-     * <code>Rounder.increment(0.05)</code> for cash transactions ("nickel rounding").
+     * Show numbers rounded and padded according to the rules for the currency unit. The most common
+     * rounding settings for currencies include <code>Rounder.fixedFraction(2)</code>,
+     * <code>Rounder.integer()</code>, and <code>Rounder.increment(0.05)</code> for cash transactions
+     * ("nickel rounding").
      *
      * <p>
      * The exact rounding details will be resolved at runtime based on the currency unit specified in the
-     * NumberFormatter chain. To round according to the rules for one currency while displaying the symbol for another
-     * currency, the withCurrency() method can be called on the return value of this method.
+     * NumberFormatter chain. To round according to the rules for one currency while displaying the
+     * symbol for another currency, the withCurrency() method can be called on the return value of this
+     * method.
      *
      * @param currencyUsage
-     *            Either STANDARD (for digital transactions) or CASH (for transactions where the rounding increment may
-     *            be limited by the available denominations of cash or coins).
+     *            Either STANDARD (for digital transactions) or CASH (for transactions where the rounding
+     *            increment may be limited by the available denominations of cash or coins).
      * @return A CurrencyRounder for chaining or passing to the NumberFormatter rounding() setter.
      * @draft ICU 60
      * @provisional This API might change or be removed in a future release.
@@ -319,8 +339,8 @@ public abstract class Rounder implements Cloneable {
     }
 
     /**
-     * Sets the {@link java.math.RoundingMode} to use when picking the direction to round (up or down). Common values
-     * include HALF_EVEN, HALF_UP, and FLOOR. The default is HALF_EVEN.
+     * Sets the {@link java.math.RoundingMode} to use when picking the direction to round (up or down).
+     * Common values include HALF_EVEN, HALF_UP, and FLOOR. The default is HALF_EVEN.
      *
      * @param roundingMode
      *            The RoundingMode to use.
@@ -470,8 +490,8 @@ public abstract class Rounder implements Cloneable {
     }
 
     /**
-     * Returns a valid working Rounder. If the Rounder is a CurrencyRounder, applies the given currency. Otherwise,
-     * simply passes through the argument.
+     * Returns a valid working Rounder. If the Rounder is a CurrencyRounder, applies the given currency.
+     * Otherwise, simply passes through the argument.
      *
      * @param currency
      *            A currency object to use in case the input object needs it.
@@ -486,17 +506,21 @@ public abstract class Rounder implements Cloneable {
     }
 
     /**
-     * Rounding endpoint used by Engineering and Compact notation. Chooses the most appropriate multiplier (magnitude
-     * adjustment), applies the adjustment, rounds, and returns the chosen multiplier.
+     * Rounding endpoint used by Engineering and Compact notation. Chooses the most appropriate
+     * multiplier (magnitude adjustment), applies the adjustment, rounds, and returns the chosen
+     * multiplier.
      *
      * <p>
-     * In most cases, this is simple. However, when rounding the number causes it to cross a multiplier boundary, we
-     * need to re-do the rounding. For example, to display 999,999 in Engineering notation with 2 sigfigs, first you
-     * guess the multiplier to be -3. However, then you end up getting 1000E3, which is not the correct output. You then
-     * change your multiplier to be -6, and you get 1.0E6, which is correct.
+     * In most cases, this is simple. However, when rounding the number causes it to cross a multiplier
+     * boundary, we need to re-do the rounding. For example, to display 999,999 in Engineering notation
+     * with 2 sigfigs, first you guess the multiplier to be -3. However, then you end up getting 1000E3,
+     * which is not the correct output. You then change your multiplier to be -6, and you get 1.0E6,
+     * which is correct.
      *
-     * @param input The quantity to process.
-     * @param producer Function to call to return a multiplier based on a magnitude.
+     * @param input
+     *            The quantity to process.
+     * @param producer
+     *            Function to call to return a multiplier based on a magnitude.
      * @return The number of orders of magnitude the input was adjusted by this method.
      */
     int chooseMultiplierAndApply(DecimalQuantity input, MultiplierProducer producer) {
@@ -563,7 +587,8 @@ public abstract class Rounder implements Cloneable {
         @Override
         public void apply(DecimalQuantity value) {
             value.roundToMagnitude(getRoundingMagnitudeFraction(maxFrac), mathContext);
-            value.setFractionLength(Math.max(0, -getDisplayMagnitudeFraction(minFrac)), Integer.MAX_VALUE);
+            value.setFractionLength(Math.max(0, -getDisplayMagnitudeFraction(minFrac)),
+                    Integer.MAX_VALUE);
         }
     }
 
@@ -579,10 +604,14 @@ public abstract class Rounder implements Cloneable {
         @Override
         public void apply(DecimalQuantity value) {
             value.roundToMagnitude(getRoundingMagnitudeSignificant(value, maxSig), mathContext);
-            value.setFractionLength(Math.max(0, -getDisplayMagnitudeSignificant(value, minSig)), Integer.MAX_VALUE);
+            value.setFractionLength(Math.max(0, -getDisplayMagnitudeSignificant(value, minSig)),
+                    Integer.MAX_VALUE);
         }
 
-        /** Version of {@link #apply} that obeys minInt constraints. Used for scientific notation compatibility mode. */
+        /**
+         * Version of {@link #apply} that obeys minInt constraints. Used for scientific notation
+         * compatibility mode.
+         */
         public void apply(DecimalQuantity quantity, int minInt) {
             assert quantity.isZero();
             quantity.setFractionLength(minSig - minInt, Integer.MAX_VALUE);
index c0f7a60293af1d9b9a973a884453a072d7964f83..e121fb7db8159edf1ea660ef60d5e86e7d76b34b 100644 (file)
@@ -15,7 +15,8 @@ import com.ibm.icu.text.DecimalFormatSymbols;
 import com.ibm.icu.text.NumberFormat;
 
 /**
- * A class that defines the scientific notation style to be used when formatting numbers in NumberFormatter.
+ * A class that defines the scientific notation style to be used when formatting numbers in
+ * NumberFormatter.
  *
  * <p>
  * To create a ScientificNotation, use one of the factory methods in {@link Notation}.
@@ -31,7 +32,10 @@ public class ScientificNotation extends Notation implements Cloneable {
     int minExponentDigits;
     SignDisplay exponentSignDisplay;
 
-    /* package-private */ ScientificNotation(int engineeringInterval, boolean requireMinInt, int minExponentDigits,
+    /* package-private */ ScientificNotation(
+            int engineeringInterval,
+            boolean requireMinInt,
+            int minExponentDigits,
             SignDisplay exponentSignDisplay) {
         this.engineeringInterval = engineeringInterval;
         this.requireMinInt = requireMinInt;
@@ -40,12 +44,12 @@ public class ScientificNotation extends Notation implements Cloneable {
     }
 
     /**
-     * Sets the minimum number of digits to show in the exponent of scientific notation, padding with zeros if
-     * necessary. Useful for fixed-width display.
+     * Sets the minimum number of digits to show in the exponent of scientific notation, padding with
+     * zeros if necessary. Useful for fixed-width display.
      *
      * <p>
-     * For example, with minExponentDigits=2, the number 123 will be printed as "1.23E02" in <em>en-US</em> instead of
-     * the default "1.23E2".
+     * For example, with minExponentDigits=2, the number 123 will be printed as "1.23E02" in
+     * <em>en-US</em> instead of the default "1.23E2".
      *
      * @param minExponentDigits
      *            The minimum number of digits to show in the exponent.
@@ -60,18 +64,19 @@ public class ScientificNotation extends Notation implements Cloneable {
             other.minExponentDigits = minExponentDigits;
             return other;
         } else {
-            throw new IllegalArgumentException(
-                    "Integer digits must be between 1 and " + RoundingUtils.MAX_INT_FRAC_SIG + " (inclusive)");
+            throw new IllegalArgumentException("Integer digits must be between 1 and "
+                    + RoundingUtils.MAX_INT_FRAC_SIG
+                    + " (inclusive)");
         }
     }
 
     /**
-     * Sets whether to show the sign on positive and negative exponents in scientific notation. The default is AUTO,
-     * showing the minus sign but not the plus sign.
+     * Sets whether to show the sign on positive and negative exponents in scientific notation. The
+     * default is AUTO, showing the minus sign but not the plus sign.
      *
      * <p>
-     * For example, with exponentSignDisplay=ALWAYS, the number 123 will be printed as "1.23E+2" in <em>en-US</em>
-     * instead of the default "1.23E2".
+     * For example, with exponentSignDisplay=ALWAYS, the number 123 will be printed as "1.23E+2" in
+     * <em>en-US</em> instead of the default "1.23E2".
      *
      * @param exponentSignDisplay
      *            The strategy for displaying the sign in the exponent.
@@ -101,21 +106,27 @@ public class ScientificNotation extends Notation implements Cloneable {
         }
     }
 
-    /* package-private */ MicroPropsGenerator withLocaleData(DecimalFormatSymbols symbols, boolean build,
+    /* package-private */ MicroPropsGenerator withLocaleData(
+            DecimalFormatSymbols symbols,
+            boolean build,
             MicroPropsGenerator parent) {
         return new ScientificHandler(this, symbols, build, parent);
     }
 
-    // NOTE: The object lifecycle of ScientificModifier and ScientificHandler differ greatly in Java and C++.
+    // NOTE: The object lifecycle of ScientificModifier and ScientificHandler differ greatly in Java and
+    // C++.
     //
     // During formatting, we need to provide an object with state (the exponent) as the inner modifier.
     //
     // In Java, where the priority is put on reducing object creations, the unsafe code path re-uses the
-    // ScientificHandler as a ScientificModifier, and the safe code path pre-computes 25 ScientificModifier
+    // ScientificHandler as a ScientificModifier, and the safe code path pre-computes 25
+    // ScientificModifier
     // instances. This scheme reduces the number of object creations by 1 in both safe and unsafe.
     //
-    // In C++, MicroProps provides a pre-allocated ScientificModifier, and ScientificHandler simply populates
-    // the state (the exponent) into that ScientificModifier. There is no difference between safe and unsafe.
+    // In C++, MicroProps provides a pre-allocated ScientificModifier, and ScientificHandler simply
+    // populates
+    // the state (the exponent) into that ScientificModifier. There is no difference between safe and
+    // unsafe.
 
     private static class ScientificHandler implements MicroPropsGenerator, MultiplierProducer, Modifier {
 
@@ -125,7 +136,10 @@ public class ScientificNotation extends Notation implements Cloneable {
         final MicroPropsGenerator parent;
         /* unsafe */ int exponent;
 
-        private ScientificHandler(ScientificNotation notation, DecimalFormatSymbols symbols, boolean safe,
+        private ScientificHandler(
+                ScientificNotation notation,
+                DecimalFormatSymbols symbols,
+                boolean safe,
                 MicroPropsGenerator parent) {
             this.notation = notation;
             this.symbols = symbols;
@@ -152,7 +166,8 @@ public class ScientificNotation extends Notation implements Cloneable {
             if (quantity.isZero()) {
                 if (notation.requireMinInt && micros.rounding instanceof SignificantRounderImpl) {
                     // Show "00.000E0" on pattern "00.000E0"
-                    ((SignificantRounderImpl) micros.rounding).apply(quantity, notation.engineeringInterval);
+                    ((SignificantRounderImpl) micros.rounding).apply(quantity,
+                            notation.engineeringInterval);
                     exponent = 0;
                 } else {
                     micros.rounding.apply(quantity);
index 7007a3af909c248ec28f6b12a9236b969e08f542..bd9ca6e5b61e9384f17a04ec9f8477ec2d1f6f20 100644 (file)
@@ -6,8 +6,8 @@ package com.ibm.icu.number;
  * A class that defines the simple notation style to be used when formatting numbers in NumberFormatter.
  *
  * <p>
- * This class exposes no public functionality. To create a SimpleNotation, use one of the factory methods in
- * {@link Notation}.
+ * This class exposes no public functionality. To create a SimpleNotation, use one of the factory methods
+ * in {@link Notation}.
  *
  * @draft ICU 60
  * @provisional This API might change or be removed in a future release.
index bc82c90b06206f658560481f748289b8ad304d71..decce7ffe2efb9531734546d068b82e98acee48a 100644 (file)
@@ -7,7 +7,8 @@ import java.util.Locale;
 import com.ibm.icu.util.ULocale;
 
 /**
- * A NumberFormatter that does not yet have a locale. In order to format numbers, a locale must be specified.
+ * A NumberFormatter that does not yet have a locale. In order to format numbers, a locale must be
+ * specified.
  *
  * @see NumberFormatter
  * @draft ICU 60
@@ -25,8 +26,8 @@ public class UnlocalizedNumberFormatter extends NumberFormatterSettings<Unlocali
     }
 
     /**
-     * Associate the given locale with the number formatter. The locale is used for picking the appropriate symbols,
-     * formats, and other data for number display.
+     * Associate the given locale with the number formatter. The locale is used for picking the
+     * appropriate symbols, formats, and other data for number display.
      *
      * <p>
      * To use the Java default locale, call Locale.getDefault():
index fe77028a44f59c3ec0e76ff4544a0184bc08c237..b29d3482f3d3484f76d50f961aa07358f032367e 100644 (file)
@@ -13,214 +13,205 @@ import com.ibm.icu.impl.number.NumberStringBuilder;
 
 public class AffixUtilsTest {
 
-    private static final SymbolProvider DEFAULT_SYMBOL_PROVIDER =
-        new SymbolProvider() {
-          @Override
-          public CharSequence getSymbol(int type) {
+    private static final SymbolProvider DEFAULT_SYMBOL_PROVIDER = new SymbolProvider() {
+        @Override
+        public CharSequence getSymbol(int type) {
             // Use interesting symbols where possible. The symbols are from ar_SA but are hard-coded
             // here to make the test independent of locale data changes.
             switch (type) {
-              case AffixUtils.TYPE_MINUS_SIGN:
+            case AffixUtils.TYPE_MINUS_SIGN:
                 return "−";
-              case AffixUtils.TYPE_PLUS_SIGN:
+            case AffixUtils.TYPE_PLUS_SIGN:
                 return "\u061C+";
-              case AffixUtils.TYPE_PERCENT:
+            case AffixUtils.TYPE_PERCENT:
                 return "٪\u061C";
-              case AffixUtils.TYPE_PERMILLE:
+            case AffixUtils.TYPE_PERMILLE:
                 return "؉";
-              case AffixUtils.TYPE_CURRENCY_SINGLE:
+            case AffixUtils.TYPE_CURRENCY_SINGLE:
                 return "$";
-              case AffixUtils.TYPE_CURRENCY_DOUBLE:
+            case AffixUtils.TYPE_CURRENCY_DOUBLE:
                 return "XXX";
-              case AffixUtils.TYPE_CURRENCY_TRIPLE:
+            case AffixUtils.TYPE_CURRENCY_TRIPLE:
                 return "long name";
-              case AffixUtils.TYPE_CURRENCY_QUAD:
+            case AffixUtils.TYPE_CURRENCY_QUAD:
                 return "\uFFFD";
-              case AffixUtils.TYPE_CURRENCY_QUINT:
+            case AffixUtils.TYPE_CURRENCY_QUINT:
                 return "@";
-              case AffixUtils.TYPE_CURRENCY_OVERFLOW:
+            case AffixUtils.TYPE_CURRENCY_OVERFLOW:
                 return "\uFFFD";
-              default:
+            default:
                 throw new AssertionError();
             }
-          }
-        };
-
-  @Test
-  public void testEscape() {
-    Object[][] cases = {
-      {"", ""},
-      {"abc", "abc"},
-      {"-", "'-'"},
-      {"-!", "'-'!"},
-      {"−", "−"},
-      {"---", "'---'"},
-      {"-%-", "'-%-'"},
-      {"'", "''"},
-      {"-'", "'-'''"},
-      {"-'-", "'-''-'"},
-      {"a-'-", "a'-''-'"}
+        }
     };
 
-    StringBuilder sb = new StringBuilder();
-    for (Object[] cas : cases) {
-      String input = (String) cas[0];
-      String expected = (String) cas[1];
-      sb.setLength(0);
-      AffixUtils.escape(input, sb);
-      assertEquals(expected, sb.toString());
+    @Test
+    public void testEscape() {
+        Object[][] cases = {
+                { "", "" },
+                { "abc", "abc" },
+                { "-", "'-'" },
+                { "-!", "'-'!" },
+                { "−", "−" },
+                { "---", "'---'" },
+                { "-%-", "'-%-'" },
+                { "'", "''" },
+                { "-'", "'-'''" },
+                { "-'-", "'-''-'" },
+                { "a-'-", "a'-''-'" } };
+
+        StringBuilder sb = new StringBuilder();
+        for (Object[] cas : cases) {
+            String input = (String) cas[0];
+            String expected = (String) cas[1];
+            sb.setLength(0);
+            AffixUtils.escape(input, sb);
+            assertEquals(expected, sb.toString());
+        }
     }
-  }
-
-  @Test
-  public void testUnescape() {
-    Object[][] cases = {
-      {"", false, 0, ""},
-      {"abc", false, 3, "abc"},
-      {"-", false, 1, "−"},
-      {"-!", false, 2, "−!"},
-      {"+", false, 1, "\u061C+"},
-      {"+!", false, 2, "\u061C+!"},
-      {"‰", false, 1, "؉"},
-      {"‰!", false, 2, "؉!"},
-      {"-x", false, 2, "−x"},
-      {"'-'x", false, 2, "-x"},
-      {"'--''-'-x", false, 6, "--'-−x"},
-      {"''", false, 1, "'"},
-      {"''''", false, 2, "''"},
-      {"''''''", false, 3, "'''"},
-      {"''x''", false, 3, "'x'"},
-      {"¤", true, 1, "$"},
-      {"¤¤", true, 2, "XXX"},
-      {"¤¤¤", true, 3, "long name"},
-      {"¤¤¤¤", true, 4, "\uFFFD"},
-      {"¤¤¤¤¤", true, 5, "@"},
-      {"¤¤¤¤¤¤", true, 6, "\uFFFD"},
-      {"¤¤¤a¤¤¤¤", true, 8, "long namea\uFFFD"},
-      {"a¤¤¤¤b¤¤¤¤¤c", true, 12, "a\uFFFDb@c"},
-      {"¤!", true, 2, "$!"},
-      {"¤¤!", true, 3, "XXX!"},
-      {"¤¤¤!", true, 4, "long name!"},
-      {"-¤¤", true, 3, "−XXX"},
-      {"¤¤-", true, 3, "XXX−"},
-      {"'¤'", false, 1, "¤"},
-      {"%", false, 1, "٪\u061C"},
-      {"'%'", false, 1, "%"},
-      {"¤'-'%", true, 3, "$-٪\u061C"},
-      {"#0#@#*#;#", false, 9, "#0#@#*#;#"}
-    };
-
-    for (Object[] cas : cases) {
-      String input = (String) cas[0];
-      boolean curr = (Boolean) cas[1];
-      int length = (Integer) cas[2];
-      String output = (String) cas[3];
 
-      assertEquals(
-          "Currency on <" + input + ">", curr, AffixUtils.hasCurrencySymbols(input));
-      assertEquals("Length on <" + input + ">", length, AffixUtils.estimateLength(input));
-
-      String actual = unescapeWithDefaults(input);
-      assertEquals("Output on <" + input + ">", output, actual);
-
-      int ulength = AffixUtils.unescapedCodePointCount(input, DEFAULT_SYMBOL_PROVIDER);
-      assertEquals("Unescaped length on <" + input + ">", output.length(), ulength);
+    @Test
+    public void testUnescape() {
+        Object[][] cases = {
+                { "", false, 0, "" },
+                { "abc", false, 3, "abc" },
+                { "-", false, 1, "−" },
+                { "-!", false, 2, "−!" },
+                { "+", false, 1, "\u061C+" },
+                { "+!", false, 2, "\u061C+!" },
+                { "‰", false, 1, "؉" },
+                { "‰!", false, 2, "؉!" },
+                { "-x", false, 2, "−x" },
+                { "'-'x", false, 2, "-x" },
+                { "'--''-'-x", false, 6, "--'-−x" },
+                { "''", false, 1, "'" },
+                { "''''", false, 2, "''" },
+                { "''''''", false, 3, "'''" },
+                { "''x''", false, 3, "'x'" },
+                { "¤", true, 1, "$" },
+                { "¤¤", true, 2, "XXX" },
+                { "¤¤¤", true, 3, "long name" },
+                { "¤¤¤¤", true, 4, "\uFFFD" },
+                { "¤¤¤¤¤", true, 5, "@" },
+                { "¤¤¤¤¤¤", true, 6, "\uFFFD" },
+                { "¤¤¤a¤¤¤¤", true, 8, "long namea\uFFFD" },
+                { "a¤¤¤¤b¤¤¤¤¤c", true, 12, "a\uFFFDb@c" },
+                { "¤!", true, 2, "$!" },
+                { "¤¤!", true, 3, "XXX!" },
+                { "¤¤¤!", true, 4, "long name!" },
+                { "-¤¤", true, 3, "−XXX" },
+                { "¤¤-", true, 3, "XXX−" },
+                { "'¤'", false, 1, "¤" },
+                { "%", false, 1, "٪\u061C" },
+                { "'%'", false, 1, "%" },
+                { "¤'-'%", true, 3, "$-٪\u061C" },
+                { "#0#@#*#;#", false, 9, "#0#@#*#;#" } };
+
+        for (Object[] cas : cases) {
+            String input = (String) cas[0];
+            boolean curr = (Boolean) cas[1];
+            int length = (Integer) cas[2];
+            String output = (String) cas[3];
+
+            assertEquals("Currency on <" + input + ">", curr, AffixUtils.hasCurrencySymbols(input));
+            assertEquals("Length on <" + input + ">", length, AffixUtils.estimateLength(input));
+
+            String actual = unescapeWithDefaults(input);
+            assertEquals("Output on <" + input + ">", output, actual);
+
+            int ulength = AffixUtils.unescapedCodePointCount(input, DEFAULT_SYMBOL_PROVIDER);
+            assertEquals("Unescaped length on <" + input + ">", output.length(), ulength);
+        }
     }
-  }
-
-  @Test
-  public void testContainsReplaceType() {
-    Object[][] cases = {
-      {"", false, ""},
-      {"-", true, "+"},
-      {"-a", true, "+a"},
-      {"a-", true, "a+"},
-      {"a-b", true, "a+b"},
-      {"--", true, "++"},
-      {"x", false, "x"}
-    };
 
-    for (Object[] cas : cases) {
-      String input = (String) cas[0];
-      boolean hasMinusSign = (Boolean) cas[1];
-      String output = (String) cas[2];
-
-      assertEquals(
-          "Contains on input " + input,
-          hasMinusSign,
-          AffixUtils.containsType(input, AffixUtils.TYPE_MINUS_SIGN));
-      assertEquals(
-          "Replace on input" + input,
-          output,
-          AffixUtils.replaceType(input, AffixUtils.TYPE_MINUS_SIGN, '+'));
+    @Test
+    public void testContainsReplaceType() {
+        Object[][] cases = {
+                { "", false, "" },
+                { "-", true, "+" },
+                { "-a", true, "+a" },
+                { "a-", true, "a+" },
+                { "a-b", true, "a+b" },
+                { "--", true, "++" },
+                { "x", false, "x" } };
+
+        for (Object[] cas : cases) {
+            String input = (String) cas[0];
+            boolean hasMinusSign = (Boolean) cas[1];
+            String output = (String) cas[2];
+
+            assertEquals("Contains on input " + input,
+                    hasMinusSign,
+                    AffixUtils.containsType(input, AffixUtils.TYPE_MINUS_SIGN));
+            assertEquals("Replace on input" + input,
+                    output,
+                    AffixUtils.replaceType(input, AffixUtils.TYPE_MINUS_SIGN, '+'));
+        }
     }
-  }
-
-  @Test
-  public void testInvalid() {
-    String[] invalidExamples = {"'", "x'", "'x", "'x''", "''x'"};
-
-    for (String str : invalidExamples) {
-      try {
-        AffixUtils.hasCurrencySymbols(str);
-        fail("No exception was thrown on an invalid string");
-      } catch (IllegalArgumentException e) {
-        // OK
-      }
-      try {
-        AffixUtils.estimateLength(str);
-        fail("No exception was thrown on an invalid string");
-      } catch (IllegalArgumentException e) {
-        // OK
-      }
-      try {
-        unescapeWithDefaults(str);
-        fail("No exception was thrown on an invalid string");
-      } catch (IllegalArgumentException e) {
-        // OK
-      }
+
+    @Test
+    public void testInvalid() {
+        String[] invalidExamples = { "'", "x'", "'x", "'x''", "''x'" };
+
+        for (String str : invalidExamples) {
+            try {
+                AffixUtils.hasCurrencySymbols(str);
+                fail("No exception was thrown on an invalid string");
+            } catch (IllegalArgumentException e) {
+                // OK
+            }
+            try {
+                AffixUtils.estimateLength(str);
+                fail("No exception was thrown on an invalid string");
+            } catch (IllegalArgumentException e) {
+                // OK
+            }
+            try {
+                unescapeWithDefaults(str);
+                fail("No exception was thrown on an invalid string");
+            } catch (IllegalArgumentException e) {
+                // OK
+            }
+        }
     }
-  }
-
-  @Test
-  public void testUnescapeWithSymbolProvider() {
-    String[][] cases = {
-      {"", ""},
-      {"-", "1"},
-      {"'-'", "-"},
-      {"- + % ‰ ¤ ¤¤ ¤¤¤ ¤¤¤¤ ¤¤¤¤¤", "1 2 3 4 5 6 7 8 9"},
-      {"'¤¤¤¤¤¤'", "¤¤¤¤¤¤"},
-      {"¤¤¤¤¤¤", "\uFFFD"}
-    };
 
-    SymbolProvider provider =
-        new SymbolProvider() {
-          @Override
-          public CharSequence getSymbol(int type) {
-            return Integer.toString(Math.abs(type));
-          }
+    @Test
+    public void testUnescapeWithSymbolProvider() {
+        String[][] cases = {
+                { "", "" },
+                { "-", "1" },
+                { "'-'", "-" },
+                { "- + % ‰ ¤ ¤¤ ¤¤¤ ¤¤¤¤ ¤¤¤¤¤", "1 2 3 4 5 6 7 8 9" },
+                { "'¤¤¤¤¤¤'", "¤¤¤¤¤¤" },
+                { "¤¤¤¤¤¤", "\uFFFD" } };
+
+        SymbolProvider provider = new SymbolProvider() {
+            @Override
+            public CharSequence getSymbol(int type) {
+                return Integer.toString(Math.abs(type));
+            }
         };
 
-    NumberStringBuilder sb = new NumberStringBuilder();
-    for (String[] cas : cases) {
-      String input = cas[0];
-      String expected = cas[1];
-      sb.clear();
-      AffixUtils.unescape(input, sb, 0, provider);
-      assertEquals("With symbol provider on <" + input + ">", expected, sb.toString());
+        NumberStringBuilder sb = new NumberStringBuilder();
+        for (String[] cas : cases) {
+            String input = cas[0];
+            String expected = cas[1];
+            sb.clear();
+            AffixUtils.unescape(input, sb, 0, provider);
+            assertEquals("With symbol provider on <" + input + ">", expected, sb.toString());
+        }
+
+        // Test insertion position
+        sb.clear();
+        sb.append("abcdefg", null);
+        AffixUtils.unescape("-+%", sb, 4, provider);
+        assertEquals("Symbol provider into middle", "abcd123efg", sb.toString());
     }
 
-    // Test insertion position
-    sb.clear();
-    sb.append("abcdefg", null);
-    AffixUtils.unescape("-+%", sb, 4, provider);
-    assertEquals("Symbol provider into middle", "abcd123efg", sb.toString());
-  }
-
-  private static String unescapeWithDefaults(String input) {
-    NumberStringBuilder nsb = new NumberStringBuilder();
-    int length = AffixUtils.unescape(input, nsb, 0, DEFAULT_SYMBOL_PROVIDER);
-    assertEquals("Return value of unescape", nsb.length(), length);
-    return nsb.toString();
-  }
+    private static String unescapeWithDefaults(String input) {
+        NumberStringBuilder nsb = new NumberStringBuilder();
+        int length = AffixUtils.unescape(input, nsb, 0, DEFAULT_SYMBOL_PROVIDER);
+        assertEquals("Return value of unescape", nsb.length(), length);
+        return nsb.toString();
+    }
 }
index 786ea1a4ecfe9be47bd0beaab2a602c50b11e0e0..d8ce44129bb23c019776351a7cc8151281824682 100644 (file)
@@ -31,490 +31,487 @@ import com.ibm.icu.util.ULocale;
 @RunWith(JUnit4.class)
 public class DecimalQuantityTest extends TestFmwk {
 
-  @Ignore
-  @Test
-  public void testBehavior() throws ParseException {
-
-    // Make a list of several formatters to test the behavior of DecimalQuantity.
-    List<LocalizedNumberFormatter> formats = new ArrayList<LocalizedNumberFormatter>();
-
-    DecimalFormatSymbols symbols = DecimalFormatSymbols.getInstance(ULocale.ENGLISH);
-
-    DecimalFormatProperties properties = new DecimalFormatProperties();
-    formats.add(NumberFormatter.fromDecimalFormat(properties, symbols, null).locale(ULocale.ENGLISH));
-
-    properties =
-        new DecimalFormatProperties()
-            .setMinimumSignificantDigits(3)
-            .setMaximumSignificantDigits(3)
-            .setCompactStyle(CompactStyle.LONG);
-    formats.add(NumberFormatter.fromDecimalFormat(properties, symbols, null).locale(ULocale.ENGLISH));
-
-    properties =
-        new DecimalFormatProperties()
-            .setMinimumExponentDigits(1)
-            .setMaximumIntegerDigits(3)
-            .setMaximumFractionDigits(1);
-    formats.add(NumberFormatter.fromDecimalFormat(properties, symbols, null).locale(ULocale.ENGLISH));
-
-    properties = new DecimalFormatProperties().setRoundingIncrement(new BigDecimal("0.5"));
-    formats.add(NumberFormatter.fromDecimalFormat(properties, symbols, null).locale(ULocale.ENGLISH));
-
-    String[] cases = {
-      "1.0",
-      "2.01",
-      "1234.56",
-      "3000.0",
-      "0.00026418",
-      "0.01789261",
-      "468160.0",
-      "999000.0",
-      "999900.0",
-      "999990.0",
-      "0.0",
-      "12345678901.0",
-      "-5193.48",
-    };
-
-    String[] hardCases = {
-      "9999999999999900.0",
-      "789000000000000000000000.0",
-      "789123123567853156372158.0",
-      "987654321987654321987654321987654321987654311987654321.0",
-    };
-
-    String[] doubleCases = {
-      "512.0000000000017",
-      "4095.9999999999977",
-      "4095.999999999998",
-      "4095.9999999999986",
-      "4095.999999999999",
-      "4095.9999999999995",
-      "4096.000000000001",
-      "4096.000000000002",
-      "4096.000000000003",
-      "4096.000000000004",
-      "4096.000000000005",
-      "4096.0000000000055",
-      "4096.000000000006",
-      "4096.000000000007",
-    };
-
-    int i = 0;
-    for (String str : cases) {
-      testDecimalQuantity(i++, str, formats, 0);
+    @Ignore
+    @Test
+    public void testBehavior() throws ParseException {
+
+        // Make a list of several formatters to test the behavior of DecimalQuantity.
+        List<LocalizedNumberFormatter> formats = new ArrayList<LocalizedNumberFormatter>();
+
+        DecimalFormatSymbols symbols = DecimalFormatSymbols.getInstance(ULocale.ENGLISH);
+
+        DecimalFormatProperties properties = new DecimalFormatProperties();
+        formats.add(
+                NumberFormatter.fromDecimalFormat(properties, symbols, null).locale(ULocale.ENGLISH));
+
+        properties = new DecimalFormatProperties().setMinimumSignificantDigits(3)
+                .setMaximumSignificantDigits(3).setCompactStyle(CompactStyle.LONG);
+        formats.add(
+                NumberFormatter.fromDecimalFormat(properties, symbols, null).locale(ULocale.ENGLISH));
+
+        properties = new DecimalFormatProperties().setMinimumExponentDigits(1).setMaximumIntegerDigits(3)
+                .setMaximumFractionDigits(1);
+        formats.add(
+                NumberFormatter.fromDecimalFormat(properties, symbols, null).locale(ULocale.ENGLISH));
+
+        properties = new DecimalFormatProperties().setRoundingIncrement(new BigDecimal("0.5"));
+        formats.add(
+                NumberFormatter.fromDecimalFormat(properties, symbols, null).locale(ULocale.ENGLISH));
+
+        String[] cases = {
+                "1.0",
+                "2.01",
+                "1234.56",
+                "3000.0",
+                "0.00026418",
+                "0.01789261",
+                "468160.0",
+                "999000.0",
+                "999900.0",
+                "999990.0",
+                "0.0",
+                "12345678901.0",
+                "-5193.48", };
+
+        String[] hardCases = {
+                "9999999999999900.0",
+                "789000000000000000000000.0",
+                "789123123567853156372158.0",
+                "987654321987654321987654321987654321987654311987654321.0", };
+
+        String[] doubleCases = {
+                "512.0000000000017",
+                "4095.9999999999977",
+                "4095.999999999998",
+                "4095.9999999999986",
+                "4095.999999999999",
+                "4095.9999999999995",
+                "4096.000000000001",
+                "4096.000000000002",
+                "4096.000000000003",
+                "4096.000000000004",
+                "4096.000000000005",
+                "4096.0000000000055",
+                "4096.000000000006",
+                "4096.000000000007", };
+
+        int i = 0;
+        for (String str : cases) {
+            testDecimalQuantity(i++, str, formats, 0);
+        }
+
+        i = 0;
+        for (String str : hardCases) {
+            testDecimalQuantity(i++, str, formats, 1);
+        }
+
+        i = 0;
+        for (String str : doubleCases) {
+            testDecimalQuantity(i++, str, formats, 2);
+        }
     }
 
-    i = 0;
-    for (String str : hardCases) {
-      testDecimalQuantity(i++, str, formats, 1);
+    static void testDecimalQuantity(
+            int t,
+            String str,
+            List<LocalizedNumberFormatter> formats,
+            int mode) {
+        if (mode == 2) {
+            assertEquals("Double is not valid", Double.toString(Double.parseDouble(str)), str);
+        }
+
+        List<DecimalQuantity> qs = new ArrayList<DecimalQuantity>();
+        BigDecimal d = new BigDecimal(str);
+        qs.add(new DecimalQuantity_SimpleStorage(d));
+        if (mode == 0)
+            qs.add(new DecimalQuantity_64BitBCD(d));
+        qs.add(new DecimalQuantity_ByteArrayBCD(d));
+        qs.add(new DecimalQuantity_DualStorageBCD(d));
+
+        if (new BigDecimal(Double.toString(d.doubleValue())).compareTo(d) == 0) {
+            double dv = d.doubleValue();
+            qs.add(new DecimalQuantity_SimpleStorage(dv));
+            if (mode == 0)
+                qs.add(new DecimalQuantity_64BitBCD(dv));
+            qs.add(new DecimalQuantity_ByteArrayBCD(dv));
+            qs.add(new DecimalQuantity_DualStorageBCD(dv));
+        }
+
+        if (new BigDecimal(Long.toString(d.longValue())).compareTo(d) == 0) {
+            double lv = d.longValue();
+            qs.add(new DecimalQuantity_SimpleStorage(lv));
+            if (mode == 0)
+                qs.add(new DecimalQuantity_64BitBCD(lv));
+            qs.add(new DecimalQuantity_ByteArrayBCD(lv));
+            qs.add(new DecimalQuantity_DualStorageBCD(lv));
+        }
+
+        testDecimalQuantityExpectedOutput(qs.get(0), str);
+
+        if (qs.size() == 1) {
+            return;
+        }
+
+        for (int i = 1; i < qs.size(); i++) {
+            DecimalQuantity q0 = qs.get(0);
+            DecimalQuantity q1 = qs.get(i);
+            testDecimalQuantityExpectedOutput(q1, str);
+            testDecimalQuantityRounding(q0, q1);
+            testDecimalQuantityRoundingInterval(q0, q1);
+            testDecimalQuantityMath(q0, q1);
+            testDecimalQuantityWithFormats(q0, q1, formats);
+        }
     }
 
-    i = 0;
-    for (String str : doubleCases) {
-      testDecimalQuantity(i++, str, formats, 2);
+    private static void testDecimalQuantityExpectedOutput(DecimalQuantity rq, String expected) {
+        DecimalQuantity q0 = rq.createCopy();
+        // Force an accurate double
+        q0.roundToInfinity();
+        q0.setIntegerLength(1, Integer.MAX_VALUE);
+        q0.setFractionLength(1, Integer.MAX_VALUE);
+        String actual = q0.toPlainString();
+        assertEquals("Unexpected output from simple string conversion (" + q0 + ")", expected, actual);
     }
-  }
 
-  static void testDecimalQuantity(int t, String str, List<LocalizedNumberFormatter> formats, int mode) {
-    if (mode == 2) {
-      assertEquals("Double is not valid", Double.toString(Double.parseDouble(str)), str);
+    private static final MathContext MATH_CONTEXT_HALF_EVEN = new MathContext(0, RoundingMode.HALF_EVEN);
+    private static final MathContext MATH_CONTEXT_CEILING = new MathContext(0, RoundingMode.CEILING);
+    private static final MathContext MATH_CONTEXT_PRECISION = new MathContext(3, RoundingMode.HALF_UP);
+
+    private static void testDecimalQuantityRounding(DecimalQuantity rq0, DecimalQuantity rq1) {
+        DecimalQuantity q0 = rq0.createCopy();
+        DecimalQuantity q1 = rq1.createCopy();
+        q0.roundToMagnitude(-1, MATH_CONTEXT_HALF_EVEN);
+        q1.roundToMagnitude(-1, MATH_CONTEXT_HALF_EVEN);
+        testDecimalQuantityBehavior(q0, q1);
+
+        q0 = rq0.createCopy();
+        q1 = rq1.createCopy();
+        q0.roundToMagnitude(-1, MATH_CONTEXT_CEILING);
+        q1.roundToMagnitude(-1, MATH_CONTEXT_CEILING);
+        testDecimalQuantityBehavior(q0, q1);
+
+        q0 = rq0.createCopy();
+        q1 = rq1.createCopy();
+        q0.roundToMagnitude(-1, MATH_CONTEXT_PRECISION);
+        q1.roundToMagnitude(-1, MATH_CONTEXT_PRECISION);
+        testDecimalQuantityBehavior(q0, q1);
     }
 
-    List<DecimalQuantity> qs = new ArrayList<DecimalQuantity>();
-    BigDecimal d = new BigDecimal(str);
-    qs.add(new DecimalQuantity_SimpleStorage(d));
-    if (mode == 0) qs.add(new DecimalQuantity_64BitBCD(d));
-    qs.add(new DecimalQuantity_ByteArrayBCD(d));
-    qs.add(new DecimalQuantity_DualStorageBCD(d));
-
-    if (new BigDecimal(Double.toString(d.doubleValue())).compareTo(d) == 0) {
-      double dv = d.doubleValue();
-      qs.add(new DecimalQuantity_SimpleStorage(dv));
-      if (mode == 0) qs.add(new DecimalQuantity_64BitBCD(dv));
-      qs.add(new DecimalQuantity_ByteArrayBCD(dv));
-      qs.add(new DecimalQuantity_DualStorageBCD(dv));
+    private static void testDecimalQuantityRoundingInterval(DecimalQuantity rq0, DecimalQuantity rq1) {
+        DecimalQuantity q0 = rq0.createCopy();
+        DecimalQuantity q1 = rq1.createCopy();
+        q0.roundToIncrement(new BigDecimal("0.05"), MATH_CONTEXT_HALF_EVEN);
+        q1.roundToIncrement(new BigDecimal("0.05"), MATH_CONTEXT_HALF_EVEN);
+        testDecimalQuantityBehavior(q0, q1);
+
+        q0 = rq0.createCopy();
+        q1 = rq1.createCopy();
+        q0.roundToIncrement(new BigDecimal("0.05"), MATH_CONTEXT_CEILING);
+        q1.roundToIncrement(new BigDecimal("0.05"), MATH_CONTEXT_CEILING);
+        testDecimalQuantityBehavior(q0, q1);
     }
 
-    if (new BigDecimal(Long.toString(d.longValue())).compareTo(d) == 0) {
-      double lv = d.longValue();
-      qs.add(new DecimalQuantity_SimpleStorage(lv));
-      if (mode == 0) qs.add(new DecimalQuantity_64BitBCD(lv));
-      qs.add(new DecimalQuantity_ByteArrayBCD(lv));
-      qs.add(new DecimalQuantity_DualStorageBCD(lv));
+    private static void testDecimalQuantityMath(DecimalQuantity rq0, DecimalQuantity rq1) {
+        DecimalQuantity q0 = rq0.createCopy();
+        DecimalQuantity q1 = rq1.createCopy();
+        q0.adjustMagnitude(-3);
+        q1.adjustMagnitude(-3);
+        testDecimalQuantityBehavior(q0, q1);
+
+        q0 = rq0.createCopy();
+        q1 = rq1.createCopy();
+        q0.multiplyBy(new BigDecimal("3.14159"));
+        q1.multiplyBy(new BigDecimal("3.14159"));
+        testDecimalQuantityBehavior(q0, q1);
     }
 
-    testDecimalQuantityExpectedOutput(qs.get(0), str);
-
-    if (qs.size() == 1) {
-      return;
+    private static void testDecimalQuantityWithFormats(
+            DecimalQuantity rq0,
+            DecimalQuantity rq1,
+            List<LocalizedNumberFormatter> formats) {
+        for (LocalizedNumberFormatter format : formats) {
+            DecimalQuantity q0 = rq0.createCopy();
+            DecimalQuantity q1 = rq1.createCopy();
+            String s1 = format.format(q0).toString();
+            String s2 = format.format(q1).toString();
+            assertEquals("Different output from formatter (" + q0 + ", " + q1 + ")", s1, s2);
+        }
     }
 
-    for (int i = 1; i < qs.size(); i++) {
-      DecimalQuantity q0 = qs.get(0);
-      DecimalQuantity q1 = qs.get(i);
-      testDecimalQuantityExpectedOutput(q1, str);
-      testDecimalQuantityRounding(q0, q1);
-      testDecimalQuantityRoundingInterval(q0, q1);
-      testDecimalQuantityMath(q0, q1);
-      testDecimalQuantityWithFormats(q0, q1, formats);
-    }
-  }
-
-  private static void testDecimalQuantityExpectedOutput(DecimalQuantity rq, String expected) {
-    DecimalQuantity q0 = rq.createCopy();
-    // Force an accurate double
-    q0.roundToInfinity();
-    q0.setIntegerLength(1, Integer.MAX_VALUE);
-    q0.setFractionLength(1, Integer.MAX_VALUE);
-    String actual = q0.toPlainString();
-    assertEquals("Unexpected output from simple string conversion (" + q0 + ")", expected, actual);
-  }
-
-  private static final MathContext MATH_CONTEXT_HALF_EVEN =
-      new MathContext(0, RoundingMode.HALF_EVEN);
-  private static final MathContext MATH_CONTEXT_CEILING = new MathContext(0, RoundingMode.CEILING);
-  private static final MathContext MATH_CONTEXT_PRECISION =
-      new MathContext(3, RoundingMode.HALF_UP);
-
-  private static void testDecimalQuantityRounding(DecimalQuantity rq0, DecimalQuantity rq1) {
-    DecimalQuantity q0 = rq0.createCopy();
-    DecimalQuantity q1 = rq1.createCopy();
-    q0.roundToMagnitude(-1, MATH_CONTEXT_HALF_EVEN);
-    q1.roundToMagnitude(-1, MATH_CONTEXT_HALF_EVEN);
-    testDecimalQuantityBehavior(q0, q1);
-
-    q0 = rq0.createCopy();
-    q1 = rq1.createCopy();
-    q0.roundToMagnitude(-1, MATH_CONTEXT_CEILING);
-    q1.roundToMagnitude(-1, MATH_CONTEXT_CEILING);
-    testDecimalQuantityBehavior(q0, q1);
-
-    q0 = rq0.createCopy();
-    q1 = rq1.createCopy();
-    q0.roundToMagnitude(-1, MATH_CONTEXT_PRECISION);
-    q1.roundToMagnitude(-1, MATH_CONTEXT_PRECISION);
-    testDecimalQuantityBehavior(q0, q1);
-  }
-
-  private static void testDecimalQuantityRoundingInterval(DecimalQuantity rq0, DecimalQuantity rq1) {
-    DecimalQuantity q0 = rq0.createCopy();
-    DecimalQuantity q1 = rq1.createCopy();
-    q0.roundToIncrement(new BigDecimal("0.05"), MATH_CONTEXT_HALF_EVEN);
-    q1.roundToIncrement(new BigDecimal("0.05"), MATH_CONTEXT_HALF_EVEN);
-    testDecimalQuantityBehavior(q0, q1);
-
-    q0 = rq0.createCopy();
-    q1 = rq1.createCopy();
-    q0.roundToIncrement(new BigDecimal("0.05"), MATH_CONTEXT_CEILING);
-    q1.roundToIncrement(new BigDecimal("0.05"), MATH_CONTEXT_CEILING);
-    testDecimalQuantityBehavior(q0, q1);
-  }
-
-  private static void testDecimalQuantityMath(DecimalQuantity rq0, DecimalQuantity rq1) {
-    DecimalQuantity q0 = rq0.createCopy();
-    DecimalQuantity q1 = rq1.createCopy();
-    q0.adjustMagnitude(-3);
-    q1.adjustMagnitude(-3);
-    testDecimalQuantityBehavior(q0, q1);
-
-    q0 = rq0.createCopy();
-    q1 = rq1.createCopy();
-    q0.multiplyBy(new BigDecimal("3.14159"));
-    q1.multiplyBy(new BigDecimal("3.14159"));
-    testDecimalQuantityBehavior(q0, q1);
-  }
-
-  private static void testDecimalQuantityWithFormats(
-      DecimalQuantity rq0, DecimalQuantity rq1, List<LocalizedNumberFormatter> formats) {
-    for (LocalizedNumberFormatter format : formats) {
-      DecimalQuantity q0 = rq0.createCopy();
-      DecimalQuantity q1 = rq1.createCopy();
-      String s1 = format.format(q0).toString();
-      String s2 = format.format(q1).toString();
-      assertEquals("Different output from formatter (" + q0 + ", " + q1 + ")", s1, s2);
+    private static void testDecimalQuantityBehavior(DecimalQuantity rq0, DecimalQuantity rq1) {
+        DecimalQuantity q0 = rq0.createCopy();
+        DecimalQuantity q1 = rq1.createCopy();
+
+        assertEquals("Different sign (" + q0 + ", " + q1 + ")", q0.isNegative(), q1.isNegative());
+
+        assertEquals("Different fingerprint (" + q0 + ", " + q1 + ")",
+                q0.getPositionFingerprint(),
+                q1.getPositionFingerprint());
+
+        assertDoubleEquals("Different double values (" + q0 + ", " + q1 + ")",
+                q0.toDouble(),
+                q1.toDouble());
+
+        assertBigDecimalEquals("Different BigDecimal values (" + q0 + ", " + q1 + ")",
+                q0.toBigDecimal(),
+                q1.toBigDecimal());
+
+        q0.roundToInfinity();
+        q1.roundToInfinity();
+
+        assertEquals("Different lower display magnitude",
+                q0.getLowerDisplayMagnitude(),
+                q1.getLowerDisplayMagnitude());
+        assertEquals("Different upper display magnitude",
+                q0.getUpperDisplayMagnitude(),
+                q1.getUpperDisplayMagnitude());
+
+        for (int m = q0.getUpperDisplayMagnitude(); m >= q0.getLowerDisplayMagnitude(); m--) {
+            assertEquals("Different digit at magnitude " + m + " (" + q0 + ", " + q1 + ")",
+                    q0.getDigit(m),
+                    q1.getDigit(m));
+        }
+
+        if (rq0 instanceof DecimalQuantity_DualStorageBCD) {
+            String message = ((DecimalQuantity_DualStorageBCD) rq0).checkHealth();
+            if (message != null)
+                errln(message);
+        }
+        if (rq1 instanceof DecimalQuantity_DualStorageBCD) {
+            String message = ((DecimalQuantity_DualStorageBCD) rq1).checkHealth();
+            if (message != null)
+                errln(message);
+        }
     }
-  }
-
-  private static void testDecimalQuantityBehavior(DecimalQuantity rq0, DecimalQuantity rq1) {
-    DecimalQuantity q0 = rq0.createCopy();
-    DecimalQuantity q1 = rq1.createCopy();
-
-    assertEquals("Different sign (" + q0 + ", " + q1 + ")", q0.isNegative(), q1.isNegative());
-
-    assertEquals(
-        "Different fingerprint (" + q0 + ", " + q1 + ")",
-        q0.getPositionFingerprint(),
-        q1.getPositionFingerprint());
-
-    assertDoubleEquals(
-        "Different double values (" + q0 + ", " + q1 + ")", q0.toDouble(), q1.toDouble());
-
-    assertBigDecimalEquals(
-        "Different BigDecimal values (" + q0 + ", " + q1 + ")",
-        q0.toBigDecimal(),
-        q1.toBigDecimal());
-
-    q0.roundToInfinity();
-    q1.roundToInfinity();
-
-    assertEquals(
-        "Different lower display magnitude",
-        q0.getLowerDisplayMagnitude(),
-        q1.getLowerDisplayMagnitude());
-    assertEquals(
-        "Different upper display magnitude",
-        q0.getUpperDisplayMagnitude(),
-        q1.getUpperDisplayMagnitude());
-
-    for (int m = q0.getUpperDisplayMagnitude(); m >= q0.getLowerDisplayMagnitude(); m--) {
-      assertEquals(
-          "Different digit at magnitude " + m + " (" + q0 + ", " + q1 + ")",
-          q0.getDigit(m),
-          q1.getDigit(m));
+
+    @Test
+    public void testSwitchStorage() {
+        DecimalQuantity_DualStorageBCD fq = new DecimalQuantity_DualStorageBCD();
+
+        fq.setToLong(1234123412341234L);
+        assertFalse("Should not be using byte array", fq.isUsingBytes());
+        assertEquals("Failed on initialize", "1234123412341234E0", fq.toNumberString());
+        assertNull("Failed health check", fq.checkHealth());
+        // Long -> Bytes
+        fq.appendDigit((byte) 5, 0, true);
+        assertTrue("Should be using byte array", fq.isUsingBytes());
+        assertEquals("Failed on multiply", "12341234123412345E0", fq.toNumberString());
+        assertNull("Failed health check", fq.checkHealth());
+        // Bytes -> Long
+        fq.roundToMagnitude(5, MATH_CONTEXT_HALF_EVEN);
+        assertFalse("Should not be using byte array", fq.isUsingBytes());
+        assertEquals("Failed on round", "123412341234E5", fq.toNumberString());
+        assertNull("Failed health check", fq.checkHealth());
     }
 
-    if (rq0 instanceof DecimalQuantity_DualStorageBCD) {
-      String message = ((DecimalQuantity_DualStorageBCD) rq0).checkHealth();
-      if (message != null) errln(message);
+    @Test
+    public void testAppend() {
+        DecimalQuantity_DualStorageBCD fq = new DecimalQuantity_DualStorageBCD();
+        fq.appendDigit((byte) 1, 0, true);
+        assertEquals("Failed on append", "1E0", fq.toNumberString());
+        assertNull("Failed health check", fq.checkHealth());
+        fq.appendDigit((byte) 2, 0, true);
+        assertEquals("Failed on append", "12E0", fq.toNumberString());
+        assertNull("Failed health check", fq.checkHealth());
+        fq.appendDigit((byte) 3, 1, true);
+        assertEquals("Failed on append", "1203E0", fq.toNumberString());
+        assertNull("Failed health check", fq.checkHealth());
+        fq.appendDigit((byte) 0, 1, true);
+        assertEquals("Failed on append", "1203E2", fq.toNumberString());
+        assertNull("Failed health check", fq.checkHealth());
+        fq.appendDigit((byte) 4, 0, true);
+        assertEquals("Failed on append", "1203004E0", fq.toNumberString());
+        assertNull("Failed health check", fq.checkHealth());
+        fq.appendDigit((byte) 0, 0, true);
+        assertEquals("Failed on append", "1203004E1", fq.toNumberString());
+        assertNull("Failed health check", fq.checkHealth());
+        fq.appendDigit((byte) 5, 0, false);
+        assertEquals("Failed on append", "120300405E-1", fq.toNumberString());
+        assertNull("Failed health check", fq.checkHealth());
+        fq.appendDigit((byte) 6, 0, false);
+        assertEquals("Failed on append", "1203004056E-2", fq.toNumberString());
+        assertNull("Failed health check", fq.checkHealth());
+        fq.appendDigit((byte) 7, 3, false);
+        assertEquals("Failed on append", "12030040560007E-6", fq.toNumberString());
+        assertNull("Failed health check", fq.checkHealth());
+        StringBuilder baseExpected = new StringBuilder("12030040560007");
+        for (int i = 0; i < 10; i++) {
+            fq.appendDigit((byte) 8, 0, false);
+            baseExpected.append('8');
+            StringBuilder expected = new StringBuilder(baseExpected);
+            expected.append("E");
+            expected.append(-7 - i);
+            assertEquals("Failed on append", expected.toString(), fq.toNumberString());
+            assertNull("Failed health check", fq.checkHealth());
+        }
+        fq.appendDigit((byte) 9, 2, false);
+        baseExpected.append("009");
+        StringBuilder expected = new StringBuilder(baseExpected);
+        expected.append('E');
+        expected.append("-19");
+        assertEquals("Failed on append", expected.toString(), fq.toNumberString());
+        assertNull("Failed health check", fq.checkHealth());
     }
-    if (rq1 instanceof DecimalQuantity_DualStorageBCD) {
-      String message = ((DecimalQuantity_DualStorageBCD) rq1).checkHealth();
-      if (message != null) errln(message);
+
+    @Ignore
+    @Test
+    public void testConvertToAccurateDouble() {
+        // based on https://github.com/google/double-conversion/issues/28
+        double[] hardDoubles = {
+                1651087494906221570.0,
+                -5074790912492772E-327,
+                83602530019752571E-327,
+                2.207817077636718750000000000000,
+                1.818351745605468750000000000000,
+                3.941719055175781250000000000000,
+                3.738609313964843750000000000000,
+                3.967735290527343750000000000000,
+                1.328025817871093750000000000000,
+                3.920967102050781250000000000000,
+                1.015235900878906250000000000000,
+                1.335227966308593750000000000000,
+                1.344520568847656250000000000000,
+                2.879127502441406250000000000000,
+                3.695838928222656250000000000000,
+                1.845344543457031250000000000000,
+                3.793952941894531250000000000000,
+                3.211402893066406250000000000000,
+                2.565971374511718750000000000000,
+                0.965156555175781250000000000000,
+                2.700004577636718750000000000000,
+                0.767097473144531250000000000000,
+                1.780448913574218750000000000000,
+                2.624839782714843750000000000000,
+                1.305290222167968750000000000000,
+                3.834922790527343750000000000000, };
+
+        double[] integerDoubles = {
+                51423,
+                51423e10,
+                4.503599627370496E15,
+                6.789512076111555E15,
+                9.007199254740991E15,
+                9.007199254740992E15 };
+
+        for (double d : hardDoubles) {
+            checkDoubleBehavior(d, true, "");
+        }
+
+        for (double d : integerDoubles) {
+            checkDoubleBehavior(d, false, "");
+        }
+
+        assertEquals("NaN check failed",
+                Double.NaN,
+                new DecimalQuantity_DualStorageBCD(Double.NaN).toDouble());
+        assertEquals("Inf check failed",
+                Double.POSITIVE_INFINITY,
+                new DecimalQuantity_DualStorageBCD(Double.POSITIVE_INFINITY).toDouble());
+        assertEquals("-Inf check failed",
+                Double.NEGATIVE_INFINITY,
+                new DecimalQuantity_DualStorageBCD(Double.NEGATIVE_INFINITY).toDouble());
+
+        // Generate random doubles
+        String alert = "UNEXPECTED FAILURE: PLEASE REPORT THIS MESSAGE TO THE ICU TEAM: ";
+        Random rnd = new Random();
+        for (int i = 0; i < 10000; i++) {
+            double d = Double.longBitsToDouble(rnd.nextLong());
+            if (Double.isNaN(d) || Double.isInfinite(d))
+                continue;
+            checkDoubleBehavior(d, false, alert);
+        }
     }
-  }
-
-  @Test
-  public void testSwitchStorage() {
-    DecimalQuantity_DualStorageBCD fq = new DecimalQuantity_DualStorageBCD();
-
-    fq.setToLong(1234123412341234L);
-    assertFalse("Should not be using byte array", fq.isUsingBytes());
-    assertEquals("Failed on initialize", "1234123412341234E0", fq.toNumberString());
-    assertNull("Failed health check", fq.checkHealth());
-    // Long -> Bytes
-    fq.appendDigit((byte) 5, 0, true);
-    assertTrue("Should be using byte array", fq.isUsingBytes());
-    assertEquals("Failed on multiply", "12341234123412345E0", fq.toNumberString());
-    assertNull("Failed health check", fq.checkHealth());
-    // Bytes -> Long
-    fq.roundToMagnitude(5, MATH_CONTEXT_HALF_EVEN);
-    assertFalse("Should not be using byte array", fq.isUsingBytes());
-    assertEquals("Failed on round", "123412341234E5", fq.toNumberString());
-    assertNull("Failed health check", fq.checkHealth());
-  }
-
-  @Test
-  public void testAppend() {
-    DecimalQuantity_DualStorageBCD fq = new DecimalQuantity_DualStorageBCD();
-    fq.appendDigit((byte) 1, 0, true);
-    assertEquals("Failed on append", "1E0", fq.toNumberString());
-    assertNull("Failed health check", fq.checkHealth());
-    fq.appendDigit((byte) 2, 0, true);
-    assertEquals("Failed on append", "12E0", fq.toNumberString());
-    assertNull("Failed health check", fq.checkHealth());
-    fq.appendDigit((byte) 3, 1, true);
-    assertEquals("Failed on append", "1203E0", fq.toNumberString());
-    assertNull("Failed health check", fq.checkHealth());
-    fq.appendDigit((byte) 0, 1, true);
-    assertEquals("Failed on append", "1203E2", fq.toNumberString());
-    assertNull("Failed health check", fq.checkHealth());
-    fq.appendDigit((byte) 4, 0, true);
-    assertEquals("Failed on append", "1203004E0", fq.toNumberString());
-    assertNull("Failed health check", fq.checkHealth());
-    fq.appendDigit((byte) 0, 0, true);
-    assertEquals("Failed on append", "1203004E1", fq.toNumberString());
-    assertNull("Failed health check", fq.checkHealth());
-    fq.appendDigit((byte) 5, 0, false);
-    assertEquals("Failed on append", "120300405E-1", fq.toNumberString());
-    assertNull("Failed health check", fq.checkHealth());
-    fq.appendDigit((byte) 6, 0, false);
-    assertEquals("Failed on append", "1203004056E-2", fq.toNumberString());
-    assertNull("Failed health check", fq.checkHealth());
-    fq.appendDigit((byte) 7, 3, false);
-    assertEquals("Failed on append", "12030040560007E-6", fq.toNumberString());
-    assertNull("Failed health check", fq.checkHealth());
-    StringBuilder baseExpected = new StringBuilder("12030040560007");
-    for (int i = 0; i < 10; i++) {
-      fq.appendDigit((byte) 8, 0, false);
-      baseExpected.append('8');
-      StringBuilder expected = new StringBuilder(baseExpected);
-      expected.append("E");
-      expected.append(-7 - i);
-      assertEquals("Failed on append", expected.toString(), fq.toNumberString());
-      assertNull("Failed health check", fq.checkHealth());
+
+    private static void checkDoubleBehavior(double d, boolean explicitRequired, String alert) {
+        DecimalQuantity_DualStorageBCD fq = new DecimalQuantity_DualStorageBCD(d);
+        if (explicitRequired) {
+            assertTrue(alert + "Should be using approximate double", !fq.explicitExactDouble);
+        }
+        assertEquals(alert + "Initial construction from hard double", d, fq.toDouble());
+        fq.roundToInfinity();
+        if (explicitRequired) {
+            assertTrue(alert + "Should not be using approximate double", fq.explicitExactDouble);
+        }
+        assertDoubleEquals(alert + "After conversion to exact BCD (double)", d, fq.toDouble());
+        assertBigDecimalEquals(alert + "After conversion to exact BCD (BigDecimal)",
+                new BigDecimal(Double.toString(d)),
+                fq.toBigDecimal());
     }
-    fq.appendDigit((byte) 9, 2, false);
-    baseExpected.append("009");
-    StringBuilder expected = new StringBuilder(baseExpected);
-    expected.append('E');
-    expected.append("-19");
-    assertEquals("Failed on append", expected.toString(), fq.toNumberString());
-    assertNull("Failed health check", fq.checkHealth());
-  }
-
-  @Ignore
-  @Test
-  public void testConvertToAccurateDouble() {
-    // based on https://github.com/google/double-conversion/issues/28
-    double[] hardDoubles = {
-      1651087494906221570.0,
-      -5074790912492772E-327,
-      83602530019752571E-327,
-      2.207817077636718750000000000000,
-      1.818351745605468750000000000000,
-      3.941719055175781250000000000000,
-      3.738609313964843750000000000000,
-      3.967735290527343750000000000000,
-      1.328025817871093750000000000000,
-      3.920967102050781250000000000000,
-      1.015235900878906250000000000000,
-      1.335227966308593750000000000000,
-      1.344520568847656250000000000000,
-      2.879127502441406250000000000000,
-      3.695838928222656250000000000000,
-      1.845344543457031250000000000000,
-      3.793952941894531250000000000000,
-      3.211402893066406250000000000000,
-      2.565971374511718750000000000000,
-      0.965156555175781250000000000000,
-      2.700004577636718750000000000000,
-      0.767097473144531250000000000000,
-      1.780448913574218750000000000000,
-      2.624839782714843750000000000000,
-      1.305290222167968750000000000000,
-      3.834922790527343750000000000000,
-    };
-
-    double[] integerDoubles = {
-      51423,
-      51423e10,
-      4.503599627370496E15,
-      6.789512076111555E15,
-      9.007199254740991E15,
-      9.007199254740992E15
-    };
-
-    for (double d : hardDoubles) {
-      checkDoubleBehavior(d, true, "");
+
+    @Test
+    public void testUseApproximateDoubleWhenAble() {
+        Object[][] cases = {
+                { 1.2345678, 1, MATH_CONTEXT_HALF_EVEN, false },
+                { 1.2345678, 7, MATH_CONTEXT_HALF_EVEN, false },
+                { 1.2345678, 12, MATH_CONTEXT_HALF_EVEN, false },
+                { 1.2345678, 13, MATH_CONTEXT_HALF_EVEN, true },
+                { 1.235, 1, MATH_CONTEXT_HALF_EVEN, false },
+                { 1.235, 2, MATH_CONTEXT_HALF_EVEN, true },
+                { 1.235, 3, MATH_CONTEXT_HALF_EVEN, false },
+                { 1.000000000000001, 0, MATH_CONTEXT_HALF_EVEN, false },
+                { 1.000000000000001, 0, MATH_CONTEXT_CEILING, true },
+                { 1.235, 1, MATH_CONTEXT_CEILING, false },
+                { 1.235, 2, MATH_CONTEXT_CEILING, false },
+                { 1.235, 3, MATH_CONTEXT_CEILING, true } };
+
+        for (Object[] cas : cases) {
+            double d = (Double) cas[0];
+            int maxFrac = (Integer) cas[1];
+            MathContext mc = (MathContext) cas[2];
+            boolean usesExact = (Boolean) cas[3];
+
+            DecimalQuantity_DualStorageBCD fq = new DecimalQuantity_DualStorageBCD(d);
+            assertTrue("Should be using approximate double", !fq.explicitExactDouble);
+            fq.roundToMagnitude(-maxFrac, mc);
+            assertEquals(
+                    "Using approximate double after rounding: " + d + " maxFrac=" + maxFrac + " " + mc,
+                    usesExact,
+                    fq.explicitExactDouble);
+        }
     }
 
-    for (double d : integerDoubles) {
-      checkDoubleBehavior(d, false, "");
+    @Test
+    public void testDecimalQuantityBehaviorStandalone() {
+        DecimalQuantity_DualStorageBCD fq = new DecimalQuantity_DualStorageBCD();
+        assertToStringAndHealth(fq, "<DecimalQuantity 999:0:0:-999 long 0E0>");
+        fq.setToInt(51423);
+        assertToStringAndHealth(fq, "<DecimalQuantity 999:0:0:-999 long 51423E0>");
+        fq.adjustMagnitude(-3);
+        assertToStringAndHealth(fq, "<DecimalQuantity 999:0:0:-999 long 51423E-3>");
+        fq.setToLong(999999999999000L);
+        assertToStringAndHealth(fq, "<DecimalQuantity 999:0:0:-999 long 999999999999E3>");
+        fq.setIntegerLength(2, 5);
+        assertToStringAndHealth(fq, "<DecimalQuantity 5:2:0:-999 long 999999999999E3>");
+        fq.setFractionLength(3, 6);
+        assertToStringAndHealth(fq, "<DecimalQuantity 5:2:-3:-6 long 999999999999E3>");
+        fq.setToDouble(987.654321);
+        assertToStringAndHealth(fq, "<DecimalQuantity 5:2:-3:-6 long 987654321E-6>");
+        fq.roundToInfinity();
+        assertToStringAndHealth(fq, "<DecimalQuantity 5:2:-3:-6 long 987654321E-6>");
+        fq.roundToIncrement(new BigDecimal("0.005"), MATH_CONTEXT_HALF_EVEN);
+        assertToStringAndHealth(fq, "<DecimalQuantity 5:2:-3:-6 long 987655E-3>");
+        fq.roundToMagnitude(-2, MATH_CONTEXT_HALF_EVEN);
+        assertToStringAndHealth(fq, "<DecimalQuantity 5:2:-3:-6 long 98766E-2>");
     }
 
-    assertEquals("NaN check failed", Double.NaN, new DecimalQuantity_DualStorageBCD(Double.NaN).toDouble());
-    assertEquals(
-        "Inf check failed",
-        Double.POSITIVE_INFINITY,
-        new DecimalQuantity_DualStorageBCD(Double.POSITIVE_INFINITY).toDouble());
-    assertEquals(
-        "-Inf check failed",
-        Double.NEGATIVE_INFINITY,
-        new DecimalQuantity_DualStorageBCD(Double.NEGATIVE_INFINITY).toDouble());
-
-    // Generate random doubles
-    String alert = "UNEXPECTED FAILURE: PLEASE REPORT THIS MESSAGE TO THE ICU TEAM: ";
-    Random rnd = new Random();
-    for (int i = 0; i < 10000; i++) {
-      double d = Double.longBitsToDouble(rnd.nextLong());
-      if (Double.isNaN(d) || Double.isInfinite(d)) continue;
-      checkDoubleBehavior(d, false, alert);
+    static void assertDoubleEquals(String message, double d1, double d2) {
+        boolean equal = (Math.abs(d1 - d2) < 1e-6) || (Math.abs((d1 - d2) / d1) < 1e-6);
+        handleAssert(equal, message, d1, d2, null, false);
     }
-  }
 
-  private static void checkDoubleBehavior(double d, boolean explicitRequired, String alert) {
-    DecimalQuantity_DualStorageBCD fq = new DecimalQuantity_DualStorageBCD(d);
-    if (explicitRequired) {
-      assertTrue(alert + "Should be using approximate double", !fq.explicitExactDouble);
+    static void assertBigDecimalEquals(String message, String d1, BigDecimal d2) {
+        assertBigDecimalEquals(message, new BigDecimal(d1), d2);
     }
-    assertEquals(alert + "Initial construction from hard double", d, fq.toDouble());
-    fq.roundToInfinity();
-    if (explicitRequired) {
-      assertTrue(alert + "Should not be using approximate double", fq.explicitExactDouble);
+
+    static void assertBigDecimalEquals(String message, BigDecimal d1, BigDecimal d2) {
+        boolean equal = d1.compareTo(d2) == 0;
+        handleAssert(equal, message, d1, d2, null, false);
     }
-    assertDoubleEquals(alert + "After conversion to exact BCD (double)", d, fq.toDouble());
-    assertBigDecimalEquals(
-        alert + "After conversion to exact BCD (BigDecimal)",
-        new BigDecimal(Double.toString(d)),
-        fq.toBigDecimal());
-  }
-
-  @Test
-  public void testUseApproximateDoubleWhenAble() {
-    Object[][] cases = {
-      {1.2345678, 1, MATH_CONTEXT_HALF_EVEN, false},
-      {1.2345678, 7, MATH_CONTEXT_HALF_EVEN, false},
-      {1.2345678, 12, MATH_CONTEXT_HALF_EVEN, false},
-      {1.2345678, 13, MATH_CONTEXT_HALF_EVEN, true},
-      {1.235, 1, MATH_CONTEXT_HALF_EVEN, false},
-      {1.235, 2, MATH_CONTEXT_HALF_EVEN, true},
-      {1.235, 3, MATH_CONTEXT_HALF_EVEN, false},
-      {1.000000000000001, 0, MATH_CONTEXT_HALF_EVEN, false},
-      {1.000000000000001, 0, MATH_CONTEXT_CEILING, true},
-      {1.235, 1, MATH_CONTEXT_CEILING, false},
-      {1.235, 2, MATH_CONTEXT_CEILING, false},
-      {1.235, 3, MATH_CONTEXT_CEILING, true}
-    };
-
-    for (Object[] cas : cases) {
-      double d = (Double) cas[0];
-      int maxFrac = (Integer) cas[1];
-      MathContext mc = (MathContext) cas[2];
-      boolean usesExact = (Boolean) cas[3];
-
-      DecimalQuantity_DualStorageBCD fq = new DecimalQuantity_DualStorageBCD(d);
-      assertTrue("Should be using approximate double", !fq.explicitExactDouble);
-      fq.roundToMagnitude(-maxFrac, mc);
-      assertEquals(
-          "Using approximate double after rounding: " + d + " maxFrac=" + maxFrac + " " + mc,
-          usesExact,
-          fq.explicitExactDouble);
+
+    static void assertToStringAndHealth(DecimalQuantity_DualStorageBCD fq, String expected) {
+        String actual = fq.toString();
+        assertEquals("DecimalQuantity toString", expected, actual);
+        String health = fq.checkHealth();
+        assertNull("DecimalQuantity health", health);
     }
-  }
-
-  @Test
-  public void testDecimalQuantityBehaviorStandalone() {
-      DecimalQuantity_DualStorageBCD fq = new DecimalQuantity_DualStorageBCD();
-      assertToStringAndHealth(fq, "<DecimalQuantity 999:0:0:-999 long 0E0>");
-      fq.setToInt(51423);
-      assertToStringAndHealth(fq, "<DecimalQuantity 999:0:0:-999 long 51423E0>");
-      fq.adjustMagnitude(-3);
-      assertToStringAndHealth(fq, "<DecimalQuantity 999:0:0:-999 long 51423E-3>");
-      fq.setToLong(999999999999000L);
-      assertToStringAndHealth(fq, "<DecimalQuantity 999:0:0:-999 long 999999999999E3>");
-      fq.setIntegerLength(2, 5);
-      assertToStringAndHealth(fq, "<DecimalQuantity 5:2:0:-999 long 999999999999E3>");
-      fq.setFractionLength(3, 6);
-      assertToStringAndHealth(fq, "<DecimalQuantity 5:2:-3:-6 long 999999999999E3>");
-      fq.setToDouble(987.654321);
-      assertToStringAndHealth(fq, "<DecimalQuantity 5:2:-3:-6 long 987654321E-6>");
-      fq.roundToInfinity();
-      assertToStringAndHealth(fq, "<DecimalQuantity 5:2:-3:-6 long 987654321E-6>");
-      fq.roundToIncrement(new BigDecimal("0.005"), MATH_CONTEXT_HALF_EVEN);
-      assertToStringAndHealth(fq, "<DecimalQuantity 5:2:-3:-6 long 987655E-3>");
-      fq.roundToMagnitude(-2, MATH_CONTEXT_HALF_EVEN);
-      assertToStringAndHealth(fq, "<DecimalQuantity 5:2:-3:-6 long 98766E-2>");
-  }
-
-  static void assertDoubleEquals(String message, double d1, double d2) {
-    boolean equal = (Math.abs(d1 - d2) < 1e-6) || (Math.abs((d1 - d2) / d1) < 1e-6);
-    handleAssert(equal, message, d1, d2, null, false);
-  }
-
-  static void assertBigDecimalEquals(String message, String d1, BigDecimal d2) {
-    assertBigDecimalEquals(message, new BigDecimal(d1), d2);
-  }
-
-  static void assertBigDecimalEquals(String message, BigDecimal d1, BigDecimal d2) {
-    boolean equal = d1.compareTo(d2) == 0;
-    handleAssert(equal, message, d1, d2, null, false);
-  }
-
-  static void assertToStringAndHealth(DecimalQuantity_DualStorageBCD fq, String expected) {
-      String actual = fq.toString();
-      assertEquals("DecimalQuantity toString", expected, actual);
-      String health = fq.checkHealth();
-      assertNull("DecimalQuantity health", health);
-  }
 }
index 6af4ea1c4a044601947da622e665e94fed46a496..10d768080a4aadb23913ee021d65bf0b3a52261f 100644 (file)
@@ -46,11 +46,20 @@ public class ModifierTest {
     @Test
     public void testSimpleModifier() {
         String[] patterns = { "{0}", "X{0}Y", "XX{0}YYY", "{0}YY", "XX📺XX{0}" };
-        Object[][] outputs = { { "", 0, 0 }, { "a📻bcde", 0, 0 }, { "a📻bcde", 4, 4 }, { "a📻bcde", 3, 5 } };
+        Object[][] outputs = {
+                { "", 0, 0 },
+                { "a📻bcde", 0, 0 },
+                { "a📻bcde", 4, 4 },
+                { "a📻bcde", 3, 5 } };
         int[] prefixLens = { 0, 1, 2, 0, 6 };
-        String[][] expectedCharFields = { { "|", "n" }, { "X|Y", "%n%" }, { "XX|YYY", "%%n%%%" }, { "|YY", "n%%" },
+        String[][] expectedCharFields = {
+                { "|", "n" },
+                { "X|Y", "%n%" },
+                { "XX|YYY", "%%n%%%" },
+                { "|YY", "n%%" },
                 { "XX📺XX|", "%%%%%%n" } };
-        String[][] expecteds = { { "", "XY", "XXYYY", "YY", "XX📺XX" },
+        String[][] expecteds = {
+                { "", "XY", "XXYYY", "YY", "XX📺XX" },
                 { "a📻bcde", "XYa📻bcde", "XXYYYa📻bcde", "YYa📻bcde", "XX📺XXa📻bcde" },
                 { "a📻bcde", "a📻bXYcde", "a📻bXXYYYcde", "a📻bYYcde", "a📻bXX📺XXcde" },
                 { "a📻bcde", "a📻XbcYde", "a📻XXbcYYYde", "a📻bcYYde", "a📻XX📺XXbcde" } };
@@ -59,7 +68,11 @@ public class ModifierTest {
             String compiledPattern = SimpleFormatterImpl
                     .compileToStringMinMaxArguments(pattern, new StringBuilder(), 1, 1);
             Modifier mod = new SimpleModifier(compiledPattern, NumberFormat.Field.PERCENT, false);
-            assertModifierEquals(mod, prefixLens[i], false, expectedCharFields[i][0], expectedCharFields[i][1]);
+            assertModifierEquals(mod,
+                    prefixLens[i],
+                    false,
+                    expectedCharFields[i][0],
+                    expectedCharFields[i][1]);
 
             // Test strange insertion positions
             for (int j = 0; j < outputs.length; j++) {
@@ -99,7 +112,9 @@ public class ModifierTest {
 
         // Test custom patterns
         // The following line means that the last char of the number should be a | (rather than a digit)
-        symbols.setPatternForCurrencySpacing(DecimalFormatSymbols.CURRENCY_SPC_SURROUNDING_MATCH, true, "[|]");
+        symbols.setPatternForCurrencySpacing(DecimalFormatSymbols.CURRENCY_SPC_SURROUNDING_MATCH,
+                true,
+                "[|]");
         suffix.append("XYZ", NumberFormat.Field.CURRENCY);
         Modifier mod3 = new CurrencySpacingEnabledModifier(prefix, suffix, true, symbols);
         assertModifierEquals(mod3, 3, true, "USD|\u00A0XYZ", "$$$nn$$$");
@@ -112,18 +127,18 @@ public class ModifierTest {
         // If this test starts failing, please update the method #getUnicodeSet() in
         // BOTH CurrencySpacingEnabledModifier.java AND in C++.
         DecimalFormatSymbols dfs = DecimalFormatSymbols.getInstance(new ULocale("en-US"));
-        assertEquals(
-                "[:^S:]",
-                dfs.getPatternForCurrencySpacing(DecimalFormatSymbols.CURRENCY_SPC_CURRENCY_MATCH, true));
-        assertEquals(
-                "[:^S:]",
-                dfs.getPatternForCurrencySpacing(DecimalFormatSymbols.CURRENCY_SPC_CURRENCY_MATCH, false));
-        assertEquals(
-                "[:digit:]",
-                dfs.getPatternForCurrencySpacing(DecimalFormatSymbols.CURRENCY_SPC_SURROUNDING_MATCH, true));
-        assertEquals(
-                "[:digit:]",
-                dfs.getPatternForCurrencySpacing(DecimalFormatSymbols.CURRENCY_SPC_SURROUNDING_MATCH, false));
+        assertEquals("[:^S:]",
+                dfs.getPatternForCurrencySpacing(DecimalFormatSymbols.CURRENCY_SPC_CURRENCY_MATCH,
+                        true));
+        assertEquals("[:^S:]",
+                dfs.getPatternForCurrencySpacing(DecimalFormatSymbols.CURRENCY_SPC_CURRENCY_MATCH,
+                        false));
+        assertEquals("[:digit:]",
+                dfs.getPatternForCurrencySpacing(DecimalFormatSymbols.CURRENCY_SPC_SURROUNDING_MATCH,
+                        true));
+        assertEquals("[:digit:]",
+                dfs.getPatternForCurrencySpacing(DecimalFormatSymbols.CURRENCY_SPC_SURROUNDING_MATCH,
+                        false));
     }
 
     private void assertModifierEquals(
@@ -134,7 +149,12 @@ public class ModifierTest {
             String expectedFields) {
         NumberStringBuilder sb = new NumberStringBuilder();
         sb.appendCodePoint('|', null);
-        assertModifierEquals(mod, sb, expectedPrefixLength, expectedStrong, expectedChars, expectedFields);
+        assertModifierEquals(mod,
+                sb,
+                expectedPrefixLength,
+                expectedStrong,
+                expectedChars,
+                expectedFields);
     }
 
     private void assertModifierEquals(
@@ -150,8 +170,10 @@ public class ModifierTest {
         assertEquals("Strong on " + sb, expectedStrong, mod.isStrong());
         if (!(mod instanceof CurrencySpacingEnabledModifier)) {
             assertEquals("Code point count equals actual code point count",
-                    sb.codePointCount() - oldCount, mod.getCodePointCount());
+                    sb.codePointCount() - oldCount,
+                    mod.getCodePointCount());
         }
-        assertEquals("<NumberStringBuilder [" + expectedChars + "] [" + expectedFields + "]>", sb.toDebugString());
+        assertEquals("<NumberStringBuilder [" + expectedChars + "] [" + expectedFields + "]>",
+                sb.toDebugString());
     }
 }
index 80f44ada5d4bb5fb8d21bff624e62a86804478f5..9622e8dd1aae4b27d9d56afaa9282f3876a9f720 100644 (file)
@@ -27,8 +27,7 @@ public class MutablePatternModifierTest {
         MutablePatternModifier mod = new MutablePatternModifier(false);
         mod.setPatternInfo(PatternStringParser.parseToPatternInfo("a0b"));
         mod.setPatternAttributes(SignDisplay.AUTO, false);
-        mod.setSymbols(
-                DecimalFormatSymbols.getInstance(ULocale.ENGLISH),
+        mod.setSymbols(DecimalFormatSymbols.getInstance(ULocale.ENGLISH),
                 Currency.getInstance("USD"),
                 UnitWidth.SHORT,
                 null);
index 8d9814cd697c40420e4093ae0f2a642d85d252f9..3baa78f32131931d355c59c3d249fc551781df2f 100644 (file)
@@ -17,208 +17,207 @@ import com.ibm.icu.text.NumberFormat;
 
 /** @author sffc */
 public class NumberStringBuilderTest {
-  private static final String[] EXAMPLE_STRINGS = {
-    "",
-    "xyz",
-    "The quick brown fox jumps over the lazy dog",
-    "😁",
-    "mixed 😇 and ASCII",
-    "with combining characters like 🇦🇧🇨🇩",
-    "A very very very very very very very very very very long string to force heap"
-  };
-
-  @Test
-  public void testInsertAppendCharSequence() {
-
-    StringBuilder sb1 = new StringBuilder();
-    NumberStringBuilder sb2 = new NumberStringBuilder();
-    for (String str : EXAMPLE_STRINGS) {
-      NumberStringBuilder sb3 = new NumberStringBuilder();
-      sb1.append(str);
-      sb2.append(str, null);
-      sb3.append(str, null);
-      assertCharSequenceEquals(sb1, sb2);
-      assertCharSequenceEquals(sb3, str);
-
-      StringBuilder sb4 = new StringBuilder();
-      NumberStringBuilder sb5 = new NumberStringBuilder();
-      sb4.append("😇");
-      sb4.append(str);
-      sb4.append("xx");
-      sb5.append("😇xx", null);
-      sb5.insert(2, str, null);
-      assertCharSequenceEquals(sb4, sb5);
-
-      int start = Math.min(1, str.length());
-      int end = Math.min(10, str.length());
-      sb4.insert(3, str, start, end);
-      sb5.insert(3, str, start, end, null);
-      assertCharSequenceEquals(sb4, sb5);
-
-      sb4.append(str.toCharArray());
-      sb5.append(str.toCharArray(), null);
-      assertCharSequenceEquals(sb4, sb5);
-
-      sb4.insert(4, str.toCharArray());
-      sb5.insert(4, str.toCharArray(), null);
-      assertCharSequenceEquals(sb4, sb5);
-
-      sb4.append(sb4.toString());
-      sb5.append(new NumberStringBuilder(sb5));
-      assertCharSequenceEquals(sb4, sb5);
+    private static final String[] EXAMPLE_STRINGS = {
+            "",
+            "xyz",
+            "The quick brown fox jumps over the lazy dog",
+            "😁",
+            "mixed 😇 and ASCII",
+            "with combining characters like 🇦🇧🇨🇩",
+            "A very very very very very very very very very very long string to force heap" };
+
+    @Test
+    public void testInsertAppendCharSequence() {
+
+        StringBuilder sb1 = new StringBuilder();
+        NumberStringBuilder sb2 = new NumberStringBuilder();
+        for (String str : EXAMPLE_STRINGS) {
+            NumberStringBuilder sb3 = new NumberStringBuilder();
+            sb1.append(str);
+            sb2.append(str, null);
+            sb3.append(str, null);
+            assertCharSequenceEquals(sb1, sb2);
+            assertCharSequenceEquals(sb3, str);
+
+            StringBuilder sb4 = new StringBuilder();
+            NumberStringBuilder sb5 = new NumberStringBuilder();
+            sb4.append("😇");
+            sb4.append(str);
+            sb4.append("xx");
+            sb5.append("😇xx", null);
+            sb5.insert(2, str, null);
+            assertCharSequenceEquals(sb4, sb5);
+
+            int start = Math.min(1, str.length());
+            int end = Math.min(10, str.length());
+            sb4.insert(3, str, start, end);
+            sb5.insert(3, str, start, end, null);
+            assertCharSequenceEquals(sb4, sb5);
+
+            sb4.append(str.toCharArray());
+            sb5.append(str.toCharArray(), null);
+            assertCharSequenceEquals(sb4, sb5);
+
+            sb4.insert(4, str.toCharArray());
+            sb5.insert(4, str.toCharArray(), null);
+            assertCharSequenceEquals(sb4, sb5);
+
+            sb4.append(sb4.toString());
+            sb5.append(new NumberStringBuilder(sb5));
+            assertCharSequenceEquals(sb4, sb5);
+        }
     }
-  }
-
-  @Test
-  public void testInsertAppendCodePoint() {
-    int[] cases = {0, 1, 60, 127, 128, 0x7fff, 0x8000, 0xffff, 0x10000, 0x1f000, 0x10ffff};
-
-    StringBuilder sb1 = new StringBuilder();
-    NumberStringBuilder sb2 = new NumberStringBuilder();
-    for (int cas : cases) {
-      NumberStringBuilder sb3 = new NumberStringBuilder();
-      sb1.appendCodePoint(cas);
-      sb2.appendCodePoint(cas, null);
-      sb3.appendCodePoint(cas, null);
-      assertCharSequenceEquals(sb1, sb2);
-      assertEquals(Character.codePointAt(sb3, 0), cas);
-
-      StringBuilder sb4 = new StringBuilder();
-      NumberStringBuilder sb5 = new NumberStringBuilder();
-      sb4.append("😇");
-      sb4.appendCodePoint(cas); // Java StringBuilder has no insertCodePoint()
-      sb4.append("xx");
-      sb5.append("😇xx", null);
-      sb5.insertCodePoint(2, cas, null);
-      assertCharSequenceEquals(sb4, sb5);
+
+    @Test
+    public void testInsertAppendCodePoint() {
+        int[] cases = { 0, 1, 60, 127, 128, 0x7fff, 0x8000, 0xffff, 0x10000, 0x1f000, 0x10ffff };
+
+        StringBuilder sb1 = new StringBuilder();
+        NumberStringBuilder sb2 = new NumberStringBuilder();
+        for (int cas : cases) {
+            NumberStringBuilder sb3 = new NumberStringBuilder();
+            sb1.appendCodePoint(cas);
+            sb2.appendCodePoint(cas, null);
+            sb3.appendCodePoint(cas, null);
+            assertCharSequenceEquals(sb1, sb2);
+            assertEquals(Character.codePointAt(sb3, 0), cas);
+
+            StringBuilder sb4 = new StringBuilder();
+            NumberStringBuilder sb5 = new NumberStringBuilder();
+            sb4.append("😇");
+            sb4.appendCodePoint(cas); // Java StringBuilder has no insertCodePoint()
+            sb4.append("xx");
+            sb5.append("😇xx", null);
+            sb5.insertCodePoint(2, cas, null);
+            assertCharSequenceEquals(sb4, sb5);
+        }
     }
-  }
-
-  @Test
-  public void testCopy() {
-    for (String str : EXAMPLE_STRINGS) {
-      NumberStringBuilder sb1 = new NumberStringBuilder();
-      sb1.append(str, null);
-      NumberStringBuilder sb2 = new NumberStringBuilder(sb1);
-      assertCharSequenceEquals(sb1, sb2);
-      assertTrue(sb1.contentEquals(sb2));
-
-      sb1.append("12345", null);
-      assertNotEquals(sb1.length(), sb2.length());
-      assertFalse(sb1.contentEquals(sb2));
+
+    @Test
+    public void testCopy() {
+        for (String str : EXAMPLE_STRINGS) {
+            NumberStringBuilder sb1 = new NumberStringBuilder();
+            sb1.append(str, null);
+            NumberStringBuilder sb2 = new NumberStringBuilder(sb1);
+            assertCharSequenceEquals(sb1, sb2);
+            assertTrue(sb1.contentEquals(sb2));
+
+            sb1.append("12345", null);
+            assertNotEquals(sb1.length(), sb2.length());
+            assertFalse(sb1.contentEquals(sb2));
+        }
     }
-  }
-
-  @Test
-  public void testFields() {
-    for (String str : EXAMPLE_STRINGS) {
-      NumberStringBuilder sb = new NumberStringBuilder();
-      sb.append(str, null);
-      sb.append(str, NumberFormat.Field.CURRENCY);
-      Field[] fields = sb.toFieldArray();
-      assertEquals(str.length() * 2, fields.length);
-      for (int i = 0; i < str.length(); i++) {
-        assertEquals(null, fields[i]);
-        assertEquals(null, sb.fieldAt(i));
-        assertEquals(NumberFormat.Field.CURRENCY, fields[i + str.length()]);
-        assertEquals(NumberFormat.Field.CURRENCY, sb.fieldAt(i + str.length()));
-      }
-
-      // Very basic FieldPosition test. More robust tests happen in NumberFormatTest.
-      // Let NumberFormatTest also take care of AttributedCharacterIterator material.
-      FieldPosition fp = new FieldPosition(NumberFormat.Field.CURRENCY);
-      sb.populateFieldPosition(fp, 0);
-      assertEquals(str.length(), fp.getBeginIndex());
-      assertEquals(str.length() * 2, fp.getEndIndex());
-
-      if (str.length() > 0) {
-        sb.insertCodePoint(2, 100, NumberFormat.Field.INTEGER);
-        fields = sb.toFieldArray();
-        assertEquals(str.length() * 2 + 1, fields.length);
-        assertEquals(fields[2], NumberFormat.Field.INTEGER);
-      }
-
-      sb.append(new NumberStringBuilder(sb));
-      sb.append(sb.toCharArray(), sb.toFieldArray());
-      int numNull = 0;
-      int numCurr = 0;
-      int numInt = 0;
-      Field[] oldFields = fields;
-      fields = sb.toFieldArray();
-      for (int i = 0; i < sb.length(); i++) {
-        assertEquals(oldFields[i % oldFields.length], fields[i]);
-        if (fields[i] == null) {
-          numNull++;
-        } else if (fields[i] == NumberFormat.Field.CURRENCY) {
-          numCurr++;
-        } else if (fields[i] == NumberFormat.Field.INTEGER) {
-          numInt++;
-        } else {
-          throw new AssertionError("Encountered unknown field in " + str);
+
+    @Test
+    public void testFields() {
+        for (String str : EXAMPLE_STRINGS) {
+            NumberStringBuilder sb = new NumberStringBuilder();
+            sb.append(str, null);
+            sb.append(str, NumberFormat.Field.CURRENCY);
+            Field[] fields = sb.toFieldArray();
+            assertEquals(str.length() * 2, fields.length);
+            for (int i = 0; i < str.length(); i++) {
+                assertEquals(null, fields[i]);
+                assertEquals(null, sb.fieldAt(i));
+                assertEquals(NumberFormat.Field.CURRENCY, fields[i + str.length()]);
+                assertEquals(NumberFormat.Field.CURRENCY, sb.fieldAt(i + str.length()));
+            }
+
+            // Very basic FieldPosition test. More robust tests happen in NumberFormatTest.
+            // Let NumberFormatTest also take care of AttributedCharacterIterator material.
+            FieldPosition fp = new FieldPosition(NumberFormat.Field.CURRENCY);
+            sb.populateFieldPosition(fp, 0);
+            assertEquals(str.length(), fp.getBeginIndex());
+            assertEquals(str.length() * 2, fp.getEndIndex());
+
+            if (str.length() > 0) {
+                sb.insertCodePoint(2, 100, NumberFormat.Field.INTEGER);
+                fields = sb.toFieldArray();
+                assertEquals(str.length() * 2 + 1, fields.length);
+                assertEquals(fields[2], NumberFormat.Field.INTEGER);
+            }
+
+            sb.append(new NumberStringBuilder(sb));
+            sb.append(sb.toCharArray(), sb.toFieldArray());
+            int numNull = 0;
+            int numCurr = 0;
+            int numInt = 0;
+            Field[] oldFields = fields;
+            fields = sb.toFieldArray();
+            for (int i = 0; i < sb.length(); i++) {
+                assertEquals(oldFields[i % oldFields.length], fields[i]);
+                if (fields[i] == null) {
+                    numNull++;
+                } else if (fields[i] == NumberFormat.Field.CURRENCY) {
+                    numCurr++;
+                } else if (fields[i] == NumberFormat.Field.INTEGER) {
+                    numInt++;
+                } else {
+                    throw new AssertionError("Encountered unknown field in " + str);
+                }
+            }
+            assertEquals(str.length() * 4, numNull);
+            assertEquals(numNull, numCurr);
+            assertEquals(str.length() > 0 ? 4 : 0, numInt);
+
+            NumberStringBuilder sb2 = new NumberStringBuilder();
+            sb2.append(sb);
+            assertTrue(sb.contentEquals(sb2));
+            assertTrue(sb.contentEquals(sb2.toCharArray(), sb2.toFieldArray()));
+
+            sb2.insertCodePoint(0, 50, NumberFormat.Field.FRACTION);
+            assertTrue(!sb.contentEquals(sb2));
+            assertTrue(!sb.contentEquals(sb2.toCharArray(), sb2.toFieldArray()));
         }
-      }
-      assertEquals(str.length() * 4, numNull);
-      assertEquals(numNull, numCurr);
-      assertEquals(str.length() > 0 ? 4 : 0, numInt);
-
-      NumberStringBuilder sb2 = new NumberStringBuilder();
-      sb2.append(sb);
-      assertTrue(sb.contentEquals(sb2));
-      assertTrue(sb.contentEquals(sb2.toCharArray(), sb2.toFieldArray()));
-
-      sb2.insertCodePoint(0, 50, NumberFormat.Field.FRACTION);
-      assertTrue(!sb.contentEquals(sb2));
-      assertTrue(!sb.contentEquals(sb2.toCharArray(), sb2.toFieldArray()));
     }
-  }
-
-  @Test
-  public void testUnlimitedCapacity() {
-    NumberStringBuilder builder = new NumberStringBuilder();
-    // The builder should never fail upon repeated appends.
-    for (int i = 0; i < 1000; i++) {
-      assertEquals(builder.length(), i);
-      builder.appendCodePoint('x', null);
-      assertEquals(builder.length(), i + 1);
+
+    @Test
+    public void testUnlimitedCapacity() {
+        NumberStringBuilder builder = new NumberStringBuilder();
+        // The builder should never fail upon repeated appends.
+        for (int i = 0; i < 1000; i++) {
+            assertEquals(builder.length(), i);
+            builder.appendCodePoint('x', null);
+            assertEquals(builder.length(), i + 1);
+        }
     }
-  }
-
-  @Test
-  public void testCodePoints() {
-      NumberStringBuilder nsb = new NumberStringBuilder();
-      assertEquals("First is -1 on empty string", -1, nsb.getFirstCodePoint());
-      assertEquals("Last is -1 on empty string", -1, nsb.getLastCodePoint());
-      assertEquals("Length is 0 on empty string", 0, nsb.codePointCount());
-
-      nsb.append("q", null);
-      assertEquals("First is q", 'q', nsb.getFirstCodePoint());
-      assertEquals("Last is q", 'q', nsb.getLastCodePoint());
-      assertEquals("0th is q", 'q', nsb.codePointAt(0));
-      assertEquals("Before 1st is q", 'q', nsb.codePointBefore(1));
-      assertEquals("Code point count is 1", 1, nsb.codePointCount());
-
-      // 🚀 is two char16s
-      nsb.append("🚀", null);
-      assertEquals("First is still q", 'q', nsb.getFirstCodePoint());
-      assertEquals("Last is space ship", 128640, nsb.getLastCodePoint());
-      assertEquals("1st is space ship", 128640, nsb.codePointAt(1));
-      assertEquals("Before 1st is q", 'q', nsb.codePointBefore(1));
-      assertEquals("Before 3rd is space ship", 128640, nsb.codePointBefore(3));
-      assertEquals("Code point count is 2", 2, nsb.codePointCount());
-  }
-
-  private static void assertCharSequenceEquals(CharSequence a, CharSequence b) {
-    assertEquals(a.toString(), b.toString());
-
-    assertEquals(a.length(), b.length());
-    for (int i = 0; i < a.length(); i++) {
-      assertEquals(a.charAt(i), b.charAt(i));
+
+    @Test
+    public void testCodePoints() {
+        NumberStringBuilder nsb = new NumberStringBuilder();
+        assertEquals("First is -1 on empty string", -1, nsb.getFirstCodePoint());
+        assertEquals("Last is -1 on empty string", -1, nsb.getLastCodePoint());
+        assertEquals("Length is 0 on empty string", 0, nsb.codePointCount());
+
+        nsb.append("q", null);
+        assertEquals("First is q", 'q', nsb.getFirstCodePoint());
+        assertEquals("Last is q", 'q', nsb.getLastCodePoint());
+        assertEquals("0th is q", 'q', nsb.codePointAt(0));
+        assertEquals("Before 1st is q", 'q', nsb.codePointBefore(1));
+        assertEquals("Code point count is 1", 1, nsb.codePointCount());
+
+        // 🚀 is two char16s
+        nsb.append("🚀", null);
+        assertEquals("First is still q", 'q', nsb.getFirstCodePoint());
+        assertEquals("Last is space ship", 128640, nsb.getLastCodePoint());
+        assertEquals("1st is space ship", 128640, nsb.codePointAt(1));
+        assertEquals("Before 1st is q", 'q', nsb.codePointBefore(1));
+        assertEquals("Before 3rd is space ship", 128640, nsb.codePointBefore(3));
+        assertEquals("Code point count is 2", 2, nsb.codePointCount());
     }
 
-    int start = Math.min(2, a.length());
-    int end = Math.min(12, a.length());
-    if (start != end) {
-      assertCharSequenceEquals(a.subSequence(start, end), b.subSequence(start, end));
+    private static void assertCharSequenceEquals(CharSequence a, CharSequence b) {
+        assertEquals(a.toString(), b.toString());
+
+        assertEquals(a.length(), b.length());
+        for (int i = 0; i < a.length(); i++) {
+            assertEquals(a.charAt(i), b.charAt(i));
+        }
+
+        int start = Math.min(2, a.length());
+        int end = Math.min(12, a.length());
+        if (start != end) {
+            assertCharSequenceEquals(a.subSequence(start, end), b.subSequence(start, end));
+        }
     }
-  }
 }
index b0979839862a7426e35ca7d8b29a8a800ab14334..93afd75376320736b1ef07a82e1523c3927f1b91 100644 (file)
@@ -16,104 +16,113 @@ import com.ibm.icu.util.ULocale;
 /** @author sffc */
 public class PatternStringTest {
 
-  @Test
-  public void testLocalized() {
-    DecimalFormatSymbols symbols = DecimalFormatSymbols.getInstance(ULocale.ENGLISH);
-    symbols.setDecimalSeparatorString("a");
-    symbols.setPercentString("b");
-    symbols.setMinusSignString(".");
-    symbols.setPlusSignString("'");
-
-    String standard = "+-abcb''a''#,##0.0%'a%'";
-    String localized = "’.'ab'c'b''a'''#,##0a0b'a%'";
-    String toStandard = "+-'ab'c'b''a'''#,##0.0%'a%'";
-
-    assertEquals(localized, PatternStringUtils.convertLocalized(standard, symbols, true));
-    assertEquals(toStandard, PatternStringUtils.convertLocalized(localized, symbols, false));
-  }
-
-  @Test
-  public void testToPatternSimple() {
-    String[][] cases = {
-      {"#", "0"},
-      {"0", "0"},
-      {"#0", "0"},
-      {"###", "0"},
-      {"0.##", "0.##"},
-      {"0.00", "0.00"},
-      {"0.00#", "0.00#"},
-      {"#E0", "#E0"},
-      {"0E0", "0E0"},
-      {"#00E00", "#00E00"},
-      {"#,##0", "#,##0"},
-      {"#;#", "0;0"},
-      {"#;-#", "0"}, // ignore a negative prefix pattern of '-' since that is the default
-      {"**##0", "**##0"},
-      {"*'x'##0", "*x##0"},
-      {"a''b0", "a''b0"},
-      {"*''##0", "*''##0"},
-      {"*📺##0", "*'📺'##0"},
-      {"*'நி'##0", "*'நி'##0"},
-    };
-
-    for (String[] cas : cases) {
-      String input = cas[0];
-      String output = cas[1];
-
-      DecimalFormatProperties properties = PatternStringParser.parseToProperties(input);
-      String actual = PatternStringUtils.propertiesToPatternString(properties);
-      assertEquals(
-          "Failed on input pattern '" + input + "', properties " + properties, output, actual);
+    @Test
+    public void testLocalized() {
+        DecimalFormatSymbols symbols = DecimalFormatSymbols.getInstance(ULocale.ENGLISH);
+        symbols.setDecimalSeparatorString("a");
+        symbols.setPercentString("b");
+        symbols.setMinusSignString(".");
+        symbols.setPlusSignString("'");
+
+        String standard = "+-abcb''a''#,##0.0%'a%'";
+        String localized = "’.'ab'c'b''a'''#,##0a0b'a%'";
+        String toStandard = "+-'ab'c'b''a'''#,##0.0%'a%'";
+
+        assertEquals(localized, PatternStringUtils.convertLocalized(standard, symbols, true));
+        assertEquals(toStandard, PatternStringUtils.convertLocalized(localized, symbols, false));
     }
-  }
-
-  @Test
-  public void testToPatternWithProperties() {
-    Object[][] cases = {
-      {new DecimalFormatProperties().setPositivePrefix("abc"), "abc#"},
-      {new DecimalFormatProperties().setPositiveSuffix("abc"), "#abc"},
-      {new DecimalFormatProperties().setPositivePrefixPattern("abc"), "abc#"},
-      {new DecimalFormatProperties().setPositiveSuffixPattern("abc"), "#abc"},
-      {new DecimalFormatProperties().setNegativePrefix("abc"), "#;abc#"},
-      {new DecimalFormatProperties().setNegativeSuffix("abc"), "#;#abc"},
-      {new DecimalFormatProperties().setNegativePrefixPattern("abc"), "#;abc#"},
-      {new DecimalFormatProperties().setNegativeSuffixPattern("abc"), "#;#abc"},
-      {new DecimalFormatProperties().setPositivePrefix("+"), "'+'#"},
-      {new DecimalFormatProperties().setPositivePrefixPattern("+"), "+#"},
-      {new DecimalFormatProperties().setPositivePrefix("+'"), "'+'''#"},
-      {new DecimalFormatProperties().setPositivePrefix("'+"), "'''+'#"},
-      {new DecimalFormatProperties().setPositivePrefix("'"), "''#"},
-      {new DecimalFormatProperties().setPositivePrefixPattern("+''"), "+''#"},
-    };
-
-    for (Object[] cas : cases) {
-      DecimalFormatProperties input = (DecimalFormatProperties) cas[0];
-      String output = (String) cas[1];
-
-      String actual = PatternStringUtils.propertiesToPatternString(input);
-      assertEquals("Failed on input properties " + input, output, actual);
+
+    @Test
+    public void testToPatternSimple() {
+        String[][] cases = {
+                { "#", "0" },
+                { "0", "0" },
+                { "#0", "0" },
+                { "###", "0" },
+                { "0.##", "0.##" },
+                { "0.00", "0.00" },
+                { "0.00#", "0.00#" },
+                { "#E0", "#E0" },
+                { "0E0", "0E0" },
+                { "#00E00", "#00E00" },
+                { "#,##0", "#,##0" },
+                { "#;#", "0;0" },
+                { "#;-#", "0" }, // ignore a negative prefix pattern of '-' since that is the default
+                { "**##0", "**##0" },
+                { "*'x'##0", "*x##0" },
+                { "a''b0", "a''b0" },
+                { "*''##0", "*''##0" },
+                { "*📺##0", "*'📺'##0" },
+                { "*'நி'##0", "*'நி'##0" }, };
+
+        for (String[] cas : cases) {
+            String input = cas[0];
+            String output = cas[1];
+
+            DecimalFormatProperties properties = PatternStringParser.parseToProperties(input);
+            String actual = PatternStringUtils.propertiesToPatternString(properties);
+            assertEquals("Failed on input pattern '" + input + "', properties " + properties,
+                    output,
+                    actual);
+        }
+    }
+
+    @Test
+    public void testToPatternWithProperties() {
+        Object[][] cases = {
+                { new DecimalFormatProperties().setPositivePrefix("abc"), "abc#" },
+                { new DecimalFormatProperties().setPositiveSuffix("abc"), "#abc" },
+                { new DecimalFormatProperties().setPositivePrefixPattern("abc"), "abc#" },
+                { new DecimalFormatProperties().setPositiveSuffixPattern("abc"), "#abc" },
+                { new DecimalFormatProperties().setNegativePrefix("abc"), "#;abc#" },
+                { new DecimalFormatProperties().setNegativeSuffix("abc"), "#;#abc" },
+                { new DecimalFormatProperties().setNegativePrefixPattern("abc"), "#;abc#" },
+                { new DecimalFormatProperties().setNegativeSuffixPattern("abc"), "#;#abc" },
+                { new DecimalFormatProperties().setPositivePrefix("+"), "'+'#" },
+                { new DecimalFormatProperties().setPositivePrefixPattern("+"), "+#" },
+                { new DecimalFormatProperties().setPositivePrefix("+'"), "'+'''#" },
+                { new DecimalFormatProperties().setPositivePrefix("'+"), "'''+'#" },
+                { new DecimalFormatProperties().setPositivePrefix("'"), "''#" },
+                { new DecimalFormatProperties().setPositivePrefixPattern("+''"), "+''#" }, };
+
+        for (Object[] cas : cases) {
+            DecimalFormatProperties input = (DecimalFormatProperties) cas[0];
+            String output = (String) cas[1];
+
+            String actual = PatternStringUtils.propertiesToPatternString(input);
+            assertEquals("Failed on input properties " + input, output, actual);
+        }
     }
-  }
-
-  @Test
-  public void testExceptionOnInvalid() {
-    String[] invalidPatterns = {
-      "#.#.#", "0#", "0#.", ".#0", "0#.#0", "@0", "0@", "0,", "0,,", "0,,0", "0,,0,", "#,##0E0"
-    };
-
-    for (String pattern : invalidPatterns) {
-      try {
-        PatternStringParser.parseToProperties(pattern);
-        fail("Didn't throw IllegalArgumentException when parsing pattern: " + pattern);
-      } catch (IllegalArgumentException e) {
-      }
+
+    @Test
+    public void testExceptionOnInvalid() {
+        String[] invalidPatterns = {
+                "#.#.#",
+                "0#",
+                "0#.",
+                ".#0",
+                "0#.#0",
+                "@0",
+                "0@",
+                "0,",
+                "0,,",
+                "0,,0",
+                "0,,0,",
+                "#,##0E0" };
+
+        for (String pattern : invalidPatterns) {
+            try {
+                PatternStringParser.parseToProperties(pattern);
+                fail("Didn't throw IllegalArgumentException when parsing pattern: " + pattern);
+            } catch (IllegalArgumentException e) {
+            }
+        }
+    }
+
+    @Test
+    public void testBug13117() {
+        DecimalFormatProperties expected = PatternStringParser.parseToProperties("0");
+        DecimalFormatProperties actual = PatternStringParser.parseToProperties("0;");
+        assertEquals("Should not consume negative subpattern", expected, actual);
     }
-  }
-
-  @Test
-  public void testBug13117() {
-    DecimalFormatProperties expected = PatternStringParser.parseToProperties("0");
-    DecimalFormatProperties actual = PatternStringParser.parseToProperties("0;");
-    assertEquals("Should not consume negative subpattern", expected, actual);
-  }
 }
index a93b7673dda6ce9ac1a4001b3967c2558dcf82d4..dc4611ae3d3b0382a1929d9db744ee54a4e5f557 100644 (file)
@@ -45,322 +45,341 @@ import com.ibm.icu.util.ULocale;
 
 public class PropertiesTest {
 
-  @Test
-  public void testBasicEquals() {
-    DecimalFormatProperties p1 = new DecimalFormatProperties();
-    DecimalFormatProperties p2 = new DecimalFormatProperties();
-    assertEquals(p1, p2);
-
-    p1.setPositivePrefix("abc");
-    assertNotEquals(p1, p2);
-    p2.setPositivePrefix("xyz");
-    assertNotEquals(p1, p2);
-    p1.setPositivePrefix("xyz");
-    assertEquals(p1, p2);
-  }
-
-  @Test
-  public void testFieldCoverage() {
-    DecimalFormatProperties p0 = new DecimalFormatProperties();
-    DecimalFormatProperties p1 = new DecimalFormatProperties();
-    DecimalFormatProperties p2 = new DecimalFormatProperties();
-    DecimalFormatProperties p3 = new DecimalFormatProperties();
-    DecimalFormatProperties p4 = new DecimalFormatProperties();
-
-    Set<Integer> hashCodes = new HashSet<Integer>();
-    Field[] fields = DecimalFormatProperties.class.getDeclaredFields();
-    for (Field field : fields) {
-      if (Modifier.isStatic(field.getModifiers())) {
-        continue;
-      }
-
-      // Check for getters and setters
-      String fieldNamePascalCase =
-          Character.toUpperCase(field.getName().charAt(0)) + field.getName().substring(1);
-      String getterName = "get" + fieldNamePascalCase;
-      String setterName = "set" + fieldNamePascalCase;
-      Method getter, setter;
-      try {
-        getter = DecimalFormatProperties.class.getMethod(getterName);
-        assertEquals(
-            "Getter does not return correct type", field.getType(), getter.getReturnType());
-      } catch (NoSuchMethodException e) {
-        fail("Could not find method " + getterName + " for field " + field);
-        continue;
-      } catch (SecurityException e) {
-        fail("Could not access method " + getterName + " for field " + field);
-        continue;
-      }
-      try {
-        setter = DecimalFormatProperties.class.getMethod(setterName, field.getType());
-        assertEquals(
-            "Method " + setterName + " does not return correct type",
-            DecimalFormatProperties.class,
-            setter.getReturnType());
-      } catch (NoSuchMethodException e) {
-        fail("Could not find method " + setterName + " for field " + field);
-        continue;
-      } catch (SecurityException e) {
-        fail("Could not access method " + setterName + " for field " + field);
-        continue;
-      }
-
-      // Check for parameter name equality.
-      // The parameter name is not always available, depending on compiler settings.
-      // TODO: Enable in Java 8
-      /*
-      Parameter param = setter.getParameters()[0];
-      if (!param.getName().subSequence(0, 3).equals("arg")) {
-        assertEquals("Parameter name should equal field name", field.getName(), param.getName());
-      }
-      */
-
-      try {
-        // Check for default value (should be null for objects)
-        if (field.getType() != Integer.TYPE && field.getType() != Boolean.TYPE) {
-          Object default0 = getter.invoke(p0);
-          assertEquals("Field " + field + " has non-null default value:", null, default0);
-        }
-
-        // Check for getter, equals, and hash code behavior
-        Object val0 = getSampleValueForType(field.getType(), 0);
-        Object val1 = getSampleValueForType(field.getType(), 1);
-        Object val2 = getSampleValueForType(field.getType(), 2);
-        assertNotEquals(val0, val1);
-        setter.invoke(p1, val0);
-        setter.invoke(p2, val0);
-        assertEquals(p1, p2);
-        assertEquals(p1.hashCode(), p2.hashCode());
-        assertEquals(getter.invoke(p1), getter.invoke(p2));
-        assertEquals(getter.invoke(p1), val0);
-        assertNotEquals(getter.invoke(p1), val1);
-        hashCodes.add(p1.hashCode());
-        setter.invoke(p1, val1);
-        assertNotEquals("Field " + field + " is missing from equals()", p1, p2);
-        assertNotEquals(getter.invoke(p1), getter.invoke(p2));
-        assertNotEquals(getter.invoke(p1), val0);
-        assertEquals(getter.invoke(p1), val1);
-        setter.invoke(p1, val0);
-        assertEquals("Field " + field + " setter might have side effects", p1, p2);
-        assertEquals(p1.hashCode(), p2.hashCode());
-        assertEquals(getter.invoke(p1), getter.invoke(p2));
-        setter.invoke(p1, val1);
-        setter.invoke(p2, val1);
+    @Test
+    public void testBasicEquals() {
+        DecimalFormatProperties p1 = new DecimalFormatProperties();
+        DecimalFormatProperties p2 = new DecimalFormatProperties();
         assertEquals(p1, p2);
-        assertEquals(p1.hashCode(), p2.hashCode());
-        assertEquals(getter.invoke(p1), getter.invoke(p2));
-        setter.invoke(p1, val2);
-        setter.invoke(p1, val1);
-        assertEquals("Field " + field + " setter might have side effects", p1, p2);
-        assertEquals(p1.hashCode(), p2.hashCode());
-        assertEquals(getter.invoke(p1), getter.invoke(p2));
-        hashCodes.add(p1.hashCode());
-
-        // Check for clone behavior
-        DecimalFormatProperties copy = p1.clone();
-        assertEquals("Field " + field + " did not get copied in clone", p1, copy);
-        assertEquals(p1.hashCode(), copy.hashCode());
-        assertEquals(getter.invoke(p1), getter.invoke(copy));
-
-        // Check for copyFrom behavior
-        setter.invoke(p1, val0);
+
+        p1.setPositivePrefix("abc");
+        assertNotEquals(p1, p2);
+        p2.setPositivePrefix("xyz");
         assertNotEquals(p1, p2);
-        assertNotEquals(getter.invoke(p1), getter.invoke(p2));
-        p2.copyFrom(p1);
-        assertEquals("Field " + field + " is missing from copyFrom()", p1, p2);
-        assertEquals(p1.hashCode(), p2.hashCode());
-        assertEquals(getter.invoke(p1), getter.invoke(p2));
-
-        // Load values into p3 and p4 for clear() behavior test
-        setter.invoke(p3, getSampleValueForType(field.getType(), 3));
-        hashCodes.add(p3.hashCode());
-        setter.invoke(p4, getSampleValueForType(field.getType(), 4));
-        hashCodes.add(p4.hashCode());
-      } catch (IllegalAccessException e) {
-        fail("Could not access method for field " + field);
-      } catch (IllegalArgumentException e) {
-        fail("Could call method for field " + field);
-      } catch (InvocationTargetException e) {
-        fail("Could invoke method on target for field " + field);
-      }
+        p1.setPositivePrefix("xyz");
+        assertEquals(p1, p2);
     }
 
-    // Check for clear() behavior
-    assertNotEquals(p3, p4);
-    p3.clear();
-    p4.clear();
-    assertEquals("A field is missing from the clear() function", p3, p4);
-
-    // A good hashCode() implementation should produce very few collisions.  We added at most
-    // 4*fields.length codes to the set.  We'll say the implementation is good if we had at least
-    // fields.length unique values.
-    // TODO: Should the requirement be stronger than this?
-    assertTrue(
-        "Too many hash code collisions: " + hashCodes.size() + " out of " + (fields.length * 4),
-        hashCodes.size() >= fields.length);
-  }
-
-  /**
-   * Creates a valid sample instance of the given type. Used to simulate getters and setters.
-   *
-   * @param type The type to generate.
-   * @param seed An integer seed, guaranteed to be positive. The same seed should generate two
-   *     instances that are equal. A different seed should in general generate two instances that
-   *     are not equal; this might not always be possible, such as with booleans or enums where
-   *     there are limited possible values.
-   * @return An instance of the specified type.
-   */
-  Object getSampleValueForType(Class<?> type, int seed) {
-    if (type == Integer.TYPE) {
-      return seed * 1000001;
-
-    } else if (type == Boolean.TYPE) {
-      return (seed % 2) == 0;
-
-    } else if (type == BigDecimal.class) {
-      if (seed == 0) return null;
-      return new BigDecimal(seed * 1000002);
-
-    } else if (type == String.class) {
-      if (seed == 0) return null;
-      return BigInteger.valueOf(seed * 1000003).toString(32);
-
-    } else if (type == CompactStyle.class) {
-      if (seed == 0) return null;
-      CompactStyle[] values = CompactStyle.values();
-      return values[seed % values.length];
-
-    } else if (type == Currency.class) {
-      if (seed == 0) return null;
-      Object[] currencies = Currency.getAvailableCurrencies().toArray();
-      return currencies[seed % currencies.length];
-
-    } else if (type == CurrencyPluralInfo.class) {
-      if (seed == 0) return null;
-      ULocale[] locales = ULocale.getAvailableLocales();
-      return CurrencyPluralInfo.getInstance(locales[seed % locales.length]);
-
-    } else if (type == CurrencyUsage.class) {
-      if (seed == 0) return null;
-      CurrencyUsage[] values = CurrencyUsage.values();
-      return values[seed % values.length];
-
-    } else if (type == GroupingMode.class) {
-      if (seed == 0) return null;
-      GroupingMode[] values = GroupingMode.values();
-      return values[seed % values.length];
-
-    } else if (type == FormatWidth.class) {
-      if (seed == 0) return null;
-      FormatWidth[] values = FormatWidth.values();
-      return values[seed % values.length];
-
-    } else if (type == Map.class) {
-      // Map<String,Map<String,String>> for compactCustomData property
-      if (seed == 0) return null;
-      Map<String, Map<String, String>> outer = new HashMap<String, Map<String, String>>();
-      Map<String, String> inner = new HashMap<String, String>();
-      inner.put("one", "0 thousand");
-      StringBuilder magnitudeKey = new StringBuilder();
-      magnitudeKey.append("1000");
-      for (int i = 0; i < seed % 9; i++) {
-        magnitudeKey.append("0");
-      }
-      outer.put(magnitudeKey.toString(), inner);
-      return outer;
-
-    } else if (type == MathContext.class) {
-      if (seed == 0) return null;
-      RoundingMode[] modes = RoundingMode.values();
-      return new MathContext(seed, modes[seed % modes.length]);
-
-    } else if (type == MeasureUnit.class) {
-      if (seed == 0) return null;
-      Object[] units = MeasureUnit.getAvailable().toArray();
-      return units[seed % units.length];
-
-    } else if (type == PadPosition.class) {
-      if (seed == 0) return null;
-      PadPosition[] values = PadPosition.values();
-      return values[seed % values.length];
-
-    } else if (type == ParseMode.class) {
-      if (seed == 0) return null;
-      ParseMode[] values = ParseMode.values();
-      return values[seed % values.length];
-
-    } else if (type == PluralRules.class) {
-      if (seed == 0) return null;
-      ULocale[] locales = PluralRules.getAvailableULocales();
-      return PluralRules.forLocale(locales[seed % locales.length]);
-
-    } else if (type == RoundingMode.class) {
-      if (seed == 0) return null;
-      RoundingMode[] values = RoundingMode.values();
-      return values[seed % values.length];
-
-    } else {
-      fail("Don't know how to handle type " + type + ". Please add it to getSampleValueForType().");
-      return null;
+    @Test
+    public void testFieldCoverage() {
+        DecimalFormatProperties p0 = new DecimalFormatProperties();
+        DecimalFormatProperties p1 = new DecimalFormatProperties();
+        DecimalFormatProperties p2 = new DecimalFormatProperties();
+        DecimalFormatProperties p3 = new DecimalFormatProperties();
+        DecimalFormatProperties p4 = new DecimalFormatProperties();
+
+        Set<Integer> hashCodes = new HashSet<Integer>();
+        Field[] fields = DecimalFormatProperties.class.getDeclaredFields();
+        for (Field field : fields) {
+            if (Modifier.isStatic(field.getModifiers())) {
+                continue;
+            }
+
+            // Check for getters and setters
+            String fieldNamePascalCase = Character.toUpperCase(field.getName().charAt(0))
+                    + field.getName().substring(1);
+            String getterName = "get" + fieldNamePascalCase;
+            String setterName = "set" + fieldNamePascalCase;
+            Method getter, setter;
+            try {
+                getter = DecimalFormatProperties.class.getMethod(getterName);
+                assertEquals("Getter does not return correct type",
+                        field.getType(),
+                        getter.getReturnType());
+            } catch (NoSuchMethodException e) {
+                fail("Could not find method " + getterName + " for field " + field);
+                continue;
+            } catch (SecurityException e) {
+                fail("Could not access method " + getterName + " for field " + field);
+                continue;
+            }
+            try {
+                setter = DecimalFormatProperties.class.getMethod(setterName, field.getType());
+                assertEquals("Method " + setterName + " does not return correct type",
+                        DecimalFormatProperties.class,
+                        setter.getReturnType());
+            } catch (NoSuchMethodException e) {
+                fail("Could not find method " + setterName + " for field " + field);
+                continue;
+            } catch (SecurityException e) {
+                fail("Could not access method " + setterName + " for field " + field);
+                continue;
+            }
+
+            // Check for parameter name equality.
+            // The parameter name is not always available, depending on compiler settings.
+            // TODO: Enable in Java 8
+            /*
+             * Parameter param = setter.getParameters()[0]; if (!param.getName().subSequence(0,
+             * 3).equals("arg")) { assertEquals("Parameter name should equal field name",
+             * field.getName(), param.getName()); }
+             */
+
+            try {
+                // Check for default value (should be null for objects)
+                if (field.getType() != Integer.TYPE && field.getType() != Boolean.TYPE) {
+                    Object default0 = getter.invoke(p0);
+                    assertEquals("Field " + field + " has non-null default value:", null, default0);
+                }
+
+                // Check for getter, equals, and hash code behavior
+                Object val0 = getSampleValueForType(field.getType(), 0);
+                Object val1 = getSampleValueForType(field.getType(), 1);
+                Object val2 = getSampleValueForType(field.getType(), 2);
+                assertNotEquals(val0, val1);
+                setter.invoke(p1, val0);
+                setter.invoke(p2, val0);
+                assertEquals(p1, p2);
+                assertEquals(p1.hashCode(), p2.hashCode());
+                assertEquals(getter.invoke(p1), getter.invoke(p2));
+                assertEquals(getter.invoke(p1), val0);
+                assertNotEquals(getter.invoke(p1), val1);
+                hashCodes.add(p1.hashCode());
+                setter.invoke(p1, val1);
+                assertNotEquals("Field " + field + " is missing from equals()", p1, p2);
+                assertNotEquals(getter.invoke(p1), getter.invoke(p2));
+                assertNotEquals(getter.invoke(p1), val0);
+                assertEquals(getter.invoke(p1), val1);
+                setter.invoke(p1, val0);
+                assertEquals("Field " + field + " setter might have side effects", p1, p2);
+                assertEquals(p1.hashCode(), p2.hashCode());
+                assertEquals(getter.invoke(p1), getter.invoke(p2));
+                setter.invoke(p1, val1);
+                setter.invoke(p2, val1);
+                assertEquals(p1, p2);
+                assertEquals(p1.hashCode(), p2.hashCode());
+                assertEquals(getter.invoke(p1), getter.invoke(p2));
+                setter.invoke(p1, val2);
+                setter.invoke(p1, val1);
+                assertEquals("Field " + field + " setter might have side effects", p1, p2);
+                assertEquals(p1.hashCode(), p2.hashCode());
+                assertEquals(getter.invoke(p1), getter.invoke(p2));
+                hashCodes.add(p1.hashCode());
+
+                // Check for clone behavior
+                DecimalFormatProperties copy = p1.clone();
+                assertEquals("Field " + field + " did not get copied in clone", p1, copy);
+                assertEquals(p1.hashCode(), copy.hashCode());
+                assertEquals(getter.invoke(p1), getter.invoke(copy));
+
+                // Check for copyFrom behavior
+                setter.invoke(p1, val0);
+                assertNotEquals(p1, p2);
+                assertNotEquals(getter.invoke(p1), getter.invoke(p2));
+                p2.copyFrom(p1);
+                assertEquals("Field " + field + " is missing from copyFrom()", p1, p2);
+                assertEquals(p1.hashCode(), p2.hashCode());
+                assertEquals(getter.invoke(p1), getter.invoke(p2));
+
+                // Load values into p3 and p4 for clear() behavior test
+                setter.invoke(p3, getSampleValueForType(field.getType(), 3));
+                hashCodes.add(p3.hashCode());
+                setter.invoke(p4, getSampleValueForType(field.getType(), 4));
+                hashCodes.add(p4.hashCode());
+            } catch (IllegalAccessException e) {
+                fail("Could not access method for field " + field);
+            } catch (IllegalArgumentException e) {
+                fail("Could call method for field " + field);
+            } catch (InvocationTargetException e) {
+                fail("Could invoke method on target for field " + field);
+            }
+        }
+
+        // Check for clear() behavior
+        assertNotEquals(p3, p4);
+        p3.clear();
+        p4.clear();
+        assertEquals("A field is missing from the clear() function", p3, p4);
+
+        // A good hashCode() implementation should produce very few collisions. We added at most
+        // 4*fields.length codes to the set. We'll say the implementation is good if we had at least
+        // fields.length unique values.
+        // TODO: Should the requirement be stronger than this?
+        assertTrue(
+                "Too many hash code collisions: " + hashCodes.size() + " out of " + (fields.length * 4),
+                hashCodes.size() >= fields.length);
     }
-  }
-
-  @Test
-  public void TestBasicSerializationRoundTrip() throws IOException, ClassNotFoundException {
-    DecimalFormatProperties props0 = new DecimalFormatProperties();
-
-    // Write values to some of the fields
-    PatternStringParser.parseToExistingProperties("A-**####,#00.00#b¤", props0);
-
-    // Write to byte stream
-    ByteArrayOutputStream baos = new ByteArrayOutputStream();
-    ObjectOutputStream oos = new ObjectOutputStream(baos);
-    oos.writeObject(props0);
-    oos.flush();
-    baos.close();
-    byte[] bytes = baos.toByteArray();
-
-    // Read from byte stream
-    ObjectInputStream ois = new ObjectInputStream(new ByteArrayInputStream(bytes));
-    Object obj = ois.readObject();
-    ois.close();
-    DecimalFormatProperties props1 = (DecimalFormatProperties) obj;
-
-    // Test equality
-    assertEquals("Did not round-trip through serialization", props0, props1);
-  }
-
-  /** Handler for serialization compatibility test suite. */
-  public static class PropertiesHandler implements SerializableTestUtility.Handler {
-
-    @Override
-    public Object[] getTestObjects() {
-      return new Object[] {
-        new DecimalFormatProperties(),
-        PatternStringParser.parseToProperties("x#,##0.00%"),
-        new DecimalFormatProperties().setCompactStyle(CompactStyle.LONG).setMinimumExponentDigits(2)
-      };
+
+    /**
+     * Creates a valid sample instance of the given type. Used to simulate getters and setters.
+     *
+     * @param type
+     *            The type to generate.
+     * @param seed
+     *            An integer seed, guaranteed to be positive. The same seed should generate two instances
+     *            that are equal. A different seed should in general generate two instances that are not
+     *            equal; this might not always be possible, such as with booleans or enums where there
+     *            are limited possible values.
+     * @return An instance of the specified type.
+     */
+    Object getSampleValueForType(Class<?> type, int seed) {
+        if (type == Integer.TYPE) {
+            return seed * 1000001;
+
+        } else if (type == Boolean.TYPE) {
+            return (seed % 2) == 0;
+
+        } else if (type == BigDecimal.class) {
+            if (seed == 0)
+                return null;
+            return new BigDecimal(seed * 1000002);
+
+        } else if (type == String.class) {
+            if (seed == 0)
+                return null;
+            return BigInteger.valueOf(seed * 1000003).toString(32);
+
+        } else if (type == CompactStyle.class) {
+            if (seed == 0)
+                return null;
+            CompactStyle[] values = CompactStyle.values();
+            return values[seed % values.length];
+
+        } else if (type == Currency.class) {
+            if (seed == 0)
+                return null;
+            Object[] currencies = Currency.getAvailableCurrencies().toArray();
+            return currencies[seed % currencies.length];
+
+        } else if (type == CurrencyPluralInfo.class) {
+            if (seed == 0)
+                return null;
+            ULocale[] locales = ULocale.getAvailableLocales();
+            return CurrencyPluralInfo.getInstance(locales[seed % locales.length]);
+
+        } else if (type == CurrencyUsage.class) {
+            if (seed == 0)
+                return null;
+            CurrencyUsage[] values = CurrencyUsage.values();
+            return values[seed % values.length];
+
+        } else if (type == GroupingMode.class) {
+            if (seed == 0)
+                return null;
+            GroupingMode[] values = GroupingMode.values();
+            return values[seed % values.length];
+
+        } else if (type == FormatWidth.class) {
+            if (seed == 0)
+                return null;
+            FormatWidth[] values = FormatWidth.values();
+            return values[seed % values.length];
+
+        } else if (type == Map.class) {
+            // Map<String,Map<String,String>> for compactCustomData property
+            if (seed == 0)
+                return null;
+            Map<String, Map<String, String>> outer = new HashMap<String, Map<String, String>>();
+            Map<String, String> inner = new HashMap<String, String>();
+            inner.put("one", "0 thousand");
+            StringBuilder magnitudeKey = new StringBuilder();
+            magnitudeKey.append("1000");
+            for (int i = 0; i < seed % 9; i++) {
+                magnitudeKey.append("0");
+            }
+            outer.put(magnitudeKey.toString(), inner);
+            return outer;
+
+        } else if (type == MathContext.class) {
+            if (seed == 0)
+                return null;
+            RoundingMode[] modes = RoundingMode.values();
+            return new MathContext(seed, modes[seed % modes.length]);
+
+        } else if (type == MeasureUnit.class) {
+            if (seed == 0)
+                return null;
+            Object[] units = MeasureUnit.getAvailable().toArray();
+            return units[seed % units.length];
+
+        } else if (type == PadPosition.class) {
+            if (seed == 0)
+                return null;
+            PadPosition[] values = PadPosition.values();
+            return values[seed % values.length];
+
+        } else if (type == ParseMode.class) {
+            if (seed == 0)
+                return null;
+            ParseMode[] values = ParseMode.values();
+            return values[seed % values.length];
+
+        } else if (type == PluralRules.class) {
+            if (seed == 0)
+                return null;
+            ULocale[] locales = PluralRules.getAvailableULocales();
+            return PluralRules.forLocale(locales[seed % locales.length]);
+
+        } else if (type == RoundingMode.class) {
+            if (seed == 0)
+                return null;
+            RoundingMode[] values = RoundingMode.values();
+            return values[seed % values.length];
+
+        } else {
+            fail("Don't know how to handle type "
+                    + type
+                    + ". Please add it to getSampleValueForType().");
+            return null;
+        }
     }
 
-    @Override
-    public boolean hasSameBehavior(Object a, Object b) {
-      return a.equals(b);
+    @Test
+    public void TestBasicSerializationRoundTrip() throws IOException, ClassNotFoundException {
+        DecimalFormatProperties props0 = new DecimalFormatProperties();
+
+        // Write values to some of the fields
+        PatternStringParser.parseToExistingProperties("A-**####,#00.00#b¤", props0);
+
+        // Write to byte stream
+        ByteArrayOutputStream baos = new ByteArrayOutputStream();
+        ObjectOutputStream oos = new ObjectOutputStream(baos);
+        oos.writeObject(props0);
+        oos.flush();
+        baos.close();
+        byte[] bytes = baos.toByteArray();
+
+        // Read from byte stream
+        ObjectInputStream ois = new ObjectInputStream(new ByteArrayInputStream(bytes));
+        Object obj = ois.readObject();
+        ois.close();
+        DecimalFormatProperties props1 = (DecimalFormatProperties) obj;
+
+        // Test equality
+        assertEquals("Did not round-trip through serialization", props0, props1);
     }
-  }
 
-  /** Handler for the ICU 59 class named "Properties" before it was renamed to "DecimalFormatProperties". */
-  public static class ICU59PropertiesHandler implements SerializableTestUtility.Handler {
+    /** Handler for serialization compatibility test suite. */
+    public static class PropertiesHandler implements SerializableTestUtility.Handler {
+
+        @Override
+        public Object[] getTestObjects() {
+            return new Object[] {
+                    new DecimalFormatProperties(),
+                    PatternStringParser.parseToProperties("x#,##0.00%"),
+                    new DecimalFormatProperties().setCompactStyle(CompactStyle.LONG)
+                            .setMinimumExponentDigits(2) };
+        }
 
-    @Override
-    public Object[] getTestObjects() {
-      return new Object[] {
-        new com.ibm.icu.impl.number.Properties()
-      };
+        @Override
+        public boolean hasSameBehavior(Object a, Object b) {
+            return a.equals(b);
+        }
     }
 
-    @Override
-    public boolean hasSameBehavior(Object a, Object b) {
-      return true;
+    /**
+     * Handler for the ICU 59 class named "Properties" before it was renamed to
+     * "DecimalFormatProperties".
+     */
+    public static class ICU59PropertiesHandler implements SerializableTestUtility.Handler {
+
+        @Override
+        public Object[] getTestObjects() {
+            return new Object[] { new com.ibm.icu.impl.number.Properties() };
+        }
+
+        @Override
+        public boolean hasSameBehavior(Object a, Object b) {
+            return true;
+        }
     }
-  }
 }