]> granicus.if.org Git - icu/commitdiff
ICU-13177 Assorted minor internal changes.
authorShane Carr <shane@unicode.org>
Fri, 28 Jul 2017 05:55:06 +0000 (05:55 +0000)
committerShane Carr <shane@unicode.org>
Fri, 28 Jul 2017 05:55:06 +0000 (05:55 +0000)
X-SVN-Rev: 40294

icu4j/main/classes/core/src/com/ibm/icu/impl/number/AffixPatternUtils.java
icu4j/main/classes/core/src/com/ibm/icu/impl/number/Modifier.java
icu4j/main/classes/core/src/com/ibm/icu/impl/number/ModifierHolder.java
icu4j/main/classes/core/src/com/ibm/icu/impl/number/NumberStringBuilder.java
icu4j/main/classes/core/src/com/ibm/icu/impl/number/formatters/PaddingFormat.java
icu4j/main/classes/core/src/com/ibm/icu/impl/number/modifiers/ConstantAffixModifier.java
icu4j/main/classes/core/src/com/ibm/icu/impl/number/modifiers/ConstantMultiFieldModifier.java
icu4j/main/classes/core/src/com/ibm/icu/impl/number/modifiers/SimpleModifier.java

index f1357836ba5d27ce91222efcacd7a78c450341d3..f1835d15f045a16f473e784d1f7deb6316464381 100644 (file)
@@ -3,7 +3,7 @@
 package com.ibm.icu.impl.number;
 
 import com.ibm.icu.text.DecimalFormatSymbols;
