1 /* 2 * Copyright (C) 2014 The Android Open Source Project 3 * Copyright (c) 1996, 2013, Oracle and/or its affiliates. All rights reserved. 4 * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. 5 * 6 * This code is free software; you can redistribute it and/or modify it 7 * under the terms of the GNU General Public License version 2 only, as 8 * published by the Free Software Foundation. Oracle designates this 9 * particular file as subject to the "Classpath" exception as provided 10 * by Oracle in the LICENSE file that accompanied this code. 11 * 12 * This code is distributed in the hope that it will be useful, but WITHOUT 13 * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or 14 * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License 15 * version 2 for more details (a copy is included in the LICENSE file that 16 * accompanied this code). 17 * 18 * You should have received a copy of the GNU General Public License version 19 * 2 along with this work; if not, write to the Free Software Foundation, 20 * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA. 21 * 22 * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA 23 * or visit www.oracle.com if you need additional information or have any 24 * questions. 25 */ 26 27 /* 28 * (C) Copyright Taligent, Inc. 1996, 1997 - All Rights Reserved 29 * (C) Copyright IBM Corp. 1996 - 1998 - All Rights Reserved 30 * 31 * The original version of this source code and documentation is copyrighted 32 * and owned by Taligent, Inc., a wholly-owned subsidiary of IBM. These 33 * materials are provided under terms of a License Agreement between Taligent 34 * and Sun. This technology is protected by multiple US and International 35 * patents. This notice and attribution to Taligent may not be removed. 36 * Taligent is a registered trademark of Taligent, Inc. 37 * 38 */ 39 40 package java.text; 41 42 import java.io.IOException; 43 import java.io.ObjectInputStream; 44 import java.io.ObjectOutputStream; 45 import java.io.ObjectStreamField; 46 import java.math.BigDecimal; 47 import java.math.BigInteger; 48 import java.math.RoundingMode; 49 import java.util.Currency; 50 import java.util.Locale; 51 import java.util.Objects; 52 import java.util.concurrent.atomic.AtomicInteger; 53 import java.util.concurrent.atomic.AtomicLong; 54 import libcore.icu.LocaleData; 55 56 import android.icu.math.MathContext; 57 58 /** 59 * <code>DecimalFormat</code> is a concrete subclass of 60 * <code>NumberFormat</code> that formats decimal numbers. It has a variety of 61 * features designed to make it possible to parse and format numbers in any 62 * locale, including support for Western, Arabic, and Indic digits. It also 63 * supports different kinds of numbers, including integers (123), fixed-point 64 * numbers (123.4), scientific notation (1.23E4), percentages (12%), and 65 * currency amounts ($123). All of these can be localized. 66 * 67 * <p>To obtain a <code>NumberFormat</code> for a specific locale, including the 68 * default locale, call one of <code>NumberFormat</code>'s factory methods, such 69 * as <code>getInstance()</code>. In general, do not call the 70 * <code>DecimalFormat</code> constructors directly, since the 71 * <code>NumberFormat</code> factory methods may return subclasses other than 72 * <code>DecimalFormat</code>. If you need to customize the format object, do 73 * something like this: 74 * 75 * <blockquote><pre> 76 * NumberFormat f = NumberFormat.getInstance(loc); 77 * if (f instanceof DecimalFormat) { 78 * ((DecimalFormat) f).setDecimalSeparatorAlwaysShown(true); 79 * } 80 * </pre></blockquote> 81 * 82 * <p>A <code>DecimalFormat</code> comprises a <em>pattern</em> and a set of 83 * <em>symbols</em>. The pattern may be set directly using 84 * <code>applyPattern()</code>, or indirectly using the API methods. The 85 * symbols are stored in a <code>DecimalFormatSymbols</code> object. When using 86 * the <code>NumberFormat</code> factory methods, the pattern and symbols are 87 * read from localized <code>ResourceBundle</code>s. 88 * 89 * <h3>Patterns</h3> 90 * 91 * <code>DecimalFormat</code> patterns have the following syntax: 92 * <blockquote><pre> 93 * <i>Pattern:</i> 94 * <i>PositivePattern</i> 95 * <i>PositivePattern</i> ; <i>NegativePattern</i> 96 * <i>PositivePattern:</i> 97 * <i>Prefix<sub>opt</sub></i> <i>Number</i> <i>Suffix<sub>opt</sub></i> 98 * <i>NegativePattern:</i> 99 * <i>Prefix<sub>opt</sub></i> <i>Number</i> <i>Suffix<sub>opt</sub></i> 100 * <i>Prefix:</i> 101 * any Unicode characters except \uFFFE, \uFFFF, and special characters 102 * <i>Suffix:</i> 103 * any Unicode characters except \uFFFE, \uFFFF, and special characters 104 * <i>Number:</i> 105 * <i>Integer</i> <i>Exponent<sub>opt</sub></i> 106 * <i>Integer</i> . <i>Fraction</i> <i>Exponent<sub>opt</sub></i> 107 * <i>Integer:</i> 108 * <i>MinimumInteger</i> 109 * # 110 * # <i>Integer</i> 111 * # , <i>Integer</i> 112 * <i>MinimumInteger:</i> 113 * 0 114 * 0 <i>MinimumInteger</i> 115 * 0 , <i>MinimumInteger</i> 116 * <i>Fraction:</i> 117 * <i>MinimumFraction<sub>opt</sub></i> <i>OptionalFraction<sub>opt</sub></i> 118 * <i>MinimumFraction:</i> 119 * 0 <i>MinimumFraction<sub>opt</sub></i> 120 * <i>OptionalFraction:</i> 121 * # <i>OptionalFraction<sub>opt</sub></i> 122 * <i>Exponent:</i> 123 * E <i>MinimumExponent</i> 124 * <i>MinimumExponent:</i> 125 * 0 <i>MinimumExponent<sub>opt</sub></i> 126 * </pre></blockquote> 127 * 128 * <p>A <code>DecimalFormat</code> pattern contains a positive and negative 129 * subpattern, for example, <code>"#,##0.00;(#,##0.00)"</code>. Each 130 * subpattern has a prefix, numeric part, and suffix. The negative subpattern 131 * is optional; if absent, then the positive subpattern prefixed with the 132 * localized minus sign (<code>'-'</code> in most locales) is used as the 133 * negative subpattern. That is, <code>"0.00"</code> alone is equivalent to 134 * <code>"0.00;-0.00"</code>. If there is an explicit negative subpattern, it 135 * serves only to specify the negative prefix and suffix; the number of digits, 136 * minimal digits, and other characteristics are all the same as the positive 137 * pattern. That means that <code>"#,##0.0#;(#)"</code> produces precisely 138 * the same behavior as <code>"#,##0.0#;(#,##0.0#)"</code>. 139 * 140 * <p>The prefixes, suffixes, and various symbols used for infinity, digits, 141 * thousands separators, decimal separators, etc. may be set to arbitrary 142 * values, and they will appear properly during formatting. However, care must 143 * be taken that the symbols and strings do not conflict, or parsing will be 144 * unreliable. For example, either the positive and negative prefixes or the 145 * suffixes must be distinct for <code>DecimalFormat.parse()</code> to be able 146 * to distinguish positive from negative values. (If they are identical, then 147 * <code>DecimalFormat</code> will behave as if no negative subpattern was 148 * specified.) Another example is that the decimal separator and thousands 149 * separator should be distinct characters, or parsing will be impossible. 150 * 151 * <p>The grouping separator is commonly used for thousands, but in some 152 * countries it separates ten-thousands. The grouping size is a constant number 153 * of digits between the grouping characters, such as 3 for 100,000,000 or 4 for 154 * 1,0000,0000. If you supply a pattern with multiple grouping characters, the 155 * interval between the last one and the end of the integer is the one that is 156 * used. So <code>"#,##,###,####"</code> == <code>"######,####"</code> == 157 * <code>"##,####,####"</code>. 158 * 159 * <h4>Special Pattern Characters</h4> 160 * 161 * <p>Many characters in a pattern are taken literally; they are matched during 162 * parsing and output unchanged during formatting. Special characters, on the 163 * other hand, stand for other characters, strings, or classes of characters. 164 * They must be quoted, unless noted otherwise, if they are to appear in the 165 * prefix or suffix as literals. 166 * 167 * <p>The characters listed here are used in non-localized patterns. Localized 168 * patterns use the corresponding characters taken from this formatter's 169 * <code>DecimalFormatSymbols</code> object instead, and these characters lose 170 * their special status. Two exceptions are the currency sign and quote, which 171 * are not localized. 172 * 173 * <blockquote> 174 * <table border=0 cellspacing=3 cellpadding=0 summary="Chart showing symbol, 175 * location, localized, and meaning."> 176 * <tr style="background-color: rgb(204, 204, 255);"> 177 * <th align=left>Symbol 178 * <th align=left>Location 179 * <th align=left>Localized? 180 * <th align=left>Meaning 181 * <tr valign=top> 182 * <td><code>0</code> 183 * <td>Number 184 * <td>Yes 185 * <td>Digit 186 * <tr style="vertical-align: top; background-color: rgb(238, 238, 255);"> 187 * <td><code>#</code> 188 * <td>Number 189 * <td>Yes 190 * <td>Digit, zero shows as absent 191 * <tr valign=top> 192 * <td><code>.</code> 193 * <td>Number 194 * <td>Yes 195 * <td>Decimal separator or monetary decimal separator 196 * <tr style="vertical-align: top; background-color: rgb(238, 238, 255);"> 197 * <td><code>-</code> 198 * <td>Number 199 * <td>Yes 200 * <td>Minus sign 201 * <tr valign=top> 202 * <td><code>,</code> 203 * <td>Number 204 * <td>Yes 205 * <td>Grouping separator 206 * <tr style="vertical-align: top; background-color: rgb(238, 238, 255);"> 207 * <td><code>E</code> 208 * <td>Number 209 * <td>Yes 210 * <td>Separates mantissa and exponent in scientific notation. 211 * <em>Need not be quoted in prefix or suffix.</em> 212 * <tr valign=top> 213 * <td><code>;</code> 214 * <td>Subpattern boundary 215 * <td>Yes 216 * <td>Separates positive and negative subpatterns 217 * <tr style="vertical-align: top; background-color: rgb(238, 238, 255);"> 218 * <td><code>%</code> 219 * <td>Prefix or suffix 220 * <td>Yes 221 * <td>Multiply by 100 and show as percentage 222 * <tr valign=top> 223 * <td><code>\u2030</code> 224 * <td>Prefix or suffix 225 * <td>Yes 226 * <td>Multiply by 1000 and show as per mille value 227 * <tr style="vertical-align: top; background-color: rgb(238, 238, 255);"> 228 * <td><code>¤</code> (<code>\u00A4</code>) 229 * <td>Prefix or suffix 230 * <td>No 231 * <td>Currency sign, replaced by currency symbol. If 232 * doubled, replaced by international currency symbol. 233 * If present in a pattern, the monetary decimal separator 234 * is used instead of the decimal separator. 235 * <tr valign=top> 236 * <td><code>'</code> 237 * <td>Prefix or suffix 238 * <td>No 239 * <td>Used to quote special characters in a prefix or suffix, 240 * for example, <code>"'#'#"</code> formats 123 to 241 * <code>"#123"</code>. To create a single quote 242 * itself, use two in a row: <code>"# o''clock"</code>. 243 * </table> 244 * </blockquote> 245 * 246 * <h4>Scientific Notation</h4> 247 * 248 * <p>Numbers in scientific notation are expressed as the product of a mantissa 249 * and a power of ten, for example, 1234 can be expressed as 1.234 x 10^3. The 250 * mantissa is often in the range 1.0 ≤ x {@literal <} 10.0, but it need not 251 * be. 252 * <code>DecimalFormat</code> can be instructed to format and parse scientific 253 * notation <em>only via a pattern</em>; there is currently no factory method 254 * that creates a scientific notation format. In a pattern, the exponent 255 * character immediately followed by one or more digit characters indicates 256 * scientific notation. Example: <code>"0.###E0"</code> formats the number 257 * 1234 as <code>"1.234E3"</code>. 258 * 259 * <ul> 260 * <li>The number of digit characters after the exponent character gives the 261 * minimum exponent digit count. There is no maximum. Negative exponents are 262 * formatted using the localized minus sign, <em>not</em> the prefix and suffix 263 * from the pattern. This allows patterns such as <code>"0.###E0 m/s"</code>. 264 * 265 * <li>The minimum and maximum number of integer digits are interpreted 266 * together: 267 * 268 * <ul> 269 * <li>If the maximum number of integer digits is greater than their minimum number 270 * and greater than 1, it forces the exponent to be a multiple of the maximum 271 * number of integer digits, and the minimum number of integer digits to be 272 * interpreted as 1. The most common use of this is to generate 273 * <em>engineering notation</em>, in which the exponent is a multiple of three, 274 * e.g., <code>"##0.#####E0"</code>. Using this pattern, the number 12345 275 * formats to <code>"12.345E3"</code>, and 123456 formats to 276 * <code>"123.456E3"</code>. 277 * 278 * <li>Otherwise, the minimum number of integer digits is achieved by adjusting the 279 * exponent. Example: 0.00123 formatted with <code>"00.###E0"</code> yields 280 * <code>"12.3E-4"</code>. 281 * </ul> 282 * 283 * <li>The number of significant digits in the mantissa is the sum of the 284 * <em>minimum integer</em> and <em>maximum fraction</em> digits, and is 285 * unaffected by the maximum integer digits. For example, 12345 formatted with 286 * <code>"##0.##E0"</code> is <code>"12.3E3"</code>. To show all digits, set 287 * the significant digits count to zero. The number of significant digits 288 * does not affect parsing. 289 * 290 * <li>Exponential patterns may not contain grouping separators. 291 * </ul> 292 * 293 * <h4>Rounding</h4> 294 * 295 * <code>DecimalFormat</code> provides rounding modes defined in 296 * {@link java.math.RoundingMode} for formatting. By default, it uses 297 * {@link java.math.RoundingMode#HALF_EVEN RoundingMode.HALF_EVEN}. 298 * 299 * <h4>Digits</h4> 300 * 301 * For formatting, <code>DecimalFormat</code> uses the ten consecutive 302 * characters starting with the localized zero digit defined in the 303 * <code>DecimalFormatSymbols</code> object as digits. For parsing, these 304 * digits as well as all Unicode decimal digits, as defined by 305 * {@link Character#digit Character.digit}, are recognized. 306 * 307 * <h4>Special Values</h4> 308 * 309 * <p><code>NaN</code> is formatted as a string, which typically has a single character 310 * <code>\uFFFD</code>. This string is determined by the 311 * <code>DecimalFormatSymbols</code> object. This is the only value for which 312 * the prefixes and suffixes are not used. 313 * 314 * <p>Infinity is formatted as a string, which typically has a single character 315 * <code>\u221E</code>, with the positive or negative prefixes and suffixes 316 * applied. The infinity string is determined by the 317 * <code>DecimalFormatSymbols</code> object. 318 * 319 * <p>Negative zero (<code>"-0"</code>) parses to 320 * <ul> 321 * <li><code>BigDecimal(0)</code> if <code>isParseBigDecimal()</code> is 322 * true, 323 * <li><code>Long(0)</code> if <code>isParseBigDecimal()</code> is false 324 * and <code>isParseIntegerOnly()</code> is true, 325 * <li><code>Double(-0.0)</code> if both <code>isParseBigDecimal()</code> 326 * and <code>isParseIntegerOnly()</code> are false. 327 * </ul> 328 * 329 * <h4><a name="synchronization">Synchronization</a></h4> 330 * 331 * <p> 332 * Decimal formats are generally not synchronized. 333 * It is recommended to create separate format instances for each thread. 334 * If multiple threads access a format concurrently, it must be synchronized 335 * externally. 336 * 337 * <h4>Example</h4> 338 * 339 * <blockquote><pre>{@code 340 * <strong>// Print out a number using the localized number, integer, currency, 341 * // and percent format for each locale</strong> 342 * Locale[] locales = NumberFormat.getAvailableLocales(); 343 * double myNumber = -1234.56; 344 * NumberFormat form; 345 * for (int j = 0; j < 4; ++j) { 346 * System.out.println("FORMAT"); 347 * for (int i = 0; i < locales.length; ++i) { 348 * if (locales[i].getCountry().length() == 0) { 349 * continue; // Skip language-only locales 350 * } 351 * System.out.print(locales[i].getDisplayName()); 352 * switch (j) { 353 * case 0: 354 * form = NumberFormat.getInstance(locales[i]); break; 355 * case 1: 356 * form = NumberFormat.getIntegerInstance(locales[i]); break; 357 * case 2: 358 * form = NumberFormat.getCurrencyInstance(locales[i]); break; 359 * default: 360 * form = NumberFormat.getPercentInstance(locales[i]); break; 361 * } 362 * if (form instanceof DecimalFormat) { 363 * System.out.print(": " + ((DecimalFormat) form).toPattern()); 364 * } 365 * System.out.print(" -> " + form.format(myNumber)); 366 * try { 367 * System.out.println(" -> " + form.parse(form.format(myNumber))); 368 * } catch (ParseException e) {} 369 * } 370 * } 371 * }</pre></blockquote> 372 * 373 * @see <a href="https://docs.oracle.com/javase/tutorial/i18n/format/decimalFormat.html">Java Tutorial</a> 374 * @see NumberFormat 375 * @see DecimalFormatSymbols 376 * @see ParsePosition 377 * @author Mark Davis 378 * @author Alan Liu 379 */ 380 public class DecimalFormat extends NumberFormat { 381 382 // Android-note: This class is heavily modified from upstream OpenJDK. 383 // Android's version delegates most of its work to android.icu.text.DecimalFormat. This is done 384 // to avoid code duplication and to stay compatible with earlier releases that used ICU4C/ICU4J 385 // to implement DecimalFormat. 386 387 // Android-added: ICU DecimalFormat to delegate to. 388 // TODO(b/68143370): switch back to ICU DecimalFormat once it can reproduce ICU 58 behavior. 389 private transient android.icu.text.DecimalFormat_ICU58_Android icuDecimalFormat; 390 391 /** 392 * Creates a DecimalFormat using the default pattern and symbols 393 * for the default {@link java.util.Locale.Category#FORMAT FORMAT} locale. 394 * This is a convenient way to obtain a 395 * DecimalFormat when internationalization is not the main concern. 396 * <p> 397 * To obtain standard formats for a given locale, use the factory methods 398 * on NumberFormat such as getNumberInstance. These factories will 399 * return the most appropriate sub-class of NumberFormat for a given 400 * locale. 401 * 402 * @see java.text.NumberFormat#getInstance 403 * @see java.text.NumberFormat#getNumberInstance 404 * @see java.text.NumberFormat#getCurrencyInstance 405 * @see java.text.NumberFormat#getPercentInstance 406 */ DecimalFormat()407 public DecimalFormat() { 408 // Get the pattern for the default locale. 409 Locale def = Locale.getDefault(Locale.Category.FORMAT); 410 // BEGIN Android-changed: Use ICU LocaleData. Remove SPI LocaleProviderAdapter. 411 /* 412 LocaleProviderAdapter adapter = LocaleProviderAdapter.getAdapter(NumberFormatProvider.class, def); 413 if (!(adapter instanceof ResourceBundleBasedAdapter)) { 414 adapter = LocaleProviderAdapter.getResourceBundleBased(); 415 } 416 String[] all = adapter.getLocaleResources(def).getNumberPatterns(); 417 */ 418 String pattern = LocaleData.get(def).numberPattern; 419 // END Android-changed: Use ICU LocaleData. Remove SPI LocaleProviderAdapter. 420 421 // Always applyPattern after the symbols are set 422 this.symbols = DecimalFormatSymbols.getInstance(def); 423 // Android-changed: initPattern() and conversion methods between ICU and Java values. 424 // applyPattern(all[0], false); 425 initPattern(pattern); 426 } 427 428 429 /** 430 * Creates a DecimalFormat using the given pattern and the symbols 431 * for the default {@link java.util.Locale.Category#FORMAT FORMAT} locale. 432 * This is a convenient way to obtain a 433 * DecimalFormat when internationalization is not the main concern. 434 * <p> 435 * To obtain standard formats for a given locale, use the factory methods 436 * on NumberFormat such as getNumberInstance. These factories will 437 * return the most appropriate sub-class of NumberFormat for a given 438 * locale. 439 * 440 * @param pattern a non-localized pattern string. 441 * @exception NullPointerException if <code>pattern</code> is null 442 * @exception IllegalArgumentException if the given pattern is invalid. 443 * @see java.text.NumberFormat#getInstance 444 * @see java.text.NumberFormat#getNumberInstance 445 * @see java.text.NumberFormat#getCurrencyInstance 446 * @see java.text.NumberFormat#getPercentInstance 447 */ DecimalFormat(String pattern)448 public DecimalFormat(String pattern) { 449 // Always applyPattern after the symbols are set 450 this.symbols = DecimalFormatSymbols.getInstance(Locale.getDefault(Locale.Category.FORMAT)); 451 // Android-changed: initPattern() and conversion methods between ICU and Java values. 452 // applyPattern(pattern, false); 453 initPattern(pattern); 454 } 455 456 457 /** 458 * Creates a DecimalFormat using the given pattern and symbols. 459 * Use this constructor when you need to completely customize the 460 * behavior of the format. 461 * <p> 462 * To obtain standard formats for a given 463 * locale, use the factory methods on NumberFormat such as 464 * getInstance or getCurrencyInstance. If you need only minor adjustments 465 * to a standard format, you can modify the format returned by 466 * a NumberFormat factory method. 467 * 468 * @param pattern a non-localized pattern string 469 * @param symbols the set of symbols to be used 470 * @exception NullPointerException if any of the given arguments is null 471 * @exception IllegalArgumentException if the given pattern is invalid 472 * @see java.text.NumberFormat#getInstance 473 * @see java.text.NumberFormat#getNumberInstance 474 * @see java.text.NumberFormat#getCurrencyInstance 475 * @see java.text.NumberFormat#getPercentInstance 476 * @see java.text.DecimalFormatSymbols 477 */ DecimalFormat(String pattern, DecimalFormatSymbols symbols)478 public DecimalFormat (String pattern, DecimalFormatSymbols symbols) { 479 // Always applyPattern after the symbols are set 480 this.symbols = (DecimalFormatSymbols)symbols.clone(); 481 // Android-changed: initPattern() and conversion methods between ICU and Java values. 482 initPattern(pattern); 483 } 484 485 // BEGIN Android-added: initPattern() and conversion methods between ICU and Java values. 486 /** 487 * Applies the pattern similarly to {@link #applyPattern(String)}, except it initializes 488 * {@link #icuDecimalFormat} in the process. This should only be called from constructors. 489 */ initPattern(String pattern)490 private void initPattern(String pattern) { 491 this.icuDecimalFormat = new android.icu.text.DecimalFormat_ICU58_Android(pattern, 492 symbols.getIcuDecimalFormatSymbols()); 493 updateFieldsFromIcu(); 494 } 495 496 /** 497 * Update local fields indicating maximum/minimum integer/fraction digit count from the ICU 498 * DecimalFormat. This needs to be called whenever a new pattern is applied. 499 */ updateFieldsFromIcu()500 private void updateFieldsFromIcu() { 501 // Imitate behaviour of ICU4C NumberFormat that Android used up to M. 502 // If the pattern doesn't enforce a different value (some exponential 503 // patterns do), then set the maximum integer digits to 2 billion. 504 if (icuDecimalFormat.getMaximumIntegerDigits() == DOUBLE_INTEGER_DIGITS) { 505 icuDecimalFormat.setMaximumIntegerDigits(2000000000); 506 } 507 maximumIntegerDigits = icuDecimalFormat.getMaximumIntegerDigits(); 508 minimumIntegerDigits = icuDecimalFormat.getMinimumIntegerDigits(); 509 maximumFractionDigits = icuDecimalFormat.getMaximumFractionDigits(); 510 minimumFractionDigits = icuDecimalFormat.getMinimumFractionDigits(); 511 } 512 513 /** 514 * Converts between field positions used by Java/ICU. 515 * @param fp The java.text.NumberFormat.Field field position 516 * @return The android.icu.text.NumberFormat.Field field position 517 */ getIcuFieldPosition(FieldPosition fp)518 private static FieldPosition getIcuFieldPosition(FieldPosition fp) { 519 Format.Field fieldAttribute = fp.getFieldAttribute(); 520 if (fieldAttribute == null) return fp; 521 522 android.icu.text.NumberFormat.Field attribute; 523 if (fieldAttribute == Field.INTEGER) { 524 attribute = android.icu.text.NumberFormat.Field.INTEGER; 525 } else if (fieldAttribute == Field.FRACTION) { 526 attribute = android.icu.text.NumberFormat.Field.FRACTION; 527 } else if (fieldAttribute == Field.DECIMAL_SEPARATOR) { 528 attribute = android.icu.text.NumberFormat.Field.DECIMAL_SEPARATOR; 529 } else if (fieldAttribute == Field.EXPONENT_SYMBOL) { 530 attribute = android.icu.text.NumberFormat.Field.EXPONENT_SYMBOL; 531 } else if (fieldAttribute == Field.EXPONENT_SIGN) { 532 attribute = android.icu.text.NumberFormat.Field.EXPONENT_SIGN; 533 } else if (fieldAttribute == Field.EXPONENT) { 534 attribute = android.icu.text.NumberFormat.Field.EXPONENT; 535 } else if (fieldAttribute == Field.GROUPING_SEPARATOR) { 536 attribute = android.icu.text.NumberFormat.Field.GROUPING_SEPARATOR; 537 } else if (fieldAttribute == Field.CURRENCY) { 538 attribute = android.icu.text.NumberFormat.Field.CURRENCY; 539 } else if (fieldAttribute == Field.PERCENT) { 540 attribute = android.icu.text.NumberFormat.Field.PERCENT; 541 } else if (fieldAttribute == Field.PERMILLE) { 542 attribute = android.icu.text.NumberFormat.Field.PERMILLE; 543 } else if (fieldAttribute == Field.SIGN) { 544 attribute = android.icu.text.NumberFormat.Field.SIGN; 545 } else { 546 throw new IllegalArgumentException("Unexpected field position attribute type."); 547 } 548 549 FieldPosition icuFieldPosition = new FieldPosition(attribute); 550 icuFieldPosition.setBeginIndex(fp.getBeginIndex()); 551 icuFieldPosition.setEndIndex(fp.getEndIndex()); 552 return icuFieldPosition; 553 } 554 555 /** 556 * Converts the Attribute that ICU returns in its AttributedCharacterIterator 557 * responses to the type that java uses. 558 * @param icuAttribute The AttributedCharacterIterator.Attribute field. 559 * @return Field converted to a java.text.NumberFormat.Field field. 560 */ toJavaFieldAttribute(AttributedCharacterIterator.Attribute icuAttribute)561 private static Field toJavaFieldAttribute(AttributedCharacterIterator.Attribute icuAttribute) { 562 String name = icuAttribute.getName(); 563 if (name.equals(Field.INTEGER.getName())) { 564 return Field.INTEGER; 565 } 566 if (name.equals(Field.CURRENCY.getName())) { 567 return Field.CURRENCY; 568 } 569 if (name.equals(Field.DECIMAL_SEPARATOR.getName())) { 570 return Field.DECIMAL_SEPARATOR; 571 } 572 if (name.equals(Field.EXPONENT.getName())) { 573 return Field.EXPONENT; 574 } 575 if (name.equals(Field.EXPONENT_SIGN.getName())) { 576 return Field.EXPONENT_SIGN; 577 } 578 if (name.equals(Field.EXPONENT_SYMBOL.getName())) { 579 return Field.EXPONENT_SYMBOL; 580 } 581 if (name.equals(Field.FRACTION.getName())) { 582 return Field.FRACTION; 583 } 584 if (name.equals(Field.GROUPING_SEPARATOR.getName())) { 585 return Field.GROUPING_SEPARATOR; 586 } 587 if (name.equals(Field.SIGN.getName())) { 588 return Field.SIGN; 589 } 590 if (name.equals(Field.PERCENT.getName())) { 591 return Field.PERCENT; 592 } 593 if (name.equals(Field.PERMILLE.getName())) { 594 return Field.PERMILLE; 595 } 596 throw new IllegalArgumentException("Unrecognized attribute: " + name); 597 } 598 // END Android-added: initPattern() and conversion methods between ICU and Java values. 599 600 // Overrides 601 /** 602 * Formats a number and appends the resulting text to the given string 603 * buffer. 604 * The number can be of any subclass of {@link java.lang.Number}. 605 * <p> 606 * This implementation uses the maximum precision permitted. 607 * @param number the number to format 608 * @param toAppendTo the <code>StringBuffer</code> to which the formatted 609 * text is to be appended 610 * @param pos On input: an alignment field, if desired. 611 * On output: the offsets of the alignment field. 612 * @return the value passed in as <code>toAppendTo</code> 613 * @exception IllegalArgumentException if <code>number</code> is 614 * null or not an instance of <code>Number</code>. 615 * @exception NullPointerException if <code>toAppendTo</code> or 616 * <code>pos</code> is null 617 * @exception ArithmeticException if rounding is needed with rounding 618 * mode being set to RoundingMode.UNNECESSARY 619 * @see java.text.FieldPosition 620 */ 621 @Override format(Object number, StringBuffer toAppendTo, FieldPosition pos)622 public final StringBuffer format(Object number, 623 StringBuffer toAppendTo, 624 FieldPosition pos) { 625 if (number instanceof Long || number instanceof Integer || 626 number instanceof Short || number instanceof Byte || 627 number instanceof AtomicInteger || 628 number instanceof AtomicLong || 629 (number instanceof BigInteger && 630 ((BigInteger)number).bitLength () < 64)) { 631 return format(((Number)number).longValue(), toAppendTo, pos); 632 } else if (number instanceof BigDecimal) { 633 return format((BigDecimal)number, toAppendTo, pos); 634 } else if (number instanceof BigInteger) { 635 return format((BigInteger)number, toAppendTo, pos); 636 } else if (number instanceof Number) { 637 return format(((Number)number).doubleValue(), toAppendTo, pos); 638 } else { 639 throw new IllegalArgumentException("Cannot format given Object as a Number"); 640 } 641 } 642 643 /** 644 * Formats a double to produce a string. 645 * @param number The double to format 646 * @param result where the text is to be appended 647 * @param fieldPosition On input: an alignment field, if desired. 648 * On output: the offsets of the alignment field. 649 * @exception ArithmeticException if rounding is needed with rounding 650 * mode being set to RoundingMode.UNNECESSARY 651 * @return The formatted number string 652 * @see java.text.FieldPosition 653 */ 654 @Override format(double number, StringBuffer result, FieldPosition fieldPosition)655 public StringBuffer format(double number, StringBuffer result, 656 FieldPosition fieldPosition) { 657 // BEGIN Android-changed: Use ICU. 658 /* 659 // If fieldPosition is a DontCareFieldPosition instance we can 660 // try to go to fast-path code. 661 boolean tryFastPath = false; 662 if (fieldPosition == DontCareFieldPosition.INSTANCE) 663 tryFastPath = true; 664 else { 665 fieldPosition.setBeginIndex(0); 666 fieldPosition.setEndIndex(0); 667 } 668 669 if (tryFastPath) { 670 String tempResult = fastFormat(number); 671 if (tempResult != null) { 672 result.append(tempResult); 673 return result; 674 } 675 } 676 677 // if fast-path could not work, we fallback to standard code. 678 return format(number, result, fieldPosition.getFieldDelegate()); 679 */ 680 FieldPosition icuFieldPosition = getIcuFieldPosition(fieldPosition); 681 icuDecimalFormat.format(number, result, icuFieldPosition); 682 fieldPosition.setBeginIndex(icuFieldPosition.getBeginIndex()); 683 fieldPosition.setEndIndex(icuFieldPosition.getEndIndex()); 684 return result; 685 // END Android-changed: Use ICU. 686 } 687 688 // BEGIN Android-removed: Use ICU. 689 // Removed unused helper function that was only used from (unused on Android) code 690 // in format(double, StringBuffer, FieldPosition). 691 /* 692 /** 693 * Formats a double to produce a string. 694 * @param number The double to format 695 * @param result where the text is to be appended 696 * @param delegate notified of locations of sub fields 697 * @exception ArithmeticException if rounding is needed with rounding 698 * mode being set to RoundingMode.UNNECESSARY 699 * @return The formatted number string 700 * 701 private StringBuffer format(double number, StringBuffer result, 702 FieldDelegate delegate) { 703 if (Double.isNaN(number) || 704 (Double.isInfinite(number) && multiplier == 0)) { 705 int iFieldStart = result.length(); 706 result.append(symbols.getNaN()); 707 delegate.formatted(INTEGER_FIELD, Field.INTEGER, Field.INTEGER, 708 iFieldStart, result.length(), result); 709 return result; 710 } 711 712 /* Detecting whether a double is negative is easy with the exception of 713 * the value -0.0. This is a double which has a zero mantissa (and 714 * exponent), but a negative sign bit. It is semantically distinct from 715 * a zero with a positive sign bit, and this distinction is important 716 * to certain kinds of computations. However, it's a little tricky to 717 * detect, since (-0.0 == 0.0) and !(-0.0 < 0.0). How then, you may 718 * ask, does it behave distinctly from +0.0? Well, 1/(-0.0) == 719 * -Infinity. Proper detection of -0.0 is needed to deal with the 720 * issues raised by bugs 4106658, 4106667, and 4147706. Liu 7/6/98. 721 * 722 boolean isNegative = ((number < 0.0) || (number == 0.0 && 1/number < 0.0)) ^ (multiplier < 0); 723 724 if (multiplier != 1) { 725 number *= multiplier; 726 } 727 728 if (Double.isInfinite(number)) { 729 if (isNegative) { 730 append(result, negativePrefix, delegate, 731 getNegativePrefixFieldPositions(), Field.SIGN); 732 } else { 733 append(result, positivePrefix, delegate, 734 getPositivePrefixFieldPositions(), Field.SIGN); 735 } 736 737 int iFieldStart = result.length(); 738 result.append(symbols.getInfinity()); 739 delegate.formatted(INTEGER_FIELD, Field.INTEGER, Field.INTEGER, 740 iFieldStart, result.length(), result); 741 742 if (isNegative) { 743 append(result, negativeSuffix, delegate, 744 getNegativeSuffixFieldPositions(), Field.SIGN); 745 } else { 746 append(result, positiveSuffix, delegate, 747 getPositiveSuffixFieldPositions(), Field.SIGN); 748 } 749 750 return result; 751 } 752 753 if (isNegative) { 754 number = -number; 755 } 756 757 // at this point we are guaranteed a nonnegative finite number. 758 assert(number >= 0 && !Double.isInfinite(number)); 759 760 synchronized(digitList) { 761 int maxIntDigits = super.getMaximumIntegerDigits(); 762 int minIntDigits = super.getMinimumIntegerDigits(); 763 int maxFraDigits = super.getMaximumFractionDigits(); 764 int minFraDigits = super.getMinimumFractionDigits(); 765 766 digitList.set(isNegative, number, useExponentialNotation ? 767 maxIntDigits + maxFraDigits : maxFraDigits, 768 !useExponentialNotation); 769 return subformat(result, delegate, isNegative, false, 770 maxIntDigits, minIntDigits, maxFraDigits, minFraDigits); 771 } 772 } 773 */ 774 // END Android-removed: Use ICU. 775 776 /** 777 * Format a long to produce a string. 778 * @param number The long to format 779 * @param result where the text is to be appended 780 * @param fieldPosition On input: an alignment field, if desired. 781 * On output: the offsets of the alignment field. 782 * @exception ArithmeticException if rounding is needed with rounding 783 * mode being set to RoundingMode.UNNECESSARY 784 * @return The formatted number string 785 * @see java.text.FieldPosition 786 */ 787 @Override format(long number, StringBuffer result, FieldPosition fieldPosition)788 public StringBuffer format(long number, StringBuffer result, 789 FieldPosition fieldPosition) { 790 // BEGIN Android-changed: Use ICU. 791 /* 792 fieldPosition.setBeginIndex(0); 793 fieldPosition.setEndIndex(0); 794 795 return format(number, result, fieldPosition.getFieldDelegate()); 796 */ 797 FieldPosition icuFieldPosition = getIcuFieldPosition(fieldPosition); 798 icuDecimalFormat.format(number, result, icuFieldPosition); 799 fieldPosition.setBeginIndex(icuFieldPosition.getBeginIndex()); 800 fieldPosition.setEndIndex(icuFieldPosition.getEndIndex()); 801 return result; 802 // END Android-changed: Use ICU. 803 } 804 805 // BEGIN Android-removed: Use ICU. 806 // Removed unused helper function that was only used from (unused on Android) code 807 // in format(long, StringBuffer, FieldDelegate). 808 /* 809 /** 810 * Format a long to produce a string. 811 * @param number The long to format 812 * @param result where the text is to be appended 813 * @param delegate notified of locations of sub fields 814 * @return The formatted number string 815 * @exception ArithmeticException if rounding is needed with rounding 816 * mode being set to RoundingMode.UNNECESSARY 817 * @see java.text.FieldPosition 818 * 819 private StringBuffer format(long number, StringBuffer result, 820 FieldDelegate delegate) { 821 boolean isNegative = (number < 0); 822 if (isNegative) { 823 number = -number; 824 } 825 826 // In general, long values always represent real finite numbers, so 827 // we don't have to check for +/- Infinity or NaN. However, there 828 // is one case we have to be careful of: The multiplier can push 829 // a number near MIN_VALUE or MAX_VALUE outside the legal range. We 830 // check for this before multiplying, and if it happens we use 831 // BigInteger instead. 832 boolean useBigInteger = false; 833 if (number < 0) { // This can only happen if number == Long.MIN_VALUE. 834 if (multiplier != 0) { 835 useBigInteger = true; 836 } 837 } else if (multiplier != 1 && multiplier != 0) { 838 long cutoff = Long.MAX_VALUE / multiplier; 839 if (cutoff < 0) { 840 cutoff = -cutoff; 841 } 842 useBigInteger = (number > cutoff); 843 } 844 845 if (useBigInteger) { 846 if (isNegative) { 847 number = -number; 848 } 849 BigInteger bigIntegerValue = BigInteger.valueOf(number); 850 return format(bigIntegerValue, result, delegate, true); 851 } 852 853 number *= multiplier; 854 if (number == 0) { 855 isNegative = false; 856 } else { 857 if (multiplier < 0) { 858 number = -number; 859 isNegative = !isNegative; 860 } 861 } 862 863 synchronized(digitList) { 864 int maxIntDigits = super.getMaximumIntegerDigits(); 865 int minIntDigits = super.getMinimumIntegerDigits(); 866 int maxFraDigits = super.getMaximumFractionDigits(); 867 int minFraDigits = super.getMinimumFractionDigits(); 868 869 digitList.set(isNegative, number, 870 useExponentialNotation ? maxIntDigits + maxFraDigits : 0); 871 872 return subformat(result, delegate, isNegative, true, 873 maxIntDigits, minIntDigits, maxFraDigits, minFraDigits); 874 } 875 } 876 */ 877 // END Android-removed: Use ICU. 878 879 /** 880 * Formats a BigDecimal to produce a string. 881 * @param number The BigDecimal to format 882 * @param result where the text is to be appended 883 * @param fieldPosition On input: an alignment field, if desired. 884 * On output: the offsets of the alignment field. 885 * @return The formatted number string 886 * @exception ArithmeticException if rounding is needed with rounding 887 * mode being set to RoundingMode.UNNECESSARY 888 * @see java.text.FieldPosition 889 */ format(BigDecimal number, StringBuffer result, FieldPosition fieldPosition)890 private StringBuffer format(BigDecimal number, StringBuffer result, 891 FieldPosition fieldPosition) { 892 // BEGIN Android-changed: Use ICU. 893 /* 894 fieldPosition.setBeginIndex(0); 895 fieldPosition.setEndIndex(0); 896 return format(number, result, fieldPosition.getFieldDelegate()); 897 */ 898 FieldPosition icuFieldPosition = getIcuFieldPosition(fieldPosition); 899 icuDecimalFormat.format(number, result, fieldPosition); 900 fieldPosition.setBeginIndex(icuFieldPosition.getBeginIndex()); 901 fieldPosition.setEndIndex(icuFieldPosition.getEndIndex()); 902 return result; 903 // END Android-changed: Use ICU. 904 } 905 906 // BEGIN Android-removed: Use ICU. 907 // Removed unused helper function that was only used from (unused on Android) code 908 // in format(BigDecimal, StringBuffer, FieldDelegate). 909 /* 910 /** 911 * Formats a BigDecimal to produce a string. 912 * @param number The BigDecimal to format 913 * @param result where the text is to be appended 914 * @param delegate notified of locations of sub fields 915 * @exception ArithmeticException if rounding is needed with rounding 916 * mode being set to RoundingMode.UNNECESSARY 917 * @return The formatted number string 918 * 919 private StringBuffer format(BigDecimal number, StringBuffer result, 920 FieldDelegate delegate) { 921 if (multiplier != 1) { 922 number = number.multiply(getBigDecimalMultiplier()); 923 } 924 boolean isNegative = number.signum() == -1; 925 if (isNegative) { 926 number = number.negate(); 927 } 928 929 synchronized(digitList) { 930 int maxIntDigits = getMaximumIntegerDigits(); 931 int minIntDigits = getMinimumIntegerDigits(); 932 int maxFraDigits = getMaximumFractionDigits(); 933 int minFraDigits = getMinimumFractionDigits(); 934 int maximumDigits = maxIntDigits + maxFraDigits; 935 936 digitList.set(isNegative, number, useExponentialNotation ? 937 ((maximumDigits < 0) ? Integer.MAX_VALUE : maximumDigits) : 938 maxFraDigits, !useExponentialNotation); 939 940 return subformat(result, delegate, isNegative, false, 941 maxIntDigits, minIntDigits, maxFraDigits, minFraDigits); 942 } 943 } 944 */ 945 // END Android-removed: Use ICU. 946 947 /** 948 * Format a BigInteger to produce a string. 949 * @param number The BigInteger to format 950 * @param result where the text is to be appended 951 * @param fieldPosition On input: an alignment field, if desired. 952 * On output: the offsets of the alignment field. 953 * @return The formatted number string 954 * @exception ArithmeticException if rounding is needed with rounding 955 * mode being set to RoundingMode.UNNECESSARY 956 * @see java.text.FieldPosition 957 */ format(BigInteger number, StringBuffer result, FieldPosition fieldPosition)958 private StringBuffer format(BigInteger number, StringBuffer result, 959 FieldPosition fieldPosition) { 960 // BEGIN Android-changed: Use ICU. 961 /* 962 fieldPosition.setBeginIndex(0); 963 fieldPosition.setEndIndex(0); 964 965 return format(number, result, fieldPosition.getFieldDelegate(), false); 966 */ 967 FieldPosition icuFieldPosition = getIcuFieldPosition(fieldPosition); 968 icuDecimalFormat.format(number, result, fieldPosition); 969 fieldPosition.setBeginIndex(icuFieldPosition.getBeginIndex()); 970 fieldPosition.setEndIndex(icuFieldPosition.getEndIndex()); 971 return result; 972 // END Android-changed: Use ICU. 973 } 974 975 // BEGIN Android-removed: Use ICU. 976 // Removed unused helper function that was only used from (unused on Android) code 977 // in format(BigInteger, StringBuffer, FieldDelegate). 978 /* 979 /** 980 * Format a BigInteger to produce a string. 981 * @param number The BigInteger to format 982 * @param result where the text is to be appended 983 * @param delegate notified of locations of sub fields 984 * @return The formatted number string 985 * @exception ArithmeticException if rounding is needed with rounding 986 * mode being set to RoundingMode.UNNECESSARY 987 * @see java.text.FieldPosition 988 * 989 private StringBuffer format(BigInteger number, StringBuffer result, 990 FieldDelegate delegate, boolean formatLong) { 991 if (multiplier != 1) { 992 number = number.multiply(getBigIntegerMultiplier()); 993 } 994 boolean isNegative = number.signum() == -1; 995 if (isNegative) { 996 number = number.negate(); 997 } 998 999 synchronized(digitList) { 1000 int maxIntDigits, minIntDigits, maxFraDigits, minFraDigits, maximumDigits; 1001 if (formatLong) { 1002 maxIntDigits = super.getMaximumIntegerDigits(); 1003 minIntDigits = super.getMinimumIntegerDigits(); 1004 maxFraDigits = super.getMaximumFractionDigits(); 1005 minFraDigits = super.getMinimumFractionDigits(); 1006 maximumDigits = maxIntDigits + maxFraDigits; 1007 } else { 1008 maxIntDigits = getMaximumIntegerDigits(); 1009 minIntDigits = getMinimumIntegerDigits(); 1010 maxFraDigits = getMaximumFractionDigits(); 1011 minFraDigits = getMinimumFractionDigits(); 1012 maximumDigits = maxIntDigits + maxFraDigits; 1013 if (maximumDigits < 0) { 1014 maximumDigits = Integer.MAX_VALUE; 1015 } 1016 } 1017 1018 digitList.set(isNegative, number, 1019 useExponentialNotation ? maximumDigits : 0); 1020 1021 return subformat(result, delegate, isNegative, true, 1022 maxIntDigits, minIntDigits, maxFraDigits, minFraDigits); 1023 } 1024 } 1025 */ 1026 // END Android-removed: Use ICU. 1027 1028 /** 1029 * Formats an Object producing an <code>AttributedCharacterIterator</code>. 1030 * You can use the returned <code>AttributedCharacterIterator</code> 1031 * to build the resulting String, as well as to determine information 1032 * about the resulting String. 1033 * <p> 1034 * Each attribute key of the AttributedCharacterIterator will be of type 1035 * <code>NumberFormat.Field</code>, with the attribute value being the 1036 * same as the attribute key. 1037 * 1038 * @exception NullPointerException if obj is null. 1039 * @exception IllegalArgumentException when the Format cannot format the 1040 * given object. 1041 * @exception ArithmeticException if rounding is needed with rounding 1042 * mode being set to RoundingMode.UNNECESSARY 1043 * @param obj The object to format 1044 * @return AttributedCharacterIterator describing the formatted value. 1045 * @since 1.4 1046 */ 1047 @Override formatToCharacterIterator(Object obj)1048 public AttributedCharacterIterator formatToCharacterIterator(Object obj) { 1049 // BEGIN Android-changed: Use ICU. 1050 /* 1051 CharacterIteratorFieldDelegate delegate = 1052 new CharacterIteratorFieldDelegate(); 1053 StringBuffer sb = new StringBuffer(); 1054 1055 if (obj instanceof Double || obj instanceof Float) { 1056 format(((Number)obj).doubleValue(), sb, delegate); 1057 } else if (obj instanceof Long || obj instanceof Integer || 1058 obj instanceof Short || obj instanceof Byte || 1059 obj instanceof AtomicInteger || obj instanceof AtomicLong) { 1060 format(((Number)obj).longValue(), sb, delegate); 1061 } else if (obj instanceof BigDecimal) { 1062 format((BigDecimal)obj, sb, delegate); 1063 } else if (obj instanceof BigInteger) { 1064 format((BigInteger)obj, sb, delegate, false); 1065 } else if (obj == null) { 1066 throw new NullPointerException( 1067 "formatToCharacterIterator must be passed non-null object"); 1068 } else { 1069 throw new IllegalArgumentException( 1070 "Cannot format given Object as a Number"); 1071 } 1072 return delegate.getIterator(sb.toString()); 1073 */ 1074 if (obj == null) { 1075 throw new NullPointerException("object == null"); 1076 } 1077 // Note: formatToCharacterIterator cannot be used directly because it returns attributes 1078 // in terms of its own class: icu.text.NumberFormat instead of java.text.NumberFormat. 1079 // http://bugs.icu-project.org/trac/ticket/11931 Proposes to use the NumberFormat constants. 1080 1081 AttributedCharacterIterator original = icuDecimalFormat.formatToCharacterIterator(obj); 1082 1083 // Extract the text out of the ICU iterator. 1084 StringBuilder textBuilder = new StringBuilder( 1085 original.getEndIndex() - original.getBeginIndex()); 1086 1087 for (int i = original.getBeginIndex(); i < original.getEndIndex(); i++) { 1088 textBuilder.append(original.current()); 1089 original.next(); 1090 } 1091 1092 AttributedString result = new AttributedString(textBuilder.toString()); 1093 1094 for (int i = original.getBeginIndex(); i < original.getEndIndex(); i++) { 1095 original.setIndex(i); 1096 1097 for (AttributedCharacterIterator.Attribute attribute 1098 : original.getAttributes().keySet()) { 1099 int start = original.getRunStart(); 1100 int end = original.getRunLimit(); 1101 Field javaAttr = toJavaFieldAttribute(attribute); 1102 result.addAttribute(javaAttr, javaAttr, start, end); 1103 } 1104 } 1105 1106 return result.getIterator(); 1107 // END Android-changed: Use ICU. 1108 } 1109 1110 // BEGIN Android-removed: "fast-path formatting logic for double", subformat(), append(). 1111 /* 1112 // ==== Begin fast-path formating logic for double ========================= 1113 1114 /* Fast-path formatting will be used for format(double ...) methods iff a 1115 * number of conditions are met (see checkAndSetFastPathStatus()): 1116 * - Only if instance properties meet the right predefined conditions. 1117 * - The abs value of the double to format is <= Integer.MAX_VALUE. 1118 * 1119 * The basic approach is to split the binary to decimal conversion of a 1120 * double value into two phases: 1121 * * The conversion of the integer portion of the double. 1122 * * The conversion of the fractional portion of the double 1123 * (limited to two or three digits). 1124 * 1125 * The isolation and conversion of the integer portion of the double is 1126 * straightforward. The conversion of the fraction is more subtle and relies 1127 * on some rounding properties of double to the decimal precisions in 1128 * question. Using the terminology of BigDecimal, this fast-path algorithm 1129 * is applied when a double value has a magnitude less than Integer.MAX_VALUE 1130 * and rounding is to nearest even and the destination format has two or 1131 * three digits of *scale* (digits after the decimal point). 1132 * 1133 * Under a rounding to nearest even policy, the returned result is a digit 1134 * string of a number in the (in this case decimal) destination format 1135 * closest to the exact numerical value of the (in this case binary) input 1136 * value. If two destination format numbers are equally distant, the one 1137 * with the last digit even is returned. To compute such a correctly rounded 1138 * value, some information about digits beyond the smallest returned digit 1139 * position needs to be consulted. 1140 * 1141 * In general, a guard digit, a round digit, and a sticky *bit* are needed 1142 * beyond the returned digit position. If the discarded portion of the input 1143 * is sufficiently large, the returned digit string is incremented. In round 1144 * to nearest even, this threshold to increment occurs near the half-way 1145 * point between digits. The sticky bit records if there are any remaining 1146 * trailing digits of the exact input value in the new format; the sticky bit 1147 * is consulted only in close to half-way rounding cases. 1148 * 1149 * Given the computation of the digit and bit values, rounding is then 1150 * reduced to a table lookup problem. For decimal, the even/odd cases look 1151 * like this: 1152 * 1153 * Last Round Sticky 1154 * 6 5 0 => 6 // exactly halfway, return even digit. 1155 * 6 5 1 => 7 // a little bit more than halfway, round up. 1156 * 7 5 0 => 8 // exactly halfway, round up to even. 1157 * 7 5 1 => 8 // a little bit more than halfway, round up. 1158 * With analogous entries for other even and odd last-returned digits. 1159 * 1160 * However, decimal negative powers of 5 smaller than 0.5 are *not* exactly 1161 * representable as binary fraction. In particular, 0.005 (the round limit 1162 * for a two-digit scale) and 0.0005 (the round limit for a three-digit 1163 * scale) are not representable. Therefore, for input values near these cases 1164 * the sticky bit is known to be set which reduces the rounding logic to: 1165 * 1166 * Last Round Sticky 1167 * 6 5 1 => 7 // a little bit more than halfway, round up. 1168 * 7 5 1 => 8 // a little bit more than halfway, round up. 1169 * 1170 * In other words, if the round digit is 5, the sticky bit is known to be 1171 * set. If the round digit is something other than 5, the sticky bit is not 1172 * relevant. Therefore, some of the logic about whether or not to increment 1173 * the destination *decimal* value can occur based on tests of *binary* 1174 * computations of the binary input number. 1175 * 1176 1177 /** 1178 * Check validity of using fast-path for this instance. If fast-path is valid 1179 * for this instance, sets fast-path state as true and initializes fast-path 1180 * utility fields as needed. 1181 * 1182 * This method is supposed to be called rarely, otherwise that will break the 1183 * fast-path performance. That means avoiding frequent changes of the 1184 * properties of the instance, since for most properties, each time a change 1185 * happens, a call to this method is needed at the next format call. 1186 * 1187 * FAST-PATH RULES: 1188 * Similar to the default DecimalFormat instantiation case. 1189 * More precisely: 1190 * - HALF_EVEN rounding mode, 1191 * - isGroupingUsed() is true, 1192 * - groupingSize of 3, 1193 * - multiplier is 1, 1194 * - Decimal separator not mandatory, 1195 * - No use of exponential notation, 1196 * - minimumIntegerDigits is exactly 1 and maximumIntegerDigits at least 10 1197 * - For number of fractional digits, the exact values found in the default case: 1198 * Currency : min = max = 2. 1199 * Decimal : min = 0. max = 3. 1200 * 1201 * 1202 private void checkAndSetFastPathStatus() { 1203 1204 boolean fastPathWasOn = isFastPath; 1205 1206 if ((roundingMode == RoundingMode.HALF_EVEN) && 1207 (isGroupingUsed()) && 1208 (groupingSize == 3) && 1209 (multiplier == 1) && 1210 (!decimalSeparatorAlwaysShown) && 1211 (!useExponentialNotation)) { 1212 1213 // The fast-path algorithm is semi-hardcoded against 1214 // minimumIntegerDigits and maximumIntegerDigits. 1215 isFastPath = ((minimumIntegerDigits == 1) && 1216 (maximumIntegerDigits >= 10)); 1217 1218 // The fast-path algorithm is hardcoded against 1219 // minimumFractionDigits and maximumFractionDigits. 1220 if (isFastPath) { 1221 if (isCurrencyFormat) { 1222 if ((minimumFractionDigits != 2) || 1223 (maximumFractionDigits != 2)) 1224 isFastPath = false; 1225 } else if ((minimumFractionDigits != 0) || 1226 (maximumFractionDigits != 3)) 1227 isFastPath = false; 1228 } 1229 } else 1230 isFastPath = false; 1231 1232 // Since some instance properties may have changed while still falling 1233 // in the fast-path case, we need to reinitialize fastPathData anyway. 1234 if (isFastPath) { 1235 // We need to instantiate fastPathData if not already done. 1236 if (fastPathData == null) 1237 fastPathData = new FastPathData(); 1238 1239 // Sets up the locale specific constants used when formatting. 1240 // '0' is our default representation of zero. 1241 fastPathData.zeroDelta = symbols.getZeroDigit() - '0'; 1242 fastPathData.groupingChar = symbols.getGroupingSeparator(); 1243 1244 // Sets up fractional constants related to currency/decimal pattern. 1245 fastPathData.fractionalMaxIntBound = (isCurrencyFormat) ? 99 : 999; 1246 fastPathData.fractionalScaleFactor = (isCurrencyFormat) ? 100.0d : 1000.0d; 1247 1248 // Records the need for adding prefix or suffix 1249 fastPathData.positiveAffixesRequired = 1250 (positivePrefix.length() != 0) || (positiveSuffix.length() != 0); 1251 fastPathData.negativeAffixesRequired = 1252 (negativePrefix.length() != 0) || (negativeSuffix.length() != 0); 1253 1254 // Creates a cached char container for result, with max possible size. 1255 int maxNbIntegralDigits = 10; 1256 int maxNbGroups = 3; 1257 int containerSize = 1258 Math.max(positivePrefix.length(), negativePrefix.length()) + 1259 maxNbIntegralDigits + maxNbGroups + 1 + maximumFractionDigits + 1260 Math.max(positiveSuffix.length(), negativeSuffix.length()); 1261 1262 fastPathData.fastPathContainer = new char[containerSize]; 1263 1264 // Sets up prefix and suffix char arrays constants. 1265 fastPathData.charsPositiveSuffix = positiveSuffix.toCharArray(); 1266 fastPathData.charsNegativeSuffix = negativeSuffix.toCharArray(); 1267 fastPathData.charsPositivePrefix = positivePrefix.toCharArray(); 1268 fastPathData.charsNegativePrefix = negativePrefix.toCharArray(); 1269 1270 // Sets up fixed index positions for integral and fractional digits. 1271 // Sets up decimal point in cached result container. 1272 int longestPrefixLength = 1273 Math.max(positivePrefix.length(), negativePrefix.length()); 1274 int decimalPointIndex = 1275 maxNbIntegralDigits + maxNbGroups + longestPrefixLength; 1276 1277 fastPathData.integralLastIndex = decimalPointIndex - 1; 1278 fastPathData.fractionalFirstIndex = decimalPointIndex + 1; 1279 fastPathData.fastPathContainer[decimalPointIndex] = 1280 isCurrencyFormat ? 1281 symbols.getMonetaryDecimalSeparator() : 1282 symbols.getDecimalSeparator(); 1283 1284 } else if (fastPathWasOn) { 1285 // Previous state was fast-path and is no more. 1286 // Resets cached array constants. 1287 fastPathData.fastPathContainer = null; 1288 fastPathData.charsPositiveSuffix = null; 1289 fastPathData.charsNegativeSuffix = null; 1290 fastPathData.charsPositivePrefix = null; 1291 fastPathData.charsNegativePrefix = null; 1292 } 1293 1294 fastPathCheckNeeded = false; 1295 } 1296 1297 /** 1298 * Returns true if rounding-up must be done on {@code scaledFractionalPartAsInt}, 1299 * false otherwise. 1300 * 1301 * This is a utility method that takes correct half-even rounding decision on 1302 * passed fractional value at the scaled decimal point (2 digits for currency 1303 * case and 3 for decimal case), when the approximated fractional part after 1304 * scaled decimal point is exactly 0.5d. This is done by means of exact 1305 * calculations on the {@code fractionalPart} floating-point value. 1306 * 1307 * This method is supposed to be called by private {@code fastDoubleFormat} 1308 * method only. 1309 * 1310 * The algorithms used for the exact calculations are : 1311 * 1312 * The <b><i>FastTwoSum</i></b> algorithm, from T.J.Dekker, described in the 1313 * papers "<i>A Floating-Point Technique for Extending the Available 1314 * Precision</i>" by Dekker, and in "<i>Adaptive Precision Floating-Point 1315 * Arithmetic and Fast Robust Geometric Predicates</i>" from J.Shewchuk. 1316 * 1317 * A modified version of <b><i>Sum2S</i></b> cascaded summation described in 1318 * "<i>Accurate Sum and Dot Product</i>" from Takeshi Ogita and All. As 1319 * Ogita says in this paper this is an equivalent of the Kahan-Babuska's 1320 * summation algorithm because we order the terms by magnitude before summing 1321 * them. For this reason we can use the <i>FastTwoSum</i> algorithm rather 1322 * than the more expensive Knuth's <i>TwoSum</i>. 1323 * 1324 * We do this to avoid a more expensive exact "<i>TwoProduct</i>" algorithm, 1325 * like those described in Shewchuk's paper above. See comments in the code 1326 * below. 1327 * 1328 * @param fractionalPart The fractional value on which we take rounding 1329 * decision. 1330 * @param scaledFractionalPartAsInt The integral part of the scaled 1331 * fractional value. 1332 * 1333 * @return the decision that must be taken regarding half-even rounding. 1334 * 1335 private boolean exactRoundUp(double fractionalPart, 1336 int scaledFractionalPartAsInt) { 1337 1338 /* exactRoundUp() method is called by fastDoubleFormat() only. 1339 * The precondition expected to be verified by the passed parameters is : 1340 * scaledFractionalPartAsInt == 1341 * (int) (fractionalPart * fastPathData.fractionalScaleFactor). 1342 * This is ensured by fastDoubleFormat() code. 1343 * 1344 1345 /* We first calculate roundoff error made by fastDoubleFormat() on 1346 * the scaled fractional part. We do this with exact calculation on the 1347 * passed fractionalPart. Rounding decision will then be taken from roundoff. 1348 * 1349 1350 /* ---- TwoProduct(fractionalPart, scale factor (i.e. 1000.0d or 100.0d)). 1351 * 1352 * The below is an optimized exact "TwoProduct" calculation of passed 1353 * fractional part with scale factor, using Ogita's Sum2S cascaded 1354 * summation adapted as Kahan-Babuska equivalent by using FastTwoSum 1355 * (much faster) rather than Knuth's TwoSum. 1356 * 1357 * We can do this because we order the summation from smallest to 1358 * greatest, so that FastTwoSum can be used without any additional error. 1359 * 1360 * The "TwoProduct" exact calculation needs 17 flops. We replace this by 1361 * a cascaded summation of FastTwoSum calculations, each involving an 1362 * exact multiply by a power of 2. 1363 * 1364 * Doing so saves overall 4 multiplications and 1 addition compared to 1365 * using traditional "TwoProduct". 1366 * 1367 * The scale factor is either 100 (currency case) or 1000 (decimal case). 1368 * - when 1000, we replace it by (1024 - 16 - 8) = 1000. 1369 * - when 100, we replace it by (128 - 32 + 4) = 100. 1370 * Every multiplication by a power of 2 (1024, 128, 32, 16, 8, 4) is exact. 1371 * 1372 * 1373 double approxMax; // Will always be positive. 1374 double approxMedium; // Will always be negative. 1375 double approxMin; 1376 1377 double fastTwoSumApproximation = 0.0d; 1378 double fastTwoSumRoundOff = 0.0d; 1379 double bVirtual = 0.0d; 1380 1381 if (isCurrencyFormat) { 1382 // Scale is 100 = 128 - 32 + 4. 1383 // Multiply by 2**n is a shift. No roundoff. No error. 1384 approxMax = fractionalPart * 128.00d; 1385 approxMedium = - (fractionalPart * 32.00d); 1386 approxMin = fractionalPart * 4.00d; 1387 } else { 1388 // Scale is 1000 = 1024 - 16 - 8. 1389 // Multiply by 2**n is a shift. No roundoff. No error. 1390 approxMax = fractionalPart * 1024.00d; 1391 approxMedium = - (fractionalPart * 16.00d); 1392 approxMin = - (fractionalPart * 8.00d); 1393 } 1394 1395 // Shewchuk/Dekker's FastTwoSum(approxMedium, approxMin). 1396 assert(-approxMedium >= Math.abs(approxMin)); 1397 fastTwoSumApproximation = approxMedium + approxMin; 1398 bVirtual = fastTwoSumApproximation - approxMedium; 1399 fastTwoSumRoundOff = approxMin - bVirtual; 1400 double approxS1 = fastTwoSumApproximation; 1401 double roundoffS1 = fastTwoSumRoundOff; 1402 1403 // Shewchuk/Dekker's FastTwoSum(approxMax, approxS1); 1404 assert(approxMax >= Math.abs(approxS1)); 1405 fastTwoSumApproximation = approxMax + approxS1; 1406 bVirtual = fastTwoSumApproximation - approxMax; 1407 fastTwoSumRoundOff = approxS1 - bVirtual; 1408 double roundoff1000 = fastTwoSumRoundOff; 1409 double approx1000 = fastTwoSumApproximation; 1410 double roundoffTotal = roundoffS1 + roundoff1000; 1411 1412 // Shewchuk/Dekker's FastTwoSum(approx1000, roundoffTotal); 1413 assert(approx1000 >= Math.abs(roundoffTotal)); 1414 fastTwoSumApproximation = approx1000 + roundoffTotal; 1415 bVirtual = fastTwoSumApproximation - approx1000; 1416 1417 // Now we have got the roundoff for the scaled fractional 1418 double scaledFractionalRoundoff = roundoffTotal - bVirtual; 1419 1420 // ---- TwoProduct(fractionalPart, scale (i.e. 1000.0d or 100.0d)) end. 1421 1422 /* ---- Taking the rounding decision 1423 * 1424 * We take rounding decision based on roundoff and half-even rounding 1425 * rule. 1426 * 1427 * The above TwoProduct gives us the exact roundoff on the approximated 1428 * scaled fractional, and we know that this approximation is exactly 1429 * 0.5d, since that has already been tested by the caller 1430 * (fastDoubleFormat). 1431 * 1432 * Decision comes first from the sign of the calculated exact roundoff. 1433 * - Since being exact roundoff, it cannot be positive with a scaled 1434 * fractional less than 0.5d, as well as negative with a scaled 1435 * fractional greater than 0.5d. That leaves us with following 3 cases. 1436 * - positive, thus scaled fractional == 0.500....0fff ==> round-up. 1437 * - negative, thus scaled fractional == 0.499....9fff ==> don't round-up. 1438 * - is zero, thus scaled fractioanl == 0.5 ==> half-even rounding applies : 1439 * we round-up only if the integral part of the scaled fractional is odd. 1440 * 1441 * 1442 if (scaledFractionalRoundoff > 0.0) { 1443 return true; 1444 } else if (scaledFractionalRoundoff < 0.0) { 1445 return false; 1446 } else if ((scaledFractionalPartAsInt & 1) != 0) { 1447 return true; 1448 } 1449 1450 return false; 1451 1452 // ---- Taking the rounding decision end 1453 } 1454 1455 /** 1456 * Collects integral digits from passed {@code number}, while setting 1457 * grouping chars as needed. Updates {@code firstUsedIndex} accordingly. 1458 * 1459 * Loops downward starting from {@code backwardIndex} position (inclusive). 1460 * 1461 * @param number The int value from which we collect digits. 1462 * @param digitsBuffer The char array container where digits and grouping chars 1463 * are stored. 1464 * @param backwardIndex the position from which we start storing digits in 1465 * digitsBuffer. 1466 * 1467 * 1468 private void collectIntegralDigits(int number, 1469 char[] digitsBuffer, 1470 int backwardIndex) { 1471 int index = backwardIndex; 1472 int q; 1473 int r; 1474 while (number > 999) { 1475 // Generates 3 digits per iteration. 1476 q = number / 1000; 1477 r = number - (q << 10) + (q << 4) + (q << 3); // -1024 +16 +8 = 1000. 1478 number = q; 1479 1480 digitsBuffer[index--] = DigitArrays.DigitOnes1000[r]; 1481 digitsBuffer[index--] = DigitArrays.DigitTens1000[r]; 1482 digitsBuffer[index--] = DigitArrays.DigitHundreds1000[r]; 1483 digitsBuffer[index--] = fastPathData.groupingChar; 1484 } 1485 1486 // Collects last 3 or less digits. 1487 digitsBuffer[index] = DigitArrays.DigitOnes1000[number]; 1488 if (number > 9) { 1489 digitsBuffer[--index] = DigitArrays.DigitTens1000[number]; 1490 if (number > 99) 1491 digitsBuffer[--index] = DigitArrays.DigitHundreds1000[number]; 1492 } 1493 1494 fastPathData.firstUsedIndex = index; 1495 } 1496 1497 /** 1498 * Collects the 2 (currency) or 3 (decimal) fractional digits from passed 1499 * {@code number}, starting at {@code startIndex} position 1500 * inclusive. There is no punctuation to set here (no grouping chars). 1501 * Updates {@code fastPathData.lastFreeIndex} accordingly. 1502 * 1503 * 1504 * @param number The int value from which we collect digits. 1505 * @param digitsBuffer The char array container where digits are stored. 1506 * @param startIndex the position from which we start storing digits in 1507 * digitsBuffer. 1508 * 1509 * 1510 private void collectFractionalDigits(int number, 1511 char[] digitsBuffer, 1512 int startIndex) { 1513 int index = startIndex; 1514 1515 char digitOnes = DigitArrays.DigitOnes1000[number]; 1516 char digitTens = DigitArrays.DigitTens1000[number]; 1517 1518 if (isCurrencyFormat) { 1519 // Currency case. Always collects fractional digits. 1520 digitsBuffer[index++] = digitTens; 1521 digitsBuffer[index++] = digitOnes; 1522 } else if (number != 0) { 1523 // Decimal case. Hundreds will always be collected 1524 digitsBuffer[index++] = DigitArrays.DigitHundreds1000[number]; 1525 1526 // Ending zeros won't be collected. 1527 if (digitOnes != '0') { 1528 digitsBuffer[index++] = digitTens; 1529 digitsBuffer[index++] = digitOnes; 1530 } else if (digitTens != '0') 1531 digitsBuffer[index++] = digitTens; 1532 1533 } else 1534 // This is decimal pattern and fractional part is zero. 1535 // We must remove decimal point from result. 1536 index--; 1537 1538 fastPathData.lastFreeIndex = index; 1539 } 1540 1541 /** 1542 * Internal utility. 1543 * Adds the passed {@code prefix} and {@code suffix} to {@code container}. 1544 * 1545 * @param container Char array container which to prepend/append the 1546 * prefix/suffix. 1547 * @param prefix Char sequence to prepend as a prefix. 1548 * @param suffix Char sequence to append as a suffix. 1549 * 1550 * 1551 // private void addAffixes(boolean isNegative, char[] container) { 1552 private void addAffixes(char[] container, char[] prefix, char[] suffix) { 1553 1554 // We add affixes only if needed (affix length > 0). 1555 int pl = prefix.length; 1556 int sl = suffix.length; 1557 if (pl != 0) prependPrefix(prefix, pl, container); 1558 if (sl != 0) appendSuffix(suffix, sl, container); 1559 1560 } 1561 1562 /** 1563 * Prepends the passed {@code prefix} chars to given result 1564 * {@code container}. Updates {@code fastPathData.firstUsedIndex} 1565 * accordingly. 1566 * 1567 * @param prefix The prefix characters to prepend to result. 1568 * @param len The number of chars to prepend. 1569 * @param container Char array container which to prepend the prefix 1570 * 1571 private void prependPrefix(char[] prefix, 1572 int len, 1573 char[] container) { 1574 1575 fastPathData.firstUsedIndex -= len; 1576 int startIndex = fastPathData.firstUsedIndex; 1577 1578 // If prefix to prepend is only 1 char long, just assigns this char. 1579 // If prefix is less or equal 4, we use a dedicated algorithm that 1580 // has shown to run faster than System.arraycopy. 1581 // If more than 4, we use System.arraycopy. 1582 if (len == 1) 1583 container[startIndex] = prefix[0]; 1584 else if (len <= 4) { 1585 int dstLower = startIndex; 1586 int dstUpper = dstLower + len - 1; 1587 int srcUpper = len - 1; 1588 container[dstLower] = prefix[0]; 1589 container[dstUpper] = prefix[srcUpper]; 1590 1591 if (len > 2) 1592 container[++dstLower] = prefix[1]; 1593 if (len == 4) 1594 container[--dstUpper] = prefix[2]; 1595 } else 1596 System.arraycopy(prefix, 0, container, startIndex, len); 1597 } 1598 1599 /** 1600 * Appends the passed {@code suffix} chars to given result 1601 * {@code container}. Updates {@code fastPathData.lastFreeIndex} 1602 * accordingly. 1603 * 1604 * @param suffix The suffix characters to append to result. 1605 * @param len The number of chars to append. 1606 * @param container Char array container which to append the suffix 1607 * 1608 private void appendSuffix(char[] suffix, 1609 int len, 1610 char[] container) { 1611 1612 int startIndex = fastPathData.lastFreeIndex; 1613 1614 // If suffix to append is only 1 char long, just assigns this char. 1615 // If suffix is less or equal 4, we use a dedicated algorithm that 1616 // has shown to run faster than System.arraycopy. 1617 // If more than 4, we use System.arraycopy. 1618 if (len == 1) 1619 container[startIndex] = suffix[0]; 1620 else if (len <= 4) { 1621 int dstLower = startIndex; 1622 int dstUpper = dstLower + len - 1; 1623 int srcUpper = len - 1; 1624 container[dstLower] = suffix[0]; 1625 container[dstUpper] = suffix[srcUpper]; 1626 1627 if (len > 2) 1628 container[++dstLower] = suffix[1]; 1629 if (len == 4) 1630 container[--dstUpper] = suffix[2]; 1631 } else 1632 System.arraycopy(suffix, 0, container, startIndex, len); 1633 1634 fastPathData.lastFreeIndex += len; 1635 } 1636 1637 /** 1638 * Converts digit chars from {@code digitsBuffer} to current locale. 1639 * 1640 * Must be called before adding affixes since we refer to 1641 * {@code fastPathData.firstUsedIndex} and {@code fastPathData.lastFreeIndex}, 1642 * and do not support affixes (for speed reason). 1643 * 1644 * We loop backward starting from last used index in {@code fastPathData}. 1645 * 1646 * @param digitsBuffer The char array container where the digits are stored. 1647 * 1648 private void localizeDigits(char[] digitsBuffer) { 1649 1650 // We will localize only the digits, using the groupingSize, 1651 // and taking into account fractional part. 1652 1653 // First take into account fractional part. 1654 int digitsCounter = 1655 fastPathData.lastFreeIndex - fastPathData.fractionalFirstIndex; 1656 1657 // The case when there is no fractional digits. 1658 if (digitsCounter < 0) 1659 digitsCounter = groupingSize; 1660 1661 // Only the digits remains to localize. 1662 for (int cursor = fastPathData.lastFreeIndex - 1; 1663 cursor >= fastPathData.firstUsedIndex; 1664 cursor--) { 1665 if (digitsCounter != 0) { 1666 // This is a digit char, we must localize it. 1667 digitsBuffer[cursor] += fastPathData.zeroDelta; 1668 digitsCounter--; 1669 } else { 1670 // Decimal separator or grouping char. Reinit counter only. 1671 digitsCounter = groupingSize; 1672 } 1673 } 1674 } 1675 1676 /** 1677 * This is the main entry point for the fast-path format algorithm. 1678 * 1679 * At this point we are sure to be in the expected conditions to run it. 1680 * This algorithm builds the formatted result and puts it in the dedicated 1681 * {@code fastPathData.fastPathContainer}. 1682 * 1683 * @param d the double value to be formatted. 1684 * @param negative Flag precising if {@code d} is negative. 1685 * 1686 private void fastDoubleFormat(double d, 1687 boolean negative) { 1688 1689 char[] container = fastPathData.fastPathContainer; 1690 1691 /* 1692 * The principle of the algorithm is to : 1693 * - Break the passed double into its integral and fractional parts 1694 * converted into integers. 1695 * - Then decide if rounding up must be applied or not by following 1696 * the half-even rounding rule, first using approximated scaled 1697 * fractional part. 1698 * - For the difficult cases (approximated scaled fractional part 1699 * being exactly 0.5d), we refine the rounding decision by calling 1700 * exactRoundUp utility method that both calculates the exact roundoff 1701 * on the approximation and takes correct rounding decision. 1702 * - We round-up the fractional part if needed, possibly propagating the 1703 * rounding to integral part if we meet a "all-nine" case for the 1704 * scaled fractional part. 1705 * - We then collect digits from the resulting integral and fractional 1706 * parts, also setting the required grouping chars on the fly. 1707 * - Then we localize the collected digits if needed, and 1708 * - Finally prepend/append prefix/suffix if any is needed. 1709 * 1710 1711 // Exact integral part of d. 1712 int integralPartAsInt = (int) d; 1713 1714 // Exact fractional part of d (since we subtract it's integral part). 1715 double exactFractionalPart = d - (double) integralPartAsInt; 1716 1717 // Approximated scaled fractional part of d (due to multiplication). 1718 double scaledFractional = 1719 exactFractionalPart * fastPathData.fractionalScaleFactor; 1720 1721 // Exact integral part of scaled fractional above. 1722 int fractionalPartAsInt = (int) scaledFractional; 1723 1724 // Exact fractional part of scaled fractional above. 1725 scaledFractional = scaledFractional - (double) fractionalPartAsInt; 1726 1727 // Only when scaledFractional is exactly 0.5d do we have to do exact 1728 // calculations and take fine-grained rounding decision, since 1729 // approximated results above may lead to incorrect decision. 1730 // Otherwise comparing against 0.5d (strictly greater or less) is ok. 1731 boolean roundItUp = false; 1732 if (scaledFractional >= 0.5d) { 1733 if (scaledFractional == 0.5d) 1734 // Rounding need fine-grained decision. 1735 roundItUp = exactRoundUp(exactFractionalPart, fractionalPartAsInt); 1736 else 1737 roundItUp = true; 1738 1739 if (roundItUp) { 1740 // Rounds up both fractional part (and also integral if needed). 1741 if (fractionalPartAsInt < fastPathData.fractionalMaxIntBound) { 1742 fractionalPartAsInt++; 1743 } else { 1744 // Propagates rounding to integral part since "all nines" case. 1745 fractionalPartAsInt = 0; 1746 integralPartAsInt++; 1747 } 1748 } 1749 } 1750 1751 // Collecting digits. 1752 collectFractionalDigits(fractionalPartAsInt, container, 1753 fastPathData.fractionalFirstIndex); 1754 collectIntegralDigits(integralPartAsInt, container, 1755 fastPathData.integralLastIndex); 1756 1757 // Localizing digits. 1758 if (fastPathData.zeroDelta != 0) 1759 localizeDigits(container); 1760 1761 // Adding prefix and suffix. 1762 if (negative) { 1763 if (fastPathData.negativeAffixesRequired) 1764 addAffixes(container, 1765 fastPathData.charsNegativePrefix, 1766 fastPathData.charsNegativeSuffix); 1767 } else if (fastPathData.positiveAffixesRequired) 1768 addAffixes(container, 1769 fastPathData.charsPositivePrefix, 1770 fastPathData.charsPositiveSuffix); 1771 } 1772 1773 /** 1774 * A fast-path shortcut of format(double) to be called by NumberFormat, or by 1775 * format(double, ...) public methods. 1776 * 1777 * If instance can be applied fast-path and passed double is not NaN or 1778 * Infinity, is in the integer range, we call {@code fastDoubleFormat} 1779 * after changing {@code d} to its positive value if necessary. 1780 * 1781 * Otherwise returns null by convention since fast-path can't be exercized. 1782 * 1783 * @param d The double value to be formatted 1784 * 1785 * @return the formatted result for {@code d} as a string. 1786 * 1787 String fastFormat(double d) { 1788 // (Re-)Evaluates fast-path status if needed. 1789 if (fastPathCheckNeeded) 1790 checkAndSetFastPathStatus(); 1791 1792 if (!isFastPath ) 1793 // DecimalFormat instance is not in a fast-path state. 1794 return null; 1795 1796 if (!Double.isFinite(d)) 1797 // Should not use fast-path for Infinity and NaN. 1798 return null; 1799 1800 // Extracts and records sign of double value, possibly changing it 1801 // to a positive one, before calling fastDoubleFormat(). 1802 boolean negative = false; 1803 if (d < 0.0d) { 1804 negative = true; 1805 d = -d; 1806 } else if (d == 0.0d) { 1807 negative = (Math.copySign(1.0d, d) == -1.0d); 1808 d = +0.0d; 1809 } 1810 1811 if (d > MAX_INT_AS_DOUBLE) 1812 // Filters out values that are outside expected fast-path range 1813 return null; 1814 else 1815 fastDoubleFormat(d, negative); 1816 1817 // Returns a new string from updated fastPathContainer. 1818 return new String(fastPathData.fastPathContainer, 1819 fastPathData.firstUsedIndex, 1820 fastPathData.lastFreeIndex - fastPathData.firstUsedIndex); 1821 1822 } 1823 1824 // ======== End fast-path formating logic for double ========================= 1825 1826 /** 1827 * Complete the formatting of a finite number. On entry, the digitList must 1828 * be filled in with the correct digits. 1829 * 1830 private StringBuffer subformat(StringBuffer result, FieldDelegate delegate, 1831 boolean isNegative, boolean isInteger, 1832 int maxIntDigits, int minIntDigits, 1833 int maxFraDigits, int minFraDigits) { 1834 // NOTE: This isn't required anymore because DigitList takes care of this. 1835 // 1836 // // The negative of the exponent represents the number of leading 1837 // // zeros between the decimal and the first non-zero digit, for 1838 // // a value < 0.1 (e.g., for 0.00123, -fExponent == 2). If this 1839 // // is more than the maximum fraction digits, then we have an underflow 1840 // // for the printed representation. We recognize this here and set 1841 // // the DigitList representation to zero in this situation. 1842 // 1843 // if (-digitList.decimalAt >= getMaximumFractionDigits()) 1844 // { 1845 // digitList.count = 0; 1846 // } 1847 1848 char zero = symbols.getZeroDigit(); 1849 int zeroDelta = zero - '0'; // '0' is the DigitList representation of zero 1850 char grouping = symbols.getGroupingSeparator(); 1851 char decimal = isCurrencyFormat ? 1852 symbols.getMonetaryDecimalSeparator() : 1853 symbols.getDecimalSeparator(); 1854 1855 /* Per bug 4147706, DecimalFormat must respect the sign of numbers which 1856 * format as zero. This allows sensible computations and preserves 1857 * relations such as signum(1/x) = signum(x), where x is +Infinity or 1858 * -Infinity. Prior to this fix, we always formatted zero values as if 1859 * they were positive. Liu 7/6/98. 1860 * 1861 if (digitList.isZero()) { 1862 digitList.decimalAt = 0; // Normalize 1863 } 1864 1865 if (isNegative) { 1866 append(result, negativePrefix, delegate, 1867 getNegativePrefixFieldPositions(), Field.SIGN); 1868 } else { 1869 append(result, positivePrefix, delegate, 1870 getPositivePrefixFieldPositions(), Field.SIGN); 1871 } 1872 1873 if (useExponentialNotation) { 1874 int iFieldStart = result.length(); 1875 int iFieldEnd = -1; 1876 int fFieldStart = -1; 1877 1878 // Minimum integer digits are handled in exponential format by 1879 // adjusting the exponent. For example, 0.01234 with 3 minimum 1880 // integer digits is "123.4E-4". 1881 1882 // Maximum integer digits are interpreted as indicating the 1883 // repeating range. This is useful for engineering notation, in 1884 // which the exponent is restricted to a multiple of 3. For 1885 // example, 0.01234 with 3 maximum integer digits is "12.34e-3". 1886 // If maximum integer digits are > 1 and are larger than 1887 // minimum integer digits, then minimum integer digits are 1888 // ignored. 1889 int exponent = digitList.decimalAt; 1890 int repeat = maxIntDigits; 1891 int minimumIntegerDigits = minIntDigits; 1892 if (repeat > 1 && repeat > minIntDigits) { 1893 // A repeating range is defined; adjust to it as follows. 1894 // If repeat == 3, we have 6,5,4=>3; 3,2,1=>0; 0,-1,-2=>-3; 1895 // -3,-4,-5=>-6, etc. This takes into account that the 1896 // exponent we have here is off by one from what we expect; 1897 // it is for the format 0.MMMMMx10^n. 1898 if (exponent >= 1) { 1899 exponent = ((exponent - 1) / repeat) * repeat; 1900 } else { 1901 // integer division rounds towards 0 1902 exponent = ((exponent - repeat) / repeat) * repeat; 1903 } 1904 minimumIntegerDigits = 1; 1905 } else { 1906 // No repeating range is defined; use minimum integer digits. 1907 exponent -= minimumIntegerDigits; 1908 } 1909 1910 // We now output a minimum number of digits, and more if there 1911 // are more digits, up to the maximum number of digits. We 1912 // place the decimal point after the "integer" digits, which 1913 // are the first (decimalAt - exponent) digits. 1914 int minimumDigits = minIntDigits + minFraDigits; 1915 if (minimumDigits < 0) { // overflow? 1916 minimumDigits = Integer.MAX_VALUE; 1917 } 1918 1919 // The number of integer digits is handled specially if the number 1920 // is zero, since then there may be no digits. 1921 int integerDigits = digitList.isZero() ? minimumIntegerDigits : 1922 digitList.decimalAt - exponent; 1923 if (minimumDigits < integerDigits) { 1924 minimumDigits = integerDigits; 1925 } 1926 int totalDigits = digitList.count; 1927 if (minimumDigits > totalDigits) { 1928 totalDigits = minimumDigits; 1929 } 1930 boolean addedDecimalSeparator = false; 1931 1932 for (int i=0; i<totalDigits; ++i) { 1933 if (i == integerDigits) { 1934 // Record field information for caller. 1935 iFieldEnd = result.length(); 1936 1937 result.append(decimal); 1938 addedDecimalSeparator = true; 1939 1940 // Record field information for caller. 1941 fFieldStart = result.length(); 1942 } 1943 result.append((i < digitList.count) ? 1944 (char)(digitList.digits[i] + zeroDelta) : 1945 zero); 1946 } 1947 1948 if (decimalSeparatorAlwaysShown && totalDigits == integerDigits) { 1949 // Record field information for caller. 1950 iFieldEnd = result.length(); 1951 1952 result.append(decimal); 1953 addedDecimalSeparator = true; 1954 1955 // Record field information for caller. 1956 fFieldStart = result.length(); 1957 } 1958 1959 // Record field information 1960 if (iFieldEnd == -1) { 1961 iFieldEnd = result.length(); 1962 } 1963 delegate.formatted(INTEGER_FIELD, Field.INTEGER, Field.INTEGER, 1964 iFieldStart, iFieldEnd, result); 1965 if (addedDecimalSeparator) { 1966 delegate.formatted(Field.DECIMAL_SEPARATOR, 1967 Field.DECIMAL_SEPARATOR, 1968 iFieldEnd, fFieldStart, result); 1969 } 1970 if (fFieldStart == -1) { 1971 fFieldStart = result.length(); 1972 } 1973 delegate.formatted(FRACTION_FIELD, Field.FRACTION, Field.FRACTION, 1974 fFieldStart, result.length(), result); 1975 1976 // The exponent is output using the pattern-specified minimum 1977 // exponent digits. There is no maximum limit to the exponent 1978 // digits, since truncating the exponent would result in an 1979 // unacceptable inaccuracy. 1980 int fieldStart = result.length(); 1981 1982 result.append(symbols.getExponentSeparator()); 1983 1984 delegate.formatted(Field.EXPONENT_SYMBOL, Field.EXPONENT_SYMBOL, 1985 fieldStart, result.length(), result); 1986 1987 // For zero values, we force the exponent to zero. We 1988 // must do this here, and not earlier, because the value 1989 // is used to determine integer digit count above. 1990 if (digitList.isZero()) { 1991 exponent = 0; 1992 } 1993 1994 boolean negativeExponent = exponent < 0; 1995 if (negativeExponent) { 1996 exponent = -exponent; 1997 fieldStart = result.length(); 1998 result.append(symbols.getMinusSign()); 1999 delegate.formatted(Field.EXPONENT_SIGN, Field.EXPONENT_SIGN, 2000 fieldStart, result.length(), result); 2001 } 2002 digitList.set(negativeExponent, exponent); 2003 2004 int eFieldStart = result.length(); 2005 2006 for (int i=digitList.decimalAt; i<minExponentDigits; ++i) { 2007 result.append(zero); 2008 } 2009 for (int i=0; i<digitList.decimalAt; ++i) { 2010 result.append((i < digitList.count) ? 2011 (char)(digitList.digits[i] + zeroDelta) : zero); 2012 } 2013 delegate.formatted(Field.EXPONENT, Field.EXPONENT, eFieldStart, 2014 result.length(), result); 2015 } else { 2016 int iFieldStart = result.length(); 2017 2018 // Output the integer portion. Here 'count' is the total 2019 // number of integer digits we will display, including both 2020 // leading zeros required to satisfy getMinimumIntegerDigits, 2021 // and actual digits present in the number. 2022 int count = minIntDigits; 2023 int digitIndex = 0; // Index into digitList.fDigits[] 2024 if (digitList.decimalAt > 0 && count < digitList.decimalAt) { 2025 count = digitList.decimalAt; 2026 } 2027 2028 // Handle the case where getMaximumIntegerDigits() is smaller 2029 // than the real number of integer digits. If this is so, we 2030 // output the least significant max integer digits. For example, 2031 // the value 1997 printed with 2 max integer digits is just "97". 2032 if (count > maxIntDigits) { 2033 count = maxIntDigits; 2034 digitIndex = digitList.decimalAt - count; 2035 } 2036 2037 int sizeBeforeIntegerPart = result.length(); 2038 for (int i=count-1; i>=0; --i) { 2039 if (i < digitList.decimalAt && digitIndex < digitList.count) { 2040 // Output a real digit 2041 result.append((char)(digitList.digits[digitIndex++] + zeroDelta)); 2042 } else { 2043 // Output a leading zero 2044 result.append(zero); 2045 } 2046 2047 // Output grouping separator if necessary. Don't output a 2048 // grouping separator if i==0 though; that's at the end of 2049 // the integer part. 2050 if (isGroupingUsed() && i>0 && (groupingSize != 0) && 2051 (i % groupingSize == 0)) { 2052 int gStart = result.length(); 2053 result.append(grouping); 2054 delegate.formatted(Field.GROUPING_SEPARATOR, 2055 Field.GROUPING_SEPARATOR, gStart, 2056 result.length(), result); 2057 } 2058 } 2059 2060 // Determine whether or not there are any printable fractional 2061 // digits. If we've used up the digits we know there aren't. 2062 boolean fractionPresent = (minFraDigits > 0) || 2063 (!isInteger && digitIndex < digitList.count); 2064 2065 // If there is no fraction present, and we haven't printed any 2066 // integer digits, then print a zero. Otherwise we won't print 2067 // _any_ digits, and we won't be able to parse this string. 2068 if (!fractionPresent && result.length() == sizeBeforeIntegerPart) { 2069 result.append(zero); 2070 } 2071 2072 delegate.formatted(INTEGER_FIELD, Field.INTEGER, Field.INTEGER, 2073 iFieldStart, result.length(), result); 2074 2075 // Output the decimal separator if we always do so. 2076 int sStart = result.length(); 2077 if (decimalSeparatorAlwaysShown || fractionPresent) { 2078 result.append(decimal); 2079 } 2080 2081 if (sStart != result.length()) { 2082 delegate.formatted(Field.DECIMAL_SEPARATOR, 2083 Field.DECIMAL_SEPARATOR, 2084 sStart, result.length(), result); 2085 } 2086 int fFieldStart = result.length(); 2087 2088 for (int i=0; i < maxFraDigits; ++i) { 2089 // Here is where we escape from the loop. We escape if we've 2090 // output the maximum fraction digits (specified in the for 2091 // expression above). 2092 // We also stop when we've output the minimum digits and either: 2093 // we have an integer, so there is no fractional stuff to 2094 // display, or we're out of significant digits. 2095 if (i >= minFraDigits && 2096 (isInteger || digitIndex >= digitList.count)) { 2097 break; 2098 } 2099 2100 // Output leading fractional zeros. These are zeros that come 2101 // after the decimal but before any significant digits. These 2102 // are only output if abs(number being formatted) < 1.0. 2103 if (-1-i > (digitList.decimalAt-1)) { 2104 result.append(zero); 2105 continue; 2106 } 2107 2108 // Output a digit, if we have any precision left, or a 2109 // zero if we don't. We don't want to output noise digits. 2110 if (!isInteger && digitIndex < digitList.count) { 2111 result.append((char)(digitList.digits[digitIndex++] + zeroDelta)); 2112 } else { 2113 result.append(zero); 2114 } 2115 } 2116 2117 // Record field information for caller. 2118 delegate.formatted(FRACTION_FIELD, Field.FRACTION, Field.FRACTION, 2119 fFieldStart, result.length(), result); 2120 } 2121 2122 if (isNegative) { 2123 append(result, negativeSuffix, delegate, 2124 getNegativeSuffixFieldPositions(), Field.SIGN); 2125 } else { 2126 append(result, positiveSuffix, delegate, 2127 getPositiveSuffixFieldPositions(), Field.SIGN); 2128 } 2129 2130 return result; 2131 } 2132 2133 /** 2134 * Appends the String <code>string</code> to <code>result</code>. 2135 * <code>delegate</code> is notified of all the 2136 * <code>FieldPosition</code>s in <code>positions</code>. 2137 * <p> 2138 * If one of the <code>FieldPosition</code>s in <code>positions</code> 2139 * identifies a <code>SIGN</code> attribute, it is mapped to 2140 * <code>signAttribute</code>. This is used 2141 * to map the <code>SIGN</code> attribute to the <code>EXPONENT</code> 2142 * attribute as necessary. 2143 * <p> 2144 * This is used by <code>subformat</code> to add the prefix/suffix. 2145 * 2146 private void append(StringBuffer result, String string, 2147 FieldDelegate delegate, 2148 FieldPosition[] positions, 2149 Format.Field signAttribute) { 2150 int start = result.length(); 2151 2152 if (string.length() > 0) { 2153 result.append(string); 2154 for (int counter = 0, max = positions.length; counter < max; 2155 counter++) { 2156 FieldPosition fp = positions[counter]; 2157 Format.Field attribute = fp.getFieldAttribute(); 2158 2159 if (attribute == Field.SIGN) { 2160 attribute = signAttribute; 2161 } 2162 delegate.formatted(attribute, attribute, 2163 start + fp.getBeginIndex(), 2164 start + fp.getEndIndex(), result); 2165 } 2166 } 2167 } 2168 */ 2169 // END Android-removed: "fast-path formatting logic for double", subformat(), append(). 2170 2171 /** 2172 * Parses text from a string to produce a <code>Number</code>. 2173 * <p> 2174 * The method attempts to parse text starting at the index given by 2175 * <code>pos</code>. 2176 * If parsing succeeds, then the index of <code>pos</code> is updated 2177 * to the index after the last character used (parsing does not necessarily 2178 * use all characters up to the end of the string), and the parsed 2179 * number is returned. The updated <code>pos</code> can be used to 2180 * indicate the starting point for the next call to this method. 2181 * If an error occurs, then the index of <code>pos</code> is not 2182 * changed, the error index of <code>pos</code> is set to the index of 2183 * the character where the error occurred, and null is returned. 2184 * <p> 2185 * The subclass returned depends on the value of {@link #isParseBigDecimal} 2186 * as well as on the string being parsed. 2187 * <ul> 2188 * <li>If <code>isParseBigDecimal()</code> is false (the default), 2189 * most integer values are returned as <code>Long</code> 2190 * objects, no matter how they are written: <code>"17"</code> and 2191 * <code>"17.000"</code> both parse to <code>Long(17)</code>. 2192 * Values that cannot fit into a <code>Long</code> are returned as 2193 * <code>Double</code>s. This includes values with a fractional part, 2194 * infinite values, <code>NaN</code>, and the value -0.0. 2195 * <code>DecimalFormat</code> does <em>not</em> decide whether to 2196 * return a <code>Double</code> or a <code>Long</code> based on the 2197 * presence of a decimal separator in the source string. Doing so 2198 * would prevent integers that overflow the mantissa of a double, 2199 * such as <code>"-9,223,372,036,854,775,808.00"</code>, from being 2200 * parsed accurately. 2201 * <p> 2202 * Callers may use the <code>Number</code> methods 2203 * <code>doubleValue</code>, <code>longValue</code>, etc., to obtain 2204 * the type they want. 2205 * <li>If <code>isParseBigDecimal()</code> is true, values are returned 2206 * as <code>BigDecimal</code> objects. The values are the ones 2207 * constructed by {@link java.math.BigDecimal#BigDecimal(String)} 2208 * for corresponding strings in locale-independent format. The 2209 * special cases negative and positive infinity and NaN are returned 2210 * as <code>Double</code> instances holding the values of the 2211 * corresponding <code>Double</code> constants. 2212 * </ul> 2213 * <p> 2214 * <code>DecimalFormat</code> parses all Unicode characters that represent 2215 * decimal digits, as defined by <code>Character.digit()</code>. In 2216 * addition, <code>DecimalFormat</code> also recognizes as digits the ten 2217 * consecutive characters starting with the localized zero digit defined in 2218 * the <code>DecimalFormatSymbols</code> object. 2219 * 2220 * @param text the string to be parsed 2221 * @param pos A <code>ParsePosition</code> object with index and error 2222 * index information as described above. 2223 * @return the parsed value, or <code>null</code> if the parse fails 2224 * @exception NullPointerException if <code>text</code> or 2225 * <code>pos</code> is null. 2226 */ 2227 @Override parse(String text, ParsePosition pos)2228 public Number parse(String text, ParsePosition pos) { 2229 // BEGIN Android-changed: Use ICU. 2230 // Return early if the parse position is bogus. 2231 /* 2232 // special case NaN 2233 if (text.regionMatches(pos.index, symbols.getNaN(), 0, symbols.getNaN().length())) { 2234 pos.index = pos.index + symbols.getNaN().length(); 2235 return new Double(Double.NaN); 2236 } 2237 2238 boolean[] status = new boolean[STATUS_LENGTH]; 2239 if (!subparse(text, pos, positivePrefix, negativePrefix, digitList, false, status)) { 2240 return null; 2241 } 2242 2243 // special case INFINITY 2244 if (status[STATUS_INFINITE]) { 2245 if (status[STATUS_POSITIVE] == (multiplier >= 0)) { 2246 return new Double(Double.POSITIVE_INFINITY); 2247 } else { 2248 return new Double(Double.NEGATIVE_INFINITY); 2249 } 2250 } 2251 2252 if (multiplier == 0) { 2253 if (digitList.isZero()) { 2254 return new Double(Double.NaN); 2255 } else if (status[STATUS_POSITIVE]) { 2256 return new Double(Double.POSITIVE_INFINITY); 2257 } else { 2258 return new Double(Double.NEGATIVE_INFINITY); 2259 } 2260 } 2261 2262 if (isParseBigDecimal()) { 2263 BigDecimal bigDecimalResult = digitList.getBigDecimal(); 2264 2265 if (multiplier != 1) { 2266 try { 2267 bigDecimalResult = bigDecimalResult.divide(getBigDecimalMultiplier()); 2268 } 2269 catch (ArithmeticException e) { // non-terminating decimal expansion 2270 bigDecimalResult = bigDecimalResult.divide(getBigDecimalMultiplier(), roundingMode); 2271 } 2272 } 2273 2274 if (!status[STATUS_POSITIVE]) { 2275 bigDecimalResult = bigDecimalResult.negate(); 2276 } 2277 return bigDecimalResult; 2278 } else { 2279 boolean gotDouble = true; 2280 boolean gotLongMinimum = false; 2281 double doubleResult = 0.0; 2282 long longResult = 0; 2283 2284 // Finally, have DigitList parse the digits into a value. 2285 if (digitList.fitsIntoLong(status[STATUS_POSITIVE], isParseIntegerOnly())) { 2286 gotDouble = false; 2287 longResult = digitList.getLong(); 2288 if (longResult < 0) { // got Long.MIN_VALUE 2289 gotLongMinimum = true; 2290 } 2291 } else { 2292 doubleResult = digitList.getDouble(); 2293 } 2294 2295 // Divide by multiplier. We have to be careful here not to do 2296 // unneeded conversions between double and long. 2297 if (multiplier != 1) { 2298 if (gotDouble) { 2299 doubleResult /= multiplier; 2300 } else { 2301 // Avoid converting to double if we can 2302 if (longResult % multiplier == 0) { 2303 longResult /= multiplier; 2304 } else { 2305 doubleResult = ((double)longResult) / multiplier; 2306 gotDouble = true; 2307 } 2308 } 2309 } 2310 2311 if (!status[STATUS_POSITIVE] && !gotLongMinimum) { 2312 doubleResult = -doubleResult; 2313 longResult = -longResult; 2314 } 2315 2316 // At this point, if we divided the result by the multiplier, the 2317 // result may fit into a long. We check for this case and return 2318 // a long if possible. 2319 // We must do this AFTER applying the negative (if appropriate) 2320 // in order to handle the case of LONG_MIN; otherwise, if we do 2321 // this with a positive value -LONG_MIN, the double is > 0, but 2322 // the long is < 0. We also must retain a double in the case of 2323 // -0.0, which will compare as == to a long 0 cast to a double 2324 // (bug 4162852). 2325 if (multiplier != 1 && gotDouble) { 2326 longResult = (long)doubleResult; 2327 gotDouble = ((doubleResult != (double)longResult) || 2328 (doubleResult == 0.0 && 1/doubleResult < 0.0)) && 2329 !isParseIntegerOnly(); 2330 } 2331 2332 return gotDouble ? 2333 (Number)new Double(doubleResult) : (Number)new Long(longResult); 2334 } 2335 */ 2336 if (pos.index < 0 || pos.index >= text.length()) { 2337 return null; 2338 } 2339 2340 // This might return android.icu.math.BigDecimal, java.math.BigInteger or a primitive type. 2341 Number number = icuDecimalFormat.parse(text, pos); 2342 if (number == null) { 2343 return null; 2344 } 2345 if (isParseBigDecimal()) { 2346 if (number instanceof Long) { 2347 return new BigDecimal(number.longValue()); 2348 } 2349 if ((number instanceof Double) && !((Double) number).isInfinite() 2350 && !((Double) number).isNaN()) { 2351 return new BigDecimal(number.toString()); 2352 } 2353 if ((number instanceof Double) && 2354 (((Double) number).isNaN() || ((Double) number).isInfinite())) { 2355 return number; 2356 } 2357 if (number instanceof android.icu.math.BigDecimal) { 2358 return ((android.icu.math.BigDecimal) number).toBigDecimal(); 2359 } 2360 } 2361 if ((number instanceof android.icu.math.BigDecimal) || (number instanceof BigInteger)) { 2362 return number.doubleValue(); 2363 } 2364 if (isParseIntegerOnly() && number.equals(new Double(-0.0))) { 2365 return 0L; 2366 } 2367 return number; 2368 // END Android-changed: Use ICU. 2369 } 2370 2371 // BEGIN Android-removed: Unused private helpers. 2372 /* 2373 /** 2374 * Return a BigInteger multiplier. 2375 * 2376 private BigInteger getBigIntegerMultiplier() { 2377 if (bigIntegerMultiplier == null) { 2378 bigIntegerMultiplier = BigInteger.valueOf(multiplier); 2379 } 2380 return bigIntegerMultiplier; 2381 } 2382 private transient BigInteger bigIntegerMultiplier; 2383 2384 /** 2385 * Return a BigDecimal multiplier. 2386 * 2387 private BigDecimal getBigDecimalMultiplier() { 2388 if (bigDecimalMultiplier == null) { 2389 bigDecimalMultiplier = new BigDecimal(multiplier); 2390 } 2391 return bigDecimalMultiplier; 2392 } 2393 private transient BigDecimal bigDecimalMultiplier; 2394 2395 private static final int STATUS_INFINITE = 0; 2396 private static final int STATUS_POSITIVE = 1; 2397 private static final int STATUS_LENGTH = 2; 2398 2399 /** 2400 * Parse the given text into a number. The text is parsed beginning at 2401 * parsePosition, until an unparseable character is seen. 2402 * @param text The string to parse. 2403 * @param parsePosition The position at which to being parsing. Upon 2404 * return, the first unparseable character. 2405 * @param digits The DigitList to set to the parsed value. 2406 * @param isExponent If true, parse an exponent. This means no 2407 * infinite values and integer only. 2408 * @param status Upon return contains boolean status flags indicating 2409 * whether the value was infinite and whether it was positive. 2410 * 2411 private final boolean subparse(String text, ParsePosition parsePosition, 2412 String positivePrefix, String negativePrefix, 2413 DigitList digits, boolean isExponent, 2414 boolean status[]) { 2415 int position = parsePosition.index; 2416 int oldStart = parsePosition.index; 2417 int backup; 2418 boolean gotPositive, gotNegative; 2419 2420 // check for positivePrefix; take longest 2421 gotPositive = text.regionMatches(position, positivePrefix, 0, 2422 positivePrefix.length()); 2423 gotNegative = text.regionMatches(position, negativePrefix, 0, 2424 negativePrefix.length()); 2425 2426 if (gotPositive && gotNegative) { 2427 if (positivePrefix.length() > negativePrefix.length()) { 2428 gotNegative = false; 2429 } else if (positivePrefix.length() < negativePrefix.length()) { 2430 gotPositive = false; 2431 } 2432 } 2433 2434 if (gotPositive) { 2435 position += positivePrefix.length(); 2436 } else if (gotNegative) { 2437 position += negativePrefix.length(); 2438 } else { 2439 parsePosition.errorIndex = position; 2440 return false; 2441 } 2442 2443 // process digits or Inf, find decimal position 2444 status[STATUS_INFINITE] = false; 2445 if (!isExponent && text.regionMatches(position,symbols.getInfinity(),0, 2446 symbols.getInfinity().length())) { 2447 position += symbols.getInfinity().length(); 2448 status[STATUS_INFINITE] = true; 2449 } else { 2450 // We now have a string of digits, possibly with grouping symbols, 2451 // and decimal points. We want to process these into a DigitList. 2452 // We don't want to put a bunch of leading zeros into the DigitList 2453 // though, so we keep track of the location of the decimal point, 2454 // put only significant digits into the DigitList, and adjust the 2455 // exponent as needed. 2456 2457 digits.decimalAt = digits.count = 0; 2458 char zero = symbols.getZeroDigit(); 2459 char decimal = isCurrencyFormat ? 2460 symbols.getMonetaryDecimalSeparator() : 2461 symbols.getDecimalSeparator(); 2462 char grouping = symbols.getGroupingSeparator(); 2463 String exponentString = symbols.getExponentSeparator(); 2464 boolean sawDecimal = false; 2465 boolean sawExponent = false; 2466 boolean sawDigit = false; 2467 int exponent = 0; // Set to the exponent value, if any 2468 2469 // We have to track digitCount ourselves, because digits.count will 2470 // pin when the maximum allowable digits is reached. 2471 int digitCount = 0; 2472 2473 backup = -1; 2474 for (; position < text.length(); ++position) { 2475 char ch = text.charAt(position); 2476 2477 /* We recognize all digit ranges, not only the Latin digit range 2478 * '0'..'9'. We do so by using the Character.digit() method, 2479 * which converts a valid Unicode digit to the range 0..9. 2480 * 2481 * The character 'ch' may be a digit. If so, place its value 2482 * from 0 to 9 in 'digit'. First try using the locale digit, 2483 * which may or MAY NOT be a standard Unicode digit range. If 2484 * this fails, try using the standard Unicode digit ranges by 2485 * calling Character.digit(). If this also fails, digit will 2486 * have a value outside the range 0..9. 2487 * 2488 int digit = ch - zero; 2489 if (digit < 0 || digit > 9) { 2490 digit = Character.digit(ch, 10); 2491 } 2492 2493 if (digit == 0) { 2494 // Cancel out backup setting (see grouping handler below) 2495 backup = -1; // Do this BEFORE continue statement below!!! 2496 sawDigit = true; 2497 2498 // Handle leading zeros 2499 if (digits.count == 0) { 2500 // Ignore leading zeros in integer part of number. 2501 if (!sawDecimal) { 2502 continue; 2503 } 2504 2505 // If we have seen the decimal, but no significant 2506 // digits yet, then we account for leading zeros by 2507 // decrementing the digits.decimalAt into negative 2508 // values. 2509 --digits.decimalAt; 2510 } else { 2511 ++digitCount; 2512 digits.append((char)(digit + '0')); 2513 } 2514 } else if (digit > 0 && digit <= 9) { // [sic] digit==0 handled above 2515 sawDigit = true; 2516 ++digitCount; 2517 digits.append((char)(digit + '0')); 2518 2519 // Cancel out backup setting (see grouping handler below) 2520 backup = -1; 2521 } else if (!isExponent && ch == decimal) { 2522 // If we're only parsing integers, or if we ALREADY saw the 2523 // decimal, then don't parse this one. 2524 if (isParseIntegerOnly() || sawDecimal) { 2525 break; 2526 } 2527 digits.decimalAt = digitCount; // Not digits.count! 2528 sawDecimal = true; 2529 } else if (!isExponent && ch == grouping && isGroupingUsed()) { 2530 if (sawDecimal) { 2531 break; 2532 } 2533 // Ignore grouping characters, if we are using them, but 2534 // require that they be followed by a digit. Otherwise 2535 // we backup and reprocess them. 2536 backup = position; 2537 } else if (!isExponent && text.regionMatches(position, exponentString, 0, exponentString.length()) 2538 && !sawExponent) { 2539 // Process the exponent by recursively calling this method. 2540 ParsePosition pos = new ParsePosition(position + exponentString.length()); 2541 boolean[] stat = new boolean[STATUS_LENGTH]; 2542 DigitList exponentDigits = new DigitList(); 2543 2544 if (subparse(text, pos, "", Character.toString(symbols.getMinusSign()), exponentDigits, true, stat) && 2545 exponentDigits.fitsIntoLong(stat[STATUS_POSITIVE], true)) { 2546 position = pos.index; // Advance past the exponent 2547 exponent = (int)exponentDigits.getLong(); 2548 if (!stat[STATUS_POSITIVE]) { 2549 exponent = -exponent; 2550 } 2551 sawExponent = true; 2552 } 2553 break; // Whether we fail or succeed, we exit this loop 2554 } else { 2555 break; 2556 } 2557 } 2558 2559 if (backup != -1) { 2560 position = backup; 2561 } 2562 2563 // If there was no decimal point we have an integer 2564 if (!sawDecimal) { 2565 digits.decimalAt = digitCount; // Not digits.count! 2566 } 2567 2568 // Adjust for exponent, if any 2569 digits.decimalAt += exponent; 2570 2571 // If none of the text string was recognized. For example, parse 2572 // "x" with pattern "#0.00" (return index and error index both 0) 2573 // parse "$" with pattern "$#0.00". (return index 0 and error 2574 // index 1). 2575 if (!sawDigit && digitCount == 0) { 2576 parsePosition.index = oldStart; 2577 parsePosition.errorIndex = oldStart; 2578 return false; 2579 } 2580 } 2581 2582 // check for suffix 2583 if (!isExponent) { 2584 if (gotPositive) { 2585 gotPositive = text.regionMatches(position,positiveSuffix,0, 2586 positiveSuffix.length()); 2587 } 2588 if (gotNegative) { 2589 gotNegative = text.regionMatches(position,negativeSuffix,0, 2590 negativeSuffix.length()); 2591 } 2592 2593 // if both match, take longest 2594 if (gotPositive && gotNegative) { 2595 if (positiveSuffix.length() > negativeSuffix.length()) { 2596 gotNegative = false; 2597 } else if (positiveSuffix.length() < negativeSuffix.length()) { 2598 gotPositive = false; 2599 } 2600 } 2601 2602 // fail if neither or both 2603 if (gotPositive == gotNegative) { 2604 parsePosition.errorIndex = position; 2605 return false; 2606 } 2607 2608 parsePosition.index = position + 2609 (gotPositive ? positiveSuffix.length() : negativeSuffix.length()); // mark success! 2610 } else { 2611 parsePosition.index = position; 2612 } 2613 2614 status[STATUS_POSITIVE] = gotPositive; 2615 if (parsePosition.index == oldStart) { 2616 parsePosition.errorIndex = position; 2617 return false; 2618 } 2619 return true; 2620 } 2621 */ 2622 // END Android-removed: Unused private helpers. 2623 2624 /** 2625 * Returns a copy of the decimal format symbols, which is generally not 2626 * changed by the programmer or user. 2627 * @return a copy of the desired DecimalFormatSymbols 2628 * @see java.text.DecimalFormatSymbols 2629 */ getDecimalFormatSymbols()2630 public DecimalFormatSymbols getDecimalFormatSymbols() { 2631 // BEGIN Android-changed: Use ICU. 2632 /* 2633 try { 2634 // don't allow multiple references 2635 return (DecimalFormatSymbols) symbols.clone(); 2636 } catch (Exception foo) { 2637 return null; // should never happen 2638 } 2639 */ 2640 return DecimalFormatSymbols.fromIcuInstance(icuDecimalFormat.getDecimalFormatSymbols()); 2641 // END Android-changed: Use ICU. 2642 } 2643 2644 2645 /** 2646 * Sets the decimal format symbols, which is generally not changed 2647 * by the programmer or user. 2648 * @param newSymbols desired DecimalFormatSymbols 2649 * @see java.text.DecimalFormatSymbols 2650 */ setDecimalFormatSymbols(DecimalFormatSymbols newSymbols)2651 public void setDecimalFormatSymbols(DecimalFormatSymbols newSymbols) { 2652 try { 2653 // don't allow multiple references 2654 symbols = (DecimalFormatSymbols) newSymbols.clone(); 2655 // BEGIN Android-changed: Use ICU. 2656 /* 2657 expandAffixes(); 2658 fastPathCheckNeeded = true; 2659 */ 2660 icuDecimalFormat.setDecimalFormatSymbols(symbols.getIcuDecimalFormatSymbols()); 2661 // END Android-changed: Use ICU. 2662 } catch (Exception foo) { 2663 // should never happen 2664 } 2665 } 2666 2667 /** 2668 * Get the positive prefix. 2669 * <P>Examples: +123, $123, sFr123 2670 * 2671 * @return the positive prefix 2672 */ getPositivePrefix()2673 public String getPositivePrefix () { 2674 // Android-changed: Use ICU. 2675 // return positivePrefix; 2676 return icuDecimalFormat.getPositivePrefix(); 2677 } 2678 2679 /** 2680 * Set the positive prefix. 2681 * <P>Examples: +123, $123, sFr123 2682 * 2683 * @param newValue the new positive prefix 2684 */ setPositivePrefix(String newValue)2685 public void setPositivePrefix (String newValue) { 2686 // BEGIN Android-changed: Use ICU. 2687 /* 2688 positivePrefix = newValue; 2689 posPrefixPattern = null; 2690 positivePrefixFieldPositions = null; 2691 fastPathCheckNeeded = true; 2692 */ 2693 icuDecimalFormat.setPositivePrefix(newValue); 2694 // END Android-changed: Use ICU. 2695 } 2696 2697 // BEGIN Android-removed: private helper getPositivePrefixFieldPositions(). 2698 /* 2699 /** 2700 * Returns the FieldPositions of the fields in the prefix used for 2701 * positive numbers. This is not used if the user has explicitly set 2702 * a positive prefix via <code>setPositivePrefix</code>. This is 2703 * lazily created. 2704 * 2705 * @return FieldPositions in positive prefix 2706 * 2707 private FieldPosition[] getPositivePrefixFieldPositions() { 2708 if (positivePrefixFieldPositions == null) { 2709 if (posPrefixPattern != null) { 2710 positivePrefixFieldPositions = expandAffix(posPrefixPattern); 2711 } else { 2712 positivePrefixFieldPositions = EmptyFieldPositionArray; 2713 } 2714 } 2715 return positivePrefixFieldPositions; 2716 } 2717 */ 2718 // END Android-removed: private helper getPositivePrefixFieldPositions(). 2719 2720 /** 2721 * Get the negative prefix. 2722 * <P>Examples: -123, ($123) (with negative suffix), sFr-123 2723 * 2724 * @return the negative prefix 2725 */ getNegativePrefix()2726 public String getNegativePrefix () { 2727 // Android-changed: Use ICU. 2728 // return negativePrefix; 2729 return icuDecimalFormat.getNegativePrefix(); 2730 } 2731 2732 /** 2733 * Set the negative prefix. 2734 * <P>Examples: -123, ($123) (with negative suffix), sFr-123 2735 * 2736 * @param newValue the new negative prefix 2737 */ setNegativePrefix(String newValue)2738 public void setNegativePrefix (String newValue) { 2739 // BEGIN Android-changed: Use ICU. 2740 /* 2741 negativePrefix = newValue; 2742 negPrefixPattern = null; 2743 fastPathCheckNeeded = true; 2744 */ 2745 icuDecimalFormat.setNegativePrefix(newValue); 2746 // END Android-changed: Use ICU. 2747 } 2748 2749 // BEGIN Android-removed: private helper getNegativePrefixFieldPositions(). 2750 /* 2751 /** 2752 * Returns the FieldPositions of the fields in the prefix used for 2753 * negative numbers. This is not used if the user has explicitly set 2754 * a negative prefix via <code>setNegativePrefix</code>. This is 2755 * lazily created. 2756 * 2757 * @return FieldPositions in positive prefix 2758 * 2759 private FieldPosition[] getNegativePrefixFieldPositions() { 2760 if (negativePrefixFieldPositions == null) { 2761 if (negPrefixPattern != null) { 2762 negativePrefixFieldPositions = expandAffix(negPrefixPattern); 2763 } else { 2764 negativePrefixFieldPositions = EmptyFieldPositionArray; 2765 } 2766 } 2767 return negativePrefixFieldPositions; 2768 } 2769 */ 2770 // END Android-removed: private helper getNegativePrefixFieldPositions(). 2771 2772 /** 2773 * Get the positive suffix. 2774 * <P>Example: 123% 2775 * 2776 * @return the positive suffix 2777 */ getPositiveSuffix()2778 public String getPositiveSuffix () { 2779 // Android-changed: Use ICU. 2780 // return positiveSuffix; 2781 return icuDecimalFormat.getPositiveSuffix(); 2782 } 2783 2784 /** 2785 * Set the positive suffix. 2786 * <P>Example: 123% 2787 * 2788 * @param newValue the new positive suffix 2789 */ setPositiveSuffix(String newValue)2790 public void setPositiveSuffix (String newValue) { 2791 // BEGIN Android-changed: Use ICU. 2792 /* 2793 positiveSuffix = newValue; 2794 posSuffixPattern = null; 2795 fastPathCheckNeeded = true; 2796 */ 2797 icuDecimalFormat.setPositiveSuffix(newValue); 2798 // END Android-changed: Use ICU. 2799 } 2800 2801 // BEGIN Android-removed: private helper getPositiveSuffixFieldPositions(). 2802 /* 2803 /** 2804 * Returns the FieldPositions of the fields in the suffix used for 2805 * positive numbers. This is not used if the user has explicitly set 2806 * a positive suffix via <code>setPositiveSuffix</code>. This is 2807 * lazily created. 2808 * 2809 * @return FieldPositions in positive prefix 2810 * 2811 private FieldPosition[] getPositiveSuffixFieldPositions() { 2812 if (positiveSuffixFieldPositions == null) { 2813 if (posSuffixPattern != null) { 2814 positiveSuffixFieldPositions = expandAffix(posSuffixPattern); 2815 } else { 2816 positiveSuffixFieldPositions = EmptyFieldPositionArray; 2817 } 2818 } 2819 return positiveSuffixFieldPositions; 2820 } 2821 */ 2822 // END Android-removed: private helper getPositiveSuffixFieldPositions(). 2823 2824 /** 2825 * Get the negative suffix. 2826 * <P>Examples: -123%, ($123) (with positive suffixes) 2827 * 2828 * @return the negative suffix 2829 */ getNegativeSuffix()2830 public String getNegativeSuffix () { 2831 // Android-changed: Use ICU. 2832 // return negativeSuffix; 2833 return icuDecimalFormat.getNegativeSuffix(); 2834 } 2835 2836 /** 2837 * Set the negative suffix. 2838 * <P>Examples: 123% 2839 * 2840 * @param newValue the new negative suffix 2841 */ setNegativeSuffix(String newValue)2842 public void setNegativeSuffix (String newValue) { 2843 // BEGIN Android-changed: Use ICU. 2844 /* 2845 negativeSuffix = newValue; 2846 negSuffixPattern = null; 2847 fastPathCheckNeeded = true; 2848 */ 2849 icuDecimalFormat.setNegativeSuffix(newValue); 2850 // END Android-changed: Use ICU. 2851 } 2852 2853 // BEGIN Android-removed: private helper getNegativeSuffixFieldPositions(). 2854 /* 2855 /** 2856 * Returns the FieldPositions of the fields in the suffix used for 2857 * negative numbers. This is not used if the user has explicitly set 2858 * a negative suffix via <code>setNegativeSuffix</code>. This is 2859 * lazily created. 2860 * 2861 * @return FieldPositions in positive prefix 2862 * 2863 private FieldPosition[] getNegativeSuffixFieldPositions() { 2864 if (negativeSuffixFieldPositions == null) { 2865 if (negSuffixPattern != null) { 2866 negativeSuffixFieldPositions = expandAffix(negSuffixPattern); 2867 } else { 2868 negativeSuffixFieldPositions = EmptyFieldPositionArray; 2869 } 2870 } 2871 return negativeSuffixFieldPositions; 2872 } 2873 */ 2874 // END Android-removed: private helper getNegativeSuffixFieldPositions(). 2875 2876 /** 2877 * Gets the multiplier for use in percent, per mille, and similar 2878 * formats. 2879 * 2880 * @return the multiplier 2881 * @see #setMultiplier(int) 2882 */ getMultiplier()2883 public int getMultiplier () { 2884 // Android-changed: Use ICU. 2885 // return multiplier; 2886 return icuDecimalFormat.getMultiplier(); 2887 } 2888 2889 /** 2890 * Sets the multiplier for use in percent, per mille, and similar 2891 * formats. 2892 * For a percent format, set the multiplier to 100 and the suffixes to 2893 * have '%' (for Arabic, use the Arabic percent sign). 2894 * For a per mille format, set the multiplier to 1000 and the suffixes to 2895 * have '\u2030'. 2896 * 2897 * <P>Example: with multiplier 100, 1.23 is formatted as "123", and 2898 * "123" is parsed into 1.23. 2899 * 2900 * @param newValue the new multiplier 2901 * @see #getMultiplier 2902 */ setMultiplier(int newValue)2903 public void setMultiplier (int newValue) { 2904 // BEGIN Android-changed: Use ICU. 2905 /* 2906 multiplier = newValue; 2907 bigDecimalMultiplier = null; 2908 bigIntegerMultiplier = null; 2909 fastPathCheckNeeded = true; 2910 */ 2911 icuDecimalFormat.setMultiplier(newValue); 2912 // END Android-changed: Use ICU. 2913 } 2914 2915 /** 2916 * {@inheritDoc} 2917 */ 2918 @Override setGroupingUsed(boolean newValue)2919 public void setGroupingUsed(boolean newValue) { 2920 // BEGIN Android-changed: Use ICU. 2921 /* 2922 super.setGroupingUsed(newValue); 2923 fastPathCheckNeeded = true; 2924 */ 2925 icuDecimalFormat.setGroupingUsed(newValue); 2926 // END Android-changed: Use ICU. 2927 } 2928 2929 // BEGIN Android-added: isGroupingUsed() override delegating to ICU. 2930 /** 2931 * {@inheritDoc} 2932 */ 2933 @Override isGroupingUsed()2934 public boolean isGroupingUsed() { 2935 return icuDecimalFormat.isGroupingUsed(); 2936 } 2937 // END Android-added: isGroupingUsed() override delegating to ICU. 2938 2939 /** 2940 * Return the grouping size. Grouping size is the number of digits between 2941 * grouping separators in the integer portion of a number. For example, 2942 * in the number "123,456.78", the grouping size is 3. 2943 * 2944 * @return the grouping size 2945 * @see #setGroupingSize 2946 * @see java.text.NumberFormat#isGroupingUsed 2947 * @see java.text.DecimalFormatSymbols#getGroupingSeparator 2948 */ getGroupingSize()2949 public int getGroupingSize () { 2950 // Android-changed: Use ICU. 2951 // return groupingSize; 2952 return icuDecimalFormat.getGroupingSize(); 2953 } 2954 2955 /** 2956 * Set the grouping size. Grouping size is the number of digits between 2957 * grouping separators in the integer portion of a number. For example, 2958 * in the number "123,456.78", the grouping size is 3. 2959 * <br> 2960 * The value passed in is converted to a byte, which may lose information. 2961 * 2962 * @param newValue the new grouping size 2963 * @see #getGroupingSize 2964 * @see java.text.NumberFormat#setGroupingUsed 2965 * @see java.text.DecimalFormatSymbols#setGroupingSeparator 2966 */ setGroupingSize(int newValue)2967 public void setGroupingSize (int newValue) { 2968 // BEGIN Android-changed: Use ICU. 2969 /* 2970 groupingSize = (byte)newValue; 2971 fastPathCheckNeeded = true; 2972 */ 2973 icuDecimalFormat.setGroupingSize(newValue); 2974 // END Android-changed: Use ICU. 2975 } 2976 2977 /** 2978 * Allows you to get the behavior of the decimal separator with integers. 2979 * (The decimal separator will always appear with decimals.) 2980 * <P>Example: Decimal ON: 12345 → 12345.; OFF: 12345 → 12345 2981 * 2982 * @return {@code true} if the decimal separator is always shown; 2983 * {@code false} otherwise 2984 */ isDecimalSeparatorAlwaysShown()2985 public boolean isDecimalSeparatorAlwaysShown() { 2986 // Android-changed: Use ICU. 2987 // return decimalSeparatorAlwaysShown; 2988 return icuDecimalFormat.isDecimalSeparatorAlwaysShown(); 2989 } 2990 2991 /** 2992 * Allows you to set the behavior of the decimal separator with integers. 2993 * (The decimal separator will always appear with decimals.) 2994 * <P>Example: Decimal ON: 12345 → 12345.; OFF: 12345 → 12345 2995 * 2996 * @param newValue {@code true} if the decimal separator is always shown; 2997 * {@code false} otherwise 2998 */ setDecimalSeparatorAlwaysShown(boolean newValue)2999 public void setDecimalSeparatorAlwaysShown(boolean newValue) { 3000 // BEGIN Android-changed: Use ICU. 3001 /* 3002 decimalSeparatorAlwaysShown = newValue; 3003 fastPathCheckNeeded = true; 3004 */ 3005 icuDecimalFormat.setDecimalSeparatorAlwaysShown(newValue); 3006 // END Android-changed: Use ICU. 3007 } 3008 3009 /** 3010 * Returns whether the {@link #parse(java.lang.String, java.text.ParsePosition)} 3011 * method returns <code>BigDecimal</code>. The default value is false. 3012 * 3013 * @return {@code true} if the parse method returns BigDecimal; 3014 * {@code false} otherwise 3015 * @see #setParseBigDecimal 3016 * @since 1.5 3017 */ isParseBigDecimal()3018 public boolean isParseBigDecimal() { 3019 // Android-changed: Use ICU. 3020 // return parseBigDecimal; 3021 return icuDecimalFormat.isParseBigDecimal(); 3022 } 3023 3024 /** 3025 * Sets whether the {@link #parse(java.lang.String, java.text.ParsePosition)} 3026 * method returns <code>BigDecimal</code>. 3027 * 3028 * @param newValue {@code true} if the parse method returns BigDecimal; 3029 * {@code false} otherwise 3030 * @see #isParseBigDecimal 3031 * @since 1.5 3032 */ setParseBigDecimal(boolean newValue)3033 public void setParseBigDecimal(boolean newValue) { 3034 // Android-changed: Use ICU. 3035 // parseBigDecimal = newValue; 3036 icuDecimalFormat.setParseBigDecimal(newValue); 3037 } 3038 3039 // BEGIN Android-added: setParseIntegerOnly()/isParseIntegerOnly() overrides delegating to ICU. 3040 /** 3041 * {@inheritDoc} 3042 */ 3043 @Override isParseIntegerOnly()3044 public boolean isParseIntegerOnly() { 3045 return icuDecimalFormat.isParseIntegerOnly(); 3046 } 3047 3048 /** 3049 * {@inheritDoc} 3050 */ 3051 @Override setParseIntegerOnly(boolean value)3052 public void setParseIntegerOnly(boolean value) { 3053 super.setParseIntegerOnly(value); 3054 icuDecimalFormat.setParseIntegerOnly(value); 3055 } 3056 // END Android-added: setParseIntegerOnly()/isParseIntegerOnly() overrides delegating to ICU. 3057 3058 /** 3059 * Standard override; no change in semantics. 3060 */ 3061 @Override clone()3062 public Object clone() { 3063 // BEGIN Android-changed: Use ICU, remove fast path related code. 3064 /* 3065 DecimalFormat other = (DecimalFormat) super.clone(); 3066 other.symbols = (DecimalFormatSymbols) symbols.clone(); 3067 other.digitList = (DigitList) digitList.clone(); 3068 3069 // Fast-path is almost stateless algorithm. The only logical state is the 3070 // isFastPath flag. In addition fastPathCheckNeeded is a sentinel flag 3071 // that forces recalculation of all fast-path fields when set to true. 3072 // 3073 // There is thus no need to clone all the fast-path fields. 3074 // We just only need to set fastPathCheckNeeded to true when cloning, 3075 // and init fastPathData to null as if it were a truly new instance. 3076 // Every fast-path field will be recalculated (only once) at next usage of 3077 // fast-path algorithm. 3078 other.fastPathCheckNeeded = true; 3079 other.isFastPath = false; 3080 other.fastPathData = null; 3081 3082 return other; 3083 */ 3084 try { 3085 DecimalFormat other = (DecimalFormat) super.clone(); 3086 other.icuDecimalFormat = (android.icu.text.DecimalFormat_ICU58_Android) icuDecimalFormat.clone(); 3087 other.symbols = (DecimalFormatSymbols) symbols.clone(); 3088 return other; 3089 } catch (Exception e) { 3090 throw new InternalError(); 3091 } 3092 // END Android-changed: Use ICU, remove fast path related code. 3093 } 3094 3095 /** 3096 * Overrides equals 3097 */ 3098 @Override equals(Object obj)3099 public boolean equals(Object obj) 3100 { 3101 // BEGIN Android-changed: re-implement equals() using ICU fields. 3102 /* 3103 if (obj == null) 3104 return false; 3105 if (!super.equals(obj)) 3106 return false; // super does class check 3107 DecimalFormat other = (DecimalFormat) obj; 3108 return ((posPrefixPattern == other.posPrefixPattern && 3109 positivePrefix.equals(other.positivePrefix)) 3110 || (posPrefixPattern != null && 3111 posPrefixPattern.equals(other.posPrefixPattern))) 3112 && ((posSuffixPattern == other.posSuffixPattern && 3113 positiveSuffix.equals(other.positiveSuffix)) 3114 || (posSuffixPattern != null && 3115 posSuffixPattern.equals(other.posSuffixPattern))) 3116 && ((negPrefixPattern == other.negPrefixPattern && 3117 negativePrefix.equals(other.negativePrefix)) 3118 || (negPrefixPattern != null && 3119 negPrefixPattern.equals(other.negPrefixPattern))) 3120 && ((negSuffixPattern == other.negSuffixPattern && 3121 negativeSuffix.equals(other.negativeSuffix)) 3122 || (negSuffixPattern != null && 3123 negSuffixPattern.equals(other.negSuffixPattern))) 3124 && multiplier == other.multiplier 3125 && groupingSize == other.groupingSize 3126 && decimalSeparatorAlwaysShown == other.decimalSeparatorAlwaysShown 3127 && parseBigDecimal == other.parseBigDecimal 3128 && useExponentialNotation == other.useExponentialNotation 3129 && (!useExponentialNotation || 3130 minExponentDigits == other.minExponentDigits) 3131 && maximumIntegerDigits == other.maximumIntegerDigits 3132 && minimumIntegerDigits == other.minimumIntegerDigits 3133 && maximumFractionDigits == other.maximumFractionDigits 3134 && minimumFractionDigits == other.minimumFractionDigits 3135 && roundingMode == other.roundingMode 3136 && symbols.equals(other.symbols); 3137 */ 3138 if (obj == null) { 3139 return false; 3140 } 3141 if (this == obj) { 3142 return true; 3143 } 3144 if (!(obj instanceof DecimalFormat)) { 3145 return false; 3146 } 3147 DecimalFormat other = (DecimalFormat) obj; 3148 return icuDecimalFormat.equals(other.icuDecimalFormat) 3149 && compareIcuRoundingIncrement(other.icuDecimalFormat); 3150 } 3151 compareIcuRoundingIncrement(android.icu.text.DecimalFormat_ICU58_Android other)3152 private boolean compareIcuRoundingIncrement(android.icu.text.DecimalFormat_ICU58_Android other) { 3153 BigDecimal increment = this.icuDecimalFormat.getRoundingIncrement(); 3154 if (increment != null) { 3155 return (other.getRoundingIncrement() != null) 3156 && increment.equals(other.getRoundingIncrement()); 3157 } 3158 return other.getRoundingIncrement() == null; 3159 } 3160 // END Android-changed: re-implement equals() using ICU fields. 3161 3162 /** 3163 * Overrides hashCode 3164 */ 3165 @Override hashCode()3166 public int hashCode() { 3167 // Android-changed: use getPositivePrefix() instead of positivePrefix field. 3168 // return super.hashCode() * 37 + positivePrefix.hashCode(); 3169 return super.hashCode() * 37 + getPositivePrefix().hashCode(); 3170 // just enough fields for a reasonable distribution 3171 } 3172 3173 /** 3174 * Synthesizes a pattern string that represents the current state 3175 * of this Format object. 3176 * 3177 * @return a pattern string 3178 * @see #applyPattern 3179 */ toPattern()3180 public String toPattern() { 3181 // Android-changed: use ICU. 3182 // return toPattern( false ); 3183 return icuDecimalFormat.toPattern(); 3184 } 3185 3186 /** 3187 * Synthesizes a localized pattern string that represents the current 3188 * state of this Format object. 3189 * 3190 * @return a localized pattern string 3191 * @see #applyPattern 3192 */ toLocalizedPattern()3193 public String toLocalizedPattern() { 3194 // Android-changed: use ICU. 3195 // return toPattern( true ); 3196 return icuDecimalFormat.toLocalizedPattern(); 3197 } 3198 3199 // BEGIN Android-removed: Unused private helpers. 3200 /* 3201 /** 3202 * Expand the affix pattern strings into the expanded affix strings. If any 3203 * affix pattern string is null, do not expand it. This method should be 3204 * called any time the symbols or the affix patterns change in order to keep 3205 * the expanded affix strings up to date. 3206 * 3207 private void expandAffixes() { 3208 // Reuse one StringBuffer for better performance 3209 StringBuffer buffer = new StringBuffer(); 3210 if (posPrefixPattern != null) { 3211 positivePrefix = expandAffix(posPrefixPattern, buffer); 3212 positivePrefixFieldPositions = null; 3213 } 3214 if (posSuffixPattern != null) { 3215 positiveSuffix = expandAffix(posSuffixPattern, buffer); 3216 positiveSuffixFieldPositions = null; 3217 } 3218 if (negPrefixPattern != null) { 3219 negativePrefix = expandAffix(negPrefixPattern, buffer); 3220 negativePrefixFieldPositions = null; 3221 } 3222 if (negSuffixPattern != null) { 3223 negativeSuffix = expandAffix(negSuffixPattern, buffer); 3224 negativeSuffixFieldPositions = null; 3225 } 3226 } 3227 3228 /** 3229 * Expand an affix pattern into an affix string. All characters in the 3230 * pattern are literal unless prefixed by QUOTE. The following characters 3231 * after QUOTE are recognized: PATTERN_PERCENT, PATTERN_PER_MILLE, 3232 * PATTERN_MINUS, and CURRENCY_SIGN. If CURRENCY_SIGN is doubled (QUOTE + 3233 * CURRENCY_SIGN + CURRENCY_SIGN), it is interpreted as an ISO 4217 3234 * currency code. Any other character after a QUOTE represents itself. 3235 * QUOTE must be followed by another character; QUOTE may not occur by 3236 * itself at the end of the pattern. 3237 * 3238 * @param pattern the non-null, possibly empty pattern 3239 * @param buffer a scratch StringBuffer; its contents will be lost 3240 * @return the expanded equivalent of pattern 3241 * 3242 private String expandAffix(String pattern, StringBuffer buffer) { 3243 buffer.setLength(0); 3244 for (int i=0; i<pattern.length(); ) { 3245 char c = pattern.charAt(i++); 3246 if (c == QUOTE) { 3247 c = pattern.charAt(i++); 3248 switch (c) { 3249 case CURRENCY_SIGN: 3250 if (i<pattern.length() && 3251 pattern.charAt(i) == CURRENCY_SIGN) { 3252 ++i; 3253 buffer.append(symbols.getInternationalCurrencySymbol()); 3254 } else { 3255 buffer.append(symbols.getCurrencySymbol()); 3256 } 3257 continue; 3258 case PATTERN_PERCENT: 3259 c = symbols.getPercent(); 3260 break; 3261 case PATTERN_PER_MILLE: 3262 c = symbols.getPerMill(); 3263 break; 3264 case PATTERN_MINUS: 3265 c = symbols.getMinusSign(); 3266 break; 3267 } 3268 } 3269 buffer.append(c); 3270 } 3271 return buffer.toString(); 3272 } 3273 3274 /** 3275 * Expand an affix pattern into an array of FieldPositions describing 3276 * how the pattern would be expanded. 3277 * All characters in the 3278 * pattern are literal unless prefixed by QUOTE. The following characters 3279 * after QUOTE are recognized: PATTERN_PERCENT, PATTERN_PER_MILLE, 3280 * PATTERN_MINUS, and CURRENCY_SIGN. If CURRENCY_SIGN is doubled (QUOTE + 3281 * CURRENCY_SIGN + CURRENCY_SIGN), it is interpreted as an ISO 4217 3282 * currency code. Any other character after a QUOTE represents itself. 3283 * QUOTE must be followed by another character; QUOTE may not occur by 3284 * itself at the end of the pattern. 3285 * 3286 * @param pattern the non-null, possibly empty pattern 3287 * @return FieldPosition array of the resulting fields. 3288 * 3289 private FieldPosition[] expandAffix(String pattern) { 3290 ArrayList<FieldPosition> positions = null; 3291 int stringIndex = 0; 3292 for (int i=0; i<pattern.length(); ) { 3293 char c = pattern.charAt(i++); 3294 if (c == QUOTE) { 3295 int field = -1; 3296 Format.Field fieldID = null; 3297 c = pattern.charAt(i++); 3298 switch (c) { 3299 case CURRENCY_SIGN: 3300 String string; 3301 if (i<pattern.length() && 3302 pattern.charAt(i) == CURRENCY_SIGN) { 3303 ++i; 3304 string = symbols.getInternationalCurrencySymbol(); 3305 } else { 3306 string = symbols.getCurrencySymbol(); 3307 } 3308 if (string.length() > 0) { 3309 if (positions == null) { 3310 positions = new ArrayList<>(2); 3311 } 3312 FieldPosition fp = new FieldPosition(Field.CURRENCY); 3313 fp.setBeginIndex(stringIndex); 3314 fp.setEndIndex(stringIndex + string.length()); 3315 positions.add(fp); 3316 stringIndex += string.length(); 3317 } 3318 continue; 3319 case PATTERN_PERCENT: 3320 c = symbols.getPercent(); 3321 field = -1; 3322 fieldID = Field.PERCENT; 3323 break; 3324 case PATTERN_PER_MILLE: 3325 c = symbols.getPerMill(); 3326 field = -1; 3327 fieldID = Field.PERMILLE; 3328 break; 3329 case PATTERN_MINUS: 3330 c = symbols.getMinusSign(); 3331 field = -1; 3332 fieldID = Field.SIGN; 3333 break; 3334 } 3335 if (fieldID != null) { 3336 if (positions == null) { 3337 positions = new ArrayList<>(2); 3338 } 3339 FieldPosition fp = new FieldPosition(fieldID, field); 3340 fp.setBeginIndex(stringIndex); 3341 fp.setEndIndex(stringIndex + 1); 3342 positions.add(fp); 3343 } 3344 } 3345 stringIndex++; 3346 } 3347 if (positions != null) { 3348 return positions.toArray(EmptyFieldPositionArray); 3349 } 3350 return EmptyFieldPositionArray; 3351 } 3352 3353 /** 3354 * Appends an affix pattern to the given StringBuffer, quoting special 3355 * characters as needed. Uses the internal affix pattern, if that exists, 3356 * or the literal affix, if the internal affix pattern is null. The 3357 * appended string will generate the same affix pattern (or literal affix) 3358 * when passed to toPattern(). 3359 * 3360 * @param buffer the affix string is appended to this 3361 * @param affixPattern a pattern such as posPrefixPattern; may be null 3362 * @param expAffix a corresponding expanded affix, such as positivePrefix. 3363 * Ignored unless affixPattern is null. If affixPattern is null, then 3364 * expAffix is appended as a literal affix. 3365 * @param localized true if the appended pattern should contain localized 3366 * pattern characters; otherwise, non-localized pattern chars are appended 3367 * 3368 private void appendAffix(StringBuffer buffer, String affixPattern, 3369 String expAffix, boolean localized) { 3370 if (affixPattern == null) { 3371 appendAffix(buffer, expAffix, localized); 3372 } else { 3373 int i; 3374 for (int pos=0; pos<affixPattern.length(); pos=i) { 3375 i = affixPattern.indexOf(QUOTE, pos); 3376 if (i < 0) { 3377 appendAffix(buffer, affixPattern.substring(pos), localized); 3378 break; 3379 } 3380 if (i > pos) { 3381 appendAffix(buffer, affixPattern.substring(pos, i), localized); 3382 } 3383 char c = affixPattern.charAt(++i); 3384 ++i; 3385 if (c == QUOTE) { 3386 buffer.append(c); 3387 // Fall through and append another QUOTE below 3388 } else if (c == CURRENCY_SIGN && 3389 i<affixPattern.length() && 3390 affixPattern.charAt(i) == CURRENCY_SIGN) { 3391 ++i; 3392 buffer.append(c); 3393 // Fall through and append another CURRENCY_SIGN below 3394 } else if (localized) { 3395 switch (c) { 3396 case PATTERN_PERCENT: 3397 c = symbols.getPercent(); 3398 break; 3399 case PATTERN_PER_MILLE: 3400 c = symbols.getPerMill(); 3401 break; 3402 case PATTERN_MINUS: 3403 c = symbols.getMinusSign(); 3404 break; 3405 } 3406 } 3407 buffer.append(c); 3408 } 3409 } 3410 } 3411 3412 /** 3413 * Append an affix to the given StringBuffer, using quotes if 3414 * there are special characters. Single quotes themselves must be 3415 * escaped in either case. 3416 * 3417 private void appendAffix(StringBuffer buffer, String affix, boolean localized) { 3418 boolean needQuote; 3419 if (localized) { 3420 needQuote = affix.indexOf(symbols.getZeroDigit()) >= 0 3421 || affix.indexOf(symbols.getGroupingSeparator()) >= 0 3422 || affix.indexOf(symbols.getDecimalSeparator()) >= 0 3423 || affix.indexOf(symbols.getPercent()) >= 0 3424 || affix.indexOf(symbols.getPerMill()) >= 0 3425 || affix.indexOf(symbols.getDigit()) >= 0 3426 || affix.indexOf(symbols.getPatternSeparator()) >= 0 3427 || affix.indexOf(symbols.getMinusSign()) >= 0 3428 || affix.indexOf(CURRENCY_SIGN) >= 0; 3429 } else { 3430 needQuote = affix.indexOf(PATTERN_ZERO_DIGIT) >= 0 3431 || affix.indexOf(PATTERN_GROUPING_SEPARATOR) >= 0 3432 || affix.indexOf(PATTERN_DECIMAL_SEPARATOR) >= 0 3433 || affix.indexOf(PATTERN_PERCENT) >= 0 3434 || affix.indexOf(PATTERN_PER_MILLE) >= 0 3435 || affix.indexOf(PATTERN_DIGIT) >= 0 3436 || affix.indexOf(PATTERN_SEPARATOR) >= 0 3437 || affix.indexOf(PATTERN_MINUS) >= 0 3438 || affix.indexOf(CURRENCY_SIGN) >= 0; 3439 } 3440 if (needQuote) buffer.append('\''); 3441 if (affix.indexOf('\'') < 0) buffer.append(affix); 3442 else { 3443 for (int j=0; j<affix.length(); ++j) { 3444 char c = affix.charAt(j); 3445 buffer.append(c); 3446 if (c == '\'') buffer.append(c); 3447 } 3448 } 3449 if (needQuote) buffer.append('\''); 3450 } 3451 3452 /** 3453 * Does the real work of generating a pattern. * 3454 private String toPattern(boolean localized) { 3455 StringBuffer result = new StringBuffer(); 3456 for (int j = 1; j >= 0; --j) { 3457 if (j == 1) 3458 appendAffix(result, posPrefixPattern, positivePrefix, localized); 3459 else appendAffix(result, negPrefixPattern, negativePrefix, localized); 3460 int i; 3461 int digitCount = useExponentialNotation 3462 ? getMaximumIntegerDigits() 3463 : Math.max(groupingSize, getMinimumIntegerDigits())+1; 3464 for (i = digitCount; i > 0; --i) { 3465 if (i != digitCount && isGroupingUsed() && groupingSize != 0 && 3466 i % groupingSize == 0) { 3467 result.append(localized ? symbols.getGroupingSeparator() : 3468 PATTERN_GROUPING_SEPARATOR); 3469 } 3470 result.append(i <= getMinimumIntegerDigits() 3471 ? (localized ? symbols.getZeroDigit() : PATTERN_ZERO_DIGIT) 3472 : (localized ? symbols.getDigit() : PATTERN_DIGIT)); 3473 } 3474 if (getMaximumFractionDigits() > 0 || decimalSeparatorAlwaysShown) 3475 result.append(localized ? symbols.getDecimalSeparator() : 3476 PATTERN_DECIMAL_SEPARATOR); 3477 for (i = 0; i < getMaximumFractionDigits(); ++i) { 3478 if (i < getMinimumFractionDigits()) { 3479 result.append(localized ? symbols.getZeroDigit() : 3480 PATTERN_ZERO_DIGIT); 3481 } else { 3482 result.append(localized ? symbols.getDigit() : 3483 PATTERN_DIGIT); 3484 } 3485 } 3486 if (useExponentialNotation) 3487 { 3488 result.append(localized ? symbols.getExponentSeparator() : 3489 PATTERN_EXPONENT); 3490 for (i=0; i<minExponentDigits; ++i) 3491 result.append(localized ? symbols.getZeroDigit() : 3492 PATTERN_ZERO_DIGIT); 3493 } 3494 if (j == 1) { 3495 appendAffix(result, posSuffixPattern, positiveSuffix, localized); 3496 if ((negSuffixPattern == posSuffixPattern && // n == p == null 3497 negativeSuffix.equals(positiveSuffix)) 3498 || (negSuffixPattern != null && 3499 negSuffixPattern.equals(posSuffixPattern))) { 3500 if ((negPrefixPattern != null && posPrefixPattern != null && 3501 negPrefixPattern.equals("'-" + posPrefixPattern)) || 3502 (negPrefixPattern == posPrefixPattern && // n == p == null 3503 negativePrefix.equals(symbols.getMinusSign() + positivePrefix))) 3504 break; 3505 } 3506 result.append(localized ? symbols.getPatternSeparator() : 3507 PATTERN_SEPARATOR); 3508 } else appendAffix(result, negSuffixPattern, negativeSuffix, localized); 3509 } 3510 return result.toString(); 3511 } 3512 */ 3513 // END Android-removed: Unused private helpers. 3514 3515 /** 3516 * Apply the given pattern to this Format object. A pattern is a 3517 * short-hand specification for the various formatting properties. 3518 * These properties can also be changed individually through the 3519 * various setter methods. 3520 * <p> 3521 * There is no limit to integer digits set 3522 * by this routine, since that is the typical end-user desire; 3523 * use setMaximumInteger if you want to set a real value. 3524 * For negative numbers, use a second pattern, separated by a semicolon 3525 * <P>Example <code>"#,#00.0#"</code> → 1,234.56 3526 * <P>This means a minimum of 2 integer digits, 1 fraction digit, and 3527 * a maximum of 2 fraction digits. 3528 * <p>Example: <code>"#,#00.0#;(#,#00.0#)"</code> for negatives in 3529 * parentheses. 3530 * <p>In negative patterns, the minimum and maximum counts are ignored; 3531 * these are presumed to be set in the positive pattern. 3532 * 3533 * @param pattern a new pattern 3534 * @exception NullPointerException if <code>pattern</code> is null 3535 * @exception IllegalArgumentException if the given pattern is invalid. 3536 */ applyPattern(String pattern)3537 public void applyPattern(String pattern) { 3538 // Android-changed: use ICU. 3539 // applyPattern(pattern, false); 3540 icuDecimalFormat.applyPattern(pattern); 3541 updateFieldsFromIcu(); 3542 } 3543 3544 /** 3545 * Apply the given pattern to this Format object. The pattern 3546 * is assumed to be in a localized notation. A pattern is a 3547 * short-hand specification for the various formatting properties. 3548 * These properties can also be changed individually through the 3549 * various setter methods. 3550 * <p> 3551 * There is no limit to integer digits set 3552 * by this routine, since that is the typical end-user desire; 3553 * use setMaximumInteger if you want to set a real value. 3554 * For negative numbers, use a second pattern, separated by a semicolon 3555 * <P>Example <code>"#,#00.0#"</code> → 1,234.56 3556 * <P>This means a minimum of 2 integer digits, 1 fraction digit, and 3557 * a maximum of 2 fraction digits. 3558 * <p>Example: <code>"#,#00.0#;(#,#00.0#)"</code> for negatives in 3559 * parentheses. 3560 * <p>In negative patterns, the minimum and maximum counts are ignored; 3561 * these are presumed to be set in the positive pattern. 3562 * 3563 * @param pattern a new pattern 3564 * @exception NullPointerException if <code>pattern</code> is null 3565 * @exception IllegalArgumentException if the given pattern is invalid. 3566 */ applyLocalizedPattern(String pattern)3567 public void applyLocalizedPattern(String pattern) { 3568 // Android-changed: use ICU. 3569 // applyPattern(pattern, true); 3570 icuDecimalFormat.applyLocalizedPattern(pattern); 3571 updateFieldsFromIcu(); 3572 } 3573 3574 // BEGIN Android-removed: applyPattern(String, boolean) as apply[Localized]Pattern calls ICU directly. 3575 /* 3576 /** 3577 * Does the real work of applying a pattern. 3578 * 3579 private void applyPattern(String pattern, boolean localized) { 3580 char zeroDigit = PATTERN_ZERO_DIGIT; 3581 char groupingSeparator = PATTERN_GROUPING_SEPARATOR; 3582 char decimalSeparator = PATTERN_DECIMAL_SEPARATOR; 3583 char percent = PATTERN_PERCENT; 3584 char perMill = PATTERN_PER_MILLE; 3585 char digit = PATTERN_DIGIT; 3586 char separator = PATTERN_SEPARATOR; 3587 String exponent = PATTERN_EXPONENT; 3588 char minus = PATTERN_MINUS; 3589 if (localized) { 3590 zeroDigit = symbols.getZeroDigit(); 3591 groupingSeparator = symbols.getGroupingSeparator(); 3592 decimalSeparator = symbols.getDecimalSeparator(); 3593 percent = symbols.getPercent(); 3594 perMill = symbols.getPerMill(); 3595 digit = symbols.getDigit(); 3596 separator = symbols.getPatternSeparator(); 3597 exponent = symbols.getExponentSeparator(); 3598 minus = symbols.getMinusSign(); 3599 } 3600 boolean gotNegative = false; 3601 decimalSeparatorAlwaysShown = false; 3602 isCurrencyFormat = false; 3603 useExponentialNotation = false; 3604 3605 // Two variables are used to record the subrange of the pattern 3606 // occupied by phase 1. This is used during the processing of the 3607 // second pattern (the one representing negative numbers) to ensure 3608 // that no deviation exists in phase 1 between the two patterns. 3609 int phaseOneStart = 0; 3610 int phaseOneLength = 0; 3611 3612 int start = 0; 3613 for (int j = 1; j >= 0 && start < pattern.length(); --j) { 3614 boolean inQuote = false; 3615 StringBuffer prefix = new StringBuffer(); 3616 StringBuffer suffix = new StringBuffer(); 3617 int decimalPos = -1; 3618 int multiplier = 1; 3619 int digitLeftCount = 0, zeroDigitCount = 0, digitRightCount = 0; 3620 byte groupingCount = -1; 3621 3622 // The phase ranges from 0 to 2. Phase 0 is the prefix. Phase 1 is 3623 // the section of the pattern with digits, decimal separator, 3624 // grouping characters. Phase 2 is the suffix. In phases 0 and 2, 3625 // percent, per mille, and currency symbols are recognized and 3626 // translated. The separation of the characters into phases is 3627 // strictly enforced; if phase 1 characters are to appear in the 3628 // suffix, for example, they must be quoted. 3629 int phase = 0; 3630 3631 // The affix is either the prefix or the suffix. 3632 StringBuffer affix = prefix; 3633 3634 for (int pos = start; pos < pattern.length(); ++pos) { 3635 char ch = pattern.charAt(pos); 3636 switch (phase) { 3637 case 0: 3638 case 2: 3639 // Process the prefix / suffix characters 3640 if (inQuote) { 3641 // A quote within quotes indicates either the closing 3642 // quote or two quotes, which is a quote literal. That 3643 // is, we have the second quote in 'do' or 'don''t'. 3644 if (ch == QUOTE) { 3645 if ((pos+1) < pattern.length() && 3646 pattern.charAt(pos+1) == QUOTE) { 3647 ++pos; 3648 affix.append("''"); // 'don''t' 3649 } else { 3650 inQuote = false; // 'do' 3651 } 3652 continue; 3653 } 3654 } else { 3655 // Process unquoted characters seen in prefix or suffix 3656 // phase. 3657 if (ch == digit || 3658 ch == zeroDigit || 3659 ch == groupingSeparator || 3660 ch == decimalSeparator) { 3661 phase = 1; 3662 if (j == 1) { 3663 phaseOneStart = pos; 3664 } 3665 --pos; // Reprocess this character 3666 continue; 3667 } else if (ch == CURRENCY_SIGN) { 3668 // Use lookahead to determine if the currency sign 3669 // is doubled or not. 3670 boolean doubled = (pos + 1) < pattern.length() && 3671 pattern.charAt(pos + 1) == CURRENCY_SIGN; 3672 if (doubled) { // Skip over the doubled character 3673 ++pos; 3674 } 3675 isCurrencyFormat = true; 3676 affix.append(doubled ? "'\u00A4\u00A4" : "'\u00A4"); 3677 continue; 3678 } else if (ch == QUOTE) { 3679 // A quote outside quotes indicates either the 3680 // opening quote or two quotes, which is a quote 3681 // literal. That is, we have the first quote in 'do' 3682 // or o''clock. 3683 if (ch == QUOTE) { 3684 if ((pos+1) < pattern.length() && 3685 pattern.charAt(pos+1) == QUOTE) { 3686 ++pos; 3687 affix.append("''"); // o''clock 3688 } else { 3689 inQuote = true; // 'do' 3690 } 3691 continue; 3692 } 3693 } else if (ch == separator) { 3694 // Don't allow separators before we see digit 3695 // characters of phase 1, and don't allow separators 3696 // in the second pattern (j == 0). 3697 if (phase == 0 || j == 0) { 3698 throw new IllegalArgumentException("Unquoted special character '" + 3699 ch + "' in pattern \"" + pattern + '"'); 3700 } 3701 start = pos + 1; 3702 pos = pattern.length(); 3703 continue; 3704 } 3705 3706 // Next handle characters which are appended directly. 3707 else if (ch == percent) { 3708 if (multiplier != 1) { 3709 throw new IllegalArgumentException("Too many percent/per mille characters in pattern \"" + 3710 pattern + '"'); 3711 } 3712 multiplier = 100; 3713 affix.append("'%"); 3714 continue; 3715 } else if (ch == perMill) { 3716 if (multiplier != 1) { 3717 throw new IllegalArgumentException("Too many percent/per mille characters in pattern \"" + 3718 pattern + '"'); 3719 } 3720 multiplier = 1000; 3721 affix.append("'\u2030"); 3722 continue; 3723 } else if (ch == minus) { 3724 affix.append("'-"); 3725 continue; 3726 } 3727 } 3728 // Note that if we are within quotes, or if this is an 3729 // unquoted, non-special character, then we usually fall 3730 // through to here. 3731 affix.append(ch); 3732 break; 3733 3734 case 1: 3735 // Phase one must be identical in the two sub-patterns. We 3736 // enforce this by doing a direct comparison. While 3737 // processing the first sub-pattern, we just record its 3738 // length. While processing the second, we compare 3739 // characters. 3740 if (j == 1) { 3741 ++phaseOneLength; 3742 } else { 3743 if (--phaseOneLength == 0) { 3744 phase = 2; 3745 affix = suffix; 3746 } 3747 continue; 3748 } 3749 3750 // Process the digits, decimal, and grouping characters. We 3751 // record five pieces of information. We expect the digits 3752 // to occur in the pattern ####0000.####, and we record the 3753 // number of left digits, zero (central) digits, and right 3754 // digits. The position of the last grouping character is 3755 // recorded (should be somewhere within the first two blocks 3756 // of characters), as is the position of the decimal point, 3757 // if any (should be in the zero digits). If there is no 3758 // decimal point, then there should be no right digits. 3759 if (ch == digit) { 3760 if (zeroDigitCount > 0) { 3761 ++digitRightCount; 3762 } else { 3763 ++digitLeftCount; 3764 } 3765 if (groupingCount >= 0 && decimalPos < 0) { 3766 ++groupingCount; 3767 } 3768 } else if (ch == zeroDigit) { 3769 if (digitRightCount > 0) { 3770 throw new IllegalArgumentException("Unexpected '0' in pattern \"" + 3771 pattern + '"'); 3772 } 3773 ++zeroDigitCount; 3774 if (groupingCount >= 0 && decimalPos < 0) { 3775 ++groupingCount; 3776 } 3777 } else if (ch == groupingSeparator) { 3778 groupingCount = 0; 3779 } else if (ch == decimalSeparator) { 3780 if (decimalPos >= 0) { 3781 throw new IllegalArgumentException("Multiple decimal separators in pattern \"" + 3782 pattern + '"'); 3783 } 3784 decimalPos = digitLeftCount + zeroDigitCount + digitRightCount; 3785 } else if (pattern.regionMatches(pos, exponent, 0, exponent.length())){ 3786 if (useExponentialNotation) { 3787 throw new IllegalArgumentException("Multiple exponential " + 3788 "symbols in pattern \"" + pattern + '"'); 3789 } 3790 useExponentialNotation = true; 3791 minExponentDigits = 0; 3792 3793 // Use lookahead to parse out the exponential part 3794 // of the pattern, then jump into phase 2. 3795 pos = pos+exponent.length(); 3796 while (pos < pattern.length() && 3797 pattern.charAt(pos) == zeroDigit) { 3798 ++minExponentDigits; 3799 ++phaseOneLength; 3800 ++pos; 3801 } 3802 3803 if ((digitLeftCount + zeroDigitCount) < 1 || 3804 minExponentDigits < 1) { 3805 throw new IllegalArgumentException("Malformed exponential " + 3806 "pattern \"" + pattern + '"'); 3807 } 3808 3809 // Transition to phase 2 3810 phase = 2; 3811 affix = suffix; 3812 --pos; 3813 continue; 3814 } else { 3815 phase = 2; 3816 affix = suffix; 3817 --pos; 3818 --phaseOneLength; 3819 continue; 3820 } 3821 break; 3822 } 3823 } 3824 3825 // Handle patterns with no '0' pattern character. These patterns 3826 // are legal, but must be interpreted. "##.###" -> "#0.###". 3827 // ".###" -> ".0##". 3828 /* We allow patterns of the form "####" to produce a zeroDigitCount 3829 * of zero (got that?); although this seems like it might make it 3830 * possible for format() to produce empty strings, format() checks 3831 * for this condition and outputs a zero digit in this situation. 3832 * Having a zeroDigitCount of zero yields a minimum integer digits 3833 * of zero, which allows proper round-trip patterns. That is, we 3834 * don't want "#" to become "#0" when toPattern() is called (even 3835 * though that's what it really is, semantically). 3836 * 3837 if (zeroDigitCount == 0 && digitLeftCount > 0 && decimalPos >= 0) { 3838 // Handle "###.###" and "###." and ".###" 3839 int n = decimalPos; 3840 if (n == 0) { // Handle ".###" 3841 ++n; 3842 } 3843 digitRightCount = digitLeftCount - n; 3844 digitLeftCount = n - 1; 3845 zeroDigitCount = 1; 3846 } 3847 3848 // Do syntax checking on the digits. 3849 if ((decimalPos < 0 && digitRightCount > 0) || 3850 (decimalPos >= 0 && (decimalPos < digitLeftCount || 3851 decimalPos > (digitLeftCount + zeroDigitCount))) || 3852 groupingCount == 0 || inQuote) { 3853 throw new IllegalArgumentException("Malformed pattern \"" + 3854 pattern + '"'); 3855 } 3856 3857 if (j == 1) { 3858 posPrefixPattern = prefix.toString(); 3859 posSuffixPattern = suffix.toString(); 3860 negPrefixPattern = posPrefixPattern; // assume these for now 3861 negSuffixPattern = posSuffixPattern; 3862 int digitTotalCount = digitLeftCount + zeroDigitCount + digitRightCount; 3863 /* The effectiveDecimalPos is the position the decimal is at or 3864 * would be at if there is no decimal. Note that if decimalPos<0, 3865 * then digitTotalCount == digitLeftCount + zeroDigitCount. 3866 * 3867 int effectiveDecimalPos = decimalPos >= 0 ? 3868 decimalPos : digitTotalCount; 3869 setMinimumIntegerDigits(effectiveDecimalPos - digitLeftCount); 3870 setMaximumIntegerDigits(useExponentialNotation ? 3871 digitLeftCount + getMinimumIntegerDigits() : 3872 MAXIMUM_INTEGER_DIGITS); 3873 setMaximumFractionDigits(decimalPos >= 0 ? 3874 (digitTotalCount - decimalPos) : 0); 3875 setMinimumFractionDigits(decimalPos >= 0 ? 3876 (digitLeftCount + zeroDigitCount - decimalPos) : 0); 3877 setGroupingUsed(groupingCount > 0); 3878 this.groupingSize = (groupingCount > 0) ? groupingCount : 0; 3879 this.multiplier = multiplier; 3880 setDecimalSeparatorAlwaysShown(decimalPos == 0 || 3881 decimalPos == digitTotalCount); 3882 } else { 3883 negPrefixPattern = prefix.toString(); 3884 negSuffixPattern = suffix.toString(); 3885 gotNegative = true; 3886 } 3887 } 3888 3889 if (pattern.length() == 0) { 3890 posPrefixPattern = posSuffixPattern = ""; 3891 setMinimumIntegerDigits(0); 3892 setMaximumIntegerDigits(MAXIMUM_INTEGER_DIGITS); 3893 setMinimumFractionDigits(0); 3894 setMaximumFractionDigits(MAXIMUM_FRACTION_DIGITS); 3895 } 3896 3897 // If there was no negative pattern, or if the negative pattern is 3898 // identical to the positive pattern, then prepend the minus sign to 3899 // the positive pattern to form the negative pattern. 3900 if (!gotNegative || 3901 (negPrefixPattern.equals(posPrefixPattern) 3902 && negSuffixPattern.equals(posSuffixPattern))) { 3903 negSuffixPattern = posSuffixPattern; 3904 negPrefixPattern = "'-" + posPrefixPattern; 3905 } 3906 3907 expandAffixes(); 3908 } 3909 */ 3910 // END Android-removed: applyPattern(String, boolean) as apply[Localized]Pattern calls ICU directly. 3911 3912 /** 3913 * Sets the maximum number of digits allowed in the integer portion of a 3914 * number. 3915 * For formatting numbers other than <code>BigInteger</code> and 3916 * <code>BigDecimal</code> objects, the lower of <code>newValue</code> and 3917 * 309 is used. Negative input values are replaced with 0. 3918 * @see NumberFormat#setMaximumIntegerDigits 3919 */ 3920 @Override setMaximumIntegerDigits(int newValue)3921 public void setMaximumIntegerDigits(int newValue) { 3922 maximumIntegerDigits = Math.min(Math.max(0, newValue), MAXIMUM_INTEGER_DIGITS); 3923 super.setMaximumIntegerDigits((maximumIntegerDigits > DOUBLE_INTEGER_DIGITS) ? 3924 DOUBLE_INTEGER_DIGITS : maximumIntegerDigits); 3925 if (minimumIntegerDigits > maximumIntegerDigits) { 3926 minimumIntegerDigits = maximumIntegerDigits; 3927 super.setMinimumIntegerDigits((minimumIntegerDigits > DOUBLE_INTEGER_DIGITS) ? 3928 DOUBLE_INTEGER_DIGITS : minimumIntegerDigits); 3929 } 3930 // Android-added: use ICU. 3931 icuDecimalFormat.setMaximumIntegerDigits(getMaximumIntegerDigits()); 3932 // Android-removed: fast path related code. 3933 // fastPathCheckNeeded = true; 3934 } 3935 3936 /** 3937 * Sets the minimum number of digits allowed in the integer portion of a 3938 * number. 3939 * For formatting numbers other than <code>BigInteger</code> and 3940 * <code>BigDecimal</code> objects, the lower of <code>newValue</code> and 3941 * 309 is used. Negative input values are replaced with 0. 3942 * @see NumberFormat#setMinimumIntegerDigits 3943 */ 3944 @Override setMinimumIntegerDigits(int newValue)3945 public void setMinimumIntegerDigits(int newValue) { 3946 minimumIntegerDigits = Math.min(Math.max(0, newValue), MAXIMUM_INTEGER_DIGITS); 3947 super.setMinimumIntegerDigits((minimumIntegerDigits > DOUBLE_INTEGER_DIGITS) ? 3948 DOUBLE_INTEGER_DIGITS : minimumIntegerDigits); 3949 if (minimumIntegerDigits > maximumIntegerDigits) { 3950 maximumIntegerDigits = minimumIntegerDigits; 3951 super.setMaximumIntegerDigits((maximumIntegerDigits > DOUBLE_INTEGER_DIGITS) ? 3952 DOUBLE_INTEGER_DIGITS : maximumIntegerDigits); 3953 } 3954 // Android-added: use ICU. 3955 icuDecimalFormat.setMinimumIntegerDigits(getMinimumIntegerDigits()); 3956 // Android-removed: fast path related code. 3957 // fastPathCheckNeeded = true; 3958 } 3959 3960 /** 3961 * Sets the maximum number of digits allowed in the fraction portion of a 3962 * number. 3963 * For formatting numbers other than <code>BigInteger</code> and 3964 * <code>BigDecimal</code> objects, the lower of <code>newValue</code> and 3965 * 340 is used. Negative input values are replaced with 0. 3966 * @see NumberFormat#setMaximumFractionDigits 3967 */ 3968 @Override setMaximumFractionDigits(int newValue)3969 public void setMaximumFractionDigits(int newValue) { 3970 maximumFractionDigits = Math.min(Math.max(0, newValue), MAXIMUM_FRACTION_DIGITS); 3971 super.setMaximumFractionDigits((maximumFractionDigits > DOUBLE_FRACTION_DIGITS) ? 3972 DOUBLE_FRACTION_DIGITS : maximumFractionDigits); 3973 if (minimumFractionDigits > maximumFractionDigits) { 3974 minimumFractionDigits = maximumFractionDigits; 3975 super.setMinimumFractionDigits((minimumFractionDigits > DOUBLE_FRACTION_DIGITS) ? 3976 DOUBLE_FRACTION_DIGITS : minimumFractionDigits); 3977 } 3978 // Android-added: use ICU. 3979 icuDecimalFormat.setMaximumFractionDigits(getMaximumFractionDigits()); 3980 // Android-removed: fast path related code. 3981 // fastPathCheckNeeded = true; 3982 } 3983 3984 /** 3985 * Sets the minimum number of digits allowed in the fraction portion of a 3986 * number. 3987 * For formatting numbers other than <code>BigInteger</code> and 3988 * <code>BigDecimal</code> objects, the lower of <code>newValue</code> and 3989 * 340 is used. Negative input values are replaced with 0. 3990 * @see NumberFormat#setMinimumFractionDigits 3991 */ 3992 @Override setMinimumFractionDigits(int newValue)3993 public void setMinimumFractionDigits(int newValue) { 3994 minimumFractionDigits = Math.min(Math.max(0, newValue), MAXIMUM_FRACTION_DIGITS); 3995 super.setMinimumFractionDigits((minimumFractionDigits > DOUBLE_FRACTION_DIGITS) ? 3996 DOUBLE_FRACTION_DIGITS : minimumFractionDigits); 3997 if (minimumFractionDigits > maximumFractionDigits) { 3998 maximumFractionDigits = minimumFractionDigits; 3999 super.setMaximumFractionDigits((maximumFractionDigits > DOUBLE_FRACTION_DIGITS) ? 4000 DOUBLE_FRACTION_DIGITS : maximumFractionDigits); 4001 } 4002 // Android-added: use ICU. 4003 icuDecimalFormat.setMinimumFractionDigits(getMinimumFractionDigits()); 4004 // Android-removed: fast path related code. 4005 // fastPathCheckNeeded = true; 4006 } 4007 4008 /** 4009 * Gets the maximum number of digits allowed in the integer portion of a 4010 * number. 4011 * For formatting numbers other than <code>BigInteger</code> and 4012 * <code>BigDecimal</code> objects, the lower of the return value and 4013 * 309 is used. 4014 * @see #setMaximumIntegerDigits 4015 */ 4016 @Override getMaximumIntegerDigits()4017 public int getMaximumIntegerDigits() { 4018 return maximumIntegerDigits; 4019 } 4020 4021 /** 4022 * Gets the minimum number of digits allowed in the integer portion of a 4023 * number. 4024 * For formatting numbers other than <code>BigInteger</code> and 4025 * <code>BigDecimal</code> objects, the lower of the return value and 4026 * 309 is used. 4027 * @see #setMinimumIntegerDigits 4028 */ 4029 @Override getMinimumIntegerDigits()4030 public int getMinimumIntegerDigits() { 4031 return minimumIntegerDigits; 4032 } 4033 4034 /** 4035 * Gets the maximum number of digits allowed in the fraction portion of a 4036 * number. 4037 * For formatting numbers other than <code>BigInteger</code> and 4038 * <code>BigDecimal</code> objects, the lower of the return value and 4039 * 340 is used. 4040 * @see #setMaximumFractionDigits 4041 */ 4042 @Override getMaximumFractionDigits()4043 public int getMaximumFractionDigits() { 4044 return maximumFractionDigits; 4045 } 4046 4047 /** 4048 * Gets the minimum number of digits allowed in the fraction portion of a 4049 * number. 4050 * For formatting numbers other than <code>BigInteger</code> and 4051 * <code>BigDecimal</code> objects, the lower of the return value and 4052 * 340 is used. 4053 * @see #setMinimumFractionDigits 4054 */ 4055 @Override getMinimumFractionDigits()4056 public int getMinimumFractionDigits() { 4057 return minimumFractionDigits; 4058 } 4059 4060 /** 4061 * Gets the currency used by this decimal format when formatting 4062 * currency values. 4063 * The currency is obtained by calling 4064 * {@link DecimalFormatSymbols#getCurrency DecimalFormatSymbols.getCurrency} 4065 * on this number format's symbols. 4066 * 4067 * @return the currency used by this decimal format, or <code>null</code> 4068 * @since 1.4 4069 */ 4070 @Override getCurrency()4071 public Currency getCurrency() { 4072 return symbols.getCurrency(); 4073 } 4074 4075 /** 4076 * Sets the currency used by this number format when formatting 4077 * currency values. This does not update the minimum or maximum 4078 * number of fraction digits used by the number format. 4079 * The currency is set by calling 4080 * {@link DecimalFormatSymbols#setCurrency DecimalFormatSymbols.setCurrency} 4081 * on this number format's symbols. 4082 * 4083 * @param currency the new currency to be used by this decimal format 4084 * @exception NullPointerException if <code>currency</code> is null 4085 * @since 1.4 4086 */ 4087 @Override setCurrency(Currency currency)4088 public void setCurrency(Currency currency) { 4089 // BEGIN Android-changed: use ICU. 4090 // Set the international currency symbol, and currency symbol on the DecimalFormatSymbols 4091 // object and tell ICU to use that. 4092 /* 4093 if (currency != symbols.getCurrency()) { 4094 symbols.setCurrency(currency); 4095 if (isCurrencyFormat) { 4096 expandAffixes(); 4097 } 4098 } 4099 */ 4100 if (currency != symbols.getCurrency() 4101 || !currency.getSymbol().equals(symbols.getCurrencySymbol())) { 4102 symbols.setCurrency(currency); 4103 icuDecimalFormat.setDecimalFormatSymbols(symbols.getIcuDecimalFormatSymbols()); 4104 // Giving the icuDecimalFormat a new currency will cause the fractional digits to be 4105 // updated. This class is specified to not touch the fraction digits, so we re-set them. 4106 icuDecimalFormat.setMinimumFractionDigits(minimumFractionDigits); 4107 icuDecimalFormat.setMaximumFractionDigits(maximumFractionDigits); 4108 } 4109 // END Android-changed: use ICU. 4110 // Android-removed: fast path related code. 4111 // fastPathCheckNeeded = true; 4112 } 4113 4114 /** 4115 * Gets the {@link java.math.RoundingMode} used in this DecimalFormat. 4116 * 4117 * @return The <code>RoundingMode</code> used for this DecimalFormat. 4118 * @see #setRoundingMode(RoundingMode) 4119 * @since 1.6 4120 */ 4121 @Override getRoundingMode()4122 public RoundingMode getRoundingMode() { 4123 return roundingMode; 4124 } 4125 4126 // BEGIN Android-added: convertRoundingMode() to convert between Java and ICU RoundingMode enums. convertRoundingMode(RoundingMode rm)4127 private static int convertRoundingMode(RoundingMode rm) { 4128 switch (rm) { 4129 case UP: 4130 return MathContext.ROUND_UP; 4131 case DOWN: 4132 return MathContext.ROUND_DOWN; 4133 case CEILING: 4134 return MathContext.ROUND_CEILING; 4135 case FLOOR: 4136 return MathContext.ROUND_FLOOR; 4137 case HALF_UP: 4138 return MathContext.ROUND_HALF_UP; 4139 case HALF_DOWN: 4140 return MathContext.ROUND_HALF_DOWN; 4141 case HALF_EVEN: 4142 return MathContext.ROUND_HALF_EVEN; 4143 case UNNECESSARY: 4144 return MathContext.ROUND_UNNECESSARY; 4145 } 4146 throw new IllegalArgumentException("Invalid rounding mode specified"); 4147 } 4148 // END Android-added: convertRoundingMode() to convert between Java and ICU RoundingMode enums. 4149 4150 /** 4151 * Sets the {@link java.math.RoundingMode} used in this DecimalFormat. 4152 * 4153 * @param roundingMode The <code>RoundingMode</code> to be used 4154 * @see #getRoundingMode() 4155 * @exception NullPointerException if <code>roundingMode</code> is null. 4156 * @since 1.6 4157 */ 4158 @Override setRoundingMode(RoundingMode roundingMode)4159 public void setRoundingMode(RoundingMode roundingMode) { 4160 if (roundingMode == null) { 4161 throw new NullPointerException(); 4162 } 4163 4164 this.roundingMode = roundingMode; 4165 // Android-changed: use ICU. 4166 // digitList.setRoundingMode(roundingMode); 4167 icuDecimalFormat.setRoundingMode(convertRoundingMode(roundingMode)); 4168 // Android-removed: fast path related code. 4169 // fastPathCheckNeeded = true; 4170 } 4171 4172 // BEGIN Android-added: Upstream code from OpenJDK 7u40 release. 4173 // This method was removed in OpenJDK 8 in favor of doing equivalent work in the provider. Since 4174 // Android removed support for providers for NumberFormat we keep this method around as an 4175 // "Android addition". 4176 /** 4177 * Adjusts the minimum and maximum fraction digits to values that 4178 * are reasonable for the currency's default fraction digits. 4179 */ adjustForCurrencyDefaultFractionDigits()4180 void adjustForCurrencyDefaultFractionDigits() { 4181 Currency currency = symbols.getCurrency(); 4182 if (currency == null) { 4183 try { 4184 currency = Currency.getInstance(symbols.getInternationalCurrencySymbol()); 4185 } catch (IllegalArgumentException e) { 4186 } 4187 } 4188 if (currency != null) { 4189 int digits = currency.getDefaultFractionDigits(); 4190 if (digits != -1) { 4191 int oldMinDigits = getMinimumFractionDigits(); 4192 // Common patterns are "#.##", "#.00", "#". 4193 // Try to adjust all of them in a reasonable way. 4194 if (oldMinDigits == getMaximumFractionDigits()) { 4195 setMinimumFractionDigits(digits); 4196 setMaximumFractionDigits(digits); 4197 } else { 4198 setMinimumFractionDigits(Math.min(digits, oldMinDigits)); 4199 setMaximumFractionDigits(digits); 4200 } 4201 } 4202 } 4203 } 4204 // END Android-added: Upstream code from OpenJDK 7u40 release. 4205 4206 // BEGIN Android-added: Custom serialization code for compatibility with RI serialization. 4207 // the fields list to be serialized 4208 private static final ObjectStreamField[] serialPersistentFields = { 4209 new ObjectStreamField("positivePrefix", String.class), 4210 new ObjectStreamField("positiveSuffix", String.class), 4211 new ObjectStreamField("negativePrefix", String.class), 4212 new ObjectStreamField("negativeSuffix", String.class), 4213 new ObjectStreamField("posPrefixPattern", String.class), 4214 new ObjectStreamField("posSuffixPattern", String.class), 4215 new ObjectStreamField("negPrefixPattern", String.class), 4216 new ObjectStreamField("negSuffixPattern", String.class), 4217 new ObjectStreamField("multiplier", int.class), 4218 new ObjectStreamField("groupingSize", byte.class), 4219 new ObjectStreamField("groupingUsed", boolean.class), 4220 new ObjectStreamField("decimalSeparatorAlwaysShown", boolean.class), 4221 new ObjectStreamField("parseBigDecimal", boolean.class), 4222 new ObjectStreamField("roundingMode", RoundingMode.class), 4223 new ObjectStreamField("symbols", DecimalFormatSymbols.class), 4224 new ObjectStreamField("useExponentialNotation", boolean.class), 4225 new ObjectStreamField("minExponentDigits", byte.class), 4226 new ObjectStreamField("maximumIntegerDigits", int.class), 4227 new ObjectStreamField("minimumIntegerDigits", int.class), 4228 new ObjectStreamField("maximumFractionDigits", int.class), 4229 new ObjectStreamField("minimumFractionDigits", int.class), 4230 new ObjectStreamField("serialVersionOnStream", int.class), 4231 }; 4232 writeObject(ObjectOutputStream stream)4233 private void writeObject(ObjectOutputStream stream) throws IOException, ClassNotFoundException { 4234 ObjectOutputStream.PutField fields = stream.putFields(); 4235 fields.put("positivePrefix", icuDecimalFormat.getPositivePrefix()); 4236 fields.put("positiveSuffix", icuDecimalFormat.getPositiveSuffix()); 4237 fields.put("negativePrefix", icuDecimalFormat.getNegativePrefix()); 4238 fields.put("negativeSuffix", icuDecimalFormat.getNegativeSuffix()); 4239 fields.put("posPrefixPattern", (String) null); 4240 fields.put("posSuffixPattern", (String) null); 4241 fields.put("negPrefixPattern", (String) null); 4242 fields.put("negSuffixPattern", (String) null); 4243 fields.put("multiplier", icuDecimalFormat.getMultiplier()); 4244 fields.put("groupingSize", (byte) icuDecimalFormat.getGroupingSize()); 4245 fields.put("groupingUsed", icuDecimalFormat.isGroupingUsed()); 4246 fields.put("decimalSeparatorAlwaysShown", icuDecimalFormat.isDecimalSeparatorAlwaysShown()); 4247 fields.put("parseBigDecimal", icuDecimalFormat.isParseBigDecimal()); 4248 fields.put("roundingMode", roundingMode); 4249 fields.put("symbols", symbols); 4250 fields.put("useExponentialNotation", false); 4251 fields.put("minExponentDigits", (byte) 0); 4252 fields.put("maximumIntegerDigits", icuDecimalFormat.getMaximumIntegerDigits()); 4253 fields.put("minimumIntegerDigits", icuDecimalFormat.getMinimumIntegerDigits()); 4254 fields.put("maximumFractionDigits", icuDecimalFormat.getMaximumFractionDigits()); 4255 fields.put("minimumFractionDigits", icuDecimalFormat.getMinimumFractionDigits()); 4256 fields.put("serialVersionOnStream", currentSerialVersion); 4257 stream.writeFields(); 4258 } 4259 // END Android-added: Custom serialization code for compatibility with RI serialization. 4260 4261 /** 4262 * Reads the default serializable fields from the stream and performs 4263 * validations and adjustments for older serialized versions. The 4264 * validations and adjustments are: 4265 * <ol> 4266 * <li> 4267 * Verify that the superclass's digit count fields correctly reflect 4268 * the limits imposed on formatting numbers other than 4269 * <code>BigInteger</code> and <code>BigDecimal</code> objects. These 4270 * limits are stored in the superclass for serialization compatibility 4271 * with older versions, while the limits for <code>BigInteger</code> and 4272 * <code>BigDecimal</code> objects are kept in this class. 4273 * If, in the superclass, the minimum or maximum integer digit count is 4274 * larger than <code>DOUBLE_INTEGER_DIGITS</code> or if the minimum or 4275 * maximum fraction digit count is larger than 4276 * <code>DOUBLE_FRACTION_DIGITS</code>, then the stream data is invalid 4277 * and this method throws an <code>InvalidObjectException</code>. 4278 * <li> 4279 * If <code>serialVersionOnStream</code> is less than 4, initialize 4280 * <code>roundingMode</code> to {@link java.math.RoundingMode#HALF_EVEN 4281 * RoundingMode.HALF_EVEN}. This field is new with version 4. 4282 * <li> 4283 * If <code>serialVersionOnStream</code> is less than 3, then call 4284 * the setters for the minimum and maximum integer and fraction digits with 4285 * the values of the corresponding superclass getters to initialize the 4286 * fields in this class. The fields in this class are new with version 3. 4287 * <li> 4288 * If <code>serialVersionOnStream</code> is less than 1, indicating that 4289 * the stream was written by JDK 1.1, initialize 4290 * <code>useExponentialNotation</code> 4291 * to false, since it was not present in JDK 1.1. 4292 * <li> 4293 * Set <code>serialVersionOnStream</code> to the maximum allowed value so 4294 * that default serialization will work properly if this object is streamed 4295 * out again. 4296 * </ol> 4297 * 4298 * <p>Stream versions older than 2 will not have the affix pattern variables 4299 * <code>posPrefixPattern</code> etc. As a result, they will be initialized 4300 * to <code>null</code>, which means the affix strings will be taken as 4301 * literal values. This is exactly what we want, since that corresponds to 4302 * the pre-version-2 behavior. 4303 */ readObject(ObjectInputStream stream)4304 private void readObject(ObjectInputStream stream) 4305 throws IOException, ClassNotFoundException { 4306 // BEGIN Android-changed: Custom serialization code for compatibility with RI serialization. 4307 /* 4308 stream.defaultReadObject(); 4309 digitList = new DigitList(); 4310 4311 // We force complete fast-path reinitialization when the instance is 4312 // deserialized. See clone() comment on fastPathCheckNeeded. 4313 fastPathCheckNeeded = true; 4314 isFastPath = false; 4315 fastPathData = null; 4316 4317 if (serialVersionOnStream < 4) { 4318 setRoundingMode(RoundingMode.HALF_EVEN); 4319 } else { 4320 setRoundingMode(getRoundingMode()); 4321 } 4322 4323 // We only need to check the maximum counts because NumberFormat 4324 // .readObject has already ensured that the maximum is greater than the 4325 // minimum count. 4326 if (super.getMaximumIntegerDigits() > DOUBLE_INTEGER_DIGITS || 4327 super.getMaximumFractionDigits() > DOUBLE_FRACTION_DIGITS) { 4328 throw new InvalidObjectException("Digit count out of range"); 4329 } 4330 if (serialVersionOnStream < 3) { 4331 setMaximumIntegerDigits(super.getMaximumIntegerDigits()); 4332 setMinimumIntegerDigits(super.getMinimumIntegerDigits()); 4333 setMaximumFractionDigits(super.getMaximumFractionDigits()); 4334 setMinimumFractionDigits(super.getMinimumFractionDigits()); 4335 } 4336 if (serialVersionOnStream < 1) { 4337 // Didn't have exponential fields 4338 useExponentialNotation = false; 4339 } 4340 serialVersionOnStream = currentSerialVersion; 4341 */ 4342 ObjectInputStream.GetField fields = stream.readFields(); 4343 this.symbols = (DecimalFormatSymbols) fields.get("symbols", null); 4344 4345 initPattern("#"); 4346 4347 // Calling a setter method on an ICU DecimalFormat object will change the object's internal 4348 // state, even if the value set is the same as the default value (ICU Ticket #13266). 4349 // 4350 // In an attempt to create objects that are equals() to the ones that were serialized, it's 4351 // therefore assumed here that any values that are the same as the default values were the 4352 // default values (ie. no setter was called to explicitly set that value). 4353 4354 String positivePrefix = (String) fields.get("positivePrefix", ""); 4355 if (!Objects.equals(positivePrefix, icuDecimalFormat.getPositivePrefix())) { 4356 icuDecimalFormat.setPositivePrefix(positivePrefix); 4357 } 4358 4359 String positiveSuffix = (String) fields.get("positiveSuffix", ""); 4360 if (!Objects.equals(positiveSuffix, icuDecimalFormat.getPositiveSuffix())) { 4361 icuDecimalFormat.setPositiveSuffix(positiveSuffix); 4362 } 4363 4364 String negativePrefix = (String) fields.get("negativePrefix", "-"); 4365 if (!Objects.equals(negativePrefix, icuDecimalFormat.getNegativePrefix())) { 4366 icuDecimalFormat.setNegativePrefix(negativePrefix); 4367 } 4368 4369 String negativeSuffix = (String) fields.get("negativeSuffix", ""); 4370 if (!Objects.equals(negativeSuffix, icuDecimalFormat.getNegativeSuffix())) { 4371 icuDecimalFormat.setNegativeSuffix(negativeSuffix); 4372 } 4373 4374 int multiplier = fields.get("multiplier", 1); 4375 if (multiplier != icuDecimalFormat.getMultiplier()) { 4376 icuDecimalFormat.setMultiplier(multiplier); 4377 } 4378 4379 boolean groupingUsed = fields.get("groupingUsed", true); 4380 if (groupingUsed != icuDecimalFormat.isGroupingUsed()) { 4381 icuDecimalFormat.setGroupingUsed(groupingUsed); 4382 } 4383 4384 int groupingSize = fields.get("groupingSize", (byte) 3); 4385 if (groupingSize != icuDecimalFormat.getGroupingSize()) { 4386 icuDecimalFormat.setGroupingSize(groupingSize); 4387 } 4388 4389 boolean decimalSeparatorAlwaysShown = fields.get("decimalSeparatorAlwaysShown", false); 4390 if (decimalSeparatorAlwaysShown != icuDecimalFormat.isDecimalSeparatorAlwaysShown()) { 4391 icuDecimalFormat.setDecimalSeparatorAlwaysShown(decimalSeparatorAlwaysShown); 4392 } 4393 4394 RoundingMode roundingMode = 4395 (RoundingMode) fields.get("roundingMode", RoundingMode.HALF_EVEN); 4396 if (convertRoundingMode(roundingMode) != icuDecimalFormat.getRoundingMode()) { 4397 setRoundingMode(roundingMode); 4398 } 4399 4400 int maximumIntegerDigits = fields.get("maximumIntegerDigits", 309); 4401 if (maximumIntegerDigits != icuDecimalFormat.getMaximumIntegerDigits()) { 4402 icuDecimalFormat.setMaximumIntegerDigits(maximumIntegerDigits); 4403 } 4404 4405 int minimumIntegerDigits = fields.get("minimumIntegerDigits", 309); 4406 if (minimumIntegerDigits != icuDecimalFormat.getMinimumIntegerDigits()) { 4407 icuDecimalFormat.setMinimumIntegerDigits(minimumIntegerDigits); 4408 } 4409 4410 int maximumFractionDigits = fields.get("maximumFractionDigits", 340); 4411 if (maximumFractionDigits != icuDecimalFormat.getMaximumFractionDigits()) { 4412 icuDecimalFormat.setMaximumFractionDigits(maximumFractionDigits); 4413 } 4414 4415 int minimumFractionDigits = fields.get("minimumFractionDigits", 340); 4416 if (minimumFractionDigits != icuDecimalFormat.getMinimumFractionDigits()) { 4417 icuDecimalFormat.setMinimumFractionDigits(minimumFractionDigits); 4418 } 4419 4420 boolean parseBigDecimal = fields.get("parseBigDecimal", true); 4421 if (parseBigDecimal != icuDecimalFormat.isParseBigDecimal()) { 4422 icuDecimalFormat.setParseBigDecimal(parseBigDecimal); 4423 } 4424 4425 updateFieldsFromIcu(); 4426 4427 if (fields.get("serialVersionOnStream", 0) < 3) { 4428 setMaximumIntegerDigits(super.getMaximumIntegerDigits()); 4429 setMinimumIntegerDigits(super.getMinimumIntegerDigits()); 4430 setMaximumFractionDigits(super.getMaximumFractionDigits()); 4431 setMinimumFractionDigits(super.getMinimumFractionDigits()); 4432 } 4433 // END Android-changed: Custom serialization code for compatibility with RI serialization. 4434 } 4435 4436 //---------------------------------------------------------------------- 4437 // INSTANCE VARIABLES 4438 //---------------------------------------------------------------------- 4439 4440 // BEGIN Android-removed: various fields now stored in icuDecimalFormat. 4441 /* 4442 private transient DigitList digitList = new DigitList(); 4443 4444 /** 4445 * The symbol used as a prefix when formatting positive numbers, e.g. "+". 4446 * 4447 * @serial 4448 * @see #getPositivePrefix 4449 * 4450 private String positivePrefix = ""; 4451 4452 /** 4453 * The symbol used as a suffix when formatting positive numbers. 4454 * This is often an empty string. 4455 * 4456 * @serial 4457 * @see #getPositiveSuffix 4458 * 4459 private String positiveSuffix = ""; 4460 4461 /** 4462 * The symbol used as a prefix when formatting negative numbers, e.g. "-". 4463 * 4464 * @serial 4465 * @see #getNegativePrefix 4466 * 4467 private String negativePrefix = "-"; 4468 4469 /** 4470 * The symbol used as a suffix when formatting negative numbers. 4471 * This is often an empty string. 4472 * 4473 * @serial 4474 * @see #getNegativeSuffix 4475 * 4476 private String negativeSuffix = ""; 4477 4478 /** 4479 * The prefix pattern for non-negative numbers. This variable corresponds 4480 * to <code>positivePrefix</code>. 4481 * 4482 * <p>This pattern is expanded by the method <code>expandAffix()</code> to 4483 * <code>positivePrefix</code> to update the latter to reflect changes in 4484 * <code>symbols</code>. If this variable is <code>null</code> then 4485 * <code>positivePrefix</code> is taken as a literal value that does not 4486 * change when <code>symbols</code> changes. This variable is always 4487 * <code>null</code> for <code>DecimalFormat</code> objects older than 4488 * stream version 2 restored from stream. 4489 * 4490 * @serial 4491 * @since 1.3 4492 * 4493 private String posPrefixPattern; 4494 4495 /** 4496 * The suffix pattern for non-negative numbers. This variable corresponds 4497 * to <code>positiveSuffix</code>. This variable is analogous to 4498 * <code>posPrefixPattern</code>; see that variable for further 4499 * documentation. 4500 * 4501 * @serial 4502 * @since 1.3 4503 * 4504 private String posSuffixPattern; 4505 4506 /** 4507 * The prefix pattern for negative numbers. This variable corresponds 4508 * to <code>negativePrefix</code>. This variable is analogous to 4509 * <code>posPrefixPattern</code>; see that variable for further 4510 * documentation. 4511 * 4512 * @serial 4513 * @since 1.3 4514 * 4515 private String negPrefixPattern; 4516 4517 /** 4518 * The suffix pattern for negative numbers. This variable corresponds 4519 * to <code>negativeSuffix</code>. This variable is analogous to 4520 * <code>posPrefixPattern</code>; see that variable for further 4521 * documentation. 4522 * 4523 * @serial 4524 * @since 1.3 4525 * 4526 private String negSuffixPattern; 4527 4528 /** 4529 * The multiplier for use in percent, per mille, etc. 4530 * 4531 * @serial 4532 * @see #getMultiplier 4533 * 4534 private int multiplier = 1; 4535 4536 /** 4537 * The number of digits between grouping separators in the integer 4538 * portion of a number. Must be greater than 0 if 4539 * <code>NumberFormat.groupingUsed</code> is true. 4540 * 4541 * @serial 4542 * @see #getGroupingSize 4543 * @see java.text.NumberFormat#isGroupingUsed 4544 * 4545 private byte groupingSize = 3; // invariant, > 0 if useThousands 4546 4547 /** 4548 * If true, forces the decimal separator to always appear in a formatted 4549 * number, even if the fractional part of the number is zero. 4550 * 4551 * @serial 4552 * @see #isDecimalSeparatorAlwaysShown 4553 * 4554 private boolean decimalSeparatorAlwaysShown = false; 4555 4556 /** 4557 * If true, parse returns BigDecimal wherever possible. 4558 * 4559 * @serial 4560 * @see #isParseBigDecimal 4561 * @since 1.5 4562 * 4563 private boolean parseBigDecimal = false; 4564 4565 4566 /** 4567 * True if this object represents a currency format. This determines 4568 * whether the monetary decimal separator is used instead of the normal one. 4569 * 4570 private transient boolean isCurrencyFormat = false; 4571 */ 4572 // END Android-removed: various fields now stored in icuDecimalFormat. 4573 4574 /** 4575 * The <code>DecimalFormatSymbols</code> object used by this format. 4576 * It contains the symbols used to format numbers, e.g. the grouping separator, 4577 * decimal separator, and so on. 4578 * 4579 * @serial 4580 * @see #setDecimalFormatSymbols 4581 * @see java.text.DecimalFormatSymbols 4582 */ 4583 private DecimalFormatSymbols symbols = null; // LIU new DecimalFormatSymbols(); 4584 4585 // BEGIN Android-removed: useExponentialNotation, *FieldPositions, minExponentDigits. 4586 /* 4587 /** 4588 * True to force the use of exponential (i.e. scientific) notation when formatting 4589 * numbers. 4590 * 4591 * @serial 4592 * @since 1.2 4593 * 4594 private boolean useExponentialNotation; // Newly persistent in the Java 2 platform v.1.2 4595 4596 /** 4597 * FieldPositions describing the positive prefix String. This is 4598 * lazily created. Use <code>getPositivePrefixFieldPositions</code> 4599 * when needed. 4600 * 4601 private transient FieldPosition[] positivePrefixFieldPositions; 4602 4603 /** 4604 * FieldPositions describing the positive suffix String. This is 4605 * lazily created. Use <code>getPositiveSuffixFieldPositions</code> 4606 * when needed. 4607 * 4608 private transient FieldPosition[] positiveSuffixFieldPositions; 4609 4610 /** 4611 * FieldPositions describing the negative prefix String. This is 4612 * lazily created. Use <code>getNegativePrefixFieldPositions</code> 4613 * when needed. 4614 * 4615 private transient FieldPosition[] negativePrefixFieldPositions; 4616 4617 /** 4618 * FieldPositions describing the negative suffix String. This is 4619 * lazily created. Use <code>getNegativeSuffixFieldPositions</code> 4620 * when needed. 4621 * 4622 private transient FieldPosition[] negativeSuffixFieldPositions; 4623 4624 /** 4625 * The minimum number of digits used to display the exponent when a number is 4626 * formatted in exponential notation. This field is ignored if 4627 * <code>useExponentialNotation</code> is not true. 4628 * 4629 * @serial 4630 * @since 1.2 4631 * 4632 private byte minExponentDigits; // Newly persistent in the Java 2 platform v.1.2 4633 4634 4635 */ 4636 // END Android-removed: useExponentialNotation, *FieldPositions, minExponentDigits. 4637 4638 /** 4639 * The maximum number of digits allowed in the integer portion of a 4640 * <code>BigInteger</code> or <code>BigDecimal</code> number. 4641 * <code>maximumIntegerDigits</code> must be greater than or equal to 4642 * <code>minimumIntegerDigits</code>. 4643 * 4644 * @serial 4645 * @see #getMaximumIntegerDigits 4646 * @since 1.5 4647 */ 4648 // Android-changed: removed initialization. 4649 private int maximumIntegerDigits /* = super.getMaximumIntegerDigits() */; 4650 4651 /** 4652 * The minimum number of digits allowed in the integer portion of a 4653 * <code>BigInteger</code> or <code>BigDecimal</code> number. 4654 * <code>minimumIntegerDigits</code> must be less than or equal to 4655 * <code>maximumIntegerDigits</code>. 4656 * 4657 * @serial 4658 * @see #getMinimumIntegerDigits 4659 * @since 1.5 4660 */ 4661 // Android-changed: removed initialization. 4662 private int minimumIntegerDigits /* = super.getMinimumIntegerDigits() */; 4663 4664 /** 4665 * The maximum number of digits allowed in the fractional portion of a 4666 * <code>BigInteger</code> or <code>BigDecimal</code> number. 4667 * <code>maximumFractionDigits</code> must be greater than or equal to 4668 * <code>minimumFractionDigits</code>. 4669 * 4670 * @serial 4671 * @see #getMaximumFractionDigits 4672 * @since 1.5 4673 */ 4674 // Android-changed: removed initialization. 4675 private int maximumFractionDigits /* = super.getMaximumFractionDigits() */; 4676 4677 /** 4678 * The minimum number of digits allowed in the fractional portion of a 4679 * <code>BigInteger</code> or <code>BigDecimal</code> number. 4680 * <code>minimumFractionDigits</code> must be less than or equal to 4681 * <code>maximumFractionDigits</code>. 4682 * 4683 * @serial 4684 * @see #getMinimumFractionDigits 4685 * @since 1.5 4686 */ 4687 // Android-changed: removed initialization. 4688 private int minimumFractionDigits /* = super.getMinimumFractionDigits() */; 4689 4690 /** 4691 * The {@link java.math.RoundingMode} used in this DecimalFormat. 4692 * 4693 * @serial 4694 * @since 1.6 4695 */ 4696 private RoundingMode roundingMode = RoundingMode.HALF_EVEN; 4697 4698 // BEGIN Android-removed: FastPathData, isFastPath, fastPathCheckNeeded and fastPathData. 4699 /* 4700 // ------ DecimalFormat fields for fast-path for double algorithm ------ 4701 4702 /** 4703 * Helper inner utility class for storing the data used in the fast-path 4704 * algorithm. Almost all fields related to fast-path are encapsulated in 4705 * this class. 4706 * 4707 * Any {@code DecimalFormat} instance has a {@code fastPathData} 4708 * reference field that is null unless both the properties of the instance 4709 * are such that the instance is in the "fast-path" state, and a format call 4710 * has been done at least once while in this state. 4711 * 4712 * Almost all fields are related to the "fast-path" state only and don't 4713 * change until one of the instance properties is changed. 4714 * 4715 * {@code firstUsedIndex} and {@code lastFreeIndex} are the only 4716 * two fields that are used and modified while inside a call to 4717 * {@code fastDoubleFormat}. 4718 * 4719 * 4720 private static class FastPathData { 4721 // --- Temporary fields used in fast-path, shared by several methods. 4722 4723 /** The first unused index at the end of the formatted result. * 4724 int lastFreeIndex; 4725 4726 /** The first used index at the beginning of the formatted result * 4727 int firstUsedIndex; 4728 4729 // --- State fields related to fast-path status. Changes due to a 4730 // property change only. Set by checkAndSetFastPathStatus() only. 4731 4732 /** Difference between locale zero and default zero representation. * 4733 int zeroDelta; 4734 4735 /** Locale char for grouping separator. * 4736 char groupingChar; 4737 4738 /** Fixed index position of last integral digit of formatted result * 4739 int integralLastIndex; 4740 4741 /** Fixed index position of first fractional digit of formatted result * 4742 int fractionalFirstIndex; 4743 4744 /** Fractional constants depending on decimal|currency state * 4745 double fractionalScaleFactor; 4746 int fractionalMaxIntBound; 4747 4748 4749 /** The char array buffer that will contain the formatted result * 4750 char[] fastPathContainer; 4751 4752 /** Suffixes recorded as char array for efficiency. * 4753 char[] charsPositivePrefix; 4754 char[] charsNegativePrefix; 4755 char[] charsPositiveSuffix; 4756 char[] charsNegativeSuffix; 4757 boolean positiveAffixesRequired = true; 4758 boolean negativeAffixesRequired = true; 4759 } 4760 4761 /** The format fast-path status of the instance. Logical state. * 4762 private transient boolean isFastPath = false; 4763 4764 /** Flag stating need of check and reinit fast-path status on next format call. * 4765 private transient boolean fastPathCheckNeeded = true; 4766 4767 /** DecimalFormat reference to its FastPathData * 4768 private transient FastPathData fastPathData; 4769 */ 4770 // END Android-removed: FastPathData, isFastPath, fastPathCheckNeeded and fastPathData. 4771 4772 //---------------------------------------------------------------------- 4773 4774 static final int currentSerialVersion = 4; 4775 4776 // BEGIN Android-removed: serialVersionOnStream. 4777 4778 /** 4779 * The internal serial version which says which version was written. 4780 * Possible values are: 4781 * <ul> 4782 * <li><b>0</b> (default): versions before the Java 2 platform v1.2 4783 * <li><b>1</b>: version for 1.2, which includes the two new fields 4784 * <code>useExponentialNotation</code> and 4785 * <code>minExponentDigits</code>. 4786 * <li><b>2</b>: version for 1.3 and later, which adds four new fields: 4787 * <code>posPrefixPattern</code>, <code>posSuffixPattern</code>, 4788 * <code>negPrefixPattern</code>, and <code>negSuffixPattern</code>. 4789 * <li><b>3</b>: version for 1.5 and later, which adds five new fields: 4790 * <code>maximumIntegerDigits</code>, 4791 * <code>minimumIntegerDigits</code>, 4792 * <code>maximumFractionDigits</code>, 4793 * <code>minimumFractionDigits</code>, and 4794 * <code>parseBigDecimal</code>. 4795 * <li><b>4</b>: version for 1.6 and later, which adds one new field: 4796 * <code>roundingMode</code>. 4797 * </ul> 4798 * @since 1.2 4799 * @serial 4800 * 4801 private int serialVersionOnStream = currentSerialVersion; 4802 */ 4803 // END Android-removed: serialVersionOnStream. 4804 4805 //---------------------------------------------------------------------- 4806 // CONSTANTS 4807 //---------------------------------------------------------------------- 4808 4809 // BEGIN Android-removed: Fast-Path for double Constants, various constants. 4810 /* 4811 // ------ Fast-Path for double Constants ------ 4812 4813 /** Maximum valid integer value for applying fast-path algorithm * 4814 private static final double MAX_INT_AS_DOUBLE = (double) Integer.MAX_VALUE; 4815 4816 /** 4817 * The digit arrays used in the fast-path methods for collecting digits. 4818 * Using 3 constants arrays of chars ensures a very fast collection of digits 4819 * 4820 private static class DigitArrays { 4821 static final char[] DigitOnes1000 = new char[1000]; 4822 static final char[] DigitTens1000 = new char[1000]; 4823 static final char[] DigitHundreds1000 = new char[1000]; 4824 4825 // initialize on demand holder class idiom for arrays of digits 4826 static { 4827 int tenIndex = 0; 4828 int hundredIndex = 0; 4829 char digitOne = '0'; 4830 char digitTen = '0'; 4831 char digitHundred = '0'; 4832 for (int i = 0; i < 1000; i++ ) { 4833 4834 DigitOnes1000[i] = digitOne; 4835 if (digitOne == '9') 4836 digitOne = '0'; 4837 else 4838 digitOne++; 4839 4840 DigitTens1000[i] = digitTen; 4841 if (i == (tenIndex + 9)) { 4842 tenIndex += 10; 4843 if (digitTen == '9') 4844 digitTen = '0'; 4845 else 4846 digitTen++; 4847 } 4848 4849 DigitHundreds1000[i] = digitHundred; 4850 if (i == (hundredIndex + 99)) { 4851 digitHundred++; 4852 hundredIndex += 100; 4853 } 4854 } 4855 } 4856 } 4857 // ------ Fast-Path for double Constants end ------ 4858 4859 // Constants for characters used in programmatic (unlocalized) patterns. 4860 private static final char PATTERN_ZERO_DIGIT = '0'; 4861 private static final char PATTERN_GROUPING_SEPARATOR = ','; 4862 private static final char PATTERN_DECIMAL_SEPARATOR = '.'; 4863 private static final char PATTERN_PER_MILLE = '\u2030'; 4864 private static final char PATTERN_PERCENT = '%'; 4865 private static final char PATTERN_DIGIT = '#'; 4866 private static final char PATTERN_SEPARATOR = ';'; 4867 private static final String PATTERN_EXPONENT = "E"; 4868 private static final char PATTERN_MINUS = '-'; 4869 4870 /** 4871 * The CURRENCY_SIGN is the standard Unicode symbol for currency. It 4872 * is used in patterns and substituted with either the currency symbol, 4873 * or if it is doubled, with the international currency symbol. If the 4874 * CURRENCY_SIGN is seen in a pattern, then the decimal separator is 4875 * replaced with the monetary decimal separator. 4876 * 4877 * The CURRENCY_SIGN is not localized. 4878 * 4879 private static final char CURRENCY_SIGN = '\u00A4'; 4880 4881 private static final char QUOTE = '\''; 4882 4883 private static FieldPosition[] EmptyFieldPositionArray = new FieldPosition[0]; 4884 */ 4885 // END Android-removed: Fast-Path for double Constants, various constants. 4886 4887 // Upper limit on integer and fraction digits for a Java double 4888 static final int DOUBLE_INTEGER_DIGITS = 309; 4889 static final int DOUBLE_FRACTION_DIGITS = 340; 4890 4891 // Upper limit on integer and fraction digits for BigDecimal and BigInteger 4892 static final int MAXIMUM_INTEGER_DIGITS = Integer.MAX_VALUE; 4893 static final int MAXIMUM_FRACTION_DIGITS = Integer.MAX_VALUE; 4894 4895 // Proclaim JDK 1.1 serial compatibility. 4896 static final long serialVersionUID = 864413376551465018L; 4897 } 4898