ICU-21232 Improve performance of DecimalFormat#parse on long numbers
This commit is contained in:
parent
95cd3904aa
commit
59cdbe1f53
@ -1008,13 +1008,8 @@ void DecimalQuantity::shiftLeft(int32_t numDigits) {
|
||||
}
|
||||
if (usingBytes) {
|
||||
ensureCapacity(precision + numDigits);
|
||||
int i = precision + numDigits - 1;
|
||||
for (; i >= numDigits; i--) {
|
||||
fBCD.bcdBytes.ptr[i] = fBCD.bcdBytes.ptr[i - numDigits];
|
||||
}
|
||||
for (; i >= 0; i--) {
|
||||
fBCD.bcdBytes.ptr[i] = 0;
|
||||
}
|
||||
uprv_memmove(fBCD.bcdBytes.ptr + numDigits, fBCD.bcdBytes.ptr, precision);
|
||||
uprv_memset(fBCD.bcdBytes.ptr, 0, numDigits);
|
||||
} else {
|
||||
fBCD.bcdLong <<= (numDigits * 4);
|
||||
}
|
||||
|
@ -247,6 +247,7 @@ void NumberFormatTest::runIndexedTest( int32_t index, UBool exec, const char* &n
|
||||
TESTCASE_AUTO(Test20961_CurrencyPluralPattern);
|
||||
TESTCASE_AUTO(Test21134_ToNumberFormatter);
|
||||
TESTCASE_AUTO(Test13733_StrictAndLenient);
|
||||
TESTCASE_AUTO(Test21232_ParseTimeout);
|
||||
TESTCASE_AUTO_END;
|
||||
}
|
||||
|
||||
@ -10033,4 +10034,29 @@ void NumberFormatTest::Test13733_StrictAndLenient() {
|
||||
}
|
||||
}
|
||||
|
||||
void NumberFormatTest::Test21232_ParseTimeout() {
|
||||
IcuTestErrorCode status(*this, "Test21232_ParseTimeout");
|
||||
|
||||
DecimalFormat df(status);
|
||||
if (status.errDataIfFailureAndReset()) {
|
||||
return;
|
||||
}
|
||||
|
||||
UnicodeString input = u"4444444444444444444444444444444444444444";
|
||||
if (quick) {
|
||||
for (int32_t i = 0; i < 5; i++) {
|
||||
input.append(input);
|
||||
}
|
||||
assertEquals("Somewhat long input of digits", 1280, input.length());
|
||||
} else {
|
||||
for (int32_t i = 0; i < 12; i++) {
|
||||
input.append(input);
|
||||
}
|
||||
assertEquals("Very long input of digits", 163840, input.length());
|
||||
}
|
||||
Formattable result;
|
||||
df.parse(input, result, status);
|
||||
// Should not hang
|
||||
}
|
||||
|
||||
#endif /* #if !UCONFIG_NO_FORMATTING */
|
||||
|
@ -303,6 +303,7 @@ class NumberFormatTest: public CalendarTimeZoneTest {
|
||||
void Test20961_CurrencyPluralPattern();
|
||||
void Test21134_ToNumberFormatter();
|
||||
void Test13733_StrictAndLenient();
|
||||
void Test21232_ParseTimeout();
|
||||
|
||||
private:
|
||||
UBool testFormattableAsUFormattable(const char *file, int line, Formattable &f);
|
||||
|
@ -4,6 +4,7 @@ package com.ibm.icu.impl.number;
|
||||
|
||||
import java.math.BigDecimal;
|
||||
import java.math.BigInteger;
|
||||
import java.util.Arrays;
|
||||
|
||||
/**
|
||||
* A DecimalQuantity with internal storage as a 64-bit BCD, with fallback to a byte array for numbers
|
||||
@ -123,13 +124,8 @@ public final class DecimalQuantity_DualStorageBCD extends DecimalQuantity_Abstra
|
||||
}
|
||||
if (usingBytes) {
|
||||
ensureCapacity(precision + numDigits);
|
||||
int i = precision + numDigits - 1;
|
||||
for (; i >= numDigits; i--) {
|
||||
bcdBytes[i] = bcdBytes[i - numDigits];
|
||||
}
|
||||
for (; i >= 0; i--) {
|
||||
bcdBytes[i] = 0;
|
||||
}
|
||||
System.arraycopy(bcdBytes, 0, bcdBytes, numDigits, precision);
|
||||
Arrays.fill(bcdBytes, 0, numDigits, (byte) 0);
|
||||
} else {
|
||||
bcdLong <<= (numDigits * 4);
|
||||
}
|
||||
|
@ -6906,4 +6906,17 @@ public class NumberFormatTest extends TestFmwk {
|
||||
parsedLenientValue, expectedLenientParse);
|
||||
}
|
||||
}
|
||||
|
||||
@Test
|
||||
public void Test21232_ParseTimeout() throws ParseException {
|
||||
DecimalFormat df = new DecimalFormat();
|
||||
StringBuilder input = new StringBuilder();
|
||||
input.append("4444444444444444444444444444444444444444");
|
||||
for (int i = 0; i < 8; i++) {
|
||||
input.append(input);
|
||||
}
|
||||
assertEquals("Long input of digits", 10240, input.length());
|
||||
df.parse(input.toString());
|
||||
// Should not hang
|
||||
}
|
||||
}
|
||||
|
Loading…
Reference in New Issue
Block a user