1 /* GENERATED SOURCE. DO NOT MODIFY. */ 2 /* 3 ******************************************************************************* 4 * Copyright (C) 2009-2014, International Business Machines Corporation and * 5 * others. All Rights Reserved. * 6 ******************************************************************************* 7 */ 8 package android.icu.impl; 9 10 import java.util.ArrayList; 11 import java.util.Collections; 12 import java.util.HashSet; 13 import java.util.List; 14 import java.util.Set; 15 16 import android.icu.text.CurrencyMetaInfo; 17 import android.icu.util.Currency.CurrencyUsage; 18 19 /** 20 * ICU's currency meta info data. 21 * @hide Only a subset of ICU is exposed in Android 22 */ 23 public class ICUCurrencyMetaInfo extends CurrencyMetaInfo { 24 private ICUResourceBundle regionInfo; 25 private ICUResourceBundle digitInfo; 26 ICUCurrencyMetaInfo()27 public ICUCurrencyMetaInfo() { 28 ICUResourceBundle bundle = (ICUResourceBundle) ICUResourceBundle.getBundleInstance( 29 ICUResourceBundle.ICU_CURR_BASE_NAME, "supplementalData", 30 ICUResourceBundle.ICU_DATA_CLASS_LOADER); 31 regionInfo = bundle.findTopLevel("CurrencyMap"); 32 digitInfo = bundle.findTopLevel("CurrencyMeta"); 33 } 34 35 @Override currencyInfo(CurrencyFilter filter)36 public List<CurrencyInfo> currencyInfo(CurrencyFilter filter) { 37 return collect(new InfoCollector(), filter); 38 } 39 40 @Override currencies(CurrencyFilter filter)41 public List<String> currencies(CurrencyFilter filter) { 42 return collect(new CurrencyCollector(), filter); 43 } 44 45 @Override regions(CurrencyFilter filter)46 public List<String> regions(CurrencyFilter filter) { 47 return collect(new RegionCollector(), filter); 48 } 49 50 @Override currencyDigits(String isoCode)51 public CurrencyDigits currencyDigits(String isoCode) { 52 return currencyDigits(isoCode, CurrencyUsage.STANDARD); 53 } 54 55 @Override currencyDigits(String isoCode, CurrencyUsage currencyPurpose)56 public CurrencyDigits currencyDigits(String isoCode, CurrencyUsage currencyPurpose) { 57 ICUResourceBundle b = digitInfo.findWithFallback(isoCode); 58 if (b == null) { 59 b = digitInfo.findWithFallback("DEFAULT"); 60 } 61 int[] data = b.getIntVector(); 62 if (currencyPurpose == CurrencyUsage.CASH) { 63 return new CurrencyDigits(data[2], data[3]); 64 } else if (currencyPurpose == CurrencyUsage.STANDARD) { 65 return new CurrencyDigits(data[0], data[1]); 66 } else { 67 return new CurrencyDigits(data[0], data[1]); 68 } 69 } 70 collect(Collector<T> collector, CurrencyFilter filter)71 private <T> List<T> collect(Collector<T> collector, CurrencyFilter filter) { 72 // We rely on the fact that the data lists the regions in order, and the 73 // priorities in order within region. This means we don't need 74 // to sort the results to ensure the ordering matches the spec. 75 76 if (filter == null) { 77 filter = CurrencyFilter.all(); 78 } 79 int needed = collector.collects(); 80 if (filter.region != null) { 81 needed |= Region; 82 } 83 if (filter.currency != null) { 84 needed |= Currency; 85 } 86 if (filter.from != Long.MIN_VALUE || filter.to != Long.MAX_VALUE) { 87 needed |= Date; 88 } 89 if (filter.tenderOnly) { 90 needed |= Tender; 91 } 92 93 if (needed != 0) { 94 if (filter.region != null) { 95 ICUResourceBundle b = regionInfo.findWithFallback(filter.region); 96 if (b != null) { 97 collectRegion(collector, filter, needed, b); 98 } 99 } else { 100 for (int i = 0; i < regionInfo.getSize(); i++) { 101 collectRegion(collector, filter, needed, regionInfo.at(i)); 102 } 103 } 104 } 105 106 return collector.getList(); 107 } 108 collectRegion(Collector<T> collector, CurrencyFilter filter, int needed, ICUResourceBundle b)109 private <T> void collectRegion(Collector<T> collector, CurrencyFilter filter, 110 int needed, ICUResourceBundle b) { 111 112 String region = b.getKey(); 113 if (needed == Region) { 114 collector.collect(b.getKey(), null, 0, 0, -1, false); 115 return; 116 } 117 118 for (int i = 0; i < b.getSize(); i++) { 119 ICUResourceBundle r = b.at(i); 120 if (r.getSize() == 0) { 121 // AQ[0] is an empty array instead of a table, so the bundle is null. 122 // There's no data here, so we skip this entirely. 123 // We'd do a type test, but the ResourceArray type is private. 124 continue; 125 } 126 String currency = null; 127 long from = Long.MIN_VALUE; 128 long to = Long.MAX_VALUE; 129 boolean tender = true; 130 131 if ((needed & Currency) != 0) { 132 ICUResourceBundle currBundle = r.at("id"); 133 currency = currBundle.getString(); 134 if (filter.currency != null && !filter.currency.equals(currency)) { 135 continue; 136 } 137 } 138 139 if ((needed & Date) != 0) { 140 from = getDate(r.at("from"), Long.MIN_VALUE, false); 141 to = getDate(r.at("to"), Long.MAX_VALUE, true); 142 // In the data, to is always > from. This means that when we have a range 143 // from == to, the comparisons below will always do the right thing, despite 144 // the range being technically empty. It really should be [from, from+1) but 145 // this way we don't need to fiddle with it. 146 if (filter.from > to) { 147 continue; 148 } 149 if (filter.to < from) { 150 continue; 151 } 152 } 153 if ((needed & Tender) != 0) { 154 ICUResourceBundle tenderBundle = r.at("tender"); 155 tender = tenderBundle == null || "true".equals(tenderBundle.getString()); 156 if (filter.tenderOnly && !tender) { 157 continue; 158 } 159 } 160 161 // data lists elements in priority order, so 'i' suffices 162 collector.collect(region, currency, from, to, i, tender); 163 } 164 } 165 166 private static final long MASK = 4294967295L; getDate(ICUResourceBundle b, long defaultValue, boolean endOfDay)167 private long getDate(ICUResourceBundle b, long defaultValue, boolean endOfDay) { 168 if (b == null) { 169 return defaultValue; 170 } 171 int[] values = b.getIntVector(); 172 return ((long) values[0] << 32) | (((long) values[1]) & MASK); 173 } 174 175 // Utility, just because I don't like the n^2 behavior of using list.contains to build a 176 // list of unique items. If we used java 6 we could use their class for this. 177 private static class UniqueList<T> { 178 private Set<T> seen = new HashSet<T>(); 179 private List<T> list = new ArrayList<T>(); 180 create()181 private static <T> UniqueList<T> create() { 182 return new UniqueList<T>(); 183 } 184 add(T value)185 void add(T value) { 186 if (!seen.contains(value)) { 187 list.add(value); 188 seen.add(value); 189 } 190 } 191 list()192 List<T> list() { 193 return Collections.unmodifiableList(list); 194 } 195 } 196 197 private static class InfoCollector implements Collector<CurrencyInfo> { 198 // Data is already unique by region/priority, so we don't need to be concerned 199 // about duplicates. 200 private List<CurrencyInfo> result = new ArrayList<CurrencyInfo>(); 201 collect(String region, String currency, long from, long to, int priority, boolean tender)202 public void collect(String region, String currency, long from, long to, int priority, boolean tender) { 203 result.add(new CurrencyInfo(region, currency, from, to, priority, tender)); 204 } 205 getList()206 public List<CurrencyInfo> getList() { 207 return Collections.unmodifiableList(result); 208 } 209 collects()210 public int collects() { 211 return Everything; 212 } 213 } 214 215 private static class RegionCollector implements Collector<String> { 216 private final UniqueList<String> result = UniqueList.create(); 217 collect( String region, String currency, long from, long to, int priority, boolean tender)218 public void collect( 219 String region, String currency, long from, long to, int priority, boolean tender) { 220 result.add(region); 221 } 222 collects()223 public int collects() { 224 return Region; 225 } 226 getList()227 public List<String> getList() { 228 return result.list(); 229 } 230 } 231 232 private static class CurrencyCollector implements Collector<String> { 233 private final UniqueList<String> result = UniqueList.create(); 234 collect( String region, String currency, long from, long to, int priority, boolean tender)235 public void collect( 236 String region, String currency, long from, long to, int priority, boolean tender) { 237 result.add(currency); 238 } 239 collects()240 public int collects() { 241 return Currency; 242 } 243 getList()244 public List<String> getList() { 245 return result.list(); 246 } 247 } 248 249 private static final int Region = 1; 250 private static final int Currency = 2; 251 private static final int Date = 4; 252 private static final int Tender = 8; 253 private static final int Everything = Integer.MAX_VALUE; 254 255 private static interface Collector<T> { 256 /** 257 * A bitmask of Region/Currency/Date indicating which features we collect. 258 * @return the bitmask 259 */ collects()260 int collects(); 261 262 /** 263 * Called with data passed by filter. Values not collected by filter should be ignored. 264 * @param region the region code (null if ignored) 265 * @param currency the currency code (null if ignored) 266 * @param from start time (0 if ignored) 267 * @param to end time (0 if ignored) 268 * @param priority priority (-1 if ignored) 269 * @param tender true if currency is legal tender. 270 */ collect(String region, String currency, long from, long to, int priority, boolean tender)271 void collect(String region, String currency, long from, long to, int priority, boolean tender); 272 273 /** 274 * Return the list of unique items in the order in which we encountered them for the 275 * first time. The returned list is unmodifiable. 276 * @return the list 277 */ getList()278 List<T> getList(); 279 } 280 } 281