diff options
author | eno <[email protected]> | 2025-03-16 19:51:59 +0100 |
---|---|---|
committer | Hiroshi SHIBATA <[email protected]> | 2025-03-27 11:37:27 +0900 |
commit | d1f3c8125854bb0976b08dbcbda3524d8ea3e3fe () | |
tree | fdf4db80041bac1b6483f71adc240b695d309635 | |
parent | dc6ffbbe9ec09c9786b67fb5a9427e5a963980a2 (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.h | 56 | ||||
-rw-r--r-- | ext/json/generator/generator.c | 1 | ||||
-rw-r--r-- | ext/json/vendor/jeaiii-ltoa.h | 257 | ||||
-rwxr-xr-x | test/json/json_generator_test.rb | 12 |
4 files changed, 309 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 @@ @@ -707,4 +707,16 @@ class JSONGeneratorTest < Test::Unit::TestCase assert_equal expected, value.to_json end end end |