-import com.ibm.icu.text.NumberFormat.Field;
+import com.ibm.icu.text.NumberFormat;
 
 /**
  * Performs manipulations on affix patterns: the prefix and suffix strings associated with a decimal
@@ -251,37 +251,38 @@ public class AffixPatternUtils {
     while (hasNext(tag, affixPattern)) {
       tag = nextToken(tag, affixPattern);
       int typeOrCp = getTypeOrCp(tag);
+      NumberFormat.Field field = (typeOrCp < 0) ? getFieldForType(typeOrCp) : null;
       switch (typeOrCp) {
         case TYPE_MINUS_SIGN:
-          output.append(minusSign, Field.SIGN);
+          output.append(minusSign, field);
           break;
         case TYPE_PLUS_SIGN:
-          output.append(symbols.getPlusSignString(), Field.SIGN);
+          output.append(symbols.getPlusSignString(), field);
           break;
         case TYPE_PERCENT:
-          output.append(symbols.getPercentString(), Field.PERCENT);
+          output.append(symbols.getPercentString(), field);
           break;
         case TYPE_PERMILLE:
-          output.append(symbols.getPerMillString(), Field.PERMILLE);
+          output.append(symbols.getPerMillString(), field);
           break;
         case TYPE_CURRENCY_SINGLE:
-          output.append(currency1, Field.CURRENCY);
+          output.append(currency1, field);
           break;
         case TYPE_CURRENCY_DOUBLE:
-          output.append(currency2, Field.CURRENCY);
+          output.append(currency2, field);
           break;
         case TYPE_CURRENCY_TRIPLE:
-          output.append(currency3, Field.CURRENCY);
+          output.append(currency3, field);
           break;
         case TYPE_CURRENCY_QUAD:
-          output.appendCodePoint('\uFFFD', Field.CURRENCY);
+          output.appendCodePoint('\uFFFD', field);
           break;
         case TYPE_CURRENCY_QUINT:
           // TODO: Add support for narrow currency symbols here.
-          output.appendCodePoint('\uFFFD', Field.CURRENCY);
+          output.appendCodePoint('\uFFFD', field);
           break;
         case TYPE_CURRENCY_OVERFLOW:
-          output.appendCodePoint('\uFFFD', Field.CURRENCY);
+          output.appendCodePoint('\uFFFD', field);
           break;
         default:
           output.appendCodePoint(typeOrCp, null);
@@ -290,28 +291,28 @@ public class AffixPatternUtils {
     }
   }
 
-  private static final Field getFieldForType(int type) {
+  public static final NumberFormat.Field getFieldForType(int type) {
     switch (type) {
       case TYPE_MINUS_SIGN:
-        return Field.SIGN;
+        return NumberFormat.Field.SIGN;
       case TYPE_PLUS_SIGN:
-        return Field.SIGN;
+        return NumberFormat.Field.SIGN;
       case TYPE_PERCENT:
-        return Field.PERCENT;
+        return NumberFormat.Field.PERCENT;
       case TYPE_PERMILLE:
-        return Field.PERMILLE;
+        return NumberFormat.Field.PERMILLE;
       case TYPE_CURRENCY_SINGLE:
-        return Field.CURRENCY;
+        return NumberFormat.Field.CURRENCY;
       case TYPE_CURRENCY_DOUBLE:
-        return Field.CURRENCY;
+        return NumberFormat.Field.CURRENCY;
       case TYPE_CURRENCY_TRIPLE:
-        return Field.CURRENCY;
+        return NumberFormat.Field.CURRENCY;
       case TYPE_CURRENCY_QUAD:
-        return Field.CURRENCY;
+        return NumberFormat.Field.CURRENCY;
       case TYPE_CURRENCY_QUINT:
-        return Field.CURRENCY;
+        return NumberFormat.Field.CURRENCY;
       case TYPE_CURRENCY_OVERFLOW:
-        return Field.CURRENCY;
+        return NumberFormat.Field.CURRENCY;
       default:
         throw new AssertionError();
     }
@@ -335,7 +336,7 @@ public class AffixPatternUtils {
       int typeOrCp = getTypeOrCp(tag);
       if (typeOrCp == TYPE_CURRENCY_OVERFLOW) {
         // Don't go to the provider for this special case
-        local.appendCodePoint(0xFFFD, Field.CURRENCY);
+        local.appendCodePoint(0xFFFD, NumberFormat.Field.CURRENCY);
       } else if (typeOrCp < 0) {
         local.append(provider.getSymbol(typeOrCp), getFieldForType(typeOrCp));
       } else {
@@ -377,12 +378,7 @@ public class AffixPatternUtils {
     while (hasNext(tag, affixPattern)) {
       tag = nextToken(tag, affixPattern);
       int typeOrCp = getTypeOrCp(tag);
-      if (typeOrCp == AffixPatternUtils.TYPE_CURRENCY_SINGLE
-          || typeOrCp == AffixPatternUtils.TYPE_CURRENCY_DOUBLE
-          || typeOrCp == AffixPatternUtils.TYPE_CURRENCY_TRIPLE
-          || typeOrCp == AffixPatternUtils.TYPE_CURRENCY_QUAD
-          || typeOrCp == AffixPatternUtils.TYPE_CURRENCY_QUINT
-          || typeOrCp == AffixPatternUtils.TYPE_CURRENCY_OVERFLOW) {
+      if (typeOrCp < 0 && getFieldForType(typeOrCp) == NumberFormat.Field.CURRENCY) {
         return true;
       }
     }
index 00739fd5743473f6a8ba9c873b23ac74543b0e37..8cb1ced988a2d38421e0e1453b50098815899c3d 100644 (file)
@@ -33,13 +33,6 @@ public interface Modifier {
    */
   public int apply(NumberStringBuilder output, int leftIndex, int rightIndex);
 
