Skip to content

Commit 4518d17

Browse files
authored
use fast parser for large bigdecimals (500+ chars) (#1157)
1 parent f24fde7 commit 4518d17

File tree

1 file changed

+1
-129
lines changed

1 file changed

+1
-129
lines changed

src/main/java/com/fasterxml/jackson/core/io/BigDecimalParser.java

+1-129
Original file line numberDiff line numberDiff line change
@@ -57,7 +57,7 @@ public static BigDecimal parse(final char[] chars, final int off, final int len)
5757
if (len < 500) {
5858
return new BigDecimal(chars, off, len);
5959
}
60-
return parseBigDecimal(chars, off, len, len / 10);
60+
return JavaBigDecimalParser.parseBigDecimal(chars, off, len);
6161

6262
// 20-Aug-2022, tatu: Although "new BigDecimal(...)" only throws NumberFormatException
6363
// operations by "parseBigDecimal()" can throw "ArithmeticException", so handle both:
@@ -111,132 +111,4 @@ public static BigDecimal parseWithFastParser(final char[] ch, final int off, fin
111111
+ "\" can not be represented as `java.math.BigDecimal`, reason: " + nfe.getMessage());
112112
}
113113
}
114-
115-
private static BigDecimal parseBigDecimal(final char[] chars, final int off, final int len, final int splitLen) {
116-
boolean numHasSign = false;
117-
boolean expHasSign = false;
118-
boolean neg = false;
119-
int numIdx = off;
120-
int expIdx = -1;
121-
int dotIdx = -1;
122-
int scale = 0;
123-
final int endIdx = off + len;
124-
125-
for (int i = off; i < endIdx; i++) {
126-
char c = chars[i];
127-
switch (c) {
128-
case '+':
129-
if (expIdx >= 0) {
130-
if (expHasSign) {
131-
throw new NumberFormatException("Multiple signs in exponent");
132-
}
133-
expHasSign = true;
134-
} else {
135-
if (numHasSign) {
136-
throw new NumberFormatException("Multiple signs in number");
137-
}
138-
numHasSign = true;
139-
numIdx = i + 1;
140-
}
141-
break;
142-
case '-':
143-
if (expIdx >= 0) {
144-
if (expHasSign) {
145-
throw new NumberFormatException("Multiple signs in exponent");
146-
}
147-
expHasSign = true;
148-
} else {
149-
if (numHasSign) {
150-
throw new NumberFormatException("Multiple signs in number");
151-
}
152-
numHasSign = true;
153-
neg = true;
154-
numIdx = i + 1;
155-
}
156-
break;
157-
case 'e':
158-
case 'E':
159-
if (expIdx >= 0) {
160-
throw new NumberFormatException("Multiple exponent markers");
161-
}
162-
expIdx = i;
163-
break;
164-
case '.':
165-
if (dotIdx >= 0) {
166-
throw new NumberFormatException("Multiple decimal points");
167-
}
168-
dotIdx = i;
169-
break;
170-
default:
171-
if (dotIdx >= 0 && expIdx == -1) {
172-
scale++;
173-
}
174-
}
175-
}
176-
177-
int numEndIdx;
178-
int exp = 0;
179-
if (expIdx >= 0) {
180-
numEndIdx = expIdx;
181-
String expStr = new String(chars, expIdx + 1, endIdx - expIdx - 1);
182-
exp = Integer.parseInt(expStr);
183-
scale = adjustScale(scale, exp);
184-
} else {
185-
numEndIdx = endIdx;
186-
}
187-
188-
BigDecimal res;
189-
190-
if (dotIdx >= 0) {
191-
int leftLen = dotIdx - numIdx;
192-
BigDecimal left = toBigDecimalRec(chars, numIdx, leftLen, exp, splitLen);
193-
194-
int rightLen = numEndIdx - dotIdx - 1;
195-
BigDecimal right = toBigDecimalRec(chars, dotIdx + 1, rightLen, exp - rightLen, splitLen);
196-
197-
res = left.add(right);
198-
} else {
199-
res = toBigDecimalRec(chars, numIdx, numEndIdx - numIdx, exp, splitLen);
200-
}
201-
202-
if (scale != 0) {
203-
res = res.setScale(scale);
204-
}
205-
206-
if (neg) {
207-
res = res.negate();
208-
}
209-
210-
return res;
211-
}
212-
213-
private static int adjustScale(int scale, long exp) {
214-
long adjScale = scale - exp;
215-
if (adjScale > Integer.MAX_VALUE || adjScale < Integer.MIN_VALUE) {
216-
throw new NumberFormatException(
217-
"Scale out of range: " + adjScale + " while adjusting scale " + scale + " to exponent " + exp);
218-
}
219-
220-
return (int) adjScale;
221-
}
222-
223-
private static BigDecimal toBigDecimalRec(final char[] chars, final int off, final int len,
224-
final int scale, final int splitLen) {
225-
if (len > splitLen) {
226-
int mid = len / 2;
227-
BigDecimal left = toBigDecimalRec(chars, off, mid, scale + len - mid, splitLen);
228-
BigDecimal right = toBigDecimalRec(chars, off + mid, len - mid, scale, splitLen);
229-
230-
return left.add(right);
231-
}
232-
233-
if (len == 0) {
234-
return BigDecimal.ZERO;
235-
}
236-
// 02-Apr-2023, tatu: [core#967] Looks like "scaleByPowerOfThen" avoids performance issue
237-
// there would be with "movePointRight" (both doing about same thing), so)
238-
return new BigDecimal(chars, off, len)
239-
// .movePointRight(scale);
240-
.scaleByPowerOfTen(scale);
241-
}
242114
}

0 commit comments

Comments
 (0)