summaryrefslogtreecommitdiff
path: root/ext/json/parser/parser.rl
diff options
context:
space:
mode:
authorJean Boussier <jean.boussier@gmail.com>2020-09-09 15:24:22 +0200
committerHiroshi SHIBATA <hsbt@ruby-lang.org>2020-10-20 21:40:25 +0900
commit520e0916af0fe53a5ca57269a2bae50cc60e4241 (patch)
tree0e5b9d615852b0557cc6cd95ce851d59df9d6121 /ext/json/parser/parser.rl
parentf6680c9ad1b334f094144d788887cd33f7043f41 (diff)
Implement a freeze: parser option
If set to true all parsed objects will be immediately frozen, and strings will be deduplicated if the Ruby implementation allows it.
Diffstat (limited to 'ext/json/parser/parser.rl')
-rw-r--r--ext/json/parser/parser.rl29
1 files changed, 28 insertions, 1 deletions
diff --git a/ext/json/parser/parser.rl b/ext/json/parser/parser.rl
index 00a35bded4..4629052096 100644
--- a/ext/json/parser/parser.rl
+++ b/ext/json/parser/parser.rl
@@ -95,7 +95,7 @@ static ID i_json_creatable_p, i_json_create, i_create_id, i_create_additions,
i_chr, i_max_nesting, i_allow_nan, i_symbolize_names,
i_object_class, i_array_class, i_decimal_class, i_key_p,
i_deep_const_get, i_match, i_match_string, i_aset, i_aref,
- i_leftshift, i_new, i_BigDecimal;
+ i_leftshift, i_new, i_BigDecimal, i_freeze, i_uminus;
%%{
machine JSON_common;
@@ -290,6 +290,10 @@ static char *JSON_parse_value(JSON_Parser *json, char *p, char *pe, VALUE *resul
%% write init;
%% write exec;
+ if (json->freeze) {
+ OBJ_FREEZE(*result);
+ }
+
if (cs >= JSON_value_first_final) {
return p;
} else {
@@ -573,7 +577,22 @@ static char *JSON_parse_string(JSON_Parser *json, char *p, char *pe, VALUE *resu
if (json->symbolize_names && json->parsing_name) {
*result = rb_str_intern(*result);
} else if (RB_TYPE_P(*result, T_STRING)) {
+# if STR_UMINUS_DEDUPE_FROZEN
+ if (json->freeze) {
+ // Starting from MRI 2.8 it is preferable to freeze the string
+ // before deduplication so that it can be interned directly
+ // otherwise it would be duplicated first which is wasteful.
+ *result = rb_funcall(rb_str_freeze(*result), i_uminus, 0);
+ }
+# elif STR_UMINUS_DEDUPE
+ if (json->freeze) {
+ // MRI 2.5 and older do not deduplicate strings that are already
+ // frozen.
+ *result = rb_funcall(*result, i_uminus, 0);
+ }
+# else
rb_str_resize(*result, RSTRING_LEN(*result));
+# endif
}
if (cs >= JSON_string_first_final) {
return p + 1;
@@ -681,6 +700,12 @@ static VALUE cParser_initialize(int argc, VALUE *argv, VALUE self)
} else {
json->symbolize_names = 0;
}
+ tmp = ID2SYM(i_freeze);
+ if (option_given_p(opts, tmp)) {
+ json->freeze = RTEST(rb_hash_aref(opts, tmp)) ? 1 : 0;
+ } else {
+ json->freeze = 0;
+ }
tmp = ID2SYM(i_create_additions);
if (option_given_p(opts, tmp)) {
json->create_additions = RTEST(rb_hash_aref(opts, tmp));
@@ -886,6 +911,8 @@ void Init_parser(void)
i_leftshift = rb_intern("<<");
i_new = rb_intern("new");
i_BigDecimal = rb_intern("BigDecimal");
+ i_freeze = rb_intern("freeze");
+ i_uminus = rb_intern("-@");
}
/*