• Home
  • Line#
  • Scopes#
  • Navigate#
  • Raw
  • Download
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) 2013-2015, International Business Machines Corporation and
7  * others. All Rights Reserved.
8  *******************************************************************************
9  */
10 package ohos.global.icu.text;
11 
12 import java.util.ArrayList;
13 import java.util.Collection;
14 import java.util.Collections;
15 import java.util.HashMap;
16 import java.util.HashSet;
17 import java.util.LinkedHashSet;
18 import java.util.List;
19 import java.util.Map;
20 import java.util.Map.Entry;
21 import java.util.Set;
22 import java.util.TreeSet;
23 
24 import ohos.global.icu.text.PluralRules.FixedDecimal;
25 import ohos.global.icu.text.PluralRules.KeywordStatus;
26 import ohos.global.icu.util.Output;
27 
28 /**
29  * @author markdavis
30  * Refactor samples as first step to moving into CLDR
31  *
32  * @deprecated This API is ICU internal only.
33  * @hide exposed on OHOS
34  * @hide draft / provisional / internal are hidden on OHOS
35  */
36 @Deprecated
37 public class PluralSamples {
38 
39     private PluralRules pluralRules;
40     private final Map<String, List<Double>> _keySamplesMap;
41 
42     /**
43      * @deprecated This API is ICU internal only.
44      * @hide draft / provisional / internal are hidden on OHOS
45      */
46     @Deprecated
47     public final Map<String, Boolean> _keyLimitedMap;
48     private final Map<String, Set<FixedDecimal>> _keyFractionSamplesMap;
49     private final Set<FixedDecimal> _fractionSamples;
50 
51     /**
52      * @deprecated This API is ICU internal only.
53      * @hide draft / provisional / internal are hidden on OHOS
54      */
55     @Deprecated
PluralSamples(PluralRules pluralRules)56     public PluralSamples(PluralRules pluralRules) {
57         this.pluralRules = pluralRules;
58         Set<String> keywords = pluralRules.getKeywords();
59         // ensure both _keySamplesMap and _keyLimitedMap are initialized.
60         // If this were allowed to vary on a per-call basis, we'd have to recheck and
61         // possibly rebuild the samples cache.  Doesn't seem worth it.
62         // This 'max samples' value only applies to keywords that are unlimited, for
63         // other keywords all the matching values are returned.  This might be a lot.
64         final int MAX_SAMPLES = 3;
65 
66         Map<String, Boolean> temp = new HashMap<String, Boolean>();
67         for (String k : keywords) {
68             temp.put(k, pluralRules.isLimited(k));
69         }
70         _keyLimitedMap = temp;
71 
72         Map<String, List<Double>> sampleMap = new HashMap<String, List<Double>>();
73         int keywordsRemaining = keywords.size();
74 
75         int limit = 128; // Math.max(5, getRepeatLimit() * MAX_SAMPLES) * 2;
76 
77         for (int i = 0; keywordsRemaining > 0 && i < limit; ++i) {
78             keywordsRemaining = addSimpleSamples(pluralRules, MAX_SAMPLES, sampleMap, keywordsRemaining, i / 2.0);
79         }
80         // Hack for Celtic
81         keywordsRemaining = addSimpleSamples(pluralRules, MAX_SAMPLES, sampleMap, keywordsRemaining, 1000000);
82 
83 
84         // collect explicit samples
85         Map<String, Set<FixedDecimal>> sampleFractionMap = new HashMap<String, Set<FixedDecimal>>();
86         Set<FixedDecimal> mentioned = new TreeSet<FixedDecimal>();
87         // make sure that there is at least one 'other' value
88         Map<String, Set<FixedDecimal>> foundKeywords = new HashMap<String, Set<FixedDecimal>>();
89         for (FixedDecimal s : mentioned) {
90             String keyword = pluralRules.select(s);
91             addRelation(foundKeywords, keyword, s);
92         }
93         main:
94             if (foundKeywords.size() != keywords.size()) {
95                 for (int i = 1; i < 1000; ++i) {
96                     boolean done = addIfNotPresent(i, mentioned, foundKeywords);
97                     if (done) break main;
98                 }
99                 // if we are not done, try tenths
100                 for (int i = 10; i < 1000; ++i) {
101                     boolean done = addIfNotPresent(i/10d, mentioned, foundKeywords);
102                     if (done) break main;
103                 }
104                 System.out.println("Failed to find sample for each keyword: " + foundKeywords + "\n\t" + pluralRules + "\n\t" + mentioned);
105             }
106         mentioned.add(new FixedDecimal(0)); // always there
107         mentioned.add(new FixedDecimal(1)); // always there
108         mentioned.add(new FixedDecimal(2)); // always there
109         mentioned.add(new FixedDecimal(0.1,1)); // always there
110         mentioned.add(new FixedDecimal(1.99,2)); // always there
111         mentioned.addAll(fractions(mentioned));
112         for (FixedDecimal s : mentioned) {
113             String keyword = pluralRules.select(s);
114             Set<FixedDecimal> list = sampleFractionMap.get(keyword);
115             if (list == null) {
116                 list = new LinkedHashSet<FixedDecimal>(); // will be sorted because the iteration is
117                 sampleFractionMap.put(keyword, list);
118             }
119             list.add(s);
120         }
121 
122         if (keywordsRemaining > 0) {
123             for (String k : keywords) {
124                 if (!sampleMap.containsKey(k)) {
125                     sampleMap.put(k, Collections.<Double>emptyList());
126                 }
127                 if (!sampleFractionMap.containsKey(k)) {
128                     sampleFractionMap.put(k, Collections.<FixedDecimal>emptySet());
129                 }
130             }
131         }
132 
133         // Make lists immutable so we can return them directly
134         for (Entry<String, List<Double>> entry : sampleMap.entrySet()) {
135             sampleMap.put(entry.getKey(), Collections.unmodifiableList(entry.getValue()));
136         }
137         for (Entry<String, Set<FixedDecimal>> entry : sampleFractionMap.entrySet()) {
138             sampleFractionMap.put(entry.getKey(), Collections.unmodifiableSet(entry.getValue()));
139         }
140         _keySamplesMap = sampleMap;
141         _keyFractionSamplesMap = sampleFractionMap;
142         _fractionSamples = Collections.unmodifiableSet(mentioned);
143     }
144 
addSimpleSamples(PluralRules pluralRules, final int MAX_SAMPLES, Map<String, List<Double>> sampleMap, int keywordsRemaining, double val)145     private int addSimpleSamples(PluralRules pluralRules, final int MAX_SAMPLES, Map<String, List<Double>> sampleMap,
146             int keywordsRemaining, double val) {
147         String keyword = pluralRules.select(val);
148         boolean keyIsLimited = _keyLimitedMap.get(keyword);
149 
150         List<Double> list = sampleMap.get(keyword);
151         if (list == null) {
152             list = new ArrayList<Double>(MAX_SAMPLES);
153             sampleMap.put(keyword, list);
154         } else if (!keyIsLimited && list.size() == MAX_SAMPLES) {
155             return keywordsRemaining;
156         }
157         list.add(Double.valueOf(val));
158 
159         if (!keyIsLimited && list.size() == MAX_SAMPLES) {
160             --keywordsRemaining;
161         }
162         return keywordsRemaining;
163     }
164 
addRelation(Map<String, Set<FixedDecimal>> foundKeywords, String keyword, FixedDecimal s)165     private void addRelation(Map<String, Set<FixedDecimal>> foundKeywords, String keyword, FixedDecimal s) {
166         Set<FixedDecimal> set = foundKeywords.get(keyword);
167         if (set == null) {
168             foundKeywords.put(keyword, set = new HashSet<FixedDecimal>());
169         }
170         set.add(s);
171     }
172 
addIfNotPresent(double d, Set<FixedDecimal> mentioned, Map<String, Set<FixedDecimal>> foundKeywords)173     private boolean addIfNotPresent(double d, Set<FixedDecimal> mentioned, Map<String, Set<FixedDecimal>> foundKeywords) {
174         FixedDecimal numberInfo = new FixedDecimal(d);
175         String keyword = pluralRules.select(numberInfo);
176         if (!foundKeywords.containsKey(keyword) || keyword.equals("other")) {
177             addRelation(foundKeywords, keyword, numberInfo);
178             mentioned.add(numberInfo);
179             if (keyword.equals("other")) {
180                 if (foundKeywords.get("other").size() > 1) {
181                     return true;
182                 }
183             }
184         }
185         return false;
186     }
187 
188     private static final int[] TENS = {1, 10, 100, 1000, 10000, 100000, 1000000};
189 
190     private static final int LIMIT_FRACTION_SAMPLES = 3;
191 
192 
fractions(Set<FixedDecimal> original)193     private Set<FixedDecimal> fractions(Set<FixedDecimal> original) {
194         Set<FixedDecimal> toAddTo = new HashSet<FixedDecimal>();
195 
196         Set<Integer> result = new HashSet<Integer>();
197         for (FixedDecimal base1 : original) {
198             result.add((int)base1.integerValue);
199         }
200         List<Integer> ints = new ArrayList<Integer>(result);
201         Set<String> keywords = new HashSet<String>();
202 
203         for (int j = 0; j < ints.size(); ++j) {
204             Integer base = ints.get(j);
205             String keyword = pluralRules.select(base);
206             if (keywords.contains(keyword)) {
207                 continue;
208             }
209             keywords.add(keyword);
210             toAddTo.add(new FixedDecimal(base,1)); // add .0
211             toAddTo.add(new FixedDecimal(base,2)); // add .00
212             Integer fract = getDifferentCategory(ints, keyword);
213             if (fract >= TENS[LIMIT_FRACTION_SAMPLES-1]) { // make sure that we always get the value
214                 toAddTo.add(new FixedDecimal(base + "." + fract));
215             } else {
216                 for (int visibleFractions = 1; visibleFractions < LIMIT_FRACTION_SAMPLES; ++visibleFractions) {
217                     for (int i = 1; i <= visibleFractions; ++i) {
218                         // with visible fractions = 3, and fract = 1, then we should get x.10, 0.01
219                         // with visible fractions = 3, and fract = 15, then we should get x.15, x.15
220                         if (fract >= TENS[i]) {
221                             continue;
222                         }
223                         toAddTo.add(new FixedDecimal(base + fract/(double)TENS[i], visibleFractions));
224                     }
225                 }
226             }
227         }
228         return toAddTo;
229     }
230 
getDifferentCategory(List<Integer> ints, String keyword)231     private Integer getDifferentCategory(List<Integer> ints, String keyword) {
232         for (int i = ints.size() - 1; i >= 0; --i) {
233             Integer other = ints.get(i);
234             String keywordOther = pluralRules.select(other);
235             if (!keywordOther.equals(keyword)) {
236                 return other;
237             }
238         }
239         return 37;
240     }
241 
242     /**
243      * @deprecated This API is ICU internal only.
244      * @hide draft / provisional / internal are hidden on OHOS
245      */
246     @Deprecated
getStatus(String keyword, int offset, Set<Double> explicits, Output<Double> uniqueValue)247     public KeywordStatus getStatus(String keyword, int offset, Set<Double> explicits, Output<Double> uniqueValue) {
248         if (uniqueValue != null) {
249             uniqueValue.value = null;
250         }
251 
252         if (!pluralRules.getKeywords().contains(keyword)) {
253             return KeywordStatus.INVALID;
254         }
255         Collection<Double> values = pluralRules.getAllKeywordValues(keyword);
256         if (values == null) {
257             return KeywordStatus.UNBOUNDED;
258         }
259         int originalSize = values.size();
260 
261         if (explicits == null) {
262             explicits = Collections.emptySet();
263         }
264 
265         // Quick check on whether there are multiple elements
266 
267         if (originalSize > explicits.size()) {
268             if (originalSize == 1) {
269                 if (uniqueValue != null) {
270                     uniqueValue.value = values.iterator().next();
271                 }
272                 return KeywordStatus.UNIQUE;
273             }
274             return KeywordStatus.BOUNDED;
275         }
276 
277         // Compute if the quick test is insufficient.
278 
279         HashSet<Double> subtractedSet = new HashSet<Double>(values);
280         for (Double explicit : explicits) {
281             subtractedSet.remove(explicit - offset);
282         }
283         if (subtractedSet.size() == 0) {
284             return KeywordStatus.SUPPRESSED;
285         }
286 
287         if (uniqueValue != null && subtractedSet.size() == 1) {
288             uniqueValue.value = subtractedSet.iterator().next();
289         }
290 
291         return originalSize == 1 ? KeywordStatus.UNIQUE : KeywordStatus.BOUNDED;
292     }
293 
getKeySamplesMap()294     Map<String, List<Double>> getKeySamplesMap() {
295         return _keySamplesMap;
296     }
297 
getKeyFractionSamplesMap()298     Map<String, Set<FixedDecimal>> getKeyFractionSamplesMap() {
299         return _keyFractionSamplesMap;
300     }
301 
getFractionSamples()302     Set<FixedDecimal> getFractionSamples() {
303         return _fractionSamples;
304     }
305 
306     /**
307      * Returns all the values that trigger this keyword, or null if the number of such
308      * values is unlimited.
309      *
310      * @param keyword the keyword
311      * @return the values that trigger this keyword, or null.  The returned collection
312      * is immutable. It will be empty if the keyword is not defined.
313      */
314 
getAllKeywordValues(String keyword)315     Collection<Double> getAllKeywordValues(String keyword) {
316         // HACK for now
317         if (!pluralRules.getKeywords().contains(keyword)) {
318             return Collections.<Double>emptyList();
319         }
320         Collection<Double> result = getKeySamplesMap().get(keyword);
321 
322         // We depend on MAX_SAMPLES here.  It's possible for a conjunction
323         // of unlimited rules that 'looks' unlimited to return a limited
324         // number of values.  There's no bounds to this limited number, in
325         // general, because you can construct arbitrarily complex rules.  Since
326         // we always generate 3 samples if a rule is really unlimited, that's
327         // where we put the cutoff.
328         if (result.size() > 2 && !_keyLimitedMap.get(keyword)) {
329             return null;
330         }
331         return result;
332     }
333 }
334