src/java.base/share/classes/java/util/Formatter.java

Print this page
rev 10699 : 8050142: Optimize java.util.Formatter
Reviewed-by: sherman, bchristi, lagergren

*** 2496,2506 **** // index of last argument referenced int last = -1; // last ordinary index int lasto = -1; ! FormatString[] fsa = parse(format); for (FormatString fs : fsa) { int index = fs.index(); try { switch (index) { case -2: // fixed string, "%n", or "%%" --- 2496,2506 ---- // index of last argument referenced int last = -1; // last ordinary index int lasto = -1; ! List<FormatString> fsa = parse(format); for (FormatString fs : fsa) { int index = fs.index(); try { switch (index) { case -2: // fixed string, "%n", or "%%"
*** 2539,2549 **** private static Pattern fsPattern = Pattern.compile(formatSpecifier); /** * Finds format specifiers in the format string. */ ! private FormatString[] parse(String s) { ArrayList<FormatString> al = new ArrayList<>(); Matcher m = fsPattern.matcher(s); for (int i = 0, len = s.length(); i < len; ) { if (m.find(i)) { // Anything between the start of the string and the beginning --- 2539,2549 ---- private static Pattern fsPattern = Pattern.compile(formatSpecifier); /** * Finds format specifiers in the format string. */ ! private List<FormatString> parse(String s) { ArrayList<FormatString> al = new ArrayList<>(); Matcher m = fsPattern.matcher(s); for (int i = 0, len = s.length(); i < len; ) { if (m.find(i)) { // Anything between the start of the string and the beginning
*** 2551,2575 **** // an invalid format string. if (m.start() != i) { // Make sure we didn't miss any invalid format specifiers checkText(s, i, m.start()); // Assume previous characters were fixed text ! al.add(new FixedString(s.substring(i, m.start()))); } ! al.add(new FormatSpecifier(m)); i = m.end(); } else { // No more valid format specifiers. Check for possible invalid // format specifiers. checkText(s, i, len); // The rest of the string is fixed text ! al.add(new FixedString(s.substring(i))); break; } } ! return al.toArray(new FormatString[al.size()]); } private static void checkText(String s, int start, int end) { for (int i = start; i < end; i++) { // Any '%' found in the region starts an invalid format specifier. --- 2551,2575 ---- // an invalid format string. if (m.start() != i) { // Make sure we didn't miss any invalid format specifiers checkText(s, i, m.start()); // Assume previous characters were fixed text ! al.add(new FixedString(s, i, m.start())); } ! al.add(new FormatSpecifier(s, m)); i = m.end(); } else { // No more valid format specifiers. Check for possible invalid // format specifiers. checkText(s, i, len); // The rest of the string is fixed text ! al.add(new FixedString(s, i, s.length())); break; } } ! return al; } private static void checkText(String s, int start, int end) { for (int i = start; i < end; i++) { // Any '%' found in the region starts an invalid format specifier.
*** 2586,2600 **** String toString(); } private class FixedString implements FormatString { private String s; ! FixedString(String s) { this.s = s; } public int index() { return -2; } public void print(Object arg, Locale l) ! throws IOException { a.append(s); } ! public String toString() { return s; } } /** * Enum for {@code BigDecimal} formatting. */ --- 2586,2606 ---- String toString(); } private class FixedString implements FormatString { private String s; ! private int start; ! private int end; ! FixedString(String s, int start, int end) { ! this.s = s; ! this.start = start; ! this.end = end; ! } public int index() { return -2; } public void print(Object arg, Locale l) ! throws IOException { a.append(s, start, end); } ! public String toString() { return s.substring(start, end); } } /** * Enum for {@code BigDecimal} formatting. */
*** 2633,2653 **** public int index() { return index; } ! private Flags flags(String s) { ! f = Flags.parse(s); if (f.contains(Flags.PREVIOUS)) index = -1; return f; } - Flags flags() { - return f; - } - private int width(String s) { width = -1; if (s != null) { try { width = Integer.parseInt(s); --- 2639,2655 ---- public int index() { return index; } ! private Flags flags(String s, int start, int end) { ! f = Flags.parse(s, start, end); if (f.contains(Flags.PREVIOUS)) index = -1; return f; } private int width(String s) { width = -1; if (s != null) { try { width = Integer.parseInt(s);
*** 2658,2671 **** } } return width; } - int width() { - return width; - } - private int precision(String s) { precision = -1; if (s != null) { try { // remove the '.' --- 2660,2669 ----
*** 2677,2724 **** } } return precision; } ! int precision() { ! return precision; ! } ! ! private char conversion(String s) { ! c = s.charAt(0); if (!dt) { ! if (!Conversion.isValid(c)) throw new UnknownFormatConversionException(String.valueOf(c)); ! if (Character.isUpperCase(c)) f.add(Flags.UPPERCASE); c = Character.toLowerCase(c); ! if (Conversion.isText(c)) index = -2; } - return c; } - - private char conversion() { return c; } ! FormatSpecifier(Matcher m) { int idx = 1; index(m.group(idx++)); ! flags(m.group(idx++)); width(m.group(idx++)); precision(m.group(idx++)); ! String tT = m.group(idx++); ! if (tT != null) { dt = true; ! if (tT.equals("T")) f.add(Flags.UPPERCASE); } ! conversion(m.group(idx)); if (dt) checkDateTime(); else if (Conversion.isGeneral(c)) checkGeneral(); --- 2675,2719 ---- } } return precision; } ! private char conversion(char conv) { ! c = conv; if (!dt) { ! if (!Conversion.isValid(c)) { throw new UnknownFormatConversionException(String.valueOf(c)); ! } ! if (Character.isUpperCase(c)) { f.add(Flags.UPPERCASE); c = Character.toLowerCase(c); ! } ! if (Conversion.isText(c)) { index = -2; } } return c; } ! FormatSpecifier(String s, Matcher m) { int idx = 1; index(m.group(idx++)); ! flags(s, m.start(idx), m.end(idx++)); width(m.group(idx++)); precision(m.group(idx++)); ! int tTStart = m.start(idx); ! int tTEnd = m.end(idx++); ! if (tTStart != -1 && tTEnd != -1) { dt = true; ! if (tTStart == tTEnd - 1 && s.charAt(tTStart) == 'T') { f.add(Flags.UPPERCASE); } + } ! conversion(s.charAt(m.start(idx))); if (dt) checkDateTime(); else if (Conversion.isGeneral(c)) checkGeneral();
*** 2907,2931 **** private void print(String s) throws IOException { if (precision != -1 && precision < s.length()) s = s.substring(0, precision); if (f.contains(Flags.UPPERCASE)) s = s.toUpperCase(); ! a.append(justify(s)); } ! private String justify(String s) { ! if (width == -1) ! return s; ! StringBuilder sb = new StringBuilder(); ! boolean pad = f.contains(Flags.LEFT_JUSTIFY); ! int sp = width - s.length(); ! if (!pad) ! for (int i = 0; i < sp; i++) sb.append(' '); ! sb.append(s); ! if (pad) ! for (int i = 0; i < sp; i++) sb.append(' '); ! return sb.toString(); } public String toString() { StringBuilder sb = new StringBuilder("%"); // Flags.UPPERCASE is set internally for legal conversions. --- 2902,2930 ---- private void print(String s) throws IOException { if (precision != -1 && precision < s.length()) s = s.substring(0, precision); if (f.contains(Flags.UPPERCASE)) s = s.toUpperCase(); ! appendJustified(a, s); } ! private Appendable appendJustified(Appendable a, CharSequence cs) throws IOException { ! if (width == -1) { ! return a.append(cs); ! } ! boolean padRight = f.contains(Flags.LEFT_JUSTIFY); ! int sp = width - cs.length(); ! if (padRight) { ! a.append(cs); ! } ! for (int i = 0; i < sp; i++) { ! a.append(' '); ! } ! if (!padRight) { ! a.append(cs); ! } ! return a; } public String toString() { StringBuilder sb = new StringBuilder("%"); // Flags.UPPERCASE is set internally for legal conversions.
*** 3086,3106 **** StringBuilder sb = new StringBuilder(); if (c == Conversion.DECIMAL_INTEGER) { boolean neg = value < 0; ! char[] va; ! if (value < 0) ! va = Long.toString(value, 10).substring(1).toCharArray(); ! else ! va = Long.toString(value, 10).toCharArray(); // leading sign indicator leadingSign(sb, neg); // the value ! localizedMagnitude(sb, va, f, adjustWidth(width, f, neg), l); // trailing sign indicator trailingSign(sb, neg); } else if (c == Conversion.OCTAL_INTEGER) { checkBadFlags(Flags.PARENTHESES, Flags.LEADING_SPACE, --- 3085,3101 ---- StringBuilder sb = new StringBuilder(); if (c == Conversion.DECIMAL_INTEGER) { boolean neg = value < 0; ! String valueStr = Long.toString(value, 10); // leading sign indicator leadingSign(sb, neg); // the value ! localizedMagnitude(sb, valueStr, neg ? 1 : 0, f, adjustWidth(width, f, neg), l); // trailing sign indicator trailingSign(sb, neg); } else if (c == Conversion.OCTAL_INTEGER) { checkBadFlags(Flags.PARENTHESES, Flags.LEADING_SPACE,
*** 3111,3122 **** : s.length()); // apply ALTERNATE (radix indicator for octal) before ZERO_PAD if (f.contains(Flags.ALTERNATE)) sb.append('0'); ! if (f.contains(Flags.ZERO_PAD)) ! for (int i = 0; i < width - len; i++) sb.append('0'); sb.append(s); } else if (c == Conversion.HEXADECIMAL_INTEGER) { checkBadFlags(Flags.PARENTHESES, Flags.LEADING_SPACE, Flags.PLUS); String s = Long.toHexString(value); --- 3106,3118 ---- : s.length()); // apply ALTERNATE (radix indicator for octal) before ZERO_PAD if (f.contains(Flags.ALTERNATE)) sb.append('0'); ! if (f.contains(Flags.ZERO_PAD)) { ! trailingZeros(sb, width - len); ! } sb.append(s); } else if (c == Conversion.HEXADECIMAL_INTEGER) { checkBadFlags(Flags.PARENTHESES, Flags.LEADING_SPACE, Flags.PLUS); String s = Long.toHexString(value);
*** 3125,3143 **** : s.length()); // apply ALTERNATE (radix indicator for hex) before ZERO_PAD if (f.contains(Flags.ALTERNATE)) sb.append(f.contains(Flags.UPPERCASE) ? "0X" : "0x"); ! if (f.contains(Flags.ZERO_PAD)) ! for (int i = 0; i < width - len; i++) sb.append('0'); if (f.contains(Flags.UPPERCASE)) s = s.toUpperCase(); sb.append(s); } // justify based on width ! a.append(justify(sb.toString())); } // neg := val < 0 private StringBuilder leadingSign(StringBuilder sb, boolean neg) { if (!neg) { --- 3121,3140 ---- : s.length()); // apply ALTERNATE (radix indicator for hex) before ZERO_PAD if (f.contains(Flags.ALTERNATE)) sb.append(f.contains(Flags.UPPERCASE) ? "0X" : "0x"); ! if (f.contains(Flags.ZERO_PAD)) { ! trailingZeros(sb, width - len); ! } if (f.contains(Flags.UPPERCASE)) s = s.toUpperCase(); sb.append(s); } // justify based on width ! appendJustified(a, sb); } // neg := val < 0 private StringBuilder leadingSign(StringBuilder sb, boolean neg) { if (!neg) {
*** 3170,3181 **** // leading sign indicator leadingSign(sb, neg); // the value if (c == Conversion.DECIMAL_INTEGER) { ! char[] va = v.toString().toCharArray(); ! localizedMagnitude(sb, va, f, adjustWidth(width, f, neg), l); } else if (c == Conversion.OCTAL_INTEGER) { String s = v.toString(8); int len = s.length() + sb.length(); if (neg && f.contains(Flags.PARENTHESES)) --- 3167,3177 ---- // leading sign indicator leadingSign(sb, neg); // the value if (c == Conversion.DECIMAL_INTEGER) { ! localizedMagnitude(sb, v.toString(), 0, f, adjustWidth(width, f, neg), l); } else if (c == Conversion.OCTAL_INTEGER) { String s = v.toString(8); int len = s.length() + sb.length(); if (neg && f.contains(Flags.PARENTHESES))
*** 3185,3196 **** if (f.contains(Flags.ALTERNATE)) { len++; sb.append('0'); } if (f.contains(Flags.ZERO_PAD)) { ! for (int i = 0; i < width - len; i++) ! sb.append('0'); } sb.append(s); } else if (c == Conversion.HEXADECIMAL_INTEGER) { String s = v.toString(16); --- 3181,3191 ---- if (f.contains(Flags.ALTERNATE)) { len++; sb.append('0'); } if (f.contains(Flags.ZERO_PAD)) { ! trailingZeros(sb, width - len); } sb.append(s); } else if (c == Conversion.HEXADECIMAL_INTEGER) { String s = v.toString(16);
*** 3201,3223 **** // apply ALTERNATE (radix indicator for hex) before ZERO_PAD if (f.contains(Flags.ALTERNATE)) { len += 2; sb.append(f.contains(Flags.UPPERCASE) ? "0X" : "0x"); } ! if (f.contains(Flags.ZERO_PAD)) ! for (int i = 0; i < width - len; i++) ! sb.append('0'); if (f.contains(Flags.UPPERCASE)) s = s.toUpperCase(); sb.append(s); } // trailing sign indicator trailingSign(sb, (value.signum() == -1)); // justify based on width ! a.append(justify(sb.toString())); } private void print(float value, Locale l) throws IOException { print((double) value, l); } --- 3196,3218 ---- // apply ALTERNATE (radix indicator for hex) before ZERO_PAD if (f.contains(Flags.ALTERNATE)) { len += 2; sb.append(f.contains(Flags.UPPERCASE) ? "0X" : "0x"); } ! if (f.contains(Flags.ZERO_PAD)) { ! trailingZeros(sb, width - len); ! } if (f.contains(Flags.UPPERCASE)) s = s.toUpperCase(); sb.append(s); } // trailing sign indicator trailingSign(sb, (value.signum() == -1)); // justify based on width ! appendJustified(a, sb); } private void print(float value, Locale l) throws IOException { print((double) value, l); }
*** 3244,3254 **** } else { sb.append(f.contains(Flags.UPPERCASE) ? "NAN" : "NaN"); } // justify based on width ! a.append(justify(sb.toString())); } // !Double.isInfinite(value) && !Double.isNaN(value) private void print(StringBuilder sb, double value, Locale l, Flags f, char c, int precision, boolean neg) --- 3239,3249 ---- } else { sb.append(f.contains(Flags.UPPERCASE) ? "NAN" : "NaN"); } // justify based on width ! appendJustified(a, sb); } // !Double.isInfinite(value) && !Double.isNaN(value) private void print(StringBuilder sb, double value, Locale l, Flags f, char c, int precision, boolean neg)
*** 3261,3370 **** FormattedFloatingDecimal fd = FormattedFloatingDecimal.valueOf(value, prec, FormattedFloatingDecimal.Form.SCIENTIFIC); ! char[] mant = addZeros(fd.getMantissa(), prec); // If the precision is zero and the '#' flag is set, add the // requested decimal point. ! if (f.contains(Flags.ALTERNATE) && (prec == 0)) ! mant = addDot(mant); ! char[] exp = (value == 0.0) ! ? new char[] {'+','0','0'} : fd.getExponent(); int newW = width; if (width != -1) ! newW = adjustWidth(width - exp.length - 1, f, neg); ! localizedMagnitude(sb, mant, f, newW, l); sb.append(f.contains(Flags.UPPERCASE) ? 'E' : 'e'); Flags flags = f.dup().remove(Flags.GROUP); ! char sign = exp[0]; assert(sign == '+' || sign == '-'); sb.append(sign); ! char[] tmp = new char[exp.length - 1]; ! System.arraycopy(exp, 1, tmp, 0, exp.length - 1); ! sb.append(localizedMagnitude(null, tmp, flags, -1, l)); } else if (c == Conversion.DECIMAL_FLOAT) { // Create a new FormattedFloatingDecimal with the desired // precision. int prec = (precision == -1 ? 6 : precision); FormattedFloatingDecimal fd = FormattedFloatingDecimal.valueOf(value, prec, FormattedFloatingDecimal.Form.DECIMAL_FLOAT); ! char[] mant = addZeros(fd.getMantissa(), prec); // If the precision is zero and the '#' flag is set, add the // requested decimal point. if (f.contains(Flags.ALTERNATE) && (prec == 0)) ! mant = addDot(mant); int newW = width; if (width != -1) newW = adjustWidth(width, f, neg); ! localizedMagnitude(sb, mant, f, newW, l); } else if (c == Conversion.GENERAL) { int prec = precision; if (precision == -1) prec = 6; else if (precision == 0) prec = 1; char[] exp; ! char[] mant; int expRounded; if (value == 0.0) { exp = null; ! mant = new char[] {'0'}; expRounded = 0; } else { FormattedFloatingDecimal fd = FormattedFloatingDecimal.valueOf(value, prec, FormattedFloatingDecimal.Form.GENERAL); exp = fd.getExponent(); ! mant = fd.getMantissa(); expRounded = fd.getExponentRounded(); } if (exp != null) { prec -= 1; } else { prec -= expRounded + 1; } ! mant = addZeros(mant, prec); // If the precision is zero and the '#' flag is set, add the // requested decimal point. ! if (f.contains(Flags.ALTERNATE) && (prec == 0)) ! mant = addDot(mant); int newW = width; if (width != -1) { if (exp != null) newW = adjustWidth(width - exp.length - 1, f, neg); else newW = adjustWidth(width, f, neg); } ! localizedMagnitude(sb, mant, f, newW, l); if (exp != null) { sb.append(f.contains(Flags.UPPERCASE) ? 'E' : 'e'); - Flags flags = f.dup().remove(Flags.GROUP); char sign = exp[0]; assert(sign == '+' || sign == '-'); sb.append(sign); ! char[] tmp = new char[exp.length - 1]; ! System.arraycopy(exp, 1, tmp, 0, exp.length - 1); ! sb.append(localizedMagnitude(null, tmp, flags, -1, l)); } } else if (c == Conversion.HEXADECIMAL_FLOAT) { int prec = precision; if (precision == -1) // assume that we want all of the digits --- 3256,3368 ---- FormattedFloatingDecimal fd = FormattedFloatingDecimal.valueOf(value, prec, FormattedFloatingDecimal.Form.SCIENTIFIC); ! StringBuilder mant = new StringBuilder().append(fd.getMantissa()); ! addZeros(mant, prec); // If the precision is zero and the '#' flag is set, add the // requested decimal point. ! if (f.contains(Flags.ALTERNATE) && (prec == 0)) { ! mant.append('.'); ! } ! StringBuilder exp = new StringBuilder(); ! if (value == 0.0) { ! exp.append("+00"); ! } else { ! exp.append(fd.getExponent()); ! } int newW = width; if (width != -1) ! newW = adjustWidth(width - exp.length() - 1, f, neg); ! localizedMagnitude(sb, mant, 0, f, newW, l); sb.append(f.contains(Flags.UPPERCASE) ? 'E' : 'e'); Flags flags = f.dup().remove(Flags.GROUP); ! char sign = exp.charAt(0); assert(sign == '+' || sign == '-'); sb.append(sign); ! sb.append(localizedMagnitude(null, exp, 1, flags, -1, l)); } else if (c == Conversion.DECIMAL_FLOAT) { // Create a new FormattedFloatingDecimal with the desired // precision. int prec = (precision == -1 ? 6 : precision); FormattedFloatingDecimal fd = FormattedFloatingDecimal.valueOf(value, prec, FormattedFloatingDecimal.Form.DECIMAL_FLOAT); ! StringBuilder mant = new StringBuilder().append(fd.getMantissa()); ! addZeros(mant, prec); // If the precision is zero and the '#' flag is set, add the // requested decimal point. if (f.contains(Flags.ALTERNATE) && (prec == 0)) ! mant.append('.'); int newW = width; if (width != -1) newW = adjustWidth(width, f, neg); ! localizedMagnitude(sb, mant, 0, f, newW, l); } else if (c == Conversion.GENERAL) { int prec = precision; if (precision == -1) prec = 6; else if (precision == 0) prec = 1; char[] exp; ! StringBuilder mant = new StringBuilder(); int expRounded; if (value == 0.0) { exp = null; ! mant.append('0'); expRounded = 0; } else { FormattedFloatingDecimal fd = FormattedFloatingDecimal.valueOf(value, prec, FormattedFloatingDecimal.Form.GENERAL); exp = fd.getExponent(); ! mant.append(fd.getMantissa()); expRounded = fd.getExponentRounded(); } if (exp != null) { prec -= 1; } else { prec -= expRounded + 1; } ! addZeros(mant, prec); // If the precision is zero and the '#' flag is set, add the // requested decimal point. ! if (f.contains(Flags.ALTERNATE) && (prec == 0)) { ! mant.append('.'); ! } int newW = width; if (width != -1) { if (exp != null) newW = adjustWidth(width - exp.length - 1, f, neg); else newW = adjustWidth(width, f, neg); } ! localizedMagnitude(sb, mant, 0, f, newW, l); if (exp != null) { sb.append(f.contains(Flags.UPPERCASE) ? 'E' : 'e'); char sign = exp[0]; assert(sign == '+' || sign == '-'); sb.append(sign); ! localizedMagnitudeExp(sb, exp, 1, l); } } else if (c == Conversion.HEXADECIMAL_FLOAT) { int prec = precision; if (precision == -1) // assume that we want all of the digits
*** 3372,3449 **** else if (precision == 0) prec = 1; String s = hexDouble(value, prec); ! char[] va; boolean upper = f.contains(Flags.UPPERCASE); sb.append(upper ? "0X" : "0x"); ! if (f.contains(Flags.ZERO_PAD)) ! for (int i = 0; i < width - s.length() - 2; i++) ! sb.append('0'); int idx = s.indexOf('p'); - va = s.substring(0, idx).toCharArray(); if (upper) { ! String tmp = new String(va); // don't localize hex tmp = tmp.toUpperCase(Locale.US); ! va = tmp.toCharArray(); } ! sb.append(prec != 0 ? addZeros(va, prec) : va); sb.append(upper ? 'P' : 'p'); ! sb.append(s.substring(idx+1)); } } // Add zeros to the requested precision. ! private char[] addZeros(char[] v, int prec) { // Look for the dot. If we don't find one, the we'll need to add // it before we add the zeros. int i; ! for (i = 0; i < v.length; i++) { ! if (v[i] == '.') break; } boolean needDot = false; ! if (i == v.length) { needDot = true; } // Determine existing precision. ! int outPrec = v.length - i - (needDot ? 0 : 1); assert (outPrec <= prec); ! if (outPrec == prec) ! return v; ! ! // Create new array with existing contents. ! char[] tmp ! = new char[v.length + prec - outPrec + (needDot ? 1 : 0)]; ! System.arraycopy(v, 0, tmp, 0, v.length); // Add dot if previously determined to be necessary. - int start = v.length; if (needDot) { ! tmp[v.length] = '.'; ! start++; } // Add zeros. ! for (int j = start; j < tmp.length; j++) ! tmp[j] = '0'; ! ! return tmp; } // Method assumes that d > 0. private String hexDouble(double d, int prec) { // Let Double.toHexString handle simple cases ! if(!Double.isFinite(d) || d == 0.0 || prec == 0 || prec >= 13) // remove "0x" return Double.toHexString(d).substring(2); ! else { assert(prec >= 1 && prec <= 12); int exponent = Math.getExponent(d); boolean subnormal = (exponent == DoubleConsts.MIN_EXPONENT - 1); --- 3370,3444 ---- else if (precision == 0) prec = 1; String s = hexDouble(value, prec); ! StringBuilder va = new StringBuilder(); boolean upper = f.contains(Flags.UPPERCASE); sb.append(upper ? "0X" : "0x"); ! if (f.contains(Flags.ZERO_PAD)) { ! trailingZeros(sb, width - s.length() - 2); ! } int idx = s.indexOf('p'); if (upper) { ! String tmp = s.substring(0, idx); // don't localize hex tmp = tmp.toUpperCase(Locale.US); ! va.append(tmp); ! } else { ! va.append(s, 0, idx); } ! if (prec != 0) { ! addZeros(va, prec); ! } ! sb.append(va); sb.append(upper ? 'P' : 'p'); ! sb.append(s, idx+1, s.length()); } } // Add zeros to the requested precision. ! private void addZeros(StringBuilder sb, int prec) { // Look for the dot. If we don't find one, the we'll need to add // it before we add the zeros. + int len = sb.length(); int i; ! for (i = 0; i < len; i++) { ! if (sb.charAt(i) == '.') { break; } + } boolean needDot = false; ! if (i == len) { needDot = true; } // Determine existing precision. ! int outPrec = len - i - (needDot ? 0 : 1); assert (outPrec <= prec); ! if (outPrec == prec) { ! return; ! } // Add dot if previously determined to be necessary. if (needDot) { ! sb.append('.'); } // Add zeros. ! trailingZeros(sb, prec - outPrec); } // Method assumes that d > 0. private String hexDouble(double d, int prec) { // Let Double.toHexString handle simple cases ! if (!Double.isFinite(d) || d == 0.0 || prec == 0 || prec >= 13) { // remove "0x" return Double.toHexString(d).substring(2); ! } else { assert(prec >= 1 && prec <= 12); int exponent = Math.getExponent(d); boolean subnormal = (exponent == DoubleConsts.MIN_EXPONENT - 1);
*** 3532,3542 **** // trailing sign indicator trailingSign(sb, neg); // justify based on width ! a.append(justify(sb.toString())); } // value > 0 private void print(StringBuilder sb, BigDecimal value, Locale l, Flags f, char c, int precision, boolean neg) --- 3527,3537 ---- // trailing sign indicator trailingSign(sb, neg); // justify based on width ! appendJustified(a, sb); } // value > 0 private void print(StringBuilder sb, BigDecimal value, Locale l, Flags f, char c, int precision, boolean neg)
*** 3563,3603 **** BigDecimalLayout bdl = new BigDecimalLayout(v.unscaledValue(), v.scale(), BigDecimalLayoutForm.SCIENTIFIC); ! char[] mant = bdl.mantissa(); // Add a decimal point if necessary. The mantissa may not // contain a decimal point if the scale is zero (the internal // representation has no fractional part) or the original // precision is one. Append a decimal point if '#' is set or if // we require zero padding to get to the requested precision. if ((origPrec == 1 || !bdl.hasDot()) ! && (nzeros > 0 || (f.contains(Flags.ALTERNATE)))) ! mant = addDot(mant); // Add trailing zeros in the case precision is greater than // the number of available digits after the decimal separator. ! mant = trailingZeros(mant, nzeros); ! char[] exp = bdl.exponent(); int newW = width; ! if (width != -1) ! newW = adjustWidth(width - exp.length - 1, f, neg); ! localizedMagnitude(sb, mant, f, newW, l); sb.append(f.contains(Flags.UPPERCASE) ? 'E' : 'e'); Flags flags = f.dup().remove(Flags.GROUP); ! char sign = exp[0]; assert(sign == '+' || sign == '-'); ! sb.append(exp[0]); ! char[] tmp = new char[exp.length - 1]; ! System.arraycopy(exp, 1, tmp, 0, exp.length - 1); ! sb.append(localizedMagnitude(null, tmp, flags, -1, l)); } else if (c == Conversion.DECIMAL_FLOAT) { // Create a new BigDecimal with the desired precision. int prec = (precision == -1 ? 6 : precision); int scale = value.scale(); --- 3558,3598 ---- BigDecimalLayout bdl = new BigDecimalLayout(v.unscaledValue(), v.scale(), BigDecimalLayoutForm.SCIENTIFIC); ! StringBuilder mant = bdl.mantissa(); // Add a decimal point if necessary. The mantissa may not // contain a decimal point if the scale is zero (the internal // representation has no fractional part) or the original // precision is one. Append a decimal point if '#' is set or if // we require zero padding to get to the requested precision. if ((origPrec == 1 || !bdl.hasDot()) ! && (nzeros > 0 || (f.contains(Flags.ALTERNATE)))) { ! mant.append('.'); ! } // Add trailing zeros in the case precision is greater than // the number of available digits after the decimal separator. ! trailingZeros(mant, nzeros); ! StringBuilder exp = bdl.exponent(); int newW = width; ! if (width != -1) { ! newW = adjustWidth(width - exp.length() - 1, f, neg); ! } ! localizedMagnitude(sb, mant, 0, f, newW, l); sb.append(f.contains(Flags.UPPERCASE) ? 'E' : 'e'); Flags flags = f.dup().remove(Flags.GROUP); ! char sign = exp.charAt(0); assert(sign == '+' || sign == '-'); ! sb.append(sign); ! sb.append(localizedMagnitude(null, exp, 1, flags, -1, l)); } else if (c == Conversion.DECIMAL_FLOAT) { // Create a new BigDecimal with the desired precision. int prec = (precision == -1 ? 6 : precision); int scale = value.scale();
*** 3617,3642 **** BigDecimalLayout bdl = new BigDecimalLayout( value.unscaledValue(), value.scale(), BigDecimalLayoutForm.DECIMAL_FLOAT); ! char mant[] = bdl.mantissa(); int nzeros = (bdl.scale() < prec ? prec - bdl.scale() : 0); // Add a decimal point if necessary. The mantissa may not // contain a decimal point if the scale is zero (the internal // representation has no fractional part). Append a decimal // point if '#' is set or we require zero padding to get to the // requested precision. ! if (bdl.scale() == 0 && (f.contains(Flags.ALTERNATE) || nzeros > 0)) ! mant = addDot(bdl.mantissa()); // Add trailing zeros if the precision is greater than the // number of available digits after the decimal separator. ! mant = trailingZeros(mant, nzeros); ! localizedMagnitude(sb, mant, f, adjustWidth(width, f, neg), l); } else if (c == Conversion.GENERAL) { int prec = precision; if (precision == -1) prec = 6; else if (precision == 0) --- 3612,3639 ---- BigDecimalLayout bdl = new BigDecimalLayout( value.unscaledValue(), value.scale(), BigDecimalLayoutForm.DECIMAL_FLOAT); ! StringBuilder mant = bdl.mantissa(); int nzeros = (bdl.scale() < prec ? prec - bdl.scale() : 0); // Add a decimal point if necessary. The mantissa may not // contain a decimal point if the scale is zero (the internal // representation has no fractional part). Append a decimal // point if '#' is set or we require zero padding to get to the // requested precision. ! if (bdl.scale() == 0 && (f.contains(Flags.ALTERNATE) ! || nzeros > 0)) { ! mant.append('.'); ! } // Add trailing zeros if the precision is greater than the // number of available digits after the decimal separator. ! trailingZeros(mant, nzeros); ! localizedMagnitude(sb, mant, 0, f, adjustWidth(width, f, neg), l); } else if (c == Conversion.GENERAL) { int prec = precision; if (precision == -1) prec = 6; else if (precision == 0)
*** 3691,3802 **** public int scale() { return scale; } ! // char[] with canonical string representation ! public char[] layoutChars() { ! StringBuilder sb = new StringBuilder(mant); ! if (exp != null) { ! sb.append('E'); ! sb.append(exp); ! } ! return toCharArray(sb); ! } ! ! public char[] mantissa() { ! return toCharArray(mant); } // The exponent will be formatted as a sign ('+' or '-') followed // by the exponent zero-padded to include at least two digits. ! public char[] exponent() { ! return toCharArray(exp); ! } ! ! private char[] toCharArray(StringBuilder sb) { ! if (sb == null) ! return null; ! char[] result = new char[sb.length()]; ! sb.getChars(0, result.length, result, 0); ! return result; } private void layout(BigInteger intVal, int scale, BigDecimalLayoutForm form) { ! char coeff[] = intVal.toString().toCharArray(); this.scale = scale; // Construct a buffer, with sufficient capacity for all cases. // If E-notation is needed, length will be: +1 if negative, +1 // if '.' needed, +2 for "E+", + up to 10 for adjusted // exponent. Otherwise it could have +1 if negative, plus // leading "0.00000" ! mant = new StringBuilder(coeff.length + 14); if (scale == 0) { - int len = coeff.length; if (len > 1) { ! mant.append(coeff[0]); if (form == BigDecimalLayoutForm.SCIENTIFIC) { mant.append('.'); dot = true; ! mant.append(coeff, 1, len - 1); exp = new StringBuilder("+"); ! if (len < 10) ! exp.append("0").append(len - 1); ! else exp.append(len - 1); } else { ! mant.append(coeff, 1, len - 1); } } else { mant.append(coeff); ! if (form == BigDecimalLayoutForm.SCIENTIFIC) exp = new StringBuilder("+00"); } return; } ! long adjusted = -(long) scale + (coeff.length - 1); if (form == BigDecimalLayoutForm.DECIMAL_FLOAT) { // count of padding zeros ! int pad = scale - coeff.length; if (pad >= 0) { // 0.xxx form mant.append("0."); dot = true; ! for (; pad > 0 ; pad--) mant.append('0'); mant.append(coeff); } else { ! if (-pad < coeff.length) { // xx.xx form mant.append(coeff, 0, -pad); mant.append('.'); dot = true; ! mant.append(coeff, -pad, scale); } else { // xx form ! mant.append(coeff, 0, coeff.length); ! for (int i = 0; i < -scale; i++) ! mant.append('0'); this.scale = 0; } } } else { // x.xxx form ! mant.append(coeff[0]); ! if (coeff.length > 1) { mant.append('.'); dot = true; ! mant.append(coeff, 1, coeff.length-1); } exp = new StringBuilder(); if (adjusted != 0) { long abs = Math.abs(adjusted); // require sign exp.append(adjusted < 0 ? '-' : '+'); ! if (abs < 10) exp.append('0'); exp.append(abs); } else { exp.append("+00"); } } --- 3688,3783 ---- public int scale() { return scale; } ! public StringBuilder mantissa() { ! return mant; } // The exponent will be formatted as a sign ('+' or '-') followed // by the exponent zero-padded to include at least two digits. ! public StringBuilder exponent() { ! return exp; } private void layout(BigInteger intVal, int scale, BigDecimalLayoutForm form) { ! String coeff = intVal.toString(); this.scale = scale; // Construct a buffer, with sufficient capacity for all cases. // If E-notation is needed, length will be: +1 if negative, +1 // if '.' needed, +2 for "E+", + up to 10 for adjusted // exponent. Otherwise it could have +1 if negative, plus // leading "0.00000" ! int len = coeff.length(); ! mant = new StringBuilder(len + 14); if (scale == 0) { if (len > 1) { ! mant.append(coeff.charAt(0)); if (form == BigDecimalLayoutForm.SCIENTIFIC) { mant.append('.'); dot = true; ! mant.append(coeff, 1, len); exp = new StringBuilder("+"); ! if (len < 10) { ! exp.append('0').append(len - 1); ! } else { exp.append(len - 1); + } } else { ! mant.append(coeff, 1, len); } } else { mant.append(coeff); ! if (form == BigDecimalLayoutForm.SCIENTIFIC) { exp = new StringBuilder("+00"); } + } return; } ! long adjusted = -(long) scale + (len - 1); if (form == BigDecimalLayoutForm.DECIMAL_FLOAT) { // count of padding zeros ! int pad = scale - len; if (pad >= 0) { // 0.xxx form mant.append("0."); dot = true; ! trailingZeros(mant, pad); mant.append(coeff); } else { ! if (-pad < len) { // xx.xx form mant.append(coeff, 0, -pad); mant.append('.'); dot = true; ! mant.append(coeff, -pad, -pad + scale); } else { // xx form ! mant.append(coeff, 0, len); ! trailingZeros(mant, -scale); this.scale = 0; } } } else { // x.xxx form ! mant.append(coeff.charAt(0)); ! if (len > 1) { mant.append('.'); dot = true; ! mant.append(coeff, 1, len); } exp = new StringBuilder(); if (adjusted != 0) { long abs = Math.abs(adjusted); // require sign exp.append(adjusted < 0 ? '-' : '+'); ! if (abs < 10) { exp.append('0'); + } exp.append(abs); } else { exp.append("+00"); } }
*** 3808,3856 **** if (newW != -1 && neg && f.contains(Flags.PARENTHESES)) newW--; return newW; } ! // Add a '.' to th mantissa if required ! private char[] addDot(char[] mant) { ! char[] tmp = mant; ! tmp = new char[mant.length + 1]; ! System.arraycopy(mant, 0, tmp, 0, mant.length); ! tmp[tmp.length - 1] = '.'; ! return tmp; ! } ! ! // Add trailing zeros in the case precision is greater than the number ! // of available digits after the decimal separator. ! private char[] trailingZeros(char[] mant, int nzeros) { ! char[] tmp = mant; ! if (nzeros > 0) { ! tmp = new char[mant.length + nzeros]; ! System.arraycopy(mant, 0, tmp, 0, mant.length); ! for (int i = mant.length; i < tmp.length; i++) ! tmp[i] = '0'; } - return tmp; } ! private void print(Calendar t, char c, Locale l) throws IOException ! { StringBuilder sb = new StringBuilder(); print(sb, t, c, l); // justify based on width ! String s = justify(sb.toString()); ! if (f.contains(Flags.UPPERCASE)) ! s = s.toUpperCase(); ! ! a.append(s); } ! private Appendable print(StringBuilder sb, Calendar t, char c, ! Locale l) ! throws IOException ! { if (sb == null) sb = new StringBuilder(); switch (c) { case DateTime.HOUR_OF_DAY_0: // 'H' (00 - 23) case DateTime.HOUR_0: // 'I' (01 - 12) --- 3789,3819 ---- if (newW != -1 && neg && f.contains(Flags.PARENTHESES)) newW--; return newW; } ! // Add trailing zeros ! private void trailingZeros(StringBuilder sb, int nzeros) { ! for (int i = 0; i < nzeros; i++) { ! sb.append('0'); } } ! private void print(Calendar t, char c, Locale l) throws IOException { StringBuilder sb = new StringBuilder(); print(sb, t, c, l); // justify based on width ! if (f.contains(Flags.UPPERCASE)) { ! appendJustified(a, sb.toString().toUpperCase()); ! } else { ! appendJustified(a, sb); ! } } ! private Appendable print(StringBuilder sb, Calendar t, char c, Locale l) ! throws IOException { if (sb == null) sb = new StringBuilder(); switch (c) { case DateTime.HOUR_OF_DAY_0: // 'H' (00 - 23) case DateTime.HOUR_0: // 'I' (01 - 12)
*** 4019,4028 **** --- 3982,3992 ---- print(sb, t, DateTime.MINUTE, l).append(sep); print(sb, t, DateTime.SECOND, l).append(' '); // this may be in wrong place for some locales StringBuilder tsb = new StringBuilder(); print(tsb, t, DateTime.AM_PM, l); + sb.append(tsb.toString().toUpperCase(l != null ? l : Locale.US)); break; } case DateTime.DATE_TIME: { // 'c' (Sat Nov 04 12:02:33 EST 1999) char sep = ' ';
*** 4056,4069 **** private void print(TemporalAccessor t, char c, Locale l) throws IOException { StringBuilder sb = new StringBuilder(); print(sb, t, c, l); // justify based on width ! String s = justify(sb.toString()); ! if (f.contains(Flags.UPPERCASE)) ! s = s.toUpperCase(); ! a.append(s); } private Appendable print(StringBuilder sb, TemporalAccessor t, char c, Locale l) throws IOException { if (sb == null) --- 4020,4034 ---- private void print(TemporalAccessor t, char c, Locale l) throws IOException { StringBuilder sb = new StringBuilder(); print(sb, t, c, l); // justify based on width ! if (f.contains(Flags.UPPERCASE)) { ! appendJustified(a, sb.toString().toUpperCase()); ! } else { ! appendJustified(a, sb); ! } } private Appendable print(StringBuilder sb, TemporalAccessor t, char c, Locale l) throws IOException { if (sb == null)
*** 4307,4343 **** return dfs.getZeroDigit(); } return zero; } ! private StringBuilder ! localizedMagnitude(StringBuilder sb, long value, Flags f, ! int width, Locale l) ! { ! char[] va = Long.toString(value, 10).toCharArray(); ! return localizedMagnitude(sb, va, f, width, l); } ! private StringBuilder ! localizedMagnitude(StringBuilder sb, char[] value, Flags f, ! int width, Locale l) ! { ! if (sb == null) sb = new StringBuilder(); int begin = sb.length(); char zero = getZero(l); // determine localized grouping separator and size char grpSep = '\0'; int grpSize = -1; char decSep = '\0'; ! int len = value.length; int dot = len; ! for (int j = 0; j < len; j++) { ! if (value[j] == '.') { dot = j; break; } } --- 4272,4305 ---- return dfs.getZeroDigit(); } return zero; } ! private StringBuilder localizedMagnitude(StringBuilder sb, ! long value, Flags f, int width, Locale l) { ! return localizedMagnitude(sb, Long.toString(value, 10), 0, f, width, l); } ! private StringBuilder localizedMagnitude(StringBuilder sb, ! CharSequence value, final int offset, Flags f, int width, ! Locale l) { ! if (sb == null) { sb = new StringBuilder(); + } int begin = sb.length(); char zero = getZero(l); // determine localized grouping separator and size char grpSep = '\0'; int grpSize = -1; char decSep = '\0'; ! int len = value.length(); int dot = len; ! for (int j = offset; j < len; j++) { ! if (value.charAt(j) == '.') { dot = j; break; } }
*** 4361,4394 **** grpSize = df.getGroupingSize(); } } // localize the digits inserting group separators as necessary ! for (int j = 0; j < len; j++) { if (j == dot) { sb.append(decSep); // no more group separators after the decimal separator grpSep = '\0'; continue; } ! char c = value[j]; sb.append((char) ((c - '0') + zero)); ! if (grpSep != '\0' && j != dot - 1 && ((dot - j) % grpSize == 1)) sb.append(grpSep); } // apply zero padding ! len = sb.length(); ! if (width != -1 && f.contains(Flags.ZERO_PAD)) ! for (int k = 0; k < width - len; k++) sb.insert(begin, zero); return sb; } } private static class Flags { private int flags; static final Flags NONE = new Flags(0); // '' --- 4323,4379 ---- grpSize = df.getGroupingSize(); } } // localize the digits inserting group separators as necessary ! for (int j = offset; j < len; j++) { if (j == dot) { sb.append(decSep); // no more group separators after the decimal separator grpSep = '\0'; continue; } ! char c = value.charAt(j); sb.append((char) ((c - '0') + zero)); ! if (grpSep != '\0' && j != dot - 1 && ((dot - j) % grpSize == 1)) { sb.append(grpSep); } + } // apply zero padding ! if (width != -1 && f.contains(Flags.ZERO_PAD)) { ! for (int k = sb.length(); k < width; k++) { sb.insert(begin, zero); + } + } return sb; } } + private void localizedMagnitudeExp(StringBuilder sb, char[] value, + final int offset, Locale l) { + + char zero = getZero(l); + + int len = value.length; + for (int j = offset; j < len; j++) { + if (value[j] == '.') { + if (l == null || l.equals(Locale.US)) { + sb.append('.'); + } else { + DecimalFormatSymbols dfs = DecimalFormatSymbols.getInstance(l); + sb.append(dfs.getDecimalSeparator()); + } + } + char c = value[j]; + sb.append((char) ((c - '0') + zero)); + } + + } + private static class Flags { private int flags; static final Flags NONE = new Flags(0); // ''
*** 4431,4444 **** public Flags remove(Flags f) { flags &= ~f.valueOf(); return this; } ! public static Flags parse(String s) { ! char[] ca = s.toCharArray(); Flags f = new Flags(0); ! for (char c : ca) { Flags v = parse(c); if (f.contains(v)) throw new DuplicateFormatFlagsException(v.toString()); f.add(v); } --- 4416,4429 ---- public Flags remove(Flags f) { flags &= ~f.valueOf(); return this; } ! public static Flags parse(String s, int start, int end) { Flags f = new Flags(0); ! for (int i = start; i < end; i++) { ! char c = s.charAt(i); Flags v = parse(c); if (f.contains(v)) throw new DuplicateFormatFlagsException(v.toString()); f.add(v); }