Skip to content

Commit e0f8732

Browse files
byroothsbt
authored andcommitted
Reduce allocations in parse and load argument handling
Avoid needless hash allocations and such that degrade performance significantly on micro-benchmarks.
1 parent 8e7e638 commit e0f8732

File tree

3 files changed

+48
-20
lines changed

3 files changed

+48
-20
lines changed

ext/json/lib/json/common.rb

Lines changed: 22 additions & 10 deletions
Original file line numberDiff line numberDiff line change
@@ -221,8 +221,12 @@ class MissingUnicodeSupport < JSONError; end
221221
# # Raises JSON::ParserError (783: unexpected token at ''):
222222
# JSON.parse('')
223223
#
224-
def parse(source, opts = {})
225-
Parser.new(source, **(opts||{})).parse
224+
def parse(source, opts = nil)
225+
if opts.nil?
226+
Parser.new(source).parse
227+
else
228+
Parser.new(source, opts).parse
229+
end
226230
end
227231

228232
# :call-seq:
@@ -543,15 +547,23 @@ class << self
543547
# #<Admin:0x00000000064c41f8
544548
# @attributes={"type"=>"Admin", "password"=>"0wn3d"}>}
545549
#
546-
def load(source, proc = nil, options = {})
547-
opts = load_default_options.merge options
548-
if source.respond_to? :to_str
549-
source = source.to_str
550-
elsif source.respond_to? :to_io
551-
source = source.to_io.read
552-
elsif source.respond_to?(:read)
553-
source = source.read
550+
def load(source, proc = nil, options = nil)
551+
opts = if options.nil?
552+
load_default_options
553+
else
554+
load_default_options.merge(options)
554555
end
556+
557+
unless source.is_a?(String)
558+
if source.respond_to? :to_str
559+
source = source.to_str
560+
elsif source.respond_to? :to_io
561+
source = source.to_io.read
562+
elsif source.respond_to?(:read)
563+
source = source.read
564+
end
565+
end
566+
555567
if opts[:allow_blank] && (source.nil? || source.empty?)
556568
source = 'null'
557569
end

ext/json/parser/parser.c

Lines changed: 17 additions & 9 deletions
Original file line numberDiff line numberDiff line change
@@ -1824,7 +1824,15 @@ static VALUE cParser_initialize(int argc, VALUE *argv, VALUE self)
18241824
if (json->Vsource) {
18251825
rb_raise(rb_eTypeError, "already initialized instance");
18261826
}
1827-
rb_scan_args(argc, argv, "1:", &source, &opts);
1827+
1828+
rb_check_arity(argc, 1, 2);
1829+
source = argv[0];
1830+
opts = Qnil;
1831+
if (argc == 2) {
1832+
opts = argv[1];
1833+
Check_Type(opts, T_HASH);
1834+
}
1835+
18281836
if (!NIL_P(opts)) {
18291837
VALUE tmp = ID2SYM(i_max_nesting);
18301838
if (option_given_p(opts, tmp)) {
@@ -1916,15 +1924,15 @@ static VALUE cParser_initialize(int argc, VALUE *argv, VALUE self)
19161924
}
19171925

19181926

1919-
#line 1920 "parser.c"
1927+
#line 1928 "parser.c"
19201928
enum {JSON_start = 1};
19211929
enum {JSON_first_final = 10};
19221930
enum {JSON_error = 0};
19231931

19241932
enum {JSON_en_main = 1};
19251933

19261934

1927-
#line 828 "parser.rl"
1935+
#line 836 "parser.rl"
19281936

19291937

19301938
/*
@@ -1942,16 +1950,16 @@ static VALUE cParser_parse(VALUE self)
19421950
GET_PARSER;
19431951

19441952

1945-
#line 1946 "parser.c"
1953+
#line 1954 "parser.c"
19461954
{
19471955
cs = JSON_start;
19481956
}
19491957

1950-
#line 845 "parser.rl"
1958+
#line 853 "parser.rl"
19511959
p = json->source;
19521960
pe = p + json->len;
19531961

1954-
#line 1955 "parser.c"
1962+
#line 1963 "parser.c"
19551963
{
19561964
if ( p == pe )
19571965
goto _test_eof;
@@ -1985,7 +1993,7 @@ case 1:
19851993
cs = 0;
19861994
goto _out;
19871995
tr2:
1988-
#line 820 "parser.rl"
1996+
#line 828 "parser.rl"
19891997
{
19901998
char *np = JSON_parse_value(json, p, pe, &result, 0);
19911999
if (np == NULL) { p--; {p++; cs = 10; goto _out;} } else {p = (( np))-1;}
@@ -1995,7 +2003,7 @@ cs = 0;
19952003
if ( ++p == pe )
19962004
goto _test_eof10;
19972005
case 10:
1998-
#line 1999 "parser.c"
2006+
#line 2007 "parser.c"
19992007
switch( (*p) ) {
20002008
case 13: goto st10;
20012009
case 32: goto st10;
@@ -2084,7 +2092,7 @@ case 9:
20842092
_out: {}
20852093
}
20862094

2087-
#line 848 "parser.rl"
2095+
#line 856 "parser.rl"
20882096

20892097
if (cs >= JSON_first_final && p == pe) {
20902098
return result;

ext/json/parser/parser.rl

Lines changed: 9 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -719,7 +719,15 @@ static VALUE cParser_initialize(int argc, VALUE *argv, VALUE self)
719719
if (json->Vsource) {
720720
rb_raise(rb_eTypeError, "already initialized instance");
721721
}
722-
rb_scan_args(argc, argv, "1:", &source, &opts);
722+
723+
rb_check_arity(argc, 1, 2);
724+
source = argv[0];
725+
opts = Qnil;
726+
if (argc == 2) {
727+
opts = argv[1];
728+
Check_Type(opts, T_HASH);
729+
}
730+
723731
if (!NIL_P(opts)) {
724732
VALUE tmp = ID2SYM(i_max_nesting);
725733
if (option_given_p(opts, tmp)) {

0 commit comments

Comments
 (0)