Skip to content

Commit

Permalink
uptake latest FastDoubleParser code (#837)
Browse files Browse the repository at this point in the history
  • Loading branch information
pjfanning committed Nov 16, 2022
1 parent 0c77083 commit 7fa3770
Show file tree
Hide file tree
Showing 65 changed files with 5,012 additions and 2,848 deletions.
8 changes: 4 additions & 4 deletions src/main/java/com/fasterxml/jackson/core/io/NumberInput.java
@@ -1,7 +1,7 @@
package com.fasterxml.jackson.core.io;

import com.fasterxml.jackson.core.io.doubleparser.FastDoubleParser;
import com.fasterxml.jackson.core.io.doubleparser.FastFloatParser;
import com.fasterxml.jackson.core.io.doubleparser.JavaDoubleParser;
import com.fasterxml.jackson.core.io.doubleparser.JavaFloatParser;

import java.math.BigDecimal;
import java.math.BigInteger;
Expand Down Expand Up @@ -355,7 +355,7 @@ public static double parseDouble(final String s) throws NumberFormatException {
* @since v2.14
*/
public static double parseDouble(final String s, final boolean useFastParser) throws NumberFormatException {
return useFastParser ? FastDoubleParser.parseDouble(s) : Double.parseDouble(s);
return useFastParser ? JavaDoubleParser.parseDouble(s) : Double.parseDouble(s);
}

/**
Expand All @@ -377,7 +377,7 @@ public static float parseFloat(final String s) throws NumberFormatException {
* @since v2.14
*/
public static float parseFloat(final String s, final boolean useFastParser) throws NumberFormatException {
return useFastParser ? FastFloatParser.parseFloat(s) : Float.parseFloat(s);
return useFastParser ? JavaFloatParser.parseFloat(s) : Float.parseFloat(s);
}

public static BigDecimal parseBigDecimal(String s) throws NumberFormatException {
Expand Down
Expand Up @@ -10,17 +10,16 @@
package com.fasterxml.jackson.core.io.doubleparser;

/**
* Parses a {@code FloatingPointLiteral} from a {@code char} array.
* Parses a Java {@code FloatingPointLiteral} from a {@code char} array.
* <p>
* This class should have a type parameter for the return value of its parse
* methods. Unfortunately Java does not support type parameters for primitive
* types. As a workaround we use {@code long}. A {@code long} has enough bits to
* fit a {@code double} value or a {@code float} value.
* <p>
* See {@link com.fasterxml.jackson.core.io.doubleparser} for the grammar of
* {@code FloatingPointLiteral}.
* See {@link JavaDoubleParser} for the grammar of {@code FloatingPointLiteral}.
*/
abstract class AbstractFloatingPointBitsFromCharArray extends AbstractFloatValueParser {
abstract class AbstractJavaFloatingPointBitsFromCharArray extends AbstractFloatValueParser {

private static boolean isDigit(char c) {
return '0' <= c && c <= '9';
Expand All @@ -34,7 +33,7 @@ private static boolean isDigit(char c) {
* @param endIndex end index (exclusive) of the optional white space
* @return index after the optional white space
*/
private int skipWhitespace(char[] str, int index, int endIndex) {
private static int skipWhitespace(char[] str, int index, int endIndex) {
for (; index < endIndex; index++) {
if ((str[index] & 0xff) > ' ') {
break;
Expand All @@ -54,7 +53,7 @@ private int skipWhitespace(char[] str, int index, int endIndex) {
* <dd><i>DecimalFloatingPointLiteral [WhiteSpace] EOT</i></dd>
* </dl>
* </blockquote>
* See {@link com.fasterxml.jackson.core.io.doubleparser} for the grammar of
* See {@link JavaDoubleParser} for the grammar of
* {@code DecimalFloatingPointLiteral} and {@code DecSignificand}.
*
* @param str a string
Expand All @@ -79,17 +78,17 @@ private long parseDecFloatLiteral(char[] str, int index, int startIndex, int end
ch = str[index];
if (isDigit(ch)) {
// This might overflow, we deal with it later.
significand = 10 * significand + ch - '0';
significand = 10 * (significand) + ch - '0';
} else if (ch == '.') {
illegal |= virtualIndexOfPoint >= 0;
virtualIndexOfPoint = index;
for (; index < endIndex - 8; index += 8) {
int eightDigits = tryToParseEightDigits(str, index + 1);
if (eightDigits < 0) {
for (; index < endIndex - 4; index += 4) {
int digits = FastDoubleSwar.tryToParseFourDigits(str, index + 1);
if (digits < 0) {
break;
}
// This might overflow, we deal with it later.
significand = 100_000_000L * significand + eightDigits;
significand = 10_000L * significand + digits;
}
} else {
break;
Expand All @@ -112,27 +111,28 @@ private long parseDecFloatLiteral(char[] str, int index, int startIndex, int end
int expNumber = 0;
if (ch == 'e' || ch == 'E') {
ch = ++index < endIndex ? str[index] : 0;
boolean neg_exp = ch == '-';
if (neg_exp || ch == '+') {
boolean isExponentNegative = ch == '-';
if (isExponentNegative || ch == '+') {
ch = ++index < endIndex ? str[index] : 0;
}
illegal |= !isDigit(ch);
do {
// Guard against overflow
if (expNumber < AbstractFloatValueParser.MAX_EXPONENT_NUMBER) {
expNumber = 10 * expNumber + ch - '0';
expNumber = 10 * (expNumber) + ch - '0';
}
ch = ++index < endIndex ? str[index] : 0;
} while (isDigit(ch));
if (neg_exp) {
if (isExponentNegative) {
expNumber = -expNumber;
}
exponent += expNumber;
}

// Skip optional FloatTypeSuffix
// long-circuit-or is faster than short-circuit-or
// ------------------------
if (index < endIndex && (ch == 'd' || ch == 'D' || ch == 'f' || ch == 'F')) {
if (ch == 'd' | ch == 'D' | ch == 'f' | ch == 'F') {
index++;
}

Expand All @@ -157,7 +157,7 @@ private long parseDecFloatLiteral(char[] str, int index, int startIndex, int end
skipCountInTruncatedDigits++;
} else {
if (Long.compareUnsigned(significand, AbstractFloatValueParser.MINIMAL_NINETEEN_DIGIT_INTEGER) < 0) {
significand = 10 * significand + ch - '0';
significand = 10 * (significand) + ch - '0';
} else {
break;
}
Expand All @@ -182,7 +182,7 @@ private long parseDecFloatLiteral(char[] str, int index, int startIndex, int end
* <dd><i>[WhiteSpace] FloatingPointLiteral [WhiteSpace]</i></dd>
* </dl>
* </blockquote>
* See {@link com.fasterxml.jackson.core.io.doubleparser} for the grammar of
* See {@link JavaDoubleParser} for the grammar of
* {@code FloatingPointLiteral}.
*
* @param str a string containing a {@code FloatingPointLiteralWithWhiteSpace}
Expand Down Expand Up @@ -218,9 +218,7 @@ public long parseFloatingPointLiteral(char[] str, int offset, int length) {
// Parse NaN or Infinity
// ---------------------
if (ch >= 'I') {
return ch == 'N'
? parseNaN(str, index, endIndex)
: parseInfinity(str, index, endIndex, isNegative);
return parseNaNOrInfinity(str, index, endIndex, isNegative);
}

// Parse optional leading zero
Expand All @@ -236,6 +234,38 @@ public long parseFloatingPointLiteral(char[] str, int offset, int length) {
return parseDecFloatLiteral(str, index, offset, endIndex, isNegative, hasLeadingZero);
}

private long parseNaNOrInfinity(char[] str, int index, int endIndex, boolean isNegative) {
if (str[index] == 'N') {
if (index + 2 < endIndex
// && str[index] == 'N'
&& str[index + 1] == 'a'
&& str[index + 2] == 'N') {

index = skipWhitespace(str, index + 3, endIndex);
if (index == endIndex) {
return nan();
}
}
} else {
if (index + 7 < endIndex
&& str[index] == 'I'
&& str[index + 1] == 'n'
&& str[index + 2] == 'f'
&& str[index + 3] == 'i'
&& str[index + 4] == 'n'
&& str[index + 5] == 'i'
&& str[index + 6] == 't'
&& str[index + 7] == 'y'
) {
index = skipWhitespace(str, index + 8, endIndex);
if (index == endIndex) {
return isNegative ? negativeInfinity() : positiveInfinity();
}
}
}
return PARSE_ERROR;
}

/**
* Parses the following rules
* (more rules are defined in {@link AbstractFloatValueParser}):
Expand Down Expand Up @@ -281,16 +311,16 @@ private long parseHexFloatLiteral(
illegal |= virtualIndexOfPoint >= 0;
virtualIndexOfPoint = index;
/*
for (;index < endIndex - 8; index += 8;) {
for (; index < endIndex - 8; index += 8) {
long parsed = tryToParseEightHexDigits(str, index + 1);
if (parsed >= 0) {
// This might overflow, we deal with it later.
digits = (digits << 32) + parsed;
significand = (significand << 32) + parsed;
} else {
break;
}
}
*/
}*/

} else {
break;
}
Expand All @@ -310,27 +340,29 @@ private long parseHexFloatLiteral(
final boolean hasExponent = (ch == 'p') || (ch == 'P');
if (hasExponent) {
ch = ++index < endIndex ? str[index] : 0;
boolean neg_exp = ch == '-';
if (neg_exp || ch == '+') {
boolean isExponentNegative = ch == '-';
if (isExponentNegative || ch == '+') {
ch = ++index < endIndex ? str[index] : 0;
}
illegal |= !isDigit(ch);
do {
// Guard against overflow
if (expNumber < AbstractFloatValueParser.MAX_EXPONENT_NUMBER) {
expNumber = 10 * expNumber + ch - '0';
expNumber = 10 * (expNumber) + ch - '0';
}
ch = ++index < endIndex ? str[index] : 0;
} while (isDigit(ch));
if (neg_exp) {
if (isExponentNegative) {
expNumber = -expNumber;
}
exponent += expNumber;
}

// Skip optional FloatTypeSuffix
// ------------------------
if (index < endIndex && (ch == 'd' || ch == 'D' || ch == 'f' || ch == 'F')) {
// long-circuit-or is faster than short-circuit-or
// ------------------------
if (ch == 'd' | ch == 'D' | ch == 'f' | ch == 'F') {
index++;
}

Expand Down Expand Up @@ -372,75 +404,8 @@ private long parseHexFloatLiteral(
virtualIndexOfPoint - index + skipCountInTruncatedDigits + expNumber);
}

/**
* Parses a {@code Infinity} production with optional trailing white space
* until the end of the text.
* <blockquote>
* <dl>
* <dt><i>InfinityWithWhiteSpace:</i></dt>
* <dd>{@code Infinity} <i>[WhiteSpace] EOT</i></dd>
* </dl>
* </blockquote>
*
* @param str a string
* @param index index of the "I" character
* @param endIndex end index (exclusive)
* @return a positive or negative infinity value
* @throws NumberFormatException on parsing failure
*/
private long parseInfinity(char[] str, int index, int endIndex, boolean negative) {
if (index + 7 < endIndex
&& str[index] == 'I'
&& str[index + 1] == 'n'
&& str[index + 2] == 'f'
&& str[index + 3] == 'i'
&& str[index + 4] == 'n'
&& str[index + 5] == 'i'
&& str[index + 6] == 't'
&& str[index + 7] == 'y'
) {
index = skipWhitespace(str, index + 8, endIndex);
if (index == endIndex) {
return negative ? negativeInfinity() : positiveInfinity();
}
}
return PARSE_ERROR;
}

/**
* Parses a {@code Nan} production with optional trailing white space
* until the end of the text.
* Given that the String contains a 'N' character at the current
* {@code index}.
* <blockquote>
* <dl>
* <dt><i>NanWithWhiteSpace:</i></dt>
* <dd>{@code NaN} <i>[WhiteSpace] EOT</i></dd>
* </dl>
* </blockquote>
*
* @param str a string that contains a "N" character at {@code index}
* @param index index of the "N" character
* @param endIndex end index (exclusive)
* @return a NaN value
* @throws NumberFormatException on parsing failure
*/
private long parseNaN(char[] str, int index, int endIndex) {
if (index + 2 < endIndex
// && str[index] == 'N'
&& str[index + 1] == 'a'
&& str[index + 2] == 'N') {

index = skipWhitespace(str, index + 3, endIndex);
if (index == endIndex) {
return nan();
}
}
return PARSE_ERROR;
}

private int tryToParseEightDigits(char[] str, int offset) {
return FastDoubleSwar.tryToParseEightDigitsUtf16(str, offset);
private long tryToParseEightHexDigits(char[] str, int offset) {
return FastDoubleSwar.tryToParseEightHexDigits(str, offset);
}

/**
Expand Down

0 comments on commit 7fa3770

Please sign in to comment.