• Home
  • Line#
  • Scopes#
  • Navigate#
  • Raw
  • Download
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