1 /* GENERATED SOURCE. DO NOT MODIFY. */ 2 // © 2017 and later: Unicode, Inc. and others. 3 // License & terms of use: http://www.unicode.org/copyright.html 4 package android.icu.number; 5 6 import java.util.HashMap; 7 import java.util.HashSet; 8 import java.util.Map; 9 import java.util.Set; 10 11 import android.icu.impl.number.CompactData; 12 import android.icu.impl.number.CompactData.CompactType; 13 import android.icu.impl.number.DecimalFormatProperties; 14 import android.icu.impl.number.DecimalQuantity; 15 import android.icu.impl.number.MicroProps; 16 import android.icu.impl.number.MicroPropsGenerator; 17 import android.icu.impl.number.MutablePatternModifier; 18 import android.icu.impl.number.MutablePatternModifier.ImmutablePatternModifier; 19 import android.icu.impl.number.PatternStringParser; 20 import android.icu.impl.number.PatternStringParser.ParsedPatternInfo; 21 import android.icu.text.CompactDecimalFormat.CompactStyle; 22 import android.icu.text.NumberFormat; 23 import android.icu.text.PluralRules; 24 import android.icu.util.ULocale; 25 26 /** 27 * A class that defines the scientific notation style to be used when formatting numbers in 28 * NumberFormatter. 29 * 30 * <p> 31 * This class exposes no public functionality. To create a CompactNotation, use one of the factory 32 * methods in {@link Notation}. 33 * 34 * @see NumberFormatter 35 */ 36 public class CompactNotation extends Notation { 37 38 final CompactStyle compactStyle; 39 final Map<String, Map<String, String>> compactCustomData; 40 41 /** 42 * Create a compact notation with custom data. 43 * @deprecated This API is ICU internal only. 44 * @see DecimalFormatProperties#setCompactCustomData 45 * @hide draft / provisional / internal are hidden on Android 46 */ 47 @Deprecated forCustomData(Map<String, Map<String, String>> compactCustomData)48 public static CompactNotation forCustomData(Map<String, Map<String, String>> compactCustomData) { 49 return new CompactNotation(compactCustomData); 50 } 51 CompactNotation(CompactStyle compactStyle)52 /* package-private */ CompactNotation(CompactStyle compactStyle) { 53 compactCustomData = null; 54 this.compactStyle = compactStyle; 55 } 56 CompactNotation(Map<String, Map<String, String>> compactCustomData)57 /* package-private */ CompactNotation(Map<String, Map<String, String>> compactCustomData) { 58 compactStyle = null; 59 this.compactCustomData = compactCustomData; 60 } 61 withLocaleData( ULocale locale, String nsName, CompactType compactType, PluralRules rules, MutablePatternModifier buildReference, boolean safe, MicroPropsGenerator parent)62 /* package-private */ MicroPropsGenerator withLocaleData( 63 ULocale locale, 64 String nsName, 65 CompactType compactType, 66 PluralRules rules, 67 MutablePatternModifier buildReference, 68 boolean safe, 69 MicroPropsGenerator parent) { 70 // TODO: Add a data cache? It would be keyed by locale, nsName, compact type, and compact style. 71 return new CompactHandler(this, locale, nsName, compactType, rules, buildReference, safe, parent); 72 } 73 74 private static class CompactHandler implements MicroPropsGenerator { 75 76 final PluralRules rules; 77 final MicroPropsGenerator parent; 78 final Map<String, ImmutablePatternModifier> precomputedMods; 79 final MutablePatternModifier unsafePatternModifier; 80 final CompactData data; 81 CompactHandler( CompactNotation notation, ULocale locale, String nsName, CompactType compactType, PluralRules rules, MutablePatternModifier buildReference, boolean safe, MicroPropsGenerator parent)82 private CompactHandler( 83 CompactNotation notation, 84 ULocale locale, 85 String nsName, 86 CompactType compactType, 87 PluralRules rules, 88 MutablePatternModifier buildReference, 89 boolean safe, 90 MicroPropsGenerator parent) { 91 this.rules = rules; 92 this.parent = parent; 93 this.data = new CompactData(); 94 if (notation.compactStyle != null) { 95 data.populate(locale, nsName, notation.compactStyle, compactType); 96 } else { 97 data.populate(notation.compactCustomData); 98 } 99 if (safe) { 100 // Safe code path 101 precomputedMods = new HashMap<>(); 102 precomputeAllModifiers(buildReference); 103 unsafePatternModifier = null; 104 } else { 105 // Unsafe code path 106 precomputedMods = null; 107 unsafePatternModifier = buildReference; 108 } 109 } 110 111 /** Used by the safe code path */ precomputeAllModifiers(MutablePatternModifier buildReference)112 private void precomputeAllModifiers(MutablePatternModifier buildReference) { 113 Set<String> allPatterns = new HashSet<>(); 114 data.getUniquePatterns(allPatterns); 115 116 for (String patternString : allPatterns) { 117 ParsedPatternInfo patternInfo = PatternStringParser.parseToPatternInfo(patternString); 118 buildReference.setPatternInfo(patternInfo, NumberFormat.Field.COMPACT); 119 precomputedMods.put(patternString, buildReference.createImmutable()); 120 } 121 } 122 123 @Override processQuantity(DecimalQuantity quantity)124 public MicroProps processQuantity(DecimalQuantity quantity) { 125 MicroProps micros = parent.processQuantity(quantity); 126 assert micros.rounder != null; 127 128 // Treat zero, NaN, and infinity as if they had magnitude 0 129 int magnitude; 130 int multiplier = 0; 131 if (quantity.isZeroish()) { 132 magnitude = 0; 133 micros.rounder.apply(quantity); 134 } else { 135 multiplier = micros.rounder.chooseMultiplierAndApply(quantity, data); 136 magnitude = quantity.isZeroish() ? 0 : quantity.getMagnitude(); 137 magnitude -= multiplier; 138 } 139 140 String patternString = data.getPattern(magnitude, rules, quantity); 141 if (patternString == null) { 142 // Use the default (non-compact) modifier. 143 // No need to take any action. 144 } else if (precomputedMods != null) { 145 // Safe code path. 146 // Java uses a hash set here for O(1) lookup. C++ uses a linear search. 147 ImmutablePatternModifier mod = precomputedMods.get(patternString); 148 mod.applyToMicros(micros, quantity); 149 } else { 150 // Unsafe code path. 151 // Overwrite the PatternInfo in the existing modMiddle. 152 ParsedPatternInfo patternInfo = PatternStringParser.parseToPatternInfo(patternString); 153 unsafePatternModifier.setPatternInfo(patternInfo, NumberFormat.Field.COMPACT); 154 unsafePatternModifier.setNumberProperties(quantity.signum(), null); 155 micros.modMiddle = unsafePatternModifier; 156 } 157 158 // Change the exponent only after we select appropriate plural form 159 // for formatting purposes so that we preserve expected formatted 160 // string behavior. 161 quantity.adjustExponent(-1 * multiplier); 162 163 // We already performed rounding. Do not perform it again. 164 micros.rounder = null; 165 166 return micros; 167 } 168 } 169 } 170