Skip to content

Commit 0557fda

Browse files
committed
Use FastDoubleParser where appropriate
This hooks up the Java implementation of Daniel Lemire's fast float parsing algorithm to our internal float parsing logic, excluding cases that are not 7-bit ASCII or which contain underscore characters (not currently allowed by FDP, see wrandelshofer/FastDoubleParser#85 for an attempt to add that feature).
1 parent 19467a7 commit 0557fda

7 files changed

Lines changed: 48 additions & 3 deletions

File tree

core/pom.rb

Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -82,6 +82,8 @@
8282

8383
jar 'org.jruby:jruby-prism:2.0.2'
8484

85+
jar 'ch.randelshofer:fastdoubleparser:2.0.1'
86+
8587
plugin_management do
8688
plugin('org.eclipse.m2e:lifecycle-mapping:1.0.0',
8789
lifecycleMappingMetadata: {

core/pom.xml

Lines changed: 5 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -242,6 +242,11 @@ DO NOT MODIFY - GENERATED CODE
242242
<artifactId>jruby-prism</artifactId>
243243
<version>2.0.2</version>
244244
</dependency>
245+
<dependency>
246+
<groupId>ch.randelshofer</groupId>
247+
<artifactId>fastdoubleparser</artifactId>
248+
<version>2.0.1</version>
249+
</dependency>
245250
</dependencies>
246251
<build>
247252
<defaultGoal>package</defaultGoal>

core/src/main/java/org/jruby/RubyFloat.java

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -1163,7 +1163,7 @@ public static RubyFloat unmarshalFrom(org.jruby.runtime.marshal.UnmarshalStream
11631163
} else if (value.equals(INFINITY_BYTELIST)) {
11641164
return RubyFloat.newFloat(input.getRuntime(), Double.POSITIVE_INFINITY);
11651165
} else {
1166-
return RubyFloat.newFloat(input.getRuntime(), ConvertDouble.byteListToDouble(value, false));
1166+
return RubyFloat.newFloat(input.getRuntime(), ConvertDouble.fastByteListToDouble(value));
11671167
}
11681168
}
11691169

@@ -1177,7 +1177,7 @@ public static RubyFloat unmarshalFrom(ThreadContext context, RubyInputStream in,
11771177
} else if (value.equals(INFINITY_BYTELIST)) {
11781178
return RubyFloat.newFloat(context.runtime, Double.POSITIVE_INFINITY);
11791179
} else {
1180-
return RubyFloat.newFloat(context.runtime, ConvertDouble.byteListToDouble(value, false));
1180+
return RubyFloat.newFloat(context.runtime, ConvertDouble.fastByteListToDouble(value));
11811181
}
11821182
}
11831183

core/src/main/java/org/jruby/RubyNumeric.java

Lines changed: 7 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -56,6 +56,7 @@
5656
import org.jruby.util.ByteList;
5757
import org.jruby.util.ConvertBytes;
5858
import org.jruby.util.ConvertDouble;
59+
import org.jruby.util.StringSupport;
5960
import org.jruby.util.TypeConverter;
6061

6162
import java.math.BigDecimal;
@@ -521,7 +522,12 @@ public static IRubyObject str2fnum(Ruby runtime, RubyString arg, boolean strict,
521522
var context = runtime.getCurrentContext();
522523
try {
523524
ByteList bytes = arg.getByteList();
524-
double value = ConvertDouble.byteListToDouble(bytes, strict);
525+
double value;
526+
if (arg.getCodeRange() == StringSupport.CR_7BIT && bytes.indexOf('_') == -1) {
527+
value = ConvertDouble.fastByteListToDouble(bytes);
528+
} else {
529+
value = ConvertDouble.byteListToDouble(bytes, strict);
530+
}
525531
return asFloat(context, value);
526532
} catch (NumberFormatException e) {
527533
if (strict) {

core/src/main/java/org/jruby/util/ConvertDouble.java

Lines changed: 13 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -28,6 +28,8 @@
2828

2929
package org.jruby.util;
3030

31+
import ch.randelshofer.fastdoubleparser.JavaDoubleParser;
32+
3133
public class ConvertDouble {
3234
/**
3335
* Converts supplied ByteList into a double. strict-mode will not like
@@ -37,6 +39,17 @@ public static double byteListToDouble(ByteList bytes, boolean strict) {
3739
return new DoubleConverter().parse(bytes, strict, true);
3840
}
3941

42+
/**
43+
* Converts supplied ByteList into a double using FastDoubleParser. String must be 7-bit ASCII and contain no
44+
* underscores.
45+
*
46+
* @param bytes the bytelist to parse
47+
* @return the resulting double value
48+
*/
49+
public static double fastByteListToDouble(ByteList bytes) {
50+
return JavaDoubleParser.parseDouble(bytes);
51+
}
52+
4053
public static class DoubleConverter {
4154
private byte[] bytes;
4255
private int index;

shaded/pom.rb

Lines changed: 5 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -41,6 +41,11 @@
4141
'Enable-Native-Access' => 'ALL-UNNAMED',
4242
}
4343
}],
44+
filters: [
45+
{ artifact: 'ch.randelshofer:fastdoubleparser', excludes: '**/23/**' },
46+
{ artifact: 'ch.randelshofer:fastdoubleparser', excludes: '**/17/**' },
47+
{ artifact: 'ch.randelshofer:fastdoubleparser', excludes: '**/11/**' },
48+
],
4449
createSourcesJar: false,
4550
compress: false)
4651
end

shaded/pom.xml

Lines changed: 14 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -75,6 +75,20 @@ DO NOT MODIFY - GENERATED CODE
7575
</manifestEntries>
7676
</transformer>
7777
</transformers>
78+
<filters>
79+
<filter>
80+
<artifact>ch.randelshofer:fastdoubleparser</artifact>
81+
<excludes>**/23/**</excludes>
82+
</filter>
83+
<filter>
84+
<artifact>ch.randelshofer:fastdoubleparser</artifact>
85+
<excludes>**/17/**</excludes>
86+
</filter>
87+
<filter>
88+
<artifact>ch.randelshofer:fastdoubleparser</artifact>
89+
<excludes>**/11/**</excludes>
90+
</filter>
91+
</filters>
7892
<createSourcesJar>false</createSourcesJar>
7993
<compress>false</compress>
8094
</configuration>

0 commit comments

Comments
 (0)