diff --git a/src/main/java/com/fasterxml/jackson/core/io/doubleparser/AbstractFloatingPointBitsFromCharArray.java b/src/main/java/com/fasterxml/jackson/core/io/doubleparser/AbstractFloatingPointBitsFromCharArray.java
index f3672d5508..f1e2a4d840 100644
--- a/src/main/java/com/fasterxml/jackson/core/io/doubleparser/AbstractFloatingPointBitsFromCharArray.java
+++ b/src/main/java/com/fasterxml/jackson/core/io/doubleparser/AbstractFloatingPointBitsFromCharArray.java
@@ -338,7 +338,7 @@ private long parseHexFloatLiteral(
// ------------------------
index = skipWhitespace(str, index, endIndex);
if (illegal || index < endIndex
- || digitCount == 0 && str[virtualIndexOfPoint] != '.'
+ || digitCount == 0
|| !hasExponent) {
return PARSE_ERROR;
}
diff --git a/src/main/java/com/fasterxml/jackson/core/io/doubleparser/AbstractFloatingPointBitsFromCharSequence.java b/src/main/java/com/fasterxml/jackson/core/io/doubleparser/AbstractFloatingPointBitsFromCharSequence.java
index 0e2a27bec9..5d3ed5ca7c 100644
--- a/src/main/java/com/fasterxml/jackson/core/io/doubleparser/AbstractFloatingPointBitsFromCharSequence.java
+++ b/src/main/java/com/fasterxml/jackson/core/io/doubleparser/AbstractFloatingPointBitsFromCharSequence.java
@@ -328,7 +328,7 @@ private long parseHexFloatLiteral(
// ------------------------
index = skipWhitespace(str, index, endIndex);
if (illegal || index < endIndex
- || digitCount == 0 && str.charAt(virtualIndexOfPoint) != '.'
+ || digitCount == 0
|| !hasExponent) {
return PARSE_ERROR;
}
diff --git a/src/main/java/com/fasterxml/jackson/core/io/doubleparser/FastDoubleSwar.java b/src/main/java/com/fasterxml/jackson/core/io/doubleparser/FastDoubleSwar.java
index 8677643a3d..afd806421c 100644
--- a/src/main/java/com/fasterxml/jackson/core/io/doubleparser/FastDoubleSwar.java
+++ b/src/main/java/com/fasterxml/jackson/core/io/doubleparser/FastDoubleSwar.java
@@ -132,9 +132,9 @@ public static int tryToParseEightDigitsUtf8(long chunk) {
}
// The last 2 multiplications are independent of each other.
- val = (val * (1 + (10 << 8))) >>> 8;
- val = (((val & 0xff_000000ffL) * (100 + (100_0000L << 32)))
- + (((val >>> 16) & 0xff_000000ffL) * (1 + (1_0000L << 32)))) >>> 32;
+ val = val * (1 + (10 << 8)) >>> 8;
+ val = (val & 0xff_000000ffL) * (100 + (100_0000L << 32))
+ + (val >>> 16 & 0xff_000000ffL) * (1 + (1_0000L << 32)) >>> 32;
return (int) val;
}
@@ -326,4 +326,4 @@ public static long readLongFromByteArrayBigEndian(byte[] a, int offset) {
| ((a[offset + 6] & 0xffL) << 8)
| (a[offset + 7] & 0xffL);
}
-}
\ No newline at end of file
+}
diff --git a/src/main/java/com/fasterxml/jackson/core/io/doubleparser/package-info.java b/src/main/java/com/fasterxml/jackson/core/io/doubleparser/package-info.java
index 15067a0a32..742c80f19c 100644
--- a/src/main/java/com/fasterxml/jackson/core/io/doubleparser/package-info.java
+++ b/src/main/java/com/fasterxml/jackson/core/io/doubleparser/package-info.java
@@ -42,14 +42,6 @@
*
*
*
- * - HexSignificand:
- *
- HexNumeral
- *
- HexNumeral {@code .}
- *
- {@code 0x} [HexDigits] {@code .} HexDigits
- *
- {@code 0X} [HexDigits] {@code .} HexDigits
- *
- *
- *
* - BinaryExponent:
*
- BinaryExponentIndicator SignedInteger
*
diff --git a/src/test/java/com/fasterxml/jackson/core/io/doubleparser/AbstractDoubleHandPickedTest.java b/src/test/java/com/fasterxml/jackson/core/io/doubleparser/AbstractDoubleHandPickedTest.java
index 23a430f0f5..f13f965484 100644
--- a/src/test/java/com/fasterxml/jackson/core/io/doubleparser/AbstractDoubleHandPickedTest.java
+++ b/src/test/java/com/fasterxml/jackson/core/io/doubleparser/AbstractDoubleHandPickedTest.java
@@ -89,6 +89,10 @@ List dynamicTestsIllegalInputs() {
dynamicTest("0x123.456789abcde", () -> testIllegalInput("0x123.456789abcde")),
dynamicTest(".", () -> testIllegalInput(".")),
dynamicTest("0x.", () -> testIllegalInput("0x.")),
+ dynamicTest("0x", () -> testIllegalInput("0x")),
+ dynamicTest("0x1", () -> testIllegalInput("0x1")),
+ dynamicTest("0xp1", () -> testIllegalInput("0xp1")),
+ dynamicTest("0x1.", () -> testIllegalInput("0x1.")),
dynamicTest(".e2", () -> testIllegalInput(".e2"))
);
}
diff --git a/src/test/java/com/fasterxml/jackson/core/io/doubleparser/AbstractLexicallyGeneratedTest.java b/src/test/java/com/fasterxml/jackson/core/io/doubleparser/AbstractLexicallyGeneratedTest.java
index 3b7617e4d1..27f6dbb8f4 100644
--- a/src/test/java/com/fasterxml/jackson/core/io/doubleparser/AbstractLexicallyGeneratedTest.java
+++ b/src/test/java/com/fasterxml/jackson/core/io/doubleparser/AbstractLexicallyGeneratedTest.java
@@ -14,8 +14,6 @@
import org.junit.jupiter.api.DynamicTest;
import org.junit.jupiter.api.TestFactory;
-import java.util.ArrayList;
-import java.util.List;
import java.util.Random;
import java.util.stream.IntStream;
import java.util.stream.Stream;
@@ -46,15 +44,15 @@ abstract class AbstractLexicallyGeneratedTest {
* (Make sure to take a note of the seed value if
* tests failed.)
*/
- public static final long SEED = 0;//System.nanoTime();
+ public static final long SEED = System.nanoTime();
@TestFactory
@Disabled
- Stream dynamicTestsRandomStringFrom10SyntaxRuleWithoutWhitespace() {
+ Stream dynamicTestsRandomStringFrom1SyntaxRuleWithoutWhitespace() {
Random rng = new Random(SEED);
LexicalGenerator gen = new LexicalGenerator(false, true);
- return IntStream.range(1, 10_000).mapToObj(i -> {
- String str = gen.produceRandomInputStringFromLexicalRuleWithoutWhitespace(10, rng);
+ return IntStream.range(0, 100).mapToObj(i -> {
+ String str = gen.produceRandomInputStringFromLexicalRuleWithoutWhitespace(1, rng);
return dynamicTest(i + ": " + str,
() -> testAgainstJdk(str));
}
@@ -63,11 +61,24 @@ Stream dynamicTestsRandomStringFrom10SyntaxRuleWithoutWhitespace()
@TestFactory
@Disabled
- Stream dynamicTestsRandomStringFrom1SyntaxRuleWithoutWhitespace() {
+ Stream dynamicTestsRandomStringFrom2SyntaxRuleWithoutWhitespace() {
Random rng = new Random(SEED);
LexicalGenerator gen = new LexicalGenerator(false, true);
- return IntStream.range(1, 10_000).mapToObj(i -> {
- String str = gen.produceRandomInputStringFromLexicalRuleWithoutWhitespace(1, rng);
+ return IntStream.range(0, 10_000).mapToObj(i -> {
+ String str = gen.produceRandomInputStringFromLexicalRuleWithoutWhitespace(2, rng);
+ return dynamicTest(i + ": " + str,
+ () -> testAgainstJdk(str));
+ }
+ );
+ }
+
+ @TestFactory
+ @Disabled
+ Stream dynamicTestsRandomStringFrom3SyntaxRuleWithoutWhitespace() {
+ Random rng = new Random(SEED);
+ LexicalGenerator gen = new LexicalGenerator(false, true);
+ return IntStream.range(0, 10_000).mapToObj(i -> {
+ String str = gen.produceRandomInputStringFromLexicalRuleWithoutWhitespace(3, rng);
return dynamicTest(i + ": " + str,
() -> testAgainstJdk(str));
}
@@ -76,11 +87,24 @@ Stream dynamicTestsRandomStringFrom1SyntaxRuleWithoutWhitespace() {
@TestFactory
@Disabled
- Stream dynamicTestsRandomStringFrom40SyntaxRuleWithoutWhitespace() {
+ Stream dynamicTestsRandomStringFrom4SyntaxRuleWithoutWhitespace() {
Random rng = new Random(SEED);
LexicalGenerator gen = new LexicalGenerator(false, true);
- return IntStream.range(1, 10_000).mapToObj(i -> {
- String str = gen.produceRandomInputStringFromLexicalRuleWithoutWhitespace(40, rng);
+ return IntStream.range(0, 10_000).mapToObj(i -> {
+ String str = gen.produceRandomInputStringFromLexicalRuleWithoutWhitespace(4, rng);
+ return dynamicTest(i + ": " + str,
+ () -> testAgainstJdk(str));
+ }
+ );
+ }
+
+ @TestFactory
+ @Disabled
+ Stream dynamicTestsRandomStringFrom10SyntaxRuleWithoutWhitespace() {
+ Random rng = new Random(SEED);
+ LexicalGenerator gen = new LexicalGenerator(false, true);
+ return IntStream.range(0, 10_000).mapToObj(i -> {
+ String str = gen.produceRandomInputStringFromLexicalRuleWithoutWhitespace(10, rng);
return dynamicTest(i + ": " + str,
() -> testAgainstJdk(str));
}
@@ -102,13 +126,38 @@ Stream dynamicTestsRandomStringsOfIncreasingLengthWithWhitespace()
@TestFactory
@Disabled
- List dynamicTestsAllSingleCharacterInputs() {
- ArrayList list = new ArrayList<>();
- for (int codePoint = 0; codePoint <= Character.MAX_VALUE; codePoint++) {
- String str = "" + (char) codePoint;
- list.add(dynamicTest("0x" + Integer.toHexString(codePoint), () -> testAgainstJdk(str)));
- }
- return list;
+ Stream dynamicTestsAsciiCharacterInputsUpTo4Characters() {
+ int maxLength = 4;
+ Random rng = new Random();
+ return IntStream.range(0, 10_000).mapToObj(i -> {
+ char[] ch = new char[4];
+ int n = rng.nextInt(maxLength) + 1;
+ for (int j = 0; j < n; j++) {
+ ch[j] = nextAsciiChar(rng);
+ }
+ StringBuilder str = new StringBuilder();
+ StringBuilder title = new StringBuilder(Integer.toString(n));
+ title.append(':');
+ for (int j = 0; j < 4; j++) {
+ char c = ch[j];
+ if (c >= ' ') {
+ if (Character.isISOControl(c) || Character.isWhitespace(c)) {
+ title.append("").append(Integer.toHexString(c)).append(';');
+ str.append(c);
+ } else {
+ title.append((char) c);
+ str.append(c);
+ }
+ }
+ }
+ return dynamicTest(title.toString(), () -> testAgainstJdk(str.toString()));
+ });
+ }
+
+ private static char nextAsciiChar(Random rng) {
+ //U+0020 SPACE
+ //U+007F DELETE
+ return (char) (rng.nextInt(0x7f - 0x20) + 0x20);
}
/**
diff --git a/src/test/java/com/fasterxml/jackson/core/io/doubleparser/LexicalGenerator.java b/src/test/java/com/fasterxml/jackson/core/io/doubleparser/LexicalGenerator.java
index 5cf55154dc..91baee71b3 100644
--- a/src/test/java/com/fasterxml/jackson/core/io/doubleparser/LexicalGenerator.java
+++ b/src/test/java/com/fasterxml/jackson/core/io/doubleparser/LexicalGenerator.java
@@ -132,40 +132,46 @@ private int produceRandomDecimalFloatingPointLiteral(int remaining, Random rng,
remaining = produceRandomDigits(remaining, rng, buf);
buf.append('.');
remaining--;
- if (rng.nextBoolean()) {
+ if (remaining > 0 && rng.nextBoolean()) {
remaining = produceRandomDigits(remaining, rng, buf);
}
- if (rng.nextBoolean()) {
+ if (remaining > 0 && rng.nextBoolean()) {
remaining = produceRandomExponentPart(remaining, rng, buf);
}
- if (rng.nextBoolean()) {
+ if (remaining > 0 && rng.nextBoolean()) {
remaining = produceRandomFloatTypeSuffix(remaining, rng, buf);
}
break;
case 1:
buf.append('.');
remaining--;
- remaining = produceRandomDigits(remaining, rng, buf);
- if (rng.nextBoolean()) {
+ if (remaining > 0) {
+ remaining = produceRandomDigits(remaining, rng, buf);
+ }
+ if (remaining > 0 && rng.nextBoolean()) {
remaining = produceRandomExponentPart(remaining, rng, buf);
}
- if (rng.nextBoolean()) {
+ if (remaining > 0 && rng.nextBoolean()) {
remaining = produceRandomFloatTypeSuffix(remaining, rng, buf);
}
break;
case 2:
remaining = produceRandomDigits(remaining, rng, buf);
- remaining = produceRandomExponentPart(remaining, rng, buf);
- if (rng.nextBoolean()) {
+ if (remaining > 0) {
+ remaining = produceRandomExponentPart(remaining, rng, buf);
+ }
+ if (remaining > 0 && rng.nextBoolean()) {
remaining = produceRandomFloatTypeSuffix(remaining, rng, buf);
}
break;
case 3:
remaining = produceRandomDigits(remaining, rng, buf);
- if (rng.nextBoolean()) {
+ if (remaining > 0 && rng.nextBoolean()) {
remaining = produceRandomExponentPart(remaining, rng, buf);
}
- remaining = produceRandomFloatTypeSuffix(remaining, rng, buf);
+ if (remaining > 0) {
+ remaining = produceRandomFloatTypeSuffix(remaining, rng, buf);
+ }
break;
}
return remaining;
@@ -205,10 +211,12 @@ private int produceRandomDigits(int remaining, Random rng, StringBuilder buf) {
break;
case 1:
remaining = produceRandomDigit(remaining, rng, buf);
- if (rng.nextBoolean()) {
+ if (remaining > 0 && rng.nextBoolean()) {
remaining = produceRandomDigitsAndUnderscores(remaining, rng, buf);
}
- remaining = produceRandomDigit(remaining, rng, buf);
+ if (remaining > 0) {
+ remaining = produceRandomDigit(remaining, rng, buf);
+ }
break;
}
@@ -226,17 +234,21 @@ private int produceRandomDigitsAndUnderscores(int remaining, Random rng, StringB
switch (rng.nextInt(2)) {
case 0:
remaining = produceRandomDigitOrUnderscore(remaining, rng, buf);
- int todo = rng.nextInt(Math.max(remaining, 1));
- for (int i = 0; i < todo; i++) {
- remaining = produceRandomDigitOrUnderscore(remaining, rng, buf);
+ if (remaining > 0) {
+ int todo = rng.nextInt(Math.max(remaining, 1));
+ for (int i = 0; i < todo; i++) {
+ remaining = produceRandomDigitOrUnderscore(remaining, rng, buf);
+ }
}
break;
case 1:
remaining = produceRandomDigit(remaining, rng, buf);
- if (rng.nextBoolean()) {
+ if (remaining > 0 && rng.nextBoolean()) {
remaining = produceRandomDigitsAndUnderscores(remaining, rng, buf);
}
- remaining = produceRandomDigit(remaining, rng, buf);
+ if (remaining > 0) {
+ remaining = produceRandomDigit(remaining, rng, buf);
+ }
break;
}
return remaining;
@@ -289,22 +301,28 @@ private int produceRandomFloatTypeSuffix(int remaining, Random rng, StringBuilde
private int produceRandomFloatValue(int remaining, Random rng, StringBuilder buf) {
switch (rng.nextInt(4)) {
case 0:
- if (rng.nextBoolean()) {
+ if (remaining > 0 && rng.nextBoolean()) {
remaining = produceRandomSign(remaining, rng, buf);
}
- remaining = produceRandomNaNOrInfinity(remaining, rng, buf);
+ if (remaining > 0 && remaining > 0) {
+ remaining = produceRandomNaNOrInfinity(remaining, rng, buf);
+ }
break;
case 1:
if (rng.nextBoolean()) {
remaining = produceRandomSign(remaining, rng, buf);
}
- remaining = produceRandomDecimalFloatingPointLiteral(remaining, rng, buf);
+ if (remaining > 0) {
+ remaining = produceRandomDecimalFloatingPointLiteral(remaining, rng, buf);
+ }
break;
case 2:
if (rng.nextBoolean()) {
remaining = produceRandomSign(remaining, rng, buf);
}
- remaining = produceRandomHexFloatingPointLiteral(remaining, rng, buf);
+ if (remaining > 0) {
+ remaining = produceRandomHexFloatingPointLiteral(remaining, rng, buf);
+ }
break;
case 3:
remaining = produceRandomSignedInteger(remaining, rng, buf);
@@ -348,15 +366,21 @@ private int produceRandomHexDigitsAndUnderscores(int remaining, Random rng, Stri
private int produceRandomHexFloatingPointLiteral(int remaining, Random rng, StringBuilder buf) {
remaining = produceRandomHexSignificand(remaining, rng, buf);
- remaining = produceRandomBinaryExponent(remaining, rng, buf);
- remaining = produceRandomFloatTypeSuffix(remaining, rng, buf);
+ if (remaining > 0) {
+ remaining = produceRandomBinaryExponent(remaining, rng, buf);
+ }
+ if (remaining > 0) {
+ remaining = produceRandomFloatTypeSuffix(remaining, rng, buf);
+ }
return remaining;
}
private int produceRandomHexNumeral(int remaining, Random rng, StringBuilder buf) {
buf.append(rng.nextBoolean() ? "0x" : "0X");
remaining--;
- remaining = produceRandomHexDigits(remaining, rng, buf);
+ if (remaining > 0) {
+ remaining = produceRandomHexDigits(remaining, rng, buf);
+ }
return remaining;
}
@@ -382,12 +406,14 @@ private int produceRandomHexSignificand(int remaining, Random rng, StringBuilder
case 2:
buf.append(rng.nextBoolean() ? "0x" : "0X");
remaining--;
- if (rng.nextBoolean()) {
+ if (remaining > 0 && rng.nextBoolean()) {
+ remaining = produceRandomHexDigits(remaining, rng, buf);
+ }
+ if (remaining > 0 && rng.nextBoolean()) {
+ buf.append('.');
+ remaining--;
remaining = produceRandomHexDigits(remaining, rng, buf);
}
- buf.append('.');
- remaining--;
- remaining = produceRandomHexDigits(remaining, rng, buf);
break;
}
return remaining;
@@ -403,8 +429,12 @@ private int produceRandomHexSignificand(int remaining, Random rng, StringBuilder
public String produceRandomInputStringFromLexicalRuleWithWhitespace(int remaining, Random rng) {
StringBuilder buf = new StringBuilder();
remaining = produceRandomWhitespaces(remaining, rng, buf);
- remaining = produceRandomFloatValue(remaining, rng, buf);
- remaining = produceRandomWhitespaces(remaining, rng, buf);
+ if (remaining > 0) {
+ remaining = produceRandomFloatValue(remaining, rng, buf);
+ }
+ if (remaining > 0) {
+ remaining = produceRandomWhitespaces(remaining, rng, buf);
+ }
return buf.toString();
}
@@ -452,7 +482,9 @@ private int produceRandomSignedInteger(int remaining, Random rng, StringBuilder
if (rng.nextBoolean()) {
remaining = produceRandomSign(remaining, rng, buf);
}
- remaining = produceRandomDigits(remaining, rng, buf);
+ if (remaining > 0) {
+ remaining = produceRandomDigits(remaining, rng, buf);
+ }
return remaining;
}