Home | History | Annotate | Download | only in number
      1 //  2017 and later: Unicode, Inc. and others.
      2 // License & terms of use: http://www.unicode.org/copyright.html#License
      3 package com.ibm.icu.number;
      4 
      5 import java.math.BigInteger;
      6 import java.util.concurrent.atomic.AtomicLongFieldUpdater;
      7 
      8 import com.ibm.icu.impl.Utility;
      9 import com.ibm.icu.impl.number.DecimalQuantity;
     10 import com.ibm.icu.impl.number.DecimalQuantity_DualStorageBCD;
     11 import com.ibm.icu.impl.number.MacroProps;
     12 import com.ibm.icu.impl.number.MicroProps;
     13 import com.ibm.icu.impl.number.NumberStringBuilder;
     14 import com.ibm.icu.math.BigDecimal;
     15 import com.ibm.icu.util.CurrencyAmount;
     16 import com.ibm.icu.util.Measure;
     17 import com.ibm.icu.util.MeasureUnit;
     18 
     19 /**
     20  * A NumberFormatter that has a locale associated with it; this means .format() methods are available.
     21  *
     22  * @see NumberFormatter
     23  * @draft ICU 60
     24  * @provisional This API might change or be removed in a future release.
     25  * @see NumberFormatter
     26  */
     27 public class LocalizedNumberFormatter extends NumberFormatterSettings<LocalizedNumberFormatter> {
     28 
     29     static final AtomicLongFieldUpdater<LocalizedNumberFormatter> callCount = AtomicLongFieldUpdater
     30             .newUpdater(LocalizedNumberFormatter.class, "callCountInternal");
     31 
     32     volatile long callCountInternal; // do not access directly; use callCount instead
     33     volatile LocalizedNumberFormatter savedWithUnit;
     34     volatile NumberFormatterImpl compiled;
     35 
     36     LocalizedNumberFormatter(NumberFormatterSettings<?> parent, int key, Object value) {
     37         super(parent, key, value);
     38     }
     39 
     40     /**
     41      * Format the given byte, short, int, or long to a string using the settings specified in the NumberFormatter fluent
     42      * setting chain.
     43      *
     44      * @param input
     45      *            The number to format.
     46      * @return A FormattedNumber object; call .toString() to get the string.
     47      * @draft ICU 60
     48      * @provisional This API might change or be removed in a future release.
     49      * @see NumberFormatter
     50      */
     51     public FormattedNumber format(long input) {
     52         return format(new DecimalQuantity_DualStorageBCD(input));
     53     }
     54 
     55     /**
     56      * Format the given float or double to a string using the settings specified in the NumberFormatter fluent setting
     57      * chain.
     58      *
     59      * @param input
     60      *            The number to format.
     61      * @return A FormattedNumber object; call .toString() to get the string.
     62      * @draft ICU 60
     63      * @provisional This API might change or be removed in a future release.
     64      * @see NumberFormatter
     65      */
     66     public FormattedNumber format(double input) {
     67         return format(new DecimalQuantity_DualStorageBCD(input));
     68     }
     69 
     70     /**
     71      * Format the given {@link BigInteger}, {@link BigDecimal}, or other {@link Number} to a string using the settings
     72      * specified in the NumberFormatter fluent setting chain.
     73      *
     74      * @param input
     75      *            The number to format.
     76      * @return A FormattedNumber object; call .toString() to get the string.
     77      * @draft ICU 60
     78      * @provisional This API might change or be removed in a future release.
     79      * @see NumberFormatter
     80      */
     81     public FormattedNumber format(Number input) {
     82         return format(new DecimalQuantity_DualStorageBCD(input));
     83     }
     84 
     85     /**
     86      * Format the given {@link Measure} or {@link CurrencyAmount} to a string using the settings specified in the
     87      * NumberFormatter fluent setting chain.
     88      *
     89      * <p>
     90      * The unit specified here overrides any unit that may have been specified in the setter chain. This method is
     91      * intended for cases when each input to the number formatter has a different unit.
     92      *
     93      * @param input
     94      *            The number to format.
     95      * @return A FormattedNumber object; call .toString() to get the string.
     96      * @draft ICU 60
     97      * @provisional This API might change or be removed in a future release.
     98      * @see NumberFormatter
     99      */
    100     public FormattedNumber format(Measure input) {
    101         MeasureUnit unit = input.getUnit();
    102         Number number = input.getNumber();
    103         // Use this formatter if possible
    104         if (Utility.equals(resolve().unit, unit)) {
    105             return format(number);
    106         }
    107         // This mechanism saves the previously used unit, so if the user calls this method with the
    108         // same unit multiple times in a row, they get a more efficient code path.
    109         LocalizedNumberFormatter withUnit = savedWithUnit;
    110         if (withUnit == null || !Utility.equals(withUnit.resolve().unit, unit)) {
    111             withUnit = new LocalizedNumberFormatter(this, KEY_UNIT, unit);
    112             savedWithUnit = withUnit;
    113         }
    114         return withUnit.format(number);
    115     }
    116 
    117     /**
    118      * This is the core entrypoint to the number formatting pipeline. It performs self-regulation: a static code path
    119      * for the first few calls, and compiling a more efficient data structure if called repeatedly.
    120      *
    121      * <p>
    122      * This function is very hot, being called in every call to the number formatting pipeline.
    123      *
    124      * @param fq
    125      *            The quantity to be formatted.
    126      * @return The formatted number result.
    127      *
    128      * @internal
    129      * @deprecated ICU 60 This API is ICU internal only.
    130      */
    131     @Deprecated
    132     public FormattedNumber format(DecimalQuantity fq) {
    133         MacroProps macros = resolve();
    134         // NOTE: In Java, the atomic increment logic is slightly different than ICU4C.
    135         // It seems to be more efficient to make just one function call instead of two.
    136         // Further benchmarking is required.
    137         long currentCount = callCount.incrementAndGet(this);
    138         NumberStringBuilder string = new NumberStringBuilder();
    139         MicroProps micros;
    140         if (currentCount == macros.threshold.longValue()) {
    141             compiled = NumberFormatterImpl.fromMacros(macros);
    142             micros = compiled.apply(fq, string);
    143         } else if (compiled != null) {
    144             micros = compiled.apply(fq, string);
    145         } else {
    146             micros = NumberFormatterImpl.applyStatic(macros, fq, string);
    147         }
    148         return new FormattedNumber(string, fq, micros);
    149     }
    150 
    151     @Override
    152     LocalizedNumberFormatter create(int key, Object value) {
    153         return new LocalizedNumberFormatter(this, key, value);
    154     }
    155 }