]> granicus.if.org Git - icu/commitdiff
ICU-13177 Renaming files and ICU4C syncing.
authorShane Carr <shane@unicode.org>
Tue, 26 Sep 2017 08:51:34 +0000 (08:51 +0000)
committerShane Carr <shane@unicode.org>
Tue, 26 Sep 2017 08:51:34 +0000 (08:51 +0000)
X-SVN-Rev: 40459

57 files changed:
icu4j/main/classes/core/src/com/ibm/icu/impl/number/AffixPatternProvider.java [moved from icu4j/main/classes/core/src/newapi/impl/AffixPatternProvider.java with 95% similarity]
icu4j/main/classes/core/src/com/ibm/icu/impl/number/CompactData.java [moved from icu4j/main/classes/core/src/newapi/impl/CompactData.java with 99% similarity]
icu4j/main/classes/core/src/com/ibm/icu/impl/number/ConstantAffixModifier.java [moved from icu4j/main/classes/core/src/com/ibm/icu/impl/number/modifiers/ConstantAffixModifier.java with 90% similarity]
icu4j/main/classes/core/src/com/ibm/icu/impl/number/ConstantMultiFieldModifier.java [moved from icu4j/main/classes/core/src/com/ibm/icu/impl/number/modifiers/ConstantMultiFieldModifier.java with 94% similarity]
icu4j/main/classes/core/src/com/ibm/icu/impl/number/CurrencySpacingEnabledModifier.java [moved from icu4j/main/classes/core/src/com/ibm/icu/impl/number/modifiers/CurrencySpacingEnabledModifier.java with 98% similarity]
icu4j/main/classes/core/src/com/ibm/icu/impl/number/CustomSymbolCurrency.java [moved from icu4j/main/classes/core/src/newapi/impl/CustomSymbolCurrency.java with 98% similarity]
icu4j/main/classes/core/src/com/ibm/icu/impl/number/DecimalFormatProperties.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/LongNameHandler.java [moved from icu4j/main/classes/core/src/newapi/impl/LongNameHandler.java with 53% similarity]
icu4j/main/classes/core/src/com/ibm/icu/impl/number/MacroProps.java [moved from icu4j/main/classes/core/src/newapi/impl/MacroProps.java with 89% similarity]
icu4j/main/classes/core/src/com/ibm/icu/impl/number/MicroProps.java [moved from icu4j/main/classes/core/src/newapi/impl/MicroProps.java with 82% similarity]
icu4j/main/classes/core/src/com/ibm/icu/impl/number/MicroPropsGenerator.java [moved from icu4j/main/classes/core/src/newapi/impl/MicroPropsGenerator.java with 96% similarity]
icu4j/main/classes/core/src/com/ibm/icu/impl/number/MicroPropsMutator.java [moved from icu4j/main/classes/core/src/newapi/impl/MicroPropsMutator.java with 88% similarity]
icu4j/main/classes/core/src/com/ibm/icu/impl/number/Modifier.java
icu4j/main/classes/core/src/com/ibm/icu/impl/number/MultiplierImpl.java [moved from icu4j/main/classes/core/src/newapi/impl/MultiplierImpl.java with 94% similarity]
icu4j/main/classes/core/src/com/ibm/icu/impl/number/MultiplierProducer.java [moved from icu4j/main/classes/core/src/newapi/impl/MultiplierProducer.java with 85% similarity]
icu4j/main/classes/core/src/com/ibm/icu/impl/number/MutablePatternModifier.java [moved from icu4j/main/classes/core/src/newapi/impl/MutablePatternModifier.java with 96% similarity]
icu4j/main/classes/core/src/com/ibm/icu/impl/number/Padder.java [moved from icu4j/main/classes/core/src/newapi/impl/Padder.java with 81% similarity]
icu4j/main/classes/core/src/com/ibm/icu/impl/number/ParameterizedModifier.java [new file with mode: 0644]
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/RoundingUtils.java
icu4j/main/classes/core/src/com/ibm/icu/impl/number/SimpleModifier.java [moved from icu4j/main/classes/core/src/com/ibm/icu/impl/number/modifiers/SimpleModifier.java with 96% similarity]
icu4j/main/classes/core/src/com/ibm/icu/number/CompactNotation.java [moved from icu4j/main/classes/core/src/newapi/CompactNotation.java with 85% similarity]
icu4j/main/classes/core/src/com/ibm/icu/number/CurrencyRounder.java [moved from icu4j/main/classes/core/src/newapi/CurrencyRounder.java with 52% similarity]
icu4j/main/classes/core/src/com/ibm/icu/number/FormattedNumber.java [moved from icu4j/main/classes/core/src/newapi/FormattedNumber.java with 98% similarity]
icu4j/main/classes/core/src/com/ibm/icu/number/FractionRounder.java [moved from icu4j/main/classes/core/src/newapi/FractionRounder.java with 56% similarity]
icu4j/main/classes/core/src/com/ibm/icu/number/Grouper.java [moved from icu4j/main/classes/core/src/newapi/Grouper.java with 94% similarity]
icu4j/main/classes/core/src/com/ibm/icu/number/IntegerWidth.java [moved from icu4j/main/classes/core/src/newapi/IntegerWidth.java with 57% similarity]
icu4j/main/classes/core/src/com/ibm/icu/number/LocalizedNumberFormatter.java [moved from icu4j/main/classes/core/src/newapi/LocalizedNumberFormatter.java with 89% similarity]
icu4j/main/classes/core/src/com/ibm/icu/number/Notation.java [new file with mode: 0644]
icu4j/main/classes/core/src/com/ibm/icu/number/NumberFormatter.java [new file with mode: 0644]
icu4j/main/classes/core/src/com/ibm/icu/number/NumberFormatterImpl.java [moved from icu4j/main/classes/core/src/newapi/NumberFormatterImpl.java with 67% similarity]
icu4j/main/classes/core/src/com/ibm/icu/number/NumberFormatterSettings.java [moved from icu4j/main/classes/core/src/newapi/NumberFormatterSettings.java with 97% similarity]
icu4j/main/classes/core/src/com/ibm/icu/number/NumberPropertyMapper.java [moved from icu4j/main/classes/core/src/newapi/NumberPropertyMapper.java with 96% similarity]
icu4j/main/classes/core/src/com/ibm/icu/number/Rounder.java [moved from icu4j/main/classes/core/src/newapi/Rounder.java with 53% similarity]
icu4j/main/classes/core/src/com/ibm/icu/number/ScientificNotation.java [moved from icu4j/main/classes/core/src/newapi/ScientificNotation.java with 80% similarity]
icu4j/main/classes/core/src/com/ibm/icu/number/SimpleNotation.java [moved from icu4j/main/classes/core/src/newapi/SimpleNotation.java with 88% similarity]
icu4j/main/classes/core/src/com/ibm/icu/number/UnlocalizedNumberFormatter.java [moved from icu4j/main/classes/core/src/newapi/UnlocalizedNumberFormatter.java with 97% similarity]
icu4j/main/classes/core/src/com/ibm/icu/text/DecimalFormat.java
icu4j/main/classes/core/src/com/ibm/icu/text/NumberFormat.java
icu4j/main/classes/core/src/newapi/Notation.java [deleted file]
icu4j/main/classes/core/src/newapi/NumberFormatter.java [deleted file]
icu4j/main/classes/core/src/newapi/SkeletonBuilder.java [deleted file]
icu4j/main/classes/core/src/newapi/impl/demo.java [deleted file]
icu4j/main/tests/core/src/com/ibm/icu/dev/data/numberformattestspecification.txt
icu4j/main/tests/core/src/com/ibm/icu/dev/test/format/NumberFormatDataDrivenTest.java
icu4j/main/tests/core/src/com/ibm/icu/dev/test/format/NumberFormatTest.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/NumberFormatterTest.java
icu4j/main/tests/core/src/com/ibm/icu/dev/test/number/PropertiesTest.java
icu4j/main/tests/core/src/com/ibm/icu/impl/number/DecimalQuantity_64BitBCD.java [moved from icu4j/main/classes/core/src/com/ibm/icu/impl/number/DecimalQuantity_64BitBCD.java with 97% similarity]
icu4j/main/tests/core/src/com/ibm/icu/impl/number/DecimalQuantity_ByteArrayBCD.java [moved from icu4j/main/classes/core/src/com/ibm/icu/impl/number/DecimalQuantity_ByteArrayBCD.java with 98% similarity]
icu4j/main/tests/core/src/com/ibm/icu/impl/number/DecimalQuantity_SimpleStorage.java [moved from icu4j/main/classes/core/src/com/ibm/icu/impl/number/DecimalQuantity_SimpleStorage.java with 100% similarity]

similarity index 95%
rename from icu4j/main/classes/core/src/newapi/impl/AffixPatternProvider.java
rename to icu4j/main/classes/core/src/com/ibm/icu/impl/number/AffixPatternProvider.java
index 87554b7f771fa60d7f60f3aaaa461a191f245c78..0cf547e341e2b8c1ac7881d3c1e4e4d214b7de37 100644 (file)
@@ -1,6 +1,6 @@
 // © 2017 and later: Unicode, Inc. and others.
 // License & terms of use: http://www.unicode.org/copyright.html#License
