summaryrefslogtreecommitdiff
path: root/ext
diff options
context:
space:
mode:
authoreno <[email protected]>2025-03-16 19:51:59 +0100
committerHiroshi SHIBATA <[email protected]>2025-03-27 11:37:27 +0900
commitd1f3c8125854bb0976b08dbcbda3524d8ea3e3fe ()
treefdf4db80041bac1b6483f71adc240b695d309635 /ext
parentdc6ffbbe9ec09c9786b67fb5a9427e5a963980a2 (diff)
Faster integer formatting
This commit provides an alternative implementation for a long → decimal conversion. The main difference is that it uses an algorithm pulled from https://.com/jeaiii/itoa. The source there is C++, it was converted by hand to C for inclusion with this gem. jeaiii's algorithm is covered by the MIT License, see source code. On addition this version now also generates the string directly into the fbuffer, foregoing the need to run a separate memory copy. As a result, I see a speedup of 32% on Apple Silicon M1 for an integer set of benchmarks.
-rw-r--r--ext/json/fbuffer/fbuffer.h56
-rw-r--r--ext/json/generator/generator.c1
-rw-r--r--ext/json/vendor/jeaiii-ltoa.h257
3 files changed, 297 insertions, 17 deletions
@@ -3,6 +3,7 @@
#include "ruby.h"
#include "ruby/encoding.h"
/* shims */
/* This is the fallback definition from Ruby 3.4 */
@@ -150,6 +151,13 @@ static void fbuffer_append(FBuffer *fb, const char *newstr, unsigned long len)
}
}
static void fbuffer_append_str(FBuffer *fb, VALUE str)
{
const char *newstr = StringValuePtr(str);
@@ -167,25 +175,39 @@ static inline void fbuffer_append_char(FBuffer *fb, char newchr)
fb->len++;
}
-static long fltoa(long number, char *buf)
-{
- static const char digits[] = "0123456789";
- long sign = number;
- char* tmp = buf;
-
- if (sign < 0) number = -number;
- do *tmp-- = digits[number % 10]; while (number /= 10);
- if (sign < 0) *tmp-- = '-';
- return buf - tmp;
-}
-
-#define LONG_BUFFER_SIZE 20
static void fbuffer_append_long(FBuffer *fb, long number)
{
- char buf[LONG_BUFFER_SIZE];
- char *buffer_end = buf + LONG_BUFFER_SIZE;
- long len = fltoa(number, buffer_end - 1);
- fbuffer_append(fb, buffer_end - len, len);
}
static VALUE fbuffer_finalize(FBuffer *fb)
@@ -1710,6 +1710,7 @@ void Init_generator(void)
cFragment = rb_const_get(mJSON, rb_intern("Fragment"));
VALUE mExt = rb_define_module_under(mJSON, "Ext");
VALUE mGenerator = rb_define_module_under(mExt, "Generator");
rb_global_variable(&eGeneratorError);
@@ -0,0 +1,257 @@