1fe77e7203e518f62b5bd8e8c603bca361e9cf47bFredrik Roubert// © 2017 and later: Unicode, Inc. and others. 2fe77e7203e518f62b5bd8e8c603bca361e9cf47bFredrik Roubert// License & terms of use: http://www.unicode.org/copyright.html#License 3fe77e7203e518f62b5bd8e8c603bca361e9cf47bFredrik Roubertpackage com.ibm.icu.impl.number; 4fe77e7203e518f62b5bd8e8c603bca361e9cf47bFredrik Roubert 5fe77e7203e518f62b5bd8e8c603bca361e9cf47bFredrik Roubertimport java.util.Arrays; 6fe77e7203e518f62b5bd8e8c603bca361e9cf47bFredrik Roubertimport java.util.Map; 7fe77e7203e518f62b5bd8e8c603bca361e9cf47bFredrik Roubertimport java.util.Set; 8fe77e7203e518f62b5bd8e8c603bca361e9cf47bFredrik Roubert 9fe77e7203e518f62b5bd8e8c603bca361e9cf47bFredrik Roubertimport com.ibm.icu.impl.ICUData; 10fe77e7203e518f62b5bd8e8c603bca361e9cf47bFredrik Roubertimport com.ibm.icu.impl.ICUResourceBundle; 11fe77e7203e518f62b5bd8e8c603bca361e9cf47bFredrik Roubertimport com.ibm.icu.impl.StandardPlural; 12fe77e7203e518f62b5bd8e8c603bca361e9cf47bFredrik Roubertimport com.ibm.icu.impl.UResource; 13fe77e7203e518f62b5bd8e8c603bca361e9cf47bFredrik Roubertimport com.ibm.icu.text.CompactDecimalFormat.CompactStyle; 14fe77e7203e518f62b5bd8e8c603bca361e9cf47bFredrik Roubertimport com.ibm.icu.util.ICUException; 15fe77e7203e518f62b5bd8e8c603bca361e9cf47bFredrik Roubertimport com.ibm.icu.util.ULocale; 16fe77e7203e518f62b5bd8e8c603bca361e9cf47bFredrik Roubertimport com.ibm.icu.util.UResourceBundle; 17fe77e7203e518f62b5bd8e8c603bca361e9cf47bFredrik Roubert 18fe77e7203e518f62b5bd8e8c603bca361e9cf47bFredrik Roubertpublic class CompactData implements MultiplierProducer { 19fe77e7203e518f62b5bd8e8c603bca361e9cf47bFredrik Roubert 20fe77e7203e518f62b5bd8e8c603bca361e9cf47bFredrik Roubert public enum CompactType { 21fe77e7203e518f62b5bd8e8c603bca361e9cf47bFredrik Roubert DECIMAL, CURRENCY 22fe77e7203e518f62b5bd8e8c603bca361e9cf47bFredrik Roubert } 23fe77e7203e518f62b5bd8e8c603bca361e9cf47bFredrik Roubert 24fe77e7203e518f62b5bd8e8c603bca361e9cf47bFredrik Roubert // A dummy object used when a "0" compact decimal entry is encountered. This is necessary 25fe77e7203e518f62b5bd8e8c603bca361e9cf47bFredrik Roubert // in order to prevent falling back to root. Object equality ("==") is intended. 26fe77e7203e518f62b5bd8e8c603bca361e9cf47bFredrik Roubert private static final String USE_FALLBACK = "<USE FALLBACK>"; 27fe77e7203e518f62b5bd8e8c603bca361e9cf47bFredrik Roubert 28fe77e7203e518f62b5bd8e8c603bca361e9cf47bFredrik Roubert private final String[] patterns; 29fe77e7203e518f62b5bd8e8c603bca361e9cf47bFredrik Roubert private final byte[] multipliers; 30fe77e7203e518f62b5bd8e8c603bca361e9cf47bFredrik Roubert private byte largestMagnitude; 31fe77e7203e518f62b5bd8e8c603bca361e9cf47bFredrik Roubert private boolean isEmpty; 32fe77e7203e518f62b5bd8e8c603bca361e9cf47bFredrik Roubert 33fe77e7203e518f62b5bd8e8c603bca361e9cf47bFredrik Roubert private static final int COMPACT_MAX_DIGITS = 15; 34fe77e7203e518f62b5bd8e8c603bca361e9cf47bFredrik Roubert 35fe77e7203e518f62b5bd8e8c603bca361e9cf47bFredrik Roubert public CompactData() { 36fe77e7203e518f62b5bd8e8c603bca361e9cf47bFredrik Roubert patterns = new String[(CompactData.COMPACT_MAX_DIGITS + 1) * StandardPlural.COUNT]; 37fe77e7203e518f62b5bd8e8c603bca361e9cf47bFredrik Roubert multipliers = new byte[CompactData.COMPACT_MAX_DIGITS + 1]; 38fe77e7203e518f62b5bd8e8c603bca361e9cf47bFredrik Roubert largestMagnitude = 0; 39fe77e7203e518f62b5bd8e8c603bca361e9cf47bFredrik Roubert isEmpty = true; 40fe77e7203e518f62b5bd8e8c603bca361e9cf47bFredrik Roubert } 41fe77e7203e518f62b5bd8e8c603bca361e9cf47bFredrik Roubert 42fe77e7203e518f62b5bd8e8c603bca361e9cf47bFredrik Roubert public void populate(ULocale locale, String nsName, CompactStyle compactStyle, CompactType compactType) { 43fe77e7203e518f62b5bd8e8c603bca361e9cf47bFredrik Roubert assert isEmpty; 44fe77e7203e518f62b5bd8e8c603bca361e9cf47bFredrik Roubert CompactDataSink sink = new CompactDataSink(this); 45fe77e7203e518f62b5bd8e8c603bca361e9cf47bFredrik Roubert ICUResourceBundle rb = (ICUResourceBundle) UResourceBundle.getBundleInstance(ICUData.ICU_BASE_NAME, locale); 46fe77e7203e518f62b5bd8e8c603bca361e9cf47bFredrik Roubert 47fe77e7203e518f62b5bd8e8c603bca361e9cf47bFredrik Roubert boolean nsIsLatn = nsName.equals("latn"); 48fe77e7203e518f62b5bd8e8c603bca361e9cf47bFredrik Roubert boolean compactIsShort = compactStyle == CompactStyle.SHORT; 49fe77e7203e518f62b5bd8e8c603bca361e9cf47bFredrik Roubert 50fe77e7203e518f62b5bd8e8c603bca361e9cf47bFredrik Roubert // Fall back to latn numbering system and/or short compact style. 51fe77e7203e518f62b5bd8e8c603bca361e9cf47bFredrik Roubert StringBuilder resourceKey = new StringBuilder(); 52fe77e7203e518f62b5bd8e8c603bca361e9cf47bFredrik Roubert getResourceBundleKey(nsName, compactStyle, compactType, resourceKey); 53fe77e7203e518f62b5bd8e8c603bca361e9cf47bFredrik Roubert rb.getAllItemsWithFallbackNoFail(resourceKey.toString(), sink); 54fe77e7203e518f62b5bd8e8c603bca361e9cf47bFredrik Roubert if (isEmpty && !nsIsLatn) { 55fe77e7203e518f62b5bd8e8c603bca361e9cf47bFredrik Roubert getResourceBundleKey("latn", compactStyle, compactType, resourceKey); 56fe77e7203e518f62b5bd8e8c603bca361e9cf47bFredrik Roubert rb.getAllItemsWithFallbackNoFail(resourceKey.toString(), sink); 57fe77e7203e518f62b5bd8e8c603bca361e9cf47bFredrik Roubert } 58fe77e7203e518f62b5bd8e8c603bca361e9cf47bFredrik Roubert if (isEmpty && !compactIsShort) { 59fe77e7203e518f62b5bd8e8c603bca361e9cf47bFredrik Roubert getResourceBundleKey(nsName, CompactStyle.SHORT, compactType, resourceKey); 60fe77e7203e518f62b5bd8e8c603bca361e9cf47bFredrik Roubert rb.getAllItemsWithFallbackNoFail(resourceKey.toString(), sink); 61fe77e7203e518f62b5bd8e8c603bca361e9cf47bFredrik Roubert } 62fe77e7203e518f62b5bd8e8c603bca361e9cf47bFredrik Roubert if (isEmpty && !nsIsLatn && !compactIsShort) { 63fe77e7203e518f62b5bd8e8c603bca361e9cf47bFredrik Roubert getResourceBundleKey("latn", CompactStyle.SHORT, compactType, resourceKey); 64fe77e7203e518f62b5bd8e8c603bca361e9cf47bFredrik Roubert rb.getAllItemsWithFallbackNoFail(resourceKey.toString(), sink); 65fe77e7203e518f62b5bd8e8c603bca361e9cf47bFredrik Roubert } 66fe77e7203e518f62b5bd8e8c603bca361e9cf47bFredrik Roubert 67fe77e7203e518f62b5bd8e8c603bca361e9cf47bFredrik Roubert // The last fallback should be guaranteed to return data. 68fe77e7203e518f62b5bd8e8c603bca361e9cf47bFredrik Roubert if (isEmpty) { 69fe77e7203e518f62b5bd8e8c603bca361e9cf47bFredrik Roubert throw new ICUException("Could not load compact decimal data for locale " + locale); 70fe77e7203e518f62b5bd8e8c603bca361e9cf47bFredrik Roubert } 71fe77e7203e518f62b5bd8e8c603bca361e9cf47bFredrik Roubert } 72fe77e7203e518f62b5bd8e8c603bca361e9cf47bFredrik Roubert 73fe77e7203e518f62b5bd8e8c603bca361e9cf47bFredrik Roubert /** Produces a string like "NumberElements/latn/patternsShort/decimalFormat". */ 74fe77e7203e518f62b5bd8e8c603bca361e9cf47bFredrik Roubert private static void getResourceBundleKey(String nsName, CompactStyle compactStyle, CompactType compactType, StringBuilder sb) { 75fe77e7203e518f62b5bd8e8c603bca361e9cf47bFredrik Roubert sb.setLength(0); 76fe77e7203e518f62b5bd8e8c603bca361e9cf47bFredrik Roubert sb.append("NumberElements/"); 77fe77e7203e518f62b5bd8e8c603bca361e9cf47bFredrik Roubert sb.append(nsName); 78fe77e7203e518f62b5bd8e8c603bca361e9cf47bFredrik Roubert sb.append(compactStyle == CompactStyle.SHORT ? "/patternsShort" : "/patternsLong"); 79fe77e7203e518f62b5bd8e8c603bca361e9cf47bFredrik Roubert sb.append(compactType == CompactType.DECIMAL ? "/decimalFormat" : "/currencyFormat"); 80fe77e7203e518f62b5bd8e8c603bca361e9cf47bFredrik Roubert } 81fe77e7203e518f62b5bd8e8c603bca361e9cf47bFredrik Roubert 82fe77e7203e518f62b5bd8e8c603bca361e9cf47bFredrik Roubert /** Java-only method used by CLDR tooling. */ 83fe77e7203e518f62b5bd8e8c603bca361e9cf47bFredrik Roubert public void populate(Map<String, Map<String, String>> powersToPluralsToPatterns) { 84fe77e7203e518f62b5bd8e8c603bca361e9cf47bFredrik Roubert assert isEmpty; 85fe77e7203e518f62b5bd8e8c603bca361e9cf47bFredrik Roubert for (Map.Entry<String, Map<String, String>> magnitudeEntry : powersToPluralsToPatterns.entrySet()) { 86fe77e7203e518f62b5bd8e8c603bca361e9cf47bFredrik Roubert byte magnitude = (byte) (magnitudeEntry.getKey().length() - 1); 87fe77e7203e518f62b5bd8e8c603bca361e9cf47bFredrik Roubert for (Map.Entry<String, String> pluralEntry : magnitudeEntry.getValue().entrySet()) { 88fe77e7203e518f62b5bd8e8c603bca361e9cf47bFredrik Roubert StandardPlural plural = StandardPlural.fromString(pluralEntry.getKey().toString()); 89fe77e7203e518f62b5bd8e8c603bca361e9cf47bFredrik Roubert String patternString = pluralEntry.getValue().toString(); 90fe77e7203e518f62b5bd8e8c603bca361e9cf47bFredrik Roubert patterns[getIndex(magnitude, plural)] = patternString; 91fe77e7203e518f62b5bd8e8c603bca361e9cf47bFredrik Roubert int numZeros = countZeros(patternString); 92fe77e7203e518f62b5bd8e8c603bca361e9cf47bFredrik Roubert if (numZeros > 0) { // numZeros==0 in certain cases, like Somali "Kun" 93fe77e7203e518f62b5bd8e8c603bca361e9cf47bFredrik Roubert // Save the multiplier. 94fe77e7203e518f62b5bd8e8c603bca361e9cf47bFredrik Roubert multipliers[magnitude] = (byte) (numZeros - magnitude - 1); 95fe77e7203e518f62b5bd8e8c603bca361e9cf47bFredrik Roubert if (magnitude > largestMagnitude) { 96fe77e7203e518f62b5bd8e8c603bca361e9cf47bFredrik Roubert largestMagnitude = magnitude; 97fe77e7203e518f62b5bd8e8c603bca361e9cf47bFredrik Roubert } 98fe77e7203e518f62b5bd8e8c603bca361e9cf47bFredrik Roubert isEmpty = false; 99fe77e7203e518f62b5bd8e8c603bca361e9cf47bFredrik Roubert } 100fe77e7203e518f62b5bd8e8c603bca361e9cf47bFredrik Roubert } 101fe77e7203e518f62b5bd8e8c603bca361e9cf47bFredrik Roubert } 102fe77e7203e518f62b5bd8e8c603bca361e9cf47bFredrik Roubert } 103fe77e7203e518f62b5bd8e8c603bca361e9cf47bFredrik Roubert 104fe77e7203e518f62b5bd8e8c603bca361e9cf47bFredrik Roubert @Override 105fe77e7203e518f62b5bd8e8c603bca361e9cf47bFredrik Roubert public int getMultiplier(int magnitude) { 106fe77e7203e518f62b5bd8e8c603bca361e9cf47bFredrik Roubert if (magnitude < 0) { 107fe77e7203e518f62b5bd8e8c603bca361e9cf47bFredrik Roubert return 0; 108fe77e7203e518f62b5bd8e8c603bca361e9cf47bFredrik Roubert } 109fe77e7203e518f62b5bd8e8c603bca361e9cf47bFredrik Roubert if (magnitude > largestMagnitude) { 110fe77e7203e518f62b5bd8e8c603bca361e9cf47bFredrik Roubert magnitude = largestMagnitude; 111fe77e7203e518f62b5bd8e8c603bca361e9cf47bFredrik Roubert } 112fe77e7203e518f62b5bd8e8c603bca361e9cf47bFredrik Roubert return multipliers[magnitude]; 113fe77e7203e518f62b5bd8e8c603bca361e9cf47bFredrik Roubert } 114fe77e7203e518f62b5bd8e8c603bca361e9cf47bFredrik Roubert 115fe77e7203e518f62b5bd8e8c603bca361e9cf47bFredrik Roubert public String getPattern(int magnitude, StandardPlural plural) { 116fe77e7203e518f62b5bd8e8c603bca361e9cf47bFredrik Roubert if (magnitude < 0) { 117fe77e7203e518f62b5bd8e8c603bca361e9cf47bFredrik Roubert return null; 118fe77e7203e518f62b5bd8e8c603bca361e9cf47bFredrik Roubert } 119fe77e7203e518f62b5bd8e8c603bca361e9cf47bFredrik Roubert if (magnitude > largestMagnitude) { 120fe77e7203e518f62b5bd8e8c603bca361e9cf47bFredrik Roubert magnitude = largestMagnitude; 121fe77e7203e518f62b5bd8e8c603bca361e9cf47bFredrik Roubert } 122fe77e7203e518f62b5bd8e8c603bca361e9cf47bFredrik Roubert String patternString = patterns[getIndex(magnitude, plural)]; 123fe77e7203e518f62b5bd8e8c603bca361e9cf47bFredrik Roubert if (patternString == null && plural != StandardPlural.OTHER) { 124fe77e7203e518f62b5bd8e8c603bca361e9cf47bFredrik Roubert // Fall back to "other" plural variant 125fe77e7203e518f62b5bd8e8c603bca361e9cf47bFredrik Roubert patternString = patterns[getIndex(magnitude, StandardPlural.OTHER)]; 126fe77e7203e518f62b5bd8e8c603bca361e9cf47bFredrik Roubert } 127fe77e7203e518f62b5bd8e8c603bca361e9cf47bFredrik Roubert if (patternString == USE_FALLBACK) { // == is intended 128fe77e7203e518f62b5bd8e8c603bca361e9cf47bFredrik Roubert // Return null if USE_FALLBACK is present 129fe77e7203e518f62b5bd8e8c603bca361e9cf47bFredrik Roubert patternString = null; 130fe77e7203e518f62b5bd8e8c603bca361e9cf47bFredrik Roubert } 131fe77e7203e518f62b5bd8e8c603bca361e9cf47bFredrik Roubert return patternString; 132fe77e7203e518f62b5bd8e8c603bca361e9cf47bFredrik Roubert } 133fe77e7203e518f62b5bd8e8c603bca361e9cf47bFredrik Roubert 134fe77e7203e518f62b5bd8e8c603bca361e9cf47bFredrik Roubert public void getUniquePatterns(Set<String> output) { 135fe77e7203e518f62b5bd8e8c603bca361e9cf47bFredrik Roubert assert output.isEmpty(); 136fe77e7203e518f62b5bd8e8c603bca361e9cf47bFredrik Roubert // NOTE: In C++, this is done more manually with a UVector. 137fe77e7203e518f62b5bd8e8c603bca361e9cf47bFredrik Roubert // In Java, we can take advantage of JDK HashSet. 138fe77e7203e518f62b5bd8e8c603bca361e9cf47bFredrik Roubert output.addAll(Arrays.asList(patterns)); 139fe77e7203e518f62b5bd8e8c603bca361e9cf47bFredrik Roubert output.remove(USE_FALLBACK); 140fe77e7203e518f62b5bd8e8c603bca361e9cf47bFredrik Roubert output.remove(null); 141fe77e7203e518f62b5bd8e8c603bca361e9cf47bFredrik Roubert } 142fe77e7203e518f62b5bd8e8c603bca361e9cf47bFredrik Roubert 143fe77e7203e518f62b5bd8e8c603bca361e9cf47bFredrik Roubert private static final class CompactDataSink extends UResource.Sink { 144fe77e7203e518f62b5bd8e8c603bca361e9cf47bFredrik Roubert 145fe77e7203e518f62b5bd8e8c603bca361e9cf47bFredrik Roubert CompactData data; 146fe77e7203e518f62b5bd8e8c603bca361e9cf47bFredrik Roubert 147fe77e7203e518f62b5bd8e8c603bca361e9cf47bFredrik Roubert public CompactDataSink(CompactData data) { 148fe77e7203e518f62b5bd8e8c603bca361e9cf47bFredrik Roubert this.data = data; 149fe77e7203e518f62b5bd8e8c603bca361e9cf47bFredrik Roubert } 150fe77e7203e518f62b5bd8e8c603bca361e9cf47bFredrik Roubert 151fe77e7203e518f62b5bd8e8c603bca361e9cf47bFredrik Roubert @Override 152fe77e7203e518f62b5bd8e8c603bca361e9cf47bFredrik Roubert public void put(UResource.Key key, UResource.Value value, boolean isRoot) { 153fe77e7203e518f62b5bd8e8c603bca361e9cf47bFredrik Roubert // traverse into the table of powers of ten 154fe77e7203e518f62b5bd8e8c603bca361e9cf47bFredrik Roubert UResource.Table powersOfTenTable = value.getTable(); 155fe77e7203e518f62b5bd8e8c603bca361e9cf47bFredrik Roubert for (int i3 = 0; powersOfTenTable.getKeyAndValue(i3, key, value); ++i3) { 156fe77e7203e518f62b5bd8e8c603bca361e9cf47bFredrik Roubert 157fe77e7203e518f62b5bd8e8c603bca361e9cf47bFredrik Roubert // Assumes that the keys are always of the form "10000" where the magnitude is the 158fe77e7203e518f62b5bd8e8c603bca361e9cf47bFredrik Roubert // length of the key minus one. We expect magnitudes to be less than MAX_DIGITS. 159fe77e7203e518f62b5bd8e8c603bca361e9cf47bFredrik Roubert byte magnitude = (byte) (key.length() - 1); 160fe77e7203e518f62b5bd8e8c603bca361e9cf47bFredrik Roubert byte multiplier = data.multipliers[magnitude]; 161fe77e7203e518f62b5bd8e8c603bca361e9cf47bFredrik Roubert assert magnitude < COMPACT_MAX_DIGITS; 162fe77e7203e518f62b5bd8e8c603bca361e9cf47bFredrik Roubert 163fe77e7203e518f62b5bd8e8c603bca361e9cf47bFredrik Roubert // Iterate over the plural variants ("one", "other", etc) 164fe77e7203e518f62b5bd8e8c603bca361e9cf47bFredrik Roubert UResource.Table pluralVariantsTable = value.getTable(); 165fe77e7203e518f62b5bd8e8c603bca361e9cf47bFredrik Roubert for (int i4 = 0; pluralVariantsTable.getKeyAndValue(i4, key, value); ++i4) { 166fe77e7203e518f62b5bd8e8c603bca361e9cf47bFredrik Roubert 167fe77e7203e518f62b5bd8e8c603bca361e9cf47bFredrik Roubert // Skip this magnitude/plural if we already have it from a child locale. 168fe77e7203e518f62b5bd8e8c603bca361e9cf47bFredrik Roubert // Note: This also skips USE_FALLBACK entries. 169fe77e7203e518f62b5bd8e8c603bca361e9cf47bFredrik Roubert StandardPlural plural = StandardPlural.fromString(key.toString()); 170fe77e7203e518f62b5bd8e8c603bca361e9cf47bFredrik Roubert if (data.patterns[getIndex(magnitude, plural)] != null) { 171fe77e7203e518f62b5bd8e8c603bca361e9cf47bFredrik Roubert continue; 172fe77e7203e518f62b5bd8e8c603bca361e9cf47bFredrik Roubert } 173fe77e7203e518f62b5bd8e8c603bca361e9cf47bFredrik Roubert 174fe77e7203e518f62b5bd8e8c603bca361e9cf47bFredrik Roubert // The value "0" means that we need to use the default pattern and not fall back 175fe77e7203e518f62b5bd8e8c603bca361e9cf47bFredrik Roubert // to parent locales. Example locale where this is relevant: 'it'. 176fe77e7203e518f62b5bd8e8c603bca361e9cf47bFredrik Roubert String patternString = value.toString(); 177fe77e7203e518f62b5bd8e8c603bca361e9cf47bFredrik Roubert if (patternString.equals("0")) { 178fe77e7203e518f62b5bd8e8c603bca361e9cf47bFredrik Roubert patternString = USE_FALLBACK; 179fe77e7203e518f62b5bd8e8c603bca361e9cf47bFredrik Roubert } 180fe77e7203e518f62b5bd8e8c603bca361e9cf47bFredrik Roubert 181fe77e7203e518f62b5bd8e8c603bca361e9cf47bFredrik Roubert // Save the pattern string. We will parse it lazily. 182fe77e7203e518f62b5bd8e8c603bca361e9cf47bFredrik Roubert data.patterns[getIndex(magnitude, plural)] = patternString; 183fe77e7203e518f62b5bd8e8c603bca361e9cf47bFredrik Roubert 184fe77e7203e518f62b5bd8e8c603bca361e9cf47bFredrik Roubert // If necessary, compute the multiplier: the difference between the magnitude 185fe77e7203e518f62b5bd8e8c603bca361e9cf47bFredrik Roubert // and the number of zeros in the pattern. 186fe77e7203e518f62b5bd8e8c603bca361e9cf47bFredrik Roubert if (multiplier == 0) { 187fe77e7203e518f62b5bd8e8c603bca361e9cf47bFredrik Roubert int numZeros = countZeros(patternString); 188fe77e7203e518f62b5bd8e8c603bca361e9cf47bFredrik Roubert if (numZeros > 0) { // numZeros==0 in certain cases, like Somali "Kun" 189fe77e7203e518f62b5bd8e8c603bca361e9cf47bFredrik Roubert multiplier = (byte) (numZeros - magnitude - 1); 190fe77e7203e518f62b5bd8e8c603bca361e9cf47bFredrik Roubert } 191fe77e7203e518f62b5bd8e8c603bca361e9cf47bFredrik Roubert } 192fe77e7203e518f62b5bd8e8c603bca361e9cf47bFredrik Roubert } 193fe77e7203e518f62b5bd8e8c603bca361e9cf47bFredrik Roubert 194fe77e7203e518f62b5bd8e8c603bca361e9cf47bFredrik Roubert // Save the multiplier. 195fe77e7203e518f62b5bd8e8c603bca361e9cf47bFredrik Roubert if (data.multipliers[magnitude] == 0) { 196fe77e7203e518f62b5bd8e8c603bca361e9cf47bFredrik Roubert data.multipliers[magnitude] = multiplier; 197fe77e7203e518f62b5bd8e8c603bca361e9cf47bFredrik Roubert if (magnitude > data.largestMagnitude) { 198fe77e7203e518f62b5bd8e8c603bca361e9cf47bFredrik Roubert data.largestMagnitude = magnitude; 199fe77e7203e518f62b5bd8e8c603bca361e9cf47bFredrik Roubert } 200fe77e7203e518f62b5bd8e8c603bca361e9cf47bFredrik Roubert data.isEmpty = false; 201fe77e7203e518f62b5bd8e8c603bca361e9cf47bFredrik Roubert } else { 202fe77e7203e518f62b5bd8e8c603bca361e9cf47bFredrik Roubert assert data.multipliers[magnitude] == multiplier; 203fe77e7203e518f62b5bd8e8c603bca361e9cf47bFredrik Roubert } 204fe77e7203e518f62b5bd8e8c603bca361e9cf47bFredrik Roubert } 205fe77e7203e518f62b5bd8e8c603bca361e9cf47bFredrik Roubert } 206fe77e7203e518f62b5bd8e8c603bca361e9cf47bFredrik Roubert } 207fe77e7203e518f62b5bd8e8c603bca361e9cf47bFredrik Roubert 208fe77e7203e518f62b5bd8e8c603bca361e9cf47bFredrik Roubert private static final int getIndex(int magnitude, StandardPlural plural) { 209fe77e7203e518f62b5bd8e8c603bca361e9cf47bFredrik Roubert return magnitude * StandardPlural.COUNT + plural.ordinal(); 210fe77e7203e518f62b5bd8e8c603bca361e9cf47bFredrik Roubert } 211fe77e7203e518f62b5bd8e8c603bca361e9cf47bFredrik Roubert 212fe77e7203e518f62b5bd8e8c603bca361e9cf47bFredrik Roubert private static final int countZeros(String patternString) { 213fe77e7203e518f62b5bd8e8c603bca361e9cf47bFredrik Roubert // NOTE: This strategy for computing the number of zeros is a hack for efficiency. 214fe77e7203e518f62b5bd8e8c603bca361e9cf47bFredrik Roubert // It could break if there are any 0s that aren't part of the main pattern. 215fe77e7203e518f62b5bd8e8c603bca361e9cf47bFredrik Roubert int numZeros = 0; 216fe77e7203e518f62b5bd8e8c603bca361e9cf47bFredrik Roubert for (int i = 0; i < patternString.length(); i++) { 217fe77e7203e518f62b5bd8e8c603bca361e9cf47bFredrik Roubert if (patternString.charAt(i) == '0') { 218fe77e7203e518f62b5bd8e8c603bca361e9cf47bFredrik Roubert numZeros++; 219fe77e7203e518f62b5bd8e8c603bca361e9cf47bFredrik Roubert } else if (numZeros > 0) { 220fe77e7203e518f62b5bd8e8c603bca361e9cf47bFredrik Roubert break; // zeros should always be contiguous 221fe77e7203e518f62b5bd8e8c603bca361e9cf47bFredrik Roubert } 222fe77e7203e518f62b5bd8e8c603bca361e9cf47bFredrik Roubert } 223fe77e7203e518f62b5bd8e8c603bca361e9cf47bFredrik Roubert return numZeros; 224fe77e7203e518f62b5bd8e8c603bca361e9cf47bFredrik Roubert } 225fe77e7203e518f62b5bd8e8c603bca361e9cf47bFredrik Roubert} 226