diff options
author | Jean Boussier <[email protected]> | 2024-10-18 12:27:17 +0200 |
---|---|---|
committer | Hiroshi SHIBATA <[email protected]> | 2024-10-26 18:44:15 +0900 |
commit | e0f8732023c50ee72ed132ebebc9e858643ba6b0 (patch) | |
tree | a64b117b3eee8c726783228cd071838607b46d3a | |
parent | 8e7e63822123568e677ad34cf5350d970eca4a17 (diff) |
Reduce allocations in `parse` and `load` argument handling
Avoid needless hash allocations and such that degrade performance
significantly on micro-benchmarks.
-rw-r--r-- | ext/json/lib/json/common.rb | 32 | ||||
-rw-r--r-- | ext/json/parser/parser.c | 26 | ||||
-rw-r--r-- | ext/json/parser/parser.rl | 10 |
3 files changed, 48 insertions, 20 deletions
diff --git a/ext/json/lib/json/common.rb b/ext/json/lib/json/common.rb index 403bd34b1d..272f5731bd 100644 --- a/ext/json/lib/json/common.rb +++ b/ext/json/lib/json/common.rb @@ -221,8 +221,12 @@ module JSON # # Raises JSON::ParserError (783: unexpected token at ''): # JSON.parse('') # - def parse(source, opts = {}) - Parser.new(source, **(opts||{})).parse + def parse(source, opts = nil) + if opts.nil? + Parser.new(source).parse + else + Parser.new(source, opts).parse + end end # :call-seq: @@ -543,15 +547,23 @@ module JSON # #<Admin:0x00000000064c41f8 # @attributes={"type"=>"Admin", "password"=>"0wn3d"}>} # - def load(source, proc = nil, options = {}) - opts = load_default_options.merge options - if source.respond_to? :to_str - source = source.to_str - elsif source.respond_to? :to_io - source = source.to_io.read - elsif source.respond_to?(:read) - source = source.read + def load(source, proc = nil, options = nil) + opts = if options.nil? + load_default_options + else + load_default_options.merge(options) end + + unless source.is_a?(String) + if source.respond_to? :to_str + source = source.to_str + elsif source.respond_to? :to_io + source = source.to_io.read + elsif source.respond_to?(:read) + source = source.read + end + end + if opts[:allow_blank] && (source.nil? || source.empty?) source = 'null' end diff --git a/ext/json/parser/parser.c b/ext/json/parser/parser.c index 06b11a8dba..c584977955 100644 --- a/ext/json/parser/parser.c +++ b/ext/json/parser/parser.c @@ -1824,7 +1824,15 @@ static VALUE cParser_initialize(int argc, VALUE *argv, VALUE self) if (json->Vsource) { rb_raise(rb_eTypeError, "already initialized instance"); } - rb_scan_args(argc, argv, "1:", &source, &opts); + + rb_check_arity(argc, 1, 2); + source = argv[0]; + opts = Qnil; + if (argc == 2) { + opts = argv[1]; + Check_Type(opts, T_HASH); + } + if (!NIL_P(opts)) { VALUE tmp = ID2SYM(i_max_nesting); if (option_given_p(opts, tmp)) { @@ -1916,7 +1924,7 @@ static VALUE cParser_initialize(int argc, VALUE *argv, VALUE self) } -#line 1920 "parser.c" +#line 1928 "parser.c" enum {JSON_start = 1}; enum {JSON_first_final = 10}; enum {JSON_error = 0}; @@ -1924,7 +1932,7 @@ enum {JSON_error = 0}; enum {JSON_en_main = 1}; -#line 828 "parser.rl" +#line 836 "parser.rl" /* @@ -1942,16 +1950,16 @@ static VALUE cParser_parse(VALUE self) GET_PARSER; -#line 1946 "parser.c" +#line 1954 "parser.c" { cs = JSON_start; } -#line 845 "parser.rl" +#line 853 "parser.rl" p = json->source; pe = p + json->len; -#line 1955 "parser.c" +#line 1963 "parser.c" { if ( p == pe ) goto _test_eof; @@ -1985,7 +1993,7 @@ st0: cs = 0; goto _out; tr2: -#line 820 "parser.rl" +#line 828 "parser.rl" { char *np = JSON_parse_value(json, p, pe, &result, 0); if (np == NULL) { p--; {p++; cs = 10; goto _out;} } else {p = (( np))-1;} @@ -1995,7 +2003,7 @@ st10: if ( ++p == pe ) goto _test_eof10; case 10: -#line 1999 "parser.c" +#line 2007 "parser.c" switch( (*p) ) { case 13: goto st10; case 32: goto st10; @@ -2084,7 +2092,7 @@ case 9: _out: {} } -#line 848 "parser.rl" +#line 856 "parser.rl" if (cs >= JSON_first_final && p == pe) { return result; diff --git a/ext/json/parser/parser.rl b/ext/json/parser/parser.rl index 2b1c743dbd..da4f7f919a 100644 --- a/ext/json/parser/parser.rl +++ b/ext/json/parser/parser.rl @@ -719,7 +719,15 @@ static VALUE cParser_initialize(int argc, VALUE *argv, VALUE self) if (json->Vsource) { rb_raise(rb_eTypeError, "already initialized instance"); } - rb_scan_args(argc, argv, "1:", &source, &opts); + + rb_check_arity(argc, 1, 2); + source = argv[0]; + opts = Qnil; + if (argc == 2) { + opts = argv[1]; + Check_Type(opts, T_HASH); + } + if (!NIL_P(opts)) { VALUE tmp = ID2SYM(i_max_nesting); if (option_given_p(opts, tmp)) { |