Skip to content

Commit 3a3eb73

Browse files
authored
Merge pull request #768 from radiospiel/eno/pr/floats-2
Faster float formatting
2 parents 2074f0c + dc4773d commit 3a3eb73

File tree

4 files changed

+510
-3
lines changed

4 files changed

+510
-3
lines changed

ext/json/ext/generator/depend

+1
Original file line numberDiff line numberDiff line change
@@ -1 +1,2 @@
11
generator.o: generator.c $(srcdir)/../fbuffer/fbuffer.h
2+
generator.o: generator.c $(srcdir)/../vendor/fpconv.c

ext/json/ext/generator/generator.c

+21-3
Original file line numberDiff line numberDiff line change
@@ -1,5 +1,6 @@
11
#include "ruby.h"
22
#include "../fbuffer/fbuffer.h"
3+
#include "../vendor/fpconv.c"
34

45
#include <math.h>
56
#include <ctype.h>
@@ -1054,8 +1055,9 @@ static void generate_json_float(FBuffer *buffer, struct generate_json_data *data
10541055
{
10551056
double value = RFLOAT_VALUE(obj);
10561057
char allow_nan = state->allow_nan;
1057-
if (!allow_nan) {
1058-
if (isinf(value) || isnan(value)) {
1058+
if (isinf(value) || isnan(value)) {
1059+
/* for NaN and Infinity values we either raise an error or rely on Float#to_s. */
1060+
if (!allow_nan) {
10591061
if (state->strict && state->as_json) {
10601062
VALUE casted_obj = rb_proc_call_with_block(state->as_json, 1, &obj, Qnil);
10611063
if (casted_obj != obj) {
@@ -1067,8 +1069,24 @@ static void generate_json_float(FBuffer *buffer, struct generate_json_data *data
10671069
}
10681070
raise_generator_error(obj, "%"PRIsVALUE" not allowed in JSON", rb_funcall(obj, i_to_s, 0));
10691071
}
1072+
1073+
VALUE tmp = rb_funcall(obj, i_to_s, 0);
1074+
fbuffer_append_str(buffer, tmp);
1075+
return;
10701076
}
1071-
fbuffer_append_str(buffer, rb_funcall(obj, i_to_s, 0));
1077+
1078+
/* This implementation writes directly into the buffer. We reserve
1079+
* the 24 characters that fpconv_dtoa states as its maximum, plus
1080+
* 2 more characters for the potential ".0" suffix.
1081+
*/
1082+
fbuffer_inc_capa(buffer, 26);
1083+
char* d = buffer->ptr + buffer->len;
1084+
int len = fpconv_dtoa(value, d);
1085+
1086+
/* fpconv_dtoa converts a float to its shortest string representation,
1087+
* but it adds a ".0" if this is a plain integer.
1088+
*/
1089+
buffer->len += len;
10721090
}
10731091

10741092
static void generate_json_fragment(FBuffer *buffer, struct generate_json_data *data, JSON_Generator_State *state, VALUE obj)

0 commit comments

Comments
 (0)