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);
}