-package newapi.impl;
+package com.ibm.icu.impl.number;
 
 public interface AffixPatternProvider {
   public static final class Flags {
similarity index 99%
rename from icu4j/main/classes/core/src/newapi/impl/CompactData.java
rename to icu4j/main/classes/core/src/com/ibm/icu/impl/number/CompactData.java
index 5090f7091bb504dd5d5b0175e16e64483e5538b6..ed524b3ab4e0cc60636a4c54a9d6fddc846ebf1f 100644 (file)
@@ -1,6 +1,6 @@
 // © 2017 and later: Unicode, Inc. and others.
 // License & terms of use: http://www.unicode.org/copyright.html#License
-package newapi.impl;
+package com.ibm.icu.impl.number;
 
 import java.util.Arrays;
 import java.util.Map;
@@ -15,10 +15,12 @@ import com.ibm.icu.util.ICUException;
 import com.ibm.icu.util.ULocale;
 import com.ibm.icu.util.UResourceBundle;
 
-import newapi.CompactNotation.CompactType;
-
 public class CompactData implements MultiplierProducer {
 
+    public enum CompactType {
+        DECIMAL, CURRENCY
+    }
+
     // A dummy object used when a "0" compact decimal entry is encountered. This is necessary
     // in order to prevent falling back to root. Object equality ("==") is intended.
     private static final String USE_FALLBACK = "<USE FALLBACK>";
similarity index 90%
rename from icu4j/main/classes/core/src/com/ibm/icu/impl/number/modifiers/ConstantAffixModifier.java
rename to icu4j/main/classes/core/src/com/ibm/icu/impl/number/ConstantAffixModifier.java
index e629712cd027a2e5ffee731c40d7777baeb973a1..53f79096fe5d0f0b1719d7ba8d9ec7916efcf037 100644 (file)
@@ -1,13 +1,7 @@
 // © 2017 and later: Unicode, Inc. and others.
 // License & terms of use: http://www.unicode.org/copyright.html#License
-package com.ibm.icu.impl.number.modifiers;
+package com.ibm.icu.impl.number;
 
-import com.ibm.icu.impl.number.Modifier;
-
-// TODO: This class is currently unused, but it might be useful for something in the future.
-// Should probably be moved to a different package.
-
-import com.ibm.icu.impl.number.NumberStringBuilder;
 import com.ibm.icu.text.NumberFormat.Field;
 
 /**
similarity index 94%
rename from icu4j/main/classes/core/src/com/ibm/icu/impl/number/modifiers/ConstantMultiFieldModifier.java
rename to icu4j/main/classes/core/src/com/ibm/icu/impl/number/ConstantMultiFieldModifier.java
index b07422407ea3ef1f0bde336c27163942ed829ad2..c6c38e07b9ec48602f38d2d7408e38a753ec8e4a 100644 (file)
@@ -1,9 +1,7 @@
 // © 2017 and later: Unicode, Inc. and others.
 // License & terms of use: http://www.unicode.org/copyright.html#License
-package com.ibm.icu.impl.number.modifiers;
+package com.ibm.icu.impl.number;
 
-import com.ibm.icu.impl.number.Modifier;
-import com.ibm.icu.impl.number.NumberStringBuilder;
 import com.ibm.icu.text.NumberFormat.Field;
 
 /**
similarity index 98%
rename from icu4j/main/classes/core/src/com/ibm/icu/impl/number/modifiers/CurrencySpacingEnabledModifier.java
rename to icu4j/main/classes/core/src/com/ibm/icu/impl/number/CurrencySpacingEnabledModifier.java
index d9318849a623750550058bdd24bcc44f2b252ac6..5aff0f3630460d381e7d1f22c94fb161db8b6ac5 100644 (file)
@@ -1,8 +1,7 @@
 // © 2017 and later: Unicode, Inc. and others.
 // License & terms of use: http://www.unicode.org/copyright.html#License
-package com.ibm.icu.impl.number.modifiers;
+package com.ibm.icu.impl.number;
 
-import com.ibm.icu.impl.number.NumberStringBuilder;
 import com.ibm.icu.text.DecimalFormatSymbols;
 import com.ibm.icu.text.NumberFormat;
 import com.ibm.icu.text.UnicodeSet;
similarity index 98%
rename from icu4j/main/classes/core/src/newapi/impl/CustomSymbolCurrency.java
rename to icu4j/main/classes/core/src/com/ibm/icu/impl/number/CustomSymbolCurrency.java
index 664694bd354353376294300a8ac006f685616110..cfbf3f91dadcbfa0628f7d9033e6dca7fa045668 100644 (file)
@@ -1,6 +1,6 @@
 // © 2017 and later: Unicode, Inc. and others.
 // License & terms of use: http://www.unicode.org/copyright.html#License
-package newapi.impl;
+package com.ibm.icu.impl.number;
 
 import com.ibm.icu.text.DecimalFormatSymbols;
 import com.ibm.icu.util.Currency;
index 2ee66346c676e2e686be2fbea6e5c802892d7ea0..52535762e695c745b4e3855088a73e365213605d 100644 (file)
@@ -15,6 +15,7 @@ import java.text.ParsePosition;
 import java.util.ArrayList;
 import java.util.Map;
 
+import com.ibm.icu.impl.number.Padder.PadPosition;
 import com.ibm.icu.impl.number.Parse.GroupingMode;
 import com.ibm.icu.impl.number.Parse.ParseMode;
 import com.ibm.icu.text.CompactDecimalFormat.CompactStyle;
@@ -23,8 +24,6 @@ import com.ibm.icu.text.PluralRules;
 import com.ibm.icu.util.Currency;
 import com.ibm.icu.util.Currency.CurrencyUsage;
 
-import newapi.impl.Padder.PadPosition;
-
 public class DecimalFormatProperties implements Cloneable, Serializable {
 
   private static final DecimalFormatProperties DEFAULT = new DecimalFormatProperties();
index 3be79a22d136079141f921eaac86f2843256379a..b442cf1f3ee5b03f278ab9e12075136e9711ac0d 100644 (file)
@@ -310,19 +310,6 @@ public abstract class DecimalQuantity_AbstractBCD implements DecimalQuantity {
     return precision == 0;
   }
 
-  @Override
-  public DecimalQuantity createCopy() {
-    if (this instanceof DecimalQuantity_64BitBCD) {
-      return new DecimalQuantity_64BitBCD((DecimalQuantity_64BitBCD) this);
-    } else if (this instanceof DecimalQuantity_ByteArrayBCD) {
-      return new DecimalQuantity_ByteArrayBCD((DecimalQuantity_ByteArrayBCD) this);
-    } else if (this instanceof DecimalQuantity_DualStorageBCD) {
-      return new DecimalQuantity_DualStorageBCD((DecimalQuantity_DualStorageBCD) this);
-    } else {
-      throw new IllegalArgumentException("Don't know how to copy " + this.getClass());
-    }
-  }
-
   public void setToInt(int n) {
     setBcdToZero();
     flags = 0;
@@ -423,6 +410,11 @@ public abstract class DecimalQuantity_AbstractBCD implements DecimalQuantity {
    * 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;
 
@@ -432,10 +424,6 @@ public abstract class DecimalQuantity_AbstractBCD implements DecimalQuantity {
       return;
     }
 
-    isApproximate = true;
-    origDouble = n;
-    origDelta = 0;
-
     // 3.3219... is log2(10)
     int fracLength = (int) ((52 - exponent) / 3.32192809489);
     if (fracLength >= 0) {
index 7774d2ac93f362dfd3941caa904116657dbc947d..e127d6fa4c7818437f2f07ab395760d2ec2ef4b2 100644 (file)
@@ -76,6 +76,11 @@ public final class DecimalQuantity_DualStorageBCD extends DecimalQuantity_Abstra
     }
   }
 
+  @Override
+  public DecimalQuantity createCopy() {
+    return new DecimalQuantity_DualStorageBCD(this);
+  }
+
   @Override
   protected byte getDigitPos(int position) {
     if (usingBytes) {
similarity index 53%
rename from icu4j/main/classes/core/src/newapi/impl/LongNameHandler.java
rename to icu4j/main/classes/core/src/com/ibm/icu/impl/number/LongNameHandler.java
index cbb67f14d5e2eff5eb641bd6a1cc46051bf8b6f0..2ed9f4d63cd5441a1685e254d5cf706b381eade6 100644 (file)
@@ -1,6 +1,6 @@
 // © 2017 and later: Unicode, Inc. and others.
 // License & terms of use: http://www.unicode.org/copyright.html#License
-package newapi.impl;
+package com.ibm.icu.impl.number;
 
 import java.util.EnumMap;
 import java.util.Map;
@@ -11,9 +11,8 @@ import com.ibm.icu.impl.ICUResourceBundle;
 import com.ibm.icu.impl.SimpleFormatterImpl;
 import com.ibm.icu.impl.StandardPlural;
 import com.ibm.icu.impl.UResource;
-import com.ibm.icu.impl.number.DecimalQuantity;
-import com.ibm.icu.impl.number.modifiers.SimpleModifier;
-import com.ibm.icu.text.NumberFormat.Field;
+import com.ibm.icu.number.NumberFormatter.UnitWidth;
+import com.ibm.icu.text.NumberFormat;
 import com.ibm.icu.text.PluralRules;
 import com.ibm.icu.util.Currency;
 import com.ibm.icu.util.ICUException;
@@ -21,97 +20,17 @@ import com.ibm.icu.util.MeasureUnit;
 import com.ibm.icu.util.ULocale;
 import com.ibm.icu.util.UResourceBundle;
 
-import newapi.NumberFormatter.UnitWidth;
-
 public class LongNameHandler implements MicroPropsGenerator {
 
-    private final Map<StandardPlural, SimpleModifier> modifiers;
-    private PluralRules rules;
-    private MicroPropsGenerator parent;
-
-    private LongNameHandler(Map<StandardPlural, SimpleModifier> modifiers) {
-        this.modifiers = modifiers;
-    }
-
-    /** For use by the "safe" code path */
-    private LongNameHandler(LongNameHandler other) {
-        this.modifiers = other.modifiers;
-    }
-
-    public static LongNameHandler forCurrencyLongNames(ULocale loc, Currency currency) {
-        Map<String, String> data = CurrencyData.provider.getInstance(loc, true).getUnitPatterns();
-        Map<StandardPlural, SimpleModifier> result = new EnumMap<StandardPlural, SimpleModifier>(StandardPlural.class);
-        StringBuilder sb = new StringBuilder();
-        for (Map.Entry<String, String> e : data.entrySet()) {
-            String pluralKeyword = e.getKey();
-            StandardPlural plural = StandardPlural.fromString(e.getKey());
-            String longName = currency.getName(loc, Currency.PLURAL_LONG_NAME, pluralKeyword, null);
-            String simpleFormat = e.getValue();
-            // Example pattern from data: "{0} {1}"
-            // Example output after find-and-replace: "{0} US dollars"
-            simpleFormat = simpleFormat.replace("{1}", longName);
-            String compiled = SimpleFormatterImpl.compileToStringMinMaxArguments(simpleFormat, sb, 1, 1);
-            SimpleModifier mod = new SimpleModifier(compiled, Field.CURRENCY, false);
-            result.put(plural, mod);
-        }
-        return new LongNameHandler(result);
-    }
-
-    public static LongNameHandler forMeasureUnit(ULocale loc, MeasureUnit unit, UnitWidth width) {
-        Map<StandardPlural, String> simpleFormats = getMeasureData(loc, unit, width);
-        Map<StandardPlural, SimpleModifier> result = new EnumMap<StandardPlural, SimpleModifier>(StandardPlural.class);
-        StringBuilder sb = new StringBuilder();
-        for (StandardPlural plural : StandardPlural.VALUES) {
-            String simpleFormat = simpleFormats.get(plural);
-            if (simpleFormat == null) {
-                simpleFormat = simpleFormats.get(StandardPlural.OTHER);
-            }
-            if (simpleFormat == null) {
-                // There should always be data in the "other" plural variant.
-                throw new ICUException("Could not find data in 'other' plural variant for unit " + unit);
-            }
-            String compiled = SimpleFormatterImpl.compileToStringMinMaxArguments(simpleFormat, sb, 1, 1);
-            // TODO: What field to use for units?
-            SimpleModifier mod = new SimpleModifier(compiled, null, false);
-            result.put(plural, mod);
-        }
-        return new LongNameHandler(result);
-    }
-
-    /**
-     * Applies locale data and inserts a long-name handler into the quantity chain.
-     *
-     * @param rules
-     *            The PluralRules instance to reference.
-     * @param parent
-     *            The old head of the quantity chain.
-     * @return The new head of the quantity chain.
-     */
-    public MicroPropsGenerator withLocaleData(PluralRules rules, MicroPropsGenerator parent) {
-        this.rules = rules;
-        this.parent = parent;
-        return this;
-    }
-
-    @Override
-    public MicroProps processQuantity(DecimalQuantity quantity) {
-        MicroProps micros = parent.processQuantity(quantity);
-        // TODO: Avoid the copy here?
-        DecimalQuantity copy = quantity.createCopy();
-        micros.rounding.apply(copy);
-        micros.modOuter = modifiers.get(copy.getStandardPlural(rules));
-        return micros;
-    }
+    //////////////////////////
+    /// BEGIN DATA LOADING ///
+    //////////////////////////
 
-    ///////////////////////////////////////
-    /// BEGIN MEASURE UNIT DATA LOADING ///
-    ///////////////////////////////////////
-
-    private static final class MeasureUnitSink extends UResource.Sink {
+    private static final class PluralTableSink extends UResource.Sink {
 
         Map<StandardPlural, String> output;
 
-        public MeasureUnitSink(Map<StandardPlural, String> output) {
+        public PluralTableSink(Map<StandardPlural, String> output) {
             this.output = output;
         }
 
@@ -132,9 +51,11 @@ public class LongNameHandler implements MicroPropsGenerator {
         }
     }
 
-    private static Map<StandardPlural, String> getMeasureData(ULocale locale, MeasureUnit unit, UnitWidth width) {
-        ICUResourceBundle resource = (ICUResourceBundle) UResourceBundle.getBundleInstance(ICUData.ICU_UNIT_BASE_NAME,
-                locale);
+    private static void getMeasureData(ULocale locale, MeasureUnit unit, UnitWidth width,
+            Map<StandardPlural, String> output) {
+        PluralTableSink sink = new PluralTableSink(output);
+        ICUResourceBundle resource;
+        resource = (ICUResourceBundle) UResourceBundle.getBundleInstance(ICUData.ICU_UNIT_BASE_NAME, locale);
         StringBuilder key = new StringBuilder();
         key.append("units");
         if (width == UnitWidth.NARROW) {
@@ -146,13 +67,89 @@ public class LongNameHandler implements MicroPropsGenerator {
         key.append(unit.getType());
         key.append("/");
         key.append(unit.getSubtype());
-        Map<StandardPlural, String> output = new EnumMap<StandardPlural, String>(StandardPlural.class);
-        MeasureUnitSink sink = new MeasureUnitSink(output);
         resource.getAllItemsWithFallback(key.toString(), sink);
-        return output;
     }
 
-    /////////////////////////////////////
-    /// END MEASURE UNIT DATA LOADING ///
-    /////////////////////////////////////
+    private static void getCurrencyLongNameData(ULocale locale, Currency currency, Map<StandardPlural, String> output) {
+        // In ICU4J, this method gets a CurrencyData from CurrencyData.provider.
+        // TODO(ICU4J): Implement this without going through CurrencyData, like in ICU4C?
+        Map<String, String> data = CurrencyData.provider.getInstance(locale, true).getUnitPatterns();
+        for (Map.Entry<String, String> e : data.entrySet()) {
+            String pluralKeyword = e.getKey();
+            StandardPlural plural = StandardPlural.fromString(e.getKey());
+            String longName = currency.getName(locale, Currency.PLURAL_LONG_NAME, pluralKeyword, null);
+            String simpleFormat = e.getValue();
+            // Example pattern from data: "{0} {1}"
+            // Example output after find-and-replace: "{0} US dollars"
+            simpleFormat = simpleFormat.replace("{1}", longName);
+            // String compiled = SimpleFormatterImpl.compileToStringMinMaxArguments(simpleFormat, sb, 1, 1);
+            // SimpleModifier mod = new SimpleModifier(compiled, Field.CURRENCY, false);
+            output.put(plural, simpleFormat);
+        }
+    }
+
+    ////////////////////////
+    /// END DATA LOADING ///
+    ////////////////////////
+
+    private final Map<StandardPlural, SimpleModifier> modifiers;
+    private final PluralRules rules;
+    private final MicroPropsGenerator parent;
+
+    private LongNameHandler(Map<StandardPlural, SimpleModifier> modifiers, PluralRules rules,
+            MicroPropsGenerator parent) {
+        this.modifiers = modifiers;
+        this.rules = rules;
+        this.parent = parent;
+    }
+
+    public static LongNameHandler forCurrencyLongNames(ULocale locale, Currency currency, PluralRules rules,
+            MicroPropsGenerator parent) {
+        Map<StandardPlural, String> simpleFormats = new EnumMap<StandardPlural, String>(StandardPlural.class);
+        getCurrencyLongNameData(locale, currency, simpleFormats);
+        // TODO(ICU4J): Reduce the number of object creations here?
+        Map<StandardPlural, SimpleModifier> modifiers = new EnumMap<StandardPlural, SimpleModifier>(
+                StandardPlural.class);
+        simpleFormatsToModifiers(simpleFormats, null, modifiers);
+        return new LongNameHandler(modifiers, rules, parent);
+    }
+
+    public static LongNameHandler forMeasureUnit(ULocale locale, MeasureUnit unit, UnitWidth width, PluralRules rules,
+            MicroPropsGenerator parent) {
+        Map<StandardPlural, String> simpleFormats = new EnumMap<StandardPlural, String>(StandardPlural.class);
+        getMeasureData(locale, unit, width, simpleFormats);
+        // TODO: What field to use for units?
+        // TODO(ICU4J): Reduce the number of object creations here?
+        Map<StandardPlural, SimpleModifier> modifiers = new EnumMap<StandardPlural, SimpleModifier>(
+                StandardPlural.class);
+        simpleFormatsToModifiers(simpleFormats, null, modifiers);
+        return new LongNameHandler(modifiers, rules, parent);
+    }
+
+    private static void simpleFormatsToModifiers(Map<StandardPlural, String> simpleFormats, NumberFormat.Field field,
+            Map<StandardPlural, SimpleModifier> output) {
+        StringBuilder sb = new StringBuilder();
+        for (StandardPlural plural : StandardPlural.VALUES) {
+            String simpleFormat = simpleFormats.get(plural);
+            if (simpleFormat == null) {
+                simpleFormat = simpleFormats.get(StandardPlural.OTHER);
+            }
+            if (simpleFormat == null) {
+                // There should always be data in the "other" plural variant.
+                throw new ICUException("Could not find data in 'other' plural variant with field " + field);
+            }
+            String compiled = SimpleFormatterImpl.compileToStringMinMaxArguments(simpleFormat, sb, 1, 1);
+            output.put(plural, new SimpleModifier(compiled, null, false));
+        }
+    }
+
+    @Override
+    public MicroProps processQuantity(DecimalQuantity quantity) {
+        MicroProps micros = parent.processQuantity(quantity);
+        // TODO: Avoid the copy here?
+        DecimalQuantity copy = quantity.createCopy();
+        micros.rounding.apply(copy);
+        micros.modOuter = modifiers.get(copy.getStandardPlural(rules));
+        return micros;
+    }
 }
similarity index 89%
rename from icu4j/main/classes/core/src/newapi/impl/MacroProps.java
rename to icu4j/main/classes/core/src/com/ibm/icu/impl/number/MacroProps.java
index 8146daffdf5ba5c3b43442ecf162603a2a81c71d..f07b1782f39d901beb9cf14848223f27c22c1fe6 100644 (file)
@@ -1,21 +1,20 @@
 // © 2017 and later: Unicode, Inc. and others.
 // License & terms of use: http://www.unicode.org/copyright.html#License
-package newapi.impl;
+package com.ibm.icu.impl.number;
 
 import java.util.Objects;
 
+import com.ibm.icu.number.Grouper;
+import com.ibm.icu.number.IntegerWidth;
+import com.ibm.icu.number.Notation;
+import com.ibm.icu.number.NumberFormatter.DecimalSeparatorDisplay;
+import com.ibm.icu.number.NumberFormatter.SignDisplay;
+import com.ibm.icu.number.NumberFormatter.UnitWidth;
+import com.ibm.icu.number.Rounder;
 import com.ibm.icu.text.PluralRules;
 import com.ibm.icu.util.MeasureUnit;
 import com.ibm.icu.util.ULocale;
 
-import newapi.Grouper;
-import newapi.IntegerWidth;
-import newapi.Notation;
-import newapi.NumberFormatter.DecimalMarkDisplay;
-import newapi.NumberFormatter.SignDisplay;
-import newapi.NumberFormatter.UnitWidth;
-import newapi.Rounder;
-
 public class MacroProps implements Cloneable {
   public Notation notation;
   public MeasureUnit unit;
@@ -26,7 +25,7 @@ public class MacroProps implements Cloneable {
   public Object symbols;
   public UnitWidth unitWidth;
   public SignDisplay sign;
-  public DecimalMarkDisplay decimal;
+  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
similarity index 82%
rename from icu4j/main/classes/core/src/newapi/impl/MicroProps.java
rename to icu4j/main/classes/core/src/com/ibm/icu/impl/number/MicroProps.java
index 03f52da2d63481901fd8e1868b3273bccb4cd82a..2c15dfc87ed3ec12ead16ba7ea2891dd06b76094 100644 (file)
@@ -1,23 +1,20 @@
 // © 2017 and later: Unicode, Inc. and others.
 // License & terms of use: http://www.unicode.org/copyright.html#License
-package newapi.impl;
+package com.ibm.icu.impl.number;
 
-import com.ibm.icu.impl.number.DecimalQuantity;
-import com.ibm.icu.impl.number.Modifier;
+import com.ibm.icu.number.Grouper;
+import com.ibm.icu.number.IntegerWidth;
+import com.ibm.icu.number.Rounder;
+import com.ibm.icu.number.NumberFormatter.DecimalSeparatorDisplay;
+import com.ibm.icu.number.NumberFormatter.SignDisplay;
 import com.ibm.icu.text.DecimalFormatSymbols;
 
-import newapi.Grouper;
-import newapi.IntegerWidth;
-import newapi.NumberFormatter.DecimalMarkDisplay;
-import newapi.NumberFormatter.SignDisplay;
-import newapi.Rounder;
-
 public class MicroProps implements Cloneable, MicroPropsGenerator {
     // Populated globally:
     public SignDisplay sign;
     public DecimalFormatSymbols symbols;
     public Padder padding;
-    public DecimalMarkDisplay decimal;
+    public DecimalSeparatorDisplay decimal;
     public IntegerWidth integerWidth;
 
     // Populated by notation/unit:
@@ -26,7 +23,6 @@ public class MicroProps implements Cloneable, MicroPropsGenerator {
     public Modifier modInner;
     public Rounder rounding;
     public Grouper grouping;
-    public int multiplier;
     public boolean useCurrency;
 
     // Internal fields:
similarity index 96%
rename from icu4j/main/classes/core/src/newapi/impl/MicroPropsGenerator.java
rename to icu4j/main/classes/core/src/com/ibm/icu/impl/number/MicroPropsGenerator.java
index 72620e7f5aedd20b5e88600f31afbe095e175b8e..c633ce7ec706e103bba2c1c095e086daadfffb7e 100644 (file)
@@ -1,8 +1,6 @@
 // © 2017 and later: Unicode, Inc. and others.
 // License & terms of use: http://www.unicode.org/copyright.html#License
-package newapi.impl;
-
-import com.ibm.icu.impl.number.DecimalQuantity;
+package com.ibm.icu.impl.number;
 
 /**
  * This interface is used when all number formatting settings, including the locale, are known, except for the quantity
similarity index 88%
rename from icu4j/main/classes/core/src/newapi/impl/MicroPropsMutator.java
rename to icu4j/main/classes/core/src/com/ibm/icu/impl/number/MicroPropsMutator.java
index 3c01a3b8636206c4a91fac269bb73fe24cab0dc1..962f8d133f5d5d429d013f74ae8211923dec5e01 100644 (file)
@@ -1,6 +1,6 @@
 // © 2017 and later: Unicode, Inc. and others.
 // License & terms of use: http://www.unicode.org/copyright.html#License
-package newapi.impl;
+package com.ibm.icu.impl.number;
 
 /**
  * @author sffc
index bff553636c83694efa3ce16c0bbef7855f1b0e88..b37e4d740fafbef536efbc4094dfc996ccf49984 100644 (file)
@@ -2,8 +2,6 @@
 // License & terms of use: http://www.unicode.org/copyright.html#License
 package com.ibm.icu.impl.number;
 
-import newapi.impl.MutablePatternModifier;
-
 /**
  * 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,
similarity index 94%
rename from icu4j/main/classes/core/src/newapi/impl/MultiplierImpl.java
rename to icu4j/main/classes/core/src/com/ibm/icu/impl/number/MultiplierImpl.java
index 1ef44e2b8872517c7a79e96bae782f33f5dafc46..ca1b8ad59e1842ac4e318ebbe9129f5f4b4a3030 100644 (file)
@@ -1,11 +1,9 @@
 // © 2017 and later: Unicode, Inc. and others.
 // License & terms of use: http://www.unicode.org/copyright.html#License
-package newapi.impl;
+package com.ibm.icu.impl.number;
 
 import java.math.BigDecimal;
 
-import com.ibm.icu.impl.number.DecimalQuantity;
-
 public class MultiplierImpl implements MicroPropsGenerator, Cloneable {
   final int magnitudeMultiplier;
   final BigDecimal bigDecimalMultiplier;
similarity index 85%
rename from icu4j/main/classes/core/src/newapi/impl/MultiplierProducer.java
rename to icu4j/main/classes/core/src/com/ibm/icu/impl/number/MultiplierProducer.java
index 814ceaabf250c0771473a5654a3fc304349f9752..2e7b96def7f039f524d3da3151291cf116addebd 100644 (file)
@@ -1,6 +1,6 @@
 // © 2017 and later: Unicode, Inc. and others.
 // License & terms of use: http://www.unicode.org/copyright.html#License
-package newapi.impl;
+package com.ibm.icu.impl.number;
 
 public interface MultiplierProducer {
     int getMultiplier(int magnitude);
similarity index 96%
rename from icu4j/main/classes/core/src/newapi/impl/MutablePatternModifier.java
rename to icu4j/main/classes/core/src/com/ibm/icu/impl/number/MutablePatternModifier.java
index 497dddbc787b397db5ffc60fa3d7521a068df729..ad61dd01965ff454799ec1bcd3897f3bbf9d9bc8 100644 (file)
@@ -1,24 +1,15 @@
 // © 2017 and later: Unicode, Inc. and others.
 // License & terms of use: http://www.unicode.org/copyright.html#License
-package newapi.impl;
+package com.ibm.icu.impl.number;
 
 import com.ibm.icu.impl.StandardPlural;
-import com.ibm.icu.impl.number.AffixUtils;
 import com.ibm.icu.impl.number.AffixUtils.SymbolProvider;
-import com.ibm.icu.impl.number.DecimalQuantity;
-import com.ibm.icu.impl.number.Modifier;
-import com.ibm.icu.impl.number.NumberStringBuilder;
-import com.ibm.icu.impl.number.ParameterizedModifier;
-import com.ibm.icu.impl.number.PatternStringParser;
-import com.ibm.icu.impl.number.modifiers.ConstantMultiFieldModifier;
-import com.ibm.icu.impl.number.modifiers.CurrencySpacingEnabledModifier;
+import com.ibm.icu.number.NumberFormatter.SignDisplay;
+import com.ibm.icu.number.NumberFormatter.UnitWidth;
 import com.ibm.icu.text.DecimalFormatSymbols;
 import com.ibm.icu.text.PluralRules;
 import com.ibm.icu.util.Currency;
 
-import newapi.NumberFormatter.SignDisplay;
-import newapi.NumberFormatter.UnitWidth;
-
 /**
  * This class is a {@link Modifier} that wraps a decimal format pattern. It applies the pattern's affixes in
  * {@link Modifier#apply}.
@@ -37,8 +28,6 @@ import newapi.NumberFormatter.UnitWidth;
  * 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.
- *
- * FIXME: Make this package-private
  */
 public class MutablePatternModifier implements Modifier, SymbolProvider, CharSequence, MicroPropsGenerator {
 
@@ -331,9 +320,11 @@ public class MutablePatternModifier implements Modifier, SymbolProvider, CharSeq
         case AffixUtils.TYPE_PERMILLE:
             return symbols.getPerMillString();
         case AffixUtils.TYPE_CURRENCY_SINGLE:
-            // UnitWidth ISO overrides the singular currency symbol.
+            // UnitWidth ISO or HIDDEN overrides the singular currency symbol.
             if (unitWidth == UnitWidth.ISO_CODE) {
                 return currency.getCurrencyCode();
+            } else if (unitWidth == UnitWidth.HIDDEN) {
+                return "";
             } else {
                 return currency.getName(symbols.getULocale(), Currency.SYMBOL_NAME, null);
             }
similarity index 81%
rename from icu4j/main/classes/core/src/newapi/impl/Padder.java
rename to icu4j/main/classes/core/src/com/ibm/icu/impl/number/Padder.java
index 6180fd58ddbcb1b7eef60ba08047672f549ac386..c1be7034d4c81596bf70cf6827195b8806e9ffeb 100644 (file)
@@ -1,9 +1,6 @@
 // © 2017 and later: Unicode, Inc. and others.
 // License & terms of use: http://www.unicode.org/copyright.html#License
-package newapi.impl;
-
-import com.ibm.icu.impl.number.Modifier;
-import com.ibm.icu.impl.number.NumberStringBuilder;
+package com.ibm.icu.impl.number;
 
 public class Padder {
     public static final String FALLBACK_PADDING_STRING = "\u0020"; // i.e. a space
@@ -45,7 +42,7 @@ public class Padder {
       }
     }
 
-    private static final Padder NONE = new Padder(null, -1, null);
+    /* like package-private */ public static final Padder NONE = new Padder(null, -1, null);
 
     String paddingString;
     int targetWidth;
@@ -53,7 +50,7 @@ public class Padder {
 
     public Padder(String paddingString, int targetWidth, PadPosition position) {
         // TODO: Add a few default instances
-        this.paddingString = (paddingString == null) ? " " : paddingString;
+        this.paddingString = (paddingString == null) ? FALLBACK_PADDING_STRING : paddingString;
         this.targetWidth = targetWidth;
         this.position = (position == null) ? PadPosition.BEFORE_PREFIX : position;
     }
@@ -102,24 +99,6 @@ public class Padder {
             length += addPaddingHelper(paddingString, requiredPadding, string, rightIndex + length);
         }
 
-        // The length might not be exactly right due to currency spacing.
-        // Make an adjustment if needed.
-        while (string.codePointCount() < targetWidth) {
-            int insertIndex = mod1.getPrefixLength() + mod2.getPrefixLength();
-            switch (position) {
-            case AFTER_PREFIX:
-                insertIndex += leftIndex;
-                break;
-            case BEFORE_SUFFIX:
-                insertIndex += rightIndex;
-                break;
-            default:
-                // Should not happen since currency spacing is always on the inside.
-                throw new AssertionError();
-            }
-            addPaddingHelper(paddingString, requiredPadding, string, insertIndex);
-        }
-
         return length;
     }
 
diff --git a/icu4j/main/classes/core/src/com/ibm/icu/impl/number/ParameterizedModifier.java b/icu4j/main/classes/core/src/com/ibm/icu/impl/number/ParameterizedModifier.java
new file mode 100644 (file)
index 0000000..5a7191a
--- /dev/null
@@ -0,0 +1,68 @@
+// © 2017 and later: Unicode, Inc. and others.
+// License & terms of use: http://www.unicode.org/copyright.html#License
+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.
+ */
+public class ParameterizedModifier {
+    private final Modifier positive;
+    private final Modifier negative;
+    final Modifier[] mods;
+    boolean frozen;
+
+    /**
+     * This constructor populates the ParameterizedModifier with a single positive and negative form.
+     *
+     * <p>
+     * If this constructor is used, a plural form CANNOT be passed to {@link #getModifier}.
+     */
+    public ParameterizedModifier(Modifier positive, Modifier negative) {
+        this.positive = positive;
+        this.negative = negative;
+        this.mods = null;
+        this.frozen = true;
+    }
+
+    /**
+     * 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}.
+     */
+    public ParameterizedModifier() {
+        this.positive = null;
+        this.negative = null;
+        this.mods = new Modifier[2 * StandardPlural.COUNT];
+        this.frozen = false;
+    }
+
+    public void setModifier(boolean isNegative, StandardPlural plural, Modifier mod) {
+        assert !frozen;
+        mods[getModIndex(isNegative, plural)] = mod;
+    }
+
+    public void freeze() {
+        frozen = true;
+    }
+
+    public Modifier getModifier(boolean isNegative) {
+        assert frozen;
+        assert mods == null;
+        return isNegative ? negative : positive;
+    }
+
+    public Modifier getModifier(boolean isNegative, StandardPlural plural) {
+        assert frozen;
+        assert positive == null;
+        return mods[getModIndex(isNegative, plural)];
+    }
+
+    private static int getModIndex(boolean isNegative, StandardPlural plural) {
+        return plural.ordinal() * 2 + (isNegative ? 1 : 0);
+    }
+}
index 853ed1dd5686ef4f6416338df4c5c3b58ea20611..50336bc09b76768d091a2e6e498192e123c6393f 100644 (file)
@@ -2,8 +2,7 @@
 // License & terms of use: http://www.unicode.org/copyright.html#License
 package com.ibm.icu.impl.number;
 
-import newapi.impl.AffixPatternProvider;
-import newapi.impl.Padder.PadPosition;
+import com.ibm.icu.impl.number.Padder.PadPosition;
 
 /** Implements a recursive descent parser for decimal format patterns. */
 public class PatternStringParser {
index cfd23d0d03bb0f23c663271439c86c95db265929..4bed35f1f56d71b74d33216d613acdce17c0a6ef 100644 (file)
@@ -4,11 +4,9 @@ package com.ibm.icu.impl.number;
 
 import java.math.BigDecimal;
 
+import com.ibm.icu.impl.number.Padder.PadPosition;
 import com.ibm.icu.text.DecimalFormatSymbols;
 
-import newapi.impl.Padder;
-import newapi.impl.Padder.PadPosition;
-
 /**
  * Assorted utilities relating to decimal formatting pattern strings.
  */
index e07c6e8c1a7951cf159f2d251524eb6c31fcf42e..0c97552c487250e178d3fd113632cb6198538ca2 100644 (file)
@@ -13,6 +13,17 @@ public class RoundingUtils {
   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.
similarity index 96%
rename from icu4j/main/classes/core/src/com/ibm/icu/impl/number/modifiers/SimpleModifier.java
rename to icu4j/main/classes/core/src/com/ibm/icu/impl/number/SimpleModifier.java
index a318a4fe2c2185a0e6243772e745be1f4d631de1..6de0284e6f242b1e0fe285682a9a38c8adc68859 100644 (file)
@@ -1,10 +1,8 @@
 // © 2017 and later: Unicode, Inc. and others.
 // License & terms of use: http://www.unicode.org/copyright.html#License
-package com.ibm.icu.impl.number.modifiers;
+package com.ibm.icu.impl.number;
 
 import com.ibm.icu.impl.SimpleFormatterImpl;
-import com.ibm.icu.impl.number.Modifier;
-import com.ibm.icu.impl.number.NumberStringBuilder;
 import com.ibm.icu.text.NumberFormat.Field;
 
 /**
similarity index 85%
rename from icu4j/main/classes/core/src/newapi/CompactNotation.java
rename to icu4j/main/classes/core/src/com/ibm/icu/number/CompactNotation.java
index 6f2415aae7181204831cb64880249ba4000922e7..bc5375eb483e05ee57c0e98ca72446dfdd790bb8 100644 (file)
@@ -1,6 +1,6 @@
 // © 2017 and later: Unicode, Inc. and others.
 // License & terms of use: http://www.unicode.org/copyright.html#License
-package newapi;
+package com.ibm.icu.number;
 
 import java.util.HashMap;
 import java.util.HashSet;
@@ -8,34 +8,41 @@ import java.util.Map;
 import java.util.Set;
 
 import com.ibm.icu.impl.StandardPlural;
+import com.ibm.icu.impl.number.CompactData;
+import com.ibm.icu.impl.number.CompactData.CompactType;
 import com.ibm.icu.impl.number.DecimalQuantity;
+import com.ibm.icu.impl.number.MicroProps;
+import com.ibm.icu.impl.number.MicroPropsGenerator;
+import com.ibm.icu.impl.number.MutablePatternModifier;
+import com.ibm.icu.impl.number.MutablePatternModifier.ImmutablePatternModifier;
 import com.ibm.icu.impl.number.PatternStringParser;
 import com.ibm.icu.impl.number.PatternStringParser.ParsedPatternInfo;
 import com.ibm.icu.text.CompactDecimalFormat.CompactStyle;
 import com.ibm.icu.text.PluralRules;
 import com.ibm.icu.util.ULocale;
 
-import newapi.impl.CompactData;
-import newapi.impl.MicroProps;
-import newapi.impl.MicroPropsGenerator;
-import newapi.impl.MutablePatternModifier;
-import newapi.impl.MutablePatternModifier.ImmutablePatternModifier;
 
+/**
+ * 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}.
+ *
+ * @draft ICU 60
+ * @see NumberFormatter
+ */
 public class CompactNotation extends Notation {
 
     final CompactStyle compactStyle;
     final Map<String, Map<String, String>> compactCustomData;
 
-    public enum CompactType {
-        DECIMAL, CURRENCY
-    }
-
-    public CompactNotation(CompactStyle compactStyle) {
+    /* package-private */ CompactNotation(CompactStyle compactStyle) {
         compactCustomData = null;
         this.compactStyle = compactStyle;
     }
 
-    public CompactNotation(Map<String, Map<String, String>> compactCustomData) {
+    /* package-private */ CompactNotation(Map<String, Map<String, String>> compactCustomData) {
         compactStyle = null;
         this.compactCustomData = compactCustomData;
     }
@@ -118,7 +125,7 @@ public class CompactNotation extends Notation {
                 // No need to take any action.
             } else if (precomputedMods != null) {
                 // Safe code path.
-                // Java uses a hash set here for O(1) lookup.  C++ uses a linear search.
+                // Java uses a hash set here for O(1) lookup. C++ uses a linear search.
                 CompactModInfo info = precomputedMods.get(patternString);
                 info.mod.applyToMicros(micros, quantity);
                 numDigits = info.numDigits;
similarity index 52%
rename from icu4j/main/classes/core/src/newapi/CurrencyRounder.java
rename to icu4j/main/classes/core/src/com/ibm/icu/number/CurrencyRounder.java
index 0749dcc408014b42cd2744794ae191e4f97407e0..041494fa45f8554db8cc1ddb86335a56c510bf73 100644 (file)
@@ -1,28 +1,31 @@
 // © 2017 and later: Unicode, Inc. and others.
 // License & terms of use: http://www.unicode.org/copyright.html#License
-package newapi;
+package com.ibm.icu.number;
 
 import com.ibm.icu.util.Currency;
-import com.ibm.icu.util.Currency.CurrencyUsage;
-import com.ibm.icu.util.CurrencyAmount;
-import com.ibm.icu.util.Measure;
-import com.ibm.icu.util.MeasureUnit;
 
-/** A rounding strategy parameterized by a currency. */
+/**
+ * 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.
+ *
+ * @draft ICU 60
+ * @see NumberFormatter
+ */
 public abstract class CurrencyRounder extends Rounder {
 
     /* package-private */ CurrencyRounder() {
     }
 
     /**
-     * Associates a {@link com.ibm.icu.util.Currency} with this rounding strategy. Only applies to rounding strategies
-     * returned from {@link #currency(CurrencyUsage)}.
+     * Associates a currency with this rounding strategy.
      *
      * <p>
-     * <strong>Calling this method is <em>not required</em></strong>, because the currency specified in
-     * {@link NumberFormatterSettings#unit(MeasureUnit)} or via a {@link CurrencyAmount} passed into
-     * {@link LocalizedNumberFormatter#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
@@ -30,7 +33,9 @@ public abstract class CurrencyRounder extends Rounder {
      *
      * @param currency
      *            The currency to associate with this rounding strategy.
-     * @return An immutable object for chaining.
+     * @return A Rounder for chaining or passing to the NumberFormatter rounding() setter.
+     * @draft ICU 60
+     * @see NumberFormatter
      */
     public Rounder withCurrency(Currency currency) {
         if (currency != null) {
similarity index 98%
rename from icu4j/main/classes/core/src/newapi/FormattedNumber.java
rename to icu4j/main/classes/core/src/com/ibm/icu/number/FormattedNumber.java
index 682f88cb6554b645264ae06370d02209edf4347c..69762031366b698ecc820638d94d58bc1262dd99 100644 (file)
@@ -1,6 +1,6 @@
 // © 2017 and later: Unicode, Inc. and others.
 // License & terms of use: http://www.unicode.org/copyright.html#License
-package newapi;
+package com.ibm.icu.number;
 
 import java.io.IOException;
 import java.math.BigDecimal;
@@ -9,12 +9,11 @@ import java.text.FieldPosition;
 import java.util.Arrays;
 
 import com.ibm.icu.impl.number.DecimalQuantity;
+import com.ibm.icu.impl.number.MicroProps;
 import com.ibm.icu.impl.number.NumberStringBuilder;
 import com.ibm.icu.text.PluralRules.IFixedDecimal;
 import com.ibm.icu.util.ICUUncheckedIOException;
 
-import newapi.impl.MicroProps;
-
 public class FormattedNumber {
     NumberStringBuilder nsb;
     DecimalQuantity fq;
similarity index 56%
rename from icu4j/main/classes/core/src/newapi/FractionRounder.java
rename to icu4j/main/classes/core/src/com/ibm/icu/number/FractionRounder.java
index 3d2a5f7eac2430b0956d43040b8e9ec1bc4dfa24..a8ff7fc3a4fb4aaf00bdeaf952c30041d3f003d0 100644 (file)
@@ -1,10 +1,18 @@
 // © 2017 and later: Unicode, Inc. and others.
 // License & terms of use: http://www.unicode.org/copyright.html#License
-package newapi;
+package com.ibm.icu.number;
+
+import com.ibm.icu.impl.number.RoundingUtils;
 
 /**
- * A rounding strategy based on a minimum and/or maximum number of fraction digits. Allows for a minimum or maximum
- * number of significant digits to be specified.
+ * 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.
+ *
+ * @draft ICU 60
+ * @see NumberFormatter
  */
 public abstract class FractionRounder extends Rounder {
 
@@ -12,7 +20,7 @@ public abstract class FractionRounder extends Rounder {
     }
 
     /**
-     * Ensures that no less than this number of significant figures are retained when rounding according to fraction
+     * Ensure that no less than this number of significant digits are retained when rounding according to fraction
      * rules.
      *
      * <p>
@@ -24,18 +32,21 @@ public abstract class FractionRounder extends Rounder {
      *
      * @param minSignificantDigits
      *            The number of significant figures to guarantee.
-     * @return An immutable object for chaining.
+     * @return A Rounder for chaining or passing to the NumberFormatter rounding() setter.
+     * @draft ICU 60
+     * @see NumberFormatter
      */
     public Rounder withMinDigits(int minSignificantDigits) {
-        if (minSignificantDigits > 0 && minSignificantDigits <= MAX_VALUE) {
+        if (minSignificantDigits > 0 && minSignificantDigits <= RoundingUtils.MAX_INT_FRAC_SIG) {
             return constructFractionSignificant(this, minSignificantDigits, -1);
         } else {
-            throw new IllegalArgumentException("Significant digits must be between 0 and " + MAX_VALUE);
+            throw new IllegalArgumentException(
+                    "Significant digits must be between 0 and " + RoundingUtils.MAX_INT_FRAC_SIG);
         }
     }
 
     /**
-     * Ensures that no more than this number of significant figures are retained when rounding according to fraction
+     * Ensure that no more than this number of significant digits are retained when rounding according to fraction
      * rules.
      *
      * <p>
@@ -48,13 +59,16 @@ public abstract class FractionRounder extends Rounder {
      *
      * @param maxSignificantDigits
      *            Round the number to no more than this number of significant figures.
-     * @return An immutable object for chaining.
+     * @return A Rounder for chaining or passing to the NumberFormatter rounding() setter.
+     * @draft ICU 60
+     * @see NumberFormatter
      */
     public Rounder withMaxDigits(int maxSignificantDigits) {
-        if (maxSignificantDigits > 0 && maxSignificantDigits <= MAX_VALUE) {
+        if (maxSignificantDigits > 0 && maxSignificantDigits <= RoundingUtils.MAX_INT_FRAC_SIG) {
             return constructFractionSignificant(this, -1, maxSignificantDigits);
         } else {
-            throw new IllegalArgumentException("Significant digits must be between 0 and " + MAX_VALUE);
+            throw new IllegalArgumentException(
+                    "Significant digits must be between 0 and " + RoundingUtils.MAX_INT_FRAC_SIG);
         }
     }
 }
\ No newline at end of file
similarity index 94%
rename from icu4j/main/classes/core/src/newapi/Grouper.java
rename to icu4j/main/classes/core/src/com/ibm/icu/number/Grouper.java
index 296dbc3cb2464078be46ef2e93cf8b3f297ee9c1..e5b030be0360da735601fc0d92171e6dce59637e 100644 (file)
@@ -1,6 +1,6 @@
 // © 2017 and later: Unicode, Inc. and others.
 // License & terms of use: http://www.unicode.org/copyright.html#License
-package newapi;
+package com.ibm.icu.number;
 
 import com.ibm.icu.impl.number.DecimalQuantity;
 import com.ibm.icu.impl.number.PatternStringParser.ParsedPatternInfo;
@@ -31,7 +31,7 @@ public class Grouper {
         return DEFAULTS;
     }
 
-    public static Grouper min2() {
+    public static Grouper minTwoDigits() {
         return MIN2;
     }
 
@@ -64,10 +64,6 @@ public class Grouper {
         }
     }
 
-    static Grouper normalizeType(Grouper grouping, ParsedPatternInfo patternInfo) {
-        return grouping.withLocaleData(patternInfo);
-    }
-
     Grouper withLocaleData(ParsedPatternInfo patternInfo) {
         if (grouping1 != -2) {
             return this;
similarity index 57%
rename from icu4j/main/classes/core/src/newapi/IntegerWidth.java
rename to icu4j/main/classes/core/src/com/ibm/icu/number/IntegerWidth.java
index e092ec08615b2bc47ebb59303550dfd07e664c1a..e1fcb9c87ee48c13b21e39a7867b8ada1d4fe4d4 100644 (file)
@@ -1,11 +1,13 @@
 // © 2017 and later: Unicode, Inc. and others.
 // License & terms of use: http://www.unicode.org/copyright.html#License
-package newapi;
+package com.ibm.icu.number;
+
+import com.ibm.icu.impl.number.RoundingUtils;
 
 @SuppressWarnings("unused")
 public class IntegerWidth {
 
-    private static final IntegerWidth DEFAULT = new IntegerWidth(1, -1);
+    /* package-private */ static final IntegerWidth DEFAULT = new IntegerWidth(1, -1);
 
     final int minInt;
     final int maxInt;
@@ -18,22 +20,24 @@ public class IntegerWidth {
     public static IntegerWidth zeroFillTo(int minInt) {
         if (minInt == 1) {
             return DEFAULT;
-        } else if (minInt >= 0 && minInt < Rounder.MAX_VALUE) {
+        } 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 " + Rounder.MAX_VALUE);
+            throw new IllegalArgumentException(
+                    "Integer digits must be between 0 and " + RoundingUtils.MAX_INT_FRAC_SIG);
         }
     }
 
     public IntegerWidth truncateAt(int maxInt) {
         if (maxInt == this.maxInt) {
             return this;
-        } else if (maxInt >= 0 && maxInt < Rounder.MAX_VALUE) {
+        } else if (maxInt >= 0 && maxInt < RoundingUtils.MAX_INT_FRAC_SIG) {
             return new IntegerWidth(minInt, maxInt);
         } else if (maxInt == -1) {
             return new IntegerWidth(minInt, maxInt);
         } else {
-            throw new IllegalArgumentException("Integer digits must be between 0 and " + Rounder.MAX_VALUE);
+            throw new IllegalArgumentException(
+                    "Integer digits must be between 0 and " + RoundingUtils.MAX_INT_FRAC_SIG);
         }
     }
 }
\ No newline at end of file
similarity index 89%
rename from icu4j/main/classes/core/src/newapi/LocalizedNumberFormatter.java
rename to icu4j/main/classes/core/src/com/ibm/icu/number/LocalizedNumberFormatter.java
index b71f1a815bb31a901d43fda6e788369d247ecd8c..d17ec7e2554a47371fabd2ba6eeb76231404cf6a 100644 (file)
@@ -1,19 +1,18 @@
 // © 2017 and later: Unicode, Inc. and others.
 // License & terms of use: http://www.unicode.org/copyright.html#License
-package newapi;
+package com.ibm.icu.number;
 
 import java.util.Objects;
 import java.util.concurrent.atomic.AtomicLongFieldUpdater;
 
 import com.ibm.icu.impl.number.DecimalQuantity;
 import com.ibm.icu.impl.number.DecimalQuantity_DualStorageBCD;
+import com.ibm.icu.impl.number.MacroProps;
+import com.ibm.icu.impl.number.MicroProps;
 import com.ibm.icu.impl.number.NumberStringBuilder;
 import com.ibm.icu.util.Measure;
 import com.ibm.icu.util.MeasureUnit;
 
-import newapi.impl.MacroProps;
-import newapi.impl.MicroProps;
-
 public class LocalizedNumberFormatter extends NumberFormatterSettings<LocalizedNumberFormatter> {
 
     static final AtomicLongFieldUpdater<LocalizedNumberFormatter> callCount = AtomicLongFieldUpdater
@@ -60,6 +59,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.
      *
+     * <p>
+     * This function is very hot, being called in every call to the number formatting pipeline.
+     *
      * @param fq
      *            The quantity to be formatted.
      * @return The formatted number result.
@@ -70,9 +72,11 @@ public class LocalizedNumberFormatter extends NumberFormatterSettings<LocalizedN
     @Deprecated
     public FormattedNumber format(DecimalQuantity fq) {
         MacroProps macros = resolve();
-        NumberStringBuilder string = new NumberStringBuilder();
-        // TODO: Make this more like C++, where we get and then conditionally atomic-increment?
+        // NOTE: In Java, the atomic increment logic is slightly different than ICU4C.
+        // It seems to be more efficient to make just one function call instead of two.
+        // Further benchmarking is required.
         long currentCount = callCount.incrementAndGet(this);
+        NumberStringBuilder string = new NumberStringBuilder();
         MicroProps micros;
         if (currentCount == macros.threshold.longValue()) {
             compiled = NumberFormatterImpl.fromMacros(macros);
diff --git a/icu4j/main/classes/core/src/com/ibm/icu/number/Notation.java b/icu4j/main/classes/core/src/com/ibm/icu/number/Notation.java
new file mode 100644 (file)
index 0000000..d0fafcc
--- /dev/null
@@ -0,0 +1,183 @@
+// © 2017 and later: Unicode, Inc. and others.
+// License & terms of use: http://www.unicode.org/copyright.html#License
+package com.ibm.icu.number;
+
+import com.ibm.icu.number.NumberFormatter.SignDisplay;
+import com.ibm.icu.text.CompactDecimalFormat.CompactStyle;
+
+/**
+ * A class that defines the notation style to be used when formatting numbers in NumberFormatter.
+ *
+ * @draft ICU 60
+ * @see NumberFormatter
+ */
+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 CompactNotation COMPACT_SHORT = new CompactNotation(CompactStyle.SHORT);
+    private static final CompactNotation COMPACT_LONG = new CompactNotation(CompactStyle.LONG);
+    private static final SimpleNotation SIMPLE = new SimpleNotation();
+
+    /* package-private */ 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".
+     *
+     * <p>
+     * Example outputs in <em>en-US</em> when printing 8.765E4 through 8.765E-3:
+     *
+     * <pre>
+     * 8.765E4
+     * 8.765E3
+     * 8.765E2
+     * 8.765E1
+     * 8.765E0
+     * 8.765E-1
+     * 8.765E-2
+     * 8.765E-3
+     * 0E0
+     * </pre>
+     *
+     * @return A ScientificNotation for chaining or passing to the NumberFormatter notation() setter.
+     * @draft ICU 60
+     * @see NumberFormatter
+     */
+    public static ScientificNotation scientific() {
+        return SCIENTIFIC;
+    }
+
+    /**
+     * 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:
+     *
+     * <pre>
+     * 87.65E3
+     * 8.765E3
+     * 876.5E0
+     * 87.65E0
+     * 8.765E0
+     * 876.5E-3
+     * 87.65E-3
+     * 8.765E-3
+     * 0E0
+     * </pre>
+     *
+     * @return A ScientificNotation for chaining or passing to the NumberFormatter notation() setter.
+     * @draft ICU 60
+     * @see NumberFormatter
+     */
+    public static ScientificNotation engineering() {
+        return ENGINEERING;
+    }
+
+    /**
+     * 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.
+     *
+     * <p>
+     * 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:
+     *
+     * <pre>
+     * 88M
+     * 8.8M
+     * 876K
+     * 88K
+     * 8.8K
+     * 876
+     * 88
+     * 8.8
+     * </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:
+     *
+     * <pre>
+     * Rounder.integer().withMinDigits(2)
+     * </pre>
+     *
+     * @return A CompactNotation for passing to the NumberFormatter notation() setter.
+     * @draft ICU 60
+     * @see NumberFormatter
+     */
+    public static CompactNotation compactShort() {
+        return COMPACT_SHORT;
+    }
+
+    /**
+     * Print the number using long-form compact notation. For more information on compact notation, see
+     * {@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:
+     *
+     * <pre>
+     * 88 million
+     * 8.8 million
+     * 876 thousand
+     * 88 thousand
+     * 8.8 thousand
+     * 876
+     * 88
+     * 8.8
+     * </pre>
+     *
+     * @return A CompactNotation for passing to the NumberFormatter notation() setter.
+     * @draft ICU 60
+     * @see NumberFormatter
+     */
+    public static CompactNotation compactLong() {
+        return COMPACT_LONG;
+    }
+
+    /**
+     * 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.
+     *
+     * <p>
+     * Example outputs in <em>en-US</em> when printing 8.765E7 through 8.765E0:
+     *
+     * <pre>
+     * 87,650,000
+     * 8,765,000
+     * 876,500
+     * 87,650
+     * 8,765
+     * 876.5
+     * 87.65
+     * 8.765
+     * </pre>
+     *
+     * @return A SimpleNotation for passing to the NumberFormatter notation() setter.
+     * @draft ICU 60
+     * @see NumberFormatter
+     */
+    public static SimpleNotation simple() {
+        return SIMPLE;
+    }
+}
\ No newline at end of file
diff --git a/icu4j/main/classes/core/src/com/ibm/icu/number/NumberFormatter.java b/icu4j/main/classes/core/src/com/ibm/icu/number/NumberFormatter.java
new file mode 100644 (file)
index 0000000..c0c3faa
--- /dev/null
@@ -0,0 +1,260 @@
+// © 2017 and later: Unicode, Inc. and others.
+// License & terms of use: http://www.unicode.org/copyright.html#License
+package com.ibm.icu.number;
+
+import java.util.Locale;
+
+import com.ibm.icu.impl.number.DecimalFormatProperties;
+import com.ibm.icu.impl.number.MacroProps;
+import com.ibm.icu.text.DecimalFormatSymbols;
+import com.ibm.icu.util.ULocale;
+
+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>:
+     *
+     * <p>
+     * <ul>
+     * <li>NARROW*: "$123.00" and "123 m"
+     * <li>SHORT: "US$ 123.00" and "123 m"
+     * <li>FULL_NAME: "123.00 US dollars" and "123 meters"
+     * <li>ISO_CODE: "USD 123.00" and undefined behavior
+     * <li>HIDDEN: "123.00" and "123"
+     * </ul>
+     *
+     * <p>
+     * * The narrow format for currencies is not currently supported; this is a known issue that will be fixed in a
+     * future version. See #11666 for more information.
+     *
+     * <p>
+     * This enum is similar to {@link com.ibm.icu.text.MeasureFormat.FormatWidth}.
+     *
+     * @draft ICU 60
+     * @see 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.
+         *
+         * <p>
+         * In CLDR, this option corresponds to the "Narrow" format for measure units and the "¤¤¤¤¤" placeholder for
+         * currencies.
+         *
+         * @draft ICU 60
+         * @see 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.
+         *
+         * <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.
+         *
+         * <p>
+         * In CLDR, this option corresponds to the "Short" format for measure units and the "¤" placeholder for
+         * currencies.
+         *
+         * @draft ICU 60
+         * @see NumberFormatter
+         */
+        SHORT,
+
+        /**
+         * 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.
+         *
+         * @draft ICU 60
+         * @see 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.
+         *
+         * <p>
+         * In CLDR, this option corresponds to the "¤¤" placeholder for currencies.
+         *
+         * @draft ICU 60
+         * @see 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.
+         *
+         * @draft ICU 60
+         * @see NumberFormatter
+         */
+        HIDDEN,
+    }
+
+    /**
+     * An enum declaring how to denote positive and negative numbers. Example outputs when formatting 123 and -123 in
+     * <em>en-US</em>:
+     *
+     * <p>
+     * <ul>
+     * <li>AUTO: "123" and "-123"
+     * <li>ALWAYS: "+123" and "-123"
+     * <li>NEVER: "123" and "123"
+     * <li>ACCOUNTING: "$123" and "($123)"
+     * <li>ACCOUNTING_ALWAYS: "+$123" and "($123)"
+     * </ul>
+     *
+     * <p>
+     * The exact format, including the position and the code point of the sign, differ by locale.
+     *
+     * @draft ICU 60
+     * @see 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.
+         *
+         * @draft ICU 60
+         * @see NumberFormatter
+         */
+        AUTO,
+
+        /**
+         * Show the minus sign on negative numbers and the plus sign on positive numbers.
+         *
+         * @draft ICU 60
+         * @see NumberFormatter
+         */
+        ALWAYS,
+
+        /**
+         * Do not show the sign on positive or negative numbers.
+         *
+         * @draft ICU 60
+         * @see NumberFormatter
+         */
+        NEVER,
+
+        /**
+         * 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.
+         *
+         * <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.
+         *
+         * @draft ICU 60
+         * @see 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.
+         *
+         * @draft ICU 60
+         * @see NumberFormatter
+         */
+        ACCOUNTING_ALWAYS,
+    }
+
+    /**
+     * An enum declaring how to render the decimal separator. Example outputs when formatting 1 and 1.1 in
+     * <em>en-US</em>:
+     *
+     * <p>
+     * <ul>
+     * <li>AUTO: "1" and "1.1"
+     * <li>ALWAYS: "1." and "1.1"
+     * </ul>
+     */
+    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.
+         *
+         * @draft ICU 60
+         * @see NumberFormatter
+         */
+        AUTO,
+
+        /**
+         * Always show the decimal separator, even if there are no digits to display after the separator.
+         *
+         * @draft ICU 60
+         * @see NumberFormatter
+         */
+        ALWAYS,
+    }
+
+    /**
+     * 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;
+
+    /**
+     * 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
+     */
+    public static UnlocalizedNumberFormatter with() {
+        return BASE;
+    }
+
+    /**
+     * 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.
+     * @return A {@link LocalizedNumberFormatter}, to be used for chaining.
+     * @draft ICU 60
+     */
+    public static LocalizedNumberFormatter withLocale(Locale locale) {
+        return BASE.locale(locale);
+    }
+
+    /**
+     * 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.
+     * @return A {@link LocalizedNumberFormatter}, to be used for chaining.
+     * @draft ICU 60
+     */
+    public static LocalizedNumberFormatter withLocale(ULocale locale) {
+        return BASE.locale(locale);
+    }
+
+    /**
+     * @internal
+     * @deprecated ICU 60 This API is ICU internal only.
+     */
+    @Deprecated
+    public static UnlocalizedNumberFormatter fromDecimalFormat(DecimalFormatProperties properties,
+            DecimalFormatSymbols symbols, DecimalFormatProperties exportedProperties) {
+        MacroProps macros = NumberPropertyMapper.oldToNew(properties, symbols, exportedProperties);
+        return NumberFormatter.with().macros(macros);
+    }
+}
similarity index 67%
rename from icu4j/main/classes/core/src/newapi/NumberFormatterImpl.java
rename to icu4j/main/classes/core/src/com/ibm/icu/number/NumberFormatterImpl.java
index 0e7fb71e862dbb6cca4d41004aec365805e0e3fc..74b49426027cae012c82116dd39b5122f0e3cb38 100644 (file)
@@ -1,31 +1,28 @@
 // © 2017 and later: Unicode, Inc. and others.
 // License & terms of use: http://www.unicode.org/copyright.html#License
-package newapi;
+package com.ibm.icu.number;
 
+import com.ibm.icu.impl.number.CompactData.CompactType;
+import com.ibm.icu.impl.number.ConstantAffixModifier;
 import com.ibm.icu.impl.number.DecimalQuantity;
+import com.ibm.icu.impl.number.LongNameHandler;
+import com.ibm.icu.impl.number.MacroProps;
+import com.ibm.icu.impl.number.MicroProps;
+import com.ibm.icu.impl.number.MicroPropsGenerator;
+import com.ibm.icu.impl.number.MutablePatternModifier;
 import com.ibm.icu.impl.number.NumberStringBuilder;
+import com.ibm.icu.impl.number.Padder;
 import com.ibm.icu.impl.number.PatternStringParser;
 import com.ibm.icu.impl.number.PatternStringParser.ParsedPatternInfo;
-import com.ibm.icu.impl.number.modifiers.ConstantAffixModifier;
+import com.ibm.icu.number.NumberFormatter.DecimalSeparatorDisplay;
+import com.ibm.icu.number.NumberFormatter.SignDisplay;
+import com.ibm.icu.number.NumberFormatter.UnitWidth;
 import com.ibm.icu.text.DecimalFormatSymbols;
 import com.ibm.icu.text.NumberFormat;
 import com.ibm.icu.text.NumberingSystem;
 import com.ibm.icu.text.PluralRules;
 import com.ibm.icu.util.Currency;
-import com.ibm.icu.util.Currency.CurrencyUsage;
-import com.ibm.icu.util.NoUnit;
-import com.ibm.icu.util.ULocale;
-
-import newapi.CompactNotation.CompactType;
-import newapi.NumberFormatter.DecimalMarkDisplay;
-import newapi.NumberFormatter.SignDisplay;
-import newapi.NumberFormatter.UnitWidth;
-import newapi.impl.LongNameHandler;
-import newapi.impl.MacroProps;
-import newapi.impl.MicroProps;
-import newapi.impl.MicroPropsGenerator;
-import newapi.impl.MutablePatternModifier;
-import newapi.impl.Padder;
+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
@@ -67,6 +64,25 @@ class NumberFormatterImpl {
 
     //////////
 
+    private static boolean unitIsCurrency(MeasureUnit unit) {
+        // TODO: Check using "instanceof" operator instead?
+        return unit != null && "currency".equals(unit.getType());
+    }
+
+    private static boolean unitIsNoUnit(MeasureUnit unit) {
+        // NOTE: In ICU4C, units cannot be null, and the default unit is a NoUnit.
+        // In ICU4J, return TRUE for a null unit from this method.
+        return unit == null || "none".equals(unit.getType());
+    }
+
+    private static boolean unitIsPercent(MeasureUnit unit) {
+        return unit != null && "percent".equals(unit.getSubtype());
+    }
+
+    private static boolean unitIsPermille(MeasureUnit unit) {
+        return unit != null && "permille".equals(unit.getSubtype());
+    }
+
     /**
      * 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
@@ -81,119 +97,122 @@ class NumberFormatterImpl {
      *            object is more expensive.
      */
     private static MicroPropsGenerator macrosToMicroGenerator(MacroProps macros, boolean safe) {
-
-        String innerPattern = null;
-        LongNameHandler longNames = null;
-        Rounder defaultRounder = Rounder.unlimited();
-        Currency currency = DEFAULT_CURRENCY;
-        UnitWidth unitWidth = (macros.unitWidth == null) ? UnitWidth.SHORT : macros.unitWidth;
-        boolean perMille = false;
-        PluralRules rules = macros.rules;
-
-        // FIXME
-        String nsName = NumberingSystem.getInstance(macros.loc).getName();
-
         MicroProps micros = new MicroProps(safe);
         MicroPropsGenerator chain = micros;
 
-        // Copy over the simple settings
-        micros.sign = macros.sign == null ? SignDisplay.AUTO : macros.sign;
-        micros.decimal = macros.decimal == null ? DecimalMarkDisplay.AUTO : macros.decimal;
-        micros.multiplier = 0;
-        micros.integerWidth = macros.integerWidth == null ? IntegerWidth.zeroFillTo(1) : macros.integerWidth;
-
-        if (macros.unit == null || macros.unit == NoUnit.BASE) {
-            // No units; default format
-            innerPattern = NumberFormat.getPatternForStyle(macros.loc, NumberFormat.NUMBERSTYLE);
-        } else if (macros.unit == NoUnit.PERCENT) {
-            // Percent
-            innerPattern = NumberFormat.getPatternForStyle(macros.loc, NumberFormat.PERCENTSTYLE);
-            micros.multiplier += 2;
-        } else if (macros.unit == NoUnit.PERMILLE) {
-            // Permille
-            innerPattern = NumberFormat.getPatternForStyle(macros.loc, NumberFormat.PERCENTSTYLE);
-            micros.multiplier += 3;
-            perMille = true;
-        } else if (macros.unit instanceof Currency && macros.unitWidth != UnitWidth.FULL_NAME) {
-            // Narrow, short, or ISO currency.
-            // TODO: Although ACCOUNTING and ACCOUNTING_ALWAYS are only supported in currencies right now,
-            // the API contract allows us to add support to other units.
-            if (macros.sign == SignDisplay.ACCOUNTING || macros.sign == SignDisplay.ACCOUNTING_ALWAYS) {
-                innerPattern = NumberFormat.getPatternForStyle(macros.loc, NumberFormat.ACCOUNTINGCURRENCYSTYLE);
-            } else {
-                innerPattern = NumberFormat.getPatternForStyle(macros.loc, NumberFormat.CURRENCYSTYLE);
-            }
-            defaultRounder = Rounder.currency(CurrencyUsage.STANDARD);
-            currency = (Currency) macros.unit;
-            micros.useCurrency = true;
-        } else if (macros.unit instanceof Currency) {
-            // Currency long name
-            innerPattern = NumberFormat.getPatternForStyle(macros.loc, NumberFormat.NUMBERSTYLE);
-            longNames = LongNameHandler.forCurrencyLongNames(macros.loc, (Currency) macros.unit);
-            defaultRounder = Rounder.currency(CurrencyUsage.STANDARD);
-            currency = (Currency) macros.unit;
-            micros.useCurrency = true;
+        // TODO: Normalize the currency (accept symbols from DecimalFormatSymbols)?
+        // currency = CustomSymbolCurrency.resolve(currency, input.loc, micros.symbols);
+
+        // Pre-compute a few values for efficiency.
+        boolean isCurrency = unitIsCurrency(macros.unit);
+        boolean isNoUnit = unitIsNoUnit(macros.unit);
+        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;
+        Currency currency = isCurrency ? (Currency) macros.unit : DEFAULT_CURRENCY;
+        UnitWidth unitWidth = UnitWidth.SHORT;
+        if (macros.unitWidth != null) {
+            unitWidth = macros.unitWidth;
+        }
+        PluralRules rules = macros.rules;
+
+        // Select the numbering system.
+        NumberingSystem ns;
+        if (macros.symbols instanceof NumberingSystem) {
+            ns = (NumberingSystem) macros.symbols;
         } else {
-            // MeasureUnit
-            innerPattern = NumberFormat.getPatternForStyle(macros.loc, NumberFormat.NUMBERSTYLE);
-            longNames = LongNameHandler.forMeasureUnit(macros.loc, macros.unit, unitWidth);
+            // TODO: Is there a way to avoid creating the NumberingSystem object?
+            ns = NumberingSystem.getInstance(macros.loc);
         }
+        String nsName = ns.getName();
+
+        // Load and parse the pattern string. It is used for grouping sizes and affixes only.
+        int patternStyle;
+        if (isPercent || isPermille) {
+            patternStyle = NumberFormat.PERCENTSTYLE;
+        } 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,
+            // 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);
+        ParsedPatternInfo patternInfo = PatternStringParser.parseToPatternInfo(pattern);
 
-        // Parse the pattern, which is used for grouping and affixes only.
-        ParsedPatternInfo patternInfo = PatternStringParser.parseToPatternInfo(innerPattern);
+        /////////////////////////////////////////////////////////////////////////////////////
+        /// START POPULATING THE DEFAULT MICROPROPS AND BUILDING THE MICROPROPS GENERATOR ///
+        /////////////////////////////////////////////////////////////////////////////////////
 
         // Symbols
-        // NOTE: C++ has a special class, SymbolsWrapper, in MacroProps. Java has all the resolution logic here
-        // directly.
-        if (macros.symbols == null) {
-            micros.symbols = DecimalFormatSymbols.getInstance(macros.loc);
-        } else if (macros.symbols instanceof DecimalFormatSymbols) {
+        if (macros.symbols instanceof DecimalFormatSymbols) {
             micros.symbols = (DecimalFormatSymbols) macros.symbols;
-        } else if (macros.symbols instanceof NumberingSystem) {
-            // TODO: Do this more efficiently. Will require modifying DecimalFormatSymbols.
-            NumberingSystem ns = (NumberingSystem) macros.symbols;
-            ULocale temp = macros.loc.setKeywordValue("numbers", ns.getName());
-            micros.symbols = DecimalFormatSymbols.getInstance(temp);
         } else {
-            throw new AssertionError();
+            micros.symbols = DecimalFormatSymbols.forNumberingSystem(macros.loc, ns);
         }
 
-        // TODO: Normalize the currency (accept symbols from DecimalFormatSymbols)?
-        // currency = CustomSymbolCurrency.resolve(currency, input.loc, micros.symbols);
-
         // Multiplier (compatibility mode value).
-        // An int magnitude multiplier is used when not in compatibility mode to
-        // reduce object creations.
         if (macros.multiplier != null) {
             chain = macros.multiplier.copyAndChain(chain);
         }
 
         // Rounding strategy
         if (macros.rounder != null) {
-            micros.rounding = Rounder.normalizeType(macros.rounder, currency);
+            micros.rounding = macros.rounder;
         } else if (macros.notation instanceof CompactNotation) {
             micros.rounding = Rounder.COMPACT_STRATEGY;
+        } else if (isCurrency) {
+            micros.rounding = Rounder.MONETARY_STANDARD;
         } else {
-            micros.rounding = Rounder.normalizeType(defaultRounder, currency);
+            micros.rounding = Rounder.MAX_FRAC_6;
         }
+        micros.rounding = micros.rounding.withLocaleData(currency);
 
         // Grouping strategy
         if (macros.grouper != null) {
-            micros.grouping = Grouper.normalizeType(macros.grouper, patternInfo);
+            micros.grouping = macros.grouper;
         } else if (macros.notation instanceof CompactNotation) {
             // Compact notation uses minGrouping by default since ICU 59
-            micros.grouping = Grouper.normalizeType(Grouper.min2(), patternInfo);
+            micros.grouping = Grouper.minTwoDigits();
         } else {
-            micros.grouping = Grouper.normalizeType(Grouper.defaults(), patternInfo);
+            micros.grouping = Grouper.defaults();
         }
+        micros.grouping = micros.grouping.withLocaleData(patternInfo);
 
         // Padding strategy
         if (macros.padder != null) {
             micros.padding = macros.padder;
         } else {
-            micros.padding = Padder.none();
+            micros.padding = Padder.NONE;
         }
 
+        // Integer width
+        if (macros.integerWidth != null) {
+            micros.integerWidth = macros.integerWidth;
+        } else {
+            micros.integerWidth = IntegerWidth.DEFAULT;
+        }
+
+        // Sign display
+        if (macros.sign != null) {
+            micros.sign = macros.sign;
+        } else {
+            micros.sign = SignDisplay.AUTO;
+        }
+
+        // Decimal mark display
+        if (macros.decimal != null) {
+            micros.decimal = macros.decimal;
+        } else {
+            micros.decimal = DecimalSeparatorDisplay.AUTO;
+        }
+
+        // Use monetary separator symbols
+        micros.useCurrency = isCurrency;
+
         // Inner modifier (scientific notation)
         if (macros.notation instanceof ScientificNotation) {
             chain = ((ScientificNotation) macros.notation).withLocaleData(micros.symbols, safe, chain);
@@ -206,7 +225,7 @@ class NumberFormatterImpl {
         // The default middle modifier is weak (thus the false argument).
         MutablePatternModifier patternMod = new MutablePatternModifier(false);
         patternMod.setPatternInfo((macros.affixProvider != null) ? macros.affixProvider : patternInfo);
-        patternMod.setPatternAttributes(micros.sign, perMille);
+        patternMod.setPatternAttributes(micros.sign, isPermille);
         if (patternMod.needsPlurals()) {
             if (rules == null) {
                 // Lazily create PluralRules
@@ -223,12 +242,18 @@ class NumberFormatterImpl {
         }
 
         // Outer modifier (CLDR units and currency long names)
-        if (longNames != null) {
+        if (isCldrUnit) {
+            if (rules == null) {
+                // Lazily create PluralRules
+                rules = PluralRules.forLocale(macros.loc);
+            }
+            chain = LongNameHandler.forMeasureUnit(macros.loc, macros.unit, unitWidth, rules, chain);
+        } else if (isCurrency && unitWidth == UnitWidth.FULL_NAME) {
             if (rules == null) {
                 // Lazily create PluralRules
                 rules = PluralRules.forLocale(macros.loc);
             }
-            chain = longNames.withLocaleData(rules, chain);
+            chain = LongNameHandler.forCurrencyLongNames(macros.loc, currency, rules, chain);
         } else {
             // No outer modifier required
             micros.modOuter = ConstantAffixModifier.EMPTY;
@@ -265,7 +290,6 @@ class NumberFormatterImpl {
      *            The output string. Will be mutated.
      */
     private static void microsToString(MicroProps micros, DecimalQuantity quantity, NumberStringBuilder string) {
-        quantity.adjustMagnitude(micros.multiplier);
         micros.rounding.apply(quantity);
         if (micros.integerWidth.maxInt == -1) {
             quantity.setIntegerLength(micros.integerWidth.minInt, Integer.MAX_VALUE);
@@ -298,7 +322,7 @@ class NumberFormatterImpl {
             length += writeIntegerDigits(micros, quantity, string);
 
             // Add the decimal point
-            if (quantity.getLowerDisplayMagnitude() < 0 || micros.decimal == DecimalMarkDisplay.ALWAYS) {
+            if (quantity.getLowerDisplayMagnitude() < 0 || micros.decimal == DecimalSeparatorDisplay.ALWAYS) {
                 length += string.insert(length, micros.useCurrency ? micros.symbols.getMonetaryDecimalSeparatorString()
                         : micros.symbols.getDecimalSeparatorString(), NumberFormat.Field.DECIMAL_SEPARATOR);
             }
similarity index 97%
rename from icu4j/main/classes/core/src/newapi/NumberFormatterSettings.java
rename to icu4j/main/classes/core/src/com/ibm/icu/number/NumberFormatterSettings.java
index 694448b345ccdf362339cf6eb2e6feed6a04a08a..1646204c895f7f148eb9ff5920789e293eb529f7 100644 (file)
@@ -1,7 +1,12 @@
 // © 2017 and later: Unicode, Inc. and others.
 // License & terms of use: http://www.unicode.org/copyright.html#License
-package newapi;
+package com.ibm.icu.number;
 
+import com.ibm.icu.impl.number.MacroProps;
+import com.ibm.icu.impl.number.Padder;
+import com.ibm.icu.number.NumberFormatter.DecimalSeparatorDisplay;
+import com.ibm.icu.number.NumberFormatter.SignDisplay;
+import com.ibm.icu.number.NumberFormatter.UnitWidth;
 import com.ibm.icu.text.DecimalFormatSymbols;
 import com.ibm.icu.text.MeasureFormat.FormatWidth;
 import com.ibm.icu.text.NumberingSystem;
@@ -11,12 +16,6 @@ import com.ibm.icu.util.MeasureUnit;
 import com.ibm.icu.util.NoUnit;
 import com.ibm.icu.util.ULocale;
 
-import newapi.NumberFormatter.DecimalMarkDisplay;
-import newapi.NumberFormatter.SignDisplay;
-import newapi.NumberFormatter.UnitWidth;
-import newapi.impl.MacroProps;
-import newapi.impl.Padder;
-
 /**
  * An abstract base class for specifying settings related to number formatting. This class is implemented by
  * {@link UnlocalizedNumberFormatter} and {@link LocalizedNumberFormatter}.
@@ -342,7 +341,7 @@ public abstract class NumberFormatterSettings<T extends NumberFormatterSettings<
         return create(KEY_SIGN, style);
     }
 
-    public T decimal(DecimalMarkDisplay style) {
+    public T decimal(DecimalSeparatorDisplay style) {
         return create(KEY_DECIMAL, style);
     }
 
@@ -364,11 +363,6 @@ public abstract class NumberFormatterSettings<T extends NumberFormatterSettings<
         return create(KEY_THRESHOLD, threshold);
     }
 
-    /** Non-public method */
-    public String toSkeleton() {
-        return SkeletonBuilder.macrosToSkeleton(resolve());
-    }
-
     abstract T create(int key, Object value);
 
     MacroProps resolve() {
@@ -438,7 +432,7 @@ public abstract class NumberFormatterSettings<T extends NumberFormatterSettings<
                 break;
             case KEY_DECIMAL:
                 if (macros.decimal == null) {
-                    macros.decimal = (DecimalMarkDisplay) current.value;
+                    macros.decimal = (DecimalSeparatorDisplay) current.value;
                 }
                 break;
             case KEY_THRESHOLD:
similarity index 96%
rename from icu4j/main/classes/core/src/newapi/NumberPropertyMapper.java
rename to icu4j/main/classes/core/src/com/ibm/icu/number/NumberPropertyMapper.java
index 943d7c9e4de324fadadcc37ce2c606b4a2bf426b..027080254ed2df09c3d757d5e6b8d69976621f0b 100644 (file)
@@ -1,15 +1,25 @@
 // © 2017 and later: Unicode, Inc. and others.
 // License & terms of use: http://www.unicode.org/copyright.html#License
-package newapi;
+package com.ibm.icu.number;
 
 import java.math.BigDecimal;
 import java.math.MathContext;
 
 import com.ibm.icu.impl.StandardPlural;
+import com.ibm.icu.impl.number.AffixPatternProvider;
 import com.ibm.icu.impl.number.AffixUtils;
+import com.ibm.icu.impl.number.CustomSymbolCurrency;
 import com.ibm.icu.impl.number.DecimalFormatProperties;
+import com.ibm.icu.impl.number.MacroProps;
+import com.ibm.icu.impl.number.MultiplierImpl;
+import com.ibm.icu.impl.number.Padder;
 import com.ibm.icu.impl.number.PatternStringParser;
 import com.ibm.icu.impl.number.PatternStringParser.ParsedPatternInfo;
+import com.ibm.icu.number.NumberFormatter.DecimalSeparatorDisplay;
+import com.ibm.icu.number.NumberFormatter.SignDisplay;
+import com.ibm.icu.number.Rounder.FractionRounderImpl;
+import com.ibm.icu.number.Rounder.IncrementRounderImpl;
+import com.ibm.icu.number.Rounder.SignificantRounderImpl;
 import com.ibm.icu.impl.number.RoundingUtils;
 import com.ibm.icu.text.CompactDecimalFormat.CompactStyle;
 import com.ibm.icu.text.CurrencyPluralInfo;
@@ -18,17 +28,6 @@ import com.ibm.icu.util.Currency;
 import com.ibm.icu.util.Currency.CurrencyUsage;
 import com.ibm.icu.util.ULocale;
 
-import newapi.NumberFormatter.DecimalMarkDisplay;
-import newapi.NumberFormatter.SignDisplay;
-import newapi.Rounder.FractionRounderImpl;
-import newapi.Rounder.IncrementRounderImpl;
-import newapi.Rounder.SignificantRounderImpl;
-import newapi.impl.AffixPatternProvider;
-import newapi.impl.CustomSymbolCurrency;
-import newapi.impl.MacroProps;
-import newapi.impl.MultiplierImpl;
-import newapi.impl.Padder;
-
 /**
  * <p>
  * This class, as well as NumberFormatterImpl, could go into the impl package, but they depend on too many
@@ -198,8 +197,8 @@ final class NumberPropertyMapper {
         // DECIMAL MARK ALWAYS SHOWN //
         ///////////////////////////////
 
-        macros.decimal = properties.getDecimalSeparatorAlwaysShown() ? DecimalMarkDisplay.ALWAYS
-                : DecimalMarkDisplay.AUTO;
+        macros.decimal = properties.getDecimalSeparatorAlwaysShown() ? DecimalSeparatorDisplay.ALWAYS
+                : DecimalSeparatorDisplay.AUTO;
 
         ///////////////////////
         // SIGN ALWAYS SHOWN //
similarity index 53%
rename from icu4j/main/classes/core/src/newapi/Rounder.java
rename to icu4j/main/classes/core/src/com/ibm/icu/number/Rounder.java
index a21776fbd91737410594d6492b36597fd8199e26..0c52e2f12ae58c69dd2c46ce5cc1f55da143059d 100644 (file)
@@ -1,39 +1,50 @@
 // © 2017 and later: Unicode, Inc. and others.
 // License & terms of use: http://www.unicode.org/copyright.html#License
-package newapi;
+package com.ibm.icu.number;
 
 import java.math.BigDecimal;
 import java.math.MathContext;
 import java.math.RoundingMode;
 
 import com.ibm.icu.impl.number.DecimalQuantity;
+import com.ibm.icu.impl.number.MultiplierProducer;
 import com.ibm.icu.impl.number.RoundingUtils;
 import com.ibm.icu.util.Currency;
 import com.ibm.icu.util.Currency.CurrencyUsage;
 
-import newapi.impl.MultiplierProducer;
-
+/**
+ * A class that defines the rounding strategy to be used when formatting numbers in NumberFormatter.
+ *
+ * <p>
+ * To create a Rounder, use one of the factory methods.
+ *
+ * @draft ICU 60
+ * @see NumberFormatter
+ */
 public abstract class Rounder implements Cloneable {
 
-    // FIXME
-    /** @internal */
-    public static final int MAX_VALUE = 100;
-
     /* package-private final */ MathContext mathContext;
 
     /* package-private */ Rounder() {
-        mathContext = RoundingUtils.mathContextUnlimited(RoundingMode.HALF_EVEN);
+        mathContext = RoundingUtils.mathContextUnlimited(RoundingUtils.DEFAULT_ROUNDING_MODE);
     }
 
     /**
      * Show all available digits to full precision.
      *
      * <p>
-     * <strong>NOTE:</strong> If you are formatting <em>doubles</em> and you know that the number of fraction places or
-     * significant digits is bounded, consider using {@link #maxFraction} or {@link #maxDigits} instead to maximize
-     * performance.
+     * <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/
      *
-     * @return A rounding strategy for {@link NumberFormatterSettings#rounding}.
+     * @return A Rounder for chaining or passing to the NumberFormatter rounding() setter.
+     * @draft ICU 60
+     * @see NumberFormatter
      */
     public static Rounder unlimited() {
         return constructInfinite();
@@ -42,18 +53,20 @@ public abstract class Rounder implements Cloneable {
     /**
      * Show numbers rounded if necessary to the nearest integer.
      *
-     * @return A rounding strategy for {@link NumberFormatterSettings#rounding}.
+     * @return A FractionRounder for chaining or passing to the NumberFormatter rounding() setter.
+     * @draft ICU 60
+     * @see NumberFormatter
      */
     public static FractionRounder integer() {
         return constructFraction(0, 0);
     }
 
     /**
-     * Show numbers rounded if necessary to a certain number of fraction places (digits after the decimal mark).
-     * Additionally, pad with zeros to ensure that this number digits 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 minMaxFractionDigits = 3:
+     * Example output with minMaxFractionPlaces = 3:
      *
      * <p>
      * 87,650.000<br>
@@ -69,106 +82,196 @@ public abstract class Rounder implements Cloneable {
      * <p>
      * This method is equivalent to {@link #minMaxFraction} with both arguments equal.
      *
-     * @param minMaxFractionDigits
-     *            The minimum and maximum number of digits to display after the decimal mark (rounding if too long or
-     *            padding with zeros if too short).
-     * @return A rounding strategy for {@link NumberFormatterSettings#rounding}.
+     * @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).
+     * @return A FractionRounder for chaining or passing to the NumberFormatter rounding() setter.
+     * @draft ICU 60
+     * @see NumberFormatter
      */
-    public static FractionRounder fixedFraction(int minMaxFractionDigits) {
-        if (minMaxFractionDigits >= 0 && minMaxFractionDigits <= MAX_VALUE) {
-            return constructFraction(minMaxFractionDigits, minMaxFractionDigits);
+    public static FractionRounder fixedFraction(int minMaxFractionPlaces) {
+        if (minMaxFractionPlaces >= 0 && minMaxFractionPlaces <= RoundingUtils.MAX_INT_FRAC_SIG) {
+            return constructFraction(minMaxFractionPlaces, minMaxFractionPlaces);
         } else {
-            throw new IllegalArgumentException("Fraction length must be between 0 and " + MAX_VALUE);
+            throw new IllegalArgumentException(
+                    "Fraction length must be between 0 and " + RoundingUtils.MAX_INT_FRAC_SIG);
         }
     }
 
     /**
-     * Always show a certain number of digits after the decimal mark, 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> and you know that the number of fraction places is
-     * bounded, consider using {@link #fixedFraction} or {@link #minMaxFraction} instead to maximize performance.
+     * <strong>NOTE:</strong> If you are formatting <em>doubles</em>, see the performance note in {@link #unlimited}.
      *
-     * @param minFractionDigits
-     *            The minimum number of digits to display after the decimal mark (padding with zeros if necessary).
-     * @return A rounding strategy for {@link NumberFormatterSettings#rounding}.
+     * @param minFractionPlaces
+     *            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
+     * @see NumberFormatter
      */
-    public static FractionRounder minFraction(int minFractionDigits) {
-        if (minFractionDigits >= 0 && minFractionDigits < MAX_VALUE) {
-            return constructFraction(minFractionDigits, -1);
+    public static FractionRounder minFraction(int minFractionPlaces) {
+        if (minFractionPlaces >= 0 && minFractionPlaces < RoundingUtils.MAX_INT_FRAC_SIG) {
+            return constructFraction(minFractionPlaces, -1);
         } else {
-            throw new IllegalArgumentException("Fraction length must be between 0 and " + MAX_VALUE);
+            throw new IllegalArgumentException(
+                    "Fraction length must be between 0 and " + RoundingUtils.MAX_INT_FRAC_SIG);
         }
     }
 
     /**
-     * Show numbers rounded if necessary to a certain number of fraction places (digits after the decimal mark). 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 maxFractionDigits
-     *            The maximum number of digits to display after the decimal mark (rounding if necessary).
-     * @return A rounding strategy for {@link NumberFormatterSettings#rounding}.
+     * @param maxFractionPlaces
+     *            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
+     * @see NumberFormatter
      */
-    public static FractionRounder maxFraction(int maxFractionDigits) {
-        if (maxFractionDigits >= 0 && maxFractionDigits < MAX_VALUE) {
-            return constructFraction(0, maxFractionDigits);
+    public static FractionRounder maxFraction(int maxFractionPlaces) {
+        if (maxFractionPlaces >= 0 && maxFractionPlaces < RoundingUtils.MAX_INT_FRAC_SIG) {
+            return constructFraction(0, maxFractionPlaces);
         } else {
-            throw new IllegalArgumentException("Fraction length must be between 0 and " + MAX_VALUE);
+            throw new IllegalArgumentException(
+                    "Fraction length must be between 0 and " + RoundingUtils.MAX_INT_FRAC_SIG);
         }
     }
 
     /**
-     * Show numbers rounded if necessary to a certain number of fraction places (digits after the decimal mark); in
-     * addition, always show a certain number of digits after the decimal mark, 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 minFractionDigits
-     *            The minimum number of digits to display after the decimal mark (padding with zeros if necessary).
-     * @param maxFractionDigits
-     *            The maximum number of digits to display after the decimal mark (rounding if necessary).
-     * @return A rounding strategy for {@link NumberFormatterSettings#rounding}.
+     * @param minFractionPlaces
+     *            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).
+     * @return A FractionRounder for chaining or passing to the NumberFormatter rounding() setter.
+     * @draft ICU 60
+     * @see NumberFormatter
      */
-    public static FractionRounder minMaxFraction(int minFractionDigits, int maxFractionDigits) {
-        if (minFractionDigits >= 0 && maxFractionDigits <= MAX_VALUE && minFractionDigits <= maxFractionDigits) {
-            return constructFraction(minFractionDigits, maxFractionDigits);
+    public static FractionRounder minMaxFraction(int minFractionPlaces, int maxFractionPlaces) {
+        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 " + MAX_VALUE);
+            throw new IllegalArgumentException(
+                    "Fraction length must be between 0 and " + RoundingUtils.MAX_INT_FRAC_SIG);
         }
     }
 
+    /**
+     * 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).
+     * @return A Rounder for chaining or passing to the NumberFormatter rounding() setter.
+     * @draft ICU 60
+     * @see NumberFormatter
+     */
     public static Rounder fixedDigits(int minMaxSignificantDigits) {
-        if (minMaxSignificantDigits > 0 && minMaxSignificantDigits <= MAX_VALUE) {
+        if (minMaxSignificantDigits > 0 && minMaxSignificantDigits <= RoundingUtils.MAX_INT_FRAC_SIG) {
             return constructSignificant(minMaxSignificantDigits, minMaxSignificantDigits);
         } else {
-            throw new IllegalArgumentException("Significant digits must be between 0 and " + MAX_VALUE);
+            throw new IllegalArgumentException(
+                    "Significant digits must be between 0 and " + RoundingUtils.MAX_INT_FRAC_SIG);
         }
     }
 
+    /**
+     * 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}.
+     *
+     * @param minSignificantDigits
+     *            The minimum number of significant digits to display (padding with zeros if too short).
+     * @return A Rounder for chaining or passing to the NumberFormatter rounding() setter.
+     * @draft ICU 60
+     * @see NumberFormatter
+     */
     public static Rounder minDigits(int minSignificantDigits) {
-        if (minSignificantDigits > 0 && minSignificantDigits <= MAX_VALUE) {
+        if (minSignificantDigits > 0 && minSignificantDigits <= RoundingUtils.MAX_INT_FRAC_SIG) {
             return constructSignificant(minSignificantDigits, -1);
         } else {
-            throw new IllegalArgumentException("Significant digits must be between 0 and " + MAX_VALUE);
+            throw new IllegalArgumentException(
+                    "Significant digits must be between 0 and " + RoundingUtils.MAX_INT_FRAC_SIG);
         }
     }
 
+    /**
+     * Show numbers rounded if necessary to a certain number of significant digits/figures.
+     *
+     * @param maxSignificantDigits
+     *            The maximum number of significant digits to display (rounding if too long).
+     * @return A Rounder for chaining or passing to the NumberFormatter rounding() setter.
+     * @draft ICU 60
+     * @see NumberFormatter
+     */
     public static Rounder maxDigits(int maxSignificantDigits) {
-        if (maxSignificantDigits > 0 && maxSignificantDigits <= MAX_VALUE) {
+        if (maxSignificantDigits > 0 && maxSignificantDigits <= RoundingUtils.MAX_INT_FRAC_SIG) {
             return constructSignificant(0, maxSignificantDigits);
         } else {
-            throw new IllegalArgumentException("Significant digits must be between 0 and " + MAX_VALUE);
+            throw new IllegalArgumentException(
+                    "Significant digits must be between 0 and " + RoundingUtils.MAX_INT_FRAC_SIG);
         }
     }
 
+    /**
+     * 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).
+     * @param maxSignificantDigits
+     *            The maximum number of significant digits to display (rounding if necessary).
+     * @return A Rounder for chaining or passing to the NumberFormatter rounding() setter.
+     * @draft ICU 60
+     * @see NumberFormatter
+     */
     public static Rounder minMaxDigits(int minSignificantDigits, int maxSignificantDigits) {
-        if (minSignificantDigits > 0 && maxSignificantDigits <= MAX_VALUE
+        if (minSignificantDigits > 0 && maxSignificantDigits <= RoundingUtils.MAX_INT_FRAC_SIG
                 && minSignificantDigits <= maxSignificantDigits) {
             return constructSignificant(minSignificantDigits, maxSignificantDigits);
         } else {
-            throw new IllegalArgumentException("Significant digits must be between 0 and " + MAX_VALUE);
+            throw new IllegalArgumentException(
+                    "Significant digits must be between 0 and " + RoundingUtils.MAX_INT_FRAC_SIG);
         }
     }
 
+    /**
+     * 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:
+     *
+     * <pre>
+     * Rounder.increment(new BigDecimal("0.50"))
+     * </pre>
+     *
+     * <p>
+     * For more information on the scale of Java BigDecimal, see {@link java.math.BigDecimal#scale()}.
+     *
+     * @param roundingIncrement
+     *            The increment to which to round numbers.
+     * @return A Rounder for chaining or passing to the NumberFormatter rounding() setter.
+     * @draft ICU 60
+     * @see NumberFormatter
+     */
     public static Rounder increment(BigDecimal roundingIncrement) {
         if (roundingIncrement != null && roundingIncrement.compareTo(BigDecimal.ZERO) > 0) {
             return constructIncrement(roundingIncrement);
@@ -177,6 +280,23 @@ 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").
+     *
+     * <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.
+     *
+     * @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).
+     * @return A CurrencyRounder for chaining or passing to the NumberFormatter rounding() setter.
+     * @draft ICU 60
+     * @see NumberFormatter
+     */
     public static CurrencyRounder currency(CurrencyUsage currencyUsage) {
         if (currencyUsage != null) {
             return constructCurrency(currencyUsage);
@@ -186,15 +306,14 @@ public abstract class Rounder implements Cloneable {
     }
 
     /**
-     * Sets the {@link java.math.RoundingMode} to use when picking the direction to round (up or down).
-     *
-     * <p>
-     * Common values include {@link RoundingMode#HALF_EVEN}, {@link RoundingMode#HALF_UP}, and
-     * {@link RoundingMode#CEILING}. 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.
-     * @return An immutable object for chaining.
+     * @return A Rounder for chaining.
+     * @draft ICU 60
+     * @see NumberFormatter
      */
     public Rounder withMode(RoundingMode roundingMode) {
         return withMode(RoundingUtils.mathContextUnlimited(roundingMode));
@@ -216,6 +335,11 @@ public abstract class Rounder implements Cloneable {
         return other;
     }
 
+    /**
+     * @internal
+     * @deprecated This API is ICU internal only.
+     */
+    @Deprecated
     @Override
     public Object clone() {
         try {
@@ -237,23 +361,24 @@ public abstract class Rounder implements Cloneable {
     // PACKAGE-PRIVATE APIS //
     //////////////////////////
 
-    private static final InfiniteRounderImpl NONE = new InfiniteRounderImpl();
+    static final InfiniteRounderImpl NONE = new InfiniteRounderImpl();
 
-    private static final FractionRounderImpl FIXED_FRAC_0 = new FractionRounderImpl(0, 0);
-    private static final FractionRounderImpl FIXED_FRAC_2 = new FractionRounderImpl(2, 2);
+    static final FractionRounderImpl FIXED_FRAC_0 = new FractionRounderImpl(0, 0);
+    static final FractionRounderImpl FIXED_FRAC_2 = new FractionRounderImpl(2, 2);
+    static final FractionRounderImpl MAX_FRAC_6 = new FractionRounderImpl(0, 6);
 
-    private static final SignificantRounderImpl FIXED_SIG_2 = new SignificantRounderImpl(2, 2);
-    private static final SignificantRounderImpl FIXED_SIG_3 = new SignificantRounderImpl(3, 3);
-    private static final SignificantRounderImpl RANGE_SIG_2_3 = new SignificantRounderImpl(2, 3);
+    static final SignificantRounderImpl FIXED_SIG_2 = new SignificantRounderImpl(2, 2);
+    static final SignificantRounderImpl FIXED_SIG_3 = new SignificantRounderImpl(3, 3);
+    static final SignificantRounderImpl RANGE_SIG_2_3 = new SignificantRounderImpl(2, 3);
 
-    /* package-private */ static final FracSigRounderImpl COMPACT_STRATEGY = new FracSigRounderImpl(0, 0, 2, -1);
+    static final FracSigRounderImpl COMPACT_STRATEGY = new FracSigRounderImpl(0, 0, 2, -1);
 
-    private static final IncrementRounderImpl NICKEL = new IncrementRounderImpl(BigDecimal.valueOf(0.5));
+    static final IncrementRounderImpl NICKEL = new IncrementRounderImpl(BigDecimal.valueOf(0.05));
 
-    private static final CurrencyRounderImpl MONETARY_STANDARD = new CurrencyRounderImpl(CurrencyUsage.STANDARD);
-    private static final CurrencyRounderImpl MONETARY_CASH = new CurrencyRounderImpl(CurrencyUsage.CASH);
+    static final CurrencyRounderImpl MONETARY_STANDARD = new CurrencyRounderImpl(CurrencyUsage.STANDARD);
+    static final CurrencyRounderImpl MONETARY_CASH = new CurrencyRounderImpl(CurrencyUsage.CASH);
 
-    private static final PassThroughRounderImpl PASS_THROUGH = new PassThroughRounderImpl();
+    static final PassThroughRounderImpl PASS_THROUGH = new PassThroughRounderImpl();
 
     static Rounder constructInfinite() {
         return NONE;
@@ -264,6 +389,8 @@ public abstract class Rounder implements Cloneable {
             return FIXED_FRAC_0;
         } else if (minFrac == 2 && maxFrac == 2) {
             return FIXED_FRAC_2;
+        } else if (minFrac == 0 && maxFrac == 6) {
+            return MAX_FRAC_6;
         } else {
             return new FractionRounderImpl(minFrac, maxFrac);
         }
@@ -293,7 +420,8 @@ public abstract class Rounder implements Cloneable {
     }
 
     static Rounder constructIncrement(BigDecimal increment) {
-        if (increment.compareTo(NICKEL.increment) == 0) {
+        // NOTE: .equals() is what we want, not .compareTo()
+        if (increment.equals(NICKEL.increment)) {
             return NICKEL;
         } else {
             return new IncrementRounderImpl(increment);
@@ -331,17 +459,15 @@ 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.
      *
-     * @param rounder
-     *            The input object.
      * @param currency
      *            A currency object to use in case the input object needs it.
      * @return A Rounder object ready for use.
      */
-    static Rounder normalizeType(Rounder rounder, Currency currency) {
-        if (rounder instanceof CurrencyRounder) {
-            return ((CurrencyRounder) rounder).withCurrency(currency);
+    Rounder withLocaleData(Currency currency) {
+        if (this instanceof CurrencyRounder) {
+            return ((CurrencyRounder) this).withCurrency(currency);
         } else {
-            return rounder;
+            return this;
         }
     }
 
similarity index 80%
rename from icu4j/main/classes/core/src/newapi/ScientificNotation.java
rename to icu4j/main/classes/core/src/com/ibm/icu/number/ScientificNotation.java
index e31ec8af73ff9bc94ebb349b5ecb69798f8a1108..4fd1d3aadde88fa525d562f50255bf39911e06e5 100644 (file)
@@ -1,20 +1,28 @@
 // © 2017 and later: Unicode, Inc. and others.
 // License & terms of use: http://www.unicode.org/copyright.html#License
-package newapi;
+package com.ibm.icu.number;
 
 import com.ibm.icu.impl.number.DecimalQuantity;
+import com.ibm.icu.impl.number.MicroProps;
+import com.ibm.icu.impl.number.MicroPropsGenerator;
 import com.ibm.icu.impl.number.Modifier;
+import com.ibm.icu.impl.number.MultiplierProducer;
 import com.ibm.icu.impl.number.NumberStringBuilder;
+import com.ibm.icu.impl.number.RoundingUtils;
+import com.ibm.icu.number.NumberFormatter.SignDisplay;
+import com.ibm.icu.number.Rounder.SignificantRounderImpl;
 import com.ibm.icu.text.DecimalFormatSymbols;
 import com.ibm.icu.text.NumberFormat;
 
-import newapi.NumberFormatter.SignDisplay;
-import newapi.Rounder.SignificantRounderImpl;
-import newapi.impl.MicroProps;
-import newapi.impl.MicroPropsGenerator;
-import newapi.impl.MultiplierProducer;
-
-@SuppressWarnings("unused")
+/**
+ * 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}.
+ *
+ * @draft ICU 60
+ * @see NumberFormatter
+ */
 public class ScientificNotation extends Notation implements Cloneable {
 
     int engineeringInterval;
@@ -30,22 +38,56 @@ public class ScientificNotation extends Notation implements Cloneable {
         this.exponentSignDisplay = exponentSignDisplay;
     }
 
+    /**
+     * 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".
+     *
+     * @param minExponentDigits
+     *            The minimum number of digits to show in the exponent.
+     * @return A ScientificNotation, for chaining.
+     * @draft ICU 60
+     * @see NumberFormatter
+     */
     public ScientificNotation withMinExponentDigits(int minExponentDigits) {
-        if (minExponentDigits >= 0 && minExponentDigits < Rounder.MAX_VALUE) {
+        if (minExponentDigits >= 0 && minExponentDigits < RoundingUtils.MAX_INT_FRAC_SIG) {
             ScientificNotation other = (ScientificNotation) this.clone();
             other.minExponentDigits = minExponentDigits;
             return other;
         } else {
-            throw new IllegalArgumentException("Integer digits must be between 0 and " + Rounder.MAX_VALUE);
+            throw new IllegalArgumentException(
+                    "Integer digits must be between 0 and " + RoundingUtils.MAX_INT_FRAC_SIG);
         }
     }
 
+    /**
+     * 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".
+     *
+     * @param exponentSignDisplay
+     *            The strategy for displaying the sign in the exponent.
+     * @return A ScientificNotation, for chaining.
+     * @draft ICU 60
+     * @see NumberFormatter
+     */
     public ScientificNotation withExponentSignDisplay(SignDisplay exponentSignDisplay) {
         ScientificNotation other = (ScientificNotation) this.clone();
         other.exponentSignDisplay = exponentSignDisplay;
         return other;
     }
 
+    /**
+     * @internal
+     * @deprecated This API is ICU internal only.
+     */
+    @Deprecated
     @Override
     public Object clone() {
         try {
@@ -183,7 +225,7 @@ public class ScientificNotation extends Notation implements Cloneable {
             i += output.insert(i, symbols.getExponentSeparator(), NumberFormat.Field.EXPONENT_SYMBOL);
             if (exponent < 0 && notation.exponentSignDisplay != SignDisplay.NEVER) {
                 i += output.insert(i, symbols.getMinusSignString(), NumberFormat.Field.EXPONENT_SIGN);
-            } else if (notation.exponentSignDisplay == SignDisplay.ALWAYS) {
+            } else if (exponent >= 0 && notation.exponentSignDisplay == SignDisplay.ALWAYS) {
                 i += output.insert(i, symbols.getPlusSignString(), NumberFormat.Field.EXPONENT_SIGN);
             }
             // Append the exponent digits (using a simple inline algorithm)
similarity index 88%
rename from icu4j/main/classes/core/src/newapi/SimpleNotation.java
rename to icu4j/main/classes/core/src/com/ibm/icu/number/SimpleNotation.java
index 8c72cb427f127f0419b22041a342a7a2df026386..08db0ca0bb8e9c7f9f6824684cae1598e555e5a0 100644 (file)
@@ -1,6 +1,6 @@
 // © 2017 and later: Unicode, Inc. and others.
 // License & terms of use: http://www.unicode.org/copyright.html#License
-package newapi;
+package com.ibm.icu.number;
 
 public class SimpleNotation extends Notation {
     /* package-private */ SimpleNotation() {
similarity index 97%
rename from icu4j/main/classes/core/src/newapi/UnlocalizedNumberFormatter.java
rename to icu4j/main/classes/core/src/com/ibm/icu/number/UnlocalizedNumberFormatter.java
index fcfa7f9993071a164c08636e4201cdc942b219f4..0afab0faa5ea7ba8f483c6d27e30e689021b469a 100644 (file)
@@ -1,6 +1,6 @@
 // © 2017 and later: Unicode, Inc. and others.
 // License & terms of use: http://www.unicode.org/copyright.html#License
-package newapi;
+package com.ibm.icu.number;
 
 import java.util.Locale;
 
index 63e20a93f020aacd1d6d4ac4a95a7fb51021ab42..1ee62d28568eaac98a115908191f07a032a0bf9e 100644 (file)
@@ -15,12 +15,16 @@ import java.text.ParsePosition;
 
 import com.ibm.icu.impl.number.AffixUtils;
 import com.ibm.icu.impl.number.DecimalFormatProperties;
+import com.ibm.icu.impl.number.Padder.PadPosition;
 import com.ibm.icu.impl.number.Parse;
 import com.ibm.icu.impl.number.PatternStringParser;
 import com.ibm.icu.impl.number.PatternStringUtils;
 import com.ibm.icu.lang.UCharacter;
 import com.ibm.icu.math.BigDecimal;
 import com.ibm.icu.math.MathContext;
+import com.ibm.icu.number.FormattedNumber;
+import com.ibm.icu.number.LocalizedNumberFormatter;
+import com.ibm.icu.number.NumberFormatter;
 import com.ibm.icu.text.PluralRules.IFixedDecimal;
 import com.ibm.icu.util.Currency;
 import com.ibm.icu.util.Currency.CurrencyUsage;
@@ -28,11 +32,6 @@ import com.ibm.icu.util.CurrencyAmount;
 import com.ibm.icu.util.ULocale;
 import com.ibm.icu.util.ULocale.Category;
 
-import newapi.FormattedNumber;
-import newapi.LocalizedNumberFormatter;
-import newapi.NumberFormatter;
-import newapi.impl.Padder.PadPosition;
-
 /**
  * {@icuenhanced java.text.DecimalFormat}.{@icu _usage_} <code>DecimalFormat</code> is the primary
  * concrete subclass of {@link NumberFormat}. It has a variety of features designed to make it
index 35216fbce770efd5927d60207d712f7037bfda98..dab77744d63110c9273656543a32ea214bdedf09 100644 (file)
@@ -1490,6 +1490,22 @@ public abstract class NumberFormat extends UFormat {
      */
     @Deprecated
     public static String getPatternForStyle(ULocale forLocale, int choice) {
+        NumberingSystem ns = NumberingSystem.getInstance(forLocale);
+        String nsName = ns.getName();
+        return getPatternForStyleAndNumberingSystem(forLocale, nsName, choice);
+    }
+
+    /**
+     * Returns the pattern for the provided locale, numbering system, and choice.
+     * @param forLocale the locale of the data.
+     * @param nsName The name of the numbering system, like "latn".
+     * @param choice the pattern format.
+     * @return the pattern
+     * @internal
+     * @deprecated This API is ICU internal only.
+     */
+    @Deprecated
+    public static String getPatternForStyleAndNumberingSystem(ULocale forLocale, String nsName, int choice) {
         /* for ISOCURRENCYSTYLE and PLURALCURRENCYSTYLE,
          * the pattern is the same as the pattern of CURRENCYSTYLE
          * but by replacing the single currency sign with
@@ -1529,10 +1545,9 @@ public abstract class NumberFormat extends UFormat {
 
         ICUResourceBundle rb = (ICUResourceBundle)UResourceBundle.
         getBundleInstance(ICUData.ICU_BASE_NAME, forLocale);
-        NumberingSystem ns = NumberingSystem.getInstance(forLocale);
 
         String result = rb.findStringWithFallback(
-                    "NumberElements/" + ns.getName() + "/patterns/" + patternKey);
+                    "NumberElements/" + nsName + "/patterns/" + patternKey);
         if (result == null) {
             result = rb.getStringWithFallback("NumberElements/latn/patterns/" + patternKey);
         }
diff --git a/icu4j/main/classes/core/src/newapi/Notation.java b/icu4j/main/classes/core/src/newapi/Notation.java
deleted file mode 100644 (file)
index 0487baa..0000000
+++ /dev/null
@@ -1,40 +0,0 @@
-// © 2017 and later: Unicode, Inc. and others.
-// License & terms of use: http://www.unicode.org/copyright.html#License
-package newapi;
-
-import com.ibm.icu.text.CompactDecimalFormat.CompactStyle;
-
-import newapi.NumberFormatter.SignDisplay;
-
-public class Notation {
-
-    // FIXME: 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 CompactNotation COMPACT_SHORT = new CompactNotation(CompactStyle.SHORT);
-    private static final CompactNotation COMPACT_LONG = new CompactNotation(CompactStyle.LONG);
-    private static final SimpleNotation SIMPLE = new SimpleNotation();
-
-    /* package-private */ Notation() {
-    }
-
-    public static ScientificNotation scientific() {
-        return SCIENTIFIC;
-    }
-
-    public static ScientificNotation engineering() {
-        return ENGINEERING;
-    }
-
-    public static CompactNotation compactShort() {
-        return COMPACT_SHORT;
-    }
-
-    public static CompactNotation compactLong() {
-        return COMPACT_LONG;
-    }
-
-    public static SimpleNotation simple() {
-        return SIMPLE;
-    }
-}
\ No newline at end of file
diff --git a/icu4j/main/classes/core/src/newapi/NumberFormatter.java b/icu4j/main/classes/core/src/newapi/NumberFormatter.java
deleted file mode 100644 (file)
index dfa3f97..0000000
+++ /dev/null
@@ -1,62 +0,0 @@
-// © 2017 and later: Unicode, Inc. and others.
-// License & terms of use: http://www.unicode.org/copyright.html#License
-package newapi;
-
-import java.util.Locale;
-
-import com.ibm.icu.impl.number.DecimalFormatProperties;
-import com.ibm.icu.text.DecimalFormatSymbols;
-import com.ibm.icu.util.ULocale;
-
-import newapi.impl.MacroProps;
-
-public final class NumberFormatter {
-
-    private static final UnlocalizedNumberFormatter BASE = new UnlocalizedNumberFormatter();
-
-    public static enum UnitWidth {
-        NARROW, // ¤¤¤¤¤ or narrow measure unit
-        SHORT, // ¤ or short measure unit (DEFAULT)
-        ISO_CODE, // ¤¤; undefined for measure unit
-        FULL_NAME, // ¤¤¤ or wide unit
-        HIDDEN, // no unit is displayed, but other unit effects are obeyed (like currency rounding)
-        // TODO: For hidden, what to do if currency symbol appears in the middle, as in Portugal ?
-    }
-
-    public static enum DecimalMarkDisplay {
-        AUTO, ALWAYS,
-    }
-
-    public static enum SignDisplay {
-        AUTO, ALWAYS, NEVER, ACCOUNTING, ACCOUNTING_ALWAYS,
-    }
-
-    /**
-     * 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;
-
-    public static UnlocalizedNumberFormatter with() {
-        return BASE;
-    }
-
-    public static LocalizedNumberFormatter withLocale(Locale locale) {
-        return BASE.locale(locale);
-    }
-
-    public static LocalizedNumberFormatter withLocale(ULocale locale) {
-        return BASE.locale(locale);
-    }
-
-    /**
-     * @internal
-     * @deprecated ICU 60 This API is ICU internal only.
-     */
-    @Deprecated
-    public static UnlocalizedNumberFormatter fromDecimalFormat(DecimalFormatProperties properties,
-            DecimalFormatSymbols symbols, DecimalFormatProperties exportedProperties) {
-        MacroProps macros = NumberPropertyMapper.oldToNew(properties, symbols, exportedProperties);
-        return NumberFormatter.with().macros(macros);
-    }
-}
diff --git a/icu4j/main/classes/core/src/newapi/SkeletonBuilder.java b/icu4j/main/classes/core/src/newapi/SkeletonBuilder.java
deleted file mode 100644 (file)
index b44385b..0000000
+++ /dev/null
@@ -1,586 +0,0 @@
-// © 2017 and later: Unicode, Inc. and others.
-// License & terms of use: http://www.unicode.org/copyright.html#License
-package newapi;
-
-import java.math.BigDecimal;
-import java.math.MathContext;
-import java.math.RoundingMode;
-
-import com.ibm.icu.text.CompactDecimalFormat.CompactStyle;
-import com.ibm.icu.text.DecimalFormatSymbols;
-import com.ibm.icu.text.NumberingSystem;
-import com.ibm.icu.util.Currency;
-import com.ibm.icu.util.Currency.CurrencyUsage;
-import com.ibm.icu.util.MeasureUnit;
-import com.ibm.icu.util.NoUnit;
-
-import newapi.NumberFormatter.DecimalMarkDisplay;
-import newapi.NumberFormatter.SignDisplay;
-import newapi.NumberFormatter.UnitWidth;
-import newapi.Rounder.CurrencyRounderImpl;
-import newapi.Rounder.FracSigRounderImpl;
-import newapi.Rounder.FractionRounderImpl;
-import newapi.Rounder.IncrementRounderImpl;
-import newapi.Rounder.InfiniteRounderImpl;
-import newapi.Rounder.SignificantRounderImpl;
-import newapi.impl.MacroProps;
-
-final class SkeletonBuilder {
-
-    public static String macrosToSkeleton(MacroProps macros) {
-        // Print out the values in their canonical order.
-        StringBuilder sb = new StringBuilder();
-        if (macros.notation != null) {
-            // sb.append("notation=");
-            notationToSkeleton(macros.notation, sb);
-            sb.append(' ');
-        }
-        if (macros.unit != null) {
-            // sb.append("unit=");
-            unitToSkeleton(macros.unit, sb);
-            sb.append(' ');
-        }
-        if (macros.rounder != null) {
-            // sb.append("rounding=");
-            rounderToSkeleton(macros.rounder, sb);
-            sb.append(' ');
-        }
-        if (macros.grouper != null) {
-            sb.append("grouping=");
-            grouperToSkeleton(macros.grouper, sb);
-            sb.append(' ');
-        }
-//        if (macros.padder != null) {
-//            sb.append("padding=");
-//            paddingToSkeleton(macros.padder, sb);
-//            sb.append(' ');
-//        }
-        if (macros.integerWidth != null) {
-            sb.append("integer-width=");
-            integerWidthToSkeleton(macros.integerWidth, sb);
-            sb.append(' ');
-        }
-        if (macros.symbols != null) {
-            sb.append("symbols=");
-            symbolsToSkeleton(macros.symbols, sb);
-            sb.append(' ');
-        }
-        if (macros.unitWidth != null) {
-            sb.append("unit-width=");
-            unitWidthToSkeleton(macros.unitWidth, sb);
-            sb.append(' ');
-        }
-        if (macros.sign != null) {
-            sb.append("sign=");
-            signToSkeleton(macros.sign, sb);
-            sb.append(' ');
-        }
-        if (macros.decimal != null) {
-            sb.append("decimal=");
-            decimalToSkeleton(macros.decimal, sb);
-            sb.append(' ');
-        }
-        if (sb.length() > 0) {
-            // Remove the trailing space
-            sb.setLength(sb.length() - 1);
-        }
-        return sb.toString();
-    }
-
-    public static MacroProps skeletonToMacros(String skeleton) {
-        MacroProps macros = new MacroProps();
-        for (int offset = 0; offset < skeleton.length();) {
-            char c = skeleton.charAt(offset);
-            switch (c) {
-            case ' ':
-                offset++;
-                break;
-            case 'E':
-            case 'C':
-            case 'I':
-                offset += skeletonToNotation(skeleton, offset, macros);
-                break;
-            case '%':
-            case 'B':
-            case '$':
-            case 'U':
-                offset += skeletonToUnit(skeleton, offset, macros);
-                break;
-            case 'F':
-            case 'S':
-            case 'M':
-            case 'G':
-            case 'Y':
-                offset += skeletonToRounding(skeleton, offset, macros);
-                break;
-            default:
-                if (skeleton.regionMatches(offset, "notation=", 0, 9)) {
-                    offset += 9;
-                    offset += skeletonToNotation(skeleton, offset, macros);
-                } else if (skeleton.regionMatches(offset, "unit=", 0, 5)) {
-                    offset += 5;
-                    offset += skeletonToUnit(skeleton, offset, macros);
-                } else if (skeleton.regionMatches(offset, "rounding=", 0, 9)) {
-                    offset += 9;
-                    offset += skeletonToRounding(skeleton, offset, macros);
-                } else if (skeleton.regionMatches(offset, "grouping=", 0, 9)) {
-                    offset += 9;
-                    offset += skeletonToGrouping(skeleton, offset, macros);
-//                } else if (skeleton.regionMatches(offset, "padding=", 0, 9)) {
-//                    offset += 8;
-//                    offset += skeletonToPadding(skeleton, offset, macros);
-                } else if (skeleton.regionMatches(offset, "integer-width=", 0, 9)) {
-                    offset += 14;
-                    offset += skeletonToIntegerWidth(skeleton, offset, macros);
-                } else if (skeleton.regionMatches(offset, "symbols=", 0, 9)) {
-                    offset += 8;
-                    offset += skeletonToSymbols(skeleton, offset, macros);
-                } else if (skeleton.regionMatches(offset, "unit-width=", 0, 9)) {
-                    offset += 11;
-                    offset += skeletonToUnitWidth(skeleton, offset, macros);
-                } else if (skeleton.regionMatches(offset, "sign=", 0, 9)) {
-                    offset += 5;
-                    offset += skeletonToSign(skeleton, offset, macros);
-                } else if (skeleton.regionMatches(offset, "decimal=", 0, 9)) {
-                    offset += 8;
-                    offset += skeletonToDecimal(skeleton, offset, macros);
-                } else {
-                    throw new IllegalArgumentException(
-                            "Unexpected token at offset " + offset + " in skeleton string: " + c);
-                }
-            }
-        }
-        return macros;
-    }
-
-    private static void notationToSkeleton(Notation value, StringBuilder sb) {
-        if (value instanceof ScientificNotation) {
-            ScientificNotation notation = (ScientificNotation) value;
-            sb.append('E');
-            if (notation.engineeringInterval != 1) {
-                sb.append(notation.engineeringInterval);
-            }
-            if (notation.exponentSignDisplay == SignDisplay.ALWAYS) {
-                sb.append('+');
-            } else if (notation.exponentSignDisplay == SignDisplay.NEVER) {
-                sb.append('!');
-            } else {
-                assert notation.exponentSignDisplay == SignDisplay.AUTO;
-            }
-            if (notation.minExponentDigits != 1) {
-                for (int i = 0; i < notation.minExponentDigits; i++) {
-                    sb.append('0');
-                }
-            }
-        } else if (value instanceof CompactNotation) {
-            CompactNotation notation = (CompactNotation) value;
-            if (notation.compactStyle == CompactStyle.SHORT) {
-                sb.append('C');
-            } else {
-                // FIXME: CCC or CCCC instead?
-                sb.append("CC");
-            }
-        } else {
-            assert value instanceof SimpleNotation;
-            sb.append('I');
-        }
-    }
-
-    private static int skeletonToNotation(String skeleton, int offset, MacroProps output) {
-        int originalOffset = offset;
-        char c0 = skeleton.charAt(offset++);
-        Notation result = null;
-        if (c0 == 'E') {
-            int engineering = 1;
-            SignDisplay sign = SignDisplay.AUTO;
-            int minExponentDigits = 0;
-            char c = safeCharAt(skeleton, offset++);
-            if (c >= '1' && c <= '9') {
-                engineering = c - '0';
-                c = safeCharAt(skeleton, offset++);
-            }
-            if (c == '+') {
-                sign = SignDisplay.ALWAYS;
-                c = safeCharAt(skeleton, offset++);
-            }
-            if (c == '!') {
-                sign = SignDisplay.NEVER;
-                c = safeCharAt(skeleton, offset++);
-            }
-            while (c == '0') {
-                minExponentDigits++;
-                c = safeCharAt(skeleton, offset++);
-            }
-            minExponentDigits = Math.max(1, minExponentDigits);
-            result = new ScientificNotation(engineering, false, minExponentDigits, sign);
-        } else if (c0 == 'C') {
-            char c = safeCharAt(skeleton, offset++);
-            if (c == 'C') {
-                result = Notation.compactLong();
-            } else {
-                result = Notation.compactShort();
-            }
-        } else if (c0 == 'I') {
-            result = Notation.simple();
-        }
-        output.notation = result;
-        return offset - originalOffset;
-    }
-
-    private static void unitToSkeleton(MeasureUnit value, StringBuilder sb) {
-        if (value.getType().equals("none")) {
-            if (value.getSubtype().equals("percent")) {
-                sb.append('%');
-            } else if (value.getSubtype().equals("permille")) {
-                sb.append("%%");
-            } else {
-                assert value.getSubtype().equals("base");
-                sb.append('B');
-            }
-        } else if (value.getType().equals("currency")) {
-            sb.append('$');
-            sb.append(value.getSubtype());
-        } else {
-            sb.append("U:");
-            sb.append(value.getType());
-            sb.append(':');
-            sb.append(value.getSubtype());
-        }
-    }
-
-    private static int skeletonToUnit(String skeleton, int offset, MacroProps output) {
-        int originalOffset = offset;
-        char c0 = skeleton.charAt(offset++);
-        MeasureUnit result = null;
-        if (c0 == '%') {
-            char c = safeCharAt(skeleton, offset++);
-            if (c == '%') {
-                result = NoUnit.PERCENT;
-            } else {
-                result = NoUnit.PERMILLE;
-            }
-        } else if (c0 == 'B') {
-            result = NoUnit.BASE;
-        } else if (c0 == '$') {
-            String currencyCode = skeleton.substring(offset, offset + 3);
-            offset += 3;
-            result = Currency.getInstance(currencyCode);
-        } else if (c0 == 'U') {
-            StringBuilder sb = new StringBuilder();
-            offset += consumeUntil(skeleton, offset, ':', sb);
-            String type = sb.toString();
-            sb.setLength(0);
-            offset += consumeUntil(skeleton, offset, ' ', sb);
-            String subtype = sb.toString();
-            for (MeasureUnit candidate : MeasureUnit.getAvailable(type)) {
-                if (candidate.getSubtype().equals(subtype)) {
-                    result = candidate;
-                    break;
-                }
-            }
-        }
-        output.unit = result;
-        return offset - originalOffset;
-    }
-
-    private static void rounderToSkeleton(Rounder value, StringBuilder sb) {
-        if (!(value instanceof Rounder)) {
-            // FIXME: Throw an exception here instead?
-            return;
-        }
-        MathContext mathContext;
-        if (value instanceof FractionRounderImpl) {
-            FractionRounderImpl rounder = (FractionRounderImpl) value;
-            sb.append('F');
-            minMaxToSkeletonHelper(rounder.minFrac, rounder.maxFrac, sb);
-            mathContext = rounder.mathContext;
-        } else if (value instanceof SignificantRounderImpl) {
-            SignificantRounderImpl rounder = (SignificantRounderImpl) value;
-            sb.append('S');
-            minMaxToSkeletonHelper(rounder.minSig, rounder.maxSig, sb);
-            mathContext = rounder.mathContext;
-        } else if (value instanceof FracSigRounderImpl) {
-            FracSigRounderImpl rounder = (FracSigRounderImpl) value;
-            sb.append('F');
-            minMaxToSkeletonHelper(rounder.minFrac, rounder.maxFrac, sb);
-            if (rounder.minSig != -1) {
-                sb.append('>');
-                sb.append(rounder.minSig);
-            } else {
-                sb.append('<');
-                sb.append(rounder.maxSig);
-            }
-            mathContext = rounder.mathContext;
-        } else if (value instanceof IncrementRounderImpl) {
-            IncrementRounderImpl rounder = (IncrementRounderImpl) value;
-            sb.append('M');
-            sb.append(rounder.increment.toString());
-            mathContext = rounder.mathContext;
-        } else if (value instanceof CurrencyRounderImpl) {
-            CurrencyRounderImpl rounder = (CurrencyRounderImpl) value;
-            sb.append('G');
-            sb.append(rounder.usage.name());
-            mathContext = rounder.mathContext;
-        } else {
-            InfiniteRounderImpl rounder = (InfiniteRounderImpl) value;
-            sb.append('Y');
-            mathContext = rounder.mathContext;
-        }
-        // RoundingMode
-        RoundingMode roundingMode = mathContext.getRoundingMode();
-        if (roundingMode != RoundingMode.HALF_EVEN) {
-            sb.append(';');
-            sb.append(roundingMode.name());
-        }
-    }
-
-    private static void minMaxToSkeletonHelper(int minFrac, int maxFrac, StringBuilder sb) {
-        if (minFrac == maxFrac) {
-            sb.append(minFrac);
-        } else {
-            boolean showMaxFrac = (maxFrac >= 0 && maxFrac < Integer.MAX_VALUE);
-            if (minFrac > 0 || !showMaxFrac) {
-                sb.append(minFrac);
-            }
-            sb.append('-');
-            if (showMaxFrac) {
-                sb.append(maxFrac);
-            }
-        }
-    }
-
-    private static int skeletonToRounding(String skeleton, int offset, MacroProps output) {
-        int originalOffset = offset;
-        char c0 = skeleton.charAt(offset++);
-        Rounder result = null;
-        if (c0 == 'F') {
-            int[] minMax = new int[2];
-            offset += skeletonToMinMaxHelper(skeleton, offset, minMax);
-            FractionRounder temp = Rounder.constructFraction(minMax[0], minMax[1]);
-            char c1 = skeleton.charAt(offset++);
-            if (c1 == '<') {
-                char c2 = skeleton.charAt(offset++);
-                result = temp.withMaxDigits(c2 - '0');
-            } else if (c1 == '>') {
-                char c2 = skeleton.charAt(offset++);
-                result = temp.withMinDigits(c2 - '0');
-            } else {
-                result = temp;
-            }
-        } else if (c0 == 'S') {
-            int[] minMax = new int[2];
-            offset += skeletonToMinMaxHelper(skeleton, offset, minMax);
-            result = Rounder.constructSignificant(minMax[0], minMax[1]);
-        } else if (c0 == 'M') {
-            StringBuilder sb = new StringBuilder();
-            offset += consumeUntil(skeleton, offset, ' ', sb);
-            BigDecimal increment = new BigDecimal(sb.toString());
-            result = Rounder.constructIncrement(increment);
-        } else if (c0 == 'G') {
-            StringBuilder sb = new StringBuilder();
-            offset += consumeUntil(skeleton, offset, ' ', sb);
-            CurrencyUsage usage = Enum.valueOf(CurrencyUsage.class, sb.toString());
-            result = Rounder.constructCurrency(usage);
-        } else if (c0 == 'Y') {
-            result = Rounder.constructInfinite();
-        }
-        output.rounder = result;
-        return offset - originalOffset;
-    }
-
-    private static int skeletonToMinMaxHelper(String skeleton, int offset, int[] output) {
-        int originalOffset = offset;
-        char c0 = safeCharAt(skeleton, offset++);
-        char c1 = safeCharAt(skeleton, offset++);
-        // TODO: This algorithm breaks if the number is more than 1 char wide.
-        if (c1 == '-') {
-            output[0] = c0 - '0';
-            char c2 = safeCharAt(skeleton, offset++);
-            if (c2 == ' ') {
-                output[1] = Integer.MAX_VALUE;
-            } else {
-                output[1] = c2 - '0';
-            }
-        } else if ('0' <= c1 && c1 <= '9') {
-            output[0] = 0;
-            output[1] = c1 - '0';
-        } else {
-            offset--;
-            output[0] = c0 - '0';
-            output[1] = c0 - '0';
-        }
-        return offset - originalOffset;
-    }
-
-    private static void grouperToSkeleton(Grouper value, StringBuilder sb) {
-        if (value.equals(Grouper.defaults())) {
-            sb.append("defaults");
-        } else if (value.equals(Grouper.min2())) {
-            sb.append("min2");
-        } else if (value.equals(Grouper.none())) {
-            sb.append("none");
-        } else {
-            // Not supported in skeleton string
-            sb.append("defaults");
-        }
-    }
-
-    private static int skeletonToGrouping(String skeleton, int offset, MacroProps output) {
-        int originalOffset = offset;
-        char c0 = skeleton.charAt(offset++);
-        Grouper result = null;
-        StringBuilder sb = new StringBuilder();
-        offset += consumeUntil(skeleton, --offset, ' ', sb);
-        String name = sb.toString();
-        if (name.equals("defaults")) {
-            result = Grouper.defaults();
-        } else if (name.equals("min2")) {
-            result = Grouper.min2();
-        } else if (name.equals("none")) {
-            result = Grouper.none();
-        }
-        output.grouper = result;
-        return offset - originalOffset;
-    }
-
-//    private static void paddingToSkeleton(Padder value, StringBuilder sb) {
-//        PaddingImpl padding = (PaddingImpl) value;
-//        if (padding == Padder.NONE) {
-//            sb.append("NONE");
-//            return;
-//        }
-//        sb.append(padding.targetWidth);
-//        sb.append(':');
-//        sb.append(padding.position.name());
-//        sb.append(':');
-//        if (!padding.paddingString.equals(" ")) {
-//            sb.append(padding.paddingString);
-//        }
-//    }
-//
-//    private static int skeletonToPadding(String skeleton, int offset, MacroProps output) {
-//        int originalOffset = offset;
-//        char c0 = skeleton.charAt(offset++);
-//        if (c0 == 'N') {
-//            offset += consumeUntil(skeleton, --offset, ' ', null);
-//        } else if ('0' <= c0 && c0 <= '9') {
-//            long intResult = consumeInt(skeleton, --offset);
-//            offset += intResult & 0xffffffff;
-//            int width = (int) (intResult >>> 32);
-//            char c1 = safeCharAt(skeleton, offset++);
-//            if (c1 != ':') {
-//                return offset - originalOffset - 1;
-//            }
-//            StringBuilder sb = new StringBuilder();
-//            offset += consumeUntil(skeleton, offset, ':', sb);
-//            String padPositionString = sb.toString();
-//            sb.setLength(0);
-//            offset += consumeUntil(skeleton, offset, ' ', sb);
-//            String string = (sb.length() == 0) ? " " : sb.toString();
-//            PadPosition position = Enum.valueOf(PadPosition.class, padPositionString);
-//            output.padder = PaddingImpl.getInstance(string, width, position);
-//        }
-//        return offset - originalOffset;
-//    }
-
-    private static void integerWidthToSkeleton(IntegerWidth value, StringBuilder sb) {
-        sb.append(value.minInt);
-        if (value.maxInt != value.minInt) {
-            sb.append('-');
-            if (value.maxInt != -1) {
-                sb.append(value.maxInt);
-            }
-        }
-    }
-
-    private static int skeletonToIntegerWidth(String skeleton, int offset, MacroProps output) {
-        int originalOffset = offset;
-        long intResult = consumeInt(skeleton, offset);
-        offset += intResult & 0xffffffff;
-        int minInt = (int) (intResult >>> 32);
-        char c1 = safeCharAt(skeleton, --offset);
-        int maxInt;
-        if (c1 == '-') {
-            intResult = consumeInt(skeleton, offset);
-            offset += intResult & 0xffffffff;
-            maxInt = (int) (intResult >>> 32);
-        }
-    }
-
-    private static void symbolsToSkeleton(Object value, StringBuilder sb) {
-        if (value instanceof DecimalFormatSymbols) {
-            // TODO: Check to see if any of the symbols are not default?
-            sb.append("loc:");
-            sb.append(((DecimalFormatSymbols) value).getULocale());
-        } else {
-            sb.append("ns:");
-            sb.append(((NumberingSystem) value).getName());
-        }
-    }
-
-    private static void unitWidthToSkeleton(UnitWidth value, StringBuilder sb) {
-        sb.append(value.name());
-    }
-
-    private static int skeletonToUnitWidth(String skeleton, int offset, MacroProps output) {
-        int originalOffset = offset;
-        StringBuilder sb = new StringBuilder();
-        offset += consumeUntil(skeleton, offset, ' ', sb);
-        output.unitWidth = Enum.valueOf(UnitWidth.class, sb.toString());
-        return offset - originalOffset;
-    }
-
-    private static void signToSkeleton(SignDisplay value, StringBuilder sb) {
-        sb.append(value.name());
-    }
-
-    private static int skeletonToSign(String skeleton, int offset, MacroProps output) {
-        int originalOffset = offset;
-        StringBuilder sb = new StringBuilder();
-        offset += consumeUntil(skeleton, offset, ' ', sb);
-        output.sign = Enum.valueOf(SignDisplay.class, sb.toString());
-        return offset - originalOffset;
-    }
-
-    private static void decimalToSkeleton(DecimalMarkDisplay value, StringBuilder sb) {
-        sb.append(value.name());
-    }
-
-    private static int skeletonToDecimal(String skeleton, int offset, MacroProps output) {
-        int originalOffset = offset;
-        StringBuilder sb = new StringBuilder();
-        offset += consumeUntil(skeleton, offset, ' ', sb);
-        output.decimal = Enum.valueOf(DecimalMarkDisplay.class, sb.toString());
-        return offset - originalOffset;
-    }
-
-    private static char safeCharAt(String str, int offset) {
-        if (offset < str.length()) {
-            return str.charAt(offset);
-        } else {
-            return ' ';
-        }
-    }
-
-    private static int consumeUntil(String skeleton, int offset, char brk, StringBuilder sb) {
-        int originalOffset = offset;
-        char c = safeCharAt(skeleton, offset++);
-        while (c != brk) {
-            if (sb != null)
-                sb.append(c);
-            c = safeCharAt(skeleton, offset++);
-        }
-        return offset - originalOffset;
-    }
-
-    private static long consumeInt(String skeleton, int offset) {
-        int originalOffset = offset;
-        char c = safeCharAt(skeleton, offset++);
-        int result = 0;
-        while ('0' <= c && c <= '9') {
-            result = (result * 10) + (c - '0');
-            c = safeCharAt(skeleton, offset++);
-        }
-        return (offset - originalOffset) | (((long) result) << 32);
-    }
-}
diff --git a/icu4j/main/classes/core/src/newapi/impl/demo.java b/icu4j/main/classes/core/src/newapi/impl/demo.java
deleted file mode 100644 (file)
index 8deaa78..0000000
+++ /dev/null
@@ -1,64 +0,0 @@
-// © 2017 and later: Unicode, Inc. and others.
-// License & terms of use: http://www.unicode.org/copyright.html#License
-package newapi.impl;
-
-import java.math.RoundingMode;
-
-import com.ibm.icu.text.DecimalFormatSymbols;
-import com.ibm.icu.text.NumberingSystem;
-import com.ibm.icu.util.Currency;
-import com.ibm.icu.util.Currency.CurrencyUsage;
-import com.ibm.icu.util.MeasureUnit;
-import com.ibm.icu.util.NoUnit;
-import com.ibm.icu.util.ULocale;
-
-import newapi.Grouper;
-import newapi.Notation;
-import newapi.NumberFormatter;
-import newapi.NumberFormatter.DecimalMarkDisplay;
-import newapi.NumberFormatter.SignDisplay;
-import newapi.NumberFormatter.UnitWidth;
-import newapi.Rounder;
-import newapi.UnlocalizedNumberFormatter;
-
-public class demo {
-  public static void main(String[] args) {
-    System.out.println(NumberingSystem.LATIN.getDescription());
-    UnlocalizedNumberFormatter formatter =
-        NumberFormatter.with()
-            .notation(Notation.compactShort())
-            .notation(Notation.scientific().withExponentSignDisplay(SignDisplay.ALWAYS))
-            .notation(Notation.engineering().withMinExponentDigits(2))
-            .notation(Notation.simple())
-            .unit(Currency.getInstance("GBP"))
-            .unit(NoUnit.PERCENT)
-            .unit(MeasureUnit.CUBIC_METER)
-            .unitWidth(UnitWidth.SHORT)
-            // .rounding(Rounding.fixedSignificantDigits(3))
-//            .rounding(
-//                (BigDecimal input) -> {
-//                  return input.divide(new BigDecimal("0.02"), 0).multiply(new BigDecimal("0.02"));
-//                })
-            .rounding(Rounder.fixedFraction(2).withMode(RoundingMode.HALF_UP))
-            .rounding(Rounder.integer().withMode(RoundingMode.CEILING))
-            .rounding(Rounder.currency(CurrencyUsage.STANDARD))
-//            .grouping(
-//                (int position, BigDecimal number) -> {
-//                  return (position % 3) == 0;
-//                })
-            .grouping(Grouper.defaults())
-            .grouping(Grouper.none())
-            .grouping(Grouper.min2())
-            // .padding(Padding.codePoints(' ', 8, PadPosition.AFTER_PREFIX))
-            .sign(SignDisplay.ALWAYS)
-            .decimal(DecimalMarkDisplay.ALWAYS)
-            .symbols(DecimalFormatSymbols.getInstance(new ULocale("fr@digits=ascii")))
-            .symbols(NumberingSystem.getInstanceByName("arab"))
-            .symbols(NumberingSystem.LATIN);
-    System.out.println(formatter.toSkeleton());
-    System.out.println(formatter.locale(ULocale.ENGLISH).format(0.98381).toString());
-    //            .locale(Locale.ENGLISH)
-    //            .format(123.45)
-    //            .toString();
-  }
-}
index 31955450cf625b93b1b48c92d006c14d0ee128c1..404fe0ddedbbcb7cc857e8b515942bbe70001aea 100644 (file)
@@ -195,25 +195,6 @@ pattern    format  output  breaks
 #E0    52413   5,2413E4        K
 0E0    52413   5E4
 
-test scientific with grouping
-set locale en
-set pattern #,##0.000E0
-begin
-format output  breaks
-// J throws an IllegalArgumentException when parsing the pattern.
-// C sets error code to U_MALFORMED_EXPONENTIAL_PATTERN.
-1      1.000E0 CJ
-11     11.00E0 CJ
-111    111.0E0 CJ
-// K doesn't print the grouping separator ("1111E0")
-1111   1,111E0 CJK
-// K prints too many digits ("1.1111E4")
-11111  1.111E4 CJK
-111111 11.11E4 CJK
-1111111        111.1E4 CJK
-11111111       1,111E4 CJK
-111111111      1.111E8 CJK
-
 test percents
 set locale fr
 begin
index 4b7ea8b21d28ca8ff5a8fb8d140e661433df1a9e..0015673974ffb5173f736ab7eba95dae1aded462 100644 (file)
@@ -10,18 +10,17 @@ import org.junit.Test;
 
 import com.ibm.icu.dev.test.TestUtil;
 import com.ibm.icu.impl.number.DecimalFormatProperties;
+import com.ibm.icu.impl.number.Padder.PadPosition;
 import com.ibm.icu.impl.number.Parse.ParseMode;
 import com.ibm.icu.impl.number.PatternStringParser;
 import com.ibm.icu.impl.number.PatternStringUtils;
+import com.ibm.icu.number.LocalizedNumberFormatter;
+import com.ibm.icu.number.NumberFormatter;
 import com.ibm.icu.text.DecimalFormatSymbols;
 import com.ibm.icu.text.DecimalFormat_ICU58;
 import com.ibm.icu.util.CurrencyAmount;
 import com.ibm.icu.util.ULocale;
 
-import newapi.LocalizedNumberFormatter;
-import newapi.NumberFormatter;
-import newapi.impl.Padder.PadPosition;
-
 public class NumberFormatDataDrivenTest {
 
   private static ULocale EN = new ULocale("en");
index ff800d3b3165d825abb8922ee8ea118acdb7d2b0..145ff9e896a2eacba964d445ae6355e2ed618550 100644 (file)
@@ -2750,7 +2750,9 @@ public class NumberFormatTest extends TestFmwk {
 
     @Test
     public void TestScientificWithGrouping() {
-        DecimalFormat df = new DecimalFormat("#,##0.000E0");
+        // Grouping separators are not allowed in the pattern, but we can enable them via the API.
+        DecimalFormat df = new DecimalFormat("###0.000E0");
+        df.setGroupingUsed(true);
         expect2(df, 123, "123.0E0");
         expect2(df, 1234, "1,234E0");
         expect2(df, 12340, "1.234E4");
index b2485ed8a1c27376d4c37790f2e76b55599cf80b..7bda67cc99832a0b288791898a857374bf4759e7 100644 (file)
@@ -20,13 +20,12 @@ import com.ibm.icu.impl.number.DecimalQuantity_64BitBCD;
 import com.ibm.icu.impl.number.DecimalQuantity_ByteArrayBCD;
 import com.ibm.icu.impl.number.DecimalQuantity_DualStorageBCD;
 import com.ibm.icu.impl.number.DecimalQuantity_SimpleStorage;
+import com.ibm.icu.number.LocalizedNumberFormatter;
+import com.ibm.icu.number.NumberFormatter;
 import com.ibm.icu.text.CompactDecimalFormat.CompactStyle;
 import com.ibm.icu.text.DecimalFormatSymbols;
 import com.ibm.icu.util.ULocale;
 
-import newapi.LocalizedNumberFormatter;
-import newapi.NumberFormatter;
-
 /** TODO: This is a temporary name for this class. Suggestions for a better name? */
 public class DecimalQuantityTest extends TestFmwk {
 
index 205660f27c79622da4ee11c4557e601a53254610..6af4ea1c4a044601947da622e665e94fed46a496 100644 (file)
@@ -8,12 +8,12 @@ import static org.junit.Assert.assertTrue;
 import org.junit.Test;
 
 import com.ibm.icu.impl.SimpleFormatterImpl;
+import com.ibm.icu.impl.number.ConstantAffixModifier;
+import com.ibm.icu.impl.number.ConstantMultiFieldModifier;
+import com.ibm.icu.impl.number.CurrencySpacingEnabledModifier;
 import com.ibm.icu.impl.number.Modifier;
 import com.ibm.icu.impl.number.NumberStringBuilder;
-import com.ibm.icu.impl.number.modifiers.ConstantAffixModifier;
-import com.ibm.icu.impl.number.modifiers.ConstantMultiFieldModifier;
-import com.ibm.icu.impl.number.modifiers.CurrencySpacingEnabledModifier;
-import com.ibm.icu.impl.number.modifiers.SimpleModifier;
+import com.ibm.icu.impl.number.SimpleModifier;
 import com.ibm.icu.text.DecimalFormatSymbols;
 import com.ibm.icu.text.NumberFormat;
 import com.ibm.icu.util.ULocale;
index 115d8229dab71cb1c9d8047bf8605addb1fd31a8..80f44ada5d4bb5fb8d21bff624e62a86804478f5 100644 (file)
@@ -10,17 +10,16 @@ import org.junit.Test;
 
 import com.ibm.icu.impl.number.DecimalQuantity;
 import com.ibm.icu.impl.number.DecimalQuantity_DualStorageBCD;
+import com.ibm.icu.impl.number.MicroProps;
+import com.ibm.icu.impl.number.MutablePatternModifier;
 import com.ibm.icu.impl.number.NumberStringBuilder;
 import com.ibm.icu.impl.number.PatternStringParser;
+import com.ibm.icu.number.NumberFormatter.SignDisplay;
+import com.ibm.icu.number.NumberFormatter.UnitWidth;
 import com.ibm.icu.text.DecimalFormatSymbols;
 import com.ibm.icu.util.Currency;
 import com.ibm.icu.util.ULocale;
 
-import newapi.NumberFormatter.SignDisplay;
-import newapi.NumberFormatter.UnitWidth;
-import newapi.impl.MicroProps;
-import newapi.impl.MutablePatternModifier;
-
 public class MutablePatternModifierTest {
 
     @Test
index 8a6d196be4c6fd29cb8025652d73dcbe3183be5f..466399ff1a14a5a9e9af075a7a7226e4867fb0a7 100644 (file)
@@ -6,12 +6,26 @@ import static org.junit.Assert.assertEquals;
 import static org.junit.Assert.assertNotEquals;
 
 import java.math.BigDecimal;
+import java.math.RoundingMode;
 import java.util.Locale;
 
 import org.junit.Ignore;
 import org.junit.Test;
 
+import com.ibm.icu.impl.number.Padder;
+import com.ibm.icu.impl.number.Padder.PadPosition;
 import com.ibm.icu.impl.number.PatternStringParser;
+import com.ibm.icu.number.FormattedNumber;
+import com.ibm.icu.number.Grouper;
+import com.ibm.icu.number.IntegerWidth;
+import com.ibm.icu.number.LocalizedNumberFormatter;
+import com.ibm.icu.number.Notation;
+import com.ibm.icu.number.NumberFormatter;
+import com.ibm.icu.number.NumberFormatter.DecimalSeparatorDisplay;
+import com.ibm.icu.number.NumberFormatter.SignDisplay;
+import com.ibm.icu.number.NumberFormatter.UnitWidth;
+import com.ibm.icu.number.Rounder;
+import com.ibm.icu.number.UnlocalizedNumberFormatter;
 import com.ibm.icu.text.DecimalFormatSymbols;
 import com.ibm.icu.text.NumberingSystem;
 import com.ibm.icu.util.Currency;
@@ -22,25 +36,12 @@ import com.ibm.icu.util.MeasureUnit;
 import com.ibm.icu.util.NoUnit;
 import com.ibm.icu.util.ULocale;
 
-import newapi.FormattedNumber;
-import newapi.Grouper;
-import newapi.IntegerWidth;
-import newapi.LocalizedNumberFormatter;
-import newapi.Notation;
-import newapi.NumberFormatter;
-import newapi.NumberFormatter.DecimalMarkDisplay;
-import newapi.NumberFormatter.SignDisplay;
-import newapi.NumberFormatter.UnitWidth;
-import newapi.Rounder;
-import newapi.UnlocalizedNumberFormatter;
-import newapi.impl.Padder;
-import newapi.impl.Padder.PadPosition;
-
 public class NumberFormatterTest {
 
     private static final Currency USD = Currency.getInstance("USD");
     private static final Currency GBP = Currency.getInstance("GBP");
     private static final Currency CZK = Currency.getInstance("CZK");
+    private static final Currency CAD = Currency.getInstance("CAD");
 
     @Test
     public void notationSimple() {
@@ -59,6 +60,21 @@ public class NumberFormatterTest {
                 "0.008765",
                 "0");
 
+        assertFormatDescendingBig(
+                "Big Simple",
+                "",
+                NumberFormatter.with().notation(Notation.simple()),
+                ULocale.ENGLISH,
+                "87,650,000",
+                "8,765,000",
+                "876,500",
+                "87,650",
+                "8,765",
+                "876.5",
+                "87.65",
+                "8.765",
+                "0");
+
         assertFormatSingle(
                 "Basic with Negative Sign",
                 "",
@@ -141,34 +157,34 @@ public class NumberFormatterTest {
 
     @Test
     public void notationCompact() {
-        assertFormatDescending(
+        assertFormatDescendingBig(
                 "Compact Short",
                 "C",
                 NumberFormatter.with().notation(Notation.compactShort()),
                 ULocale.ENGLISH,
+                "88M",
+                "8.8M",
+                "876K",
                 "88K",
                 "8.8K",
                 "876",
                 "88",
                 "8.8",
-                "0.88",
-                "0.088",
-                "0.0088",
                 "0");
 
-        assertFormatDescending(
+        assertFormatDescendingBig(
                 "Compact Long",
                 "CC",
                 NumberFormatter.with().notation(Notation.compactLong()),
                 ULocale.ENGLISH,
+                "88 million",
+                "8.8 million",
+                "876 thousand",
                 "88 thousand",
                 "8.8 thousand",
                 "876",
                 "88",
                 "8.8",
-                "0.88",
-                "0.088",
-                "0.0088",
                 "0");
 
         assertFormatDescending(
@@ -189,10 +205,7 @@ public class NumberFormatterTest {
         assertFormatDescending(
                 "Compact Short with ISO Currency",
                 "C $USD unit-width=ISO_CODE",
-                NumberFormatter.with()
-                    .notation(Notation.compactShort())
-                    .unit(USD)
-                    .unitWidth(UnitWidth.ISO_CODE),
+                NumberFormatter.with().notation(Notation.compactShort()).unit(USD).unitWidth(UnitWidth.ISO_CODE),
                 ULocale.ENGLISH,
                 "USD 88K",
                 "USD 8.8K",
@@ -207,10 +220,7 @@ public class NumberFormatterTest {
         assertFormatDescending(
                 "Compact Short with Long Name Currency",
                 "C $USD unit-width=FULL_NAME",
-                NumberFormatter.with()
-                    .notation(Notation.compactShort())
-                    .unit(USD)
-                    .unitWidth(UnitWidth.FULL_NAME),
+                NumberFormatter.with().notation(Notation.compactShort()).unit(USD).unitWidth(UnitWidth.FULL_NAME),
                 ULocale.ENGLISH,
                 "88K US dollars",
                 "8.8K US dollars",
@@ -244,10 +254,7 @@ public class NumberFormatterTest {
         assertFormatDescending(
                 "Compact Long with ISO Currency",
                 "CC $USD unit-width=ISO_CODE",
-                NumberFormatter.with()
-                    .notation(Notation.compactLong())
-                    .unit(USD)
-                    .unitWidth(UnitWidth.ISO_CODE),
+                NumberFormatter.with().notation(Notation.compactLong()).unit(USD).unitWidth(UnitWidth.ISO_CODE),
                 ULocale.ENGLISH,
                 "USD 88K", // should be something like "USD 88 thousand"
                 "USD 8.8K",
@@ -263,10 +270,7 @@ public class NumberFormatterTest {
         assertFormatDescending(
                 "Compact Long with Long Name Currency",
                 "CC $USD unit-width=FULL_NAME",
-                NumberFormatter.with()
-                    .notation(Notation.compactLong())
-                    .unit(USD)
-                    .unitWidth(UnitWidth.FULL_NAME),
+                NumberFormatter.with().notation(Notation.compactLong()).unit(USD).unitWidth(UnitWidth.FULL_NAME),
                 ULocale.ENGLISH,
                 "88 thousand US dollars",
                 "8.8 thousand US dollars",
@@ -442,6 +446,24 @@ public class NumberFormatterTest {
                 ULocale.forLanguageTag("en-GB"),
                 5.43,
                 "5.43 m²");
+
+        // es_US has "{0}°" for unitsNarrow/temperature/FAHRENHEIT.
+        // NOTE: This example is in the documentation.
+        assertFormatSingle(
+                "MeasureUnit Difference between Narrow and Short (Narrow Version)",
+                "",
+                NumberFormatter.with().unit(MeasureUnit.FAHRENHEIT).unitWidth(UnitWidth.NARROW),
+                ULocale.forLanguageTag("es-US"),
+                5.43,
+                "5.43°");
+
+        assertFormatSingle(
+                "MeasureUnit Difference between Narrow and Short (Short Version)",
+                "",
+                NumberFormatter.with().unit(MeasureUnit.FAHRENHEIT).unitWidth(UnitWidth.SHORT),
+                ULocale.forLanguageTag("es-US"),
+                5.43,
+                "5.43 °F");
     }
 
     @Test
@@ -491,6 +513,21 @@ public class NumberFormatterTest {
                 "0.01 British pounds",
                 "0.00 British pounds");
 
+        assertFormatDescending(
+                "Currency Hidden",
+                "$GBP unit-width=HIDDEN",
+                NumberFormatter.with().unit(GBP).unitWidth(UnitWidth.HIDDEN),
+                ULocale.ENGLISH,
+                "87,650.00",
+                "8,765.00",
+                "876.50",
+                "87.65",
+                "8.76",
+                "0.88",
+                "0.09",
+                "0.01",
+                "0.00");
+
         assertFormatSingleMeasure(
                 "Currency with CurrencyAmount Input",
                 "",
@@ -517,6 +554,25 @@ public class NumberFormatterTest {
                 ULocale.ENGLISH,
                 -9876543.21,
                 "-£9,876,543.21");
+
+        // The full currency symbol is not shown in NARROW format.
+        // NOTE: This example is in the documentation.
+        // FIXME: Narrow Currency does not currently work; see #11666
+        assertFormatSingle(
+                "Currency Difference between Narrow and Short (Narrow Version)",
+                "",
+                NumberFormatter.with().unit(USD).unitWidth(UnitWidth.NARROW),
+                ULocale.forLanguageTag("en-CA"),
+                5.43,
+                "US$5.43");
+
+        assertFormatSingle(
+                "Currency Difference between Narrow and Short (Short Version)",
+                "",
+                NumberFormatter.with().unit(USD).unitWidth(UnitWidth.SHORT),
+                ULocale.forLanguageTag("en_CA"),
+                5.43,
+                "US$ 5.43");
     }
 
     @Test
@@ -526,14 +582,14 @@ public class NumberFormatterTest {
                 "%",
                 NumberFormatter.with().unit(NoUnit.PERCENT),
                 ULocale.ENGLISH,
-                "8,765,000%",
-                "876,500%",
                 "87,650%",
                 "8,765%",
                 "876.5%",
                 "87.65%",
                 "8.765%",
                 "0.8765%",
+                "0.08765%",
+                "0.008765%",
                 "0%");
 
         assertFormatDescending(
@@ -541,14 +597,14 @@ public class NumberFormatterTest {
                 "%%",
                 NumberFormatter.with().unit(NoUnit.PERMILLE),
                 ULocale.ENGLISH,
-                "87,650,000‰",
-                "8,765,000‰",
-                "876,500‰",
                 "87,650‰",
                 "8,765‰",
                 "876.5‰",
                 "87.65‰",
                 "8.765‰",
+                "0.8765‰",
+                "0.08765‰",
+                "0.008765‰",
                 "0‰");
 
         assertFormatSingle(
@@ -564,8 +620,8 @@ public class NumberFormatterTest {
                 "%",
                 NumberFormatter.with().unit(NoUnit.PERCENT),
                 ULocale.ENGLISH,
-                -0.987654321,
-                "-98.7654321%");
+                -98.7654321,
+                "-98.765432%");
     }
 
     @Test
@@ -792,6 +848,21 @@ public class NumberFormatterTest {
                 "0.0",
                 "0.0");
 
+        assertFormatDescending(
+                "Increment with Min Fraction",
+                "M0.5",
+                NumberFormatter.with().rounding(Rounder.increment(new BigDecimal("0.50"))),
+                ULocale.ENGLISH,
+                "87,650.00",
+                "8,765.00",
+                "876.50",
+                "87.50",
+                "9.00",
+                "1.00",
+                "0.00",
+                "0.00",
+                "0.00");
+
         assertFormatDescending(
                 "Currency Standard",
                 "$CZK GSTANDARD",
@@ -822,6 +893,21 @@ public class NumberFormatterTest {
                 "CZK 0",
                 "CZK 0");
 
+        assertFormatDescending(
+                "Currency Cash with Nickel Rounding",
+                "$CAD GCASH",
+                NumberFormatter.with().rounding(Rounder.currency(CurrencyUsage.CASH)).unit(CAD),
+                ULocale.ENGLISH,
+                "CA$87,650.00",
+                "CA$8,765.00",
+                "CA$876.50",
+                "CA$87.65",
+                "CA$8.75",
+                "CA$0.90",
+                "CA$0.10",
+                "CA$0.00",
+                "CA$0.00");
+
         assertFormatDescending(
                 "Currency not in top-level fluent chain",
                 "F0",
@@ -836,71 +922,100 @@ public class NumberFormatterTest {
                 "0",
                 "0",
                 "0");
+
+        // NOTE: Other tests cover the behavior of the other rounding modes.
+        assertFormatDescending(
+                "Rounding Mode CEILING",
+                "",
+                NumberFormatter.with().rounding(Rounder.integer().withMode(RoundingMode.CEILING)),
+                ULocale.ENGLISH,
+                "87,650",
+                "8,765",
+                "877",
+                "88",
+                "9",
+                "1",
+                "1",
+                "1",
+                "0");
     }
 
     @Test
     public void grouping() {
-        // NoUnit.PERMILLE multiplies all the number by 10^3 (good for testing grouping).
-        // Note that en-US is already performed in the unitPercent() function.
-        assertFormatDescending(
+        assertFormatDescendingBig(
+                "Western Grouping",
+                "grouping=defaults",
+                NumberFormatter.with().grouping(Grouper.defaults()),
+                ULocale.ENGLISH,
+                "87,650,000",
+                "8,765,000",
+                "876,500",
+                "87,650",
+                "8,765",
+                "876.5",
+                "87.65",
+                "8.765",
+                "0");
+
+        assertFormatDescendingBig(
                 "Indic Grouping",
-                "%% grouping=defaults",
-                NumberFormatter.with().unit(NoUnit.PERMILLE).grouping(Grouper.defaults()),
+                "grouping=defaults",
+                NumberFormatter.with().grouping(Grouper.defaults()),
                 new ULocale("en-IN"),
-                "8,76,50,000",
-                "87,65,000",
-                "8,76,500",
-                "87,650",
-                "8,765",
-                "876.5",
-                "87.65",
-                "8.765",
-                "0");
+                "8,76,50,000",
+                "87,65,000",
+                "8,76,500",
+                "87,650",
+                "8,765",
+                "876.5",
+                "87.65",
+                "8.765",
+                "0");
 
-        assertFormatDescending(
+        assertFormatDescendingBig(
                 "Western Grouping, Min 2",
-                "%% grouping=min2",
-                NumberFormatter.with().unit(NoUnit.PERMILLE).grouping(Grouper.min2()),
+                "grouping=min2",
+                NumberFormatter.with().grouping(Grouper.minTwoDigits()),
                 ULocale.ENGLISH,
-                "87,650,000",
-                "8,765,000",
-                "876,500",
-                "87,650",
-                "8765",
-                "876.5",
-                "87.65",
-                "8.765",
-                "0");
+                "87,650,000",
+                "8,765,000",
+                "876,500",
+                "87,650",
+                "8765",
+                "876.5",
+                "87.65",
+                "8.765",
+                "0");
 
-        assertFormatDescending(
+        assertFormatDescendingBig(
                 "Indic Grouping, Min 2",
-                "%% grouping=min2",
-                NumberFormatter.with().unit(NoUnit.PERMILLE).grouping(Grouper.min2()),
+                "grouping=min2",
+                NumberFormatter.with().grouping(Grouper.minTwoDigits()),
                 new ULocale("en-IN"),
-                "8,76,50,000",
-                "87,65,000",
-                "8,76,500",
-                "87,650",
-                "8765",
-                "876.5",
-                "87.65",
-                "8.765",
-                "0");
+                "8,76,50,000",
+                "87,65,000",
+                "8,76,500",
+                "87,650",
+                "8765",
+                "876.5",
+                "87.65",
+                "8.765",
+                "0");
 
-        assertFormatDescending(
+        assertFormatDescendingBig(
                 "No Grouping",
-                "%% grouping=none",
-                NumberFormatter.with().unit(NoUnit.PERMILLE).grouping(Grouper.none()),
+                "grouping=none",
+                NumberFormatter.with().grouping(Grouper.none()),
                 new ULocale("en-IN"),
-                "87650000",
-                "8765000",
-                "876500",
-                "87650",
-                "8765",
-                "876.5",
-                "87.65",
-                "8.765",
-                "0");
+                "87650000",
+                "8765000",
+                "876500",
+                "87650",
+                "8765",
+                "876.5",
+                "87.65",
+                "8.765",
+                "0");
     }
 
     @Test
@@ -1004,7 +1119,7 @@ public class NumberFormatterTest {
                 NumberFormatter.with().padding(Padder.codePoints('*', 8, PadPosition.BEFORE_SUFFIX))
                         .unit(NoUnit.PERCENT),
                 ULocale.ENGLISH,
-                0.8888,
+                88.88,
                 "88.88**%");
 
         assertFormatSingle(
@@ -1013,14 +1128,14 @@ public class NumberFormatterTest {
                 NumberFormatter.with().padding(Padder.codePoints('*', 8, PadPosition.AFTER_SUFFIX))
                         .unit(NoUnit.PERCENT),
                 ULocale.ENGLISH,
-                0.8888,
+                88.88,
                 "88.88%**");
 
         assertFormatSingle(
                 "Currency Spacing with Zero Digit Padding Broken",
                 "$GBP unit-width=ISO_CODE",
                 NumberFormatter.with().padding(Padder.codePoints('0', 12, PadPosition.AFTER_PREFIX)).unit(GBP)
-                .unitWidth(UnitWidth.ISO_CODE),
+                        .unitWidth(UnitWidth.ISO_CODE),
                 ULocale.ENGLISH,
                 514.23,
                 "GBP 000514.23"); // TODO: This is broken; it renders too wide (13 instead of 12).
@@ -1135,15 +1250,15 @@ public class NumberFormatterTest {
                 "$USD symbols=ns:latn",
                 NumberFormatter.with().symbols(NumberingSystem.LATIN).unit(USD),
                 new ULocale("ar"),
-                "87,650.00 US$",
-                "8,765.00 US$",
-                "876.50 US$",
-                "87.65 US$",
-                "8.76 US$",
-                "0.88 US$",
-                "0.09 US$",
-                "0.01 US$",
-                "0.00 US$");
+                "US$ 87,650.00",
+                "US$ 8,765.00",
+                "US$ 876.50",
+                "US$ 87.65",
+                "US$ 8.76",
+                "US$ 0.88",
+                "US$ 0.09",
+                "US$ 0.01",
+                "US$ 0.00");
 
         assertFormatDescending(
                 "Math Numbering System with French Data",
@@ -1176,6 +1291,40 @@ public class NumberFormatterTest {
                 12345.67,
                 "\u1041\u1042,\u1043\u1044\u1045.\u1046\u1047");
 
+        // NOTE: Locale ar puts ¤ after the number in NS arab but before the number in NS latn.
+
+        assertFormatSingle(
+                "Currency symbol should precede number in ar with NS latn",
+                "",
+                NumberFormatter.with().symbols(NumberingSystem.LATIN).unit(USD),
+                new ULocale("ar"),
+                12345.67,
+                "US$ 12,345.67");
+
+        assertFormatSingle(
+                "Currency symbol should precede number in ar@numbers=latn",
+                "",
+                NumberFormatter.with().unit(USD),
+                new ULocale("ar@numbers=latn"),
+                12345.67,
+                "US$ 12,345.67");
+
+        assertFormatSingle(
+                "Currency symbol should follow number in ar with NS arab",
+                "",
+                NumberFormatter.with().unit(USD),
+                new ULocale("ar"),
+                12345.67,
+                "١٢٬٣٤٥٫٦٧ US$");
+
+        assertFormatSingle(
+                "Currency symbol should follow number in ar@numbers=arab",
+                "",
+                NumberFormatter.with().unit(USD),
+                new ULocale("ar@numbers=arab"),
+                12345.67,
+                "١٢٬٣٤٥٫٦٧ US$");
+
         DecimalFormatSymbols symbols = DecimalFormatSymbols.getInstance(new ULocale("de-CH"));
         UnlocalizedNumberFormatter f = NumberFormatter.with().symbols(symbols);
         symbols.setGroupingSeparatorString("!");
@@ -1300,6 +1449,14 @@ public class NumberFormatterTest {
                 ULocale.ENGLISH,
                 -444444,
                 "($444,444.00)");
+
+        assertFormatSingle(
+                "Sign Accounting Negative Hidden",
+                "$USD unit-width=HIDDEN sign=ACCOUNTING",
+                NumberFormatter.with().sign(SignDisplay.ACCOUNTING).unit(USD).unitWidth(UnitWidth.HIDDEN),
+                ULocale.ENGLISH,
+                -444444,
+                "(444,444.00)");
     }
 
     @Test
@@ -1307,7 +1464,7 @@ public class NumberFormatterTest {
         assertFormatDescending(
                 "Decimal Default",
                 "decimal=AUTO",
-                NumberFormatter.with().decimal(DecimalMarkDisplay.AUTO),
+                NumberFormatter.with().decimal(DecimalSeparatorDisplay.AUTO),
                 ULocale.ENGLISH,
                 "87,650",
                 "8,765",
@@ -1322,7 +1479,7 @@ public class NumberFormatterTest {
         assertFormatDescending(
                 "Decimal Always Shown",
                 "decimal=ALWAYS",
-                NumberFormatter.with().decimal(DecimalMarkDisplay.ALWAYS),
+                NumberFormatter.with().decimal(DecimalSeparatorDisplay.ALWAYS),
                 ULocale.ENGLISH,
                 "87,650.",
                 "8,765.",
@@ -1394,17 +1551,38 @@ public class NumberFormatterTest {
             UnlocalizedNumberFormatter f,
             ULocale locale,
             String... expected) {
-        assert expected.length == 9;
-        assertEquals(message + ": Skeleton:", skeleton, f.toSkeleton());
         final double[] inputs = new double[] { 87650, 8765, 876.5, 87.65, 8.765, 0.8765, 0.08765, 0.008765, 0 };
+        assertFormatDescending(message, skeleton, f, locale, inputs, expected);
+    }
+
+    private static void assertFormatDescendingBig(
+            String message,
+            String skeleton,
+            UnlocalizedNumberFormatter f,
+            ULocale locale,
+            String... expected) {
+        final double[] inputs = new double[] { 87650000, 8765000, 876500, 87650, 8765, 876.5, 87.65, 8.765, 0 };
+        assertFormatDescending(message, skeleton, f, locale, inputs, expected);
+    }
+
+    private static void assertFormatDescending(
+            String message,
+            String skeleton,
+            UnlocalizedNumberFormatter f,
+            ULocale locale,
+            double[] inputs,
+            String... expected) {
+        assert expected.length == 9;
+        // TODO: Add a check for skeleton.
+        // assertEquals(message + ": Skeleton:", skeleton, f.toSkeleton());
         LocalizedNumberFormatter l1 = f.threshold(0L).locale(locale); // no self-regulation
         LocalizedNumberFormatter l2 = f.threshold(1L).locale(locale); // all self-regulation
         for (int i = 0; i < 9; i++) {
             double d = inputs[i];
             String actual1 = l1.format(d).toString();
-            assertEquals(message + ": L1: " + d, expected[i], actual1);
+            assertEquals(message + ": Unsafe Path: " + d, expected[i], actual1);
             String actual2 = l2.format(d).toString();
-            assertEquals(message + ": L2: " + d, expected[i], actual2);
+            assertEquals(message + ": Safe Path: " + d, expected[i], actual2);
         }
     }
 
@@ -1415,7 +1593,8 @@ public class NumberFormatterTest {
             ULocale locale,
             Number input,
             String expected) {
-        assertEquals(message + ": Skeleton:", skeleton, f.toSkeleton());
+        // TODO: Add a check for skeleton.
+        // assertEquals(message + ": Skeleton:", skeleton, f.toSkeleton());
         LocalizedNumberFormatter l1 = f.threshold(0L).locale(locale); // no self-regulation
         LocalizedNumberFormatter l2 = f.threshold(1L).locale(locale); // all self-regulation
         String actual1 = l1.format(input).toString();
@@ -1431,7 +1610,8 @@ public class NumberFormatterTest {
             ULocale locale,
             Measure input,
             String expected) {
-        assertEquals(message + ": Skeleton:", skeleton, f.toSkeleton());
+        // TODO: Add a check for skeleton.
+        // assertEquals(message + ": Skeleton:", skeleton, f.toSkeleton());
         LocalizedNumberFormatter l1 = f.threshold(0L).locale(locale); // no self-regulation
         LocalizedNumberFormatter l2 = f.threshold(1L).locale(locale); // all self-regulation
         String actual1 = l1.format(input).toString();
index 64e034925c5268141fb3a05049280c03ecd58d6b..e3a1a9b848b5dc9ebd04da26d3ad777865ee47c6 100644 (file)
@@ -33,6 +33,7 @@ import com.ibm.icu.impl.number.DecimalFormatProperties;
 import com.ibm.icu.impl.number.Parse.GroupingMode;
 import com.ibm.icu.impl.number.Parse.ParseMode;
 import com.ibm.icu.impl.number.PatternStringParser;
+import com.ibm.icu.impl.number.Padder.PadPosition;
 import com.ibm.icu.text.CompactDecimalFormat.CompactStyle;
 import com.ibm.icu.text.CurrencyPluralInfo;
 import com.ibm.icu.text.MeasureFormat.FormatWidth;
@@ -42,8 +43,6 @@ import com.ibm.icu.util.Currency.CurrencyUsage;
 import com.ibm.icu.util.MeasureUnit;
 import com.ibm.icu.util.ULocale;
 
-import newapi.impl.Padder.PadPosition;
-
 public class PropertiesTest {
 
   @Test
similarity index 97%
rename from icu4j/main/classes/core/src/com/ibm/icu/impl/number/DecimalQuantity_64BitBCD.java
rename to icu4j/main/tests/core/src/com/ibm/icu/impl/number/DecimalQuantity_64BitBCD.java
index 4954444a54c1565db38376a04dd3c339fca507c9..c968a0abc52da1f62b09c32e23750512e025abdc 100644 (file)
@@ -45,6 +45,11 @@ public final class DecimalQuantity_64BitBCD extends DecimalQuantity_AbstractBCD
     copyFrom(other);
   }
 
+  @Override
+  public DecimalQuantity createCopy() {
+    return new DecimalQuantity_64BitBCD(this);
+  }
+
   @Override
   protected byte getDigitPos(int position) {
     if (position < 0 || position >= 16) return 0;
similarity index 98%
rename from icu4j/main/classes/core/src/com/ibm/icu/impl/number/DecimalQuantity_ByteArrayBCD.java
rename to icu4j/main/tests/core/src/com/ibm/icu/impl/number/DecimalQuantity_ByteArrayBCD.java
index e428c6810c5cb8d53a2e0ff5f9767245865b17b4..f0198109bffee3d3a11c957cd88cb565957f8763 100644 (file)
@@ -45,6 +45,11 @@ public final class DecimalQuantity_ByteArrayBCD extends DecimalQuantity_Abstract
     copyFrom(other);
   }
 
+  @Override
+  public DecimalQuantity createCopy() {
+    return new DecimalQuantity_ByteArrayBCD(this);
+  }
+
   @Override
   protected byte getDigitPos(int position) {
     if (position < 0 || position > precision) return 0;