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