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