12d2bb24f747c65578da13d5b13b82f0669690461Fredrik Roubert// © 2016 and later: Unicode, Inc. and others. 22d2bb24f747c65578da13d5b13b82f0669690461Fredrik Roubert// License & terms of use: http://www.unicode.org/copyright.html#License 37935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubert/* 47935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubert ******************************************************************************* 503f16b04d95bbaa98f702b69791b0de29ac75915Yoshito Umaoka * Copyright (C) 2007-2016, International Business Machines Corporation and 67935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubert * others. All Rights Reserved. 77935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubert ******************************************************************************* 87935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubert */ 97935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubert 107935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubertpackage com.ibm.icu.text; 117935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubert 127935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubertimport java.io.IOException; 137935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubertimport java.io.NotSerializableException; 147935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubertimport java.io.ObjectInputStream; 157935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubertimport java.io.ObjectOutputStream; 167935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubertimport java.io.ObjectStreamException; 177935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubertimport java.io.Serializable; 187935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubertimport java.text.ParseException; 197935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubertimport java.util.ArrayList; 207935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubertimport java.util.Collection; 217935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubertimport java.util.Collections; 227935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubertimport java.util.HashSet; 237935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubertimport java.util.Iterator; 247935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubertimport java.util.LinkedHashSet; 257935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubertimport java.util.List; 267935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubertimport java.util.Locale; 277935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubertimport java.util.Set; 287935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubertimport java.util.TreeSet; 297935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubertimport java.util.regex.Pattern; 307935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubert 317935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubertimport com.ibm.icu.impl.PluralRulesLoader; 327935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubertimport com.ibm.icu.util.Output; 337935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubertimport com.ibm.icu.util.ULocale; 347935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubert 357935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubert/** 367935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubert * <p> 377935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubert * Defines rules for mapping non-negative numeric values onto a small set of keywords. 387935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubert * </p> 397935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubert * <p> 407935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubert * Rules are constructed from a text description, consisting of a series of keywords and conditions. The {@link #select} 417935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubert * method examines each condition in order and returns the keyword for the first condition that matches the number. If 427935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubert * none match, {@link #KEYWORD_OTHER} is returned. 437935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubert * </p> 447935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubert * <p> 457935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubert * A PluralRules object is immutable. It contains caches for sample values, but those are synchronized. 467935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubert * <p> 477935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubert * PluralRules is Serializable so that it can be used in formatters, which are serializable. 487935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubert * </p> 497935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubert * <p> 507935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubert * For more information, details, and tips for writing rules, see the <a 517935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubert * href="http://www.unicode.org/draft/reports/tr35/tr35.html#Language_Plural_Rules">LDML spec, C.11 Language Plural 527935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubert * Rules</a> 537935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubert * </p> 547935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubert * <p> 557935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubert * Examples: 567935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubert * </p> 572d2bb24f747c65578da13d5b13b82f0669690461Fredrik Roubert * 587935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubert * <pre> 597935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubert * "one: n is 1; few: n in 2..4" 607935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubert * </pre> 617935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubert * <p> 627935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubert * This defines two rules, for 'one' and 'few'. The condition for 'one' is "n is 1" which means that the number must be 637935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubert * equal to 1 for this condition to pass. The condition for 'few' is "n in 2..4" which means that the number must be 647935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubert * between 2 and 4 inclusive - and be an integer - for this condition to pass. All other numbers are assigned the 657935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubert * keyword "other" by the default rule. 667935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubert * </p> 672d2bb24f747c65578da13d5b13b82f0669690461Fredrik Roubert * 687935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubert * <pre> 697935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubert * "zero: n is 0; one: n is 1; zero: n mod 100 in 1..19" 707935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubert * </pre> 717935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubert * <p> 727935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubert * This illustrates that the same keyword can be defined multiple times. Each rule is examined in order, and the first 737935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubert * keyword whose condition passes is the one returned. Also notes that a modulus is applied to n in the last rule. Thus 747935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubert * its condition holds for 119, 219, 319... 757935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubert * </p> 762d2bb24f747c65578da13d5b13b82f0669690461Fredrik Roubert * 777935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubert * <pre> 787935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubert * "one: n is 1; few: n mod 10 in 2..4 and n mod 100 not in 12..14" 797935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubert * </pre> 807935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubert * <p> 817935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubert * This illustrates conjunction and negation. The condition for 'few' has two parts, both of which must be met: 827935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubert * "n mod 10 in 2..4" and "n mod 100 not in 12..14". The first part applies a modulus to n before the test as in the 837935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubert * previous example. The second part applies a different modulus and also uses negation, thus it matches all numbers 847935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubert * _not_ in 12, 13, 14, 112, 113, 114, 212, 213, 214... 857935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubert * </p> 867935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubert * <p> 877935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubert * Syntax: 887935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubert * </p> 897935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubert * <pre> 907935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubert * rules = rule (';' rule)* 917935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubert * rule = keyword ':' condition 927935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubert * keyword = <identifier> 937935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubert * condition = and_condition ('or' and_condition)* 947935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubert * and_condition = relation ('and' relation)* 957935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubert * relation = not? expr not? rel not? range_list 967935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubert * expr = ('n' | 'i' | 'f' | 'v' | 't') (mod value)? 977935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubert * not = 'not' | '!' 987935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubert * rel = 'in' | 'is' | '=' | '≠' | 'within' 997935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubert * mod = 'mod' | '%' 1007935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubert * range_list = (range | value) (',' range_list)* 1017935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubert * value = digit+ 1027935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubert * digit = 0|1|2|3|4|5|6|7|8|9 1037935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubert * range = value'..'value 1047935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubert * </pre> 1057935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubert * <p>Each <b>not</b> term inverts the meaning; however, there should not be more than one of them.</p> 1067935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubert * <p> 1077935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubert * The i, f, t, and v values are defined as follows: 1087935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubert * </p> 1097935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubert * <ul> 1107935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubert * <li>i to be the integer digits.</li> 1117935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubert * <li>f to be the visible decimal digits, as an integer.</li> 1127935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubert * <li>t to be the visible decimal digits—without trailing zeros—as an integer.</li> 1137935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubert * <li>v to be the number of visible fraction digits.</li> 1147935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubert * <li>j is defined to only match integers. That is j is 3 fails if v != 0 (eg for 3.1 or 3.0).</li> 1157935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubert * </ul> 1167935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubert * <p> 1177935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubert * Examples are in the following table: 1187935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubert * </p> 1197935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubert * <table border='1' style="border-collapse:collapse"> 1207935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubert * <tbody> 1217935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubert * <tr> 1227935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubert * <th>n</th> 1237935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubert * <th>i</th> 1247935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubert * <th>f</th> 1257935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubert * <th>v</th> 1267935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubert * </tr> 1277935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubert * <tr> 1287935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubert * <td>1.0</td> 1297935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubert * <td>1</td> 1307935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubert * <td align="right">0</td> 1317935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubert * <td>1</td> 1327935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubert * </tr> 1337935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubert * <tr> 1347935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubert * <td>1.00</td> 1357935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubert * <td>1</td> 1367935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubert * <td align="right">0</td> 1377935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubert * <td>2</td> 1387935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubert * </tr> 1397935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubert * <tr> 1407935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubert * <td>1.3</td> 1417935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubert * <td>1</td> 1427935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubert * <td align="right">3</td> 1437935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubert * <td>1</td> 1447935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubert * </tr> 1457935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubert * <tr> 1467935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubert * <td>1.03</td> 1477935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubert * <td>1</td> 1487935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubert * <td align="right">3</td> 1497935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubert * <td>2</td> 1507935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubert * </tr> 1517935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubert * <tr> 1527935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubert * <td>1.23</td> 1537935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubert * <td>1</td> 1547935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubert * <td align="right">23</td> 1557935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubert * <td>2</td> 1567935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubert * </tr> 1577935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubert * </tbody> 1587935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubert * </table> 1597935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubert * <p> 1607935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubert * An "identifier" is a sequence of characters that do not have the Unicode Pattern_Syntax or Pattern_White_Space 1617935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubert * properties. 1627935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubert * <p> 1637935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubert * The difference between 'in' and 'within' is that 'in' only includes integers in the specified range, while 'within' 1647935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubert * includes all values. Using 'within' with a range_list consisting entirely of values is the same as using 'in' (it's 1657935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubert * not an error). 1667935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubert * </p> 1672d2bb24f747c65578da13d5b13b82f0669690461Fredrik Roubert * 1687935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubert * @stable ICU 3.8 1697935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubert */ 1707935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubertpublic class PluralRules implements Serializable { 1717935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubert 1727935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubert static final UnicodeSet ALLOWED_ID = new UnicodeSet("[a-z]").freeze(); 1737935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubert 1747935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubert // TODO Remove RulesList by moving its API and fields into PluralRules. 1757935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubert /** 1767935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubert * @internal 1777935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubert * @deprecated This API is ICU internal only. 1787935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubert */ 1797935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubert @Deprecated 1807935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubert public static final String CATEGORY_SEPARATOR = "; "; 1817935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubert /** 1827935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubert * @internal 1837935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubert * @deprecated This API is ICU internal only. 1847935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubert */ 1857935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubert @Deprecated 1867935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubert public static final String KEYWORD_RULE_SEPARATOR = ": "; 1877935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubert 1887935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubert private static final long serialVersionUID = 1; 1897935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubert 1907935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubert private final RuleList rules; 1917935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubert private final transient Set<String> keywords; 1927935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubert 1937935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubert /** 1947935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubert * Provides a factory for returning plural rules 1952d2bb24f747c65578da13d5b13b82f0669690461Fredrik Roubert * 1967935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubert * @internal 1977935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubert * @deprecated This API is ICU internal only. 1987935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubert */ 1997935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubert @Deprecated 2007935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubert public static abstract class Factory { 2017935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubert /** 2027935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubert * Sole constructor 2037935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubert * @internal 2047935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubert * @deprecated This API is ICU internal only. 2057935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubert */ 2067935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubert @Deprecated 2077935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubert protected Factory() { 2087935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubert } 2097935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubert 2107935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubert /** 2117935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubert * Provides access to the predefined <code>PluralRules</code> for a given locale and the plural type. 2122d2bb24f747c65578da13d5b13b82f0669690461Fredrik Roubert * 2137935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubert * <p> 2147935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubert * ICU defines plural rules for many locales based on CLDR <i>Language Plural Rules</i>. For these predefined 2157935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubert * rules, see CLDR page at http://unicode.org/repos/cldr-tmp/trunk/diff/supplemental/language_plural_rules.html 2162d2bb24f747c65578da13d5b13b82f0669690461Fredrik Roubert * 2177935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubert * @param locale 2187935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubert * The locale for which a <code>PluralRules</code> object is returned. 2197935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubert * @param type 2207935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubert * The plural type (e.g., cardinal or ordinal). 2217935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubert * @return The predefined <code>PluralRules</code> object for this locale. If there's no predefined rules for 2227935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubert * this locale, the rules for the closest parent in the locale hierarchy that has one will be returned. 2237935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubert * The final fallback always returns the default rules. 2247935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubert * @internal 2257935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubert * @deprecated This API is ICU internal only. 2267935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubert */ 2277935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubert @Deprecated 2287935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubert public abstract PluralRules forLocale(ULocale locale, PluralType type); 2297935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubert 2307935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubert /** 2317935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubert * Utility for getting CARDINAL rules. 2327935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubert * @param locale the locale 2337935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubert * @return plural rules. 2347935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubert * @internal 2357935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubert * @deprecated This API is ICU internal only. 2367935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubert */ 2377935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubert @Deprecated 2387935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubert public final PluralRules forLocale(ULocale locale) { 2397935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubert return forLocale(locale, PluralType.CARDINAL); 2407935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubert } 2417935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubert 2427935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubert /** 2437935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubert * Returns the locales for which there is plurals data. 2442d2bb24f747c65578da13d5b13b82f0669690461Fredrik Roubert * 2457935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubert * @internal 2467935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubert * @deprecated This API is ICU internal only. 2477935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubert */ 2487935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubert @Deprecated 2497935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubert public abstract ULocale[] getAvailableULocales(); 2507935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubert 2517935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubert /** 2527935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubert * Returns the 'functionally equivalent' locale with respect to plural rules. Calling PluralRules.forLocale with 253bee65486a185907111f3be60992433e133ec0e32Scott Russell * the functionally equivalent locale, and with the provided locale, returns rules that behave the same. <br> 2547935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubert * All locales with the same functionally equivalent locale have plural rules that behave the same. This is not 2557935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubert * exaustive; there may be other locales whose plural rules behave the same that do not have the same equivalent 2567935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubert * locale. 2572d2bb24f747c65578da13d5b13b82f0669690461Fredrik Roubert * 2587935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubert * @param locale 2597935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubert * the locale to check 2607935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubert * @param isAvailable 261bee65486a185907111f3be60992433e133ec0e32Scott Russell * if not null and of length > 0, this will hold 'true' at index 0 if locale is directly defined 2627935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubert * (without fallback) as having plural rules 2637935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubert * @return the functionally-equivalent locale 2647935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubert * @internal 2657935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubert * @deprecated This API is ICU internal only. 2667935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubert */ 2677935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubert @Deprecated 2687935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubert public abstract ULocale getFunctionalEquivalent(ULocale locale, boolean[] isAvailable); 2697935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubert 2707935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubert /** 2717935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubert * Returns the default factory. 2727935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubert * @internal 2737935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubert * @deprecated This API is ICU internal only. 2747935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubert */ 2757935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubert @Deprecated 2767935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubert public static PluralRulesLoader getDefaultFactory() { 2777935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubert return PluralRulesLoader.loader; 2787935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubert } 2797935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubert 2807935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubert /** 2817935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubert * Returns whether or not there are overrides. 2827935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubert * @internal 2837935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubert * @deprecated This API is ICU internal only. 2847935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubert */ 2857935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubert @Deprecated 2867935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubert public abstract boolean hasOverride(ULocale locale); 2877935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubert } 2887935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubert // Standard keywords. 2897935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubert 2907935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubert /** 2917935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubert * Common name for the 'zero' plural form. 2927935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubert * @stable ICU 3.8 2937935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubert */ 2947935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubert public static final String KEYWORD_ZERO = "zero"; 2957935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubert 2967935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubert /** 2977935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubert * Common name for the 'singular' plural form. 2987935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubert * @stable ICU 3.8 2997935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubert */ 3007935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubert public static final String KEYWORD_ONE = "one"; 3017935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubert 3027935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubert /** 3037935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubert * Common name for the 'dual' plural form. 3047935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubert * @stable ICU 3.8 3057935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubert */ 3067935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubert public static final String KEYWORD_TWO = "two"; 3077935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubert 3087935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubert /** 3097935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubert * Common name for the 'paucal' or other special plural form. 3107935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubert * @stable ICU 3.8 3117935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubert */ 3127935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubert public static final String KEYWORD_FEW = "few"; 3137935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubert 3147935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubert /** 3157935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubert * Common name for the arabic (11 to 99) plural form. 3167935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubert * @stable ICU 3.8 3177935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubert */ 3187935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubert public static final String KEYWORD_MANY = "many"; 3197935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubert 3207935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubert /** 3217935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubert * Common name for the default plural form. This name is returned 3227935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubert * for values to which no other form in the rule applies. It 3237935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubert * can additionally be assigned rules of its own. 3247935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubert * @stable ICU 3.8 3257935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubert */ 3267935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubert public static final String KEYWORD_OTHER = "other"; 3277935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubert 3287935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubert /** 3297935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubert * Value returned by {@link #getUniqueKeywordValue} when there is no 3307935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubert * unique value to return. 3317935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubert * @stable ICU 4.8 3327935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubert */ 3337935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubert public static final double NO_UNIQUE_VALUE = -0.00123456777; 3347935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubert 3357935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubert /** 3367935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubert * Type of plurals and PluralRules. 3377935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubert * @stable ICU 50 3387935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubert */ 3397935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubert public enum PluralType { 3407935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubert /** 3417935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubert * Plural rules for cardinal numbers: 1 file vs. 2 files. 3427935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubert * @stable ICU 50 3437935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubert */ 3447935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubert CARDINAL, 3457935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubert /** 3467935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubert * Plural rules for ordinal numbers: 1st file, 2nd file, 3rd file, 4th file, etc. 3477935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubert * @stable ICU 50 3487935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubert */ 3497935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubert ORDINAL 3507935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubert }; 3517935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubert 3527935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubert /* 3537935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubert * The default constraint that is always satisfied. 3547935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubert */ 3557935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubert private static final Constraint NO_CONSTRAINT = new Constraint() { 3567935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubert private static final long serialVersionUID = 9163464945387899416L; 3577935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubert 3582d2bb24f747c65578da13d5b13b82f0669690461Fredrik Roubert @Override 3597935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubert public boolean isFulfilled(FixedDecimal n) { 3607935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubert return true; 3617935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubert } 3627935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubert 3632d2bb24f747c65578da13d5b13b82f0669690461Fredrik Roubert @Override 3647935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubert public boolean isLimited(SampleType sampleType) { 3657935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubert return false; 3667935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubert } 3677935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubert 3682d2bb24f747c65578da13d5b13b82f0669690461Fredrik Roubert @Override 3697935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubert public String toString() { 3707935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubert return ""; 3717935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubert } 3727935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubert }; 3737935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubert 3747935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubert /** 3752d2bb24f747c65578da13d5b13b82f0669690461Fredrik Roubert * 3767935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubert */ 3777935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubert private static final Rule DEFAULT_RULE = new Rule("other", NO_CONSTRAINT, null, null); 3787935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubert 3797935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubert /** 3807935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubert * Parses a plural rules description and returns a PluralRules. 3817935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubert * @param description the rule description. 3827935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubert * @throws ParseException if the description cannot be parsed. 3837935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubert * The exception index is typically not set, it will be -1. 3847935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubert * @stable ICU 3.8 3857935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubert */ 3867935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubert public static PluralRules parseDescription(String description) 3877935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubert throws ParseException { 3887935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubert 3897935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubert description = description.trim(); 3907935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubert return description.length() == 0 ? DEFAULT : new PluralRules(parseRuleChain(description)); 3917935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubert } 3927935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubert 3937935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubert /** 3947935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubert * Creates a PluralRules from a description if it is parsable, 3957935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubert * otherwise returns null. 3967935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubert * @param description the rule description. 3977935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubert * @return the PluralRules 3987935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubert * @stable ICU 3.8 3997935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubert */ 4007935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubert public static PluralRules createRules(String description) { 4017935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubert try { 4027935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubert return parseDescription(description); 4037935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubert } catch(Exception e) { 4047935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubert return null; 4057935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubert } 4067935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubert } 4077935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubert 4087935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubert /** 4097935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubert * The default rules that accept any number and return 4107935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubert * {@link #KEYWORD_OTHER}. 4117935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubert * @stable ICU 3.8 4127935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubert */ 4137935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubert public static final PluralRules DEFAULT = new PluralRules(new RuleList().addRule(DEFAULT_RULE)); 4147935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubert 4157935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubert private enum Operand { 4167935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubert n, 4177935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubert i, 4187935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubert f, 4197935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubert t, 4207935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubert v, 4217935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubert w, 4227935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubert /* deprecated */ 4237935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubert j; 4247935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubert } 4257935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubert 4267935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubert /** 4277935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubert * @internal 4287935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubert * @deprecated This API is ICU internal only. 4297935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubert */ 4307935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubert @Deprecated 4317935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubert public static class FixedDecimal extends Number implements Comparable<FixedDecimal> { 4327935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubert private static final long serialVersionUID = -4756200506571685661L; 4337935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubert /** 4347935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubert * @internal 4357935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubert * @deprecated This API is ICU internal only. 4367935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubert */ 4377935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubert @Deprecated 4387935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubert public final double source; 4397935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubert /** 4407935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubert * @internal 4417935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubert * @deprecated This API is ICU internal only. 4427935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubert */ 4437935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubert @Deprecated 4447935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubert public final int visibleDecimalDigitCount; 4457935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubert /** 4467935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubert * @internal 4477935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubert * @deprecated This API is ICU internal only. 4487935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubert */ 4497935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubert @Deprecated 4507935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubert public final int visibleDecimalDigitCountWithoutTrailingZeros; 4517935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubert /** 4527935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubert * @internal 4537935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubert * @deprecated This API is ICU internal only. 4547935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubert */ 4557935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubert @Deprecated 4567935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubert public final long decimalDigits; 4577935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubert /** 4587935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubert * @internal 4597935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubert * @deprecated This API is ICU internal only. 4607935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubert */ 4617935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubert @Deprecated 4627935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubert public final long decimalDigitsWithoutTrailingZeros; 4637935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubert /** 4647935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubert * @internal 4657935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubert * @deprecated This API is ICU internal only. 4667935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubert */ 4677935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubert @Deprecated 4687935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubert public final long integerValue; 4697935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubert /** 4707935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubert * @internal 4717935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubert * @deprecated This API is ICU internal only. 4727935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubert */ 4737935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubert @Deprecated 4747935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubert public final boolean hasIntegerValue; 4757935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubert /** 4767935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubert * @internal 4777935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubert * @deprecated This API is ICU internal only. 4787935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubert */ 4797935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubert @Deprecated 4807935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubert public final boolean isNegative; 4817935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubert private final int baseFactor; 4827935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubert 4837935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubert /** 4847935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubert * @internal 4857935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubert * @deprecated This API is ICU internal only. 4867935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubert */ 4877935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubert @Deprecated 4887935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubert public double getSource() { 4897935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubert return source; 4907935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubert } 4917935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubert 4927935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubert /** 4937935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubert * @internal 4947935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubert * @deprecated This API is ICU internal only. 4957935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubert */ 4967935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubert @Deprecated 4977935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubert public int getVisibleDecimalDigitCount() { 4987935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubert return visibleDecimalDigitCount; 4997935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubert } 5007935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubert 5017935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubert /** 5027935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubert * @internal 5037935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubert * @deprecated This API is ICU internal only. 5047935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubert */ 5057935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubert @Deprecated 5067935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubert public int getVisibleDecimalDigitCountWithoutTrailingZeros() { 5077935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubert return visibleDecimalDigitCountWithoutTrailingZeros; 5087935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubert } 5097935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubert 5107935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubert /** 5117935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubert * @internal 5127935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubert * @deprecated This API is ICU internal only. 5137935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubert */ 5147935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubert @Deprecated 5157935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubert public long getDecimalDigits() { 5167935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubert return decimalDigits; 5177935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubert } 5187935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubert 5197935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubert /** 5207935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubert * @internal 5217935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubert * @deprecated This API is ICU internal only. 5227935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubert */ 5237935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubert @Deprecated 5247935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubert public long getDecimalDigitsWithoutTrailingZeros() { 5257935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubert return decimalDigitsWithoutTrailingZeros; 5267935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubert } 5277935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubert 5287935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubert /** 5297935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubert * @internal 5307935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubert * @deprecated This API is ICU internal only. 5317935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubert */ 5327935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubert @Deprecated 5337935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubert public long getIntegerValue() { 5347935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubert return integerValue; 5357935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubert } 5367935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubert 5377935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubert /** 5387935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubert * @internal 5397935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubert * @deprecated This API is ICU internal only. 5407935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubert */ 5417935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubert @Deprecated 5427935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubert public boolean isHasIntegerValue() { 5437935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubert return hasIntegerValue; 5447935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubert } 5457935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubert 5467935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubert /** 5477935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubert * @internal 5487935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubert * @deprecated This API is ICU internal only. 5497935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubert */ 5507935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubert @Deprecated 5517935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubert public boolean isNegative() { 5527935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubert return isNegative; 5537935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubert } 5547935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubert 5557935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubert /** 5567935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubert * @internal 5577935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubert * @deprecated This API is ICU internal only. 5587935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubert */ 5597935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubert @Deprecated 5607935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubert public int getBaseFactor() { 5617935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubert return baseFactor; 5627935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubert } 5637935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubert 5647935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubert static final long MAX = (long)1E18; 5657935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubert 5667935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubert /** 5677935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubert * @internal 5687935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubert * @deprecated This API is ICU internal only. 5697935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubert * @param n is the original number 5707935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubert * @param v number of digits to the right of the decimal place. e.g 1.00 = 2 25. = 0 5717935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubert * @param f Corresponds to f in the plural rules grammar. 5727935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubert * The digits to the right of the decimal place as an integer. e.g 1.10 = 10 5737935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubert */ 5747935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubert @Deprecated 5757935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubert public FixedDecimal(double n, int v, long f) { 5767935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubert isNegative = n < 0; 5777935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubert source = isNegative ? -n : n; 5787935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubert visibleDecimalDigitCount = v; 5797935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubert decimalDigits = f; 5802d2bb24f747c65578da13d5b13b82f0669690461Fredrik Roubert integerValue = n > MAX 5812d2bb24f747c65578da13d5b13b82f0669690461Fredrik Roubert ? MAX 5827935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubert : (long)n; 5837935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubert hasIntegerValue = source == integerValue; 5847935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubert // check values. TODO make into unit test. 5852d2bb24f747c65578da13d5b13b82f0669690461Fredrik Roubert // 5867935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubert // long visiblePower = (int) Math.pow(10, v); 5877935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubert // if (fractionalDigits > visiblePower) { 5887935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubert // throw new IllegalArgumentException(); 5897935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubert // } 5907935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubert // double fraction = intValue + (fractionalDigits / (double) visiblePower); 5917935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubert // if (fraction != source) { 5927935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubert // double diff = Math.abs(fraction - source)/(Math.abs(fraction) + Math.abs(source)); 5937935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubert // if (diff > 0.00000001d) { 5947935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubert // throw new IllegalArgumentException(); 5957935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubert // } 5967935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubert // } 5977935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubert if (f == 0) { 5987935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubert decimalDigitsWithoutTrailingZeros = 0; 5997935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubert visibleDecimalDigitCountWithoutTrailingZeros = 0; 6007935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubert } else { 6017935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubert long fdwtz = f; 6027935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubert int trimmedCount = v; 6037935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubert while ((fdwtz%10) == 0) { 6047935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubert fdwtz /= 10; 6057935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubert --trimmedCount; 6067935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubert } 6077935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubert decimalDigitsWithoutTrailingZeros = fdwtz; 6087935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubert visibleDecimalDigitCountWithoutTrailingZeros = trimmedCount; 6097935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubert } 6107935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubert baseFactor = (int) Math.pow(10, v); 6117935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubert } 6127935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubert 6137935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubert /** 6147935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubert * @internal 6157935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubert * @deprecated This API is ICU internal only. 6167935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubert */ 6177935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubert @Deprecated 6187935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubert public FixedDecimal(double n, int v) { 6197935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubert this(n,v,getFractionalDigits(n, v)); 6207935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubert } 6217935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubert 6227935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubert private static int getFractionalDigits(double n, int v) { 6237935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubert if (v == 0) { 6247935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubert return 0; 6257935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubert } else { 6267935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubert if (n < 0) { 6277935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubert n = -n; 6287935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubert } 6297935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubert int baseFactor = (int) Math.pow(10, v); 6307935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubert long scaled = Math.round(n * baseFactor); 6317935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubert return (int) (scaled % baseFactor); 6327935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubert } 6337935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubert } 6347935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubert 6357935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubert /** 6367935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubert * @internal 6377935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubert * @deprecated This API is ICU internal only. 6387935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubert */ 6397935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubert @Deprecated 6407935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubert public FixedDecimal(double n) { 6417935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubert this(n, decimals(n)); 6427935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubert } 6437935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubert 6447935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubert /** 6457935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubert * @internal 6467935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubert * @deprecated This API is ICU internal only. 6477935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubert */ 6487935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubert @Deprecated 6497935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubert public FixedDecimal(long n) { 6507935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubert this(n,0); 6517935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubert } 6527935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubert 6537935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubert private static final long MAX_INTEGER_PART = 1000000000; 6547935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubert /** 6557935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubert * Return a guess as to the number of decimals that would be displayed. This is only a guess; callers should 6567935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubert * always supply the decimals explicitly if possible. Currently, it is up to 6 decimals (without trailing zeros). 6577935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubert * Returns 0 for infinities and nans. 6587935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubert * @internal 6597935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubert * @deprecated This API is ICU internal only. 6602d2bb24f747c65578da13d5b13b82f0669690461Fredrik Roubert * 6617935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubert */ 6627935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubert @Deprecated 6637935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubert public static int decimals(double n) { 6647935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubert // Ugly... 6657935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubert if (Double.isInfinite(n) || Double.isNaN(n)) { 6667935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubert return 0; 6677935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubert } 6687935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubert if (n < 0) { 6697935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubert n = -n; 6707935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubert } 6717935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubert if (n == Math.floor(n)) { 6727935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubert return 0; 6737935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubert } 6747935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubert if (n < MAX_INTEGER_PART) { 6757935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubert long temp = (long)(n * 1000000) % 1000000; // get 6 decimals 6767935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubert for (int mask = 10, digits = 6; digits > 0; mask *= 10, --digits) { 6777935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubert if ((temp % mask) != 0) { 6787935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubert return digits; 6797935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubert } 6807935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubert } 6817935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubert return 0; 6827935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubert } else { 6837935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubert String buf = String.format(Locale.ENGLISH, "%1.15e", n); 6847935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubert int ePos = buf.lastIndexOf('e'); 6857935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubert int expNumPos = ePos + 1; 6867935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubert if (buf.charAt(expNumPos) == '+') { 6877935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubert expNumPos++; 6887935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubert } 6897935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubert String exponentStr = buf.substring(expNumPos); 6907935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubert int exponent = Integer.parseInt(exponentStr); 6917935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubert int numFractionDigits = ePos - 2 - exponent; 6927935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubert if (numFractionDigits < 0) { 6937935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubert return 0; 6947935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubert } 6957935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubert for (int i=ePos-1; numFractionDigits > 0; --i) { 6967935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubert if (buf.charAt(i) != '0') { 6977935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubert break; 6987935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubert } 6992d2bb24f747c65578da13d5b13b82f0669690461Fredrik Roubert --numFractionDigits; 7007935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubert } 7017935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubert return numFractionDigits; 7027935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubert } 7037935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubert } 7047935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubert 7057935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubert /** 7067935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubert * @internal 7077935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubert * @deprecated This API is ICU internal only. 7087935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubert */ 7097935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubert @Deprecated 7107935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubert public FixedDecimal (String n) { 7117935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubert // Ugly, but for samples we don't care. 7127935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubert this(Double.parseDouble(n), getVisibleFractionCount(n)); 7137935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubert } 7147935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubert 7157935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubert private static int getVisibleFractionCount(String value) { 7167935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubert value = value.trim(); 7177935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubert int decimalPos = value.indexOf('.') + 1; 7187935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubert if (decimalPos == 0) { 7197935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubert return 0; 7207935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubert } else { 7217935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubert return value.length() - decimalPos; 7227935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubert } 7237935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubert } 7247935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubert 7257935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubert /** 7267935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubert * @internal 7277935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubert * @deprecated This API is ICU internal only. 7287935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubert */ 7297935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubert @Deprecated 7307935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubert public double get(Operand operand) { 7317935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubert switch(operand) { 7327935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubert default: return source; 7337935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubert case i: return integerValue; 7347935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubert case f: return decimalDigits; 7357935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubert case t: return decimalDigitsWithoutTrailingZeros; 7367935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubert case v: return visibleDecimalDigitCount; 7377935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubert case w: return visibleDecimalDigitCountWithoutTrailingZeros; 7387935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubert } 7397935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubert } 7407935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubert 7417935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubert /** 7427935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubert * @internal 7437935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubert * @deprecated This API is ICU internal only. 7447935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubert */ 7457935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubert @Deprecated 7467935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubert public static Operand getOperand(String t) { 7477935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubert return Operand.valueOf(t); 7487935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubert } 7497935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubert 7507935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubert /** 7517935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubert * We're not going to care about NaN. 7527935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubert * @internal 7537935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubert * @deprecated This API is ICU internal only. 7547935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubert */ 7552d2bb24f747c65578da13d5b13b82f0669690461Fredrik Roubert @Override 7567935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubert @Deprecated 7577935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubert public int compareTo(FixedDecimal other) { 7587935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubert if (integerValue != other.integerValue) { 7597935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubert return integerValue < other.integerValue ? -1 : 1; 7607935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubert } 7617935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubert if (source != other.source) { 7627935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubert return source < other.source ? -1 : 1; 7637935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubert } 7647935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubert if (visibleDecimalDigitCount != other.visibleDecimalDigitCount) { 7657935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubert return visibleDecimalDigitCount < other.visibleDecimalDigitCount ? -1 : 1; 7667935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubert } 7677935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubert long diff = decimalDigits - other.decimalDigits; 7687935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubert if (diff != 0) { 7697935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubert return diff < 0 ? -1 : 1; 7707935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubert } 7717935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubert return 0; 7727935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubert } 7737935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubert 7747935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubert /** 7757935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubert * @internal 7767935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubert * @deprecated This API is ICU internal only. 7777935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubert */ 7787935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubert @Deprecated 7797935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubert @Override 7807935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubert public boolean equals(Object arg0) { 7817935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubert if (arg0 == null) { 7827935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubert return false; 7837935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubert } 7847935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubert if (arg0 == this) { 7857935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubert return true; 7867935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubert } 7877935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubert if (!(arg0 instanceof FixedDecimal)) { 7887935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubert return false; 7897935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubert } 7907935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubert FixedDecimal other = (FixedDecimal)arg0; 7917935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubert return source == other.source && visibleDecimalDigitCount == other.visibleDecimalDigitCount && decimalDigits == other.decimalDigits; 7927935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubert } 7937935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubert 7947935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubert /** 7957935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubert * @internal 7967935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubert * @deprecated This API is ICU internal only. 7977935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubert */ 7987935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubert @Deprecated 7997935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubert @Override 8007935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubert public int hashCode() { 8017935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubert // TODO Auto-generated method stub 8027935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubert return (int)(decimalDigits + 37 * (visibleDecimalDigitCount + (int)(37 * source))); 8037935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubert } 8047935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubert 8057935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubert /** 8067935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubert * @internal 8077935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubert * @deprecated This API is ICU internal only. 8087935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubert */ 8097935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubert @Deprecated 8107935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubert @Override 8117935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubert public String toString() { 8127935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubert return String.format("%." + visibleDecimalDigitCount + "f", source); 8137935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubert } 8147935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubert 8157935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubert /** 8167935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubert * @internal 8177935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubert * @deprecated This API is ICU internal only. 8187935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubert */ 8197935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubert @Deprecated 8207935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubert public boolean hasIntegerValue() { 8217935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubert return hasIntegerValue; 8227935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubert } 8237935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubert 8247935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubert /** 8257935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubert * @internal 8267935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubert * @deprecated This API is ICU internal only. 8277935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubert */ 8287935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubert @Deprecated 8297935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubert @Override 8307935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubert public int intValue() { 8317935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubert // TODO Auto-generated method stub 8327935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubert return (int)integerValue; 8337935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubert } 8347935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubert 8357935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubert /** 8367935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubert * @internal 8377935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubert * @deprecated This API is ICU internal only. 8387935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubert */ 8397935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubert @Deprecated 8407935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubert @Override 8417935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubert public long longValue() { 8427935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubert return integerValue; 8437935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubert } 8447935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubert 8457935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubert /** 8467935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubert * @internal 8477935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubert * @deprecated This API is ICU internal only. 8487935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubert */ 8497935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubert @Deprecated 8507935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubert @Override 8517935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubert public float floatValue() { 8527935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubert return (float) source; 8537935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubert } 8547935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubert 8557935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubert /** 8567935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubert * @internal 8577935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubert * @deprecated This API is ICU internal only. 8587935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubert */ 8597935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubert @Deprecated 8607935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubert @Override 8617935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubert public double doubleValue() { 8627935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubert return isNegative ? -source : source; 8637935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubert } 8647935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubert 8657935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubert /** 8667935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubert * @internal 8677935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubert * @deprecated This API is ICU internal only. 8687935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubert */ 8697935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubert @Deprecated 8707935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubert public long getShiftedValue() { 8717935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubert return integerValue * baseFactor + decimalDigits; 8727935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubert } 8737935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubert 8747935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubert private void writeObject( 8757935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubert ObjectOutputStream out) 8767935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubert throws IOException { 8777935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubert throw new NotSerializableException(); 8787935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubert } 8797935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubert 8807935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubert private void readObject(ObjectInputStream in 8817935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubert ) throws IOException, ClassNotFoundException { 8827935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubert throw new NotSerializableException(); 8837935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubert } 8847935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubert } 8857935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubert 8867935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubert /** 8877935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubert * Selection parameter for either integer-only or decimal-only. 8887935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubert * @internal 8897935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubert * @deprecated This API is ICU internal only. 8907935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubert */ 8917935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubert @Deprecated 8927935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubert public enum SampleType { 8937935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubert /** 8947935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubert * @internal 8957935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubert * @deprecated This API is ICU internal only. 8967935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubert */ 8977935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubert @Deprecated 8987935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubert INTEGER, 8997935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubert /** 9007935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubert * @internal 9017935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubert * @deprecated This API is ICU internal only. 9027935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubert */ 9037935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubert @Deprecated 9047935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubert DECIMAL 9057935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubert } 9067935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubert 9077935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubert /** 9087935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubert * A range of NumberInfo that includes all values with the same visibleFractionDigitCount. 9097935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubert * @internal 9107935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubert * @deprecated This API is ICU internal only. 9117935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubert */ 9127935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubert @Deprecated 9137935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubert public static class FixedDecimalRange { 9147935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubert /** 9157935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubert * @internal 9167935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubert * @deprecated This API is ICU internal only. 9177935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubert */ 9187935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubert @Deprecated 9197935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubert public final FixedDecimal start; 9207935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubert /** 9217935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubert * @internal 9227935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubert * @deprecated This API is ICU internal only. 9237935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubert */ 9247935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubert @Deprecated 9257935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubert public final FixedDecimal end; 9267935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubert /** 9277935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubert * @internal 9287935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubert * @deprecated This API is ICU internal only. 9297935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubert */ 9307935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubert @Deprecated 9317935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubert public FixedDecimalRange(FixedDecimal start, FixedDecimal end) { 9327935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubert if (start.visibleDecimalDigitCount != end.visibleDecimalDigitCount) { 9337935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubert throw new IllegalArgumentException("Ranges must have the same number of visible decimals: " + start + "~" + end); 9347935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubert } 9357935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubert this.start = start; 9367935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubert this.end = end; 9377935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubert } 9387935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubert /** 9397935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubert * @internal 9407935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubert * @deprecated This API is ICU internal only. 9417935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubert */ 9427935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubert @Deprecated 9437935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubert @Override 9447935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubert public String toString() { 9457935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubert return start + (end == start ? "" : "~" + end); 9467935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubert } 9477935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubert } 9487935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubert 9497935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubert /** 9507935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubert * A list of NumberInfo that includes all values with the same visibleFractionDigitCount. 9517935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubert * @internal 9527935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubert * @deprecated This API is ICU internal only. 9537935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubert */ 9547935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubert @Deprecated 9557935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubert public static class FixedDecimalSamples { 9567935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubert /** 9577935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubert * @internal 9587935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubert * @deprecated This API is ICU internal only. 9597935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubert */ 9607935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubert @Deprecated 9617935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubert public final SampleType sampleType; 9627935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubert /** 9637935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubert * @internal 9647935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubert * @deprecated This API is ICU internal only. 9657935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubert */ 9667935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubert @Deprecated 9677935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubert public final Set<FixedDecimalRange> samples; 9687935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubert /** 9697935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubert * @internal 9707935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubert * @deprecated This API is ICU internal only. 9717935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubert */ 9727935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubert @Deprecated 9737935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubert public final boolean bounded; 9747935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubert /** 9757935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubert * The samples must be immutable. 9767935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubert * @param sampleType 9777935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubert * @param samples 9787935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubert */ 9797935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubert private FixedDecimalSamples(SampleType sampleType, Set<FixedDecimalRange> samples, boolean bounded) { 9807935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubert super(); 9817935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubert this.sampleType = sampleType; 9827935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubert this.samples = samples; 9837935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubert this.bounded = bounded; 9847935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubert } 9857935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubert /* 9867935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubert * Parse a list of the form described in CLDR. The source must be trimmed. 9877935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubert */ 9887935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubert static FixedDecimalSamples parse(String source) { 9897935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubert SampleType sampleType2; 9907935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubert boolean bounded2 = true; 9917935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubert boolean haveBound = false; 9927935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubert Set<FixedDecimalRange> samples2 = new LinkedHashSet<FixedDecimalRange>(); 9937935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubert 9947935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubert if (source.startsWith("integer")) { 9957935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubert sampleType2 = SampleType.INTEGER; 9967935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubert } else if (source.startsWith("decimal")) { 9977935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubert sampleType2 = SampleType.DECIMAL; 9987935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubert } else { 9997935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubert throw new IllegalArgumentException("Samples must start with 'integer' or 'decimal'"); 10007935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubert } 10017935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubert source = source.substring(7).trim(); // remove both 10027935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubert 10037935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubert for (String range : COMMA_SEPARATED.split(source)) { 10047935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubert if (range.equals("…") || range.equals("...")) { 10057935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubert bounded2 = false; 10067935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubert haveBound = true; 10077935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubert continue; 10087935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubert } 10097935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubert if (haveBound) { 10107935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubert throw new IllegalArgumentException("Can only have … at the end of samples: " + range); 10117935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubert } 10127935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubert String[] rangeParts = TILDE_SEPARATED.split(range); 10137935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubert switch (rangeParts.length) { 10142d2bb24f747c65578da13d5b13b82f0669690461Fredrik Roubert case 1: 10157935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubert FixedDecimal sample = new FixedDecimal(rangeParts[0]); 10167935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubert checkDecimal(sampleType2, sample); 10177935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubert samples2.add(new FixedDecimalRange(sample, sample)); 10187935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubert break; 10197935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubert case 2: 10207935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubert FixedDecimal start = new FixedDecimal(rangeParts[0]); 10217935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubert FixedDecimal end = new FixedDecimal(rangeParts[1]); 10227935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubert checkDecimal(sampleType2, start); 10237935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubert checkDecimal(sampleType2, end); 10247935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubert samples2.add(new FixedDecimalRange(start, end)); 10257935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubert break; 10267935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubert default: throw new IllegalArgumentException("Ill-formed number range: " + range); 10277935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubert } 10287935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubert } 10297935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubert return new FixedDecimalSamples(sampleType2, Collections.unmodifiableSet(samples2), bounded2); 10307935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubert } 10317935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubert 10327935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubert private static void checkDecimal(SampleType sampleType2, FixedDecimal sample) { 10337935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubert if ((sampleType2 == SampleType.INTEGER) != (sample.getVisibleDecimalDigitCount() == 0)) { 10342d2bb24f747c65578da13d5b13b82f0669690461Fredrik Roubert throw new IllegalArgumentException("Ill-formed number range: " + sample); 10357935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubert } 10367935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubert } 10377935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubert 10387935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubert /** 10397935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubert * @internal 10407935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubert * @deprecated This API is ICU internal only. 10417935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubert */ 10427935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubert @Deprecated 10437935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubert public Set<Double> addSamples(Set<Double> result) { 10447935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubert for (FixedDecimalRange item : samples) { 10457935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubert // we have to convert to longs so we don't get strange double issues 10467935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubert long startDouble = item.start.getShiftedValue(); 10477935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubert long endDouble = item.end.getShiftedValue(); 10487935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubert 10497935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubert for (long d = startDouble; d <= endDouble; d += 1) { 10507935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubert result.add(d/(double)item.start.baseFactor); 10517935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubert } 10527935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubert } 10537935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubert return result; 10547935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubert } 10557935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubert 10567935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubert /** 10577935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubert * @internal 10587935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubert * @deprecated This API is ICU internal only. 10597935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubert */ 10607935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubert @Deprecated 10617935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubert @Override 10627935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubert public String toString() { 10637935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubert StringBuilder b = new StringBuilder("@").append(sampleType.toString().toLowerCase(Locale.ENGLISH)); 10647935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubert boolean first = true; 10657935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubert for (FixedDecimalRange item : samples) { 10667935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubert if (first) { 10677935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubert first = false; 10687935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubert } else { 10697935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubert b.append(","); 10707935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubert } 10717935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubert b.append(' ').append(item); 10727935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubert } 10737935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubert if (!bounded) { 10747935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubert b.append(", …"); 10757935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubert } 10767935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubert return b.toString(); 10777935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubert } 10787935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubert 10797935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubert /** 10807935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubert * @internal 10817935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubert * @deprecated This API is ICU internal only. 10827935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubert */ 10837935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubert @Deprecated 10847935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubert public Set<FixedDecimalRange> getSamples() { 10857935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubert return samples; 10867935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubert } 10877935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubert 10887935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubert /** 10897935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubert * @internal 10907935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubert * @deprecated This API is ICU internal only. 10917935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubert */ 10927935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubert @Deprecated 10937935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubert public void getStartEndSamples(Set<FixedDecimal> target) { 10947935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubert for (FixedDecimalRange item : samples) { 10957935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubert target.add(item.start); 10967935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubert target.add(item.end); 10977935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubert } 10987935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubert } 10997935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubert } 11007935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubert 11017935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubert /* 11027935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubert * A constraint on a number. 11037935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubert */ 11047935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubert private interface Constraint extends Serializable { 11057935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubert /* 11067935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubert * Returns true if the number fulfills the constraint. 11077935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubert * @param n the number to test, >= 0. 11087935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubert */ 11097935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubert boolean isFulfilled(FixedDecimal n); 11107935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubert 11117935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubert /* 11127935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubert * Returns false if an unlimited number of values fulfills the 11137935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubert * constraint. 11147935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubert */ 11157935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubert boolean isLimited(SampleType sampleType); 11167935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubert } 11177935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubert 11187935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubert static class SimpleTokenizer { 11197935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubert static final UnicodeSet BREAK_AND_IGNORE = new UnicodeSet(0x09, 0x0a, 0x0c, 0x0d, 0x20, 0x20).freeze(); 11207935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubert static final UnicodeSet BREAK_AND_KEEP = new UnicodeSet('!', '!', '%', '%', ',', ',', '.', '.', '=', '=').freeze(); 11217935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubert static String[] split(String source) { 11227935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubert int last = -1; 11237935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubert List<String> result = new ArrayList<String>(); 11247935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubert for (int i = 0; i < source.length(); ++i) { 11257935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubert char ch = source.charAt(i); 11267935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubert if (BREAK_AND_IGNORE.contains(ch)) { 11277935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubert if (last >= 0) { 11287935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubert result.add(source.substring(last,i)); 11297935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubert last = -1; 11307935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubert } 11317935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubert } else if (BREAK_AND_KEEP.contains(ch)) { 11327935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubert if (last >= 0) { 11337935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubert result.add(source.substring(last,i)); 11347935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubert } 11357935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubert result.add(source.substring(i,i+1)); 11367935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubert last = -1; 11377935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubert } else if (last < 0) { 11387935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubert last = i; 11397935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubert } 11407935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubert } 11417935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubert if (last >= 0) { 11427935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubert result.add(source.substring(last)); 11437935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubert } 11447935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubert return result.toArray(new String[result.size()]); 11457935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubert } 11467935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubert } 11477935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubert 11487935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubert /* 11497935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubert * syntax: 11507935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubert * condition : or_condition 11517935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubert * and_condition 11527935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubert * or_condition : and_condition 'or' condition 11537935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubert * and_condition : relation 11547935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubert * relation 'and' relation 11557935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubert * relation : in_relation 11567935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubert * within_relation 11577935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubert * in_relation : not? expr not? in not? range 11587935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubert * within_relation : not? expr not? 'within' not? range 11597935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubert * not : 'not' 11607935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubert * '!' 11617935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubert * expr : 'n' 11627935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubert * 'n' mod value 11637935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubert * mod : 'mod' 11647935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubert * '%' 11657935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubert * in : 'in' 11667935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubert * 'is' 11677935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubert * '=' 11687935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubert * '≠' 11697935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubert * value : digit+ 11707935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubert * digit : 0|1|2|3|4|5|6|7|8|9 11717935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubert * range : value'..'value 11727935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubert */ 11737935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubert private static Constraint parseConstraint(String description) 11747935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubert throws ParseException { 11757935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubert 11767935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubert Constraint result = null; 11777935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubert String[] or_together = OR_SEPARATED.split(description); 11787935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubert for (int i = 0; i < or_together.length; ++i) { 11797935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubert Constraint andConstraint = null; 11807935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubert String[] and_together = AND_SEPARATED.split(or_together[i]); 11817935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubert for (int j = 0; j < and_together.length; ++j) { 11827935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubert Constraint newConstraint = NO_CONSTRAINT; 11837935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubert 11847935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubert String condition = and_together[j].trim(); 11857935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubert String[] tokens = SimpleTokenizer.split(condition); 11867935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubert 11877935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubert int mod = 0; 11887935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubert boolean inRange = true; 11897935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubert boolean integersOnly = true; 11907935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubert double lowBound = Long.MAX_VALUE; 11917935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubert double highBound = Long.MIN_VALUE; 11927935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubert long[] vals = null; 11937935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubert 11947935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubert int x = 0; 11957935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubert String t = tokens[x++]; 11967935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubert boolean hackForCompatibility = false; 11977935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubert Operand operand; 11987935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubert try { 11997935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubert operand = FixedDecimal.getOperand(t); 12007935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubert } catch (Exception e) { 12017935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubert throw unexpected(t, condition); 12027935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubert } 12037935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubert if (x < tokens.length) { 12047935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubert t = tokens[x++]; 12057935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubert if ("mod".equals(t) || "%".equals(t)) { 12067935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubert mod = Integer.parseInt(tokens[x++]); 12077935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubert t = nextToken(tokens, x++, condition); 12087935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubert } 12097935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubert if ("not".equals(t)) { 12107935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubert inRange = !inRange; 12117935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubert t = nextToken(tokens, x++, condition); 12127935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubert if ("=".equals(t)) { 12137935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubert throw unexpected(t, condition); 12147935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubert } 12157935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubert } else if ("!".equals(t)) { 12167935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubert inRange = !inRange; 12177935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubert t = nextToken(tokens, x++, condition); 12187935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubert if (!"=".equals(t)) { 12197935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubert throw unexpected(t, condition); 12207935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubert } 12217935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubert } 12227935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubert if ("is".equals(t) || "in".equals(t) || "=".equals(t)) { 12237935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubert hackForCompatibility = "is".equals(t); 12247935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubert if (hackForCompatibility && !inRange) { 12257935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubert throw unexpected(t, condition); 12267935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubert } 12277935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubert t = nextToken(tokens, x++, condition); 12287935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubert } else if ("within".equals(t)) { 12297935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubert integersOnly = false; 12307935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubert t = nextToken(tokens, x++, condition); 12317935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubert } else { 12327935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubert throw unexpected(t, condition); 12337935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubert } 12347935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubert if ("not".equals(t)) { 12357935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubert if (!hackForCompatibility && !inRange) { 12367935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubert throw unexpected(t, condition); 12377935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubert } 12387935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubert inRange = !inRange; 12397935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubert t = nextToken(tokens, x++, condition); 12407935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubert } 12417935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubert 12427935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubert List<Long> valueList = new ArrayList<Long>(); 12437935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubert 12447935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubert // the token t is always one item ahead 12457935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubert while (true) { 12467935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubert long low = Long.parseLong(t); 12477935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubert long high = low; 12487935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubert if (x < tokens.length) { 12497935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubert t = nextToken(tokens, x++, condition); 12507935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubert if (t.equals(".")) { 12517935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubert t = nextToken(tokens, x++, condition); 12527935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubert if (!t.equals(".")) { 12537935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubert throw unexpected(t, condition); 12547935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubert } 12557935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubert t = nextToken(tokens, x++, condition); 12567935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubert high = Long.parseLong(t); 12577935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubert if (x < tokens.length) { 12587935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubert t = nextToken(tokens, x++, condition); 12597935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubert if (!t.equals(",")) { // adjacent number: 1 2 12607935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubert // no separator, fail 12617935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubert throw unexpected(t, condition); 12622d2bb24f747c65578da13d5b13b82f0669690461Fredrik Roubert } 12637935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubert } 12647935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubert } else if (!t.equals(",")) { // adjacent number: 1 2 12657935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubert // no separator, fail 12667935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubert throw unexpected(t, condition); 12677935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubert } 12687935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubert } 12697935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubert // at this point, either we are out of tokens, or t is ',' 12707935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubert if (low > high) { 12717935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubert throw unexpected(low + "~" + high, condition); 12727935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubert } else if (mod != 0 && high >= mod) { 12737935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubert throw unexpected(high + ">mod=" + mod, condition); 12747935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubert } 12757935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubert valueList.add(low); 12767935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubert valueList.add(high); 12777935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubert lowBound = Math.min(lowBound, low); 12787935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubert highBound = Math.max(highBound, high); 12797935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubert if (x >= tokens.length) { 12807935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubert break; 12817935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubert } 12827935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubert t = nextToken(tokens, x++, condition); 12837935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubert } 12847935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubert 12857935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubert if (t.equals(",")) { 12867935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubert throw unexpected(t, condition); 12877935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubert } 12887935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubert 12897935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubert if (valueList.size() == 2) { 12907935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubert vals = null; 12917935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubert } else { 12927935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubert vals = new long[valueList.size()]; 12937935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubert for (int k = 0; k < vals.length; ++k) { 12947935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubert vals[k] = valueList.get(k); 12957935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubert } 12967935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubert } 12977935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubert 12987935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubert // Hack to exclude "is not 1,2" 12997935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubert if (lowBound != highBound && hackForCompatibility && !inRange) { 13007935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubert throw unexpected("is not <range>", condition); 13017935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubert } 13027935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubert 13037935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubert newConstraint = 13047935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubert new RangeConstraint(mod, inRange, operand, integersOnly, lowBound, highBound, vals); 13057935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubert } 13067935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubert 13077935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubert if (andConstraint == null) { 13087935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubert andConstraint = newConstraint; 13097935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubert } else { 13107935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubert andConstraint = new AndConstraint(andConstraint, 13117935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubert newConstraint); 13127935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubert } 13137935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubert } 13147935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubert 13157935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubert if (result == null) { 13167935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubert result = andConstraint; 13177935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubert } else { 13187935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubert result = new OrConstraint(result, andConstraint); 13197935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubert } 13207935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubert } 13217935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubert return result; 13227935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubert } 13237935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubert 13247935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubert static final Pattern AT_SEPARATED = Pattern.compile("\\s*\\Q\\E@\\s*"); 13257935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubert static final Pattern OR_SEPARATED = Pattern.compile("\\s*or\\s*"); 13267935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubert static final Pattern AND_SEPARATED = Pattern.compile("\\s*and\\s*"); 13277935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubert static final Pattern COMMA_SEPARATED = Pattern.compile("\\s*,\\s*"); 13287935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubert static final Pattern DOTDOT_SEPARATED = Pattern.compile("\\s*\\Q..\\E\\s*"); 13297935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubert static final Pattern TILDE_SEPARATED = Pattern.compile("\\s*~\\s*"); 13307935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubert static final Pattern SEMI_SEPARATED = Pattern.compile("\\s*;\\s*"); 13317935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubert 13327935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubert 13337935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubert /* Returns a parse exception wrapping the token and context strings. */ 13347935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubert private static ParseException unexpected(String token, String context) { 13357935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubert return new ParseException("unexpected token '" + token + 13367935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubert "' in '" + context + "'", -1); 13377935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubert } 13387935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubert 13397935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubert /* 13407935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubert * Returns the token at x if available, else throws a parse exception. 13417935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubert */ 13427935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubert private static String nextToken(String[] tokens, int x, String context) 13437935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubert throws ParseException { 13447935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubert if (x < tokens.length) { 13457935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubert return tokens[x]; 13467935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubert } 13477935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubert throw new ParseException("missing token at end of '" + context + "'", -1); 13487935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubert } 13497935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubert 13507935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubert /* 13517935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubert * Syntax: 13527935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubert * rule : keyword ':' condition 13537935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubert * keyword: <identifier> 13547935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubert */ 13557935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubert private static Rule parseRule(String description) throws ParseException { 13567935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubert if (description.length() == 0) { 13577935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubert return DEFAULT_RULE; 13587935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubert } 13597935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubert 13607935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubert description = description.toLowerCase(Locale.ENGLISH); 13617935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubert 13627935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubert int x = description.indexOf(':'); 13637935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubert if (x == -1) { 13647935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubert throw new ParseException("missing ':' in rule description '" + 13657935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubert description + "'", 0); 13667935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubert } 13677935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubert 13687935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubert String keyword = description.substring(0, x).trim(); 13697935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubert if (!isValidKeyword(keyword)) { 13707935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubert throw new ParseException("keyword '" + keyword + 13717935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubert " is not valid", 0); 13727935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubert } 13737935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubert 13747935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubert description = description.substring(x+1).trim(); 13757935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubert String[] constraintOrSamples = AT_SEPARATED.split(description); 13767935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubert boolean sampleFailure = false; 13777935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubert FixedDecimalSamples integerSamples = null, decimalSamples = null; 13787935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubert switch (constraintOrSamples.length) { 13797935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubert case 1: break; 13802d2bb24f747c65578da13d5b13b82f0669690461Fredrik Roubert case 2: 13817935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubert integerSamples = FixedDecimalSamples.parse(constraintOrSamples[1]); 13827935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubert if (integerSamples.sampleType == SampleType.DECIMAL) { 13837935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubert decimalSamples = integerSamples; 13847935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubert integerSamples = null; 13857935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubert } 13867935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubert break; 13877935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubert case 3: 13887935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubert integerSamples = FixedDecimalSamples.parse(constraintOrSamples[1]); 13897935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubert decimalSamples = FixedDecimalSamples.parse(constraintOrSamples[2]); 13907935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubert if (integerSamples.sampleType != SampleType.INTEGER || decimalSamples.sampleType != SampleType.DECIMAL) { 13917935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubert throw new IllegalArgumentException("Must have @integer then @decimal in " + description); 13927935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubert } 13937935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubert break; 13942d2bb24f747c65578da13d5b13b82f0669690461Fredrik Roubert default: 13957935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubert throw new IllegalArgumentException("Too many samples in " + description); 13967935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubert } 13977935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubert if (sampleFailure) { 13987935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubert throw new IllegalArgumentException("Ill-formed samples—'@' characters."); 13997935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubert } 14007935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubert 14017935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubert // 'other' is special, and must have no rules; all other keywords must have rules. 14027935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubert boolean isOther = keyword.equals("other"); 14037935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubert if (isOther != (constraintOrSamples[0].length() == 0)) { 14047935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubert throw new IllegalArgumentException("The keyword 'other' must have no constraints, just samples."); 14057935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubert } 14067935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubert 14077935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubert Constraint constraint; 14087935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubert if (isOther) { 14097935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubert constraint = NO_CONSTRAINT; 14107935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubert } else { 14117935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubert constraint = parseConstraint(constraintOrSamples[0]); 14127935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubert } 14137935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubert return new Rule(keyword, constraint, integerSamples, decimalSamples); 14147935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubert } 14157935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubert 14167935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubert 14177935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubert /* 14187935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubert * Syntax: 14197935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubert * rules : rule 14207935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubert * rule ';' rules 14217935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubert */ 14227935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubert private static RuleList parseRuleChain(String description) 14237935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubert throws ParseException { 14247935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubert RuleList result = new RuleList(); 14257935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubert // remove trailing ; 14262d2bb24f747c65578da13d5b13b82f0669690461Fredrik Roubert if (description.endsWith(";")) { 14277935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubert description = description.substring(0,description.length()-1); 14287935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubert } 14297935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubert String[] rules = SEMI_SEPARATED.split(description); 14307935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubert for (int i = 0; i < rules.length; ++i) { 14317935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubert Rule rule = parseRule(rules[i].trim()); 14327935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubert result.hasExplicitBoundingInfo |= rule.integerSamples != null || rule.decimalSamples != null; 14337935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubert result.addRule(rule); 14347935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubert } 14357935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubert return result.finish(); 14367935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubert } 14377935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubert 14387935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubert /* 14397935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubert * An implementation of Constraint representing a modulus, 14407935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubert * a range of values, and include/exclude. Provides lots of 14417935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubert * convenience factory methods. 14427935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubert */ 14437935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubert private static class RangeConstraint implements Constraint, Serializable { 14447935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubert private static final long serialVersionUID = 1; 14457935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubert 14467935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubert private final int mod; 14477935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubert private final boolean inRange; 14487935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubert private final boolean integersOnly; 14497935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubert private final double lowerBound; 14507935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubert private final double upperBound; 14517935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubert private final long[] range_list; 14527935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubert private final Operand operand; 14537935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubert 14547935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubert RangeConstraint(int mod, boolean inRange, Operand operand, boolean integersOnly, 14557935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubert double lowBound, double highBound, long[] vals) { 14567935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubert this.mod = mod; 14577935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubert this.inRange = inRange; 14587935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubert this.integersOnly = integersOnly; 14597935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubert this.lowerBound = lowBound; 14607935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubert this.upperBound = highBound; 14617935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubert this.range_list = vals; 14627935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubert this.operand = operand; 14637935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubert } 14647935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubert 14652d2bb24f747c65578da13d5b13b82f0669690461Fredrik Roubert @Override 14667935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubert public boolean isFulfilled(FixedDecimal number) { 14677935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubert double n = number.get(operand); 14687935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubert if ((integersOnly && (n - (long)n) != 0.0 14697935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubert || operand == Operand.j && number.visibleDecimalDigitCount != 0)) { 14707935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubert return !inRange; 14717935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubert } 14727935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubert if (mod != 0) { 14737935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubert n = n % mod; // java % handles double numerator the way we want 14747935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubert } 14757935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubert boolean test = n >= lowerBound && n <= upperBound; 14767935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubert if (test && range_list != null) { 14777935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubert test = false; 14787935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubert for (int i = 0; !test && i < range_list.length; i += 2) { 14797935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubert test = n >= range_list[i] && n <= range_list[i+1]; 14807935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubert } 14817935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubert } 14827935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubert return inRange == test; 14837935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubert } 14847935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubert 14852d2bb24f747c65578da13d5b13b82f0669690461Fredrik Roubert @Override 14867935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubert public boolean isLimited(SampleType sampleType) { 14877935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubert boolean valueIsZero = lowerBound == upperBound && lowerBound == 0d; 14882d2bb24f747c65578da13d5b13b82f0669690461Fredrik Roubert boolean hasDecimals = 14897935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubert (operand == Operand.v || operand == Operand.w || operand == Operand.f || operand == Operand.t) 14907935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubert && inRange != valueIsZero; // either NOT f = zero or f = non-zero 14917935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubert switch (sampleType) { 14922d2bb24f747c65578da13d5b13b82f0669690461Fredrik Roubert case INTEGER: 14937935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubert return hasDecimals // will be empty 14947935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubert || (operand == Operand.n || operand == Operand.i || operand == Operand.j) 14952d2bb24f747c65578da13d5b13b82f0669690461Fredrik Roubert && mod == 0 14967935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubert && inRange; 14977935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubert 14987935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubert case DECIMAL: 14997935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubert return (!hasDecimals || operand == Operand.n || operand == Operand.j) 15007935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubert && (integersOnly || lowerBound == upperBound) 15012d2bb24f747c65578da13d5b13b82f0669690461Fredrik Roubert && mod == 0 15027935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubert && inRange; 15037935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubert } 15047935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubert return false; 15057935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubert } 15067935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubert 15072d2bb24f747c65578da13d5b13b82f0669690461Fredrik Roubert @Override 15087935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubert public String toString() { 15097935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubert StringBuilder result = new StringBuilder(); 15107935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubert result.append(operand); 15117935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubert if (mod != 0) { 15127935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubert result.append(" % ").append(mod); 15137935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubert } 15147935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubert boolean isList = lowerBound != upperBound; 15157935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubert result.append( 15167935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubert !isList ? (inRange ? " = " : " != ") 15177935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubert : integersOnly ? (inRange ? " = " : " != ") 15182d2bb24f747c65578da13d5b13b82f0669690461Fredrik Roubert : (inRange ? " within " : " not within ") 15197935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubert ); 15207935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubert if (range_list != null) { 15217935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubert for (int i = 0; i < range_list.length; i += 2) { 15227935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubert addRange(result, range_list[i], range_list[i+1], i != 0); 15237935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubert } 15247935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubert } else { 15257935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubert addRange(result, lowerBound, upperBound, false); 15267935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubert } 15277935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubert return result.toString(); 15287935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubert } 15297935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubert } 15307935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubert 15317935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubert private static void addRange(StringBuilder result, double lb, double ub, boolean addSeparator) { 15327935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubert if (addSeparator) { 15337935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubert result.append(","); 15347935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubert } 15357935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubert if (lb == ub) { 15367935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubert result.append(format(lb)); 15377935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubert } else { 15387935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubert result.append(format(lb) + ".." + format(ub)); 15397935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubert } 15407935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubert } 15417935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubert 15427935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubert private static String format(double lb) { 15437935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubert long lbi = (long) lb; 15447935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubert return lb == lbi ? String.valueOf(lbi) : String.valueOf(lb); 15457935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubert } 15467935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubert 15477935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubert /* Convenience base class for and/or constraints. */ 15487935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubert private static abstract class BinaryConstraint implements Constraint, 15497935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubert Serializable { 15507935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubert private static final long serialVersionUID = 1; 15517935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubert protected final Constraint a; 15527935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubert protected final Constraint b; 15537935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubert 15547935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubert protected BinaryConstraint(Constraint a, Constraint b) { 15557935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubert this.a = a; 15567935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubert this.b = b; 15577935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubert } 15587935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubert } 15597935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubert 15607935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubert /* A constraint representing the logical and of two constraints. */ 15617935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubert private static class AndConstraint extends BinaryConstraint { 15627935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubert private static final long serialVersionUID = 7766999779862263523L; 15637935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubert 15647935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubert AndConstraint(Constraint a, Constraint b) { 15657935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubert super(a, b); 15667935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubert } 15677935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubert 15682d2bb24f747c65578da13d5b13b82f0669690461Fredrik Roubert @Override 15697935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubert public boolean isFulfilled(FixedDecimal n) { 15702d2bb24f747c65578da13d5b13b82f0669690461Fredrik Roubert return a.isFulfilled(n) 15717935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubert && b.isFulfilled(n); 15727935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubert } 15737935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubert 15742d2bb24f747c65578da13d5b13b82f0669690461Fredrik Roubert @Override 15757935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubert public boolean isLimited(SampleType sampleType) { 15767935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubert // we ignore the case where both a and b are unlimited but no values 15777935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubert // satisfy both-- we still consider this 'unlimited' 15782d2bb24f747c65578da13d5b13b82f0669690461Fredrik Roubert return a.isLimited(sampleType) 15797935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubert || b.isLimited(sampleType); 15807935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubert } 15817935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubert 15822d2bb24f747c65578da13d5b13b82f0669690461Fredrik Roubert @Override 15837935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubert public String toString() { 15847935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubert return a.toString() + " and " + b.toString(); 15857935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubert } 15867935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubert } 15877935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubert 15887935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubert /* A constraint representing the logical or of two constraints. */ 15897935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubert private static class OrConstraint extends BinaryConstraint { 15907935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubert private static final long serialVersionUID = 1405488568664762222L; 15917935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubert 15927935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubert OrConstraint(Constraint a, Constraint b) { 15937935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubert super(a, b); 15947935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubert } 15957935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubert 15962d2bb24f747c65578da13d5b13b82f0669690461Fredrik Roubert @Override 15977935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubert public boolean isFulfilled(FixedDecimal n) { 15982d2bb24f747c65578da13d5b13b82f0669690461Fredrik Roubert return a.isFulfilled(n) 15997935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubert || b.isFulfilled(n); 16007935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubert } 16017935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubert 16022d2bb24f747c65578da13d5b13b82f0669690461Fredrik Roubert @Override 16037935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubert public boolean isLimited(SampleType sampleType) { 16042d2bb24f747c65578da13d5b13b82f0669690461Fredrik Roubert return a.isLimited(sampleType) 16057935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubert && b.isLimited(sampleType); 16067935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubert } 16077935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubert 16082d2bb24f747c65578da13d5b13b82f0669690461Fredrik Roubert @Override 16097935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubert public String toString() { 16107935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubert return a.toString() + " or " + b.toString(); 16117935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubert } 16127935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubert } 16137935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubert 16147935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubert /* 16157935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubert * Implementation of Rule that uses a constraint. 16167935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubert * Provides 'and' and 'or' to combine constraints. Immutable. 16177935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubert */ 16187935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubert private static class Rule implements Serializable { 16192d2bb24f747c65578da13d5b13b82f0669690461Fredrik Roubert // TODO - Findbugs: Class com.ibm.icu.text.PluralRules$Rule defines non-transient 16202d2bb24f747c65578da13d5b13b82f0669690461Fredrik Roubert // non-serializable instance field integerSamples. See ticket#10494. 16217935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubert private static final long serialVersionUID = 1; 16227935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubert private final String keyword; 16237935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubert private final Constraint constraint; 16247935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubert private final FixedDecimalSamples integerSamples; 16257935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubert private final FixedDecimalSamples decimalSamples; 16267935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubert 16277935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubert public Rule(String keyword, Constraint constraint, FixedDecimalSamples integerSamples, FixedDecimalSamples decimalSamples) { 16287935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubert this.keyword = keyword; 16297935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubert this.constraint = constraint; 16307935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubert this.integerSamples = integerSamples; 16317935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubert this.decimalSamples = decimalSamples; 16327935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubert } 16337935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubert 16347935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubert @SuppressWarnings("unused") 16357935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubert public Rule and(Constraint c) { 16367935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubert return new Rule(keyword, new AndConstraint(constraint, c), integerSamples, decimalSamples); 16377935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubert } 16387935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubert 16397935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubert @SuppressWarnings("unused") 16407935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubert public Rule or(Constraint c) { 16417935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubert return new Rule(keyword, new OrConstraint(constraint, c), integerSamples, decimalSamples); 16427935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubert } 16437935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubert 16447935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubert public String getKeyword() { 16457935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubert return keyword; 16467935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubert } 16477935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubert 16487935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubert public boolean appliesTo(FixedDecimal n) { 16497935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubert return constraint.isFulfilled(n); 16507935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubert } 16517935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubert 16527935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubert public boolean isLimited(SampleType sampleType) { 16537935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubert return constraint.isLimited(sampleType); 16547935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubert } 16557935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubert 16562d2bb24f747c65578da13d5b13b82f0669690461Fredrik Roubert @Override 16577935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubert public String toString() { 16582d2bb24f747c65578da13d5b13b82f0669690461Fredrik Roubert return keyword + ": " + constraint.toString() 16597935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubert + (integerSamples == null ? "" : " " + integerSamples.toString()) 16607935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubert + (decimalSamples == null ? "" : " " + decimalSamples.toString()); 16617935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubert } 16627935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubert 16637935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubert /** 16647935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubert * @internal 16657935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubert * @deprecated This API is ICU internal only. 16667935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubert */ 16677935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubert @Deprecated 16687935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubert @Override 16697935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubert public int hashCode() { 16707935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubert return keyword.hashCode() ^ constraint.hashCode(); 16717935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubert } 16727935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubert 16737935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubert public String getConstraint() { 16747935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubert return constraint.toString(); 16757935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubert } 16767935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubert } 16777935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubert 16787935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubert private static class RuleList implements Serializable { 16797935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubert private boolean hasExplicitBoundingInfo = false; 16807935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubert private static final long serialVersionUID = 1; 16817935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubert private final List<Rule> rules = new ArrayList<Rule>(); 16827935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubert 16837935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubert public RuleList addRule(Rule nextRule) { 16847935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubert String keyword = nextRule.getKeyword(); 16857935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubert for (Rule rule : rules) { 16867935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubert if (keyword.equals(rule.getKeyword())) { 16877935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubert throw new IllegalArgumentException("Duplicate keyword: " + keyword); 16887935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubert } 16897935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubert } 16907935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubert rules.add(nextRule); 16917935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubert return this; 16927935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubert } 16937935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubert 16947935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubert public RuleList finish() throws ParseException { 16957935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubert // make sure that 'other' is present, and at the end. 16967935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubert Rule otherRule = null; 16977935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubert for (Iterator<Rule> it = rules.iterator(); it.hasNext();) { 16987935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubert Rule rule = it.next(); 16997935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubert if ("other".equals(rule.getKeyword())) { 17007935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubert otherRule = rule; 17017935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubert it.remove(); 17027935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubert } 17037935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubert } 17047935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubert if (otherRule == null) { 17057935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubert otherRule = parseRule("other:"); // make sure we have always have an 'other' a rule 17067935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubert } 17077935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubert rules.add(otherRule); 17087935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubert return this; 17097935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubert } 17107935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubert 17117935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubert private Rule selectRule(FixedDecimal n) { 17127935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubert for (Rule rule : rules) { 17137935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubert if (rule.appliesTo(n)) { 17147935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubert return rule; 17157935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubert } 17167935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubert } 17177935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubert return null; 17187935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubert } 17197935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubert 17207935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubert public String select(FixedDecimal n) { 17217935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubert if (Double.isInfinite(n.source) || Double.isNaN(n.source)) { 17227935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubert return KEYWORD_OTHER; 17237935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubert } 17247935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubert Rule r = selectRule(n); 17257935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubert return r.getKeyword(); 17267935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubert } 17277935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubert 17287935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubert public Set<String> getKeywords() { 17297935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubert Set<String> result = new LinkedHashSet<String>(); 17307935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubert for (Rule rule : rules) { 17317935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubert result.add(rule.getKeyword()); 17327935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubert } 17337935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubert // since we have explict 'other', we don't need this. 17347935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubert //result.add(KEYWORD_OTHER); 17357935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubert return result; 17367935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubert } 17377935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubert 17387935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubert public boolean isLimited(String keyword, SampleType sampleType) { 17397935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubert if (hasExplicitBoundingInfo) { 17407935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubert FixedDecimalSamples mySamples = getDecimalSamples(keyword, sampleType); 17417935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubert return mySamples == null ? true : mySamples.bounded; 17427935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubert } 17437935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubert 17447935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubert return computeLimited(keyword, sampleType); 17457935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubert } 17467935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubert 17477935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubert public boolean computeLimited(String keyword, SampleType sampleType) { 17487935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubert // if all rules with this keyword are limited, it's limited, 17497935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubert // and if there's no rule with this keyword, it's unlimited 17507935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubert boolean result = false; 17517935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubert for (Rule rule : rules) { 17527935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubert if (keyword.equals(rule.getKeyword())) { 17537935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubert if (!rule.isLimited(sampleType)) { 17547935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubert return false; 17557935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubert } 17567935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubert result = true; 17577935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubert } 17587935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubert } 17597935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubert return result; 17607935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubert } 17617935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubert 17622d2bb24f747c65578da13d5b13b82f0669690461Fredrik Roubert @Override 17637935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubert public String toString() { 17647935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubert StringBuilder builder = new StringBuilder(); 17657935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubert for (Rule rule : rules) { 17667935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubert if (builder.length() != 0) { 17677935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubert builder.append(CATEGORY_SEPARATOR); 17687935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubert } 17697935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubert builder.append(rule); 17707935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubert } 17717935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubert return builder.toString(); 17727935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubert } 17737935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubert 17747935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubert public String getRules(String keyword) { 17757935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubert for (Rule rule : rules) { 17767935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubert if (rule.getKeyword().equals(keyword)) { 17777935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubert return rule.getConstraint(); 17787935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubert } 17797935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubert } 17807935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubert return null; 17817935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubert } 17827935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubert 17837935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubert public boolean select(FixedDecimal sample, String keyword) { 17847935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubert for (Rule rule : rules) { 17857935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubert if (rule.getKeyword().equals(keyword) && rule.appliesTo(sample)) { 17867935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubert return true; 17877935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubert } 17887935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubert } 17897935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubert return false; 17907935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubert } 17917935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubert 17927935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubert public FixedDecimalSamples getDecimalSamples(String keyword, SampleType sampleType) { 17937935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubert for (Rule rule : rules) { 17947935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubert if (rule.getKeyword().equals(keyword)) { 17957935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubert return sampleType == SampleType.INTEGER ? rule.integerSamples : rule.decimalSamples; 17967935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubert } 17977935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubert } 17987935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubert return null; 17997935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubert } 18007935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubert } 18017935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubert 18027935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubert @SuppressWarnings("unused") 18037935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubert private boolean addConditional(Set<FixedDecimal> toAddTo, Set<FixedDecimal> others, double trial) { 18047935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubert boolean added; 18057935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubert FixedDecimal toAdd = new FixedDecimal(trial); 18067935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubert if (!toAddTo.contains(toAdd) && !others.contains(toAdd)) { 18077935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubert others.add(toAdd); 18087935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubert added = true; 18097935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubert } else { 18107935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubert added = false; 18117935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubert } 18127935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubert return added; 18137935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubert } 18147935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubert 18157935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubert 18167935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubert 18177935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubert // ------------------------------------------------------------------------- 18187935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubert // Static class methods. 18197935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubert // ------------------------------------------------------------------------- 18207935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubert 18217935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubert /** 18227935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubert * Provides access to the predefined cardinal-number <code>PluralRules</code> for a given 18237935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubert * locale. 18247935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubert * Same as forLocale(locale, PluralType.CARDINAL). 18257935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubert * 18267935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubert * <p>ICU defines plural rules for many locales based on CLDR <i>Language Plural Rules</i>. 18277935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubert * For these predefined rules, see CLDR page at 18287935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubert * http://unicode.org/repos/cldr-tmp/trunk/diff/supplemental/language_plural_rules.html 18297935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubert * 18307935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubert * @param locale The locale for which a <code>PluralRules</code> object is 18317935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubert * returned. 18327935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubert * @return The predefined <code>PluralRules</code> object for this locale. 18337935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubert * If there's no predefined rules for this locale, the rules 18347935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubert * for the closest parent in the locale hierarchy that has one will 18357935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubert * be returned. The final fallback always returns the default 18367935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubert * rules. 18377935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubert * @stable ICU 3.8 18387935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubert */ 18397935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubert public static PluralRules forLocale(ULocale locale) { 18407935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubert return Factory.getDefaultFactory().forLocale(locale, PluralType.CARDINAL); 18417935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubert } 18427935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubert 18437935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubert /** 18447935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubert * Provides access to the predefined cardinal-number <code>PluralRules</code> for a given 184503f16b04d95bbaa98f702b69791b0de29ac75915Yoshito Umaoka * {@link java.util.Locale}. 18467935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubert * Same as forLocale(locale, PluralType.CARDINAL). 18477935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubert * 18487935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubert * <p>ICU defines plural rules for many locales based on CLDR <i>Language Plural Rules</i>. 18497935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubert * For these predefined rules, see CLDR page at 18507935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubert * http://unicode.org/repos/cldr-tmp/trunk/diff/supplemental/language_plural_rules.html 18517935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubert * 185203f16b04d95bbaa98f702b69791b0de29ac75915Yoshito Umaoka * @param locale The locale for which a <code>PluralRules</code> object is 18537935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubert * returned. 18547935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubert * @return The predefined <code>PluralRules</code> object for this locale. 18557935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubert * If there's no predefined rules for this locale, the rules 18567935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubert * for the closest parent in the locale hierarchy that has one will 18577935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubert * be returned. The final fallback always returns the default 18587935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubert * rules. 1859bd1cbb618dcaa1ac6ba7c77dece35cb79593a5d7Fredrik Roubert * @stable ICU 54 18607935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubert */ 18617935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubert public static PluralRules forLocale(Locale locale) { 18627935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubert return forLocale(ULocale.forLocale(locale)); 18637935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubert } 18647935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubert 18657935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubert /** 18667935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubert * Provides access to the predefined <code>PluralRules</code> for a given 18677935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubert * locale and the plural type. 18687935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubert * 18697935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubert * <p>ICU defines plural rules for many locales based on CLDR <i>Language Plural Rules</i>. 18707935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubert * For these predefined rules, see CLDR page at 18717935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubert * http://unicode.org/repos/cldr-tmp/trunk/diff/supplemental/language_plural_rules.html 18727935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubert * 18737935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubert * @param locale The locale for which a <code>PluralRules</code> object is 18747935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubert * returned. 18757935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubert * @param type The plural type (e.g., cardinal or ordinal). 18767935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubert * @return The predefined <code>PluralRules</code> object for this locale. 18777935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubert * If there's no predefined rules for this locale, the rules 18787935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubert * for the closest parent in the locale hierarchy that has one will 18797935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubert * be returned. The final fallback always returns the default 18807935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubert * rules. 18817935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubert * @stable ICU 50 18827935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubert */ 18837935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubert public static PluralRules forLocale(ULocale locale, PluralType type) { 18847935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubert return Factory.getDefaultFactory().forLocale(locale, type); 18857935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubert } 18867935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubert 18877935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubert /** 18887935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubert * Provides access to the predefined <code>PluralRules</code> for a given 188903f16b04d95bbaa98f702b69791b0de29ac75915Yoshito Umaoka * {@link java.util.Locale} and the plural type. 18907935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubert * 18917935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubert * <p>ICU defines plural rules for many locales based on CLDR <i>Language Plural Rules</i>. 18927935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubert * For these predefined rules, see CLDR page at 18937935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubert * http://unicode.org/repos/cldr-tmp/trunk/diff/supplemental/language_plural_rules.html 18947935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubert * 189503f16b04d95bbaa98f702b69791b0de29ac75915Yoshito Umaoka * @param locale The locale for which a <code>PluralRules</code> object is 18967935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubert * returned. 18977935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubert * @param type The plural type (e.g., cardinal or ordinal). 18987935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubert * @return The predefined <code>PluralRules</code> object for this locale. 18997935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubert * If there's no predefined rules for this locale, the rules 19007935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubert * for the closest parent in the locale hierarchy that has one will 19017935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubert * be returned. The final fallback always returns the default 19027935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubert * rules. 1903bd1cbb618dcaa1ac6ba7c77dece35cb79593a5d7Fredrik Roubert * @stable ICU 54 19047935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubert */ 19057935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubert public static PluralRules forLocale(Locale locale, PluralType type) { 19067935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubert return forLocale(ULocale.forLocale(locale), type); 19077935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubert } 19087935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubert 19097935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubert /* 19107935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubert * Checks whether a token is a valid keyword. 19117935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubert * 19127935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubert * @param token the token to be checked 19137935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubert * @return true if the token is a valid keyword. 19147935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubert */ 19157935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubert private static boolean isValidKeyword(String token) { 19167935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubert return ALLOWED_ID.containsAll(token); 19177935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubert } 19187935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubert 19197935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubert /* 19207935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubert * Creates a new <code>PluralRules</code> object. Immutable. 19217935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubert */ 19227935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubert private PluralRules(RuleList rules) { 19237935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubert this.rules = rules; 19247935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubert this.keywords = Collections.unmodifiableSet(rules.getKeywords()); 19257935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubert } 19267935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubert 19277935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubert /** 19287935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubert * @internal 19297935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubert * @deprecated This API is ICU internal only. 19307935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubert */ 19317935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubert @Deprecated 19327935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubert @Override 19337935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubert public int hashCode() { 19347935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubert return rules.hashCode(); 19357935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubert } 19367935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubert /** 19377935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubert * Given a number, returns the keyword of the first rule that applies to 19387935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubert * the number. 19397935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubert * 19407935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubert * @param number The number for which the rule has to be determined. 19417935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubert * @return The keyword of the selected rule. 19427935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubert * @stable ICU 4.0 19437935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubert */ 19447935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubert public String select(double number) { 19457935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubert return rules.select(new FixedDecimal(number)); 19467935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubert } 19477935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubert 19487935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubert /** 19497935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubert * Given a number, returns the keyword of the first rule that applies to 19507935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubert * the number. 19517935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubert * 19527935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubert * @param number The number for which the rule has to be determined. 19537935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubert * @return The keyword of the selected rule. 19547935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubert * @internal 19557935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubert * @deprecated This API is ICU internal only. 19567935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubert */ 19577935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubert @Deprecated 19587935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubert public String select(double number, int countVisibleFractionDigits, long fractionaldigits) { 19597935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubert return rules.select(new FixedDecimal(number, countVisibleFractionDigits, fractionaldigits)); 19607935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubert } 19617935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubert 19627935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubert /** 19637935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubert * Given a number information, returns the keyword of the first rule that applies to 19647935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubert * the number. 19657935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubert * 196682027afe36d2dbe419417f025716dc57c89ee0a4Markus Scherer * @param number The number information for which the rule has to be determined. 19677935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubert * @return The keyword of the selected rule. 19687935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubert * @internal 19697935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubert * @deprecated This API is ICU internal only. 19707935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubert */ 19717935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubert @Deprecated 197282027afe36d2dbe419417f025716dc57c89ee0a4Markus Scherer public String select(FixedDecimal number) { 197382027afe36d2dbe419417f025716dc57c89ee0a4Markus Scherer return rules.select(number); 19747935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubert } 19757935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubert 197682027afe36d2dbe419417f025716dc57c89ee0a4Markus Scherer /** 19777935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubert * Given a number information, and keyword, return whether the keyword would match the number. 19787935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubert * 19797935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubert * @param sample The number information for which the rule has to be determined. 19807935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubert * @param keyword The keyword to filter on 19817935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubert * @internal 19827935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubert * @deprecated This API is ICU internal only. 19837935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubert */ 19847935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubert @Deprecated 19857935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubert public boolean matches(FixedDecimal sample, String keyword) { 19867935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubert return rules.select(sample, keyword); 19877935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubert } 19887935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubert 19897935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubert /** 19907935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubert * Returns a set of all rule keywords used in this <code>PluralRules</code> 19917935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubert * object. The rule "other" is always present by default. 19927935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubert * 19937935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubert * @return The set of keywords. 19947935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubert * @stable ICU 3.8 19957935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubert */ 19967935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubert public Set<String> getKeywords() { 19977935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubert return keywords; 19987935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubert } 19997935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubert 20007935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubert /** 20017935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubert * Returns the unique value that this keyword matches, or {@link #NO_UNIQUE_VALUE} 20027935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubert * if the keyword matches multiple values or is not defined for this PluralRules. 20037935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubert * 20047935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubert * @param keyword the keyword to check for a unique value 20057935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubert * @return The unique value for the keyword, or NO_UNIQUE_VALUE. 20067935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubert * @stable ICU 4.8 20077935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubert */ 20087935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubert public double getUniqueKeywordValue(String keyword) { 20097935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubert Collection<Double> values = getAllKeywordValues(keyword); 20107935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubert if (values != null && values.size() == 1) { 20117935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubert return values.iterator().next(); 20127935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubert } 20137935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubert return NO_UNIQUE_VALUE; 20147935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubert } 20157935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubert 20167935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubert /** 20177935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubert * Returns all the values that trigger this keyword, or null if the number of such 20187935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubert * values is unlimited. 20197935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubert * 20207935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubert * @param keyword the keyword 20217935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubert * @return the values that trigger this keyword, or null. The returned collection 20227935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubert * is immutable. It will be empty if the keyword is not defined. 20237935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubert * @stable ICU 4.8 20247935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubert */ 20257935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubert public Collection<Double> getAllKeywordValues(String keyword) { 20267935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubert return getAllKeywordValues(keyword, SampleType.INTEGER); 20277935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubert } 20287935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubert 20297935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubert /** 20307935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubert * Returns all the values that trigger this keyword, or null if the number of such 20317935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubert * values is unlimited. 20327935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubert * 20337935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubert * @param keyword the keyword 20347935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubert * @param type the type of samples requested, INTEGER or DECIMAL 20357935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubert * @return the values that trigger this keyword, or null. The returned collection 20367935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubert * is immutable. It will be empty if the keyword is not defined. 20372d2bb24f747c65578da13d5b13b82f0669690461Fredrik Roubert * 20387935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubert * @internal 20397935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubert * @deprecated This API is ICU internal only. 20407935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubert */ 20417935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubert @Deprecated 20427935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubert public Collection<Double> getAllKeywordValues(String keyword, SampleType type) { 20437935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubert if (!isLimited(keyword, type)) { 20447935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubert return null; 20457935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubert } 20467935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubert Collection<Double> samples = getSamples(keyword, type); 20477935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubert return samples == null ? null : Collections.unmodifiableCollection(samples); 20487935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubert } 20497935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubert 20507935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubert /** 20517935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubert * Returns a list of integer values for which select() would return that keyword, 20527935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubert * or null if the keyword is not defined. The returned collection is unmodifiable. 20537935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubert * The returned list is not complete, and there might be additional values that 20547935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubert * would return the keyword. 20557935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubert * 20567935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubert * @param keyword the keyword to test 20577935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubert * @return a list of values matching the keyword. 20587935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubert * @stable ICU 4.8 20597935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubert */ 20607935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubert public Collection<Double> getSamples(String keyword) { 20617935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubert return getSamples(keyword, SampleType.INTEGER); 20627935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubert } 20637935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubert 20647935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubert /** 20657935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubert * Returns a list of values for which select() would return that keyword, 20667935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubert * or null if the keyword is not defined. 20677935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubert * The returned collection is unmodifiable. 20687935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubert * The returned list is not complete, and there might be additional values that 20697935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubert * would return the keyword. The keyword might be defined, and yet have an empty set of samples, 20707935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubert * IF there are samples for the other sampleType. 20717935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubert * 20727935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubert * @param keyword the keyword to test 20737935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubert * @param sampleType the type of samples requested, INTEGER or DECIMAL 20747935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubert * @return a list of values matching the keyword. 20757935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubert * @internal 20767935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubert * @deprecated ICU internal only 20777935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubert */ 20787935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubert @Deprecated 20797935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubert public Collection<Double> getSamples(String keyword, SampleType sampleType) { 20807935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubert if (!keywords.contains(keyword)) { 20817935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubert return null; 20827935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubert } 20837935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubert Set<Double> result = new TreeSet<Double>(); 20847935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubert 20857935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubert if (rules.hasExplicitBoundingInfo) { 20867935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubert FixedDecimalSamples samples = rules.getDecimalSamples(keyword, sampleType); 20877935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubert return samples == null ? Collections.unmodifiableSet(result) 20887935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubert : Collections.unmodifiableSet(samples.addSamples(result)); 20897935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubert } 20907935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubert 20917935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubert // hack in case the rule is created without explicit samples 20927935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubert int maxCount = isLimited(keyword, sampleType) ? Integer.MAX_VALUE : 20; 20937935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubert 20947935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubert switch (sampleType) { 20957935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubert case INTEGER: 20967935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubert for (int i = 0; i < 200; ++i) { 20977935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubert if (!addSample(keyword, i, maxCount, result)) { 20987935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubert break; 20997935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubert } 21007935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubert } 21017935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubert addSample(keyword, 1000000, maxCount, result); // hack for Welsh 21027935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubert break; 21037935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubert case DECIMAL: 21047935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubert for (int i = 0; i < 2000; ++i) { 21057935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubert if (!addSample(keyword, new FixedDecimal(i/10d, 1), maxCount, result)) { 21067935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubert break; 21077935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubert } 21087935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubert } 21097935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubert addSample(keyword, new FixedDecimal(1000000d, 1), maxCount, result); // hack for Welsh 21107935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubert break; 21117935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubert } 21127935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubert return result.size() == 0 ? null : Collections.unmodifiableSet(result); 21137935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubert } 21147935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubert 21157935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubert /** 21167935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubert * @internal 21177935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubert * @deprecated This API is ICU internal only. 21187935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubert */ 21197935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubert @Deprecated 21207935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubert public boolean addSample(String keyword, Number sample, int maxCount, Set<Double> result) { 21217935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubert String selectedKeyword = sample instanceof FixedDecimal ? select((FixedDecimal)sample) : select(sample.doubleValue()); 21227935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubert if (selectedKeyword.equals(keyword)) { 21237935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubert result.add(sample.doubleValue()); 21247935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubert if (--maxCount < 0) { 21257935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubert return false; 21267935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubert } 21277935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubert } 21287935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubert return true; 21297935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubert } 21307935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubert 21317935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubert /** 21327935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubert * Returns a list of values for which select() would return that keyword, 21337935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubert * or null if the keyword is not defined or no samples are available. 21347935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubert * The returned collection is unmodifiable. 21357935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubert * The returned list is not complete, and there might be additional values that 21367935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubert * would return the keyword. 21377935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubert * 21387935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubert * @param keyword the keyword to test 21397935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubert * @param sampleType the type of samples requested, INTEGER or DECIMAL 21407935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubert * @return a list of values matching the keyword. 21417935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubert * @internal 21427935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubert * @deprecated This API is ICU internal only. 21437935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubert */ 21447935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubert @Deprecated 21457935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubert public FixedDecimalSamples getDecimalSamples(String keyword, SampleType sampleType) { 21467935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubert return rules.getDecimalSamples(keyword, sampleType); 21477935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubert } 21487935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubert 21497935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubert /** 21507935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubert * Returns the set of locales for which PluralRules are known. 21517935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubert * @return the set of locales for which PluralRules are known, as a list 21527935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubert * @draft ICU 4.2 (retain) 21537935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubert * @provisional This API might change or be removed in a future release. 21547935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubert */ 21557935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubert public static ULocale[] getAvailableULocales() { 21567935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubert return Factory.getDefaultFactory().getAvailableULocales(); 21577935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubert } 21587935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubert 21597935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubert /** 21607935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubert * Returns the 'functionally equivalent' locale with respect to 21617935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubert * plural rules. Calling PluralRules.forLocale with the functionally equivalent 21627935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubert * locale, and with the provided locale, returns rules that behave the same. 2163bee65486a185907111f3be60992433e133ec0e32Scott Russell * <br> 21647935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubert * All locales with the same functionally equivalent locale have 21657935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubert * plural rules that behave the same. This is not exaustive; 21667935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubert * there may be other locales whose plural rules behave the same 21677935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubert * that do not have the same equivalent locale. 21687935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubert * 21697935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubert * @param locale the locale to check 2170bee65486a185907111f3be60992433e133ec0e32Scott Russell * @param isAvailable if not null and of length > 0, this will hold 'true' at 21717935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubert * index 0 if locale is directly defined (without fallback) as having plural rules 21727935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubert * @return the functionally-equivalent locale 21737935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubert * @draft ICU 4.2 (retain) 21747935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubert * @provisional This API might change or be removed in a future release. 21757935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubert */ 21767935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubert public static ULocale getFunctionalEquivalent(ULocale locale, boolean[] isAvailable) { 21777935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubert return Factory.getDefaultFactory().getFunctionalEquivalent(locale, isAvailable); 21787935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubert } 21797935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubert 21807935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubert /** 21817935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubert * {@inheritDoc} 21827935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubert * @stable ICU 3.8 21837935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubert */ 21842d2bb24f747c65578da13d5b13b82f0669690461Fredrik Roubert @Override 21857935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubert public String toString() { 21867935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubert return rules.toString(); 21877935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubert } 21887935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubert 21897935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubert /** 21907935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubert * {@inheritDoc} 21917935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubert * @stable ICU 3.8 21927935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubert */ 21932d2bb24f747c65578da13d5b13b82f0669690461Fredrik Roubert @Override 21947935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubert public boolean equals(Object rhs) { 21957935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubert return rhs instanceof PluralRules && equals((PluralRules)rhs); 21967935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubert } 21977935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubert 21987935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubert /** 21997935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubert * Returns true if rhs is equal to this. 22007935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubert * @param rhs the PluralRules to compare to. 22017935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubert * @return true if this and rhs are equal. 22027935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubert * @stable ICU 3.8 22037935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubert */ 22047935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubert // TODO Optimize this 22057935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubert public boolean equals(PluralRules rhs) { 22067935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubert return rhs != null && toString().equals(rhs.toString()); 22077935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubert } 22087935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubert 22097935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubert /** 22107935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubert * Status of the keyword for the rules, given a set of explicit values. 22112d2bb24f747c65578da13d5b13b82f0669690461Fredrik Roubert * 22127935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubert * @draft ICU 50 22137935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubert * @provisional This API might change or be removed in a future release. 22147935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubert */ 22157935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubert public enum KeywordStatus { 22167935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubert /** 22177935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubert * The keyword is not valid for the rules. 22182d2bb24f747c65578da13d5b13b82f0669690461Fredrik Roubert * 22197935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubert * @draft ICU 50 22207935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubert * @provisional This API might change or be removed in a future release. 22217935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubert */ 22227935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubert INVALID, 22237935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubert /** 22247935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubert * The keyword is valid, but unused (it is covered by the explicit values, OR has no values for the given {@link SampleType}). 22252d2bb24f747c65578da13d5b13b82f0669690461Fredrik Roubert * 22267935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubert * @draft ICU 50 22277935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubert * @provisional This API might change or be removed in a future release. 22287935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubert */ 22297935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubert SUPPRESSED, 22307935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubert /** 22317935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubert * The keyword is valid, used, and has a single possible value (before considering explicit values). 22322d2bb24f747c65578da13d5b13b82f0669690461Fredrik Roubert * 22337935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubert * @draft ICU 50 22347935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubert * @provisional This API might change or be removed in a future release. 22357935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubert */ 22367935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubert UNIQUE, 22377935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubert /** 22387935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubert * The keyword is valid, used, not unique, and has a finite set of values. 22392d2bb24f747c65578da13d5b13b82f0669690461Fredrik Roubert * 22407935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubert * @draft ICU 50 22417935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubert * @provisional This API might change or be removed in a future release. 22427935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubert */ 22437935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubert BOUNDED, 22447935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubert /** 22457935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubert * The keyword is valid but not bounded; there indefinitely many matching values. 22462d2bb24f747c65578da13d5b13b82f0669690461Fredrik Roubert * 22477935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubert * @draft ICU 50 22487935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubert * @provisional This API might change or be removed in a future release. 22497935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubert */ 22507935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubert UNBOUNDED 22517935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubert } 22527935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubert 22537935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubert /** 22547935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubert * Find the status for the keyword, given a certain set of explicit values. 22552d2bb24f747c65578da13d5b13b82f0669690461Fredrik Roubert * 22567935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubert * @param keyword 22577935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubert * the particular keyword (call rules.getKeywords() to get the valid ones) 22587935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubert * @param offset 22597935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubert * the offset used, or 0.0d if not. Internally, the offset is subtracted from each explicit value before 22607935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubert * checking against the keyword values. 22617935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubert * @param explicits 22627935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubert * a set of Doubles that are used explicitly (eg [=0], "[=1]"). May be empty or null. 22637935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubert * @param uniqueValue 22647935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubert * If non null, set to the unique value. 22657935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubert * @return the KeywordStatus 22667935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubert * @draft ICU 50 22677935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubert * @provisional This API might change or be removed in a future release. 22687935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubert */ 22697935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubert public KeywordStatus getKeywordStatus(String keyword, int offset, Set<Double> explicits, 22707935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubert Output<Double> uniqueValue) { 22717935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubert return getKeywordStatus(keyword, offset, explicits, uniqueValue, SampleType.INTEGER); 22727935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubert } 22737935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubert /** 22747935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubert * Find the status for the keyword, given a certain set of explicit values. 22752d2bb24f747c65578da13d5b13b82f0669690461Fredrik Roubert * 22767935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubert * @param keyword 22777935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubert * the particular keyword (call rules.getKeywords() to get the valid ones) 22787935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubert * @param offset 22797935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubert * the offset used, or 0.0d if not. Internally, the offset is subtracted from each explicit value before 22807935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubert * checking against the keyword values. 22817935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubert * @param explicits 22827935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubert * a set of Doubles that are used explicitly (eg [=0], "[=1]"). May be empty or null. 22837935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubert * @param sampleType 22847935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubert * request KeywordStatus relative to INTEGER or DECIMAL values 22857935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubert * @param uniqueValue 22867935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubert * If non null, set to the unique value. 22877935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubert * @return the KeywordStatus 22887935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubert * @internal 22897935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubert * @deprecated This API is ICU internal only. 22907935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubert */ 22917935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubert @Deprecated 22927935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubert public KeywordStatus getKeywordStatus(String keyword, int offset, Set<Double> explicits, 22937935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubert Output<Double> uniqueValue, SampleType sampleType) { 22947935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubert if (uniqueValue != null) { 22957935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubert uniqueValue.value = null; 22967935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubert } 22977935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubert 22987935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubert if (!keywords.contains(keyword)) { 22997935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubert return KeywordStatus.INVALID; 23007935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubert } 23017935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubert 23027935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubert if (!isLimited(keyword, sampleType)) { 23037935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubert return KeywordStatus.UNBOUNDED; 23047935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubert } 23057935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubert 23067935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubert Collection<Double> values = getSamples(keyword, sampleType); 23077935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubert 23087935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubert int originalSize = values.size(); 23097935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubert 23107935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubert if (explicits == null) { 23117935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubert explicits = Collections.emptySet(); 23127935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubert } 23137935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubert 23147935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubert // Quick check on whether there are multiple elements 23157935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubert 23167935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubert if (originalSize > explicits.size()) { 23177935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubert if (originalSize == 1) { 23187935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubert if (uniqueValue != null) { 23197935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubert uniqueValue.value = values.iterator().next(); 23207935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubert } 23217935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubert return KeywordStatus.UNIQUE; 23227935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubert } 23237935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubert return KeywordStatus.BOUNDED; 23247935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubert } 23257935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubert 23267935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubert // Compute if the quick test is insufficient. 23277935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubert 23287935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubert HashSet<Double> subtractedSet = new HashSet<Double>(values); 23297935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubert for (Double explicit : explicits) { 23307935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubert subtractedSet.remove(explicit - offset); 23317935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubert } 23327935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubert if (subtractedSet.size() == 0) { 23337935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubert return KeywordStatus.SUPPRESSED; 23347935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubert } 23357935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubert 23367935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubert if (uniqueValue != null && subtractedSet.size() == 1) { 23377935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubert uniqueValue.value = subtractedSet.iterator().next(); 23387935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubert } 23397935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubert 23407935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubert return originalSize == 1 ? KeywordStatus.UNIQUE : KeywordStatus.BOUNDED; 23417935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubert } 23427935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubert 23437935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubert /** 23447935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubert * @internal 23457935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubert * @deprecated This API is ICU internal only. 23467935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubert */ 23477935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubert @Deprecated 23487935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubert public String getRules(String keyword) { 23497935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubert return rules.getRules(keyword); 23507935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubert } 23517935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubert 23527935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubert private void writeObject( 23537935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubert ObjectOutputStream out) 23547935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubert throws IOException { 23557935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubert throw new NotSerializableException(); 23567935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubert } 23577935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubert 23587935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubert private void readObject(ObjectInputStream in 23597935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubert ) throws IOException, ClassNotFoundException { 23607935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubert throw new NotSerializableException(); 23617935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubert } 23627935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubert 23637935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubert private Object writeReplace() throws ObjectStreamException { 23647935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubert return new PluralRulesSerialProxy(toString()); 23657935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubert } 23667935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubert 23677935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubert /** 23687935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubert * @internal 23697935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubert * @deprecated internal 23707935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubert */ 23717935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubert @Deprecated 23727935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubert public int compareTo(PluralRules other) { 23737935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubert return toString().compareTo(other.toString()); 23747935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubert } 23757935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubert 23767935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubert /** 23777935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubert * @internal 23787935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubert * @deprecated internal 23797935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubert */ 23807935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubert @Deprecated 23817935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubert public Boolean isLimited(String keyword) { 23827935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubert return rules.isLimited(keyword, SampleType.INTEGER); 23837935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubert } 23847935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubert 23857935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubert /** 23867935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubert * @internal 23877935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubert * @deprecated internal 23887935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubert */ 23897935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubert @Deprecated 23907935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubert public boolean isLimited(String keyword, SampleType sampleType) { 23917935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubert return rules.isLimited(keyword, sampleType); 23927935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubert } 23937935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubert 23947935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubert /** 23957935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubert * @internal 23967935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubert * @deprecated internal 23977935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubert */ 23987935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubert @Deprecated 23997935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubert public boolean computeLimited(String keyword, SampleType sampleType) { 24007935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubert return rules.computeLimited(keyword, sampleType); 24017935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubert } 24027935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubert} 2403