├── .github
└── workflows
│ ├── ci.yml
│ └── maven-publish.yml
├── .gitignore
├── .idea
├── FastDoubleParser.iml
├── codeStyles
│ ├── Project.xml
│ └── codeStyleConfig.xml
├── compiler.xml
├── copyright
│ ├── MIT_License.xml
│ └── profiles_settings.xml
├── encodings.xml
├── jarRepositories.xml
├── misc.xml
├── runConfigurations
│ ├── Main_Dev__0_1_.xml
│ ├── Main_Dev_ar.xml
│ ├── Main_Dev_canada.xml
│ ├── Main_Dev_canada_hex.xml
│ ├── Main_Dev_mesh.xml
│ ├── Main_Java11__0_1_.xml
│ ├── Main_Java17__0_1_.xml
│ ├── Main_Java17_canada_hex.xml
│ ├── Main_Java23__0_1_.xml
│ └── Main_Java8__0_1_.xml
├── uiDesigner.xml
└── vcs.xml
├── KEYS
├── LICENSE
├── NOTICE
├── README.md
├── deployment
├── deployment.md
└── pom.xml
├── fastdoubleparser-dev
├── pom.xml
└── src
│ ├── main
│ ├── java
│ │ └── ch.randelshofer.fastdoubleparser
│ │ │ ├── ch
│ │ │ └── randelshofer
│ │ │ │ └── fastdoubleparser
│ │ │ │ ├── AbstractBigDecimalParser.java
│ │ │ │ ├── AbstractBigIntegerParser.java
│ │ │ │ ├── AbstractConfigurableFloatingPointBitsFromByteArrayAscii.java
│ │ │ │ ├── AbstractConfigurableFloatingPointBitsFromByteArrayUtf8.java
│ │ │ │ ├── AbstractConfigurableFloatingPointBitsFromCharArray.java
│ │ │ │ ├── AbstractConfigurableFloatingPointBitsFromCharSequence.java
│ │ │ │ ├── AbstractFloatValueParser.java
│ │ │ │ ├── AbstractJavaFloatingPointBitsFromByteArray.java
│ │ │ │ ├── AbstractJavaFloatingPointBitsFromCharArray.java
│ │ │ │ ├── AbstractJavaFloatingPointBitsFromCharSequence.java
│ │ │ │ ├── AbstractJsonFloatingPointBitsFromByteArray.java
│ │ │ │ ├── AbstractJsonFloatingPointBitsFromCharArray.java
│ │ │ │ ├── AbstractJsonFloatingPointBitsFromCharSequence.java
│ │ │ │ ├── AbstractNumberParser.java
│ │ │ │ ├── BigSignificand.java
│ │ │ │ ├── ConfigurableDoubleBitsFromByteArrayAscii.java
│ │ │ │ ├── ConfigurableDoubleBitsFromByteArrayUtf8.java
│ │ │ │ ├── ConfigurableDoubleBitsFromCharArray.java
│ │ │ │ ├── ConfigurableDoubleBitsFromCharSequence.java
│ │ │ │ ├── ConfigurableDoubleParser.java
│ │ │ │ ├── FastDoubleMath.java
│ │ │ │ ├── FastDoubleSwar.java
│ │ │ │ ├── FastDoubleVector.java
│ │ │ │ ├── FastFloatMath.java
│ │ │ │ ├── FastIntegerMath.java
│ │ │ │ ├── FftMultiplier.java
│ │ │ │ ├── JavaBigDecimalFromByteArray.java
│ │ │ │ ├── JavaBigDecimalFromCharArray.java
│ │ │ │ ├── JavaBigDecimalFromCharSequence.java
│ │ │ │ ├── JavaBigDecimalParser.java
│ │ │ │ ├── JavaBigIntegerFromByteArray.java
│ │ │ │ ├── JavaBigIntegerFromCharArray.java
│ │ │ │ ├── JavaBigIntegerFromCharSequence.java
│ │ │ │ ├── JavaBigIntegerParser.java
│ │ │ │ ├── JavaDoubleBitsFromByteArray.java
│ │ │ │ ├── JavaDoubleBitsFromCharArray.java
│ │ │ │ ├── JavaDoubleBitsFromCharSequence.java
│ │ │ │ ├── JavaDoubleParser.java
│ │ │ │ ├── JavaFloatBitsFromByteArray.java
│ │ │ │ ├── JavaFloatBitsFromCharArray.java
│ │ │ │ ├── JavaFloatBitsFromCharSequence.java
│ │ │ │ ├── JavaFloatParser.java
│ │ │ │ ├── JsonDoubleBitsFromByteArray.java
│ │ │ │ ├── JsonDoubleBitsFromCharArray.java
│ │ │ │ ├── JsonDoubleBitsFromCharSequence.java
│ │ │ │ ├── JsonDoubleParser.java
│ │ │ │ ├── NumberFormatSymbols.java
│ │ │ │ ├── NumberFormatSymbolsInfo.java
│ │ │ │ ├── ParseDigitsTaskByteArray.java
│ │ │ │ ├── ParseDigitsTaskCharArray.java
│ │ │ │ ├── ParseDigitsTaskCharSequence.java
│ │ │ │ ├── SlowDoubleConversionPath.java
│ │ │ │ ├── Utf8Decoder.java
│ │ │ │ ├── bte
│ │ │ │ ├── ByteDigitSet.java
│ │ │ │ ├── ByteSet.java
│ │ │ │ ├── ByteSetOfFew.java
│ │ │ │ ├── ByteSetOfNone.java
│ │ │ │ ├── ByteSetOfOne.java
│ │ │ │ ├── ByteToIntMap.java
│ │ │ │ ├── ByteTrie.java
│ │ │ │ ├── ByteTrieNode.java
│ │ │ │ ├── ByteTrieOfFew.java
│ │ │ │ ├── ByteTrieOfFewIgnoreCase.java
│ │ │ │ ├── ByteTrieOfNone.java
│ │ │ │ ├── ByteTrieOfOne.java
│ │ │ │ ├── ByteTrieOfOneSingleByte.java
│ │ │ │ ├── ConsecutiveByteDigitSet.java
│ │ │ │ └── package-info.java
│ │ │ │ ├── chr
│ │ │ │ ├── CharDigitSet.java
│ │ │ │ ├── CharSet.java
│ │ │ │ ├── CharSetOfFew.java
│ │ │ │ ├── CharSetOfNone.java
│ │ │ │ ├── CharSetOfOne.java
│ │ │ │ ├── CharToIntMap.java
│ │ │ │ ├── CharTrie.java
│ │ │ │ ├── CharTrieNode.java
│ │ │ │ ├── CharTrieOfFew.java
│ │ │ │ ├── CharTrieOfFewIgnoreCase.java
│ │ │ │ ├── CharTrieOfNone.java
│ │ │ │ ├── CharTrieOfOne.java
│ │ │ │ ├── CharTrieOfOneSingleChar.java
│ │ │ │ ├── ConsecutiveCharDigitSet.java
│ │ │ │ ├── FormatCharSet.java
│ │ │ │ └── package-info.java
│ │ │ │ └── package-info.java
│ │ │ └── module-info.java
│ └── resources
│ │ └── ch.randelshofer.fastdoubleparser
│ │ └── META-INF
│ │ └── thirdparty-LICENSE
│ └── test
│ └── java
│ └── ch.randelshofer.fastdoubleparser
│ └── ch
│ └── randelshofer
│ └── fastdoubleparser
│ ├── BigDecimalTestDataFactory.java
│ ├── BigIntegerTestDataFactory.java
│ ├── BigSignificandTest.java
│ ├── ConfigurableDoubleParserTest.java
│ ├── ConfigurableDoubleParserTestDataFactory.java
│ ├── EarlyAccessEightDigitsVectorTest.java
│ ├── EightDigitsSwarTest.java
│ ├── EightDigitsTestDataFactory.java
│ ├── FastDoubleMathTest.java
│ ├── FastFloatMathTest.java
│ ├── FastIntegerMathTest.java
│ ├── FftMultiplierTest.java
│ ├── FloatValueTestDataFactory.java
│ ├── JavaBigDecimalFromByteArrayTest.java
│ ├── JavaBigDecimalFromCharArrayTest.java
│ ├── JavaBigDecimalFromCharSequenceTest.java
│ ├── JavaBigIntegerFromByteArrayTest.java
│ ├── JavaBigIntegerFromCharArrayTest.java
│ ├── JavaBigIntegerFromCharSequenceTest.java
│ ├── JavaDoubleParserTest.java
│ ├── JavaDoubleTestDataFactory.java
│ ├── JavaFloatParserTest.java
│ ├── JavaFloatTestDataFactory.java
│ ├── JmhBigDecimalEmpiricial.java
│ ├── JmhBigDecimalScalability.java
│ ├── JmhBigIntegerScalability.java
│ ├── JmhComplex.java
│ ├── JmhConfigurableDoubleFromCharSequenceEmpirical.java
│ ├── JmhDoubleEmpirical.java
│ ├── JmhDoubleScalability.java
│ ├── JmhEightDigits.java
│ ├── JmhFastDoubleMath.java
│ ├── JmhFastFloatMath.java
│ ├── JmhFftMultiplier.java
│ ├── JmhFloat.java
│ ├── JmhJavaBigDecimalFromByteArrayEmpirical.java
│ ├── JmhJavaBigDecimalFromByteArrayScalability.java
│ ├── JmhJavaBigDecimalFromCharArrayScalability.java
│ ├── JmhJavaBigDecimalFromCharSequenceEmpirical.java
│ ├── JmhJavaBigDecimalFromCharSequenceScalability.java
│ ├── JmhJavaBigIntegerFromByteArrayScalability.java
│ ├── JmhJavaBigIntegerFromCharArrayScalability.java
│ ├── JmhJavaBigIntegerFromCharSequenceScalability.java
│ ├── JmhJavaDoubleFromByteArrayEmpirical.java
│ ├── JmhJavaDoubleFromByteArrayScalability.java
│ ├── JmhJavaDoubleFromCharArrayEmpirical.java
│ ├── JmhJavaDoubleFromCharSequenceEmpirical.java
│ ├── JmhJavaDoubleFromCharSequenceScalability.java
│ ├── JmhJavaFloatFromByteArray.java
│ ├── JmhJavaFloatFromCharSequence.java
│ ├── JmhJsonDoubleFromByteArray.java
│ ├── JmhJsonDoubleFromCharArray.java
│ ├── JmhScalb.java
│ ├── JmhSplitFloor16.java
│ ├── JmhUseBigDecimalForSlowPath.java
│ ├── JsonDoubleParserTest.java
│ ├── JsonDoubleTestDataFactory.java
│ ├── MiniTest.java
│ ├── NumberTestData.java
│ ├── NumberTestDataSupplier.java
│ ├── ParseSignificandWithSwarTest.java
│ ├── SlowDoubleConversionPathTest.java
│ ├── Strings.java
│ ├── Utf8DecoderTest.java
│ ├── VirtualCharSequence.java
│ ├── bte
│ ├── ByteToIntMapTest.java
│ ├── ByteTrieOfFewIgnoreCaseTest.java
│ └── ByteTrieTest.java
│ └── chr
│ ├── CharToIntMapTest.java
│ ├── CharTrieOfFewIgnoreCaseTest.java
│ └── CharTrieTest.java
├── fastdoubleparser-java11
├── pom.xml
└── src
│ ├── main
│ └── java
│ │ └── ch.randelshofer.fastdoubleparser
│ │ ├── ch
│ │ └── randelshofer
│ │ │ └── fastdoubleparser
│ │ │ ├── FastDoubleSwar.java
│ │ │ ├── FastIntegerMath.java
│ │ │ └── NumberFormatSymbols.java
│ │ └── module-info.java
│ └── test
│ └── java
│ └── ch.randelshofer.fastdoubleparser
│ └── ch
│ └── randelshofer
│ └── fastdoubleparser
│ ├── NumberTestData.java
│ └── NumberTestDataSupplier.java
├── fastdoubleparser-java17
├── pom.xml
└── src
│ ├── main
│ └── java
│ │ └── ch.randelshofer.fastdoubleparser
│ │ ├── ch
│ │ └── randelshofer
│ │ │ └── fastdoubleparser
│ │ │ ├── FastDoubleSwar.java
│ │ │ └── FastIntegerMath.java
│ │ └── module-info.java
│ └── test
│ └── java
│ └── ch.randelshofer.fastdoubleparser
│ └── ch
│ └── randelshofer
│ └── fastdoubleparser
│ └── empty.txt
├── fastdoubleparser-java21
├── pom.xml
└── src
│ ├── main
│ └── java
│ │ └── ch.randelshofer.fastdoubleparser
│ │ ├── ch
│ │ └── randelshofer
│ │ │ └── fastdoubleparser
│ │ │ └── FastDoubleSwar.java
│ │ └── module-info.java
│ └── test
│ └── java
│ └── ch.randelshofer.fastdoubleparser
│ └── ch
│ └── randelshofer
│ └── fastdoubleparser
│ └── empty.txt
├── fastdoubleparser-java23
├── pom.xml
└── src
│ ├── main
│ └── java
│ │ └── ch.randelshofer.fastdoubleparser
│ │ └── module-info.java
│ └── test
│ └── java
│ └── ch.randelshofer.fastdoubleparser
│ └── ch
│ └── randelshofer
│ └── fastdoubleparser
│ └── empty.txt
├── fastdoubleparser-java8
├── pom.xml
└── src
│ ├── main
│ └── java
│ │ └── ch.randelshofer.fastdoubleparser
│ │ └── ch
│ │ └── randelshofer
│ │ └── fastdoubleparser
│ │ ├── BigSignificand.java
│ │ ├── FastDoubleSwar.java
│ │ ├── FastIntegerMath.java
│ │ └── NumberFormatSymbols.java
│ └── test
│ └── java
│ └── ch.randelshofer.fastdoubleparser
│ └── ch
│ └── randelshofer
│ └── fastdoubleparser
│ ├── NumberTestData.java
│ └── NumberTestDataSupplier.java
├── fastdoubleparser
├── pom.xml
└── src
│ └── assembly
│ └── mrjar.xml
├── fastdoubleparserdemo-dev
├── pom.xml
└── src
│ ├── main
│ └── java
│ │ └── ch.randelshofer.fastdoubleparserdemo
│ │ ├── ch
│ │ └── randelshofer
│ │ │ └── fastdoubleparserdemo
│ │ │ ├── DoubleSum.java
│ │ │ ├── GenerateNumberFormatNumbers.java
│ │ │ ├── Main.java
│ │ │ ├── Stats.java
│ │ │ ├── SystemInfo.java
│ │ │ └── VarianceStatistics.java
│ │ └── module-info.java
│ └── test
│ └── java
│ └── ch.randelshofer.fastdoubleparserdemo
│ └── ch
│ └── randelshofer
│ └── fastdoubleparser
│ └── empty.txt
├── fastdoubleparserdemo-java11
├── pom.xml
└── src
│ └── main
│ └── java
│ └── ch.randelshofer.fastdoubleparserdemo
│ └── ch
│ └── randelshofer
│ └── fastdoubleparserdemo
│ ├── DecimalFormatMain.java
│ └── empty.txt
├── fastdoubleparserdemo-java17
├── pom.xml
└── src
│ ├── main
│ └── java
│ │ └── ch.randelshofer.fastdoubleparserdemo
│ │ └── ch
│ │ └── randelshofer
│ │ └── fastdoubleparser
│ │ └── empty.txt
│ └── test
│ └── java
│ └── ch.randelshofer.fastdoubleparserdemo
│ └── ch
│ └── randelshofer
│ └── fastdoubleparser
│ └── empty.txt
├── fastdoubleparserdemo-java21
├── pom.xml
└── src
│ ├── main
│ └── java
│ │ └── ch.randelshofer.fastdoubleparserdemo
│ │ └── ch
│ │ └── randelshofer
│ │ └── fastdoubleparser
│ │ └── empty.txt
│ └── test
│ └── java
│ └── ch.randelshofer.fastdoubleparserdemo
│ └── ch
│ └── randelshofer
│ └── fastdoubleparser
│ └── empty.txt
├── fastdoubleparserdemo-java23
├── pom.xml
└── src
│ ├── main
│ └── java
│ │ └── ch.randelshofer.fastdoubleparserdemo
│ │ └── ch
│ │ └── randelshofer
│ │ └── fastdoubleparser
│ │ └── empty.txt
│ └── test
│ └── java
│ └── ch.randelshofer.fastdoubleparserdemo
│ └── ch
│ └── randelshofer
│ └── fastdoubleparser
│ └── empty.txt
├── fastdoubleparserdemo-java8
├── pom.xml
└── src
│ ├── main
│ └── java
│ │ └── ch.randelshofer.fastdoubleparserdemo
│ │ └── empty.txt
│ └── test
│ └── java
│ └── ch.randelshofer.fastdoubleparserdemo
│ └── ch
│ └── randelshofer
│ └── fastdoubleparserdemo
│ └── empty.txt
├── fastdoubleparserdemo
├── data
│ ├── canada.txt
│ ├── canada_hex.txt
│ ├── formatted_ar-Java8.txt
│ ├── formatted_ar-java11.txt
│ ├── formatted_ar.txt
│ ├── formatted_en-GB.txt
│ ├── formatted_fr-FR.txt
│ ├── formatted_zh-CN.txt
│ └── mesh.txt
├── pom.xml
└── src
│ └── assembly
│ └── mrjar.xml
└── pom.xml
/.github/workflows/ci.yml:
--------------------------------------------------------------------------------
1 | name: Java CI build and test
2 |
3 | on: [push]
4 |
5 | jobs:
6 | test:
7 | runs-on: ${{ matrix.os }}
8 | strategy:
9 | matrix:
10 | os: [ ubuntu-latest ]
11 | java: [ 23 ]
12 | arch: [ x64 ]
13 | dist: [ zulu ]
14 | fail-fast: false
15 | max-parallel: 4
16 | name: Test JDK ${{ matrix.java }}, ${{ matrix.os }}, ${{ matrix.arch }}
17 | steps:
18 | - uses: actions/checkout@v4
19 | - name: Set up JDK ${{ matrix.java }}
20 | uses: actions/setup-java@v4
21 | with:
22 | java-version: ${{ matrix.java }}
23 | architecture: ${{ matrix.arch }}
24 | distribution: ${{ matrix.dist }}
25 |
26 | - name: Show where Java Home is
27 | run: echo JAVA_HOME=$JAVA_HOME
28 | - name: Build with Maven
29 | run: mvn --batch-mode --update-snapshots --errors package
30 | - name: Performance Test canada.txt
31 | run: java -XX:CompileCommand=inline,java/lang/String.charAt -p ~/.m2/repository/com/ibm/icu/icu4j/75.1/icu4j-75.1.jar:fastdoubleparserdemo/target:fastdoubleparser/target -m ch.randelshofer.fastdoubleparserdemo/ch.randelshofer.fastdoubleparserdemo.Main fastdoubleparserdemo/data/canada.txt
32 | ...
33 |
--------------------------------------------------------------------------------
/.github/workflows/maven-publish.yml:
--------------------------------------------------------------------------------
1 | # This workflow will build a package using Maven and then publish it to GitHub packages when a release is created
2 | # For more information see: https://github.com/actions/setup-java/blob/main/docs/advanced-usage.md#apache-maven-with-a-settings-path
3 |
4 | name: Maven Package
5 |
6 | on:
7 | release:
8 | types: [created]
9 |
10 | jobs:
11 | build:
12 | runs-on: ubuntu-latest
13 |
14 | steps:
15 | - uses: actions/checkout@v4
16 | - name: Set up JDK 21
17 | uses: actions/setup-java@v4
18 | with:
19 | distribution: 'zulu'
20 | java-version: '23'
21 |
22 | - name: Build with Maven
23 | run: mvn -B package --file pom.xml
24 |
25 | - name: Publish to GitHub Packages Apache Maven
26 | run: mvn deploy
27 | env:
28 | GITHUB_TOKEN: ${{ github.token }} # GITHUB_TOKEN is the default env for the password
29 |
30 | - name: Set up Apache Maven Central
31 | uses: actions/setup-java@v4
32 | with: # running setup-java again overwrites the settings.xml
33 | distribution: 'zulu'
34 | java-version: '23'
35 | server-id: maven # Value of the distributionManagement/repository/id field of the pom.xml
36 | server-username: MAVEN_USERNAME # env variable for username in deploy
37 | server-password: MAVEN_CENTRAL_TOKEN # env variable for token in deploy
38 | gpg-private-key: ${{ secrets.MAVEN_GPG_PRIVATE_KEY }} # Value of the GPG private key to import
39 | gpg-passphrase: MAVEN_GPG_PASSPHRASE # env variable for GPG private key passphrase
40 |
41 | - name: Publish to Apache Maven Central
42 | run: mvn deploy
43 | env:
44 | MAVEN_USERNAME: maven_username123
45 | MAVEN_CENTRAL_TOKEN: ${{ secrets.MAVEN_CENTRAL_TOKEN }}
46 | MAVEN_GPG_PASSPHRASE: ${{ secrets.MAVEN_GPG_PASSPHRASE }}
--------------------------------------------------------------------------------
/.gitignore:
--------------------------------------------------------------------------------
1 | /out/
2 | **/target/
3 | /lib/
4 | /.idea/shelf/
5 | /.idea/workspace.xml
6 | **/.DS_Store
7 | **/.flattened-pom.xml
8 |
--------------------------------------------------------------------------------
/.idea/FastDoubleParser.iml:
--------------------------------------------------------------------------------
1 |
2 |
3 |
4 |
5 |
6 |
7 |
8 |
9 |
--------------------------------------------------------------------------------
/.idea/codeStyles/codeStyleConfig.xml:
--------------------------------------------------------------------------------
1 |
2 |
3 |
4 |
5 |
--------------------------------------------------------------------------------
/.idea/copyright/MIT_License.xml:
--------------------------------------------------------------------------------
1 |
2 |
3 |
4 |
5 |
6 |
7 |
--------------------------------------------------------------------------------
/.idea/copyright/profiles_settings.xml:
--------------------------------------------------------------------------------
1 |
2 |
3 |
4 |
5 |
6 |
7 |
8 |
9 |
10 |
11 |
12 |
13 |
14 |
--------------------------------------------------------------------------------
/.idea/jarRepositories.xml:
--------------------------------------------------------------------------------
1 |
2 |
3 |
4 |
5 |
6 |
7 |
8 |
9 |
10 |
11 |
12 |
13 |
14 |
15 |
--------------------------------------------------------------------------------
/.idea/misc.xml:
--------------------------------------------------------------------------------
1 |
2 |
3 |
4 |
5 |
6 |
7 |
8 |
9 |
10 |
11 |
12 |
13 |
14 |
--------------------------------------------------------------------------------
/.idea/runConfigurations/Main_Dev__0_1_.xml:
--------------------------------------------------------------------------------
1 |
2 |
3 |
4 |
5 |
6 |
7 |
8 |
9 |
10 |
11 |
12 |
13 |
14 |
15 |
16 |
17 |
18 |
--------------------------------------------------------------------------------
/.idea/runConfigurations/Main_Dev_ar.xml:
--------------------------------------------------------------------------------
1 |
2 |
3 |
4 |
5 |
6 |
7 |
8 |
9 |
10 |
11 |
12 |
13 |
14 |
15 |
16 |
17 |
18 |
19 |
--------------------------------------------------------------------------------
/.idea/runConfigurations/Main_Dev_canada.xml:
--------------------------------------------------------------------------------
1 |
2 |
3 |
4 |
5 |
6 |
7 |
8 |
9 |
10 |
11 |
12 |
13 |
14 |
15 |
16 |
17 |
18 |
19 |
--------------------------------------------------------------------------------
/.idea/runConfigurations/Main_Dev_canada_hex.xml:
--------------------------------------------------------------------------------
1 |
2 |
3 |
4 |
5 |
6 |
7 |
8 |
9 |
10 |
11 |
12 |
13 |
14 |
15 |
16 |
17 |
18 |
--------------------------------------------------------------------------------
/.idea/runConfigurations/Main_Dev_mesh.xml:
--------------------------------------------------------------------------------
1 |
2 |
3 |
4 |
5 |
6 |
7 |
8 |
9 |
10 |
11 |
12 |
13 |
14 |
15 |
16 |
17 |
18 |
19 |
--------------------------------------------------------------------------------
/.idea/runConfigurations/Main_Java11__0_1_.xml:
--------------------------------------------------------------------------------
1 |
2 |
3 |
4 |
5 |
6 |
7 |
8 |
9 |
10 |
11 |
12 |
13 |
14 |
15 |
16 |
17 |
18 |
19 |
--------------------------------------------------------------------------------
/.idea/runConfigurations/Main_Java17__0_1_.xml:
--------------------------------------------------------------------------------
1 |
2 |
3 |
4 |
5 |
6 |
7 |
8 |
9 |
10 |
11 |
12 |
13 |
14 |
15 |
16 |
17 |
18 |
19 |
20 |
--------------------------------------------------------------------------------
/.idea/runConfigurations/Main_Java17_canada_hex.xml:
--------------------------------------------------------------------------------
1 |
2 |
3 |
4 |
5 |
6 |
7 |
8 |
9 |
10 |
11 |
12 |
13 |
14 |
15 |
16 |
17 |
18 |
19 |
--------------------------------------------------------------------------------
/.idea/runConfigurations/Main_Java23__0_1_.xml:
--------------------------------------------------------------------------------
1 |
2 |
3 |
4 |
5 |
6 |
7 |
8 |
9 |
10 |
11 |
12 |
13 |
14 |
15 |
16 |
17 |
18 |
--------------------------------------------------------------------------------
/.idea/runConfigurations/Main_Java8__0_1_.xml:
--------------------------------------------------------------------------------
1 |
2 |
3 |
4 |
5 |
6 |
7 |
8 |
9 |
10 |
11 |
12 |
13 |
14 |
15 |
16 |
17 |
18 |
19 |
--------------------------------------------------------------------------------
/.idea/vcs.xml:
--------------------------------------------------------------------------------
1 |
2 |
3 |
4 |
5 |
6 |
--------------------------------------------------------------------------------
/LICENSE:
--------------------------------------------------------------------------------
1 | MIT License
2 |
3 | Copyright (c) 2024 Werner Randelshofer, Switzerland.
4 |
5 | Permission is hereby granted, free of charge, to any person obtaining a copy
6 | of this software and associated documentation files (the "Software"), to deal
7 | in the Software without restriction, including without limitation the rights
8 | to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
9 | copies of the Software, and to permit persons to whom the Software is
10 | furnished to do so, subject to the following conditions:
11 |
12 | The above copyright notice and this permission notice shall be included in all
13 | copies or substantial portions of the Software.
14 |
15 | THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
16 | IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
17 | FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
18 | AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
19 | LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
20 | OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
21 | SOFTWARE.
22 |
--------------------------------------------------------------------------------
/NOTICE:
--------------------------------------------------------------------------------
1 | # FastDoubleParser
2 |
3 | This is a Java port of Daniel Lemire's fast_float project.
4 | This project provides parsers for double, float, BigDecimal and BigInteger values.
5 |
6 | ## Copyright
7 |
8 | Copyright © 2024 Werner Randelshofer, Switzerland.
9 |
10 | ## Licensing
11 |
12 | This code is licensed under MIT License.
13 | https://github.com/wrandelshofer/FastDoubleParser/blob/522be16e145f43308c43b23094e31d5efcaa580e/LICENSE
14 | (The file 'LICENSE' is included in the sources and classes Jar files that are released by this project
15 | - as is required by that license.)
16 |
17 | Some portions of the code have been derived from other projects.
18 | All these projects require that we include a copyright notice, and some require that we also include some text of their
19 | license file.
20 |
21 | fast_double_parser, Copyright (c) 2022 Daniel Lemire. BSL License.
22 | https://github.com/lemire/fast_double_parser
23 | https://github.com/lemire/fast_double_parser/blob/07d9189a8fb815fe800cb15ca022e7a07093236e/LICENSE.BSL
24 | (The file 'thirdparty-LICENSE' is included in the sources and classes Jar files that are released by this project
25 | - as is required by that license.)
26 |
27 | fast_float, Copyright (c) 2021 The fast_float authors. MIT License.
28 | https://github.com/fastfloat/fast_float
29 | https://github.com/fastfloat/fast_float/blob/cc1e01e9eee74128e48d51488a6b1df4a767a810/LICENSE-MIT
30 | (The file 'thirdparty-LICENSE' is included in the sources and classes Jar files that are released by this project
31 | - as is required by that license.)
32 |
33 | bigint, Copyright 2020 Tim Buktu. 2-clause BSD License.
34 | https://github.com/tbuktu/bigint/tree/floatfft
35 | https://github.com/tbuktu/bigint/blob/617c8cd8a7c5e4fb4d919c6a4d11e2586107f029/LICENSE
36 | https://github.com/wrandelshofer/FastDoubleParser/blob/39e123b15b71f29a38a087d16a0bc620fc879aa6/bigint-LICENSE
37 | (We only use those portions of the bigint project that can be licensed under 2-clause BSD License.)
38 | (The file 'thirdparty-LICENSE' is included in the sources and classes Jar files that are released by this project
39 | - as is required by that license.)
40 |
--------------------------------------------------------------------------------
/deployment/deployment.md:
--------------------------------------------------------------------------------
1 | # How to deploy to the nexus repository manager
2 |
3 | The nexus repository manager only accepts lower case character in the module name and in the version
4 | number.
5 |
6 | We deploy the following files:
7 |
8 | - fastdoubleparser/target/fastdoubleparser-x.y.z.jar
9 | - fastdoubleparser/target/fastdoubleparser-x.y.z-sources.jar
10 | - fastdoubleparser-java9/target/fastdoubleparser-java21-x.y.z-sources.jar
11 |
12 |
13 | All files must be signed with GPG. We create a bundle.jar file, which we then
14 | can upload to the nexus repository manager.
15 |
16 | ```shell
17 | cp ../fastdoubleparser/target/*.jar .
18 | cp ../fastdoubleparser-java23/target/*javadoc.jar fastdoubleparser-2.0.1-javadoc.jar
19 | rm -rf META-INF
20 | mkdir META-INF
21 | cp ../LICENSE META-INF
22 | cp ../fastdoubleparser-dev/src/main/resources/ch.randelshofer.fastdoubleparser/META-INF/thirdparty-LICENSE META-INF
23 | cp ../NOTICE META-INF
24 | jar -uf fastdoubleparser-2.0.1-javadoc.jar META-INF/*
25 | jar -uf fastdoubleparser-2.0.1-sources.jar META-INF/*
26 | rm *.asc
27 | for f in *.jar; do gpg -ab "$f"; done
28 | for f in *.xml; do gpg -ab "$f"; done
29 | rm *bundle.jar
30 | jar -cf fastdoubleparser-2.0.1-bundle.jar $(ls -1 pom*|xargs) $(ls -1 fastdoubleparser*|xargs)
31 | ```
32 |
--------------------------------------------------------------------------------
/deployment/pom.xml:
--------------------------------------------------------------------------------
1 |
2 |
3 | 4.0.0
4 | ch.randelshofer
5 | fastdoubleparser
6 | 2.0.1
7 | jar
8 |
9 | ch.randelshofer:fastdoubleparser
10 | A Java port of Daniel Lemire's fast_float project.
11 | https://github.com/wrandelshofer/FastDoubleParser
12 |
13 |
14 |
15 | MIT License
16 | https://github.com/wrandelshofer/FastDoubleParser/blob/9a3ccae38254c9bf84b5e6a218a47675bf80ed9f/LICENSE
17 | repo
18 |
19 |
20 |
21 |
22 |
23 | Werner Randelshofer
24 | werner.randelshofer@bluewin.ch
25 | ch.randelshofer
26 | http://www.randelshofer.ch
27 |
28 |
29 |
30 |
31 | scm:git:git://github.com/wrandelshofer/FastDoubleParser.git
32 | scm:git:ssh://github.com/wrandelshofer/FastDoubleParser.git
33 | https://github.com/wrandelshofer/FastDoubleParser/tree/master
34 |
35 |
36 |
37 |
38 |
--------------------------------------------------------------------------------
/fastdoubleparser-dev/pom.xml:
--------------------------------------------------------------------------------
1 |
2 |
4 | 4.0.0
5 |
6 | ch.randelshofer
7 | fastdoubleparser-parentproject
8 | ${revision}
9 |
10 | fastdoubleparser-dev
11 | jar
12 | fastdoubleparser-dev
13 |
14 | 23
15 | ${javaVersion}
16 | ${javaVersion}
17 | true
18 | true
19 | true
20 |
21 |
22 |
23 | ${basedir}/src/main/java/ch.randelshofer.fastdoubleparser
24 | ${basedir}/src/test/java/ch.randelshofer.fastdoubleparser
25 |
26 |
27 | ${basedir}/src/main/resources/ch.randelshofer.fastdoubleparser
28 |
29 |
30 |
31 |
32 | org.apache.maven.plugins
33 | maven-compiler-plugin
34 |
35 |
36 | -Xlint:all
37 |
38 |
39 |
40 |
41 |
42 | org.apache.maven.plugins
43 | maven-surefire-plugin
44 |
45 |
46 | -Xmx20g
47 | classesAndMethods
48 | 4
49 |
50 |
51 |
52 |
53 |
54 |
--------------------------------------------------------------------------------
/fastdoubleparser-dev/src/main/java/ch.randelshofer.fastdoubleparser/ch/randelshofer/fastdoubleparser/AbstractBigDecimalParser.java:
--------------------------------------------------------------------------------
1 | /*
2 | * @(#)AbstractBigDecimalParser.java
3 | * Copyright © 2024 Werner Randelshofer, Switzerland. MIT License.
4 | */
5 | package ch.randelshofer.fastdoubleparser;
6 |
7 | abstract class AbstractBigDecimalParser extends ch.randelshofer.fastdoubleparser.AbstractNumberParser {
8 |
9 | /**
10 | * Threshold on the number of input characters for selecting the
11 | * algorithm optimised for few digits in the significand vs. the algorithm for many
12 | * digits in the significand.
13 | *
14 | * Set this to {@link Integer#MAX_VALUE} if you only want to use
15 | * the algorithm optimised for few digits in the significand.
16 | *
17 | * Set this to {@code 0} if you only want to use the algorithm for
18 | * long inputs.
19 | *
20 | * Rationale for choosing a specific threshold value:
21 | * We speculate that we only need to use the algorithm for large inputs
22 | * if there is zero chance, that we can parse the input with the algorithm
23 | * for small inputs.
24 | *
25 | * optional significant sign = 1
26 | * 18 significant digits = 18
27 | * optional decimal point in significant = 1
28 | * optional exponent = 1
29 | * optional exponent sign = 1
30 | * 10 exponent digits = 10
31 | *
32 | */
33 | public static final int MANY_DIGITS_THRESHOLD = 1 + 18 + 1 + 1 + 1 + 10;
34 | /**
35 | * Threshold on the number of digits for selecting the
36 | * recursive algorithm instead of the iterative algorithm.
37 | *
38 | * Set this to {@link Integer#MAX_VALUE} if you only want to use the
39 | * iterative algorithm.
40 | *
41 | * Set this to {@code 0} if you only want to use the recursive algorithm.
42 | *
43 | * Rationale for choosing a specific threshold value:
44 | * The iterative algorithm has a smaller constant overhead than the
45 | * recursive algorithm. We speculate that we break even somewhere at twice
46 | * the threshold value.
47 | */
48 | static final int RECURSION_THRESHOLD = 400;
49 |
50 |
51 | protected final static long MAX_EXPONENT_NUMBER = Integer.MAX_VALUE;
52 | /**
53 | * See {@link JavaBigDecimalParser}.
54 | */
55 | protected final static int MAX_DIGITS_WITHOUT_LEADING_ZEROS = 646_456_993;
56 |
57 | protected static boolean hasManyDigits(int length) {
58 | return length >= MANY_DIGITS_THRESHOLD;
59 | }
60 |
61 | protected static void checkParsedBigDecimalBounds(boolean illegal, int index, int endIndex, int digitCount, long exponent) {
62 | if (illegal || index < endIndex) {
63 | throw new NumberFormatException(SYNTAX_ERROR);
64 | }
65 | if (exponent <= Integer.MIN_VALUE || exponent > Integer.MAX_VALUE || digitCount > MAX_DIGITS_WITHOUT_LEADING_ZEROS) {
66 | throw new NumberFormatException(VALUE_EXCEEDS_LIMITS);
67 | }
68 | }
69 | }
70 |
--------------------------------------------------------------------------------
/fastdoubleparser-dev/src/main/java/ch.randelshofer.fastdoubleparser/ch/randelshofer/fastdoubleparser/AbstractBigIntegerParser.java:
--------------------------------------------------------------------------------
1 | /*
2 | * @(#)AbstractBigIntegerParser.java
3 | * Copyright © 2024 Werner Randelshofer, Switzerland. MIT License.
4 | */
5 | package ch.randelshofer.fastdoubleparser;
6 |
7 | abstract class AbstractBigIntegerParser extends AbstractNumberParser {
8 |
9 | /**
10 | * The resulting value must fit into {@code 2^31 - 1} bits.
11 | * The decimal representation of {@code 2^31 - 1} bits has 646,456,993 digits.
12 | */
13 | private static final int MAX_DECIMAL_DIGITS = 646_456_993;
14 |
15 | /**
16 | * The resulting value must fit into {@code 2^31 - 1} bits.
17 | * The hexadecimal representation of {@code 2^31 - 1} bits has 536,870,912 digits.
18 | */
19 | private static final int MAX_HEX_DIGITS = 536_870_912;
20 | /**
21 | * Threshold on the number of digits for selecting the
22 | * recursive algorithm instead of the iterative algorithm.
23 | *
24 | * Set this to {@link Integer#MAX_VALUE} if you only want to use the
25 | * iterative algorithm.
26 | *
27 | * Set this to {@code 0} if you only want to use the recursive algorithm.
28 | *
29 | * Rationale for choosing a specific threshold value:
30 | * The iterative algorithm has a smaller constant overhead than the
31 | * recursive algorithm. We speculate that we break even somewhere at twice
32 | * the threshold value.
33 | */
34 | static final int RECURSION_THRESHOLD = 400;
35 |
36 | protected static boolean hasManyDigits(int length) {
37 | return length > 18;
38 | }
39 |
40 | protected static void checkHexBigIntegerBounds(int numDigits) {
41 | if (numDigits > MAX_HEX_DIGITS) {
42 | throw new NumberFormatException(AbstractNumberParser.VALUE_EXCEEDS_LIMITS);
43 | }
44 | }
45 |
46 | protected static void checkDecBigIntegerBounds(int numDigits) {
47 | if (numDigits > MAX_DECIMAL_DIGITS) {
48 | throw new NumberFormatException(AbstractNumberParser.VALUE_EXCEEDS_LIMITS);
49 | }
50 | }
51 | }
52 |
--------------------------------------------------------------------------------
/fastdoubleparser-dev/src/main/java/ch.randelshofer.fastdoubleparser/ch/randelshofer/fastdoubleparser/AbstractFloatValueParser.java:
--------------------------------------------------------------------------------
1 | /*
2 | * @(#)AbstractFloatValueParser.java
3 | * Copyright © 2024 Werner Randelshofer, Switzerland. MIT License.
4 | */
5 | package ch.randelshofer.fastdoubleparser;
6 |
7 | /**
8 | * Abstract base class for parsers that parse a {@code FloatingPointLiteral} from a
9 | * character sequence ({@code str}).
10 | *
11 | * This is a C++ to Java port of Daniel Lemire's fast_double_parser.
12 | *
13 | * References:
14 | *
15 | * Daniel Lemire, fast_float number parsing library: 4x faster than strtod.
16 | * MIT License .
17 | * github.com
18 | *
19 | * Daniel Lemire, Number Parsing at a Gigabyte per Second,
20 | * Software: Practice and Experience 51 (8), 2021.
21 | * arXiv.2101.11408v3 [cs.DS] 24 Feb 2021
22 | * arxiv.org
23 | *
24 | */
25 | abstract class AbstractFloatValueParser extends AbstractNumberParser {
26 | /**
27 | * This is the maximal input length that a Java array can have.
28 | */
29 | public final static int MAX_INPUT_LENGTH = Integer.MAX_VALUE - 4;
30 |
31 | /**
32 | * This is the smallest non-negative number that has 19 decimal digits.
33 | */
34 | final static long MINIMAL_NINETEEN_DIGIT_INTEGER = 1000_00000_00000_00000L;
35 |
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 |
43 | }
44 |
--------------------------------------------------------------------------------
/fastdoubleparser-dev/src/main/java/ch.randelshofer.fastdoubleparser/ch/randelshofer/fastdoubleparser/BigSignificand.java:
--------------------------------------------------------------------------------
1 | /*
2 | * @(#)BigSignificand.java
3 | * Copyright © 2024 Werner Randelshofer, Switzerland. MIT License.
4 | */
5 | package ch.randelshofer.fastdoubleparser;
6 |
7 | import java.lang.invoke.MethodHandles;
8 | import java.lang.invoke.VarHandle;
9 | import java.math.BigInteger;
10 | import java.nio.ByteOrder;
11 |
12 | /**
13 | * A mutable non-negative significand with a fixed number of bits.
14 | */
15 | final class BigSignificand {
16 | private static final long LONG_MASK = 0xffffffffL;
17 | private final static VarHandle readIntBE =
18 | MethodHandles.byteArrayViewVarHandle(int[].class, ByteOrder.BIG_ENDIAN);
19 | private final int numInts;
20 | private final byte[] x;
21 | private int firstNonZeroInt;
22 |
23 | /**
24 | * Creates a new instance with the specified number in bits.
25 | *
26 | * @param numBits the number of bits in range {@literal [0, Integer.MAX_VALUE)}.
27 | */
28 | public BigSignificand(long numBits) {
29 | if (numBits <= 0 || numBits >= Integer.MAX_VALUE) {
30 | throw new IllegalArgumentException("numBits=" + numBits);
31 | }
32 | int numLongs = (int) ((numBits + 63) >>> 6) + 1;
33 | numInts = numLongs << 1;
34 | int numBytes = numLongs << 3;
35 | x = new byte[numBytes];
36 | firstNonZeroInt = numInts;
37 | }
38 |
39 | /**
40 | * Adds the specified value to the significand in place.
41 | *
42 | * @param value the addend, must be a non-negative value
43 | * @throws ArrayIndexOutOfBoundsException on overflow
44 | */
45 | public void add(int value) {
46 | if (value == 0) {
47 | return;
48 | }
49 | long carry = value & LONG_MASK;
50 | int i = numInts - 1;
51 | for (; carry != 0; i--) {
52 | long sum = (x(i) & LONG_MASK) + carry;
53 | x(i, (int) sum);
54 | carry = sum >>> 32;
55 | }
56 | firstNonZeroInt = Math.min(firstNonZeroInt, i + 1);
57 | }
58 |
59 | /**
60 | * Multiplies the significand with the specified factor in place,
61 | * and then adds the specified addend to it (also in place).
62 | *
63 | * @param factor the multiplication factor, must be a non-negative value
64 | * @param addend the addend, must be a non-negative value
65 | * @throws ArrayIndexOutOfBoundsException on overflow
66 | */
67 | public void fma(int factor, int addend) {
68 | long factorL = factor & LONG_MASK;
69 | long carry = addend;
70 | int i = numInts - 1;
71 | for (; i >= firstNonZeroInt; i--) {
72 | long product = factorL * (x(i) & LONG_MASK) + carry;
73 | x(i, (int) product);
74 | carry = product >>> 32;
75 | }
76 | if (carry != 0) {
77 | x(i, (int) carry);
78 | firstNonZeroInt = i;
79 | }
80 | }
81 |
82 | /**
83 | * Converts the BigSignificand to a BigInteger.
84 | * @return a new BigInteger instance
85 | */
86 | public BigInteger toBigInteger() {
87 | return new BigInteger(x);
88 | }
89 |
90 | private void x(int i, int value) {
91 | readIntBE.set(x, i << 2, value);
92 | }
93 |
94 | private int x(int i) {
95 | return (int) readIntBE.get(x, i << 2);
96 | }
97 | }
98 |
--------------------------------------------------------------------------------
/fastdoubleparser-dev/src/main/java/ch.randelshofer.fastdoubleparser/ch/randelshofer/fastdoubleparser/ConfigurableDoubleBitsFromByteArrayAscii.java:
--------------------------------------------------------------------------------
1 | /*
2 | * @(#)ConfigurableDoubleBitsFromCharArray.java
3 | * Copyright © 2024 Werner Randelshofer, Switzerland. MIT License.
4 | */
5 | package ch.randelshofer.fastdoubleparser;
6 |
7 | /**
8 | * Parses a {@code double} from a {@code char[]} with configurable {@link NumberFormatSymbols}.
9 | */
10 | final class ConfigurableDoubleBitsFromByteArrayAscii extends AbstractConfigurableFloatingPointBitsFromByteArrayAscii {
11 | /**
12 | * Creates a new instance.
13 | */
14 | public ConfigurableDoubleBitsFromByteArrayAscii(NumberFormatSymbols symbols, boolean ignoreCase) {
15 | super(symbols, ignoreCase);
16 | }
17 |
18 | @Override
19 | long nan() {
20 | return Double.doubleToRawLongBits(Double.NaN);
21 | }
22 |
23 | @Override
24 | long negativeInfinity() {
25 | return Double.doubleToRawLongBits(Double.NEGATIVE_INFINITY);
26 | }
27 |
28 | @Override
29 | long positiveInfinity() {
30 | return Double.doubleToRawLongBits(Double.POSITIVE_INFINITY);
31 | }
32 | @Override
33 | long valueOfFloatLiteral(byte[] str, int integerStartIndex, int integerEndIndex, int fractionStartIndex, int fractionEndIndex, boolean isSignificandNegative,
34 | long significand, int exponent, boolean isSignificandTruncated,
35 | int exponentOfTruncatedSignificand, int exponentValue, int startIndex, int endIndex) {
36 | double d = FastDoubleMath.tryDecFloatToDoubleTruncated(isSignificandNegative, significand, exponent, isSignificandTruncated,
37 | exponentOfTruncatedSignificand);
38 | return Double.doubleToRawLongBits(Double.isNaN(d) ?
39 | slowPathToDouble(str, integerStartIndex, integerEndIndex, fractionStartIndex, fractionEndIndex, isSignificandNegative, exponentValue) :
40 | d);
41 | }
42 | }
--------------------------------------------------------------------------------
/fastdoubleparser-dev/src/main/java/ch.randelshofer.fastdoubleparser/ch/randelshofer/fastdoubleparser/ConfigurableDoubleBitsFromByteArrayUtf8.java:
--------------------------------------------------------------------------------
1 | /*
2 | * @(#)ConfigurableDoubleBitsFromCharArray.java
3 | * Copyright © 2024 Werner Randelshofer, Switzerland. MIT License.
4 | */
5 | package ch.randelshofer.fastdoubleparser;
6 |
7 | /**
8 | * Parses a {@code double} from a {@code char[]} with configurable {@link NumberFormatSymbols}.
9 | */
10 | final class ConfigurableDoubleBitsFromByteArrayUtf8 extends AbstractConfigurableFloatingPointBitsFromByteArrayUtf8 {
11 | /**
12 | * Creates a new instance.
13 | */
14 | public ConfigurableDoubleBitsFromByteArrayUtf8(NumberFormatSymbols symbols, boolean ignoreCase) {
15 | super(symbols, ignoreCase);
16 | }
17 |
18 | @Override
19 | long nan() {
20 | return Double.doubleToRawLongBits(Double.NaN);
21 | }
22 |
23 | @Override
24 | long negativeInfinity() {
25 | return Double.doubleToRawLongBits(Double.NEGATIVE_INFINITY);
26 | }
27 |
28 | @Override
29 | long positiveInfinity() {
30 | return Double.doubleToRawLongBits(Double.POSITIVE_INFINITY);
31 | }
32 |
33 | @Override
34 | long valueOfFloatLiteral(byte[] str, int integerStartIndex, int integerEndIndex, int fractionStartIndex, int fractionEndIndex, boolean isSignificandNegative,
35 | long significand, int exponent, boolean isSignificandTruncated,
36 | int exponentOfTruncatedSignificand, int exponentValue, int startIndex, int endIndex) {
37 | double d = FastDoubleMath.tryDecFloatToDoubleTruncated(isSignificandNegative, significand, exponent, isSignificandTruncated,
38 | exponentOfTruncatedSignificand);
39 | return Double.doubleToRawLongBits(Double.isNaN(d) ?
40 | slowPathToDouble(str, integerStartIndex, integerEndIndex, fractionStartIndex, fractionEndIndex, isSignificandNegative, exponentValue) :
41 | d);
42 | }
43 | }
--------------------------------------------------------------------------------
/fastdoubleparser-dev/src/main/java/ch.randelshofer.fastdoubleparser/ch/randelshofer/fastdoubleparser/ConfigurableDoubleBitsFromCharArray.java:
--------------------------------------------------------------------------------
1 | /*
2 | * @(#)ConfigurableDoubleBitsFromCharArray.java
3 | * Copyright © 2024 Werner Randelshofer, Switzerland. MIT License.
4 | */
5 | package ch.randelshofer.fastdoubleparser;
6 |
7 | /**
8 | * Parses a {@code double} from a {@code char[]} with configurable {@link NumberFormatSymbols}.
9 | */
10 | final class ConfigurableDoubleBitsFromCharArray extends AbstractConfigurableFloatingPointBitsFromCharArray {
11 | /**
12 | * Creates a new instance.
13 | */
14 | public ConfigurableDoubleBitsFromCharArray(NumberFormatSymbols symbols, boolean ignoreCase) {
15 | super(symbols, ignoreCase);
16 | }
17 |
18 | @Override
19 | long nan() {
20 | return Double.doubleToRawLongBits(Double.NaN);
21 | }
22 |
23 | @Override
24 | long negativeInfinity() {
25 | return Double.doubleToRawLongBits(Double.NEGATIVE_INFINITY);
26 | }
27 |
28 | @Override
29 | long positiveInfinity() {
30 | return Double.doubleToRawLongBits(Double.POSITIVE_INFINITY);
31 | }
32 | @Override
33 | long valueOfFloatLiteral(char[] str, int integerStartIndex, int integerEndIndex, int fractionStartIndex, int fractionEndIndex, boolean isSignificandNegative,
34 | long significand, int exponent, boolean isSignificandTruncated,
35 | int exponentOfTruncatedSignificand, int exponentValue, int startIndex, int endIndex) {
36 | double d = FastDoubleMath.tryDecFloatToDoubleTruncated(isSignificandNegative, significand, exponent, isSignificandTruncated,
37 | exponentOfTruncatedSignificand);
38 | return Double.doubleToRawLongBits(Double.isNaN(d) ?
39 | slowPathToDouble(str, integerStartIndex, integerEndIndex, fractionStartIndex, fractionEndIndex, isSignificandNegative, exponentValue) :
40 | d);
41 | }
42 | }
--------------------------------------------------------------------------------
/fastdoubleparser-dev/src/main/java/ch.randelshofer.fastdoubleparser/ch/randelshofer/fastdoubleparser/ConfigurableDoubleBitsFromCharSequence.java:
--------------------------------------------------------------------------------
1 | /*
2 | * @(#)ConfigurableDoubleBitsFromCharSequence.java
3 | * Copyright © 2024 Werner Randelshofer, Switzerland. MIT License.
4 | */
5 | package ch.randelshofer.fastdoubleparser;
6 |
7 | /**
8 | * Parses a {@code double} from a {@link CharSequence} with configurable {@link NumberFormatSymbols}.
9 | */
10 | final class ConfigurableDoubleBitsFromCharSequence extends AbstractConfigurableFloatingPointBitsFromCharSequence {
11 | /**
12 | * Creates a new instance.
13 | */
14 | public ConfigurableDoubleBitsFromCharSequence(NumberFormatSymbols symbols, boolean ignoreCase) {
15 | super(symbols, ignoreCase);
16 | }
17 |
18 | @Override
19 | long nan() {
20 | return Double.doubleToRawLongBits(Double.NaN);
21 | }
22 |
23 | @Override
24 | long negativeInfinity() {
25 | return Double.doubleToRawLongBits(Double.NEGATIVE_INFINITY);
26 | }
27 |
28 | @Override
29 | long positiveInfinity() {
30 | return Double.doubleToRawLongBits(Double.POSITIVE_INFINITY);
31 | }
32 |
33 | @Override
34 | long valueOfFloatLiteral(CharSequence str, int integerStartIndex, int integerEndIndex, int fractionStartIndex, int fractionEndIndex, boolean isSignificandNegative,
35 | long significand, int exponent, boolean isSignificandTruncated,
36 | int exponentOfTruncatedSignificand, int exponentValue, int startIndex, int endIndex) {
37 | double d = FastDoubleMath.tryDecFloatToDoubleTruncated(isSignificandNegative, significand, exponent, isSignificandTruncated,
38 | exponentOfTruncatedSignificand);
39 | return Double.doubleToRawLongBits(Double.isNaN(d) ?
40 | slowPathToDouble(str, integerStartIndex, integerEndIndex, fractionStartIndex, fractionEndIndex, isSignificandNegative, exponentValue) :
41 | d);
42 | }
43 |
44 | }
--------------------------------------------------------------------------------
/fastdoubleparser-dev/src/main/java/ch.randelshofer.fastdoubleparser/ch/randelshofer/fastdoubleparser/JavaDoubleBitsFromByteArray.java:
--------------------------------------------------------------------------------
1 | /*
2 | * @(#)JavaDoubleBitsFromByteArray.java
3 | * Copyright © 2024 Werner Randelshofer, Switzerland. MIT License.
4 | */
5 | package ch.randelshofer.fastdoubleparser;
6 |
7 | import java.nio.charset.StandardCharsets;
8 |
9 | /**
10 | * Parses a {@code double} from a {@code byte} array.
11 | */
12 | final class JavaDoubleBitsFromByteArray extends AbstractJavaFloatingPointBitsFromByteArray {
13 |
14 | /**
15 | * Creates a new instance.
16 | */
17 | public JavaDoubleBitsFromByteArray() {
18 |
19 | }
20 |
21 | @Override
22 | long nan() {
23 | return Double.doubleToRawLongBits(Double.NaN);
24 | }
25 |
26 | @Override
27 | long negativeInfinity() {
28 | return Double.doubleToRawLongBits(Double.NEGATIVE_INFINITY);
29 | }
30 |
31 | @Override
32 | long positiveInfinity() {
33 | return Double.doubleToRawLongBits(Double.POSITIVE_INFINITY);
34 | }
35 |
36 | @Override
37 | long valueOfFloatLiteral(byte[] str, int startIndex, int endIndex, boolean isNegative,
38 | long significand, int exponent, boolean isSignificandTruncated,
39 | int exponentOfTruncatedSignificand) {
40 | double d = FastDoubleMath.tryDecFloatToDoubleTruncated(isNegative, significand, exponent, isSignificandTruncated,
41 | exponentOfTruncatedSignificand);
42 | return Double.doubleToRawLongBits(Double.isNaN(d)
43 | // via Double.parseDouble
44 | ? Double.parseDouble(new String(str, startIndex, endIndex - startIndex, StandardCharsets.ISO_8859_1))
45 |
46 | // via BigDecimal
47 | // This only makes sense from JDK 21 onwards.
48 | // See fix for https://bugs.openjdk.org/browse/JDK-8205592
49 | // FIXME Only pass up to 764 significand digits to the BigDecimalParser
50 | // new JavaBigDecimalFromByteArray().valueOfBigDecimalString(str,integerPartIndex,decimalPointIndex,nonZeroFractionalPartIndex,exponentIndicatorIndex,isNegative,exponent).doubleValue()
51 | //? new JavaBigDecimalFromByteArray().parseBigDecimalString(str, startIndex, endIndex - startIndex).doubleValue()
52 |
53 | : d);
54 | }
55 |
56 | @Override
57 | long valueOfHexLiteral(
58 | byte[] str, int startIndex, int endIndex, boolean isNegative, long significand, int exponent,
59 | boolean isSignificandTruncated, int exponentOfTruncatedSignificand) {
60 | double d = FastDoubleMath.tryHexFloatToDoubleTruncated(isNegative, significand, exponent, isSignificandTruncated,
61 | exponentOfTruncatedSignificand);
62 | return Double.doubleToRawLongBits(Double.isNaN(d) ? Double.parseDouble(new String(str, startIndex, endIndex - startIndex, StandardCharsets.ISO_8859_1)) : d);
63 | }
64 | }
--------------------------------------------------------------------------------
/fastdoubleparser-dev/src/main/java/ch.randelshofer.fastdoubleparser/ch/randelshofer/fastdoubleparser/JavaDoubleBitsFromCharArray.java:
--------------------------------------------------------------------------------
1 | /*
2 | * @(#)JavaDoubleBitsFromCharArray.java
3 | * Copyright © 2024 Werner Randelshofer, Switzerland. MIT License.
4 | */
5 | package ch.randelshofer.fastdoubleparser;
6 |
7 | /**
8 | * Parses a {@code double} from a {@code char} array.
9 | */
10 | final class JavaDoubleBitsFromCharArray extends AbstractJavaFloatingPointBitsFromCharArray {
11 |
12 | /**
13 | * Creates a new instance.
14 | */
15 | public JavaDoubleBitsFromCharArray() {
16 |
17 | }
18 |
19 | @Override
20 | long nan() {
21 | return Double.doubleToRawLongBits(Double.NaN);
22 | }
23 |
24 | @Override
25 | long negativeInfinity() {
26 | return Double.doubleToRawLongBits(Double.NEGATIVE_INFINITY);
27 | }
28 |
29 | @Override
30 | long positiveInfinity() {
31 | return Double.doubleToRawLongBits(Double.POSITIVE_INFINITY);
32 | }
33 |
34 | @Override
35 | long valueOfFloatLiteral(char[] str, int startIndex, int endIndex, boolean isNegative,
36 | long significand, int exponent, boolean isSignificandTruncated,
37 | int exponentOfTruncatedSignificand) {
38 | double d = FastDoubleMath.tryDecFloatToDoubleTruncated(isNegative, significand, exponent, isSignificandTruncated,
39 | exponentOfTruncatedSignificand);
40 | return Double.doubleToRawLongBits(Double.isNaN(d) ? Double.parseDouble(new String(str, startIndex, endIndex - startIndex)) : d);
41 | }
42 |
43 | @Override
44 | long valueOfHexLiteral(
45 | char[] str, int startIndex, int endIndex, boolean isNegative, long significand, int exponent,
46 | boolean isSignificandTruncated, int exponentOfTruncatedSignificand) {
47 | double d = FastDoubleMath.tryHexFloatToDoubleTruncated(isNegative, significand, exponent, isSignificandTruncated,
48 | exponentOfTruncatedSignificand);
49 | return Double.doubleToRawLongBits(Double.isNaN(d) ? Double.parseDouble(new String(str, startIndex, endIndex - startIndex)) : d);
50 | }
51 | }
--------------------------------------------------------------------------------
/fastdoubleparser-dev/src/main/java/ch.randelshofer.fastdoubleparser/ch/randelshofer/fastdoubleparser/JavaDoubleBitsFromCharSequence.java:
--------------------------------------------------------------------------------
1 | /*
2 | * @(#)JavaDoubleBitsFromCharSequence.java
3 | * Copyright © 2024 Werner Randelshofer, Switzerland. MIT License.
4 | */
5 | package ch.randelshofer.fastdoubleparser;
6 |
7 | /**
8 | * Parses a {@code double} from a {@link CharSequence}.
9 | */
10 | final class JavaDoubleBitsFromCharSequence extends AbstractJavaFloatingPointBitsFromCharSequence {
11 |
12 | /**
13 | * Creates a new instance.
14 | */
15 | public JavaDoubleBitsFromCharSequence() {
16 |
17 | }
18 |
19 | @Override
20 | long nan() {
21 | return Double.doubleToRawLongBits(Double.NaN);
22 | }
23 |
24 | @Override
25 | long negativeInfinity() {
26 | return Double.doubleToRawLongBits(Double.NEGATIVE_INFINITY);
27 | }
28 |
29 | @Override
30 | long positiveInfinity() {
31 | return Double.doubleToRawLongBits(Double.POSITIVE_INFINITY);
32 | }
33 |
34 | @Override
35 | long valueOfFloatLiteral(CharSequence str, int startIndex, int endIndex, boolean isNegative,
36 | long significand, int exponent, boolean isSignificandTruncated,
37 | int exponentOfTruncatedSignificand) {
38 | double d = FastDoubleMath.tryDecFloatToDoubleTruncated(isNegative, significand, exponent, isSignificandTruncated,
39 | exponentOfTruncatedSignificand);
40 | return Double.doubleToRawLongBits(Double.isNaN(d)
41 | ? Double.parseDouble(str.subSequence(startIndex, endIndex).toString())
42 | : d);
43 | }
44 |
45 | @Override
46 | long valueOfHexLiteral(
47 | CharSequence str, int startIndex, int endIndex, boolean isNegative, long significand, int exponent,
48 | boolean isSignificandTruncated, int exponentOfTruncatedSignificand) {
49 | double d = FastDoubleMath.tryHexFloatToDoubleTruncated(isNegative, significand, exponent, isSignificandTruncated,
50 | exponentOfTruncatedSignificand);
51 | return Double.doubleToRawLongBits(Double.isNaN(d)
52 | ? Double.parseDouble(str.subSequence(startIndex, endIndex).toString())
53 | : d);
54 | }
55 | }
--------------------------------------------------------------------------------
/fastdoubleparser-dev/src/main/java/ch.randelshofer.fastdoubleparser/ch/randelshofer/fastdoubleparser/JavaFloatBitsFromByteArray.java:
--------------------------------------------------------------------------------
1 | /*
2 | * @(#)JavaFloatBitsFromByteArray.java
3 | * Copyright © 2024 Werner Randelshofer, Switzerland. MIT License.
4 | */
5 | package ch.randelshofer.fastdoubleparser;
6 |
7 | import java.nio.charset.StandardCharsets;
8 |
9 | /**
10 | * Parses a {@code float} from a {@code byte} array.
11 | */
12 | final class JavaFloatBitsFromByteArray extends AbstractJavaFloatingPointBitsFromByteArray {
13 |
14 |
15 | /**
16 | * Creates a new instance.
17 | */
18 | public JavaFloatBitsFromByteArray() {
19 |
20 | }
21 |
22 | @Override
23 | long nan() {
24 | return Float.floatToRawIntBits(Float.NaN);
25 | }
26 |
27 | @Override
28 | long negativeInfinity() {
29 | return Float.floatToRawIntBits(Float.NEGATIVE_INFINITY);
30 | }
31 |
32 | @Override
33 | long positiveInfinity() {
34 | return Float.floatToRawIntBits(Float.POSITIVE_INFINITY);
35 | }
36 |
37 | @Override
38 | long valueOfFloatLiteral(byte[] str, int startIndex, int endIndex, boolean isNegative,
39 | long significand, int exponent, boolean isSignificandTruncated,
40 | int exponentOfTruncatedSignificand) {
41 | float result = FastFloatMath.tryDecFloatToFloatTruncated(isNegative, significand, exponent, isSignificandTruncated, exponentOfTruncatedSignificand);
42 | return Float.floatToRawIntBits(Float.isNaN(result) ? Float.parseFloat(
43 | new String(str, startIndex, endIndex - startIndex, StandardCharsets.ISO_8859_1)) : result);
44 | }
45 |
46 | @Override
47 | long valueOfHexLiteral(
48 | byte[] str, int startIndex, int endIndex, boolean isNegative, long significand, int exponent,
49 | boolean isSignificandTruncated, int exponentOfTruncatedSignificand) {
50 | float d = FastFloatMath.tryHexFloatToFloatTruncated(isNegative, significand, exponent, isSignificandTruncated, exponentOfTruncatedSignificand);
51 | return Float.floatToRawIntBits(Float.isNaN(d) ? Float.parseFloat(new String(str, startIndex, endIndex - startIndex, StandardCharsets.ISO_8859_1)) : d);
52 | }
53 |
54 | }
--------------------------------------------------------------------------------
/fastdoubleparser-dev/src/main/java/ch.randelshofer.fastdoubleparser/ch/randelshofer/fastdoubleparser/JavaFloatBitsFromCharArray.java:
--------------------------------------------------------------------------------
1 | /*
2 | * @(#)JavaFloatBitsFromCharArray.java
3 | * Copyright © 2024 Werner Randelshofer, Switzerland. MIT License.
4 | */
5 | package ch.randelshofer.fastdoubleparser;
6 |
7 | /**
8 | * Parses a {@code float} from a {@code char} array.
9 | */
10 | final class JavaFloatBitsFromCharArray extends AbstractJavaFloatingPointBitsFromCharArray {
11 |
12 |
13 | /**
14 | * Creates a new instance.
15 | */
16 | public JavaFloatBitsFromCharArray() {
17 |
18 | }
19 |
20 | @Override
21 | long nan() {
22 | return Float.floatToRawIntBits(Float.NaN);
23 | }
24 |
25 | @Override
26 | long negativeInfinity() {
27 | return Float.floatToRawIntBits(Float.NEGATIVE_INFINITY);
28 | }
29 |
30 | @Override
31 | long positiveInfinity() {
32 | return Float.floatToRawIntBits(Float.POSITIVE_INFINITY);
33 | }
34 |
35 | @Override
36 | long valueOfFloatLiteral(char[] str, int startIndex, int endIndex, boolean isNegative,
37 | long significand, int exponent, boolean isSignificandTruncated,
38 | int exponentOfTruncatedSignificand) {
39 | float result = FastFloatMath.tryDecFloatToFloatTruncated(isNegative, significand, exponent, isSignificandTruncated, exponentOfTruncatedSignificand);
40 | return Float.isNaN(result) ? (long) Float.floatToRawIntBits(Float.parseFloat(new String(str, startIndex, endIndex - startIndex))) : Float.floatToRawIntBits(result);
41 | }
42 |
43 | @Override
44 | long valueOfHexLiteral(
45 | char[] str, int startIndex, int endIndex, boolean isNegative, long significand, int exponent,
46 | boolean isSignificandTruncated, int exponentOfTruncatedSignificand) {
47 | float d = FastFloatMath.tryHexFloatToFloatTruncated(isNegative, significand, exponent, isSignificandTruncated, exponentOfTruncatedSignificand);
48 | return Float.floatToRawIntBits(Float.isNaN(d) ? Float.parseFloat(new String(str, startIndex, endIndex - startIndex)) : d);
49 | }
50 | }
--------------------------------------------------------------------------------
/fastdoubleparser-dev/src/main/java/ch.randelshofer.fastdoubleparser/ch/randelshofer/fastdoubleparser/JavaFloatBitsFromCharSequence.java:
--------------------------------------------------------------------------------
1 | /*
2 | * @(#)JavaFloatBitsFromCharSequence.java
3 | * Copyright © 2024 Werner Randelshofer, Switzerland. MIT License.
4 | */
5 | package ch.randelshofer.fastdoubleparser;
6 |
7 | /**
8 | * Parses a {@code float} from a {@link CharSequence}.
9 | */
10 | final class JavaFloatBitsFromCharSequence extends AbstractJavaFloatingPointBitsFromCharSequence {
11 |
12 |
13 | /**
14 | * Creates a new instance.
15 | */
16 | public JavaFloatBitsFromCharSequence() {
17 |
18 | }
19 |
20 | @Override
21 | long nan() {
22 | return Float.floatToRawIntBits(Float.NaN);
23 | }
24 |
25 | @Override
26 | long negativeInfinity() {
27 | return Float.floatToRawIntBits(Float.NEGATIVE_INFINITY);
28 | }
29 |
30 | @Override
31 | long positiveInfinity() {
32 | return Float.floatToRawIntBits(Float.POSITIVE_INFINITY);
33 | }
34 |
35 | @Override
36 | long valueOfFloatLiteral(CharSequence str, int startIndex, int endIndex, boolean isNegative,
37 | long significand, int exponent, boolean isSignificandTruncated,
38 | int exponentOfTruncatedSignificand) {
39 | float d = FastFloatMath.tryDecFloatToFloatTruncated(isNegative, significand, exponent, isSignificandTruncated, exponentOfTruncatedSignificand);
40 | return Float.floatToRawIntBits(Float.isNaN(d) ? Float.parseFloat(str.subSequence(startIndex, endIndex).toString()) : d);
41 | }
42 |
43 | @Override
44 | long valueOfHexLiteral(
45 | CharSequence str, int startIndex, int endIndex, boolean isNegative, long significand, int exponent,
46 | boolean isSignificandTruncated, int exponentOfTruncatedSignificand) {
47 | float d = FastFloatMath.tryHexFloatToFloatTruncated(isNegative, significand, exponent, isSignificandTruncated, exponentOfTruncatedSignificand);
48 | return Float.floatToRawIntBits(Float.isNaN(d) ? Float.parseFloat(str.subSequence(startIndex, endIndex).toString()) : d);
49 | }
50 |
51 | }
--------------------------------------------------------------------------------
/fastdoubleparser-dev/src/main/java/ch.randelshofer.fastdoubleparser/ch/randelshofer/fastdoubleparser/JsonDoubleBitsFromByteArray.java:
--------------------------------------------------------------------------------
1 | /*
2 | * @(#)JsonDoubleBitsFromByteArray.java
3 | * Copyright © 2024 Werner Randelshofer, Switzerland. MIT License.
4 | */
5 | package ch.randelshofer.fastdoubleparser;
6 |
7 | import java.nio.charset.StandardCharsets;
8 |
9 | /**
10 | * Parses a {@code double} from a {@code byte} array.
11 | */
12 | final class JsonDoubleBitsFromByteArray extends AbstractJsonFloatingPointBitsFromByteArray {
13 |
14 | /**
15 | * Creates a new instance.
16 | */
17 | public JsonDoubleBitsFromByteArray() {
18 |
19 | }
20 |
21 | @Override
22 | long valueOfFloatLiteral(byte[] str, int startIndex, int endIndex, boolean isNegative,
23 | long significand, int exponent, boolean isSignificandTruncated,
24 | int exponentOfTruncatedSignificand) {
25 | double d = FastDoubleMath.tryDecFloatToDoubleTruncated(isNegative, significand, exponent, isSignificandTruncated,
26 | exponentOfTruncatedSignificand);
27 | return Double.doubleToRawLongBits(Double.isNaN(d) ? Double.parseDouble(new String(str, startIndex, endIndex - startIndex, StandardCharsets.ISO_8859_1)) : d);
28 | }
29 | }
--------------------------------------------------------------------------------
/fastdoubleparser-dev/src/main/java/ch.randelshofer.fastdoubleparser/ch/randelshofer/fastdoubleparser/JsonDoubleBitsFromCharArray.java:
--------------------------------------------------------------------------------
1 | /*
2 | * @(#)JsonDoubleBitsFromCharArray.java
3 | * Copyright © 2024 Werner Randelshofer, Switzerland. MIT License.
4 | */
5 | package ch.randelshofer.fastdoubleparser;
6 |
7 | /**
8 | * Parses a {@code double} from a {@code char} array.
9 | */
10 | final class JsonDoubleBitsFromCharArray extends AbstractJsonFloatingPointBitsFromCharArray {
11 |
12 | /**
13 | * Creates a new instance.
14 | */
15 | public JsonDoubleBitsFromCharArray() {
16 |
17 | }
18 |
19 | @Override
20 | long valueOfFloatLiteral(char[] str, int startIndex, int endIndex, boolean isNegative,
21 | long significand, int exponent, boolean isSignificandTruncated,
22 | int exponentOfTruncatedSignificand) {
23 | double d = FastDoubleMath.tryDecFloatToDoubleTruncated(isNegative, significand, exponent, isSignificandTruncated,
24 | exponentOfTruncatedSignificand);
25 | return Double.doubleToRawLongBits(Double.isNaN(d) ? Double.parseDouble(new String(str, startIndex, endIndex - startIndex)) : d);
26 | }
27 | }
--------------------------------------------------------------------------------
/fastdoubleparser-dev/src/main/java/ch.randelshofer.fastdoubleparser/ch/randelshofer/fastdoubleparser/JsonDoubleBitsFromCharSequence.java:
--------------------------------------------------------------------------------
1 | /*
2 | * @(#)JsonDoubleBitsFromCharSequence.java
3 | * Copyright © 2024 Werner Randelshofer, Switzerland. MIT License.
4 | */
5 | package ch.randelshofer.fastdoubleparser;
6 |
7 | /**
8 | * Parses a {@code double} from a {@link CharSequence}.
9 | */
10 | final class JsonDoubleBitsFromCharSequence extends AbstractJsonFloatingPointBitsFromCharSequence {
11 |
12 | /**
13 | * Creates a new instance.
14 | */
15 | public JsonDoubleBitsFromCharSequence() {
16 |
17 | }
18 |
19 | @Override
20 | long valueOfFloatLiteral(CharSequence str, int startIndex, int endIndex, boolean isNegative,
21 | long significand, int exponent, boolean isSignificandTruncated,
22 | int exponentOfTruncatedSignificand) {
23 | double d = FastDoubleMath.tryDecFloatToDoubleTruncated(isNegative, significand, exponent, isSignificandTruncated,
24 | exponentOfTruncatedSignificand);
25 | return Double.doubleToRawLongBits(Double.isNaN(d) ? Double.parseDouble(str.subSequence(startIndex, endIndex).toString()) : d);
26 | }
27 | }
--------------------------------------------------------------------------------
/fastdoubleparser-dev/src/main/java/ch.randelshofer.fastdoubleparser/ch/randelshofer/fastdoubleparser/ParseDigitsTaskByteArray.java:
--------------------------------------------------------------------------------
1 | /*
2 | * @(#)ParseDigitsTaskByteArray.java
3 | * Copyright © 2024 Werner Randelshofer, Switzerland. MIT License.
4 | */
5 | package ch.randelshofer.fastdoubleparser;
6 |
7 | import java.math.BigInteger;
8 | import java.util.Map;
9 |
10 | import static ch.randelshofer.fastdoubleparser.AbstractNumberParser.SYNTAX_ERROR;
11 | import static ch.randelshofer.fastdoubleparser.FastIntegerMath.splitFloor16;
12 |
13 | /**
14 | * Parses digits.
15 | */
16 | final class ParseDigitsTaskByteArray {
17 | /**
18 | * Don't let anyone instantiate this class.
19 | */
20 | private ParseDigitsTaskByteArray() {
21 | }
22 |
23 |
24 | /**
25 | * Parses digits in quadratic time O(N2 ).
26 | */
27 | static BigInteger parseDigitsIterative(byte[] str, int from, int to) {
28 | assert str != null : "str==null";
29 |
30 | int numDigits = to - from;
31 |
32 | BigSignificand bigSignificand = new BigSignificand(FastIntegerMath.estimateNumBits(numDigits));
33 | int preroll = from + (numDigits & 7);
34 | int value = FastDoubleSwar.tryToParseUpTo7Digits(str, from, preroll);
35 | boolean success = value >= 0;
36 | bigSignificand.add(value);
37 | for (from = preroll; from < to; from += 8) {
38 | int addend = FastDoubleSwar.tryToParseEightDigits(str, from);
39 | success &= addend >= 0;
40 | bigSignificand.fma(100_000_000, addend);
41 | }
42 | if (!success) {
43 | throw new NumberFormatException(SYNTAX_ERROR);
44 | }
45 | return bigSignificand.toBigInteger();
46 | }
47 |
48 | /**
49 | * Parses digits in O(N log N (log log N)) time.
50 | *
51 | * A conventional recursive algorithm would require O(N1.5 ).
52 | * We achieve better performance by performing multiplications of long bit sequences
53 | * in the frequency domain using {@link FftMultiplier}.
54 | */
55 | static BigInteger parseDigitsRecursive(byte[] str, int from, int to, Map powersOfTen, int recursionThreshold) {
56 | assert str != null : "str==null";
57 | assert powersOfTen != null : "powersOfTen==null";
58 |
59 | int numDigits = to - from;
60 |
61 | // Base case: Short sequences can be parsed iteratively.
62 | if (numDigits <= recursionThreshold) {
63 | return parseDigitsIterative(str, from, to);
64 | }
65 |
66 | // Recursion case: Split large sequences up into two parts. The lower part is a multiple of 16 digits.
67 | int mid = splitFloor16(from, to);
68 | BigInteger high = parseDigitsRecursive(str, from, mid, powersOfTen, recursionThreshold);
69 | BigInteger low = parseDigitsRecursive(str, mid, to, powersOfTen, recursionThreshold);
70 |
71 | //high = high.multiply(powersOfTen.get(to - mid));
72 | high = FftMultiplier.multiply(high, powersOfTen.get(to - mid));
73 | return low.add(high);
74 | }
75 | }
76 |
--------------------------------------------------------------------------------
/fastdoubleparser-dev/src/main/java/ch.randelshofer.fastdoubleparser/ch/randelshofer/fastdoubleparser/ParseDigitsTaskCharArray.java:
--------------------------------------------------------------------------------
1 | /*
2 | * @(#)ParseDigitsTaskCharArray.java
3 | * Copyright © 2024 Werner Randelshofer, Switzerland. MIT License.
4 | */
5 | package ch.randelshofer.fastdoubleparser;
6 |
7 | import java.math.BigInteger;
8 | import java.util.Map;
9 |
10 | import static ch.randelshofer.fastdoubleparser.AbstractNumberParser.SYNTAX_ERROR;
11 | import static ch.randelshofer.fastdoubleparser.FastIntegerMath.splitFloor16;
12 |
13 | /**
14 | * Parses digits.
15 | */
16 | final class ParseDigitsTaskCharArray {
17 | /**
18 | * Don't let anyone instantiate this class.
19 | */
20 | private ParseDigitsTaskCharArray() {
21 | }
22 |
23 |
24 | /**
25 | * Parses digits in quadratic time O(N2 ).
26 | */
27 | static BigInteger parseDigitsIterative(char[] str, int from, int to) {
28 | assert str != null : "str==null";
29 |
30 | int numDigits = to - from;
31 |
32 | BigSignificand bigSignificand = new BigSignificand(FastIntegerMath.estimateNumBits(numDigits));
33 | int preroll = from + (numDigits & 7);
34 | int value = FastDoubleSwar.tryToParseUpTo7Digits(str, from, preroll);
35 | boolean success = value >= 0;
36 | bigSignificand.add(value);
37 | for (from = preroll; from < to; from += 8) {
38 | int addend = FastDoubleSwar.tryToParseEightDigits(str, from);
39 | success &= addend >= 0;
40 | bigSignificand.fma(100_000_000, addend);
41 | }
42 | if (!success) {
43 | throw new NumberFormatException(SYNTAX_ERROR);
44 | }
45 | return bigSignificand.toBigInteger();
46 | }
47 |
48 | /**
49 | * Parses digits in O(N log N (log log N)) time.
50 | *
51 | * A conventional recursive algorithm would require O(N1.5 ).
52 | * We achieve better performance by performing multiplications of long bit sequences
53 | * in the frequency domain.
54 | */
55 | static BigInteger parseDigitsRecursive(char[] str, int from, int to, Map powersOfTen, int recursionThreshold) {
56 | assert str != null : "str==null";
57 | assert powersOfTen != null : "powersOfTen==null";
58 |
59 | int numDigits = to - from;
60 |
61 | // Base case: Short sequences can be parsed iteratively.
62 | if (numDigits <= recursionThreshold) {
63 | return parseDigitsIterative(str, from, to);
64 | }
65 |
66 | // Recursion case: Split large sequences up into two parts. The lower part is a multiple of 16 digits.
67 | int mid = splitFloor16(from, to);
68 | BigInteger high = parseDigitsRecursive(str, from, mid, powersOfTen, recursionThreshold);
69 | BigInteger low = parseDigitsRecursive(str, mid, to, powersOfTen, recursionThreshold);
70 |
71 | high = FftMultiplier.multiply(high, powersOfTen.get(to - mid));
72 | return low.add(high);
73 | }
74 | }
75 |
--------------------------------------------------------------------------------
/fastdoubleparser-dev/src/main/java/ch.randelshofer.fastdoubleparser/ch/randelshofer/fastdoubleparser/ParseDigitsTaskCharSequence.java:
--------------------------------------------------------------------------------
1 | /*
2 | * @(#)ParseDigitsTaskCharSequence.java
3 | * Copyright © 2024 Werner Randelshofer, Switzerland. MIT License.
4 | */
5 | package ch.randelshofer.fastdoubleparser;
6 |
7 | import java.math.BigInteger;
8 | import java.util.Map;
9 |
10 | import static ch.randelshofer.fastdoubleparser.AbstractNumberParser.SYNTAX_ERROR;
11 | import static ch.randelshofer.fastdoubleparser.FastIntegerMath.splitFloor16;
12 |
13 | /**
14 | * Parses digits.
15 | */
16 | final class ParseDigitsTaskCharSequence {
17 | /**
18 | * Don't let anyone instantiate this class.
19 | */
20 | private ParseDigitsTaskCharSequence() {
21 | }
22 |
23 |
24 |
25 | /**
26 | * Parses digits in quadratic time O(N2 ).
27 | */
28 | static BigInteger parseDigitsIterative(CharSequence str, int from, int to) {
29 | assert str != null : "str==null";
30 |
31 | int numDigits = to - from;
32 |
33 | BigSignificand bigSignificand = new BigSignificand(FastIntegerMath.estimateNumBits(numDigits));
34 | int preroll = from + (numDigits & 7);
35 | int value = FastDoubleSwar.tryToParseUpTo7Digits(str, from, preroll);
36 | boolean success = value >= 0;
37 | bigSignificand.add(value);
38 | for (from = preroll; from < to; from += 8) {
39 | int addend = FastDoubleSwar.tryToParseEightDigits(str, from);
40 | success &= addend >= 0;
41 | bigSignificand.fma(100_000_000, addend);
42 | }
43 | if (!success) {
44 | throw new NumberFormatException(SYNTAX_ERROR);
45 | }
46 | return bigSignificand.toBigInteger();
47 | }
48 |
49 | /**
50 | * Parses digits in O(N log N (log log N)) time.
51 | *
52 | * A conventional recursive algorithm would require O(N1.5 ).
53 | * We achieve better performance by performing multiplications of long bit sequences
54 | * in the frequency domain.
55 | */
56 | static BigInteger parseDigitsRecursive(CharSequence str, int from, int to, Map powersOfTen, int recursionThreshold) {
57 | assert str != null : "str==null";
58 | assert powersOfTen != null : "powersOfTen==null";
59 |
60 | // Base case: All sequences of 18 or fewer digits fit into a long.
61 | int numDigits = to - from;
62 |
63 | // Base case: Short sequences can be parsed iteratively.
64 | if (numDigits <= recursionThreshold) {
65 | return parseDigitsIterative(str, from, to);
66 | }
67 |
68 | // Recursion case: Split large sequences up into two parts. The lower part is a multiple of 16 digits.
69 | int mid = splitFloor16(from, to);
70 | BigInteger high = parseDigitsRecursive(str, from, mid, powersOfTen, recursionThreshold);
71 | BigInteger low = parseDigitsRecursive(str, mid, to, powersOfTen, recursionThreshold);
72 |
73 | //high = high.multiply(powersOfTen.get(to - mid));
74 | high = FftMultiplier.multiply(high, powersOfTen.get(to - mid));
75 | return low.add(high);
76 | }
77 | }
78 |
--------------------------------------------------------------------------------
/fastdoubleparser-dev/src/main/java/ch.randelshofer.fastdoubleparser/ch/randelshofer/fastdoubleparser/bte/ByteDigitSet.java:
--------------------------------------------------------------------------------
1 | /*
2 | * @(#)ByteDigitSet.java
3 | * Copyright © 2024 Werner Randelshofer, Switzerland. MIT License.
4 | */
5 | package ch.randelshofer.fastdoubleparser.bte;
6 |
7 | import java.util.List;
8 |
9 | /**
10 | * Interface for sets of digit bytes.
11 | */
12 | public interface ByteDigitSet {
13 | /**
14 | * Returns a value in the range 0 to 9 if the specified character is a digit.
15 | * Otherwise, Returns a value greater than 9.
16 | *
17 | * @param ch a character
18 | * @return a value in the range 0 to Integer.MAX_VALUE.
19 | */
20 | int toDigit(byte ch);
21 |
22 | /**
23 | * Creates a new {@link ByteDigitSet} instead from the
24 | * specified list.
25 | *
26 | * The list must contain characters for the digits 0 to 9.
27 | *
28 | * @param digits a list of digit characters
29 | * @return a new {@link ByteDigitSet} instance
30 | */
31 | @SuppressWarnings("SequencedCollectionMethodCanBeUsed")
32 | static ByteDigitSet copyOf(List digits) {
33 | boolean consecutive = true;
34 | char zeroDigit = digits.get(0);
35 | for (int i = 1; i < 10; i++) {
36 | char current = digits.get(i);
37 | consecutive &= current == zeroDigit + i;
38 | }
39 | return consecutive ?
40 | new ConsecutiveByteDigitSet(digits.get(0)) :
41 | new ByteToIntMap(digits);
42 | }
43 | }
44 |
--------------------------------------------------------------------------------
/fastdoubleparser-dev/src/main/java/ch.randelshofer.fastdoubleparser/ch/randelshofer/fastdoubleparser/bte/ByteSet.java:
--------------------------------------------------------------------------------
1 | /*
2 | * @(#)ByteSet.java
3 | * Copyright © 2024 Werner Randelshofer, Switzerland. MIT License.
4 | */
5 | package ch.randelshofer.fastdoubleparser.bte;
6 |
7 | import java.util.LinkedHashSet;
8 | import java.util.Set;
9 |
10 | /**
11 | * Interface for sets of bytes.
12 | */
13 | public interface ByteSet {
14 | /**
15 | * Returns true if the set contains the specified byte.
16 | *
17 | * @param b a byte
18 | * @return true if the byte is in the set
19 | */
20 | boolean containsKey(byte b);
21 |
22 | /**
23 | * Creates a new {@link ByteSet} from the provided set.
24 | *
25 | * @param set a set of characters
26 | * @param ignoreCase whether the {@link ByteSet} shall ignore the
27 | * case of the characters
28 | * @return a new {@link ByteSet} instance
29 | */
30 | static ByteSet copyOf(Set set, boolean ignoreCase) {
31 | set = applyIgnoreCase(set, ignoreCase);
32 | switch (set.size()) {
33 | case 0:
34 | return new ByteSetOfNone();
35 | case 1:
36 | return new ByteSetOfOne(set);
37 | default:
38 | return set.size() < 5 ? new ByteSetOfFew(set) : new ByteToIntMap(set);
39 | }
40 | }
41 |
42 | /**
43 | * Creates a copy of the provided set, or returns the same set.
44 | *
45 | * If {@code ignoreCase} is set to true, the copy will contain
46 | * an upper and lower case character for each character in the provided
47 | * set.
48 | *
49 | * @param set a set of characters
50 | * @param ignoreCase whether the copy of the set shall contain
51 | * upper and lower case characters from the
52 | * provided set
53 | * @return a new set if {@code ignoreCase} is false, otherwise a copy of the set
54 | */
55 | static Set applyIgnoreCase(Set set, boolean ignoreCase) {
56 | if (ignoreCase) {
57 | LinkedHashSet convertedSet = new LinkedHashSet();
58 | for (Character ch : set) {
59 | // Add the original input char.
60 | convertedSet.add(ch);
61 |
62 | // Convert to lower case. This does not cover all cases.
63 | char lc = Character.toLowerCase(ch);
64 |
65 | // We have to convert to upper case and then to lower case
66 | // because of sophisticated writing systems, like Georgian script.
67 | char uc = Character.toUpperCase(ch);
68 | char uclc = Character.toLowerCase(uc);
69 |
70 | convertedSet.add(lc);
71 | convertedSet.add(uc);
72 | convertedSet.add(uclc);
73 | }
74 | set = convertedSet;
75 | }
76 | return set;
77 | }
78 |
79 |
80 | }
81 |
--------------------------------------------------------------------------------
/fastdoubleparser-dev/src/main/java/ch.randelshofer.fastdoubleparser/ch/randelshofer/fastdoubleparser/bte/ByteSetOfFew.java:
--------------------------------------------------------------------------------
1 | /*
2 | * @(#)ByteSetOfFew.java
3 | * Copyright © 2024 Werner Randelshofer, Switzerland. MIT License.
4 | */
5 | package ch.randelshofer.fastdoubleparser.bte;
6 |
7 | import java.nio.charset.StandardCharsets;
8 | import java.util.Arrays;
9 | import java.util.Set;
10 |
11 | /**
12 | * A set of {@code char} with linear search.
13 | */
14 | final class ByteSetOfFew implements ByteSet {
15 | private final byte[] bytes;
16 |
17 | public ByteSetOfFew(Set set) {
18 | byte[] tmp = new byte[set.size() * 4];
19 | int i = 0;
20 | for (char ch : set) {
21 | for (byte b : String.valueOf(ch).getBytes(StandardCharsets.UTF_8)) {
22 | tmp[i++] = b;
23 | }
24 | }
25 | this.bytes = Arrays.copyOf(tmp, i);
26 | }
27 |
28 | public boolean containsKey(byte b) {
29 | boolean found = false;
30 | for (byte aChar : bytes) {
31 | found |= aChar == b;
32 | }
33 | return found;
34 | }
35 | }
36 |
--------------------------------------------------------------------------------
/fastdoubleparser-dev/src/main/java/ch.randelshofer.fastdoubleparser/ch/randelshofer/fastdoubleparser/bte/ByteSetOfNone.java:
--------------------------------------------------------------------------------
1 | /*
2 | * @(#)ByteSetOfNone.java
3 | * Copyright © 2024 Werner Randelshofer, Switzerland. MIT License.
4 | */
5 | package ch.randelshofer.fastdoubleparser.bte;
6 |
7 | final class ByteSetOfNone implements ByteSet {
8 |
9 | ByteSetOfNone() {
10 | }
11 |
12 | public boolean containsKey(byte b) {
13 | return false;
14 | }
15 | }
16 |
--------------------------------------------------------------------------------
/fastdoubleparser-dev/src/main/java/ch.randelshofer.fastdoubleparser/ch/randelshofer/fastdoubleparser/bte/ByteSetOfOne.java:
--------------------------------------------------------------------------------
1 | /*
2 | * @(#)ByteSetOfOne.java
3 | * Copyright © 2024 Werner Randelshofer, Switzerland. MIT License.
4 | */
5 | package ch.randelshofer.fastdoubleparser.bte;
6 |
7 | import java.util.Set;
8 |
9 | final class ByteSetOfOne implements ByteSet {
10 | private final byte ch;
11 |
12 | ByteSetOfOne(Set set) {
13 | if (set.size() != 1) throw new IllegalArgumentException("set size must be 1, size=" + set.size());
14 | char ch = set.iterator().next();
15 | if (ch > 127)
16 | throw new IllegalArgumentException("can not map to a single byte. ch='" + ch + "' 0x" + Integer.toHexString(ch));
17 | this.ch = (byte) ch;
18 | }
19 |
20 | @Override
21 | public boolean containsKey(byte b) {
22 | return this.ch == b;
23 | }
24 | }
25 |
--------------------------------------------------------------------------------
/fastdoubleparser-dev/src/main/java/ch.randelshofer.fastdoubleparser/ch/randelshofer/fastdoubleparser/bte/ByteToIntMap.java:
--------------------------------------------------------------------------------
1 | /*
2 | * @(#)ByteToIntMap.java
3 | * Copyright © 2024 Werner Randelshofer, Switzerland. MIT License.
4 | */
5 | package ch.randelshofer.fastdoubleparser.bte;
6 |
7 | import java.util.Collection;
8 |
9 | /**
10 | * A primitive map {@literal Map}.
11 | */
12 | final class ByteToIntMap implements ByteDigitSet, ByteSet {
13 |
14 |
15 | public ByteToIntMap(Collection chars) {
16 | this(chars.size());
17 | int i = 0;
18 | for (char ch : chars) {
19 | if (ch > 127) throw new IllegalArgumentException("can not map to a single byte. ch=" + ch);
20 | put((byte) ch, i++);
21 | }
22 | }
23 |
24 | @Override
25 | public boolean containsKey(byte b) {
26 | return getOrDefault(b, -1) >= 0;
27 | }
28 |
29 | @Override
30 | public int toDigit(byte ch) {
31 | return getOrDefault(ch, 10);
32 | }
33 |
34 | private static class Node {
35 | byte key;
36 | int value;
37 | Node next;
38 |
39 | public Node(byte key, int value) {
40 | this.key = key;
41 | this.value = value;
42 | }
43 | }
44 |
45 | private Node[] table;
46 |
47 | public ByteToIntMap(int maxSize) {
48 | // int n = BigInteger.valueOf(maxSize*2).nextProbablePrime().intValue();
49 | int n = (-1 >>> Integer.numberOfLeadingZeros(maxSize * 2)) + 1;
50 | this.table = new Node[n];
51 | }
52 |
53 | public void put(byte key, int value) {
54 | int index = getIndex(key);
55 | Node found = table[index];
56 | if (found == null) {
57 | table[index] = new Node(key, value);
58 | } else {
59 | while (found.next != null && found.key != key) {
60 | found = found.next;
61 | }
62 | if (found.key == key) {
63 | found.value = value;
64 | } else {
65 | found.next = new Node(key, value);
66 | }
67 | }
68 | }
69 |
70 | private int getIndex(byte key) {
71 | return key & (table.length - 1);
72 | }
73 |
74 | public int getOrDefault(byte key, int defaultValue) {
75 | int index = getIndex(key);
76 | Node found = table[index];
77 | while (found != null) {
78 | if (found.key == key) return found.value;
79 | found = found.next;
80 | }
81 | return defaultValue;
82 | }
83 | }
84 |
--------------------------------------------------------------------------------
/fastdoubleparser-dev/src/main/java/ch.randelshofer.fastdoubleparser/ch/randelshofer/fastdoubleparser/bte/ByteTrieNode.java:
--------------------------------------------------------------------------------
1 | /*
2 | * @(#)ByteTrieNode.java
3 | * Copyright © 2024 Werner Randelshofer, Switzerland. MIT License.
4 | */
5 | package ch.randelshofer.fastdoubleparser.bte;
6 |
7 | import java.util.Arrays;
8 |
9 | /**
10 | * Represents a node in a {@link ch.randelshofer.fastdoubleparser.bte.ByteTrieOfFew}
11 | */
12 | final class ByteTrieNode {
13 | private byte[] chars = new byte[0];
14 | private ByteTrieNode[] children = new ByteTrieNode[0];
15 | private boolean isEnd;
16 |
17 |
18 | public ByteTrieNode() {
19 | }
20 |
21 | /**
22 | * Insert a character into this node if it does not already exist.
23 | * Returns the child node corresponding to the char.
24 | *
25 | * @param ch the character
26 | * @return the child node corresponding to the char
27 | */
28 | public ByteTrieNode insert(byte ch) {
29 | int index = indexOf(ch);
30 | if (index < 0) {
31 | index = chars.length;
32 | chars = Arrays.copyOf(chars, chars.length + 1);
33 | children = Arrays.copyOf(children, children.length + 1);
34 | chars[index] = ch;
35 | children[index] = new ByteTrieNode();
36 | }
37 | return children[index];
38 | }
39 |
40 | /**
41 | * Insert a character into this node if it does not already exist.
42 | * Forces the node 'forceNode' to be inserted.
43 | *
44 | * @param ch the character
45 | * @param forcedNode the forced node
46 | * @return the forced node
47 | */
48 | public ByteTrieNode insert(byte ch, ByteTrieNode forcedNode) {
49 | int index = indexOf(ch);
50 | if (index < 0) {
51 | index = chars.length;
52 | chars = Arrays.copyOf(chars, chars.length + 1);
53 | children = Arrays.copyOf(children, children.length + 1);
54 | chars[index] = ch;
55 | children[index] = forcedNode;
56 | }
57 | if (children[index] != forcedNode) {
58 | throw new AssertionError("trie is corrupt");
59 | }
60 | return children[index];
61 | }
62 |
63 | /**
64 | * Gets the child not for the given character, if it exists.
65 | *
66 | * @param ch the character
67 | * @return the child node corresponding to the char, or the sentinel node
68 | */
69 | public ByteTrieNode get(byte ch) {
70 | int index = indexOf(ch);
71 | return index < 0 ? null : children[index];
72 | }
73 |
74 | /**
75 | * Returns the index of the specified character in this node.
76 | *
77 | * @param ch the character
78 | * @return the index or -1
79 | */
80 | private int indexOf(byte ch) {
81 | // intentionally 'branchless' loop
82 | int index = -1;
83 | for (int i = 0; i < chars.length; i++) {
84 | if (chars[i] == ch) index = i;
85 | }
86 | return index;
87 | }
88 |
89 | public void setEnd() {
90 | isEnd = true;
91 | }
92 |
93 | public boolean isEnd() {
94 | return isEnd;
95 | }
96 |
97 | }
98 |
--------------------------------------------------------------------------------
/fastdoubleparser-dev/src/main/java/ch.randelshofer.fastdoubleparser/ch/randelshofer/fastdoubleparser/bte/ByteTrieOfFew.java:
--------------------------------------------------------------------------------
1 | /*
2 | * @(#)ByteTrieOfFew.java
3 | * Copyright © 2024 Werner Randelshofer, Switzerland. MIT License.
4 | */
5 | package ch.randelshofer.fastdoubleparser.bte;
6 |
7 | import java.nio.charset.StandardCharsets;
8 | import java.util.Set;
9 |
10 | /**
11 | * A trie for testing if a String is contained in a set of Strings.
12 | */
13 | final class ByteTrieOfFew implements ByteTrie {
14 | private ByteTrieNode root = new ByteTrieNode();
15 |
16 | public ByteTrieOfFew(Set set) {
17 | for (String str : set) {
18 | if (!str.isEmpty()) {
19 | add(str);
20 | }
21 | }
22 | }
23 |
24 | private void add(String str) {
25 | ByteTrieNode node = root;
26 | byte[] strBytes = str.getBytes(StandardCharsets.UTF_8);
27 | for (int i = 0; i < strBytes.length; i++) {
28 | node = node.insert(strBytes[i]);
29 | }
30 | node.setEnd();
31 | }
32 |
33 |
34 | @Override
35 | public int match(byte[] str, int startIndex, int endIndex) {
36 | ByteTrieNode node = root;
37 | int longestMatch = startIndex;
38 | for (int i = startIndex; i < endIndex; i++) {
39 | node = node.get(str[i]);
40 | if (node == null) break;
41 | longestMatch = node.isEnd() ? i + 1 : longestMatch;
42 | }
43 | return longestMatch - startIndex;
44 | }
45 | }
46 |
--------------------------------------------------------------------------------
/fastdoubleparser-dev/src/main/java/ch.randelshofer.fastdoubleparser/ch/randelshofer/fastdoubleparser/bte/ByteTrieOfNone.java:
--------------------------------------------------------------------------------
1 | /*
2 | * @(#)ByteTrieOfNone.java
3 | * Copyright © 2024 Werner Randelshofer, Switzerland. MIT License.
4 | */
5 | package ch.randelshofer.fastdoubleparser.bte;
6 |
7 | final class ByteTrieOfNone implements ByteTrie {
8 |
9 |
10 | @Override
11 | public int match(byte[] str) {
12 | return 0;
13 | }
14 |
15 | @Override
16 | public int match(byte[] str, int startIndex, int endIndex) {
17 | return 0;
18 | }
19 | }
20 |
--------------------------------------------------------------------------------
/fastdoubleparser-dev/src/main/java/ch.randelshofer.fastdoubleparser/ch/randelshofer/fastdoubleparser/bte/ByteTrieOfOne.java:
--------------------------------------------------------------------------------
1 | /*
2 | * @(#)ByteTrieOfOne.java
3 | * Copyright © 2024 Werner Randelshofer, Switzerland. MIT License.
4 | */
5 | package ch.randelshofer.fastdoubleparser.bte;
6 |
7 | import java.nio.charset.StandardCharsets;
8 | import java.util.Set;
9 |
10 | final class ByteTrieOfOne implements ByteTrie {
11 | private final byte[] chars;
12 |
13 | public ByteTrieOfOne(Set set) {
14 | if (set.size() != 1) throw new IllegalArgumentException("set size must be 1, size=" + set.size());
15 | chars = set.iterator().next().getBytes(StandardCharsets.UTF_8);
16 | }
17 |
18 |
19 | @Override
20 | public int match(byte[] str) {
21 | return match(str, 0, str.length);
22 | }
23 |
24 | @Override
25 | public int match(byte[] str, int startIndex, int endIndex) {
26 | int i = 0;
27 | int limit = Math.min(endIndex - startIndex, chars.length);
28 | while (i < limit && str[i + startIndex] == chars[i]) {
29 | i++;
30 | }
31 | return i == chars.length ? chars.length : 0;
32 | }
33 | }
34 |
--------------------------------------------------------------------------------
/fastdoubleparser-dev/src/main/java/ch.randelshofer.fastdoubleparser/ch/randelshofer/fastdoubleparser/bte/ByteTrieOfOneSingleByte.java:
--------------------------------------------------------------------------------
1 | /*
2 | * @(#)ByteTrieOfOne.java
3 | * Copyright © 2024 Werner Randelshofer, Switzerland. MIT License.
4 | */
5 | package ch.randelshofer.fastdoubleparser.bte;
6 |
7 | import java.nio.charset.StandardCharsets;
8 | import java.util.Set;
9 |
10 | final class ByteTrieOfOneSingleByte implements ByteTrie {
11 | private final byte ch;
12 |
13 | public ByteTrieOfOneSingleByte(Set set) {
14 | if (set.size() != 1) throw new IllegalArgumentException("set size must be 1, size=" + set.size());
15 | byte[] chars = set.iterator().next().getBytes(StandardCharsets.UTF_8);
16 | if (chars.length != 1) throw new IllegalArgumentException("char size must be 1, size=" + set.size());
17 | ch = chars[0];
18 | }
19 |
20 | public ByteTrieOfOneSingleByte(byte ch) {
21 | this.ch = ch;
22 | }
23 |
24 |
25 | @Override
26 | public int match(byte[] str) {
27 | return match(str, 0, str.length);
28 | }
29 |
30 | @Override
31 | public int match(byte[] str, int startIndex, int endIndex) {
32 | return startIndex < endIndex && str[startIndex] == ch ? 1 : 0;
33 | }
34 | }
35 |
--------------------------------------------------------------------------------
/fastdoubleparser-dev/src/main/java/ch.randelshofer.fastdoubleparser/ch/randelshofer/fastdoubleparser/bte/ConsecutiveByteDigitSet.java:
--------------------------------------------------------------------------------
1 | /*
2 | * @(#)ConsecutiveByteDigitSet.java
3 | * Copyright © 2024 Werner Randelshofer, Switzerland. MIT License.
4 | */
5 | package ch.randelshofer.fastdoubleparser.bte;
6 |
7 | final class ConsecutiveByteDigitSet implements ByteDigitSet {
8 | private final byte zeroDigit;
9 |
10 | public ConsecutiveByteDigitSet(char zeroDigit) {
11 | if (zeroDigit > 127) {
12 | throw new IllegalArgumentException("can not map to a single byte. zeroDigit=" + zeroDigit + "' 0x" + Integer.toHexString(zeroDigit));
13 | }
14 | this.zeroDigit = (byte) zeroDigit;
15 | }
16 |
17 | @Override
18 | public int toDigit(byte ch) {
19 | return (char) (ch - zeroDigit);
20 | }
21 | }
22 |
--------------------------------------------------------------------------------
/fastdoubleparser-dev/src/main/java/ch.randelshofer.fastdoubleparser/ch/randelshofer/fastdoubleparser/bte/package-info.java:
--------------------------------------------------------------------------------
1 | /*
2 | * @(#)package-info.java
3 | * Copyright © 2024 Werner Randelshofer, Switzerland. MIT License.
4 | */
5 |
6 | /**
7 | * This is a module-private package.
8 | *
9 | * It provides primitive {@code byte} collections.
10 | */
11 | package ch.randelshofer.fastdoubleparser.bte;
--------------------------------------------------------------------------------
/fastdoubleparser-dev/src/main/java/ch.randelshofer.fastdoubleparser/ch/randelshofer/fastdoubleparser/chr/CharDigitSet.java:
--------------------------------------------------------------------------------
1 | /*
2 | * @(#)CharDigitSet.java
3 | * Copyright © 2024 Werner Randelshofer, Switzerland. MIT License.
4 | */
5 | package ch.randelshofer.fastdoubleparser.chr;
6 |
7 | import ch.randelshofer.fastdoubleparser.bte.ByteDigitSet;
8 |
9 | import java.util.List;
10 |
11 | /**
12 | * Interface for sets of digit characters.
13 | */
14 | public interface CharDigitSet {
15 | /**
16 | * Returns a value in the range 0 to 9 if the specified character is a digit.
17 | * Otherwise, Returns a value greater than 9.
18 | *
19 | * @param ch a character
20 | * @return a value in the range 0 to Integer.MAX_VALUE.
21 | */
22 | int toDigit(char ch);
23 |
24 |
25 | /**
26 | * Creates a new {@link CharDigitSet} instead from the
27 | * specified list.
28 | *
29 | * The list must contain characters for the digits 0 to 9.
30 | *
31 | * @param digits a list of digit characters
32 | * @return a new {@link ByteDigitSet} instance
33 | */
34 | @SuppressWarnings("SequencedCollectionMethodCanBeUsed")
35 | static CharDigitSet copyOf(List digits) {
36 | boolean consecutive = true;
37 | char zeroDigit = digits.get(0);
38 | for (int i = 1; i < 10; i++) {
39 | char current = digits.get(i);
40 | consecutive &= current == zeroDigit + i;
41 | }
42 | return consecutive ?
43 | new ConsecutiveCharDigitSet(digits.get(0)) :
44 | new CharToIntMap(digits);
45 | }
46 | }
47 |
--------------------------------------------------------------------------------
/fastdoubleparser-dev/src/main/java/ch.randelshofer.fastdoubleparser/ch/randelshofer/fastdoubleparser/chr/CharSet.java:
--------------------------------------------------------------------------------
1 | /*
2 | * @(#)ByteSet.java
3 | * Copyright © 2024 Werner Randelshofer, Switzerland. MIT License.
4 | */
5 | package ch.randelshofer.fastdoubleparser.chr;
6 |
7 | import ch.randelshofer.fastdoubleparser.bte.ByteSet;
8 |
9 | import java.util.LinkedHashSet;
10 | import java.util.Set;
11 |
12 | /**
13 | * Interface for sets of characters.
14 | */
15 | public interface CharSet {
16 | /**
17 | * Returns true if the set contains the specified character.
18 | *
19 | * @param ch a character
20 | * @return true if the byte is in the set
21 | */
22 | boolean containsKey(char ch);
23 |
24 |
25 | /**
26 | * Creates a new {@link CharSet} from the provided set.
27 | *
28 | * @param set a set of characters
29 | * @param ignoreCase whether the {@link CharSet} shall ignore the
30 | * case of the characters
31 | * @return a new {@link ByteSet} instance
32 | */
33 | static CharSet copyOf(Set set, boolean ignoreCase) {
34 | set = applyIgnoreCase(set, ignoreCase);
35 | switch (set.size()) {
36 | case 0:
37 | return new CharSetOfNone();
38 | case 1:
39 | return new CharSetOfOne(set);
40 | default:
41 | return set.size() < 5 ? new CharSetOfFew(set) : new CharToIntMap(set);
42 | }
43 | }
44 |
45 | /**
46 | * Creates a copy of the provided set, or returns the same set.
47 | *
48 | * If {@code ignoreCase} is set to true, the copy will contain
49 | * an upper and lower case character for each character in the provided
50 | * set.
51 | *
52 | * @param set a set of characters
53 | * @param ignoreCase whether the copy of the set shall contain
54 | * upper and lower case characters from the
55 | * provided set
56 | * @return a new set if {@code ignoreCase} is false, otherwise a copy of the set
57 | */
58 | static Set applyIgnoreCase(Set set, boolean ignoreCase) {
59 | if (ignoreCase) {
60 | LinkedHashSet convertedSet = new LinkedHashSet();
61 | for (Character ch : set) {
62 | // Add the original input char.
63 | convertedSet.add(ch);
64 |
65 | // Convert to lower case. This does not cover all cases.
66 | char lc = Character.toLowerCase(ch);
67 |
68 | // We have to convert to upper case and then to lower case
69 | // because of sophisticated writing systems, like Georgian script.
70 | char uc = Character.toUpperCase(ch);
71 | char uclc = Character.toLowerCase(uc);
72 |
73 | convertedSet.add(lc);
74 | convertedSet.add(uc);
75 | convertedSet.add(uclc);
76 | }
77 | set = convertedSet;
78 | }
79 | return set;
80 | }
81 |
82 | }
83 |
--------------------------------------------------------------------------------
/fastdoubleparser-dev/src/main/java/ch.randelshofer.fastdoubleparser/ch/randelshofer/fastdoubleparser/chr/CharSetOfFew.java:
--------------------------------------------------------------------------------
1 | /*
2 | * @(#)CharSetOfFew.java
3 | * Copyright © 2024 Werner Randelshofer, Switzerland. MIT License.
4 | */
5 | package ch.randelshofer.fastdoubleparser.chr;
6 |
7 | import java.util.Set;
8 |
9 | /**
10 | * A set of {@code char} with linear search.
11 | */
12 | final class CharSetOfFew implements CharSet {
13 | private final char[] chars;
14 |
15 | public CharSetOfFew(Set set) {
16 | this.chars = new char[set.size()];
17 | int i = 0;
18 | for (Character ch : set) {
19 | chars[i++] = ch;
20 | }
21 | }
22 |
23 | public boolean containsKey(char ch) {
24 | boolean found = false;
25 | for (char aChar : chars) {
26 | found |= aChar == ch;
27 | }
28 | return found;
29 | }
30 | }
31 |
--------------------------------------------------------------------------------
/fastdoubleparser-dev/src/main/java/ch.randelshofer.fastdoubleparser/ch/randelshofer/fastdoubleparser/chr/CharSetOfNone.java:
--------------------------------------------------------------------------------
1 | /*
2 | * @(#)CharSetOfNone.java
3 | * Copyright © 2024 Werner Randelshofer, Switzerland. MIT License.
4 | */
5 | package ch.randelshofer.fastdoubleparser.chr;
6 |
7 | public final class CharSetOfNone implements CharSet {
8 |
9 | public CharSetOfNone() {
10 | }
11 |
12 | public boolean containsKey(char ch) {
13 | return false;
14 | }
15 | }
16 |
--------------------------------------------------------------------------------
/fastdoubleparser-dev/src/main/java/ch.randelshofer.fastdoubleparser/ch/randelshofer/fastdoubleparser/chr/CharSetOfOne.java:
--------------------------------------------------------------------------------
1 | /*
2 | * @(#)CharSetOfOne.java
3 | * Copyright © 2024 Werner Randelshofer, Switzerland. MIT License.
4 | */
5 | package ch.randelshofer.fastdoubleparser.chr;
6 |
7 | import java.util.Set;
8 |
9 | final class CharSetOfOne implements CharSet {
10 | private final char ch;
11 |
12 | CharSetOfOne(Set set) {
13 | if (set.size() != 1) throw new IllegalArgumentException("set size must be 1, size=" + set.size());
14 | this.ch = set.iterator().next();
15 |
16 | }
17 |
18 | public boolean containsKey(char ch) {
19 | return this.ch == ch;
20 | }
21 | }
22 |
--------------------------------------------------------------------------------
/fastdoubleparser-dev/src/main/java/ch.randelshofer.fastdoubleparser/ch/randelshofer/fastdoubleparser/chr/CharToIntMap.java:
--------------------------------------------------------------------------------
1 | /*
2 | * @(#)CharToIntMap.java
3 | * Copyright © 2024 Werner Randelshofer, Switzerland. MIT License.
4 | */
5 | package ch.randelshofer.fastdoubleparser.chr;
6 |
7 | import java.util.Collection;
8 |
9 | /**
10 | * A primitive map {@literal Map}.
11 | */
12 | final class CharToIntMap implements CharDigitSet, CharSet {
13 |
14 |
15 | public CharToIntMap(Collection chars) {
16 | this(chars.size());
17 | int i = 0;
18 | for (char ch : chars) {
19 | put(ch, i++);
20 | }
21 | }
22 |
23 | @Override
24 | public boolean containsKey(char key) {
25 | return getOrDefault(key, -1) >= 0;
26 | }
27 |
28 | @Override
29 | public int toDigit(char ch) {
30 | return getOrDefault(ch, 10);
31 | }
32 |
33 | private static class Node {
34 | char key;
35 | int value;
36 | Node next;
37 |
38 | public Node(char key, int value) {
39 | this.key = key;
40 | this.value = value;
41 | }
42 | }
43 |
44 | private Node[] table;
45 |
46 | public CharToIntMap(int maxSize) {
47 | // int n = BigInteger.valueOf(maxSize*2).nextProbablePrime().intValue();
48 | int n = (-1 >>> Integer.numberOfLeadingZeros(maxSize * 2)) + 1;
49 | this.table = new Node[n];
50 | }
51 |
52 | public void put(char key, int value) {
53 | int index = getIndex(key);
54 | Node found = table[index];
55 | if (found == null) {
56 | table[index] = new Node(key, value);
57 | } else {
58 | while (found.next != null && found.key != key) {
59 | found = found.next;
60 | }
61 | if (found.key == key) {
62 | found.value = value;
63 | } else {
64 | found.next = new Node(key, value);
65 | }
66 | }
67 | }
68 |
69 | private int getIndex(char key) {
70 | return key & (table.length - 1);
71 | }
72 |
73 | public int getOrDefault(char key, int defaultValue) {
74 | int index = getIndex(key);
75 | Node found = table[index];
76 | while (found != null) {
77 | if (found.key == key) return found.value;
78 | found = found.next;
79 | }
80 | return defaultValue;
81 | }
82 | }
83 |
--------------------------------------------------------------------------------
/fastdoubleparser-dev/src/main/java/ch.randelshofer.fastdoubleparser/ch/randelshofer/fastdoubleparser/chr/CharTrie.java:
--------------------------------------------------------------------------------
1 | /*
2 | * @(#)ByteTrie.java
3 | * Copyright © 2024 Werner Randelshofer, Switzerland. MIT License.
4 | */
5 | package ch.randelshofer.fastdoubleparser.chr;
6 |
7 | import java.util.Set;
8 |
9 | /**
10 | * Interface for a data retrieval tree (trie) of characters.
11 | */
12 | public interface CharTrie {
13 | /**
14 | * Searches for the longest matching string in the trie
15 | * that matches the provided string.
16 | *
17 | * @param str a string in the form of a {@link CharSequence}
18 | * @return the length of the longest matching string, or 0 if no string matches
19 | */
20 | default int match(CharSequence str) {
21 | return match(str, 0, str.length());
22 | }
23 |
24 | /**
25 | * Searches for the longest matching string in the trie
26 | * that matches the provided string.
27 | *
28 | * @param str a string in the form of a char array
29 | * @return the length of the longest matching string, or 0 if no string matches
30 | */
31 | default int match(char[] str) {
32 | return match(str, 0, str.length);
33 | }
34 |
35 |
36 | /**
37 | * Searches for the longest matching string in the trie
38 | * that matches the provided string.
39 | *
40 | * @param str a string
41 | * @param startIndex start index (inclusive)
42 | * @param endIndex end index (exclusive)
43 | * @return the length of the longest matching string, or 0 if no string matches
44 | */
45 | int match(CharSequence str, int startIndex, int endIndex);
46 |
47 | /**
48 | * Searches for the longest matching string in the trie
49 | * that matches the provided string.
50 | *
51 | * @param str a string
52 | * @param startIndex start index (inclusive)
53 | * @param endIndex end index (exclusive)
54 | * @return the length of the longest matching string, or 0 if no string matches
55 | */
56 | int match(char[] str, int startIndex, int endIndex);
57 |
58 |
59 | /**
60 | * Creates a new {@link CharTrie} from the provided set.
61 | *
62 | * @param set a set of strings
63 | * @param ignoreCase whether the {@link CharTrie} shall ignore the
64 | * case of the characters
65 | * @return a new {@link CharTrie} instance
66 | */
67 | static CharTrie copyOf(Set set, boolean ignoreCase) {
68 | switch (set.size()) {
69 | case 0:
70 | return new CharTrieOfNone();
71 | case 1:
72 | if (set.iterator().next().length() == 1) {
73 | return ignoreCase ? new CharTrieOfFewIgnoreCase(set) : new CharTrieOfOneSingleChar(set);
74 | }
75 | return ignoreCase ? new CharTrieOfFewIgnoreCase(set) : new CharTrieOfOne(set);
76 | default:
77 | return ignoreCase ? new CharTrieOfFewIgnoreCase(set) : new CharTrieOfFew(set);
78 | }
79 | }
80 | }
81 |
--------------------------------------------------------------------------------
/fastdoubleparser-dev/src/main/java/ch.randelshofer.fastdoubleparser/ch/randelshofer/fastdoubleparser/chr/CharTrieNode.java:
--------------------------------------------------------------------------------
1 | /*
2 | * @(#)CharTrieNode.java
3 | * Copyright © 2024 Werner Randelshofer, Switzerland. MIT License.
4 | */
5 | package ch.randelshofer.fastdoubleparser.chr;
6 |
7 |
8 | import java.util.Arrays;
9 |
10 | final class CharTrieNode {
11 | private char[] chars = new char[0];
12 | private CharTrieNode[] children = new CharTrieNode[0];
13 | private boolean isEnd;
14 |
15 |
16 |
17 | public CharTrieNode() {
18 | }
19 |
20 | /**
21 | * Insert a character into this node if it does not already exist.
22 | * Returns the child node corresponding to the char.
23 | *
24 | * @param ch the character
25 | * @return the child node corresponding to the char
26 | */
27 | public CharTrieNode insert(char ch) {
28 | int index = indexOf(ch);
29 | if (index < 0) {
30 | index = chars.length;
31 | chars = Arrays.copyOf(chars, chars.length + 1);
32 | children = Arrays.copyOf(children, children.length + 1);
33 | chars[index] = ch;
34 | children[index] = new CharTrieNode();
35 | }
36 | return children[index];
37 | }
38 |
39 | /**
40 | * Gets the child not for the given character, if it exists.
41 | *
42 | * @param ch the character
43 | * @return the child node corresponding to the char, or the sentinel node
44 | */
45 | public CharTrieNode get(char ch) {
46 | int index = indexOf(ch);
47 | return index < 0 ? null : children[index];
48 | }
49 |
50 | /**
51 | * Returns the index of the specified character in this node.
52 | *
53 | * @param ch the character
54 | * @return the index or -1
55 | */
56 | private int indexOf(char ch) {
57 | // intentionally 'branchless' loop
58 | int index = -1;
59 | for (int i = 0; i < chars.length; i++) {
60 | if (chars[i] == ch) index = i;
61 | }
62 | return index;
63 | }
64 |
65 | public void setEnd() {
66 | isEnd = true;
67 | }
68 |
69 | public boolean isEnd() {
70 | return isEnd;
71 | }
72 |
73 | /**
74 | * Insert a character into this node if it does not already exist.
75 | * Forces the node 'forceNode' to be inserted.
76 | *
77 | * @param ch the character
78 | * @param forcedNode the forced node
79 | * @return the forced node
80 | */
81 | public CharTrieNode insert(char ch, CharTrieNode forcedNode) {
82 | int index = indexOf(ch);
83 | if (index < 0) {
84 | index = chars.length;
85 | chars = Arrays.copyOf(chars, chars.length + 1);
86 | children = Arrays.copyOf(children, children.length + 1);
87 | chars[index] = ch;
88 | children[index] = forcedNode;
89 | }
90 | if (children[index] != forcedNode) {
91 | throw new AssertionError("trie is corrupt");
92 | }
93 | return children[index];
94 | }
95 | }
96 |
--------------------------------------------------------------------------------
/fastdoubleparser-dev/src/main/java/ch.randelshofer.fastdoubleparser/ch/randelshofer/fastdoubleparser/chr/CharTrieOfFew.java:
--------------------------------------------------------------------------------
1 | /*
2 | * @(#)CharTrieOfFew.java
3 | * Copyright © 2024 Werner Randelshofer, Switzerland. MIT License.
4 | */
5 | package ch.randelshofer.fastdoubleparser.chr;
6 |
7 | import java.util.Set;
8 |
9 | /**
10 | * A trie for testing if a String is contained in a set of Strings.
11 | */
12 | final class CharTrieOfFew implements CharTrie {
13 | private CharTrieNode root = new CharTrieNode();
14 |
15 | public CharTrieOfFew(Set set) {
16 | for (String str : set) {
17 | if (!str.isEmpty()) {
18 | add(str);
19 | }
20 | }
21 | }
22 |
23 | private void add(String str) {
24 | CharTrieNode node = root;
25 | for (int i = 0; i < str.length(); i++) {
26 | node = node.insert(str.charAt(i));
27 | }
28 | node.setEnd();
29 | }
30 |
31 |
32 | @Override
33 | public int match(CharSequence str, int startIndex, int endIndex) {
34 | CharTrieNode node = root;
35 | int longestMatch = startIndex;
36 | for (int i = startIndex; i < endIndex; i++) {
37 | node = node.get(str.charAt(i));
38 | if (node == null) break;
39 | longestMatch = node.isEnd() ? i + 1 : longestMatch;
40 | }
41 | return longestMatch - startIndex;
42 | }
43 |
44 | @Override
45 | public int match(char[] str, int startIndex, int endIndex) {
46 | CharTrieNode node = root;
47 | int longestMatch = startIndex;
48 | for (int i = startIndex; i < endIndex; i++) {
49 | node = node.get(str[i]);
50 | if (node == null) break;
51 | longestMatch = node.isEnd() ? i + 1 : longestMatch;
52 | }
53 | return longestMatch - startIndex;
54 | }
55 |
56 | }
57 |
--------------------------------------------------------------------------------
/fastdoubleparser-dev/src/main/java/ch.randelshofer.fastdoubleparser/ch/randelshofer/fastdoubleparser/chr/CharTrieOfFewIgnoreCase.java:
--------------------------------------------------------------------------------
1 | /*
2 | * @(#)CharTrieOfFewIgnoreCase.java
3 | * Copyright © 2024 Werner Randelshofer, Switzerland. MIT License.
4 | */
5 | package ch.randelshofer.fastdoubleparser.chr;
6 |
7 | import java.util.Set;
8 |
9 | /**
10 | * A trie for testing if a String is contained in a set of Strings.
11 | *
12 | * This trie is a directed acyclic graph.
13 | *
14 | *
15 | * Given: the strings: "NaN", "Inf"
16 | * The trie will have the following structure:
17 | *
18 | * root ['N','n', 'I','i']
19 | * │ │ │ │
20 | * │ │ └─┬─┘
21 | * │ │ └─→ node ['N','n']
22 | * │ │ │ │
23 | * │ │ └─┬─┘
24 | * └─┬─┘ └─→ node ['F','f']
25 | * └─→ node ['A','a']
26 | * │ │
27 | * └─┬─┘
28 | * └─→ node ['N','N']
29 | *
30 | */
31 | final class CharTrieOfFewIgnoreCase implements CharTrie {
32 | private CharTrieNode root = new CharTrieNode();
33 |
34 | public CharTrieOfFewIgnoreCase(Set set) {
35 | for (String str : set) {
36 | if (!str.isEmpty()) {
37 | add(str);
38 | }
39 | }
40 | }
41 |
42 | private void add(String str) {
43 | // We have to convert to upper case and then to lower case
44 | // because of sophisticated writing systems, like Georgian script.
45 | CharTrieNode upperNode = root;
46 | CharTrieNode lowerNode = root;
47 | String upperStr = str.toUpperCase();
48 | String lowerStr = upperStr.toLowerCase();
49 | for (int i = 0; i < str.length(); i++) {
50 | char upper = upperStr.charAt(i);
51 | char lower = lowerStr.charAt(i);
52 | upperNode = upperNode.insert(upper);
53 | lowerNode = lowerNode.insert(lower, upperNode);
54 |
55 | }
56 | upperNode.setEnd();
57 | }
58 |
59 |
60 | @Override
61 | public int match(char[] str, int startIndex, int endIndex) {
62 | CharTrieNode node = root;
63 | int longestMatch = startIndex;
64 | for (int i = startIndex; i < endIndex; i++) {
65 | node = node.get(str[i]);
66 | if (node == null) break;
67 | longestMatch = node.isEnd() ? i + 1 : longestMatch;
68 | }
69 | return longestMatch - startIndex;
70 | }
71 |
72 | @Override
73 | public int match(CharSequence str, int startIndex, int endIndex) {
74 | CharTrieNode node = root;
75 | int longestMatch = startIndex;
76 | for (int i = startIndex; i < endIndex; i++) {
77 | node = node.get(str.charAt(i));
78 | if (node == null) break;
79 | longestMatch = node.isEnd() ? i + 1 : longestMatch;
80 | }
81 | return longestMatch - startIndex;
82 | }
83 |
84 | }
85 |
--------------------------------------------------------------------------------
/fastdoubleparser-dev/src/main/java/ch.randelshofer.fastdoubleparser/ch/randelshofer/fastdoubleparser/chr/CharTrieOfNone.java:
--------------------------------------------------------------------------------
1 | /*
2 | * @(#)CharTrieOfNone.java
3 | * Copyright © 2024 Werner Randelshofer, Switzerland. MIT License.
4 | */
5 | package ch.randelshofer.fastdoubleparser.chr;
6 |
7 | final class CharTrieOfNone implements CharTrie {
8 | @Override
9 | public int match(CharSequence str) {
10 | return 0;
11 | }
12 |
13 | @Override
14 | public int match(CharSequence str, int startIndex, int endIndex) {
15 | return 0;
16 | }
17 |
18 | @Override
19 | public int match(char[] str) {
20 | return 0;
21 | }
22 |
23 | @Override
24 | public int match(char[] str, int startIndex, int endIndex) {
25 | return 0;
26 | }
27 |
28 | }
29 |
--------------------------------------------------------------------------------
/fastdoubleparser-dev/src/main/java/ch.randelshofer.fastdoubleparser/ch/randelshofer/fastdoubleparser/chr/CharTrieOfOne.java:
--------------------------------------------------------------------------------
1 | /*
2 | * @(#)CharTrieOfOne.java
3 | * Copyright © 2024 Werner Randelshofer, Switzerland. MIT License.
4 | */
5 | package ch.randelshofer.fastdoubleparser.chr;
6 |
7 | import java.util.Set;
8 |
9 | final class CharTrieOfOne implements CharTrie {
10 | private final char[] chars;
11 |
12 | public CharTrieOfOne(Set set) {
13 | if (set.size() != 1) throw new IllegalArgumentException("set size must be 1, size=" + set.size());
14 | chars = set.iterator().next().toCharArray();
15 | }
16 |
17 | public CharTrieOfOne(char[] chars) {
18 | this.chars = chars;
19 | }
20 |
21 | @Override
22 | public int match(CharSequence str) {
23 | return match(str, 0, str.length());
24 | }
25 |
26 | @Override
27 | public int match(CharSequence str, int startIndex, int endIndex) {
28 | int i = 0;
29 | int limit = Math.min(endIndex - startIndex, chars.length);
30 | while (i < limit && str.charAt(i + startIndex) == chars[i]) {
31 | i++;
32 | }
33 | return i == chars.length ? chars.length : 0;
34 | }
35 |
36 | @Override
37 | public int match(char[] str) {
38 | return match(str, 0, str.length);
39 | }
40 |
41 | @Override
42 | public int match(char[] str, int startIndex, int endIndex) {
43 | /*
44 | int mismatch = Arrays.mismatch(chars, 0, chars.length, str, startIndex,startIndex+ Math.min(endIndex - startIndex, chars.length));
45 | return mismatch<0?chars.length:0;
46 | */
47 | int i = 0;
48 | int limit = Math.min(endIndex - startIndex, chars.length);
49 | while (i < limit && str[i + startIndex] == chars[i]) {
50 | i++;
51 | }
52 | return i == chars.length ? chars.length : 0;
53 |
54 | }
55 | }
56 |
--------------------------------------------------------------------------------
/fastdoubleparser-dev/src/main/java/ch.randelshofer.fastdoubleparser/ch/randelshofer/fastdoubleparser/chr/CharTrieOfOneSingleChar.java:
--------------------------------------------------------------------------------
1 | /*
2 | * @(#)ByteTrieOfOne.java
3 | * Copyright © 2024 Werner Randelshofer, Switzerland. MIT License.
4 | */
5 | package ch.randelshofer.fastdoubleparser.chr;
6 |
7 | import java.util.Set;
8 |
9 | final class CharTrieOfOneSingleChar implements CharTrie {
10 | private final char ch;
11 |
12 | public CharTrieOfOneSingleChar(Set set) {
13 | if (set.size() != 1) throw new IllegalArgumentException("set size must be 1, size=" + set.size());
14 | char[] chars = set.iterator().next().toCharArray();
15 | if (chars.length != 1) throw new IllegalArgumentException("char size must be 1, size=" + set.size());
16 | ch = chars[0];
17 | }
18 |
19 | public CharTrieOfOneSingleChar(char ch) {
20 | this.ch = ch;
21 | }
22 |
23 | @Override
24 | public int match(CharSequence str, int startIndex, int endIndex) {
25 | return startIndex < endIndex && str.charAt(startIndex) == ch ? 1 : 0;
26 | }
27 |
28 | @Override
29 | public int match(char[] str) {
30 | return match(str, 0, str.length);
31 | }
32 |
33 | @Override
34 | public int match(char[] str, int startIndex, int endIndex) {
35 | return startIndex < endIndex && str[startIndex] == ch ? 1 : 0;
36 | }
37 | }
38 |
--------------------------------------------------------------------------------
/fastdoubleparser-dev/src/main/java/ch.randelshofer.fastdoubleparser/ch/randelshofer/fastdoubleparser/chr/ConsecutiveCharDigitSet.java:
--------------------------------------------------------------------------------
1 | /*
2 | * @(#)ConsecutiveByteDigitSet.java
3 | * Copyright © 2024 Werner Randelshofer, Switzerland. MIT License.
4 | */
5 | package ch.randelshofer.fastdoubleparser.chr;
6 |
7 | final class ConsecutiveCharDigitSet implements CharDigitSet {
8 | private final char zeroDigit;
9 |
10 | public ConsecutiveCharDigitSet(char zeroDigit) {
11 | this.zeroDigit = zeroDigit;
12 | }
13 |
14 | @Override
15 | public int toDigit(char ch) {
16 | return (char) (ch - zeroDigit);
17 | }
18 | }
19 |
--------------------------------------------------------------------------------
/fastdoubleparser-dev/src/main/java/ch.randelshofer.fastdoubleparser/ch/randelshofer/fastdoubleparser/chr/FormatCharSet.java:
--------------------------------------------------------------------------------
1 | /*
2 | * @(#)FormatCharSet.java
3 | * Copyright © 2024 Werner Randelshofer, Switzerland. MIT License.
4 | */
5 | package ch.randelshofer.fastdoubleparser.chr;
6 |
7 | /**
8 | * This format set contains all Unicode format chars.
9 | */
10 | public class FormatCharSet implements CharSet {
11 | @Override
12 | public boolean containsKey(char ch) {
13 | return Character.getType(ch) == Character.FORMAT;
14 | }
15 | }
16 |
--------------------------------------------------------------------------------
/fastdoubleparser-dev/src/main/java/ch.randelshofer.fastdoubleparser/ch/randelshofer/fastdoubleparser/chr/package-info.java:
--------------------------------------------------------------------------------
1 | /*
2 | * @(#)package-info.java
3 | * Copyright © 2024 Werner Randelshofer, Switzerland. MIT License.
4 | */
5 |
6 | /**
7 | * This is a module-private package.
8 | *
9 | * It provides primitive {@code char} collections.
10 | */
11 | package ch.randelshofer.fastdoubleparser.chr;
--------------------------------------------------------------------------------
/fastdoubleparser-dev/src/main/java/ch.randelshofer.fastdoubleparser/ch/randelshofer/fastdoubleparser/package-info.java:
--------------------------------------------------------------------------------
1 | /*
2 | * @(#)package-info.java
3 | * Copyright © 2024 Werner Randelshofer, Switzerland. MIT License.
4 | */
5 |
6 | /**
7 | * Provides fast parsers for Java {@code FloatingPointLiteral}s,
8 | * and JSON {@code number}s.
9 | *
10 | * References:
11 | *
12 | * The Java® Language Specification, Java SE 18 Edition,
13 | * Chapter 3. Lexical Structure, 3.10.2. Floating-Point Literals
14 | * docs.oracle.com
15 | *
16 | * IETF RFC 8259. The JavaScript Object Notation (JSON) Data Interchange
17 | * Format, Chapter 6. Numbers
18 | * www.ietf.org
19 | *
20 | */
21 | package ch.randelshofer.fastdoubleparser;
--------------------------------------------------------------------------------
/fastdoubleparser-dev/src/main/java/ch.randelshofer.fastdoubleparser/module-info.java:
--------------------------------------------------------------------------------
1 | /*
2 | * @(#)module-info.java
3 | * Copyright © 2024 Werner Randelshofer, Switzerland. MIT License.
4 | */
5 |
6 | /**
7 | * Provides fast parsers for Java {@code FloatingPointLiteral}s,
8 | * and JSON {@code number}s.
9 | */
10 | module ch.randelshofer.fastdoubleparser {
11 | requires jdk.incubator.vector;
12 | exports ch.randelshofer.fastdoubleparser;
13 | }
--------------------------------------------------------------------------------
/fastdoubleparser-dev/src/main/resources/ch.randelshofer.fastdoubleparser/META-INF/thirdparty-LICENSE:
--------------------------------------------------------------------------------
1 | ------
2 | Third-party license for
3 | fast_float, Copyright (c) 2021 The fast_float authors. MIT License.
4 | https://github.com/fastfloat/fast_float
5 | https://github.com/fastfloat/fast_float/blob/35d523195bf7d57aba0e735ad6eba1e6f71ba8d6/LICENSE-MIT
6 |
7 | MIT License
8 |
9 | Copyright (c) 2021 The fast_float authors
10 |
11 | Permission is hereby granted, free of charge, to any person obtaining a copy
12 | of this software and associated documentation files (the "Software"), to deal
13 | in the Software without restriction, including without limitation the rights
14 | to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
15 | copies of the Software, and to permit persons to whom the Software is
16 | furnished to do so, subject to the following conditions:
17 |
18 | The above copyright notice and this permission notice shall be included in all
19 | copies or substantial portions of the Software.
20 |
21 | THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
22 | IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
23 | FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
24 | AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
25 | LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
26 | OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
27 | SOFTWARE.
28 | ------
29 | Third-party license for
30 | bigint, Copyright 2020 Tim Buktu. 2-clause BSD License.
31 | https://github.com/tbuktu/bigint/tree/floatfft
32 | https://github.com/tbuktu/bigint/blob/617c8cd8a7c5e4fb4d919c6a4d11e2586107f029/LICENSE
33 | https://github.com/wrandelshofer/FastDoubleParser/blob/39e123b15b71f29a38a087d16a0bc620fc879aa6/bigint-LICENSE
34 | (We only use those portions of the bigint project that can be licensed under 2-clause BSD License.)
35 |
36 | 2-clause BSD License
37 |
38 | Copyright 2022 Tim Buktu
39 |
40 | Redistribution and use in source and binary forms, with or without
41 | modification, are permitted provided that the following conditions
42 | are met:
43 |
44 | 1. Redistributions of source code must retain the above copyright notice, this
45 | list of conditions and the following disclaimer.
46 |
47 | 2. Redistributions in binary form must reproduce the above copyright notice,
48 | this list of conditions and the following disclaimer in the documentation
49 | and/or other materials provided with the distribution.
50 |
51 | THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS “AS IS” AND
52 | ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED
53 | WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE
54 | DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE LIABLE
55 | FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
56 | DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR
57 | SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER
58 | CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY,
59 | OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
60 | OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
61 |
--------------------------------------------------------------------------------
/fastdoubleparser-dev/src/test/java/ch.randelshofer.fastdoubleparser/ch/randelshofer/fastdoubleparser/BigSignificandTest.java:
--------------------------------------------------------------------------------
1 | /*
2 | * @(#)BigSignificandTest.java
3 | * Copyright © 2024 Werner Randelshofer, Switzerland. MIT License.
4 | */
5 | package ch.randelshofer.fastdoubleparser;
6 |
7 | import org.junit.jupiter.api.Test;
8 |
9 | import java.math.BigInteger;
10 |
11 | import static org.junit.jupiter.api.Assertions.assertEquals;
12 |
13 | /**
14 | * Unit tests for {@link BigSignificand}.
15 | */
16 | public final class BigSignificandTest {
17 | @Test
18 | public void shouldAddValuesThatExceedIntValueRange() {
19 | int value = 2_000_000_000;
20 | int addend = 1_000_000_000;
21 |
22 | BigInteger expected = BigInteger.valueOf(value);
23 | expected = expected.add(BigInteger.valueOf(addend));
24 |
25 | BigSignificand instance = new BigSignificand(64);
26 | instance.add(value);
27 | instance.add(addend);
28 | BigInteger actual = instance.toBigInteger();
29 |
30 | assertEquals(expected, actual);
31 | }
32 |
33 | @Test
34 | public void shouldMultiplyValuesThatExceedIntValueRange() {
35 | int value = 2_000_000_000;
36 | int factor = 1_000_000_000;
37 |
38 | BigInteger expected = BigInteger.valueOf(value);
39 | expected = expected.multiply(BigInteger.valueOf(factor));
40 |
41 | BigSignificand instance = new BigSignificand(64);
42 | instance.add(value);
43 | instance.fma(factor, 0);
44 | BigInteger actual = instance.toBigInteger();
45 |
46 | assertEquals(expected, actual);
47 | }
48 |
49 | @Test
50 | public void shouldFmaValuesThatExceedIntValueRange() {
51 | int value = 2_000_000_000;
52 | int addend = 1_900_000_000;
53 | int factor = 1_000_000_000;
54 |
55 | BigInteger expected = BigInteger.valueOf(value);
56 | expected = expected.multiply(BigInteger.valueOf(factor));
57 | expected = expected.add(BigInteger.valueOf(addend));
58 |
59 | BigSignificand instance = new BigSignificand(64);
60 | instance.fma(1, value);
61 | instance.fma(factor, addend);
62 | BigInteger actual = instance.toBigInteger();
63 |
64 | assertEquals(expected, actual);
65 | }
66 | }
67 |
--------------------------------------------------------------------------------
/fastdoubleparser-dev/src/test/java/ch.randelshofer.fastdoubleparser/ch/randelshofer/fastdoubleparser/FastIntegerMathTest.java:
--------------------------------------------------------------------------------
1 | /*
2 | * @(#)FastIntegerMathTest.java
3 | * Copyright © 2024 Werner Randelshofer, Switzerland. MIT License.
4 | */
5 | package ch.randelshofer.fastdoubleparser;
6 |
7 | import org.junit.jupiter.api.Test;
8 | import org.junit.jupiter.params.ParameterizedTest;
9 | import org.junit.jupiter.params.provider.Arguments;
10 | import org.junit.jupiter.params.provider.MethodSource;
11 |
12 | import java.util.stream.Stream;
13 |
14 | import static org.junit.jupiter.api.Assertions.assertEquals;
15 |
16 | public final class FastIntegerMathTest {
17 | @Test
18 | public void testUnsignedMultiplyHigh() {
19 | long actualHigh = FastIntegerMath.unsignedMultiplyHigh(0x123456789ABCDEF0L, 0x10L);
20 | assertEquals(1L, actualHigh);
21 |
22 | actualHigh = FastIntegerMath.unsignedMultiplyHigh(0x123456789ABCDEF0L, -0x10L);
23 | assertEquals(0x123456789abcdeeeL, actualHigh);
24 | }
25 |
26 | private static Stream splitFloor16testData() {
27 | return Stream.of(// from, to, expectedMid
28 | Arguments.of(0, 0, 0),
29 | Arguments.of(0, 16, 0),
30 | Arguments.of(10, 30, 14),
31 | Arguments.of(0, 32, 16),
32 | Arguments.of(10, 40, 24),
33 | Arguments.of(0, 100, 36),
34 | Arguments.of(1, 101, 37)
35 | );
36 | }
37 |
38 | @ParameterizedTest
39 | @MethodSource("splitFloor16testData")
40 | void splitFloor16specialValues(int from, int to, int expectedMid) {
41 | assert (to - expectedMid) % 16 == 0;
42 | assert expectedMid <= from + (to - from) / 2;
43 | assert expectedMid >= from + (to - from) / 2 - 15;
44 |
45 | assertEquals(expectedMid, FastIntegerMath.splitFloor16(from, to));
46 | }
47 | }
48 |
--------------------------------------------------------------------------------
/fastdoubleparser-dev/src/test/java/ch.randelshofer.fastdoubleparser/ch/randelshofer/fastdoubleparser/JmhBigDecimalScalability.java:
--------------------------------------------------------------------------------
1 | /*
2 | * @(#)JmhBigDecimalScalability.java
3 | * Copyright © 2024 Werner Randelshofer, Switzerland. MIT License.
4 | */
5 | package ch.randelshofer.fastdoubleparser;
6 |
7 | import org.openjdk.jmh.annotations.Benchmark;
8 | import org.openjdk.jmh.annotations.BenchmarkMode;
9 | import org.openjdk.jmh.annotations.Fork;
10 | import org.openjdk.jmh.annotations.Level;
11 | import org.openjdk.jmh.annotations.Measurement;
12 | import org.openjdk.jmh.annotations.Mode;
13 | import org.openjdk.jmh.annotations.OutputTimeUnit;
14 | import org.openjdk.jmh.annotations.Param;
15 | import org.openjdk.jmh.annotations.Scope;
16 | import org.openjdk.jmh.annotations.Setup;
17 | import org.openjdk.jmh.annotations.State;
18 | import org.openjdk.jmh.annotations.Warmup;
19 |
20 | import java.math.BigDecimal;
21 | import java.util.concurrent.TimeUnit;
22 |
23 | import static ch.randelshofer.fastdoubleparser.Strings.repeat;
24 |
25 | /**
26 | * Benchmarks for selected floating point strings.
27 | *
28 | * # JMH version: 1.35
29 | * # VM version: JDK 20-ea, OpenJDK 64-Bit Server VM, 20-ea+27-2213
30 | * # Intel(R) Core(TM) i7-8700B CPU @ 3.20GHz
31 | *
32 | * Benchmark Mode Cnt Score Error Units
33 | * m 24 avgt 2 116.786 ns/op
34 | * m 1 avgt 2 12.473 ns/op
35 | * m 10 avgt 2 20.776 ns/op
36 | * m 100 avgt 2 480.817 ns/op
37 | * m 1000 avgt 2 14832.646 ns/op
38 | * m 10000 avgt 2 1200632.862 ns/op
39 | * m 100000 avgt 2 117587913.424 ns/op
40 | * m 1000000 avgt 2 12027995151.000 ns/op
41 | * m 10000000 avgt 1 1281686999490.000 ns/op
42 | * m 100000000 avgt ? 128_168_699_949_000.000 ns/op
43 | * m 646391315 avgt ? 5_355_166_821_464_850.000 ns/op
44 | *
45 | */
46 |
47 | @Fork(value = 1, jvmArgsAppend = {
48 | "-Xmx16g"
49 | })
50 | @Measurement(iterations = 2)
51 | @Warmup(iterations = 2)
52 | @OutputTimeUnit(TimeUnit.NANOSECONDS)
53 | @BenchmarkMode(Mode.AverageTime)
54 | @State(Scope.Benchmark)
55 | public class JmhBigDecimalScalability {
56 |
57 |
58 | @Param({
59 | // "24"
60 | // , "1"
61 | // , "10"
62 | // , "100"
63 | // , "1000"
64 | // , "10000"
65 | // , "100000"
66 | // , "1000000"
67 | // , "10000000"
68 | "100000000"
69 | , "646391315"// The maximal number non-zero digits in the significand
70 |
71 | })
72 | public int digits;
73 | private String str;
74 |
75 | @Setup(Level.Trial)
76 | public void setUp() {
77 | str = repeat('7', digits);
78 | }
79 |
80 | @Benchmark
81 | public BigDecimal m() {
82 | return new BigDecimal(str);
83 | }
84 | }
85 |
86 |
87 |
88 |
89 |
90 |
--------------------------------------------------------------------------------
/fastdoubleparser-dev/src/test/java/ch.randelshofer.fastdoubleparser/ch/randelshofer/fastdoubleparser/JmhBigIntegerScalability.java:
--------------------------------------------------------------------------------
1 | /*
2 | * @(#)JmhBigIntegerScalability.java
3 | * Copyright © 2024 Werner Randelshofer, Switzerland. MIT License.
4 | */
5 | package ch.randelshofer.fastdoubleparser;
6 |
7 | import org.openjdk.jmh.annotations.Benchmark;
8 | import org.openjdk.jmh.annotations.BenchmarkMode;
9 | import org.openjdk.jmh.annotations.Fork;
10 | import org.openjdk.jmh.annotations.Level;
11 | import org.openjdk.jmh.annotations.Measurement;
12 | import org.openjdk.jmh.annotations.Mode;
13 | import org.openjdk.jmh.annotations.OutputTimeUnit;
14 | import org.openjdk.jmh.annotations.Param;
15 | import org.openjdk.jmh.annotations.Scope;
16 | import org.openjdk.jmh.annotations.Setup;
17 | import org.openjdk.jmh.annotations.State;
18 | import org.openjdk.jmh.annotations.Warmup;
19 |
20 | import java.math.BigInteger;
21 | import java.util.concurrent.TimeUnit;
22 |
23 | import static ch.randelshofer.fastdoubleparser.Strings.repeat;
24 |
25 | /**
26 | * Benchmarks for selected floating point strings.
27 | *
28 | * # JMH version: 1.35
29 | * # VM version: OpenJDK 64-Bit Server VM, Oracle Corporation, 20-ea+22-1594
30 | * # Intel(R) Core(TM) i7-8700B CPU @ 3.20GHz
31 | *
32 | * (digits) Mode Cnt Score Error Units
33 | * m 1 avgt 2 23.866 ns/op
34 | * m 10 avgt 2 64.853 ns/op
35 | * m 100 avgt 2 505.986 ns/op
36 | * m 1000 avgt 2 15322.876 ns/op
37 | * m 10000 avgt 2 1211620.965 ns/op
38 | * m 100000 avgt 2 117030135.430 ns/op
39 | * m 1000000 avgt 2 11883795509.500 ns/op
40 | *
41 | */
42 |
43 | @Fork(value = 1)
44 | @Measurement(iterations = 2)
45 | @Warmup(iterations = 2)
46 | @OutputTimeUnit(TimeUnit.NANOSECONDS)
47 | @BenchmarkMode(Mode.AverageTime)
48 | @State(Scope.Benchmark)
49 | public class JmhBigIntegerScalability {
50 |
51 |
52 | @Param({
53 | "1",
54 | "10",
55 | "100",
56 | "1000",
57 | "10000",
58 | "100000",
59 | "1000000",
60 | "10000000",
61 | "100000000",
62 | "646391315"
63 | })
64 | public int digits;
65 | private String str;
66 |
67 | @Setup(Level.Trial)
68 | public void setUp() {
69 | str = repeat("8808065258", (digits + 9) / 10).substring(0, digits);
70 | }
71 |
72 | @Benchmark
73 | public BigInteger m() {
74 | return new BigInteger(str);
75 | }
76 | }
77 |
78 |
79 |
80 |
81 |
82 |
--------------------------------------------------------------------------------
/fastdoubleparser-dev/src/test/java/ch.randelshofer.fastdoubleparser/ch/randelshofer/fastdoubleparser/JmhComplex.java:
--------------------------------------------------------------------------------
1 | /*
2 | * @(#)JmhComplex.java
3 | * Copyright © 2024 Werner Randelshofer, Switzerland. MIT License.
4 | */
5 | package ch.randelshofer.fastdoubleparser;
6 |
7 | import org.openjdk.jmh.annotations.Benchmark;
8 | import org.openjdk.jmh.annotations.BenchmarkMode;
9 | import org.openjdk.jmh.annotations.Fork;
10 | import org.openjdk.jmh.annotations.Level;
11 | import org.openjdk.jmh.annotations.Measurement;
12 | import org.openjdk.jmh.annotations.Mode;
13 | import org.openjdk.jmh.annotations.OutputTimeUnit;
14 | import org.openjdk.jmh.annotations.Scope;
15 | import org.openjdk.jmh.annotations.Setup;
16 | import org.openjdk.jmh.annotations.State;
17 | import org.openjdk.jmh.annotations.Warmup;
18 |
19 | import java.util.Random;
20 | import java.util.concurrent.TimeUnit;
21 |
22 | /**
23 | * Benchmarks for selected integer strings.
24 | *
25 | * # JMH version: 1.35
26 | * # VM version: JDK 20-ea, OpenJDK 64-Bit Server VM, 20-ea+29-2280
27 | * # Intel(R) Core(TM) i7-8700B CPU @ 3.20GHz
28 | *
29 | * Benchmark Mode Cnt Score Error Units
30 | * JmhComplex.mul avgt 4 1.080 ± 0.117 ns/op
31 | * JmhComplex.mulFma1 avgt 4 0.995 ± 0.042 ns/op
32 | * JmhComplex.mulFma2 avgt 4 0.997 ± 0.028 ns/op
33 | *
34 | */
35 | @Fork(value = 1, jvmArgsAppend = {
36 | "-XX:+UnlockExperimentalVMOptions", "--add-modules", "jdk.incubator.vector"
37 | , "--enable-preview"
38 | , "-Xmx24g"
39 | // , "--add-opens", "java.base/java.math=ALL-UNNAMED"
40 |
41 | // Options for analysis with https://github.com/AdoptOpenJDK/jitwatch
42 | //, "-XX:+UnlockDiagnosticVMOptions"
43 | //, "-Xlog:class+load=info"
44 | //, "-XX:+LogCompilation"
45 | //, "-XX:+PrintAssembly"
46 |
47 | })
48 | @Measurement(iterations = 4)
49 | @Warmup(iterations = 2)
50 | @OutputTimeUnit(TimeUnit.NANOSECONDS)
51 | @BenchmarkMode(Mode.AverageTime)
52 | @State(Scope.Benchmark)
53 | public class JmhComplex {
54 |
55 |
56 | private double ar, ai;
57 | private double br, bi;
58 |
59 | private double rr, ri;
60 |
61 | @Setup(Level.Trial)
62 | public void setUp() {
63 | Random rng = new Random();
64 | ar = rng.nextDouble();
65 | ai = rng.nextDouble();
66 | br = rng.nextDouble();
67 | bi = rng.nextDouble();
68 | }
69 |
70 |
71 | @Benchmark
72 | public void mul() {
73 | double real = ar;
74 | double imag = ai;
75 | rr = real * br - imag * bi;
76 | ri = real * bi + imag * br;
77 | }
78 |
79 | @Benchmark
80 | public void mulFma1() {
81 | double real = ar;
82 | double imag = ai;
83 | rr = real * br - imag * bi;
84 | ri = Math.fma(real, bi, imag * br);
85 | }
86 |
87 | @Benchmark
88 | public void mulFma2() {
89 | double real = ar;
90 | double imag = ai;
91 | rr = Math.fma(real, br, -imag * bi);
92 | ri = Math.fma(real, bi, imag * br);
93 | }
94 |
95 | }
96 |
97 |
98 |
99 |
100 |
101 |
--------------------------------------------------------------------------------
/fastdoubleparser-dev/src/test/java/ch.randelshofer.fastdoubleparser/ch/randelshofer/fastdoubleparser/JmhDoubleScalability.java:
--------------------------------------------------------------------------------
1 | /*
2 | * @(#)JmhDoubleScalability.java
3 | * Copyright © 2024 Werner Randelshofer, Switzerland. MIT License.
4 | */
5 | package ch.randelshofer.fastdoubleparser;
6 |
7 | import org.openjdk.jmh.annotations.Benchmark;
8 | import org.openjdk.jmh.annotations.BenchmarkMode;
9 | import org.openjdk.jmh.annotations.Fork;
10 | import org.openjdk.jmh.annotations.Level;
11 | import org.openjdk.jmh.annotations.Measurement;
12 | import org.openjdk.jmh.annotations.Mode;
13 | import org.openjdk.jmh.annotations.OutputTimeUnit;
14 | import org.openjdk.jmh.annotations.Param;
15 | import org.openjdk.jmh.annotations.Scope;
16 | import org.openjdk.jmh.annotations.Setup;
17 | import org.openjdk.jmh.annotations.State;
18 | import org.openjdk.jmh.annotations.Warmup;
19 |
20 | import java.util.concurrent.TimeUnit;
21 |
22 | import static ch.randelshofer.fastdoubleparser.Strings.repeat;
23 |
24 | /**
25 | * Benchmarks for selected floating point strings.
26 | *
27 | * # JMH version: 1.35
28 | * # VM version: JDK 20-ea, OpenJDK 64-Bit Server VM, 20-ea+27-2213
29 | * # Intel(R) Core(TM) i7-8700B CPU @ 3.20GHz
30 | *
31 | * (digits) Mode Cnt Score Error Units
32 | * m 1 avgt 2 13.594 ns/op
33 | * m 10 avgt 2 22.188 ns/op
34 | * m 100 avgt 2 276.957 ns/op
35 | * m 1000 avgt 2 440.983 ns/op
36 | * m 10000 avgt 2 4426.218 ns/op
37 | * m 100000 avgt 2 47251.366 ns/op
38 | * m 1000000 avgt 2 469427.913 ns/op
39 | * m 10000000 avgt 2 4821577.118 ns/op
40 | * m 100000000 avgt 2 48427968.251 ns/op
41 | * m 1000000000 avgt 2 490691954.952 ns/op
42 | * m 2147483643 avgt 2 1040876939.400 ns/op
43 | *
44 | */
45 |
46 | @Fork(value = 1, jvmArgsAppend = {
47 | "-XX:+UnlockExperimentalVMOptions", "--add-modules", "jdk.incubator.vector"
48 | , "--enable-preview"
49 | , "-Xmx16g"
50 |
51 | // ,"-XX:+UnlockDiagnosticVMOptions", "-XX:PrintAssemblyOptions=intel", "-XX:CompileCommand=print,ch/randelshofer/fastdoubleparser/FastDoubleParser.*"
52 |
53 | })
54 | @Measurement(iterations = 2)
55 | @Warmup(iterations = 2)
56 | @OutputTimeUnit(TimeUnit.NANOSECONDS)
57 | @BenchmarkMode(Mode.AverageTime)
58 | @State(Scope.Benchmark)
59 | public class JmhDoubleScalability {
60 |
61 |
62 | @Param({
63 | "24" // Double.toString() never produces more than 24 characters
64 | , "1"
65 | , "10"
66 | , "100"
67 | , "1000"
68 | , "10000"
69 | , "100000"
70 | , "1000000"
71 | , "10000000"
72 | , "100000000"
73 | , "1000000000"
74 | , "2147483643" // Integer.MAX_VALUE - 4 = the largest support array size
75 | })
76 | public int digits;
77 | private String str;
78 |
79 | @Setup(Level.Trial)
80 | public void setUp() {
81 | str = repeat('7', digits);
82 | }
83 |
84 | @Benchmark
85 | public double m() {
86 | return Double.valueOf(str);
87 | }
88 | }
--------------------------------------------------------------------------------
/fastdoubleparser-dev/src/test/java/ch.randelshofer.fastdoubleparser/ch/randelshofer/fastdoubleparser/JmhFastDoubleMath.java:
--------------------------------------------------------------------------------
1 | /*
2 | * @(#)JmhFastDoubleMath.java
3 | * Copyright © 2024 Werner Randelshofer, Switzerland. MIT License.
4 | */
5 | package ch.randelshofer.fastdoubleparser;
6 |
7 |
8 | import org.openjdk.jmh.annotations.Benchmark;
9 | import org.openjdk.jmh.annotations.BenchmarkMode;
10 | import org.openjdk.jmh.annotations.Fork;
11 | import org.openjdk.jmh.annotations.Measurement;
12 | import org.openjdk.jmh.annotations.Mode;
13 | import org.openjdk.jmh.annotations.OutputTimeUnit;
14 | import org.openjdk.jmh.annotations.Scope;
15 | import org.openjdk.jmh.annotations.Setup;
16 | import org.openjdk.jmh.annotations.State;
17 | import org.openjdk.jmh.annotations.Warmup;
18 |
19 | import java.util.Random;
20 | import java.util.concurrent.TimeUnit;
21 |
22 | /**
23 | *
24 | * # JMH version: 1.36
25 | * # VM version: JDK 20.0.1, OpenJDK 64-Bit Server VM, 20.0.1+9-29
26 | * # Intel(R) Core(TM) i7-8700B CPU @ 3.20GHz SIMD-256
27 | *
28 | * Benchmark Mode Cnt Score Error Units
29 | * JmhFastDoubleMath.tryHexFloatToDoubleTruncated avgt 4 2.939 ± 0.427 ns/op
30 | */
31 | @Fork(value = 1, jvmArgsAppend = {"-ea"})
32 | @Measurement(iterations = 4)
33 | @Warmup(iterations = 2)
34 | @OutputTimeUnit(TimeUnit.NANOSECONDS)
35 | @BenchmarkMode(Mode.AverageTime)
36 | @State(Scope.Benchmark)
37 | public class JmhFastDoubleMath {
38 | private boolean negative;
39 | private long significand;
40 | private int exponent;
41 |
42 | @Setup
43 | public void prepare() {
44 | Random rng = new Random();
45 | negative = rng.nextBoolean();
46 | significand = rng.nextLong();
47 | exponent = rng.nextInt(Double.MIN_EXPONENT, Double.MAX_EXPONENT);
48 | }
49 |
50 | @Benchmark
51 | public double tryHexFloatToDoubleTruncated() {
52 | double v = FastDoubleMath.tryHexFloatToDoubleTruncated(negative, significand, exponent, false, 0);
53 | assert !Double.isNaN(v);
54 | return v;
55 | }
56 | }
57 |
--------------------------------------------------------------------------------
/fastdoubleparser-dev/src/test/java/ch.randelshofer.fastdoubleparser/ch/randelshofer/fastdoubleparser/JmhFastFloatMath.java:
--------------------------------------------------------------------------------
1 | /*
2 | * @(#)JmhFastFloatMath.java
3 | * Copyright © 2024 Werner Randelshofer, Switzerland. MIT License.
4 | */
5 | package ch.randelshofer.fastdoubleparser;
6 |
7 |
8 | import org.openjdk.jmh.annotations.Benchmark;
9 | import org.openjdk.jmh.annotations.BenchmarkMode;
10 | import org.openjdk.jmh.annotations.Fork;
11 | import org.openjdk.jmh.annotations.Measurement;
12 | import org.openjdk.jmh.annotations.Mode;
13 | import org.openjdk.jmh.annotations.OutputTimeUnit;
14 | import org.openjdk.jmh.annotations.Scope;
15 | import org.openjdk.jmh.annotations.Setup;
16 | import org.openjdk.jmh.annotations.State;
17 | import org.openjdk.jmh.annotations.Warmup;
18 |
19 | import java.util.Random;
20 | import java.util.concurrent.TimeUnit;
21 |
22 | /**
23 | *
24 | * # JMH version: 1.36
25 | * # VM version: JDK 20.0.1, OpenJDK 64-Bit Server VM, 20.0.1+9-29
26 | * # Intel(R) Core(TM) i7-8700B CPU @ 3.20GHz SIMD-256
27 | *
28 | * Benchmark Mode Cnt Score Error Units
29 | * JmhFastFloatMath.tryHexFloatToFloatTruncated avgt 4 2.531 ± 0.009 ns/op
30 | */
31 | @Fork(value = 1, jvmArgsAppend = {"-ea"})
32 | @Measurement(iterations = 4)
33 | @Warmup(iterations = 2)
34 | @OutputTimeUnit(TimeUnit.NANOSECONDS)
35 | @BenchmarkMode(Mode.AverageTime)
36 | @State(Scope.Benchmark)
37 | public class JmhFastFloatMath {
38 | private boolean negative;
39 | private long significand;
40 | private int exponent;
41 |
42 | @Setup
43 | public void prepare() {
44 | Random rng = new Random();
45 | negative = rng.nextBoolean();
46 | significand = rng.nextLong();
47 | exponent = rng.nextInt(Float.MIN_EXPONENT, Float.MAX_EXPONENT);
48 | }
49 |
50 | @Benchmark
51 | public float tryHexFloatToFloatTruncated() {
52 | float v = FastFloatMath.tryHexFloatToFloatTruncated(negative, significand, exponent, false, 0);
53 | assert !Float.isNaN(v);
54 | return v;
55 | }
56 | }
57 |
--------------------------------------------------------------------------------
/fastdoubleparser-dev/src/test/java/ch.randelshofer.fastdoubleparser/ch/randelshofer/fastdoubleparser/JmhFloat.java:
--------------------------------------------------------------------------------
1 | /*
2 | * @(#)JmhFloat.java
3 | * Copyright © 2024 Werner Randelshofer, Switzerland. MIT License.
4 | */
5 | package ch.randelshofer.fastdoubleparser;
6 |
7 | import org.openjdk.jmh.annotations.Benchmark;
8 | import org.openjdk.jmh.annotations.BenchmarkMode;
9 | import org.openjdk.jmh.annotations.Fork;
10 | import org.openjdk.jmh.annotations.Measurement;
11 | import org.openjdk.jmh.annotations.Mode;
12 | import org.openjdk.jmh.annotations.OutputTimeUnit;
13 | import org.openjdk.jmh.annotations.Param;
14 | import org.openjdk.jmh.annotations.Scope;
15 | import org.openjdk.jmh.annotations.State;
16 | import org.openjdk.jmh.annotations.Warmup;
17 |
18 | import java.util.concurrent.TimeUnit;
19 |
20 | /**
21 | * Benchmarks for selected floating point strings.
22 | *
23 | * # JMH version: 1.28
24 | * # VM version: JDK 17, OpenJDK 64-Bit Server VM, 17+35-2724
25 | * # Intel(R) Core(TM) i7-8700B CPU @ 3.20GHz
26 | *
27 | * Benchmark (str) Mode Cnt Score Error Units
28 | * m 0 avgt 2 9.607 ns/op
29 | * m 365 avgt 2 15.991 ns/op
30 | * m 10.1 avgt 2 18.379 ns/op
31 | * m 3.1415927 avgt 2 77.434 ns/op
32 | * m 1.6162552E-35 avgt 2 89.729 ns/op
33 | * m 0x1.57bd4ep-116 avgt 2 290.443 ns/op
34 | *
35 | */
36 |
37 | @Fork(value = 1)
38 | @Measurement(iterations = 2)
39 | @Warmup(iterations = 2)
40 | @OutputTimeUnit(TimeUnit.NANOSECONDS)
41 | @BenchmarkMode(Mode.AverageTime)
42 | @State(Scope.Benchmark)
43 | public class JmhFloat {
44 |
45 |
46 | @Param({
47 | "0",
48 | "365",
49 | "10.1",
50 | "3.1415927",
51 | "1.6162552E-35",
52 | "0x1.57bd4ep-116"
53 | })
54 | public String str;
55 |
56 | @Benchmark
57 | public float m() {
58 | return Float.parseFloat(str);
59 | }
60 | }
61 |
62 |
63 |
64 |
65 |
66 |
--------------------------------------------------------------------------------
/fastdoubleparser-dev/src/test/java/ch.randelshofer.fastdoubleparser/ch/randelshofer/fastdoubleparser/JmhJavaBigDecimalFromByteArrayScalability.java:
--------------------------------------------------------------------------------
1 | /*
2 | * @(#)JmhJavaBigDecimalFromByteArrayScalability.java
3 | * Copyright © 2024 Werner Randelshofer, Switzerland. MIT License.
4 | */
5 | package ch.randelshofer.fastdoubleparser;
6 |
7 | import org.openjdk.jmh.annotations.Benchmark;
8 | import org.openjdk.jmh.annotations.BenchmarkMode;
9 | import org.openjdk.jmh.annotations.Fork;
10 | import org.openjdk.jmh.annotations.Level;
11 | import org.openjdk.jmh.annotations.Measurement;
12 | import org.openjdk.jmh.annotations.Mode;
13 | import org.openjdk.jmh.annotations.OutputTimeUnit;
14 | import org.openjdk.jmh.annotations.Param;
15 | import org.openjdk.jmh.annotations.Scope;
16 | import org.openjdk.jmh.annotations.Setup;
17 | import org.openjdk.jmh.annotations.State;
18 | import org.openjdk.jmh.annotations.Warmup;
19 |
20 | import java.math.BigDecimal;
21 | import java.nio.charset.StandardCharsets;
22 | import java.util.concurrent.TimeUnit;
23 |
24 | import static ch.randelshofer.fastdoubleparser.Strings.repeatStringBuilder;
25 |
26 | /**
27 | * Benchmarks for selected floating point strings.
28 | *
29 | * # JMH version: 1.37
30 | * # VM version: JDK 21-ea, OpenJDK 64-Bit Server VM, 21-ea+20-1677
31 | * # Intel(R) Core(TM) i7-8700B CPU @ 3.20GHz
32 | *
33 | * (digits) Mode Cnt Score Error Units
34 | * m 1 avgt 10.688 ns/op
35 | * m 10 avgt 19.903 ns/op
36 | * m 100 avgt 551.403 ns/op
37 | * m 1000 avgt 5999.290 ns/op
38 | * m 10000 avgt 221929.429 ns/op
39 | * m 100000 avgt 5881864.021 ns/op
40 | * m 1000000 avgt 110878102.879 ns/op
41 | * m 10000000 avgt 1649224533.143 ns/op
42 | * m 100000000 avgt 25932859264.000 ns/op
43 | *
44 | */
45 |
46 | @Fork(value = 1, jvmArgsAppend = {
47 | "-XX:+UnlockExperimentalVMOptions", "--add-modules", "jdk.incubator.vector"
48 | , "--enable-preview"
49 | , "-Xmx24g"
50 |
51 | // ,"-XX:+UnlockDiagnosticVMOptions", "-XX:PrintAssemblyOptions=intel", "-XX:CompileCommand=print,ch/randelshofer/fastdoubleparser/JavaBigDecimalParser.*"
52 |
53 | })
54 | @Measurement(iterations = 1)
55 | @Warmup(iterations = 1)
56 | @OutputTimeUnit(TimeUnit.NANOSECONDS)
57 | @BenchmarkMode(Mode.AverageTime)
58 | @State(Scope.Benchmark)
59 | public class JmhJavaBigDecimalFromByteArrayScalability {
60 | @Param({
61 | "1"
62 | , "10"
63 | , "100"
64 | , "1000"
65 | , "10000"
66 | , "100000"
67 | , "1000000"
68 | , "10000000"
69 | , "100000000"
70 | // , "646391315"// The maximal number of non-zero digits in the significand
71 | })
72 |
73 | public int digits;
74 | private byte[] input;
75 |
76 | @Setup(Level.Trial)
77 | public void setUp() {
78 | StringBuilder str = repeatStringBuilder("9", digits + 1);
79 | str.setCharAt(digits / 3, '.');
80 | input = str.toString().getBytes(StandardCharsets.UTF_8);
81 | }
82 |
83 |
84 | @Benchmark
85 | public BigDecimal m() {
86 | return JavaBigDecimalParser.parseBigDecimal(input);
87 | }
88 | }
--------------------------------------------------------------------------------
/fastdoubleparser-dev/src/test/java/ch.randelshofer.fastdoubleparser/ch/randelshofer/fastdoubleparser/JmhJavaBigDecimalFromCharSequenceScalability.java:
--------------------------------------------------------------------------------
1 | /*
2 | * @(#)JmhJavaBigDecimalFromCharSequenceScalability.java
3 | * Copyright © 2024 Werner Randelshofer, Switzerland. MIT License.
4 | */
5 | package ch.randelshofer.fastdoubleparser;
6 |
7 | import org.openjdk.jmh.annotations.Benchmark;
8 | import org.openjdk.jmh.annotations.BenchmarkMode;
9 | import org.openjdk.jmh.annotations.Fork;
10 | import org.openjdk.jmh.annotations.Level;
11 | import org.openjdk.jmh.annotations.Measurement;
12 | import org.openjdk.jmh.annotations.Mode;
13 | import org.openjdk.jmh.annotations.OutputTimeUnit;
14 | import org.openjdk.jmh.annotations.Param;
15 | import org.openjdk.jmh.annotations.Scope;
16 | import org.openjdk.jmh.annotations.Setup;
17 | import org.openjdk.jmh.annotations.State;
18 | import org.openjdk.jmh.annotations.Warmup;
19 |
20 | import java.math.BigDecimal;
21 | import java.util.concurrent.TimeUnit;
22 |
23 | import static ch.randelshofer.fastdoubleparser.Strings.repeatStringBuilder;
24 |
25 | /**
26 | * Benchmarks for selected floating point strings.
27 | *
28 | * # JMH version: 1.37
29 | * # VM version: JDK 21.0.1, OpenJDK 64-Bit Server VM, 21.0.1+12-LTS
30 | * # Intel(R) Core(TM) i7-8700B CPU @ 3.20GHz
31 | *
32 | * (digits) Mode Cnt Score Error Units
33 | * m 1 avgt 11.760 ns/op
34 | * m 10 avgt 24.240 ns/op
35 | * m 100 avgt 641.794 ns/op
36 | * m 1000 avgt 6619.499 ns/op
37 | * m 10000 avgt 220716.603 ns/op
38 | * m 100000 avgt 5959907.182 ns/op
39 | * m 1000000 avgt 112629492.933 ns/op
40 | * m 10000000 avgt 1719489749.000 ns/op
41 | * m 100000000 avgt 28698919868.000 ns/op
42 | *
43 | */
44 |
45 | @Fork(value = 1, jvmArgsAppend = {
46 | "-XX:+UnlockExperimentalVMOptions", "--add-modules", "jdk.incubator.vector"
47 | , "--enable-preview"
48 | //, "-XX:+UnlockDiagnosticVMOptions"
49 | // "-XX:PrintAssemblyOptions=intel", "-XX:CompileCommand=print,ch/randelshofer/fastdoubleparser/*.*"
50 | //, "-XX:-PrintInlining"
51 |
52 | })
53 | @Measurement(iterations = 1)
54 | @Warmup(iterations = 1)
55 | @OutputTimeUnit(TimeUnit.NANOSECONDS)
56 | @BenchmarkMode(Mode.AverageTime)
57 | @State(Scope.Benchmark)
58 | public class JmhJavaBigDecimalFromCharSequenceScalability {
59 |
60 |
61 | @Param({
62 | "1"
63 | , "10"
64 | , "100"
65 | , "1000"
66 | , "10000"
67 | , "100000"
68 | , "1000000"
69 | , "10000000"
70 | , "100000000"
71 | // , "646391315"// The maximal number of non-zero digits in the significand
72 | })
73 | public int digits;
74 | private String input;
75 |
76 | @Setup(Level.Trial)
77 | public void setUp() {
78 | StringBuilder str = repeatStringBuilder("9", digits + 1);
79 | str.setCharAt(digits / 3, '.');
80 | input = str.toString();
81 | }
82 |
83 | @Benchmark
84 | public BigDecimal m() {
85 | return JavaBigDecimalParser.parseBigDecimal(input);
86 | }
87 |
88 | }
89 |
90 |
91 |
92 |
93 |
94 |
--------------------------------------------------------------------------------
/fastdoubleparser-dev/src/test/java/ch.randelshofer.fastdoubleparser/ch/randelshofer/fastdoubleparser/JmhJavaDoubleFromByteArrayEmpirical.java:
--------------------------------------------------------------------------------
1 | /*
2 | * @(#)JmhJavaDoubleFromByteArrayEmpirical.java
3 | * Copyright © 2024 Werner Randelshofer, Switzerland. MIT License.
4 | */
5 | package ch.randelshofer.fastdoubleparser;
6 |
7 | import org.openjdk.jmh.annotations.Benchmark;
8 | import org.openjdk.jmh.annotations.BenchmarkMode;
9 | import org.openjdk.jmh.annotations.Fork;
10 | import org.openjdk.jmh.annotations.Measurement;
11 | import org.openjdk.jmh.annotations.Mode;
12 | import org.openjdk.jmh.annotations.OutputTimeUnit;
13 | import org.openjdk.jmh.annotations.Param;
14 | import org.openjdk.jmh.annotations.Scope;
15 | import org.openjdk.jmh.annotations.Setup;
16 | import org.openjdk.jmh.annotations.State;
17 | import org.openjdk.jmh.annotations.Warmup;
18 |
19 | import java.nio.charset.StandardCharsets;
20 | import java.util.concurrent.TimeUnit;
21 |
22 | /**
23 | * Benchmarks for selected floating point strings.
24 | *
25 | * # JMH version: 1.36
26 | * # VM version: JDK 20, OpenJDK 64-Bit Server VM, 20+36-2344
27 | * # Intel(R) Core(TM) i7-8700B CPU @ 3.20GHz
28 | * (str) Mode Cnt Score Error Units
29 | * m 0 avgt 4 4.057 ± 0.126 ns/op
30 | * m 365 avgt 4 9.017 ± 0.093 ns/op
31 | * m 10.1 avgt 4 12.221 ± 1.717 ns/op
32 | * m -1.2345678901234568E-121 avgt 4 27.247 ± 0.221 ns/op
33 | * m -0.29235596393453456 avgt 4 19.884 ± 0.300 ns/op
34 | * m 0x123.456789abcdep123 avgt 4 22.941 ± 0.275 ns/op
35 | *
36 | */
37 | @Fork(value = 1, jvmArgsAppend = {
38 | "-XX:+UnlockExperimentalVMOptions", "--add-modules", "jdk.incubator.vector",
39 | "--enable-preview",
40 |
41 | // Options for analysis with https://github.com/AdoptOpenJDK/jitwatch
42 | //"-XX:+UnlockDiagnosticVMOptions",
43 | //"-Xlog:class+load=info",
44 | //"-XX:+LogCompilation",
45 | //"-XX:+PrintAssembly"
46 | })
47 | @Measurement(iterations = 4)
48 | @Warmup(iterations = 2)
49 | @OutputTimeUnit(TimeUnit.NANOSECONDS)
50 | @BenchmarkMode(Mode.AverageTime)
51 | @State(Scope.Benchmark)
52 | public class JmhJavaDoubleFromByteArrayEmpirical {
53 | @Param({
54 | "0"
55 | , "365"
56 | , "10.1"
57 | , "-1.2345678901234568E-121"
58 | , "-0.29235596393453456"
59 | , "0x123.456789abcdep123"
60 | })
61 | public String str;
62 | private byte[] byteArray;
63 |
64 | @Setup
65 | public void prepare() {
66 | byteArray = str.getBytes(StandardCharsets.ISO_8859_1);
67 | }
68 |
69 | @Benchmark
70 | public double m() {
71 | return JavaDoubleParser.parseDouble(byteArray);
72 | }
73 | }
74 |
75 |
76 |
--------------------------------------------------------------------------------
/fastdoubleparser-dev/src/test/java/ch.randelshofer.fastdoubleparser/ch/randelshofer/fastdoubleparser/JmhJavaDoubleFromCharSequenceEmpirical.java:
--------------------------------------------------------------------------------
1 | /*
2 | * @(#)JmhJavaDoubleFromCharSequenceEmpirical.java
3 | * Copyright © 2024 Werner Randelshofer, Switzerland. MIT License.
4 | */
5 | package ch.randelshofer.fastdoubleparser;
6 |
7 | import org.openjdk.jmh.annotations.Benchmark;
8 | import org.openjdk.jmh.annotations.BenchmarkMode;
9 | import org.openjdk.jmh.annotations.Fork;
10 | import org.openjdk.jmh.annotations.Measurement;
11 | import org.openjdk.jmh.annotations.Mode;
12 | import org.openjdk.jmh.annotations.OutputTimeUnit;
13 | import org.openjdk.jmh.annotations.Param;
14 | import org.openjdk.jmh.annotations.Scope;
15 | import org.openjdk.jmh.annotations.State;
16 | import org.openjdk.jmh.annotations.Warmup;
17 |
18 | import java.util.concurrent.TimeUnit;
19 |
20 | /**
21 | * Benchmarks for selected floating point strings.
22 | *
23 | * # JMH version: 1.35
24 | * # VM version: JDK 20-ea, OpenJDK 64-Bit Server VM, 20-ea+27-2213
25 | * # Intel(R) Core(TM) i7-8700B CPU @ 3.20GHz
26 | *
27 | * (str) Mode Cnt Score Error Units
28 | * m 0 avgt 2 5.131 ns/op
29 | * m 365 avgt 2 12.730 ns/op
30 | * m 10.1 avgt 2 14.839 ns/op
31 | * m -1.2345678901234568E-121 avgt 2 34.010 ns/op
32 | * m -0.29235596393453456 avgt 2 25.021 ns/op
33 | * m -0x123.456789abcdep-123 avgt 2 28.997 ns/op
34 | * m 95773983001708984375E-308 avgt 2 9455.148 ns/op
35 | *
36 | */
37 | @Fork(value = 1, jvmArgsAppend = {"-XX:+UnlockExperimentalVMOptions", "--add-modules", "jdk.incubator.vector"
38 | , "--enable-preview",
39 |
40 | // Options for analysis with https://github.com/AdoptOpenJDK/jitwatch
41 | //"-XX:+UnlockDiagnosticVMOptions",
42 | //"-Xlog:class+load=info",
43 | //"-XX:+LogCompilation",
44 | //"-XX:+PrintAssembly"
45 | })
46 | @Measurement(iterations = 2)
47 | @Warmup(iterations = 2)
48 | @OutputTimeUnit(TimeUnit.NANOSECONDS)
49 | @BenchmarkMode(Mode.AverageTime)
50 | @State(Scope.Benchmark)
51 | public class JmhJavaDoubleFromCharSequenceEmpirical {
52 | @Param({
53 | "0"
54 | , "365"
55 | , "10.1"
56 | , "-1.2345678901234568E-121"
57 | , "-0.29235596393453456"
58 | , "-0x123.456789abcdep-123"
59 | , "2.22507385850720212418870147920222032907240528279439037814303133837435107319244194686754406432563881851382188218502438069999947733013005649884107791928741341929297200970481951993067993290969042784064731682041565926728632933630474670123316852983422152744517260835859654566319282835244787787799894310779783833699159288594555213714181128458251145584319223079897504395086859412457230891738946169368372321191373658977977723286698840356390251044443035457396733706583981055420456693824658413747607155981176573877626747665912387199931904006317334709003012790188175203447190250028061277777916798391090578584006464715943810511489154282775041174682194133952466682503431306181587829379004205392375072083366693241580002758391118854188641513168478436313080237596295773983001708984375E-308"
60 |
61 |
62 | })
63 | public String str;
64 |
65 | @Benchmark
66 | public double m() {
67 | return JavaDoubleParser.parseDouble(str);
68 | }
69 | }
70 |
71 |
72 |
--------------------------------------------------------------------------------
/fastdoubleparser-dev/src/test/java/ch.randelshofer.fastdoubleparser/ch/randelshofer/fastdoubleparser/JmhJavaFloatFromCharSequence.java:
--------------------------------------------------------------------------------
1 | /*
2 | * @(#)JmhJavaFloatFromCharSequence.java
3 | * Copyright © 2024 Werner Randelshofer, Switzerland. MIT License.
4 | */
5 | package ch.randelshofer.fastdoubleparser;
6 |
7 | import org.openjdk.jmh.annotations.Benchmark;
8 | import org.openjdk.jmh.annotations.BenchmarkMode;
9 | import org.openjdk.jmh.annotations.Fork;
10 | import org.openjdk.jmh.annotations.Measurement;
11 | import org.openjdk.jmh.annotations.Mode;
12 | import org.openjdk.jmh.annotations.OutputTimeUnit;
13 | import org.openjdk.jmh.annotations.Param;
14 | import org.openjdk.jmh.annotations.Scope;
15 | import org.openjdk.jmh.annotations.Setup;
16 | import org.openjdk.jmh.annotations.State;
17 | import org.openjdk.jmh.annotations.Warmup;
18 |
19 | import java.util.concurrent.TimeUnit;
20 |
21 | /**
22 | * Benchmarks for selected floating point strings.
23 | *
24 | * # JMH version: 1.28
25 | * # VM version: JDK 16, OpenJDK 64-Bit Server VM, 16+36-2231
26 | * # Intel(R) Core(TM) i7-8700B CPU @ 3.20GHz
27 | *
28 | * Benchmark (str) Mode Cnt Score Error Units
29 | * m 0 avgt 2 6.570 ns/op
30 | * m 365 avgt 2 14.525 ns/op
31 | * m 10.1 avgt 2 16.646 ns/op
32 | * m 3.1415927 avgt 2 24.022 ns/op
33 | * m 1.6162552E-35 avgt 2 28.465 ns/op
34 | * m 0x1.57bd4ep-116 avgt 2 336.391 ns/op
35 | *
36 | */
37 |
38 | @Fork(value = 1)
39 | @Measurement(iterations = 2)
40 | @Warmup(iterations = 2)
41 | @OutputTimeUnit(TimeUnit.NANOSECONDS)
42 | @BenchmarkMode(Mode.AverageTime)
43 | @State(Scope.Benchmark)
44 | public class JmhJavaFloatFromCharSequence {
45 |
46 |
47 | @Param({
48 | "0",
49 | "365",
50 | "10.1",
51 | "3.14159267",
52 | "1.6162552E-35",
53 | "0x1.57bd4ep-116"
54 | })
55 | public String str;
56 |
57 | @Setup
58 | public void setup() {
59 | System.out.println(str + "=" + JavaFloatParser.parseFloat(str));
60 | }
61 |
62 | @Benchmark
63 | public float m() {
64 | return JavaFloatParser.parseFloat(str);
65 | }
66 | }
67 |
68 |
69 |
70 |
71 |
72 |
--------------------------------------------------------------------------------
/fastdoubleparser-dev/src/test/java/ch.randelshofer.fastdoubleparser/ch/randelshofer/fastdoubleparser/JmhJsonDoubleFromByteArray.java:
--------------------------------------------------------------------------------
1 | /*
2 | * @(#)JmhJsonDoubleFromByteArray.java
3 | * Copyright © 2024 Werner Randelshofer, Switzerland. MIT License.
4 | */
5 | package ch.randelshofer.fastdoubleparser;
6 |
7 | import org.openjdk.jmh.annotations.Benchmark;
8 | import org.openjdk.jmh.annotations.BenchmarkMode;
9 | import org.openjdk.jmh.annotations.Fork;
10 | import org.openjdk.jmh.annotations.Measurement;
11 | import org.openjdk.jmh.annotations.Mode;
12 | import org.openjdk.jmh.annotations.OutputTimeUnit;
13 | import org.openjdk.jmh.annotations.Param;
14 | import org.openjdk.jmh.annotations.Scope;
15 | import org.openjdk.jmh.annotations.Setup;
16 | import org.openjdk.jmh.annotations.State;
17 | import org.openjdk.jmh.annotations.Warmup;
18 |
19 | import java.nio.charset.StandardCharsets;
20 | import java.util.concurrent.TimeUnit;
21 |
22 | /**
23 | * Benchmarks for selected floating point strings.
24 | *
25 | * # JMH version: 1.35
26 | * # VM version: JDK 19-ea, OpenJDK 64-Bit Server VM, 20-ea+22-1594
27 | * # Intel(R) Core(TM) i7-8700B CPU @ 3.20GHz
28 | *
29 | * (str) Mode Cnt Score Error Units
30 | * m 0 avgt 5 4.719 ± 1.005 ns/op
31 | * m 365 avgt 5 11.517 ± 0.119 ns/op
32 | * m 10.1 avgt 5 13.060 ± 0.101 ns/op
33 | * m 123.45678901234567e123 avgt 5 28.984 ± 0.207 ns/op
34 | * m 123.4567890123456789 avgt 5 24.307 ± 0.358 ns/op
35 | * m 123.4567890123456789e123 avgt 5 31.024 ± 0.190 ns/op
36 | * m -0.29235596393453456 avgt 5 20.588 ± 0.077 ns/op
37 | *
38 | */
39 | @Fork(value = 1, jvmArgsAppend = {
40 | "-XX:+UnlockExperimentalVMOptions", "--add-modules", "jdk.incubator.vector"
41 | , "--enable-preview"
42 | , "-XX:+UnlockDiagnosticVMOptions"
43 | // "-XX:PrintAssemblyOptions=intel", "-XX:CompileCommand=print,ch/randelshofer/fastdoubleparser/*.*"
44 | //,"-XX:+PrintInlining"
45 |
46 | })
47 | @Measurement(iterations = 5)
48 | @Warmup(iterations = 2)
49 | @OutputTimeUnit(TimeUnit.NANOSECONDS)
50 | @BenchmarkMode(Mode.AverageTime)
51 | @State(Scope.Benchmark)
52 | public class JmhJsonDoubleFromByteArray {
53 | @Param({
54 | "0"
55 | , "365"
56 | , "10.1"
57 | , "123.45678901234567e123"
58 | , "123.4567890123456789"
59 | , "123.4567890123456789e123"
60 | , "-0.29235596393453456"
61 | })
62 | public String str;
63 | private byte[] byteArray;
64 |
65 | @Setup
66 | public void prepare() {
67 | byteArray = str.getBytes(StandardCharsets.ISO_8859_1);
68 | }
69 |
70 | @Benchmark
71 | public double m() {
72 | return JsonDoubleParser.parseDouble(byteArray);
73 | }
74 | }
75 |
76 |
77 |
--------------------------------------------------------------------------------
/fastdoubleparser-dev/src/test/java/ch.randelshofer.fastdoubleparser/ch/randelshofer/fastdoubleparser/JmhJsonDoubleFromCharArray.java:
--------------------------------------------------------------------------------
1 | /*
2 | * @(#)JmhJsonDoubleFromCharArray.java
3 | * Copyright © 2024 Werner Randelshofer, Switzerland. MIT License.
4 | */
5 | package ch.randelshofer.fastdoubleparser;
6 |
7 | import org.openjdk.jmh.annotations.Benchmark;
8 | import org.openjdk.jmh.annotations.BenchmarkMode;
9 | import org.openjdk.jmh.annotations.Fork;
10 | import org.openjdk.jmh.annotations.Measurement;
11 | import org.openjdk.jmh.annotations.Mode;
12 | import org.openjdk.jmh.annotations.OutputTimeUnit;
13 | import org.openjdk.jmh.annotations.Param;
14 | import org.openjdk.jmh.annotations.Scope;
15 | import org.openjdk.jmh.annotations.Setup;
16 | import org.openjdk.jmh.annotations.State;
17 | import org.openjdk.jmh.annotations.Warmup;
18 |
19 | import java.util.concurrent.TimeUnit;
20 |
21 | /**
22 | * Benchmarks for selected floating point strings.
23 | *
24 | * # JMH version: 1.35
25 | * # VM version: JDK 20-ea, OpenJDK 64-Bit Server VM, 20-ea+27-2213
26 | * # Intel(R) Core(TM) i7-8700B CPU @ 3.20GHz
27 | *
28 | * (str) Mode Cnt Score Error Units
29 | * m 0 avgt 5 3.440 ± 0.113 ns/op
30 | * m 365 avgt 5 10.405 ± 0.162 ns/op
31 | * m 10.1 avgt 5 12.453 ± 1.461 ns/op
32 | * m -1.2345678901234568E-121 avgt 5 26.581 ± 0.256 ns/op
33 | * m -0.29235596393453456 avgt 5 18.163 ± 0.140 ns/op
34 | *
35 | */
36 | @Fork(value = 1, jvmArgsAppend = {
37 | "--enable-preview",
38 |
39 | // Options for analysis with https://github.com/AdoptOpenJDK/jitwatch
40 | // "-XX:+UnlockDiagnosticVMOptions",
41 | // "-Xlog:class+load=info",
42 | // "-XX:+LogCompilation",
43 | // "-XX:+PrintAssembly"
44 |
45 | })
46 | @Measurement(iterations = 5)
47 | @Warmup(iterations = 2)
48 | @OutputTimeUnit(TimeUnit.NANOSECONDS)
49 | @BenchmarkMode(Mode.AverageTime)
50 | @State(Scope.Benchmark)
51 | public class JmhJsonDoubleFromCharArray {
52 | @Param({
53 | "0"
54 | , "365"
55 | , "10.1"
56 | , "-1.2345678901234568E-121"
57 | , "-0.29235596393453456"
58 | })
59 | public String str;
60 | private char[] charArray;
61 |
62 | @Setup
63 | public void prepare() {
64 | charArray = str.toCharArray();
65 | }
66 |
67 | @Benchmark
68 | public double m() {
69 | return JsonDoubleParser.parseDouble(charArray);
70 | }
71 | }
72 |
73 |
74 |
--------------------------------------------------------------------------------
/fastdoubleparser-dev/src/test/java/ch.randelshofer.fastdoubleparser/ch/randelshofer/fastdoubleparser/JmhSplitFloor16.java:
--------------------------------------------------------------------------------
1 | /*
2 | * @(#)JmhSplitFloor16.java
3 | * Copyright © 2024 Werner Randelshofer, Switzerland. MIT License.
4 | */
5 | package ch.randelshofer.fastdoubleparser;
6 |
7 | import org.openjdk.jmh.annotations.Benchmark;
8 | import org.openjdk.jmh.annotations.BenchmarkMode;
9 | import org.openjdk.jmh.annotations.Fork;
10 | import org.openjdk.jmh.annotations.Measurement;
11 | import org.openjdk.jmh.annotations.Mode;
12 | import org.openjdk.jmh.annotations.OperationsPerInvocation;
13 | import org.openjdk.jmh.annotations.OutputTimeUnit;
14 | import org.openjdk.jmh.annotations.Warmup;
15 | import org.openjdk.jmh.infra.Blackhole;
16 |
17 | import java.util.concurrent.TimeUnit;
18 |
19 | /**
20 | *
21 | * # JMH version: 1.37
22 | * # VM version: JDK 22-ea, OpenJDK 64-Bit Server VM, 22-ea+34-2360
23 | * # Intel(R) Core(TM) i7-8700B CPU @ 3.20GHz
24 | *
25 | * Benchmark Mode Cnt Score Error Units
26 | * JmhSplitFloor16.oldSplitFloor16 avgt 2 58.752 ns/op
27 | * JmhSplitFloor16.splitFloor16 avgt 2 42.323 ns/op
28 | *
29 | */
30 | @Fork(value = 1)
31 | @Measurement(iterations = 2, time = 1)
32 | @Warmup(iterations = 2, time = 1)
33 | @OutputTimeUnit(TimeUnit.NANOSECONDS)
34 | @BenchmarkMode(Mode.AverageTime)
35 | public class JmhSplitFloor16 {
36 | private static final int TO_MAX = 1024 + 1;
37 | private static final int FROM_MAX = 100;
38 | private static final int DATA_LENGTH = TO_MAX - FROM_MAX;
39 |
40 | @Benchmark
41 | @OperationsPerInvocation(DATA_LENGTH)
42 | public void oldSplitFloor16(Blackhole blackhole) {
43 | for (int i = 0; i < FROM_MAX; i++) {
44 | for (int j = i; j < TO_MAX; j++) {
45 | blackhole.consume(oldSplitFloor16(i, j));
46 | }
47 | }
48 | }
49 |
50 | @Benchmark
51 | @OperationsPerInvocation(DATA_LENGTH)
52 | public void splitFloor16(Blackhole blackhole) {
53 | for (int i = 0; i < FROM_MAX; i++) {
54 | for (int j = i; j < TO_MAX; j++) {
55 | blackhole.consume(splitFloor16(i, j));
56 | }
57 | }
58 | }
59 |
60 | static int oldSplitFloor16(int from, int to) {
61 | int mid = (from + to) >>> 1;// split in half
62 | mid = to - (((to - mid + 15) >> 4) << 4);// make numDigits of low a multiple of 16
63 | return mid;
64 | }
65 |
66 | static int splitFloor16(int from, int to) {
67 | // divide length by 2 as we want the middle, round up range half to multiples of 16
68 | int range = (((to - from + 31) >>> 5) << 4);
69 | return to - range;
70 | }
71 | }
--------------------------------------------------------------------------------
/fastdoubleparser-dev/src/test/java/ch.randelshofer.fastdoubleparser/ch/randelshofer/fastdoubleparser/MiniTest.java:
--------------------------------------------------------------------------------
1 | /*
2 | * @(#)MiniTest.java
3 | * Copyright © 2024 Werner Randelshofer, Switzerland. MIT License.
4 | */
5 | package ch.randelshofer.fastdoubleparser;
6 |
7 | public final class MiniTest {
8 | public static void main(String... args) {
9 | //ConfigurableDoubleParser p = new ConfigurableDoubleParser();
10 | //double v=p.parseDouble("7.3177701707893310e+15");//Outside Clinger fast path, bail-out in semi-fast path, 7.3177701707893310e+15
11 | //System.out.println(v);
12 | /*
13 | JmhUseBigDecimalForSlowPath jmh=new JmhUseBigDecimalForSlowPath();
14 | jmh.str="7.3177701707893310e15";
15 | jmh.setup();
16 | System.out.println(jmh.bigDecimal);
17 |
18 | */
19 | }
20 | }
21 |
--------------------------------------------------------------------------------
/fastdoubleparser-dev/src/test/java/ch.randelshofer.fastdoubleparser/ch/randelshofer/fastdoubleparser/NumberTestDataSupplier.java:
--------------------------------------------------------------------------------
1 | /*
2 | * @(#)NumberTestDataSupplier.java
3 | * Copyright © 2024 Werner Randelshofer, Switzerland. MIT License.
4 | */
5 | package ch.randelshofer.fastdoubleparser;
6 |
7 | import java.util.function.Supplier;
8 |
9 | public record NumberTestDataSupplier(String title,
10 | Supplier supplier) {
11 | public NumberTestDataSupplier(String inputValue) {
12 | this(inputValue, () -> new NumberTestData(inputValue));
13 | }
14 | }
15 |
--------------------------------------------------------------------------------
/fastdoubleparser-dev/src/test/java/ch.randelshofer.fastdoubleparser/ch/randelshofer/fastdoubleparser/Strings.java:
--------------------------------------------------------------------------------
1 | /*
2 | * @(#)Strings.java
3 | * Copyright © 2024 Werner Randelshofer, Switzerland. MIT License.
4 | */
5 | package ch.randelshofer.fastdoubleparser;
6 |
7 | import java.nio.charset.StandardCharsets;
8 | import java.util.Arrays;
9 |
10 | public final class Strings {
11 | public static StringBuilder repeatStringBuilder(String str, int count) {
12 | StringBuilder b = new StringBuilder(str.length() * count);
13 | while (count-- > 0) {
14 | b.append(str);
15 | }
16 | return b;
17 | }
18 |
19 | public static String repeat(String str, int count) {
20 | return repeatStringBuilder(str, count).toString();
21 | }
22 |
23 | public static String repeat(char ch, int count) {
24 | if (ch < 256) {
25 | byte[] chars = new byte[count];
26 | Arrays.fill(chars, (byte) ch);
27 | return new String(chars, StandardCharsets.ISO_8859_1);
28 | }
29 | char[] chars = new char[count];
30 | Arrays.fill(chars, ch);
31 | return String.copyValueOf(chars);
32 | }
33 | }
34 |
--------------------------------------------------------------------------------
/fastdoubleparser-dev/src/test/java/ch.randelshofer.fastdoubleparser/ch/randelshofer/fastdoubleparser/Utf8DecoderTest.java:
--------------------------------------------------------------------------------
1 | /*
2 | * @(#)Utf8DecoderTest.java
3 | * Copyright © 2024 Werner Randelshofer, Switzerland. MIT License.
4 | */
5 | package ch.randelshofer.fastdoubleparser;
6 |
7 | import org.junit.jupiter.params.ParameterizedTest;
8 | import org.junit.jupiter.params.provider.ValueSource;
9 |
10 | import java.nio.charset.StandardCharsets;
11 | import java.util.Arrays;
12 |
13 | import static org.junit.jupiter.api.Assertions.assertArrayEquals;
14 | import static org.junit.jupiter.api.Assertions.assertEquals;
15 | import static org.junit.jupiter.api.Assertions.assertThrows;
16 |
17 | public final class Utf8DecoderTest {
18 |
19 | @SuppressWarnings("UnnecessaryUnicodeEscape")
20 | @ParameterizedTest
21 | @ValueSource(strings = {
22 | "lowerbounds\u0000\u0080\u0800\ud800\udc00",
23 | "upperbounds\u007f\u07ff\uffff\udbff\udfff"})
24 | public void shouldDecode(String str) {
25 | byte[] bytes = str.getBytes(StandardCharsets.UTF_8);
26 | Utf8Decoder.Result actual = Utf8Decoder.decode(bytes, 0, bytes.length);
27 | char[] expected = str.toCharArray();
28 |
29 | String actualStr = new String(actual.chars(), 0, actual.length());
30 | assertEquals(str, actualStr);
31 |
32 | assertEquals(expected.length, actual.length());
33 | assertArrayEquals(expected, Arrays.copyOf(actual.chars(), actual.length()));
34 | }
35 |
36 | @SuppressWarnings("UnnecessaryUnicodeEscape")
37 | @ParameterizedTest
38 | @ValueSource(strings = {
39 | "80",
40 | "c0",
41 | "c0 80",
42 | "e0 80",
43 | "e0 80 80",
44 | "e0 80 e0",
45 | "f0 80 80",
46 | "f0 80 80 80",
47 | "f0 80 80 80",
48 | "f0 80 a0 a0",
49 | })
50 | public void shouldNotDecode(String str) {
51 | String[] hexes = str.split(" ");
52 | byte[] bytes = new byte[hexes.length];
53 | for (int i = 0; i < hexes.length; i++) {
54 | bytes[i] = (byte) Integer.parseInt(hexes[i], 16);
55 |
56 | }
57 | assertThrows(NumberFormatException.class, () -> Utf8Decoder.decode(bytes, 0, bytes.length));
58 | }
59 | }
--------------------------------------------------------------------------------
/fastdoubleparser-dev/src/test/java/ch.randelshofer.fastdoubleparser/ch/randelshofer/fastdoubleparser/bte/ByteToIntMapTest.java:
--------------------------------------------------------------------------------
1 | /*
2 | * @(#)CharToIntMapTest.java
3 | * Copyright © 2024 Werner Randelshofer, Switzerland. MIT License.
4 | */
5 | package ch.randelshofer.fastdoubleparser.bte;
6 |
7 |
8 | import org.junit.jupiter.api.Test;
9 |
10 | import java.util.Arrays;
11 | import java.util.List;
12 |
13 | import static org.junit.jupiter.api.Assertions.assertEquals;
14 |
15 | public final class ByteToIntMapTest {
16 | @Test
17 | public void shouldFindDigit() {
18 | List digits = Arrays.asList('h', 'a', 'm', 'b', 'u', 'r', 'g', 'e', 'f', 'o');
19 | ByteToIntMap charMap = new ByteToIntMap(digits.size());
20 | for (int i = 0, digitsSize = digits.size(); i < digitsSize; i++) {
21 | charMap.put((byte) (char) digits.get(i), i);
22 | }
23 |
24 | for (int i = 0, digitsSize = digits.size(); i < digitsSize; i++) {
25 | byte d = (byte) (char) digits.get(i);
26 | int actual = charMap.getOrDefault(d, 10);
27 | assertEquals(i, actual, "for d=" + d);
28 | }
29 | }
30 | }
31 |
--------------------------------------------------------------------------------
/fastdoubleparser-dev/src/test/java/ch.randelshofer.fastdoubleparser/ch/randelshofer/fastdoubleparser/bte/ByteTrieOfFewIgnoreCaseTest.java:
--------------------------------------------------------------------------------
1 | /*
2 | * @(#)CharToIntMapTest.java
3 | * Copyright © 2024 Werner Randelshofer, Switzerland. MIT License.
4 | */
5 | package ch.randelshofer.fastdoubleparser.bte;
6 |
7 |
8 | import org.junit.jupiter.api.Test;
9 |
10 | import java.util.Arrays;
11 | import java.util.LinkedHashSet;
12 | import java.util.Set;
13 |
14 | import static org.junit.jupiter.api.Assertions.assertEquals;
15 |
16 | public final class ByteTrieOfFewIgnoreCaseTest {
17 | @Test
18 | public void shouldMatchString() {
19 | Set strings = new LinkedHashSet<>(Arrays.asList("NaN", "інф"));
20 | ByteTrieOfFewIgnoreCase trie = new ByteTrieOfFewIgnoreCase(strings);
21 |
22 | assertEquals(0, trie.match(new byte[]{'a'}));
23 | assertEquals(0, trie.match(new byte[]{'A'}));
24 |
25 | // NAN, nan, nAn
26 | assertEquals(3, trie.match(new byte[]{0x4e, 0x41, 0x4e}));
27 | assertEquals(3, trie.match(new byte[]{0x6e, 0x61, 0x6e}));
28 | assertEquals(3, trie.match(new byte[]{0x6e, 0x41, 0x6e}));
29 |
30 | // "ІНФ", "інф", "іНф"
31 | assertEquals(6, trie.match(new byte[]{(byte) 0xd0, (byte) 0x86, (byte) 0xd0, (byte) 0x9d, (byte) 0xd0, (byte) 0xa4}));
32 | assertEquals(6, trie.match(new byte[]{(byte) 0xd1, (byte) 0x96, (byte) 0xd0, (byte) 0xbd, (byte) 0xd1, (byte) 0x84}));
33 | assertEquals(6, trie.match(new byte[]{(byte) 0xd1, (byte) 0x96, (byte) 0xd0, (byte) 0x9d, (byte) 0xd1, (byte) 0x84}));
34 | }
35 | }
36 |
--------------------------------------------------------------------------------
/fastdoubleparser-dev/src/test/java/ch.randelshofer.fastdoubleparser/ch/randelshofer/fastdoubleparser/bte/ByteTrieTest.java:
--------------------------------------------------------------------------------
1 | /*
2 | * @(#)CharTrieTest.java
3 | * Copyright © 2024 Werner Randelshofer, Switzerland. MIT License.
4 | */
5 | package ch.randelshofer.fastdoubleparser.bte;
6 |
7 | import org.junit.jupiter.api.Test;
8 |
9 | import java.util.Arrays;
10 | import java.util.HashSet;
11 |
12 | import static org.junit.jupiter.api.Assertions.assertEquals;
13 |
14 | public final class ByteTrieTest {
15 | @Test
16 | public void shouldAddAndRetrieve() {
17 | ByteTrieOfFew trie = new ByteTrieOfFew(new HashSet<>(Arrays.asList("e", "E", "Exp")));
18 | assertEquals(0, trie.match(new byte[]{'a'}));
19 | assertEquals(1, trie.match(new byte[]{'e'}));
20 | assertEquals(1, trie.match(new byte[]{'E'}));
21 | assertEquals(3, trie.match(new byte[]{'E', 'x', 'p'}));
22 | assertEquals(3, trie.match(new byte[]{'E', 'x', 'p', 'o', 'n', 'e', 'n', 't'}));
23 | }
24 | }
25 |
--------------------------------------------------------------------------------
/fastdoubleparser-dev/src/test/java/ch.randelshofer.fastdoubleparser/ch/randelshofer/fastdoubleparser/chr/CharToIntMapTest.java:
--------------------------------------------------------------------------------
1 | /*
2 | * @(#)CharToIntMapTest.java
3 | * Copyright © 2024 Werner Randelshofer, Switzerland. MIT License.
4 | */
5 | package ch.randelshofer.fastdoubleparser.chr;
6 |
7 | import org.junit.jupiter.api.Test;
8 |
9 | import java.util.Arrays;
10 | import java.util.List;
11 |
12 | import static org.junit.jupiter.api.Assertions.assertEquals;
13 |
14 | public final class CharToIntMapTest {
15 | @Test
16 | public void shouldFindDigit() {
17 | List digits = Arrays.asList('〇', '一', '二', '三', '四', '五', '六', '七', '八', '九');
18 | CharToIntMap charMap = new CharToIntMap(digits.size());
19 | for (int i = 0, digitsSize = digits.size(); i < digitsSize; i++) {
20 | charMap.put(digits.get(i), i);
21 | }
22 |
23 | for (int i = 0, digitsSize = digits.size(); i < digitsSize; i++) {
24 | char d = digits.get(i);
25 | int actual = charMap.getOrDefault(d, 10);
26 | assertEquals(i, actual, "for d=" + d);
27 | }
28 | }
29 | }
30 |
--------------------------------------------------------------------------------
/fastdoubleparser-dev/src/test/java/ch.randelshofer.fastdoubleparser/ch/randelshofer/fastdoubleparser/chr/CharTrieOfFewIgnoreCaseTest.java:
--------------------------------------------------------------------------------
1 | /*
2 | * @(#)CharTrieOfFewIgnoreCaseTest.java
3 | * Copyright © 2024 Werner Randelshofer, Switzerland. MIT License.
4 | */
5 | package ch.randelshofer.fastdoubleparser.chr;
6 |
7 |
8 | import org.junit.jupiter.api.Test;
9 |
10 | import java.util.Arrays;
11 | import java.util.LinkedHashSet;
12 | import java.util.Set;
13 |
14 | import static org.junit.jupiter.api.Assertions.assertEquals;
15 |
16 | public final class CharTrieOfFewIgnoreCaseTest {
17 | @Test
18 | public void shouldMatchString() {
19 | Set strings = new LinkedHashSet<>(Arrays.asList("NaN", "інф"));
20 | CharTrieOfFewIgnoreCase trie = new CharTrieOfFewIgnoreCase(strings);
21 |
22 | assertEquals(0, trie.match(new char[]{'a'}));
23 | assertEquals(0, trie.match(new char[]{'A'}));
24 |
25 | // NAN, nan, nAn
26 | assertEquals(3, trie.match(new char[]{'N', 'A', 'N'}));
27 | assertEquals(3, trie.match(new char[]{'n', 'a', 'n'}));
28 | assertEquals(3, trie.match(new char[]{'n', 'A', 'n'}));
29 |
30 | // "ІНФ", "інф", "іНф"
31 | assertEquals(3, trie.match(new char[]{'І', 'Н', 'Ф'}));
32 | assertEquals(3, trie.match(new char[]{'і', 'н', 'ф'}));
33 | assertEquals(3, trie.match(new char[]{'і', 'Н', 'ф'}));
34 | }
35 | }
36 |
--------------------------------------------------------------------------------
/fastdoubleparser-dev/src/test/java/ch.randelshofer.fastdoubleparser/ch/randelshofer/fastdoubleparser/chr/CharTrieTest.java:
--------------------------------------------------------------------------------
1 | /*
2 | * @(#)CharTrieTest.java
3 | * Copyright © 2024 Werner Randelshofer, Switzerland. MIT License.
4 | */
5 | package ch.randelshofer.fastdoubleparser.chr;
6 |
7 | import org.junit.jupiter.api.Test;
8 |
9 | import java.util.Arrays;
10 | import java.util.HashSet;
11 |
12 | import static org.junit.jupiter.api.Assertions.assertEquals;
13 |
14 | public final class CharTrieTest {
15 | @Test
16 | public void shouldAddAndRetrieve() {
17 | CharTrieOfFew trie = new CharTrieOfFew(new HashSet<>(Arrays.asList("e", "E", "Exp")));
18 | assertEquals(0, trie.match("a"));
19 | assertEquals(1, trie.match("e"));
20 | assertEquals(1, trie.match("E"));
21 | assertEquals(3, trie.match("Exp"));
22 | assertEquals(3, trie.match("Exponent"));
23 | }
24 | }
25 |
--------------------------------------------------------------------------------
/fastdoubleparser-java11/src/main/java/ch.randelshofer.fastdoubleparser/module-info.java:
--------------------------------------------------------------------------------
1 | /*
2 | * @(#)module-info.java
3 | * Copyright © 2024 Werner Randelshofer, Switzerland. MIT License.
4 | */
5 |
6 | /**
7 | * Provides fast parsers for Java {@code FloatingPointLiteral}s,
8 | * and JSON {@code number}s.
9 | */
10 | module ch.randelshofer.fastdoubleparser {
11 | exports ch.randelshofer.fastdoubleparser;
12 | }
--------------------------------------------------------------------------------
/fastdoubleparser-java11/src/test/java/ch.randelshofer.fastdoubleparser/ch/randelshofer/fastdoubleparser/NumberTestDataSupplier.java:
--------------------------------------------------------------------------------
1 | /*
2 | * @(#)NumberTestDataSupplier.java
3 | * Copyright © 2024 Werner Randelshofer, Switzerland. MIT License.
4 | */
5 | package ch.randelshofer.fastdoubleparser;
6 |
7 | import java.util.Objects;
8 | import java.util.function.Supplier;
9 |
10 | public final class NumberTestDataSupplier {
11 | private final String title;
12 | private final Supplier supplier;
13 |
14 | public NumberTestDataSupplier(String title,
15 | Supplier supplier) {
16 | this.title = title;
17 | this.supplier = supplier;
18 | }
19 |
20 | public NumberTestDataSupplier(String inputValue) {
21 | this(inputValue, () -> new NumberTestData(inputValue));
22 | }
23 |
24 | public String title() {
25 | return title;
26 | }
27 |
28 | public Supplier supplier() {
29 | return supplier;
30 | }
31 |
32 | @Override
33 | public boolean equals(Object obj) {
34 | if (obj == this) {
35 | return true;
36 | }
37 | if (obj == null || obj.getClass() != this.getClass()) {
38 | return false;
39 | }
40 | NumberTestDataSupplier that = (NumberTestDataSupplier) obj;
41 | return Objects.equals(this.title, that.title) &&
42 | Objects.equals(this.supplier, that.supplier);
43 | }
44 |
45 | @Override
46 | public int hashCode() {
47 | return Objects.hash(title, supplier);
48 | }
49 |
50 | @Override
51 | public String toString() {
52 | return "NumberTestDataSupplier[" +
53 | "title=" + title + ", " +
54 | "supplier=" + supplier + ']';
55 | }
56 |
57 | }
58 |
--------------------------------------------------------------------------------
/fastdoubleparser-java17/src/main/java/ch.randelshofer.fastdoubleparser/module-info.java:
--------------------------------------------------------------------------------
1 | /*
2 | * @(#)module-info.java
3 | * Copyright © 2024 Werner Randelshofer, Switzerland. MIT License.
4 | */
5 |
6 | /**
7 | * Provides fast parsers for Java {@code FloatingPointLiteral}s,
8 | * and JSON {@code number}s.
9 | */
10 | module ch.randelshofer.fastdoubleparser {
11 | exports ch.randelshofer.fastdoubleparser;
12 | }
--------------------------------------------------------------------------------
/fastdoubleparser-java17/src/test/java/ch.randelshofer.fastdoubleparser/ch/randelshofer/fastdoubleparser/empty.txt:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/wrandelshofer/FastDoubleParser/302b4d097b50d49e7c7224948658f72f057db47a/fastdoubleparser-java17/src/test/java/ch.randelshofer.fastdoubleparser/ch/randelshofer/fastdoubleparser/empty.txt
--------------------------------------------------------------------------------
/fastdoubleparser-java21/src/main/java/ch.randelshofer.fastdoubleparser/module-info.java:
--------------------------------------------------------------------------------
1 | /*
2 | * @(#)module-info.java
3 | * Copyright © 2024 Werner Randelshofer, Switzerland. MIT License.
4 | */
5 |
6 | /**
7 | * Provides fast parsers for Java {@code FloatingPointLiteral}s,
8 | * and JSON {@code number}s.
9 | */
10 | module ch.randelshofer.fastdoubleparser {
11 | exports ch.randelshofer.fastdoubleparser;
12 | }
--------------------------------------------------------------------------------
/fastdoubleparser-java21/src/test/java/ch.randelshofer.fastdoubleparser/ch/randelshofer/fastdoubleparser/empty.txt:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/wrandelshofer/FastDoubleParser/302b4d097b50d49e7c7224948658f72f057db47a/fastdoubleparser-java21/src/test/java/ch.randelshofer.fastdoubleparser/ch/randelshofer/fastdoubleparser/empty.txt
--------------------------------------------------------------------------------
/fastdoubleparser-java23/src/main/java/ch.randelshofer.fastdoubleparser/module-info.java:
--------------------------------------------------------------------------------
1 | /*
2 | * @(#)module-info.java
3 | * Copyright © 2024 Werner Randelshofer, Switzerland. MIT License.
4 | */
5 |
6 | /**
7 | * Provides fast parsers for Java {@code FloatingPointLiteral}s,
8 | * and JSON {@code number}s.
9 | */
10 | module ch.randelshofer.fastdoubleparser {
11 | exports ch.randelshofer.fastdoubleparser;
12 | }
--------------------------------------------------------------------------------
/fastdoubleparser-java23/src/test/java/ch.randelshofer.fastdoubleparser/ch/randelshofer/fastdoubleparser/empty.txt:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/wrandelshofer/FastDoubleParser/302b4d097b50d49e7c7224948658f72f057db47a/fastdoubleparser-java23/src/test/java/ch.randelshofer.fastdoubleparser/ch/randelshofer/fastdoubleparser/empty.txt
--------------------------------------------------------------------------------
/fastdoubleparser-java8/src/main/java/ch.randelshofer.fastdoubleparser/ch/randelshofer/fastdoubleparser/BigSignificand.java:
--------------------------------------------------------------------------------
1 | /*
2 | * @(#)BigSignificand.java
3 | * Copyright © 2024 Werner Randelshofer, Switzerland. MIT License.
4 | */
5 | package ch.randelshofer.fastdoubleparser;
6 |
7 | import java.math.BigInteger;
8 | import java.nio.ByteBuffer;
9 | import java.nio.IntBuffer;
10 |
11 | /**
12 | * A mutable significand with a fixed number of bits.
13 | */
14 | final class BigSignificand {
15 | private static final long LONG_MASK = 0xffffffffL;
16 | private final int numInts;
17 | private final int[] x;
18 | private int firstNonZeroInt;
19 |
20 | public BigSignificand(long numBits) {
21 | if (numBits <= 0 || numBits >= Integer.MAX_VALUE) {
22 | throw new IllegalArgumentException("numBits=" + numBits);
23 | }
24 | int numLongs = (int) ((numBits + 63) >>> 6) + 1;
25 | numInts = numLongs << 1;
26 | x = new int[numInts];
27 | firstNonZeroInt = numInts;
28 | }
29 |
30 | /**
31 | * Adds the specified value to the significand in place.
32 | *
33 | * @param value the addend, must be a non-negative value
34 | * @throws ArrayIndexOutOfBoundsException on overflow
35 | */
36 | public void add(int value) {
37 | if (value == 0) {
38 | return;
39 | }
40 | long carry = value & LONG_MASK;
41 | int i = numInts - 1;
42 | for (; carry != 0; i--) {
43 | long sum = (x(i) & LONG_MASK) + carry;
44 | x(i, (int) sum);
45 | carry = sum >>> 32;
46 | }
47 | firstNonZeroInt = Math.min(firstNonZeroInt, i + 1);
48 | }
49 |
50 | /**
51 | * Multiplies the significand with the specified factor in place,
52 | * and then adds the specified addend to it (also in place).
53 | *
54 | * @param factor the multiplication factor, must be a non-negative value
55 | * @param addend the addend, must be a non-negative value
56 | * @throws ArrayIndexOutOfBoundsException on overflow
57 | */
58 | public void fma(int factor, int addend) {
59 | long factorL = factor & LONG_MASK;
60 | long carry = addend;
61 | int i = numInts - 1;
62 | for (; i >= firstNonZeroInt; i--) {
63 | long product = factorL * (x(i) & LONG_MASK) + carry;
64 | x(i, (int) product);
65 | carry = product >>> 32;
66 | }
67 | if (carry != 0) {
68 | x(i, (int) carry);
69 | firstNonZeroInt = i;
70 | }
71 | }
72 |
73 | public BigInteger toBigInteger() {
74 | byte[] bytes = new byte[x.length << 2];
75 | IntBuffer buf = ByteBuffer.wrap(bytes).asIntBuffer();
76 | for (int i = 0; i < x.length; i++) {
77 | buf.put(i, x[i]);
78 | }
79 | return new BigInteger(bytes);
80 | }
81 |
82 | private void x(int i, int value) {
83 | x[i] = value;
84 | }
85 |
86 | private int x(int i) {
87 | return x[i];
88 | }
89 | }
90 |
--------------------------------------------------------------------------------
/fastdoubleparser-java8/src/test/java/ch.randelshofer.fastdoubleparser/ch/randelshofer/fastdoubleparser/NumberTestDataSupplier.java:
--------------------------------------------------------------------------------
1 | /*
2 | * @(#)NumberTestDataSupplier.java
3 | * Copyright © 2024 Werner Randelshofer, Switzerland. MIT License.
4 | */
5 | package ch.randelshofer.fastdoubleparser;
6 |
7 | import java.util.Objects;
8 | import java.util.function.Supplier;
9 |
10 | public final class NumberTestDataSupplier {
11 | private final String title;
12 | private final Supplier supplier;
13 |
14 | public NumberTestDataSupplier(String title,
15 | Supplier supplier) {
16 | this.title = title;
17 | this.supplier = supplier;
18 | }
19 |
20 | public NumberTestDataSupplier(String inputValue) {
21 | this(inputValue, () -> new NumberTestData(inputValue));
22 | }
23 |
24 | public String title() {
25 | return title;
26 | }
27 |
28 | public Supplier supplier() {
29 | return supplier;
30 | }
31 |
32 | @Override
33 | public boolean equals(Object obj) {
34 | if (obj == this) {
35 | return true;
36 | }
37 | if (obj == null || obj.getClass() != this.getClass()) {
38 | return false;
39 | }
40 | NumberTestDataSupplier that = (NumberTestDataSupplier) obj;
41 | return Objects.equals(this.title, that.title) &&
42 | Objects.equals(this.supplier, that.supplier);
43 | }
44 |
45 | @Override
46 | public int hashCode() {
47 | return Objects.hash(title, supplier);
48 | }
49 |
50 | @Override
51 | public String toString() {
52 | return "NumberTestDataSupplier[" +
53 | "title=" + title + ", " +
54 | "supplier=" + supplier + ']';
55 | }
56 |
57 | }
58 |
--------------------------------------------------------------------------------
/fastdoubleparserdemo-dev/pom.xml:
--------------------------------------------------------------------------------
1 |
2 |
4 | 4.0.0
5 |
6 | ch.randelshofer
7 | fastdoubleparser-parentproject
8 | ${revision}
9 |
10 | fastdoubleparserdemo-dev
11 | jar
12 |
13 | 23
14 | ${javaVersion}
15 | ${javaVersion}
16 | true
17 | true
18 | true
19 |
20 |
21 | fastdoubleparserdemo-dev
22 |
23 |
24 | ${basedir}/src/main/java/ch.randelshofer.fastdoubleparserdemo
25 | ${basedir}/src/test/java/ch.randelshofer.fastdoubleparserdemo
26 |
27 |
28 |
29 |
30 | ch.randelshofer
31 | fastdoubleparser-dev
32 | ${revision}
33 |
34 |
35 | com.ibm.icu
36 | icu4j
37 |
38 |
39 |
40 |
--------------------------------------------------------------------------------
/fastdoubleparserdemo-dev/src/main/java/ch.randelshofer.fastdoubleparserdemo/ch/randelshofer/fastdoubleparserdemo/DoubleSum.java:
--------------------------------------------------------------------------------
1 | /*
2 | * @(#)DoubleSum.java
3 | * Copyright © 2024 Werner Randelshofer, Switzerland. MIT License.
4 | */
5 | package ch.randelshofer.fastdoubleparserdemo;
6 |
7 | import java.util.ArrayList;
8 | import java.util.List;
9 | import java.util.function.DoubleConsumer;
10 |
11 | import static java.lang.Math.abs;
12 |
13 | /**
14 | * Computes the sum of doubles with the Neumaier compensation algorithm.
15 | *
16 | * Usage with a double stream:
17 | *
18 | * DoubleSum stats = doubleStream.collect(DoubleSum::new,
19 | * DoubleSum::accept,
20 | * DoubleSum::combine);
21 | *
22 | *
23 | * References:
24 | *
25 | * Neumaier Sum.
26 | * Wikipedia.
27 | * link
28 | *
29 | *
30 | */
31 | public final class DoubleSum implements DoubleConsumer {
32 | private double sum = 0.0;
33 | private double c = 0.0;
34 | private List values = new ArrayList<>();
35 | /**
36 | * Adds a value to the sample.
37 | *
38 | * @param value a new value
39 | */
40 | @Override
41 | public void accept(double value) {
42 | sumWithCompensation(value);
43 | }
44 |
45 | /**
46 | * Combines the state of another {@code VarianceStatistics} into this one.
47 | *
48 | * @param other another {@code VarianceStatistics}
49 | * @return this
50 | */
51 | public DoubleSum combine(DoubleSum other) {
52 | sumWithCompensation(other.sum);
53 | sumWithCompensation(other.c);
54 | return this;
55 | }
56 |
57 | /**
58 | * Returns the sum.
59 | *
60 | * @return the sum of square
61 | */
62 | public double getSum() {
63 | return sum + c;
64 | }
65 |
66 | /**
67 | * Performs the Neumaier Sum algorithm.
68 | *
69 | * @param input the new input value
70 | */
71 | private void sumWithCompensation(double input) {
72 | values.add(input);
73 | double t = sum + input;
74 | if (abs(sum) >= abs(input)) {
75 | c += (sum - t) + input;// If sum is bigger, low-order digits of input are lost.
76 | } else {
77 | c += (input - t) + sum;// Else low-order digits of sum are lost
78 | }
79 | sum = t;
80 | }
81 | }
82 |
--------------------------------------------------------------------------------
/fastdoubleparserdemo-dev/src/main/java/ch.randelshofer.fastdoubleparserdemo/module-info.java:
--------------------------------------------------------------------------------
1 | module ch.randelshofer.fastdoubleparserdemo {
2 | requires ch.randelshofer.fastdoubleparser;
3 | requires java.management;
4 | requires com.ibm.icu;
5 | }
--------------------------------------------------------------------------------
/fastdoubleparserdemo-dev/src/test/java/ch.randelshofer.fastdoubleparserdemo/ch/randelshofer/fastdoubleparser/empty.txt:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/wrandelshofer/FastDoubleParser/302b4d097b50d49e7c7224948658f72f057db47a/fastdoubleparserdemo-dev/src/test/java/ch.randelshofer.fastdoubleparserdemo/ch/randelshofer/fastdoubleparser/empty.txt
--------------------------------------------------------------------------------
/fastdoubleparserdemo-java11/pom.xml:
--------------------------------------------------------------------------------
1 |
2 |
4 | 4.0.0
5 |
6 | ch.randelshofer
7 | fastdoubleparser-parentproject
8 | ${revision}
9 |
10 | fastdoubleparserdemo-java11
11 | jar
12 |
13 | 11
14 | true
15 | true
16 | true
17 |
18 |
19 | fastdoubleparserdemo-Java11
20 |
21 |
22 | ${basedir}/src/main/java/ch.randelshofer.fastdoubleparserdemo
23 |
24 | src/main/java/ch.randelshofer.fastdoubleparserdemo/ch/randelshofer/fastdoubleparserdemo/test/java/ch.randelshofer.fastdoubleparserdemo
25 |
26 |
27 |
28 | maven-resources-plugin
29 |
30 |
31 | copy-sources-from-fastdoubleparserdemo-dev
32 | generate-sources
33 |
34 | copy-resources
35 |
36 |
37 | ${project.build.directory}/generated-sources/java
38 |
39 |
40 |
41 | ${basedir}/../fastdoubleparserdemo-dev/src/main/java/ch.randelshofer.fastdoubleparserdemo
42 |
43 |
44 | **/*.java
45 |
46 |
47 |
48 |
49 |
50 |
51 |
52 |
53 | org.codehaus.mojo
54 | build-helper-maven-plugin
55 |
56 |
57 | generate-sources
58 |
59 | add-source
60 |
61 |
62 |
63 | ${project.build.directory}/generated-sources/java
64 |
65 |
66 |
67 |
68 |
69 |
70 |
71 |
72 |
73 |
74 | ch.randelshofer
75 | fastdoubleparser-java11
76 | ${revision}
77 |
78 |
79 | com.ibm.icu
80 | icu4j
81 |
82 |
83 |
84 |
--------------------------------------------------------------------------------
/fastdoubleparserdemo-java11/src/main/java/ch.randelshofer.fastdoubleparserdemo/ch/randelshofer/fastdoubleparserdemo/DecimalFormatMain.java:
--------------------------------------------------------------------------------
1 | /*
2 | * @(#)DecimalFormatMain.java
3 | * Copyright © 2024 Werner Randelshofer, Switzerland. MIT License.
4 | */
5 | package ch.randelshofer.fastdoubleparserdemo;
6 |
7 | import java.text.DecimalFormat;
8 | import java.text.NumberFormat;
9 | import java.util.Locale;
10 |
11 | public final class DecimalFormatMain {
12 |
13 | public static void main(String... args) {
14 | Locale locale = Locale.forLanguageTag("ar");
15 | DecimalFormat f = (DecimalFormat) NumberFormat.getNumberInstance(locale);
16 | String formatted = f.format(-123_456.789);
17 | System.out.print(formatted + '\n');
18 | for (char ch : formatted.toCharArray()) {
19 | System.out.print("U+" + Integer.toHexString(ch) + " ");
20 | }
21 | System.out.println();
22 | }
23 | }
24 |
--------------------------------------------------------------------------------
/fastdoubleparserdemo-java11/src/main/java/ch.randelshofer.fastdoubleparserdemo/ch/randelshofer/fastdoubleparserdemo/empty.txt:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/wrandelshofer/FastDoubleParser/302b4d097b50d49e7c7224948658f72f057db47a/fastdoubleparserdemo-java11/src/main/java/ch.randelshofer.fastdoubleparserdemo/ch/randelshofer/fastdoubleparserdemo/empty.txt
--------------------------------------------------------------------------------
/fastdoubleparserdemo-java17/pom.xml:
--------------------------------------------------------------------------------
1 |
2 |
4 | 4.0.0
5 |
6 | ch.randelshofer
7 | fastdoubleparser-parentproject
8 | ${revision}
9 |
10 | fastdoubleparserdemo-java17
11 | jar
12 |
13 | 17
14 | true
15 | true
16 | true
17 |
18 |
19 | fastdoubleparserdemo-Java17
20 |
21 |
22 | ${basedir}/src/main/java/ch.randelshofer.fastdoubleparserdemo
23 | ${basedir}/src/test/java/ch.randelshofer.fastdoubleparserdemo
24 |
25 |
26 | maven-resources-plugin
27 |
28 |
29 | copy-sources-from-fastdoubleparserdemo-dev
30 | generate-sources
31 |
32 | copy-resources
33 |
34 |
35 | ${project.build.directory}/generated-sources/java
36 |
37 |
38 |
39 | ${basedir}/../fastdoubleparserdemo-dev/src/main/java/ch.randelshofer.fastdoubleparserdemo
40 |
41 |
42 | **/*.java
43 |
44 |
45 |
46 |
47 |
48 |
49 |
50 |
51 | org.codehaus.mojo
52 | build-helper-maven-plugin
53 |
54 |
55 | generate-sources
56 |
57 | add-source
58 |
59 |
60 |
61 | ${project.build.directory}/generated-sources/java
62 |
63 |
64 |
65 |
66 |
67 |
68 |
69 |
70 |
71 |
72 | ch.randelshofer
73 | fastdoubleparser-java17
74 | ${revision}
75 |
76 |
77 | com.ibm.icu
78 | icu4j
79 |
80 |
81 |
82 |
--------------------------------------------------------------------------------
/fastdoubleparserdemo-java17/src/main/java/ch.randelshofer.fastdoubleparserdemo/ch/randelshofer/fastdoubleparser/empty.txt:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/wrandelshofer/FastDoubleParser/302b4d097b50d49e7c7224948658f72f057db47a/fastdoubleparserdemo-java17/src/main/java/ch.randelshofer.fastdoubleparserdemo/ch/randelshofer/fastdoubleparser/empty.txt
--------------------------------------------------------------------------------
/fastdoubleparserdemo-java17/src/test/java/ch.randelshofer.fastdoubleparserdemo/ch/randelshofer/fastdoubleparser/empty.txt:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/wrandelshofer/FastDoubleParser/302b4d097b50d49e7c7224948658f72f057db47a/fastdoubleparserdemo-java17/src/test/java/ch.randelshofer.fastdoubleparserdemo/ch/randelshofer/fastdoubleparser/empty.txt
--------------------------------------------------------------------------------
/fastdoubleparserdemo-java21/pom.xml:
--------------------------------------------------------------------------------
1 |
2 |
4 | 4.0.0
5 |
6 | ch.randelshofer
7 | fastdoubleparser-parentproject
8 | ${revision}
9 |
10 | fastdoubleparserdemo-java21
11 | jar
12 |
13 | 21
14 | true
15 | true
16 | true
17 |
18 |
19 | fastdoubleparserdemo-Java21
20 |
21 |
22 | ${basedir}/src/main/java/ch.randelshofer.fastdoubleparserdemo
23 | ${basedir}/src/test/java/ch.randelshofer.fastdoubleparserdemo
24 |
25 |
26 | maven-resources-plugin
27 |
28 |
29 | copy-sources-from-fastdoubleparserdemo-dev
30 | generate-sources
31 |
32 | copy-resources
33 |
34 |
35 | ${project.build.directory}/generated-sources/java
36 |
37 |
38 |
39 | ${basedir}/../fastdoubleparserdemo-dev/src/main/java/ch.randelshofer.fastdoubleparserdemo
40 |
41 |
42 | **/*.java
43 |
44 |
45 |
46 |
47 |
48 |
49 |
50 |
51 | org.codehaus.mojo
52 | build-helper-maven-plugin
53 |
54 |
55 | generate-sources
56 |
57 | add-source
58 |
59 |
60 |
61 | ${project.build.directory}/generated-sources/java
62 |
63 |
64 |
65 |
66 |
67 |
68 |
69 |
70 |
71 |
72 | ch.randelshofer
73 | fastdoubleparser-java21
74 | ${revision}
75 |
76 |
77 | com.ibm.icu
78 | icu4j
79 |
80 |
81 |
82 |
--------------------------------------------------------------------------------
/fastdoubleparserdemo-java21/src/main/java/ch.randelshofer.fastdoubleparserdemo/ch/randelshofer/fastdoubleparser/empty.txt:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/wrandelshofer/FastDoubleParser/302b4d097b50d49e7c7224948658f72f057db47a/fastdoubleparserdemo-java21/src/main/java/ch.randelshofer.fastdoubleparserdemo/ch/randelshofer/fastdoubleparser/empty.txt
--------------------------------------------------------------------------------
/fastdoubleparserdemo-java21/src/test/java/ch.randelshofer.fastdoubleparserdemo/ch/randelshofer/fastdoubleparser/empty.txt:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/wrandelshofer/FastDoubleParser/302b4d097b50d49e7c7224948658f72f057db47a/fastdoubleparserdemo-java21/src/test/java/ch.randelshofer.fastdoubleparserdemo/ch/randelshofer/fastdoubleparser/empty.txt
--------------------------------------------------------------------------------
/fastdoubleparserdemo-java23/src/main/java/ch.randelshofer.fastdoubleparserdemo/ch/randelshofer/fastdoubleparser/empty.txt:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/wrandelshofer/FastDoubleParser/302b4d097b50d49e7c7224948658f72f057db47a/fastdoubleparserdemo-java23/src/main/java/ch.randelshofer.fastdoubleparserdemo/ch/randelshofer/fastdoubleparser/empty.txt
--------------------------------------------------------------------------------
/fastdoubleparserdemo-java23/src/test/java/ch.randelshofer.fastdoubleparserdemo/ch/randelshofer/fastdoubleparser/empty.txt:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/wrandelshofer/FastDoubleParser/302b4d097b50d49e7c7224948658f72f057db47a/fastdoubleparserdemo-java23/src/test/java/ch.randelshofer.fastdoubleparserdemo/ch/randelshofer/fastdoubleparser/empty.txt
--------------------------------------------------------------------------------
/fastdoubleparserdemo-java8/pom.xml:
--------------------------------------------------------------------------------
1 |
2 |
4 | 4.0.0
5 |
6 | ch.randelshofer
7 | fastdoubleparser-parentproject
8 | ${revision}
9 |
10 | fastdoubleparserdemo-java8
11 | jar
12 |
13 | 8
14 | true
15 | true
16 | true
17 |
18 |
19 | fastdoubleparserdemo-Java8
20 |
21 |
22 | ${basedir}/src/main/java/ch.randelshofer.fastdoubleparserdemo
23 | ${basedir}/src/test/java/ch.randelshofer.fastdoubleparserdemo
24 |
25 |
26 | maven-resources-plugin
27 |
28 |
29 | copy-sources-from-fastdoubleparserdemo-dev
30 | generate-sources
31 |
32 | copy-resources
33 |
34 |
35 | ${project.build.directory}/generated-sources/java
36 |
37 |
38 |
39 | ${basedir}/../fastdoubleparserdemo-dev/src/main/java/ch.randelshofer.fastdoubleparserdemo
40 |
41 |
42 | **/*.java
43 |
44 |
45 | **/module-info.java
46 |
47 |
48 |
49 |
50 |
51 |
52 |
53 |
54 | org.codehaus.mojo
55 | build-helper-maven-plugin
56 |
57 |
58 | generate-sources
59 |
60 | add-source
61 |
62 |
63 |
64 | ${project.build.directory}/generated-sources/java
65 |
66 |
67 |
68 |
69 |
70 |
71 |
72 |
73 |
74 |
75 | ch.randelshofer
76 | fastdoubleparser-java8
77 | ${revision}
78 |
79 |
80 | com.ibm.icu
81 | icu4j
82 |
83 |
84 |
85 |
--------------------------------------------------------------------------------
/fastdoubleparserdemo-java8/src/main/java/ch.randelshofer.fastdoubleparserdemo/empty.txt:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/wrandelshofer/FastDoubleParser/302b4d097b50d49e7c7224948658f72f057db47a/fastdoubleparserdemo-java8/src/main/java/ch.randelshofer.fastdoubleparserdemo/empty.txt
--------------------------------------------------------------------------------
/fastdoubleparserdemo-java8/src/test/java/ch.randelshofer.fastdoubleparserdemo/ch/randelshofer/fastdoubleparserdemo/empty.txt:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/wrandelshofer/FastDoubleParser/302b4d097b50d49e7c7224948658f72f057db47a/fastdoubleparserdemo-java8/src/test/java/ch.randelshofer.fastdoubleparserdemo/ch/randelshofer/fastdoubleparserdemo/empty.txt
--------------------------------------------------------------------------------
/fastdoubleparserdemo/pom.xml:
--------------------------------------------------------------------------------
1 |
2 |
4 | 4.0.0
5 |
6 | ch.randelshofer
7 | fastdoubleparser-parentproject
8 | ${revision}
9 |
10 | fastdoubleparserdemo
11 | fastdoubleparserdemo multi-release jar
12 |
13 |
14 | false
15 | true
16 |
17 |
18 |
19 |
20 |
21 | org.apache.maven.plugins
22 | maven-compiler-plugin
23 |
24 |
25 | default-compile
26 | compile
27 |
28 | compile
29 |
30 |
31 | true
32 |
33 |
34 |
35 |
36 |
37 | org.apache.maven.plugins
38 | maven-javadoc-plugin
39 |
40 | true
41 |
42 |
43 |
44 | org.apache.maven.plugins
45 | maven-site-plugin
46 |
47 | true
48 |
49 |
50 |
51 | maven-assembly-plugin
52 |
53 | false
54 |
55 | src/assembly/mrjar.xml
56 |
57 |
58 |
59 | -
60 | -
61 | -
62 | ${project.scm.url}
63 | ${git.commit.time}
64 | ${git.commit.id.full}
65 | true
66 | ch.randelshofer.fastdoubleparserdemo
67 |
68 |
69 |
70 |
71 |
72 | make-assembly
73 | package
74 |
75 | single
76 |
77 |
78 |
79 |
80 |
81 |
82 |
83 |
--------------------------------------------------------------------------------
/fastdoubleparserdemo/src/assembly/mrjar.xml:
--------------------------------------------------------------------------------
1 |
2 | mvjar
3 |
4 | jar
5 |
6 | false
7 |
8 |
9 | true
10 |
11 | ch.randelshofer:fastdoubleparserdemo-java8
12 |
13 |
14 | true
15 | false
16 |
17 |
18 |
19 | true
20 |
21 | ch.randelshofer:fastdoubleparserdemo-java11
22 |
23 |
24 | META-INF/versions/11
25 | true
26 | false
27 |
28 |
29 | /META-INF/**
30 |
31 |
32 |
33 |
34 |
35 | true
36 |
37 | ch.randelshofer:fastdoubleparserdemo-java17
38 |
39 |
40 | META-INF/versions/17
41 | true
42 | false
43 |
44 |
45 | /META-INF/**
46 |
47 |
48 |
49 |
50 |
51 | true
52 |
53 | ch.randelshofer:fastdoubleparserdemo-fastdoubleparser-java21
54 |
55 |
56 | META-INF/versions/19
57 | true
58 | false
59 |
60 |
61 | /META-INF/**
62 |
63 |
64 |
65 |
66 |
67 |
68 |
--------------------------------------------------------------------------------