Skip to content

Commit 159355e

Browse files
authored
add fast parser code from wrandelshofer/FastDoubleParser (#766)
1 parent 4f95115 commit 159355e

31 files changed

+31805
-0
lines changed

pom.xml

Lines changed: 15 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -141,4 +141,19 @@ com.fasterxml.jackson.core.*;version=${project.version}
141141
</plugins>
142142
</build>
143143

144+
<dependencies>
145+
<dependency>
146+
<groupId>org.junit.vintage</groupId>
147+
<artifactId>junit-vintage-engine</artifactId>
148+
<version>5.8.2</version>
149+
<scope>test</scope>
150+
</dependency>
151+
<dependency>
152+
<groupId>org.junit.jupiter</groupId>
153+
<artifactId>junit-jupiter</artifactId>
154+
<version>5.8.2</version>
155+
<scope>test</scope>
156+
</dependency>
157+
</dependencies>
158+
144159
</project>

src/main/java/com/fasterxml/jackson/core/io/doubleparser/AbstractFloatValueFromCharSequence.java

Lines changed: 520 additions & 0 deletions
Large diffs are not rendered by default.
Lines changed: 77 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,77 @@
1+
/**
2+
* References:
3+
* <dl>
4+
* <dt>This class has been derived from "FastDoubleParser".</dt>
5+
* <dd>Copyright (c) Werner Randelshofer. Apache 2.0 License.
6+
* <a href="https://github.com/wrandelshofer/FastDoubleParser">github.com</a>.</dd>
7+
* </dl>
8+
*/
9+
10+
package com.fasterxml.jackson.core.io.doubleparser;
11+
12+
/**
13+
* Abstract base class for parsers that parse a {@code FloatValue} from a
14+
* character sequence ({@code str}).
15+
* <p>
16+
* This is a C++ to Java port of Daniel Lemire's fast_double_parser.
17+
* <p>
18+
* References:
19+
* <dl>
20+
* <dt>Daniel Lemire, fast_double_parser, 4x faster than strtod.
21+
* Apache License 2.0 or Boost Software License.</dt>
22+
* <dd><a href="https://github.com/lemire/fast_double_parser">github.com</a></dd>
23+
*
24+
* <dt>Daniel Lemire, fast_float number parsing library: 4x faster than strtod.
25+
* Apache License 2.0.</dt>
26+
* <dd><a href="https://github.com/fastfloat/fast_float">github.com</a></dd>
27+
*
28+
* <dt>Daniel Lemire, Number Parsing at a Gigabyte per Second,
29+
* Software: Practice and Experience 51 (8), 2021.
30+
* arXiv.2101.11408v3 [cs.DS] 24 Feb 2021</dt>
31+
* <dd><a href="https://arxiv.org/pdf/2101.11408.pdf">arxiv.org</a></dd>
32+
* </dl>
33+
*/
34+
abstract class AbstractFloatValueParser {
35+
final static long MINIMAL_NINETEEN_DIGIT_INTEGER = 1000_00000_00000_00000L;
36+
/**
37+
* The decimal exponent of a double has a range of -324 to +308.
38+
* The hexadecimal exponent of a double has a range of -1022 to +1023.
39+
*/
40+
final static int MAX_EXPONENT_NUMBER = 1024;
41+
/**
42+
* Special value in {@link #CHAR_TO_HEX_MAP} for
43+
* the decimal point character.
44+
*/
45+
static final byte DECIMAL_POINT_CLASS = -4;
46+
/**
47+
* Special value in {@link #CHAR_TO_HEX_MAP} for
48+
* characters that are neither a hex digit nor
49+
* a decimal point character..
50+
*/
51+
static final byte OTHER_CLASS = -1;
52+
/**
53+
* Includes all non-negative values of a {@code byte}, so that we only have
54+
* to check for byte values {@literal <} 0 before accessing this array.
55+
*/
56+
static final byte[] CHAR_TO_HEX_MAP = new byte[128];
57+
58+
static {
59+
for (char ch = 0; ch < AbstractFloatValueParser.CHAR_TO_HEX_MAP.length; ch++) {
60+
AbstractFloatValueParser.CHAR_TO_HEX_MAP[ch] = AbstractFloatValueParser.OTHER_CLASS;
61+
}
62+
for (char ch = '0'; ch <= '9'; ch++) {
63+
AbstractFloatValueParser.CHAR_TO_HEX_MAP[ch] = (byte) (ch - '0');
64+
}
65+
for (char ch = 'A'; ch <= 'F'; ch++) {
66+
AbstractFloatValueParser.CHAR_TO_HEX_MAP[ch] = (byte) (ch - 'A' + 10);
67+
}
68+
for (char ch = 'a'; ch <= 'f'; ch++) {
69+
AbstractFloatValueParser.CHAR_TO_HEX_MAP[ch] = (byte) (ch - 'a' + 10);
70+
}
71+
for (char ch = '.'; ch <= '.'; ch++) {
72+
AbstractFloatValueParser.CHAR_TO_HEX_MAP[ch] = AbstractFloatValueParser.DECIMAL_POINT_CLASS;
73+
}
74+
}
75+
76+
77+
}
Lines changed: 74 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,74 @@
1+
/**
2+
* References:
3+
* <dl>
4+
* <dt>This class has been derived from "FastDoubleParser".</dt>
5+
* <dd>Copyright (c) Werner Randelshofer. Apache 2.0 License.
6+
* <a href="https://github.com/wrandelshofer/FastDoubleParser">github.com</a>.</dd>
7+
* </dl>
8+
*/
9+
10+
package com.fasterxml.jackson.core.io.doubleparser;
11+
12+
/**
13+
* Parses a {@code double} from a {@link CharSequence}.
14+
*/
15+
public final class DoubleFromCharSequence extends AbstractFloatValueFromCharSequence {
16+
17+
18+
/**
19+
* Creates a new instance.
20+
*/
21+
public DoubleFromCharSequence() {
22+
23+
}
24+
25+
@Override
26+
long nan() {
27+
return Double.doubleToRawLongBits(Double.NaN);
28+
}
29+
30+
@Override
31+
long negativeInfinity() {
32+
return Double.doubleToRawLongBits(Double.NEGATIVE_INFINITY);
33+
}
34+
35+
/**
36+
* Parses a {@code FloatValue} from a {@link CharSequence} and converts it
37+
* into a {@code double} value.
38+
* <p>
39+
* See {@link com.fasterxml.jackson.core.io.doubleparser} for the syntax of {@code FloatValue}.
40+
*
41+
* @param str the string to be parsed
42+
* @param offset the start offset of the {@code FloatValue} in {@code str}
43+
* @param length the length of {@code FloatValue} in {@code str}
44+
* @return the parsed double value
45+
* @throws NumberFormatException if the string can not be parsed
46+
*/
47+
public double parseDouble(CharSequence str, int offset, int length) throws NumberFormatException {
48+
return Double.longBitsToDouble(parseFloatValue(str, offset, length));
49+
}
50+
51+
@Override
52+
long positiveInfinity() {
53+
return Double.doubleToRawLongBits(Double.POSITIVE_INFINITY);
54+
}
55+
56+
@Override
57+
long valueOfFloatLiteral(CharSequence str, int startIndex, int endIndex, boolean isNegative,
58+
long significand, int exponent, boolean isSignificandTruncated,
59+
int exponentOfTruncatedSignificand) {
60+
double d = FastDoubleMath.tryDecFloatToDoubleTruncated(isNegative, significand, exponent, isSignificandTruncated,
61+
exponentOfTruncatedSignificand);
62+
return Double.doubleToRawLongBits(Double.isNaN(d) ? Double.parseDouble(str.subSequence(startIndex, endIndex).toString()) : d);
63+
}
64+
65+
@Override
66+
long valueOfHexLiteral(
67+
CharSequence str, int startIndex, int endIndex, boolean isNegative, long significand, int exponent,
68+
boolean isSignificandTruncated, int exponentOfTruncatedSignificand) {
69+
double d = FastDoubleMath.tryHexFloatToDoubleTruncated(isNegative, significand, exponent, isSignificandTruncated,
70+
exponentOfTruncatedSignificand);
71+
return Double.doubleToRawLongBits(Double.isNaN(d) ? Double.parseDouble(str.subSequence(startIndex, endIndex).toString()) : d);
72+
}
73+
74+
}

0 commit comments

Comments
 (0)