diff --git a/src/main/java/com/fasterxml/jackson/core/io/BigDecimalParser.java b/src/main/java/com/fasterxml/jackson/core/io/BigDecimalParser.java index 921fca70e5..e512351d30 100644 --- a/src/main/java/com/fasterxml/jackson/core/io/BigDecimalParser.java +++ b/src/main/java/com/fasterxml/jackson/core/io/BigDecimalParser.java @@ -57,7 +57,7 @@ public static BigDecimal parse(final char[] chars, final int off, final int len) if (len < 500) { return new BigDecimal(chars, off, len); } - return parseBigDecimal(chars, off, len, len / 10); + return JavaBigDecimalParser.parseBigDecimal(chars, off, len); // 20-Aug-2022, tatu: Although "new BigDecimal(...)" only throws NumberFormatException // operations by "parseBigDecimal()" can throw "ArithmeticException", so handle both: @@ -111,132 +111,4 @@ public static BigDecimal parseWithFastParser(final char[] ch, final int off, fin + "\" can not be represented as `java.math.BigDecimal`, reason: " + nfe.getMessage()); } } - - private static BigDecimal parseBigDecimal(final char[] chars, final int off, final int len, final int splitLen) { - boolean numHasSign = false; - boolean expHasSign = false; - boolean neg = false; - int numIdx = off; - int expIdx = -1; - int dotIdx = -1; - int scale = 0; - final int endIdx = off + len; - - for (int i = off; i < endIdx; i++) { - char c = chars[i]; - switch (c) { - case '+': - if (expIdx >= 0) { - if (expHasSign) { - throw new NumberFormatException("Multiple signs in exponent"); - } - expHasSign = true; - } else { - if (numHasSign) { - throw new NumberFormatException("Multiple signs in number"); - } - numHasSign = true; - numIdx = i + 1; - } - break; - case '-': - if (expIdx >= 0) { - if (expHasSign) { - throw new NumberFormatException("Multiple signs in exponent"); - } - expHasSign = true; - } else { - if (numHasSign) { - throw new NumberFormatException("Multiple signs in number"); - } - numHasSign = true; - neg = true; - numIdx = i + 1; - } - break; - case 'e': - case 'E': - if (expIdx >= 0) { - throw new NumberFormatException("Multiple exponent markers"); - } - expIdx = i; - break; - case '.': - if (dotIdx >= 0) { - throw new NumberFormatException("Multiple decimal points"); - } - dotIdx = i; - break; - default: - if (dotIdx >= 0 && expIdx == -1) { - scale++; - } - } - } - - int numEndIdx; - int exp = 0; - if (expIdx >= 0) { - numEndIdx = expIdx; - String expStr = new String(chars, expIdx + 1, endIdx - expIdx - 1); - exp = Integer.parseInt(expStr); - scale = adjustScale(scale, exp); - } else { - numEndIdx = endIdx; - } - - BigDecimal res; - - if (dotIdx >= 0) { - int leftLen = dotIdx - numIdx; - BigDecimal left = toBigDecimalRec(chars, numIdx, leftLen, exp, splitLen); - - int rightLen = numEndIdx - dotIdx - 1; - BigDecimal right = toBigDecimalRec(chars, dotIdx + 1, rightLen, exp - rightLen, splitLen); - - res = left.add(right); - } else { - res = toBigDecimalRec(chars, numIdx, numEndIdx - numIdx, exp, splitLen); - } - - if (scale != 0) { - res = res.setScale(scale); - } - - if (neg) { - res = res.negate(); - } - - return res; - } - - private static int adjustScale(int scale, long exp) { - long adjScale = scale - exp; - if (adjScale > Integer.MAX_VALUE || adjScale < Integer.MIN_VALUE) { - throw new NumberFormatException( - "Scale out of range: " + adjScale + " while adjusting scale " + scale + " to exponent " + exp); - } - - return (int) adjScale; - } - - private static BigDecimal toBigDecimalRec(final char[] chars, final int off, final int len, - final int scale, final int splitLen) { - if (len > splitLen) { - int mid = len / 2; - BigDecimal left = toBigDecimalRec(chars, off, mid, scale + len - mid, splitLen); - BigDecimal right = toBigDecimalRec(chars, off + mid, len - mid, scale, splitLen); - - return left.add(right); - } - - if (len == 0) { - return BigDecimal.ZERO; - } - // 02-Apr-2023, tatu: [core#967] Looks like "scaleByPowerOfThen" avoids performance issue - // there would be with "movePointRight" (both doing about same thing), so) - return new BigDecimal(chars, off, len) -// .movePointRight(scale); - .scaleByPowerOfTen(scale); - } }