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 }