mirror of
https://github.com/Eaglercraft-TeaVM-Fork/eagler-teavm.git
synced 2024-12-22 08:14:09 -08:00
classlib: implement float support for String.format (#873)
This commit is contained in:
parent
bb837bd020
commit
953c475b46
|
@ -245,7 +245,7 @@ public class TDecimalFormat extends TNumberFormat {
|
|||
if (digit >= 0 && digit <= 9) {
|
||||
if (!fractionalPart) {
|
||||
++intSize;
|
||||
allowGroupSeparator = groupingSize > 1;
|
||||
allowGroupSeparator = isGroupingUsed() && groupingSize > 1;
|
||||
} else {
|
||||
++fracSize;
|
||||
}
|
||||
|
@ -383,7 +383,7 @@ public class TDecimalFormat extends TNumberFormat {
|
|||
if (digit >= 0 && digit <= 9) {
|
||||
if (!fractionalPart) {
|
||||
++intSize;
|
||||
allowGroupSeparator = groupingSize > 1;
|
||||
allowGroupSeparator = isGroupingUsed() && groupingSize > 1;
|
||||
} else {
|
||||
++fracSize;
|
||||
}
|
||||
|
@ -710,7 +710,7 @@ public class TDecimalFormat extends TNumberFormat {
|
|||
int digitPos = Math.max(intLength, getMinimumIntegerDigits()) - 1;
|
||||
for (int i = getMinimumIntegerDigits() - 1; i >= intLength; --i) {
|
||||
buffer.append('0');
|
||||
if (groupingSize > 0 && digitPos % groupingSize == 0 && digitPos > 0) {
|
||||
if (isGroupingUsed() && groupingSize > 0 && digitPos % groupingSize == 0 && digitPos > 0) {
|
||||
buffer.append(symbols.getGroupingSeparator());
|
||||
}
|
||||
--digitPos;
|
||||
|
@ -723,7 +723,7 @@ public class TDecimalFormat extends TNumberFormat {
|
|||
long mantissaDigitMask = POW10_ARRAY[mantissaDigit--];
|
||||
buffer.append(forDigit(Math.abs((int) (mantissa / mantissaDigitMask))));
|
||||
mantissa %= mantissaDigitMask;
|
||||
if (groupingSize > 0 && digitPos % groupingSize == 0 && digitPos > 0) {
|
||||
if (isGroupingUsed() && groupingSize > 0 && digitPos % groupingSize == 0 && digitPos > 0) {
|
||||
buffer.append(symbols.getGroupingSeparator());
|
||||
}
|
||||
--digitPos;
|
||||
|
@ -733,7 +733,7 @@ public class TDecimalFormat extends TNumberFormat {
|
|||
intLength -= significantIntDigits;
|
||||
for (int i = 0; i < intLength; ++i) {
|
||||
buffer.append('0');
|
||||
if (groupingSize > 0 && digitPos % groupingSize == 0 && digitPos > 0) {
|
||||
if (isGroupingUsed() && groupingSize > 0 && digitPos % groupingSize == 0 && digitPos > 0) {
|
||||
buffer.append(symbols.getGroupingSeparator());
|
||||
}
|
||||
--digitPos;
|
||||
|
@ -901,7 +901,7 @@ public class TDecimalFormat extends TNumberFormat {
|
|||
int digitPos = Math.max(intLength, getMinimumIntegerDigits()) - 1;
|
||||
for (int i = getMinimumIntegerDigits() - 1; i >= intLength; --i) {
|
||||
buffer.append('0');
|
||||
if (groupingSize > 0 && digitPos % groupingSize == 0 && digitPos > 0) {
|
||||
if (isGroupingUsed() && groupingSize > 0 && digitPos % groupingSize == 0 && digitPos > 0) {
|
||||
buffer.append(symbols.getGroupingSeparator());
|
||||
}
|
||||
--digitPos;
|
||||
|
@ -914,7 +914,7 @@ public class TDecimalFormat extends TNumberFormat {
|
|||
BigInteger[] parts = mantissa.divideAndRemainder(mantissaDigitMask);
|
||||
buffer.append(forDigit(Math.abs(parts[0].intValue())));
|
||||
mantissa = parts[1];
|
||||
if (groupingSize > 0 && digitPos % groupingSize == 0 && digitPos > 0) {
|
||||
if (isGroupingUsed() && groupingSize > 0 && digitPos % groupingSize == 0 && digitPos > 0) {
|
||||
buffer.append(symbols.getGroupingSeparator());
|
||||
}
|
||||
--digitPos;
|
||||
|
@ -926,7 +926,7 @@ public class TDecimalFormat extends TNumberFormat {
|
|||
intLength -= significantIntDigits;
|
||||
for (int i = 0; i < intLength; ++i) {
|
||||
buffer.append('0');
|
||||
if (groupingSize > 0 && digitPos % groupingSize == 0 && digitPos > 0) {
|
||||
if (isGroupingUsed() && groupingSize > 0 && digitPos % groupingSize == 0 && digitPos > 0) {
|
||||
buffer.append(symbols.getGroupingSeparator());
|
||||
}
|
||||
--digitPos;
|
||||
|
|
|
@ -22,6 +22,7 @@ import java.io.OutputStream;
|
|||
import java.io.OutputStreamWriter;
|
||||
import java.io.PrintStream;
|
||||
import java.io.UnsupportedEncodingException;
|
||||
import java.math.BigDecimal;
|
||||
import java.text.DecimalFormat;
|
||||
import java.text.DecimalFormatSymbols;
|
||||
import java.text.NumberFormat;
|
||||
|
@ -31,6 +32,7 @@ import java.util.IllegalFormatConversionException;
|
|||
import java.util.Locale;
|
||||
import java.util.UnknownFormatConversionException;
|
||||
import org.teavm.classlib.impl.IntegerUtil;
|
||||
import org.teavm.classlib.java.text.TDecimalFormat;
|
||||
|
||||
public final class TFormatter implements Closeable, Flushable {
|
||||
private Locale locale;
|
||||
|
@ -240,11 +242,98 @@ public final class TFormatter implements Closeable, Flushable {
|
|||
formatRadixInt(specifier, 4, true);
|
||||
break;
|
||||
|
||||
case 'f':
|
||||
formatFloat(specifier, false);
|
||||
break;
|
||||
|
||||
default:
|
||||
throw new UnknownFormatConversionException(String.valueOf(specifier));
|
||||
}
|
||||
}
|
||||
|
||||
private void formatFloat(char specifier, boolean upperCase) throws IOException {
|
||||
verifyFlags(specifier, MASK_FOR_INT_DECIMAL_FORMAT);
|
||||
verifyFloatFlags();
|
||||
|
||||
if (precision == -1) {
|
||||
precision = 6;
|
||||
}
|
||||
|
||||
Object arg = args[argumentIndex];
|
||||
boolean negative;
|
||||
if (arg instanceof Double) {
|
||||
negative = (Double) arg < 0;
|
||||
} else if (arg instanceof Float) {
|
||||
negative = (Float) arg < 0;
|
||||
} else if (arg instanceof BigDecimal) {
|
||||
negative = ((BigDecimal) arg).signum() < 0;
|
||||
} else {
|
||||
throw new IllegalFormatConversionException(specifier, arg == null ? null : arg.getClass());
|
||||
}
|
||||
|
||||
TDecimalFormat format = new TDecimalFormat();
|
||||
format.setDecimalFormatSymbols(new DecimalFormatSymbols(locale));
|
||||
if (width != -1) {
|
||||
int decimalSize = predictDecimalSize(negative, format);
|
||||
format.setMaximumIntegerDigits(decimalSize);
|
||||
if ((flags & TFormattableFlags.ZERO_PADDED) != 0) {
|
||||
format.setMinimumIntegerDigits(decimalSize);
|
||||
}
|
||||
}
|
||||
format.setMaximumFractionDigits(precision);
|
||||
format.setMinimumFractionDigits(precision);
|
||||
format.setGroupingUsed((flags & TFormattableFlags.GROUPING_SEPARATOR) != 0);
|
||||
if ((flags & TFormattableFlags.PARENTHESIZED_NEGATIVE) != 0) {
|
||||
format.setNegativePrefix("(");
|
||||
format.setNegativeSuffix(")");
|
||||
}
|
||||
if ((flags & TFormattableFlags.SIGNED) != 0) {
|
||||
format.setPositivePrefix("+"); // DecimalFormatSymbols has no plus sign
|
||||
} else if ((flags & TFormattableFlags.LEADING_SPACE) != 0) {
|
||||
format.setPositivePrefix(" ");
|
||||
}
|
||||
|
||||
String str = format.format(arg);
|
||||
|
||||
precision = -1; // prevent formatGivenString from trimming
|
||||
|
||||
formatGivenString(upperCase, str);
|
||||
}
|
||||
|
||||
private int predictDecimalSize(boolean negative, TDecimalFormat format) {
|
||||
int decimalSize = width;
|
||||
if (precision > 0) {
|
||||
decimalSize -= precision + 1; // width also includes decimal places. Subtract them!
|
||||
}
|
||||
// signs take up space as well. Also subtract them!
|
||||
if (negative) {
|
||||
if ((flags & TFormattableFlags.PARENTHESIZED_NEGATIVE) != 0) {
|
||||
decimalSize -= 2;
|
||||
} else {
|
||||
decimalSize--;
|
||||
}
|
||||
} else if ((flags & (TFormattableFlags.SIGNED | TFormattableFlags.LEADING_SPACE)) != 0) {
|
||||
decimalSize--;
|
||||
}
|
||||
// the grouping separator also takes up space. You know the drill.
|
||||
if ((flags & TFormattableFlags.GROUPING_SEPARATOR) != 0) {
|
||||
decimalSize -= decimalSize / (format.getGroupingSize() + 1);
|
||||
}
|
||||
return decimalSize;
|
||||
}
|
||||
|
||||
private void verifyFloatFlags() {
|
||||
if ((flags & TFormattableFlags.SIGNED) != 0 && (flags & TFormattableFlags.LEADING_SPACE) != 0) {
|
||||
throw new TIllegalFormatFlagsException("+ ");
|
||||
}
|
||||
if ((flags & TFormattableFlags.ZERO_PADDED) != 0 && (flags & TFormattableFlags.LEFT_JUSTIFY) != 0) {
|
||||
throw new TIllegalFormatFlagsException("0-");
|
||||
}
|
||||
if ((flags & TFormattableFlags.LEFT_JUSTIFY) != 0 && width < 0) {
|
||||
throw new TMissingFormatWidthException(format.substring(formatSpecifierStart, index));
|
||||
}
|
||||
}
|
||||
|
||||
private void formatBoolean(char specifier, boolean upperCase) throws IOException {
|
||||
verifyFlagsForGeneralFormat(specifier);
|
||||
Object arg = args[argumentIndex];
|
||||
|
|
|
@ -479,6 +479,22 @@ public class DecimalFormatTest {
|
|||
assertEquals("23.00 RUB", format.format(23));
|
||||
}
|
||||
|
||||
@Test
|
||||
public void formatsManual() {
|
||||
DecimalFormat format = new DecimalFormat();
|
||||
format.setDecimalFormatSymbols(new DecimalFormatSymbols(Locale.US));
|
||||
format.setMaximumFractionDigits(6);
|
||||
format.setMinimumFractionDigits(6);
|
||||
format.setGroupingUsed(false);
|
||||
assertEquals("1.200000", format.format((Object) 1.2));
|
||||
assertEquals("12.200000", format.format((Object) 12.2));
|
||||
format.setMaximumFractionDigits(0);
|
||||
format.setMinimumFractionDigits(0);
|
||||
format.setMaximumIntegerDigits(5);
|
||||
format.setMinimumIntegerDigits(5);
|
||||
assertEquals("00002", format.format((Object) 2.0));
|
||||
}
|
||||
|
||||
private DecimalFormat createFormat(String format) {
|
||||
return new DecimalFormat(format, symbols);
|
||||
}
|
||||
|
|
|
@ -253,4 +253,30 @@ public class FormatterTest {
|
|||
assertEquals(2, e.getPrecision());
|
||||
}
|
||||
}
|
||||
|
||||
@Test
|
||||
public void formatsDouble() {
|
||||
assertEquals("1.200000", new Formatter(Locale.US).format("%f", 1.2).toString());
|
||||
assertEquals("12.200000", new Formatter(Locale.US).format("%f", 12.2).toString());
|
||||
|
||||
assertEquals("00002", new Formatter(Locale.US).format("%05.0f", 2.3).toString());
|
||||
assertEquals("-0023", new Formatter(Locale.US).format("%05.0f", -23f).toString());
|
||||
assertEquals("1,234.600000", new Formatter(Locale.US).format("%0,9f", 1234.6).toString());
|
||||
assertEquals("(1,234.6)", new Formatter(Locale.US).format("%0,(9.1f", -1234.6).toString());
|
||||
|
||||
assertEquals("1 12 123 1,234 12,345 123,456 1,234,567", new Formatter(Locale.US)
|
||||
.format("%,.0f %,.0f %,.0f %,.0f %,.0f %,.0f %,.0f", 1f, 12f, 123f, 1234f, 12345f, 123456f, 1234567f)
|
||||
.toString());
|
||||
|
||||
assertEquals(" -123.1:-234.2 ", new Formatter(Locale.US)
|
||||
.format("%7.1f:%-7.1f", -123.1, -234.2).toString());
|
||||
|
||||
assertEquals("+123.1 +123.2 +0.3", new Formatter(Locale.US)
|
||||
.format("%+.1f %+05.1f %+.1f", 123.1, 123.2, 0.3).toString());
|
||||
|
||||
assertEquals(": 123.0:-123.0:", new Formatter(Locale.US)
|
||||
.format(":% .1f:% .1f:", 123f, -123d).toString());
|
||||
|
||||
assertEquals("12.050", new Formatter(Locale.US).format("%4.3f", 12.05).toString());
|
||||
}
|
||||
}
|
||||
|
|
Loading…
Reference in New Issue
Block a user