oj 3.16.11 → 3.17.6
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- checksums.yaml +4 -4
- data/CHANGELOG.md +133 -0
- data/README.md +0 -16
- data/ext/oj/cache.c +17 -1
- data/ext/oj/cache.h +5 -0
- data/ext/oj/circarray.c +6 -2
- data/ext/oj/compat.c +5 -5
- data/ext/oj/custom.c +12 -5
- data/ext/oj/dump.c +433 -206
- data/ext/oj/dump.h +12 -0
- data/ext/oj/dump_compat.c +17 -5
- data/ext/oj/dump_object.c +25 -10
- data/ext/oj/dump_strict.c +13 -8
- data/ext/oj/extconf.rb +11 -7
- data/ext/oj/fast.c +123 -60
- data/ext/oj/intern.c +7 -2
- data/ext/oj/mimic_json.c +3 -0
- data/ext/oj/object.c +26 -15
- data/ext/oj/odd.c +6 -2
- data/ext/oj/oj.c +511 -22
- data/ext/oj/oj.h +61 -53
- data/ext/oj/parse.c +229 -30
- data/ext/oj/parse.h +0 -1
- data/ext/oj/parser.c +226 -65
- data/ext/oj/rails.c +197 -57
- data/ext/oj/reader.c +18 -6
- data/ext/oj/resolve.c +11 -2
- data/ext/oj/rxclass.c +17 -1
- data/ext/oj/rxclass.h +2 -1
- data/ext/oj/safe.c +244 -0
- data/ext/oj/safe.h +91 -0
- data/ext/oj/saj.c +56 -12
- data/ext/oj/simd.h +210 -1
- data/ext/oj/sparse.c +22 -9
- data/ext/oj/stream_writer.c +16 -1
- data/ext/oj/string_writer.c +23 -7
- data/ext/oj/usual.c +23 -6
- data/ext/oj/util.c +27 -0
- data/ext/oj/util.h +2 -1
- data/ext/oj/val_stack.h +24 -5
- data/ext/oj/wab.c +15 -27
- data/lib/oj/version.rb +1 -1
- data/pages/Compatibility.md +1 -1
- data/pages/Custom.md +2 -3
- data/pages/InstallOptions.md +8 -6
- data/pages/Modes.md +1 -1
- data/pages/Options.md +5 -6
- data/pages/Parser.md +2 -2
- data/pages/Rails.md +6 -0
- data/pages/Security.md +21 -7
- metadata +21 -19
data/ext/oj/oj.c
CHANGED
|
@@ -20,6 +20,8 @@
|
|
|
20
20
|
#include "rails.h"
|
|
21
21
|
#include "simd.h"
|
|
22
22
|
|
|
23
|
+
#define MAX_INDENT 16
|
|
24
|
+
|
|
23
25
|
typedef struct _yesNoOpt {
|
|
24
26
|
VALUE sym;
|
|
25
27
|
char *attr;
|
|
@@ -120,7 +122,9 @@ static VALUE create_id_sym;
|
|
|
120
122
|
static VALUE custom_sym;
|
|
121
123
|
static VALUE empty_string_sym;
|
|
122
124
|
static VALUE escape_mode_sym;
|
|
125
|
+
static VALUE except_sym;
|
|
123
126
|
static VALUE integer_range_sym;
|
|
127
|
+
static VALUE max_integer_digits_sym;
|
|
124
128
|
static VALUE fast_sym;
|
|
125
129
|
static VALUE float_prec_sym;
|
|
126
130
|
static VALUE float_format_sym;
|
|
@@ -138,6 +142,7 @@ static VALUE null_sym;
|
|
|
138
142
|
static VALUE object_sym;
|
|
139
143
|
static VALUE omit_null_byte_sym;
|
|
140
144
|
static VALUE omit_nil_sym;
|
|
145
|
+
static VALUE only_sym;
|
|
141
146
|
static VALUE rails_sym;
|
|
142
147
|
static VALUE raise_sym;
|
|
143
148
|
static VALUE ruby_sym;
|
|
@@ -167,6 +172,8 @@ pthread_mutex_t oj_cache_mutex;
|
|
|
167
172
|
VALUE oj_cache_mutex = Qnil;
|
|
168
173
|
#endif
|
|
169
174
|
|
|
175
|
+
SIMD_Implementation SIMD_Impl = SIMD_NONE;
|
|
176
|
+
|
|
170
177
|
extern void oj_parser_init();
|
|
171
178
|
|
|
172
179
|
const char oj_json_class[] = "json_class";
|
|
@@ -202,6 +209,7 @@ struct _options oj_default_options = {
|
|
|
202
209
|
0, // cache_str
|
|
203
210
|
0, // int_range_min
|
|
204
211
|
0, // int_range_max
|
|
212
|
+
0, // max_integer_digits
|
|
205
213
|
oj_json_class, // create_id
|
|
206
214
|
10, // create_id_len
|
|
207
215
|
9, // sec_prec
|
|
@@ -226,6 +234,8 @@ struct _options oj_default_options = {
|
|
|
226
234
|
false, // omit_nil
|
|
227
235
|
false, // omit_null_byte
|
|
228
236
|
MAX_DEPTH, // max_depth
|
|
237
|
+
NULL, // only
|
|
238
|
+
NULL, // except
|
|
229
239
|
},
|
|
230
240
|
{
|
|
231
241
|
// str_rx
|
|
@@ -236,6 +246,22 @@ struct _options oj_default_options = {
|
|
|
236
246
|
NULL,
|
|
237
247
|
};
|
|
238
248
|
|
|
249
|
+
static VALUE only_array_from_string(const char *str) {
|
|
250
|
+
volatile VALUE a = Qnil;
|
|
251
|
+
|
|
252
|
+
if (NULL != str && 2 < strlen(str)) {
|
|
253
|
+
str++;
|
|
254
|
+
char *cp;
|
|
255
|
+
|
|
256
|
+
a = rb_ary_new();
|
|
257
|
+
while (NULL != (cp = strchr(str, ':'))) {
|
|
258
|
+
rb_ary_push(a, rb_id2sym(rb_intern2(str, cp - str)));
|
|
259
|
+
str = cp + 1;
|
|
260
|
+
}
|
|
261
|
+
}
|
|
262
|
+
return a;
|
|
263
|
+
}
|
|
264
|
+
|
|
239
265
|
/* Document-method: default_options()
|
|
240
266
|
* call-seq: default_options()
|
|
241
267
|
*
|
|
@@ -273,7 +299,8 @@ struct _options oj_default_options = {
|
|
|
273
299
|
* floats, 0 indicates use Ruby
|
|
274
300
|
* - *:float_format* [_String_] the C printf format string for printing floats.
|
|
275
301
|
* Default follows the float_precision and will be changed if float_precision is
|
|
276
|
-
* changed. The string can be no more than 6 bytes
|
|
302
|
+
* changed. The string can be no more than 6 bytes and can hold at most one
|
|
303
|
+
* directive, which must be one of aAeEfgG and take no argument of its own.
|
|
277
304
|
* - *:use_to_json* [_Boolean_|_nil_] call to_json() methods on dump, default is false
|
|
278
305
|
* - *:use_as_json* [_Boolean_|_nil_] call as_json() methods on dump, default is false
|
|
279
306
|
* - *:use_raw_json* [_Boolean_|_nil_] call raw_json() methods on dump, default is false
|
|
@@ -312,10 +339,17 @@ struct _options oj_default_options = {
|
|
|
312
339
|
* - *:cache_str* [_Fixnum_] maximum string value length to cache (strings less
|
|
313
340
|
* than this are cached)
|
|
314
341
|
* - *:integer_range* [_Range_] Dump integers outside range as strings.
|
|
342
|
+
* - *:max_integer_digits* [_Fixnum_] Maximum number of decimal digits allowed in a
|
|
343
|
+
* parsed integer. When the limit is exceeded a parse error is raised. 0 (the
|
|
344
|
+
* default) disables the limit. Setting a reasonable limit is recommended when
|
|
345
|
+
* parsing untrusted input to mitigate CPU-DoS attacks. Only applies to the
|
|
346
|
+
* legacy parsers (Oj.load, Oj::Doc, JSON.parse mimic); Oj::Parser is unaffected.
|
|
315
347
|
* - *:trace* [_true,_|_false_] Trace all load and dump calls, default is false
|
|
316
348
|
* (trace is off)
|
|
317
349
|
* - *:safe* [_true,_|_false_] Safe mimic breaks JSON mimic to be safer, default
|
|
318
350
|
* is false (safe is off)
|
|
351
|
+
* - *:only* [_nil,_|_Array_] A list of the fields to encode. All others are skipped.
|
|
352
|
+
* - *:except* [_nil,_|_Array_] A list of the fields to not encode. All others are encoded.
|
|
319
353
|
*
|
|
320
354
|
* Return [_Hash_] all current option settings.
|
|
321
355
|
*/
|
|
@@ -424,6 +458,7 @@ static VALUE get_def_opts(VALUE self) {
|
|
|
424
458
|
} else {
|
|
425
459
|
rb_hash_aset(opts, integer_range_sym, Qnil);
|
|
426
460
|
}
|
|
461
|
+
rb_hash_aset(opts, max_integer_digits_sym, LONG2NUM((long)oj_default_options.max_integer_digits));
|
|
427
462
|
switch (oj_default_options.escape_mode) {
|
|
428
463
|
case NLEsc: rb_hash_aset(opts, escape_mode_sym, newline_sym); break;
|
|
429
464
|
case JSONEsc: rb_hash_aset(opts, escape_mode_sym, json_sym); break;
|
|
@@ -481,6 +516,9 @@ static VALUE get_def_opts(VALUE self) {
|
|
|
481
516
|
rb_hash_aset(opts, oj_hash_class_sym, oj_default_options.hash_class);
|
|
482
517
|
rb_hash_aset(opts, oj_array_class_sym, oj_default_options.array_class);
|
|
483
518
|
|
|
519
|
+
rb_hash_aset(opts, only_sym, only_array_from_string(oj_default_options.dump_opts.only));
|
|
520
|
+
rb_hash_aset(opts, except_sym, only_array_from_string(oj_default_options.dump_opts.except));
|
|
521
|
+
|
|
484
522
|
if (NULL == oj_default_options.ignore) {
|
|
485
523
|
rb_hash_aset(opts, ignore_sym, Qnil);
|
|
486
524
|
} else {
|
|
@@ -537,7 +575,8 @@ static VALUE get_def_opts(VALUE self) {
|
|
|
537
575
|
* when dumping the seconds portion of time.
|
|
538
576
|
* - *:float_format* [_String_] the C printf format string for printing floats.
|
|
539
577
|
* Default follows the float_precision and will be changed if float_precision
|
|
540
|
-
* is changed. The string can be no more than 6 bytes
|
|
578
|
+
* is changed. The string can be no more than 6 bytes and can hold at most one
|
|
579
|
+
* directive, which must be one of aAeEfgG and take no argument of its own.
|
|
541
580
|
* - *:float_precision* [_Fixnum_|_nil_] number of digits of precision when dumping floats, 0 indicates use Ruby.
|
|
542
581
|
* - *:use_to_json* [_Boolean_|_nil_] call to_json() methods on dump, default is false.
|
|
543
582
|
* - *:use_as_json* [_Boolean_|_nil_] call as_json() methods on dump, default is false.
|
|
@@ -564,12 +603,57 @@ static VALUE get_def_opts(VALUE self) {
|
|
|
564
603
|
* - *:cache_keys* [_Boolean_] if true then hash keys are cached
|
|
565
604
|
* - *:cache_str* [_Fixnum_] maximum string value length to cache (strings less than this are cached)
|
|
566
605
|
* - *:integer_range* [_Range_] Dump integers outside range as strings.
|
|
606
|
+
* - *:max_integer_digits* [_Fixnum_] Maximum decimal digits in a parsed integer
|
|
607
|
+
* (0 = unlimited). Use to mitigate CPU-DoS via huge integer values in JSON.
|
|
567
608
|
* - *:trace* [_Boolean_] turn trace on or off.
|
|
568
609
|
* - *:safe* [_Boolean_] turn safe mimic on or off.
|
|
569
610
|
*/
|
|
611
|
+
static ID oj_default_options_keeper_id = 0;
|
|
612
|
+
|
|
613
|
+
// The default options are a plain C global so the Ruby objects in them, the
|
|
614
|
+
// classes of the hash_class, array_class, and ignore options and the regexps
|
|
615
|
+
// and the classes of the match_string option, can not be reached by the GC and
|
|
616
|
+
// are collected while the defaults still refer to them. Holding them in an
|
|
617
|
+
// array the GC does know about keeps them alive. The array is rebuilt whenever
|
|
618
|
+
// the defaults change and replaces the previous one so that only the objects
|
|
619
|
+
// the defaults are currently using are held.
|
|
620
|
+
static void keep_default_options(void) {
|
|
621
|
+
VALUE keep = rb_ary_new();
|
|
622
|
+
|
|
623
|
+
if (0 == oj_default_options_keeper_id) {
|
|
624
|
+
oj_default_options_keeper_id = rb_intern("@default_options_keeper");
|
|
625
|
+
}
|
|
626
|
+
if (Qnil != oj_default_options.hash_class) {
|
|
627
|
+
rb_ary_push(keep, oj_default_options.hash_class);
|
|
628
|
+
}
|
|
629
|
+
if (Qnil != oj_default_options.array_class) {
|
|
630
|
+
rb_ary_push(keep, oj_default_options.array_class);
|
|
631
|
+
}
|
|
632
|
+
if (NULL != oj_default_options.ignore) {
|
|
633
|
+
VALUE *vp;
|
|
634
|
+
|
|
635
|
+
for (vp = oj_default_options.ignore; Qnil != *vp; vp++) {
|
|
636
|
+
rb_ary_push(keep, *vp);
|
|
637
|
+
}
|
|
638
|
+
}
|
|
639
|
+
oj_rxclass_keep(&oj_default_options.str_rx, keep);
|
|
640
|
+
// An instance variable of the Oj module is a reference the GC can follow on
|
|
641
|
+
// every engine, unlike a C global.
|
|
642
|
+
rb_ivar_set(Oj, oj_default_options_keeper_id, keep);
|
|
643
|
+
}
|
|
644
|
+
|
|
570
645
|
static VALUE set_def_opts(VALUE self, VALUE opts) {
|
|
571
646
|
Check_Type(opts, T_HASH);
|
|
647
|
+
// A :match_string option replaces the regexps instead of adding to them so
|
|
648
|
+
// the ones the defaults are holding have to be freed here, the only place
|
|
649
|
+
// that owns them. A per call options struct only aliases them.
|
|
650
|
+
if (Qnil != rb_hash_lookup(opts, match_string_sym)) {
|
|
651
|
+
oj_rxclass_cleanup(&oj_default_options.str_rx);
|
|
652
|
+
oj_default_options.str_rx.head = NULL;
|
|
653
|
+
oj_default_options.str_rx.tail = NULL;
|
|
654
|
+
}
|
|
572
655
|
oj_parse_options(opts, &oj_default_options);
|
|
656
|
+
keep_default_options();
|
|
573
657
|
|
|
574
658
|
return Qnil;
|
|
575
659
|
}
|
|
@@ -623,12 +707,143 @@ bool set_yesno_options(VALUE key, VALUE value, Options copts) {
|
|
|
623
707
|
return false;
|
|
624
708
|
}
|
|
625
709
|
|
|
626
|
-
static
|
|
627
|
-
|
|
628
|
-
|
|
710
|
+
inline static bool in_set(const char *set, char c) {
|
|
711
|
+
return '\0' != c && NULL != strchr(set, c);
|
|
712
|
+
}
|
|
713
|
+
|
|
714
|
+
// The format is used with one double and nothing else, so a directive that
|
|
715
|
+
// asks for anything more takes it from whatever is left in the argument
|
|
716
|
+
// registers. %s reads it as a pointer and %n writes through it.
|
|
717
|
+
static void validate_float_format(const char *str, size_t len) {
|
|
718
|
+
const char *s = str;
|
|
719
|
+
const char *end = str + len;
|
|
720
|
+
int cnt = 0;
|
|
721
|
+
|
|
722
|
+
for (; s < end; s++) {
|
|
723
|
+
if ('%' != *s) {
|
|
724
|
+
continue;
|
|
725
|
+
}
|
|
726
|
+
s++;
|
|
727
|
+
if (s < end && '%' == *s) {
|
|
728
|
+
continue;
|
|
729
|
+
}
|
|
730
|
+
if (1 < ++cnt) {
|
|
731
|
+
rb_raise(rb_eArgError, ":float_format must not have more than one directive.");
|
|
732
|
+
}
|
|
733
|
+
for (; s < end && in_set("-+ #0", *s); s++) {
|
|
734
|
+
}
|
|
735
|
+
for (; s < end && '0' <= *s && *s <= '9'; s++) {
|
|
736
|
+
}
|
|
737
|
+
if (s < end && '.' == *s) {
|
|
738
|
+
for (s++; s < end && '0' <= *s && *s <= '9'; s++) {
|
|
739
|
+
}
|
|
740
|
+
}
|
|
741
|
+
if (s < end && 'l' == *s) {
|
|
742
|
+
s++;
|
|
743
|
+
}
|
|
744
|
+
if (end <= s || !in_set("aAeEfgG", *s)) {
|
|
745
|
+
rb_raise(rb_eArgError, ":float_format directive must be one of aAeEfgG and take no argument of its own.");
|
|
746
|
+
}
|
|
747
|
+
}
|
|
748
|
+
}
|
|
749
|
+
|
|
750
|
+
static const char *make_only_value(VALUE v) {
|
|
751
|
+
switch (rb_type(v)) {
|
|
752
|
+
case RUBY_T_NIL:
|
|
753
|
+
case RUBY_T_NONE: return NULL;
|
|
754
|
+
case RUBY_T_ARRAY: {
|
|
755
|
+
long len = rb_array_len(v);
|
|
756
|
+
long i;
|
|
757
|
+
long size = 0;
|
|
758
|
+
char *buf;
|
|
759
|
+
char *bp;
|
|
760
|
+
|
|
761
|
+
for (i = 0; i < len; i++) {
|
|
762
|
+
VALUE x = rb_ary_entry(v, i);
|
|
763
|
+
|
|
764
|
+
switch (rb_type(x)) {
|
|
765
|
+
case RUBY_T_SYMBOL:
|
|
766
|
+
size += strlen(rb_id2name(rb_sym2id(x)));
|
|
767
|
+
size++;
|
|
768
|
+
break;
|
|
769
|
+
case RUBY_T_STRING:
|
|
770
|
+
size += strlen(StringValueCStr(x));
|
|
771
|
+
size++;
|
|
772
|
+
break;
|
|
773
|
+
default: rb_raise(rb_eArgError, ":only and :except must be nil, symbol, string, or array."); break;
|
|
774
|
+
}
|
|
775
|
+
}
|
|
776
|
+
if (0 == size) {
|
|
777
|
+
return NULL;
|
|
778
|
+
}
|
|
779
|
+
buf = OJ_R_ALLOC_N(char, size + 2);
|
|
780
|
+
bp = buf;
|
|
781
|
+
*bp++ = ':';
|
|
782
|
+
for (i = 0; i < len; i++) {
|
|
783
|
+
VALUE x = rb_ary_entry(v, i);
|
|
784
|
+
const char *str;
|
|
785
|
+
|
|
786
|
+
switch (rb_type(x)) {
|
|
787
|
+
case RUBY_T_SYMBOL:
|
|
788
|
+
str = rb_id2name(rb_sym2id(x));
|
|
789
|
+
size = strlen(str);
|
|
790
|
+
memcpy(bp, str, size);
|
|
791
|
+
bp += size;
|
|
792
|
+
*bp++ = ':';
|
|
793
|
+
break;
|
|
794
|
+
case RUBY_T_STRING:
|
|
795
|
+
str = StringValueCStr(x);
|
|
796
|
+
size = strlen(str);
|
|
797
|
+
memcpy(bp, str, size);
|
|
798
|
+
bp += size;
|
|
799
|
+
*bp++ = ':';
|
|
800
|
+
break;
|
|
801
|
+
default:
|
|
802
|
+
// ignore
|
|
803
|
+
break;
|
|
804
|
+
}
|
|
805
|
+
}
|
|
806
|
+
*bp = '\0';
|
|
807
|
+
|
|
808
|
+
return buf;
|
|
809
|
+
}
|
|
810
|
+
case RUBY_T_STRING: {
|
|
811
|
+
const char *str = StringValueCStr(v);
|
|
812
|
+
size_t size = strlen(str);
|
|
813
|
+
char *buf = OJ_R_ALLOC_N(char, size + 3);
|
|
814
|
+
|
|
815
|
+
buf[0] = ':';
|
|
816
|
+
strcpy(buf + 1, str);
|
|
817
|
+
buf[size + 1] = ':';
|
|
818
|
+
buf[size + 2] = '\0';
|
|
819
|
+
|
|
820
|
+
return buf;
|
|
821
|
+
}
|
|
822
|
+
case RUBY_T_SYMBOL: {
|
|
823
|
+
const char *str = rb_id2name(rb_sym2id(v));
|
|
824
|
+
size_t size = strlen(str);
|
|
825
|
+
char *buf = OJ_R_ALLOC_N(char, size + 3);
|
|
826
|
+
|
|
827
|
+
buf[0] = ':';
|
|
828
|
+
strcpy(buf + 1, str);
|
|
829
|
+
buf[size + 1] = ':';
|
|
830
|
+
buf[size + 2] = '\0';
|
|
831
|
+
|
|
832
|
+
return buf;
|
|
833
|
+
}
|
|
834
|
+
default: rb_raise(rb_eArgError, ":only and zzz :except must be nil, symbol, string, or array."); break;
|
|
835
|
+
}
|
|
836
|
+
return NULL;
|
|
837
|
+
}
|
|
838
|
+
|
|
839
|
+
// Apply one key and value to copts. Returns true if the key named an option Oj
|
|
840
|
+
// knows and false if it did not. An unrecognized key is still ignored rather
|
|
841
|
+
// than an error; the return only lets a caller tell the two cases apart.
|
|
842
|
+
static bool parse_one_option(VALUE k, VALUE v, Options copts) {
|
|
843
|
+
size_t len;
|
|
629
844
|
|
|
630
845
|
if (set_yesno_options(k, v, copts)) {
|
|
631
|
-
return
|
|
846
|
+
return true;
|
|
632
847
|
}
|
|
633
848
|
if (oj_indent_sym == k) {
|
|
634
849
|
switch (rb_type(v)) {
|
|
@@ -640,7 +855,10 @@ static int parse_options_cb(VALUE k, VALUE v, VALUE opts) {
|
|
|
640
855
|
case T_FIXNUM:
|
|
641
856
|
copts->dump_opts.indent_size = 0;
|
|
642
857
|
*copts->dump_opts.indent_str = '\0';
|
|
643
|
-
|
|
858
|
+
if (MAX_INDENT < FIX2INT(v)) {
|
|
859
|
+
rb_raise(rb_eArgError, "indent is limited to %d characters.", MAX_INDENT);
|
|
860
|
+
}
|
|
861
|
+
copts->indent = FIX2INT(v);
|
|
644
862
|
break;
|
|
645
863
|
case T_STRING:
|
|
646
864
|
if (sizeof(copts->dump_opts.indent_str) <= (len = RSTRING_LEN(v))) {
|
|
@@ -751,7 +969,7 @@ static int parse_options_cb(VALUE k, VALUE v, VALUE opts) {
|
|
|
751
969
|
}
|
|
752
970
|
} else if (bigdecimal_load_sym == k) {
|
|
753
971
|
if (Qnil == v) {
|
|
754
|
-
return
|
|
972
|
+
return true;
|
|
755
973
|
}
|
|
756
974
|
|
|
757
975
|
if (bigdecimal_sym == v || Qtrue == v) {
|
|
@@ -767,7 +985,7 @@ static int parse_options_cb(VALUE k, VALUE v, VALUE opts) {
|
|
|
767
985
|
}
|
|
768
986
|
} else if (compat_bigdecimal_sym == k) {
|
|
769
987
|
if (Qnil == v) {
|
|
770
|
-
return
|
|
988
|
+
return true;
|
|
771
989
|
}
|
|
772
990
|
copts->compat_bigdec = (Qtrue == v);
|
|
773
991
|
} else if (oj_decimal_class_sym == k) {
|
|
@@ -779,9 +997,13 @@ static int parse_options_cb(VALUE k, VALUE v, VALUE opts) {
|
|
|
779
997
|
rb_raise(rb_eArgError, ":decimal_class must be BigDecimal or Float.");
|
|
780
998
|
}
|
|
781
999
|
} else if (create_id_sym == k) {
|
|
1000
|
+
// A per call copy of the options aliases the buffer the default
|
|
1001
|
+
// options own, so only the defaults may free it.
|
|
1002
|
+
bool owned = (&oj_default_options == copts && NULL != copts->create_id && oj_json_class != copts->create_id);
|
|
1003
|
+
|
|
782
1004
|
if (Qnil == v) {
|
|
783
|
-
if (
|
|
784
|
-
OJ_R_FREE((char *)
|
|
1005
|
+
if (owned) {
|
|
1006
|
+
OJ_R_FREE((char *)copts->create_id);
|
|
785
1007
|
}
|
|
786
1008
|
copts->create_id = NULL;
|
|
787
1009
|
copts->create_id_len = 0;
|
|
@@ -789,7 +1011,10 @@ static int parse_options_cb(VALUE k, VALUE v, VALUE opts) {
|
|
|
789
1011
|
const char *str = StringValuePtr(v);
|
|
790
1012
|
|
|
791
1013
|
len = RSTRING_LEN(v);
|
|
792
|
-
if (len != copts->create_id_len || 0 != strcmp(copts->create_id, str)) {
|
|
1014
|
+
if (NULL == copts->create_id || len != copts->create_id_len || 0 != strcmp(copts->create_id, str)) {
|
|
1015
|
+
if (owned) {
|
|
1016
|
+
OJ_R_FREE((char *)copts->create_id);
|
|
1017
|
+
}
|
|
793
1018
|
copts->create_id = OJ_R_ALLOC_N(char, len + 1);
|
|
794
1019
|
strcpy((char *)copts->create_id, str);
|
|
795
1020
|
copts->create_id_len = len;
|
|
@@ -855,7 +1080,7 @@ static int parse_options_cb(VALUE k, VALUE v, VALUE opts) {
|
|
|
855
1080
|
}
|
|
856
1081
|
} else if (nan_sym == k) {
|
|
857
1082
|
if (Qnil == v) {
|
|
858
|
-
return
|
|
1083
|
+
return true;
|
|
859
1084
|
}
|
|
860
1085
|
if (null_sym == v) {
|
|
861
1086
|
copts->dump_opts.nan_dump = NullNan;
|
|
@@ -872,7 +1097,7 @@ static int parse_options_cb(VALUE k, VALUE v, VALUE opts) {
|
|
|
872
1097
|
}
|
|
873
1098
|
} else if (omit_nil_sym == k) {
|
|
874
1099
|
if (Qnil == v) {
|
|
875
|
-
return
|
|
1100
|
+
return true;
|
|
876
1101
|
}
|
|
877
1102
|
if (Qtrue == v) {
|
|
878
1103
|
copts->dump_opts.omit_nil = true;
|
|
@@ -883,7 +1108,7 @@ static int parse_options_cb(VALUE k, VALUE v, VALUE opts) {
|
|
|
883
1108
|
}
|
|
884
1109
|
} else if (omit_null_byte_sym == k) {
|
|
885
1110
|
if (Qnil == v) {
|
|
886
|
-
return
|
|
1111
|
+
return true;
|
|
887
1112
|
}
|
|
888
1113
|
if (Qtrue == v) {
|
|
889
1114
|
copts->dump_opts.omit_null_byte = true;
|
|
@@ -921,7 +1146,11 @@ static int parse_options_cb(VALUE k, VALUE v, VALUE opts) {
|
|
|
921
1146
|
copts->array_class = v;
|
|
922
1147
|
}
|
|
923
1148
|
} else if (ignore_sym == k) {
|
|
924
|
-
|
|
1149
|
+
// Only free when replacing the defaults; a per-call copy's ignore still
|
|
1150
|
+
// aliases the default-owned buffer, which oj_free_call_options() frees.
|
|
1151
|
+
if (&oj_default_options == copts) {
|
|
1152
|
+
OJ_R_FREE(copts->ignore);
|
|
1153
|
+
}
|
|
925
1154
|
copts->ignore = NULL;
|
|
926
1155
|
if (Qnil != v) {
|
|
927
1156
|
size_t cnt;
|
|
@@ -940,7 +1169,7 @@ static int parse_options_cb(VALUE k, VALUE v, VALUE opts) {
|
|
|
940
1169
|
}
|
|
941
1170
|
} else if (integer_range_sym == k) {
|
|
942
1171
|
if (Qnil == v) {
|
|
943
|
-
return
|
|
1172
|
+
return true;
|
|
944
1173
|
}
|
|
945
1174
|
if (rb_obj_class(v) == rb_cRange) {
|
|
946
1175
|
VALUE min = rb_funcall(v, oj_begin_id, 0);
|
|
@@ -955,9 +1184,23 @@ static int parse_options_cb(VALUE k, VALUE v, VALUE opts) {
|
|
|
955
1184
|
} else if (Qfalse != v) {
|
|
956
1185
|
rb_raise(rb_eArgError, ":integer_range must be a range of Fixnum.");
|
|
957
1186
|
}
|
|
1187
|
+
} else if (max_integer_digits_sym == k) {
|
|
1188
|
+
if (Qnil == v || Qfalse == v) {
|
|
1189
|
+
copts->max_integer_digits = 0;
|
|
1190
|
+
} else if (T_FIXNUM == rb_type(v)) {
|
|
1191
|
+
long n = FIX2LONG(v);
|
|
1192
|
+
|
|
1193
|
+
if (n < 0) {
|
|
1194
|
+
rb_raise(rb_eArgError, ":max_integer_digits must be >= 0.");
|
|
1195
|
+
}
|
|
1196
|
+
|
|
1197
|
+
copts->max_integer_digits = (size_t)n;
|
|
1198
|
+
} else {
|
|
1199
|
+
rb_raise(rb_eArgError, ":max_integer_digits must be a non-negative Integer.");
|
|
1200
|
+
}
|
|
958
1201
|
} else if (symbol_keys_sym == k || oj_symbolize_names_sym == k) {
|
|
959
1202
|
if (Qnil == v) {
|
|
960
|
-
return
|
|
1203
|
+
return true;
|
|
961
1204
|
}
|
|
962
1205
|
copts->sym_key = (Qtrue == v) ? Yes : No;
|
|
963
1206
|
|
|
@@ -977,23 +1220,180 @@ static int parse_options_cb(VALUE k, VALUE v, VALUE opts) {
|
|
|
977
1220
|
if (6 < RSTRING_LEN(v)) {
|
|
978
1221
|
rb_raise(rb_eArgError, ":float_format must be 6 bytes or less.");
|
|
979
1222
|
}
|
|
1223
|
+
validate_float_format(RSTRING_PTR(v), (size_t)RSTRING_LEN(v));
|
|
980
1224
|
strncpy(copts->float_fmt, RSTRING_PTR(v), (size_t)RSTRING_LEN(v));
|
|
981
1225
|
copts->float_fmt[RSTRING_LEN(v)] = '\0';
|
|
1226
|
+
} else if (only_sym == k) {
|
|
1227
|
+
// Only free when replacing the defaults; a per-call copy's pointer still
|
|
1228
|
+
// aliases the default-owned buffer, which oj_free_call_options() frees.
|
|
1229
|
+
if (&oj_default_options == copts && NULL != copts->dump_opts.only) {
|
|
1230
|
+
OJ_R_FREE((void *)copts->dump_opts.only);
|
|
1231
|
+
}
|
|
1232
|
+
copts->dump_opts.only = make_only_value(v);
|
|
1233
|
+
} else if (except_sym == k) {
|
|
1234
|
+
if (&oj_default_options == copts && NULL != copts->dump_opts.except) {
|
|
1235
|
+
OJ_R_FREE((void *)copts->dump_opts.except);
|
|
1236
|
+
}
|
|
1237
|
+
copts->dump_opts.except = make_only_value(v);
|
|
1238
|
+
} else {
|
|
1239
|
+
return false;
|
|
1240
|
+
}
|
|
1241
|
+
return true;
|
|
1242
|
+
}
|
|
1243
|
+
|
|
1244
|
+
// Collects the return of parse_one_option() over every key in a hash.
|
|
1245
|
+
struct _optsParse {
|
|
1246
|
+
Options copts;
|
|
1247
|
+
bool consumed;
|
|
1248
|
+
};
|
|
1249
|
+
|
|
1250
|
+
static int parse_options_cb(VALUE k, VALUE v, VALUE opts) {
|
|
1251
|
+
struct _optsParse *op = (struct _optsParse *)opts;
|
|
1252
|
+
|
|
1253
|
+
if (parse_one_option(k, v, op->copts)) {
|
|
1254
|
+
op->consumed = true;
|
|
982
1255
|
}
|
|
983
1256
|
return ST_CONTINUE;
|
|
984
1257
|
}
|
|
985
1258
|
|
|
986
|
-
|
|
1259
|
+
// Apply the options in ropts to copts and report whether any key was
|
|
1260
|
+
// recognized. A hash of nothing but unknown keys leaves copts untouched and
|
|
1261
|
+
// returns false.
|
|
1262
|
+
bool oj_parse_options_consumed(VALUE ropts, Options copts) {
|
|
1263
|
+
struct _optsParse op = {copts, false};
|
|
1264
|
+
|
|
987
1265
|
if (T_HASH != rb_type(ropts)) {
|
|
988
|
-
return;
|
|
1266
|
+
return false;
|
|
1267
|
+
}
|
|
1268
|
+
rb_hash_foreach(ropts, parse_options_cb, (VALUE)&op);
|
|
1269
|
+
if (Qnil != rb_hash_lookup(ropts, match_string_sym)) {
|
|
1270
|
+
op.consumed = true;
|
|
989
1271
|
}
|
|
990
|
-
rb_hash_foreach(ropts, parse_options_cb, (VALUE)copts);
|
|
991
1272
|
oj_parse_opt_match_string(&copts->str_rx, ropts);
|
|
992
1273
|
|
|
993
1274
|
copts->dump_opts.use = (0 < copts->dump_opts.indent_size || 0 < copts->dump_opts.after_size ||
|
|
994
1275
|
0 < copts->dump_opts.before_size || 0 < copts->dump_opts.hash_size ||
|
|
995
1276
|
0 < copts->dump_opts.array_size);
|
|
996
|
-
|
|
1277
|
+
|
|
1278
|
+
return op.consumed;
|
|
1279
|
+
}
|
|
1280
|
+
|
|
1281
|
+
void oj_parse_options(VALUE ropts, Options copts) {
|
|
1282
|
+
oj_parse_options_consumed(ropts, copts);
|
|
1283
|
+
}
|
|
1284
|
+
|
|
1285
|
+
// Free the option buffers that oj_parse_options() allocated for a single call.
|
|
1286
|
+
// A per-call options struct is a copy of oj_default_options, so its create_id,
|
|
1287
|
+
// ignore, only, and except members initially alias the ones owned by the
|
|
1288
|
+
// defaults. Only free a member when it differs from the default, i.e. when it
|
|
1289
|
+
// was allocated for this call; the default-owned buffers must be left alone.
|
|
1290
|
+
void oj_free_call_options(Options copts) {
|
|
1291
|
+
if (NULL != copts->create_id && oj_default_options.create_id != copts->create_id) {
|
|
1292
|
+
OJ_R_FREE((char *)copts->create_id);
|
|
1293
|
+
copts->create_id = NULL;
|
|
1294
|
+
copts->create_id_len = 0;
|
|
1295
|
+
}
|
|
1296
|
+
if (NULL != copts->ignore && oj_default_options.ignore != copts->ignore) {
|
|
1297
|
+
OJ_R_FREE(copts->ignore);
|
|
1298
|
+
copts->ignore = NULL;
|
|
1299
|
+
}
|
|
1300
|
+
if (NULL != copts->dump_opts.only && oj_default_options.dump_opts.only != copts->dump_opts.only) {
|
|
1301
|
+
OJ_R_FREE((void *)copts->dump_opts.only);
|
|
1302
|
+
copts->dump_opts.only = NULL;
|
|
1303
|
+
}
|
|
1304
|
+
if (NULL != copts->dump_opts.except && oj_default_options.dump_opts.except != copts->dump_opts.except) {
|
|
1305
|
+
OJ_R_FREE((void *)copts->dump_opts.except);
|
|
1306
|
+
copts->dump_opts.except = NULL;
|
|
1307
|
+
}
|
|
1308
|
+
}
|
|
1309
|
+
|
|
1310
|
+
static char *dup_option_str(const char *str, size_t len) {
|
|
1311
|
+
char *buf = OJ_R_ALLOC_N(char, len + 1);
|
|
1312
|
+
|
|
1313
|
+
memcpy(buf, str, len);
|
|
1314
|
+
buf[len] = '\0';
|
|
1315
|
+
|
|
1316
|
+
return buf;
|
|
1317
|
+
}
|
|
1318
|
+
|
|
1319
|
+
// Give an options struct private copies of the option buffers it still shares
|
|
1320
|
+
// with the defaults so that it owns all of them.
|
|
1321
|
+
//
|
|
1322
|
+
// An options struct that outlives the call it was created in can not rely on
|
|
1323
|
+
// the default-owned buffers it aliases: Oj.default_options= is free to replace
|
|
1324
|
+
// them at any time, which would leave the alias dangling. Call this once, in
|
|
1325
|
+
// the call that creates such an object and after oj_parse_options(), then free
|
|
1326
|
+
// the buffers with oj_options_release() when the object is collected.
|
|
1327
|
+
void oj_options_take_ownership(Options copts) {
|
|
1328
|
+
if (NULL != copts->create_id && oj_default_options.create_id == copts->create_id) {
|
|
1329
|
+
copts->create_id = dup_option_str(copts->create_id, copts->create_id_len);
|
|
1330
|
+
}
|
|
1331
|
+
if (NULL != copts->ignore && oj_default_options.ignore == copts->ignore) {
|
|
1332
|
+
VALUE *vp;
|
|
1333
|
+
VALUE *buf;
|
|
1334
|
+
size_t cnt = 0;
|
|
1335
|
+
|
|
1336
|
+
for (vp = copts->ignore; Qnil != *vp; vp++) {
|
|
1337
|
+
cnt++;
|
|
1338
|
+
}
|
|
1339
|
+
buf = OJ_R_ALLOC_N(VALUE, cnt + 1);
|
|
1340
|
+
memcpy(buf, copts->ignore, sizeof(VALUE) * (cnt + 1));
|
|
1341
|
+
copts->ignore = buf;
|
|
1342
|
+
}
|
|
1343
|
+
if (NULL != copts->dump_opts.only && oj_default_options.dump_opts.only == copts->dump_opts.only) {
|
|
1344
|
+
copts->dump_opts.only = dup_option_str(copts->dump_opts.only, strlen(copts->dump_opts.only));
|
|
1345
|
+
}
|
|
1346
|
+
if (NULL != copts->dump_opts.except && oj_default_options.dump_opts.except == copts->dump_opts.except) {
|
|
1347
|
+
copts->dump_opts.except = dup_option_str(copts->dump_opts.except, strlen(copts->dump_opts.except));
|
|
1348
|
+
}
|
|
1349
|
+
}
|
|
1350
|
+
|
|
1351
|
+
// Free the option buffers of an options struct that owns all of them, i.e. one
|
|
1352
|
+
// that oj_options_take_ownership() was called on. Unlike oj_free_call_options()
|
|
1353
|
+
// this never looks at the defaults, so it is safe to call from a GC free
|
|
1354
|
+
// function, where the defaults may have been replaced since the object was
|
|
1355
|
+
// created.
|
|
1356
|
+
void oj_options_release(Options copts) {
|
|
1357
|
+
if (NULL != copts->create_id) {
|
|
1358
|
+
OJ_R_FREE((char *)copts->create_id);
|
|
1359
|
+
copts->create_id = NULL;
|
|
1360
|
+
copts->create_id_len = 0;
|
|
1361
|
+
}
|
|
1362
|
+
if (NULL != copts->ignore) {
|
|
1363
|
+
OJ_R_FREE(copts->ignore);
|
|
1364
|
+
copts->ignore = NULL;
|
|
1365
|
+
}
|
|
1366
|
+
if (NULL != copts->dump_opts.only) {
|
|
1367
|
+
OJ_R_FREE((void *)copts->dump_opts.only);
|
|
1368
|
+
copts->dump_opts.only = NULL;
|
|
1369
|
+
}
|
|
1370
|
+
if (NULL != copts->dump_opts.except) {
|
|
1371
|
+
OJ_R_FREE((void *)copts->dump_opts.except);
|
|
1372
|
+
copts->dump_opts.except = NULL;
|
|
1373
|
+
}
|
|
1374
|
+
// The str_rx chain is detached from the defaults when the owner is created
|
|
1375
|
+
// so the chain, if there is one, was built for this options struct alone.
|
|
1376
|
+
oj_rxclass_cleanup(&copts->str_rx);
|
|
1377
|
+
}
|
|
1378
|
+
|
|
1379
|
+
// Mark the Ruby objects held by an owned options struct. A long lived object
|
|
1380
|
+
// such as a writer or an encoder can be the only reference to the classes in
|
|
1381
|
+
// the options so without this they could be collected while the owner is still
|
|
1382
|
+
// alive leaving the options with dangling VALUEs.
|
|
1383
|
+
void oj_options_mark(Options copts) {
|
|
1384
|
+
if (Qnil != copts->hash_class) {
|
|
1385
|
+
rb_gc_mark(copts->hash_class);
|
|
1386
|
+
}
|
|
1387
|
+
if (Qnil != copts->array_class) {
|
|
1388
|
+
rb_gc_mark(copts->array_class);
|
|
1389
|
+
}
|
|
1390
|
+
if (NULL != copts->ignore) {
|
|
1391
|
+
VALUE *vp;
|
|
1392
|
+
|
|
1393
|
+
for (vp = copts->ignore; Qnil != *vp; vp++) {
|
|
1394
|
+
rb_gc_mark(*vp);
|
|
1395
|
+
}
|
|
1396
|
+
}
|
|
997
1397
|
}
|
|
998
1398
|
|
|
999
1399
|
static int match_string_cb(VALUE key, VALUE value, VALUE rx) {
|
|
@@ -1287,6 +1687,7 @@ static VALUE dump_ensure(VALUE a) {
|
|
|
1287
1687
|
volatile struct dump_arg *arg = (void *)a;
|
|
1288
1688
|
|
|
1289
1689
|
oj_out_free(arg->out);
|
|
1690
|
+
oj_free_call_options(arg->copts);
|
|
1290
1691
|
|
|
1291
1692
|
return Qnil;
|
|
1292
1693
|
}
|
|
@@ -1402,6 +1803,7 @@ static VALUE to_file(int argc, VALUE *argv, VALUE self) {
|
|
|
1402
1803
|
oj_parse_options(argv[2], &copts);
|
|
1403
1804
|
}
|
|
1404
1805
|
oj_write_obj_to_file(argv[1], StringValuePtr(*argv), &copts);
|
|
1806
|
+
oj_free_call_options(&copts);
|
|
1405
1807
|
|
|
1406
1808
|
return Qnil;
|
|
1407
1809
|
}
|
|
@@ -1423,6 +1825,7 @@ static VALUE to_stream(int argc, VALUE *argv, VALUE self) {
|
|
|
1423
1825
|
oj_parse_options(argv[2], &copts);
|
|
1424
1826
|
}
|
|
1425
1827
|
oj_write_obj_to_stream(argv[1], *argv, &copts);
|
|
1828
|
+
oj_free_call_options(&copts);
|
|
1426
1829
|
|
|
1427
1830
|
return Qnil;
|
|
1428
1831
|
}
|
|
@@ -1780,6 +2183,78 @@ static VALUE mem_report(VALUE self) {
|
|
|
1780
2183
|
*
|
|
1781
2184
|
* - *:wab* specifically for WAB data exchange.
|
|
1782
2185
|
*/
|
|
2186
|
+
|
|
2187
|
+
// =============================================================================
|
|
2188
|
+
// Runtime SIMD CPU detection
|
|
2189
|
+
// Cross-platform support for Windows (MSVC), Linux, and macOS (GCC/Clang)
|
|
2190
|
+
// =============================================================================
|
|
2191
|
+
SIMD_Implementation oj_get_simd_implementation(void) {
|
|
2192
|
+
#ifdef HAVE_SIMD_X86
|
|
2193
|
+
// x86/x86_64 runtime detection
|
|
2194
|
+
|
|
2195
|
+
#if defined(_MSC_VER)
|
|
2196
|
+
// MSVC: Use __cpuid intrinsic
|
|
2197
|
+
int cpu_info[4];
|
|
2198
|
+
__cpuid(cpu_info, 1);
|
|
2199
|
+
|
|
2200
|
+
// Check for SSE4.2 (bit 20 of ECX)
|
|
2201
|
+
if (cpu_info[2] & (1 << 20)) {
|
|
2202
|
+
return SIMD_SSE42;
|
|
2203
|
+
}
|
|
2204
|
+
// Check for SSE2 (bit 26 of EDX)
|
|
2205
|
+
if (cpu_info[3] & (1 << 26)) {
|
|
2206
|
+
return SIMD_SSE2;
|
|
2207
|
+
}
|
|
2208
|
+
|
|
2209
|
+
#elif defined(__GNUC__) || defined(__clang__)
|
|
2210
|
+
// GCC/Clang: Use __builtin_cpu_supports if available
|
|
2211
|
+
#if defined(__has_builtin)
|
|
2212
|
+
#if __has_builtin(__builtin_cpu_supports)
|
|
2213
|
+
#define OJ_HAS_BUILTIN_CPU_SUPPORTS 1
|
|
2214
|
+
#endif
|
|
2215
|
+
#elif defined(__GNUC__) && (__GNUC__ > 4 || (__GNUC__ == 4 && __GNUC_MINOR__ >= 8))
|
|
2216
|
+
// GCC 4.8+ has __builtin_cpu_supports
|
|
2217
|
+
#define OJ_HAS_BUILTIN_CPU_SUPPORTS 1
|
|
2218
|
+
#endif
|
|
2219
|
+
|
|
2220
|
+
#ifdef OJ_HAS_BUILTIN_CPU_SUPPORTS
|
|
2221
|
+
#ifdef HAVE_SIMD_SSE4_2
|
|
2222
|
+
if (__builtin_cpu_supports("sse4.2")) {
|
|
2223
|
+
return SIMD_SSE42;
|
|
2224
|
+
}
|
|
2225
|
+
#endif
|
|
2226
|
+
#ifdef HAVE_SIMD_SSE2
|
|
2227
|
+
if (__builtin_cpu_supports("sse2")) {
|
|
2228
|
+
return SIMD_SSE2;
|
|
2229
|
+
}
|
|
2230
|
+
#endif
|
|
2231
|
+
#else
|
|
2232
|
+
// Fallback: Use CPUID instruction directly
|
|
2233
|
+
unsigned int eax, ebx, ecx, edx;
|
|
2234
|
+
if (__get_cpuid(1, &eax, &ebx, &ecx, &edx)) {
|
|
2235
|
+
// Check for SSE4.2 (bit 20 of ECX)
|
|
2236
|
+
if (ecx & (1 << 20)) {
|
|
2237
|
+
return SIMD_SSE42;
|
|
2238
|
+
}
|
|
2239
|
+
// Check for SSE2 (bit 26 of EDX)
|
|
2240
|
+
if (edx & (1 << 26)) {
|
|
2241
|
+
return SIMD_SSE2;
|
|
2242
|
+
}
|
|
2243
|
+
}
|
|
2244
|
+
#endif // OJ_HAS_BUILTIN_CPU_SUPPORTS
|
|
2245
|
+
|
|
2246
|
+
#endif // _MSC_VER vs GCC/Clang
|
|
2247
|
+
|
|
2248
|
+
#endif // HAVE_SIMD_X86
|
|
2249
|
+
|
|
2250
|
+
#ifdef HAVE_SIMD_NEON
|
|
2251
|
+
// ARM NEON is always available on ARM64 and detected at compile time
|
|
2252
|
+
return SIMD_NEON;
|
|
2253
|
+
#endif
|
|
2254
|
+
|
|
2255
|
+
return SIMD_NONE;
|
|
2256
|
+
}
|
|
2257
|
+
|
|
1783
2258
|
void Init_oj(void) {
|
|
1784
2259
|
int err = 0;
|
|
1785
2260
|
|
|
@@ -1953,6 +2428,8 @@ void Init_oj(void) {
|
|
|
1953
2428
|
rb_gc_register_address(&escape_mode_sym);
|
|
1954
2429
|
integer_range_sym = ID2SYM(rb_intern("integer_range"));
|
|
1955
2430
|
rb_gc_register_address(&integer_range_sym);
|
|
2431
|
+
max_integer_digits_sym = ID2SYM(rb_intern("max_integer_digits"));
|
|
2432
|
+
rb_gc_register_address(&max_integer_digits_sym);
|
|
1956
2433
|
fast_sym = ID2SYM(rb_intern("fast"));
|
|
1957
2434
|
rb_gc_register_address(&fast_sym);
|
|
1958
2435
|
float_format_sym = ID2SYM(rb_intern("float_format"));
|
|
@@ -2059,6 +2536,10 @@ void Init_oj(void) {
|
|
|
2059
2536
|
rb_gc_register_address(&xmlschema_sym);
|
|
2060
2537
|
xss_safe_sym = ID2SYM(rb_intern("xss_safe"));
|
|
2061
2538
|
rb_gc_register_address(&xss_safe_sym);
|
|
2539
|
+
only_sym = ID2SYM(rb_intern("only"));
|
|
2540
|
+
rb_gc_register_address(&only_sym);
|
|
2541
|
+
except_sym = ID2SYM(rb_intern("except"));
|
|
2542
|
+
rb_gc_register_address(&except_sym);
|
|
2062
2543
|
|
|
2063
2544
|
oj_slash_string = rb_str_new2("/");
|
|
2064
2545
|
rb_gc_register_address(&oj_slash_string);
|
|
@@ -2080,10 +2561,18 @@ void Init_oj(void) {
|
|
|
2080
2561
|
#endif
|
|
2081
2562
|
oj_init_doc();
|
|
2082
2563
|
|
|
2564
|
+
SIMD_Impl = oj_get_simd_implementation();
|
|
2565
|
+
|
|
2083
2566
|
oj_parser_init();
|
|
2084
2567
|
oj_scanner_init();
|
|
2085
2568
|
|
|
2086
2569
|
#ifdef HAVE_SIMD_NEON
|
|
2087
2570
|
initialize_neon();
|
|
2088
2571
|
#endif /* HAVE_SIMD_NEON */
|
|
2572
|
+
|
|
2573
|
+
#ifdef HAVE_SIMD_SSE4_2
|
|
2574
|
+
if (SIMD_Impl == SIMD_SSE42) {
|
|
2575
|
+
initialize_sse42();
|
|
2576
|
+
}
|
|
2577
|
+
#endif /* HAVE_SIMD_SSE4_2 */
|
|
2089
2578
|
}
|