-  /**
-   * The number of characters that {@link #apply} would add to the string builder.
-   *
-   * @return The number of characters (UTF-16 code units) that would be added to a string builder.
-   */
-  public int length();
-
   /**
    * 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
index 483d6fd67927bf90414496bae8581e4136d7e600..a35647c3bb5805697d1a9059b142b32886516bca 100644 (file)
@@ -17,6 +17,12 @@ public class ModifierHolder {
   //    private Modifier mod4 = null;
   //    private Modifier mod5 = null;
 
+  public ModifierHolder createCopy() {
+    ModifierHolder copy = new ModifierHolder();
+    copy.mods.addAll(mods);
+    return copy;
+  }
+
   public ModifierHolder clear() {
     //      mod1 = null;
     //      mod2 = null;
@@ -89,18 +95,4 @@ public class ModifierHolder {
     }
     return addedLength;
   }
-
-  public int totalLength() {
-    int length = 0;
-    //      if (mod1 != null) length += mod1.length();
-    //      if (mod2 != null) length += mod2.length();
-    //      if (mod3 != null) length += mod3.length();
-    //      if (mod4 != null) length += mod4.length();
-    //      if (mod5 != null) length += mod5.length();
-    for (Modifier mod : mods) {
-      if (mod == null) continue;
-      length += mod.length();
-    }
-    return length;
-  }
 }
index 7ea35f2b568f80dbdf159a29785894b5fed1fd8e..ad4a52f6be6a19efbd1c4a39fd3757c02bc1380e 100644 (file)
@@ -12,7 +12,21 @@ import java.util.Map;
 import com.ibm.icu.text.NumberFormat;
 import com.ibm.icu.text.NumberFormat.Field;
 
+/**
+ * A StringBuilder optimized for number formatting. It implements the following key features beyond
+ * a normal JDK StringBuilder:
+ *
+ * <ol>
+ *   <li>Efficient prepend as well as append.
+ *   <li>Keeps tracks of Fields in an efficient manner.
+ *   <li>String operations are fast-pathed to code point operations when possible.
+ * </ol>
+ */
 public class NumberStringBuilder implements CharSequence {
+
+  /** A constant, empty NumberStringBuilder. Do NOT call mutative operations on this. */
+  public static final NumberStringBuilder EMPTY = new NumberStringBuilder();
+
   private char[] chars;
   private Field[] fields;
   private int zero;
@@ -31,6 +45,10 @@ public class NumberStringBuilder implements CharSequence {
 
   public NumberStringBuilder(NumberStringBuilder source) {
     this(source.chars.length);
+    copyFrom(source);
+  }
+
+  public void copyFrom(NumberStringBuilder source) {
     zero = source.zero;
     length = source.length;
     System.arraycopy(source.chars, zero, chars, zero, length);
@@ -42,6 +60,10 @@ public class NumberStringBuilder implements CharSequence {
     return length;
   }
 
+  public int codePointCount() {
+    return Character.codePointCount(this, 0, length());
+  }
+
   @Override
   public char charAt(int index) {
     if (index < 0 || index > length) {
@@ -50,6 +72,13 @@ public class NumberStringBuilder implements CharSequence {
     return chars[zero + index];
   }
 
+  public Field fieldAt(int index) {
+    if (index < 0 || index > length) {
+      throw new IndexOutOfBoundsException();
+    }
+    return fields[zero + index];
+  }
+
   /**
    * Appends the specified codePoint to the end of the string.
    *
@@ -325,6 +354,16 @@ public class NumberStringBuilder implements CharSequence {
     return true;
   }
 
+  @Override
+  public int hashCode() {
+    throw new UnsupportedOperationException("Don't call #hashCode() or #equals() on a mutable.");
+  }
+
+  @Override
+  public boolean equals(Object other) {
+    throw new UnsupportedOperationException("Don't call #hashCode() or #equals() on a mutable.");
+  }
+
   /**
    * Populates the given {@link FieldPosition} based on this string builder.
    *
index 5aa3c48c63ffa3c14d111f1d45d6f09e0363f1d9..77eb6dc1c62e2510426e7d97156367bf44cca065 100644 (file)
@@ -112,9 +112,7 @@ public class PaddingFormat implements AfterFormat {
 
   public static AfterFormat getInstance(IProperties properties) {
     return new PaddingFormat(
-        properties.getFormatWidth(),
-        properties.getPadString(),
-        properties.getPadPosition());
+        properties.getFormatWidth(), properties.getPadString(), properties.getPadPosition());
   }
 
   // Properties
@@ -122,19 +120,21 @@ public class PaddingFormat implements AfterFormat {
   private final String paddingString;
   private final PadPosition paddingLocation;
 
-  private PaddingFormat(
-      int paddingWidth, String paddingString, PadPosition paddingLocation) {
+  private PaddingFormat(int paddingWidth, String paddingString, PadPosition paddingLocation) {
     this.paddingWidth = paddingWidth > 0 ? paddingWidth : 10; // TODO: Is this a sensible default?
     this.paddingString = paddingString != null ? paddingString : FALLBACK_PADDING_STRING;
-    this.paddingLocation =
-        paddingLocation != null ? paddingLocation : PadPosition.BEFORE_PREFIX;
+    this.paddingLocation = paddingLocation != null ? paddingLocation : PadPosition.BEFORE_PREFIX;
   }
 
   @Override
   public int after(ModifierHolder mods, NumberStringBuilder string, int leftIndex, int rightIndex) {
 
     // TODO: Count code points instead of code units?
-    int requiredPadding = paddingWidth - (rightIndex - leftIndex) - mods.totalLength();
+    // TODO: Make this more efficient (less copying)
+    NumberStringBuilder copy1 = new NumberStringBuilder(string);
+    ModifierHolder copy2 = mods.createCopy();
+    copy2.applyAll(copy1, leftIndex, rightIndex);
+    int requiredPadding = paddingWidth - copy1.length();
 
     if (requiredPadding <= 0) {
       // Skip padding, but still apply modifiers to be consistent
index 2eea973956e78a4bf008c95ca7efb82824116f6a..ba46aa9d0cb8820500a422a1cfd9dbc7767162e9 100644 (file)
@@ -40,9 +40,7 @@ public class ConstantAffixModifier extends Modifier.BaseModifier implements Affi
     this.strong = strong;
   }
 
-  /**
-   * Constructs a new instance with an empty prefix, suffix, and field.
-   */
+  /** Constructs a new instance with an empty prefix, suffix, and field. */
   public ConstantAffixModifier() {
     prefix = "";
     suffix = "";
@@ -58,11 +56,6 @@ public class ConstantAffixModifier extends Modifier.BaseModifier implements Affi
     return length;
   }
 
-  @Override
-  public int length() {
-    return prefix.length() + suffix.length();
-  }
-
   @Override
   public boolean isStrong() {
     return strong;
@@ -94,8 +87,7 @@ public class ConstantAffixModifier extends Modifier.BaseModifier implements Affi
 
   @Override
   public String toString() {
-    return String.format(
-        "<ConstantAffixModifier(%d) prefix:'%s' suffix:'%s'>", length(), prefix, suffix);
+    return String.format("<ConstantAffixModifier prefix:'%s' suffix:'%s'>", prefix, suffix);
   }
 
   @Override
index e7ed0a612346f46d5c86d5711bc6925df3de7f32..499f6d7ee0495ee311536d554e5a054a86e12a3f 100644 (file)
@@ -18,10 +18,10 @@ public class ConstantMultiFieldModifier extends Modifier.BaseModifier implements
   // TODO: Avoid making a new instance by default if prefix and suffix are empty
   public static final ConstantMultiFieldModifier EMPTY = new ConstantMultiFieldModifier();
 
-  private final char[] prefixChars;
-  private final char[] suffixChars;
-  private final Field[] prefixFields;
-  private final Field[] suffixFields;
+  protected final char[] prefixChars;
+  protected final char[] suffixChars;
+  protected final Field[] prefixFields;
+  protected final Field[] suffixFields;
   private final String prefix;
   private final String suffix;
   private final boolean strong;
@@ -55,11 +55,6 @@ public class ConstantMultiFieldModifier extends Modifier.BaseModifier implements
     return length;
   }
 
-  @Override
-  public int length() {
-    return prefixChars.length + suffixChars.length;
-  }
-
   @Override
   public boolean isStrong() {
     return strong;
@@ -82,8 +77,7 @@ public class ConstantMultiFieldModifier extends Modifier.BaseModifier implements
 
   @Override
   public String toString() {
-    return String.format(
-        "<ConstantMultiFieldModifier(%d) prefix:'%s' suffix:'%s'>", length(), prefix, suffix);
+    return String.format("<ConstantMultiFieldModifier prefix:'%s' suffix:'%s'>", prefix, suffix);
   }
 
   @Override
index 23a15f44aac1851ce4bb8739c2158942c50df424..63f1cc1cd1d69b051ca31e7e0517c3631d295079 100644 (file)
@@ -29,12 +29,6 @@ public class SimpleModifier extends Modifier.BaseModifier {
     return formatAsPrefixSuffix(compiledPattern, output, leftIndex, rightIndex, field);
   }
 
-  @Override
-  public int length() {
-    // TODO: Make a separate method for computing the length only?
-    return formatAsPrefixSuffix(compiledPattern, null, -1, -1, field);
-  }
-
   @Override
   public boolean isStrong() {
     return strong;