oj 3.16.6 → 3.17.3

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.
Files changed (130) hide show
  1. checksums.yaml +4 -4
  2. data/CHANGELOG.md +81 -0
  3. data/README.md +0 -16
  4. data/ext/oj/compat.c +3 -3
  5. data/ext/oj/custom.c +17 -11
  6. data/ext/oj/dump.c +592 -81
  7. data/ext/oj/dump.h +9 -2
  8. data/ext/oj/dump_compat.c +15 -9
  9. data/ext/oj/dump_leaf.c +1 -1
  10. data/ext/oj/dump_object.c +32 -17
  11. data/ext/oj/dump_strict.c +20 -14
  12. data/ext/oj/extconf.rb +10 -7
  13. data/ext/oj/fast.c +40 -23
  14. data/ext/oj/intern.c +1 -1
  15. data/ext/oj/mimic_json.c +11 -7
  16. data/ext/oj/object.c +8 -8
  17. data/ext/oj/oj.c +256 -10
  18. data/ext/oj/oj.h +55 -52
  19. data/ext/oj/parse.c +243 -46
  20. data/ext/oj/parser.c +113 -37
  21. data/ext/oj/parser.h +2 -0
  22. data/ext/oj/rails.c +41 -36
  23. data/ext/oj/rxclass.c +1 -1
  24. data/ext/oj/rxclass.h +1 -1
  25. data/ext/oj/safe.c +230 -0
  26. data/ext/oj/safe.h +79 -0
  27. data/ext/oj/saj.c +13 -8
  28. data/ext/oj/scp.c +3 -6
  29. data/ext/oj/simd.h +219 -0
  30. data/ext/oj/sparse.c +6 -3
  31. data/ext/oj/stream_writer.c +3 -13
  32. data/ext/oj/strict.c +2 -4
  33. data/ext/oj/string_writer.c +5 -7
  34. data/ext/oj/usual.c +20 -7
  35. data/ext/oj/wab.c +5 -4
  36. data/lib/oj/version.rb +1 -1
  37. data/pages/Encoding.md +1 -1
  38. metadata +22 -114
  39. data/test/_test_active.rb +0 -75
  40. data/test/_test_active_mimic.rb +0 -95
  41. data/test/_test_mimic_rails.rb +0 -123
  42. data/test/activerecord/result_test.rb +0 -31
  43. data/test/activesupport6/abstract_unit.rb +0 -44
  44. data/test/activesupport6/decoding_test.rb +0 -133
  45. data/test/activesupport6/encoding_test.rb +0 -542
  46. data/test/activesupport6/encoding_test_cases.rb +0 -98
  47. data/test/activesupport6/test_common.rb +0 -17
  48. data/test/activesupport6/test_helper.rb +0 -163
  49. data/test/activesupport6/time_zone_test_helpers.rb +0 -39
  50. data/test/activesupport7/abstract_unit.rb +0 -52
  51. data/test/activesupport7/decoding_test.rb +0 -125
  52. data/test/activesupport7/encoding_test.rb +0 -536
  53. data/test/activesupport7/encoding_test_cases.rb +0 -104
  54. data/test/activesupport7/time_zone_test_helpers.rb +0 -47
  55. data/test/files.rb +0 -29
  56. data/test/foo.rb +0 -26
  57. data/test/helper.rb +0 -39
  58. data/test/isolated/shared.rb +0 -309
  59. data/test/isolated/test_mimic_after.rb +0 -13
  60. data/test/isolated/test_mimic_alone.rb +0 -12
  61. data/test/isolated/test_mimic_as_json.rb +0 -45
  62. data/test/isolated/test_mimic_before.rb +0 -13
  63. data/test/isolated/test_mimic_define.rb +0 -28
  64. data/test/isolated/test_mimic_rails_after.rb +0 -22
  65. data/test/isolated/test_mimic_rails_before.rb +0 -21
  66. data/test/isolated/test_mimic_redefine.rb +0 -15
  67. data/test/json_gem/json_addition_test.rb +0 -216
  68. data/test/json_gem/json_common_interface_test.rb +0 -155
  69. data/test/json_gem/json_encoding_test.rb +0 -107
  70. data/test/json_gem/json_ext_parser_test.rb +0 -21
  71. data/test/json_gem/json_fixtures_test.rb +0 -36
  72. data/test/json_gem/json_generator_test.rb +0 -413
  73. data/test/json_gem/json_generic_object_test.rb +0 -90
  74. data/test/json_gem/json_parser_test.rb +0 -477
  75. data/test/json_gem/json_string_matching_test.rb +0 -42
  76. data/test/json_gem/test_helper.rb +0 -30
  77. data/test/mem.rb +0 -34
  78. data/test/perf.rb +0 -102
  79. data/test/perf_compat.rb +0 -128
  80. data/test/perf_dump.rb +0 -50
  81. data/test/perf_fast.rb +0 -162
  82. data/test/perf_file.rb +0 -62
  83. data/test/perf_object.rb +0 -134
  84. data/test/perf_once.rb +0 -59
  85. data/test/perf_parser.rb +0 -183
  86. data/test/perf_saj.rb +0 -101
  87. data/test/perf_scp.rb +0 -140
  88. data/test/perf_simple.rb +0 -289
  89. data/test/perf_strict.rb +0 -137
  90. data/test/perf_wab.rb +0 -129
  91. data/test/prec.rb +0 -23
  92. data/test/sample/change.rb +0 -13
  93. data/test/sample/dir.rb +0 -18
  94. data/test/sample/doc.rb +0 -35
  95. data/test/sample/file.rb +0 -47
  96. data/test/sample/group.rb +0 -15
  97. data/test/sample/hasprops.rb +0 -15
  98. data/test/sample/layer.rb +0 -11
  99. data/test/sample/line.rb +0 -20
  100. data/test/sample/oval.rb +0 -10
  101. data/test/sample/rect.rb +0 -9
  102. data/test/sample/shape.rb +0 -34
  103. data/test/sample/text.rb +0 -19
  104. data/test/sample.rb +0 -54
  105. data/test/sample_json.rb +0 -37
  106. data/test/test_compat.rb +0 -567
  107. data/test/test_custom.rb +0 -555
  108. data/test/test_debian.rb +0 -50
  109. data/test/test_fast.rb +0 -526
  110. data/test/test_file.rb +0 -250
  111. data/test/test_gc.rb +0 -60
  112. data/test/test_generate.rb +0 -21
  113. data/test/test_hash.rb +0 -39
  114. data/test/test_integer_range.rb +0 -72
  115. data/test/test_null.rb +0 -376
  116. data/test/test_object.rb +0 -1030
  117. data/test/test_parser.rb +0 -11
  118. data/test/test_parser_debug.rb +0 -27
  119. data/test/test_parser_saj.rb +0 -337
  120. data/test/test_parser_usual.rb +0 -251
  121. data/test/test_rails.rb +0 -35
  122. data/test/test_saj.rb +0 -188
  123. data/test/test_scp.rb +0 -431
  124. data/test/test_strict.rb +0 -441
  125. data/test/test_various.rb +0 -801
  126. data/test/test_wab.rb +0 -311
  127. data/test/test_writer.rb +0 -380
  128. data/test/tests.rb +0 -33
  129. data/test/tests_mimic.rb +0 -23
  130. data/test/tests_mimic_addition.rb +0 -16
data/ext/oj/dump.h CHANGED
@@ -7,12 +7,17 @@
7
7
  #include <ruby.h>
8
8
 
9
9
  #include "oj.h"
10
+ #include "simd.h"
10
11
 
11
12
  #define MAX_DEPTH 1000
12
13
 
13
14
  // Extra padding at end of buffer.
14
15
  #define BUFFER_EXTRA 64
15
16
 
17
+ #ifdef HAVE_SIMD_NEON
18
+ extern void initialize_neon(void);
19
+ #endif /* HAVE_SIMD_NEON */
20
+
16
21
  extern void oj_dump_nil(VALUE obj, int depth, Out out, bool as_ok);
17
22
  extern void oj_dump_true(VALUE obj, int depth, Out out, bool as_ok);
18
23
  extern void oj_dump_false(VALUE obj, int depth, Out out, bool as_ok);
@@ -30,7 +35,7 @@ extern void oj_dump_xml_time(VALUE obj, Out out);
30
35
  extern void oj_dump_time(VALUE obj, Out out, int withZone);
31
36
  extern void oj_dump_obj_to_s(VALUE obj, Out out);
32
37
 
33
- extern const char *oj_nan_str(VALUE obj, int opt, int mode, bool plus, int *lenp);
38
+ extern const char *oj_nan_str(VALUE obj, int opt, int mode, bool plus, size_t *lenp);
34
39
 
35
40
  // initialize an out buffer with the provided stack allocated memory
36
41
  extern void oj_out_init(Out out);
@@ -53,10 +58,12 @@ extern void oj_dump_raw_json(VALUE obj, int depth, Out out);
53
58
  extern VALUE oj_add_to_json(int argc, VALUE *argv, VALUE self);
54
59
  extern VALUE oj_remove_to_json(int argc, VALUE *argv, VALUE self);
55
60
 
56
- extern int oj_dump_float_printf(char *buf, size_t blen, VALUE obj, double d, const char *format);
61
+ extern size_t oj_dump_float_printf(char *buf, size_t blen, VALUE obj, double d, const char *format);
57
62
 
58
63
  extern time_t oj_sec_from_time_hard_way(VALUE obj);
59
64
 
65
+ extern bool oj_key_skip(VALUE key, const char *only, const char *except);
66
+
60
67
  inline static void assure_size(Out out, size_t len) {
61
68
  if (out->end - out->cur <= (long)len) {
62
69
  oj_grow_out(out, len);
data/ext/oj/dump_compat.c CHANGED
@@ -103,7 +103,7 @@ static void dump_values_array(VALUE *values, int depth, Out out) {
103
103
  static void dump_to_json(VALUE obj, Out out) {
104
104
  volatile VALUE rs;
105
105
  const char *s;
106
- int len;
106
+ size_t len;
107
107
 
108
108
  TRACE(out->opts->trace, "to_json", obj, 0, TraceRubyIn);
109
109
  if (0 == rb_obj_method_arity(obj, oj_to_json_id)) {
@@ -115,7 +115,7 @@ static void dump_to_json(VALUE obj, Out out) {
115
115
 
116
116
  StringValue(rs);
117
117
  s = RSTRING_PTR(rs);
118
- len = (int)RSTRING_LEN(rs);
118
+ len = RSTRING_LEN(rs);
119
119
 
120
120
  assure_size(out, len + 1);
121
121
  APPEND_CHARS(out->cur, s, len);
@@ -124,7 +124,8 @@ static void dump_to_json(VALUE obj, Out out) {
124
124
 
125
125
  static void dump_array(VALUE a, int depth, Out out, bool as_ok) {
126
126
  size_t size;
127
- int i, cnt;
127
+ size_t i;
128
+ size_t cnt;
128
129
  int d2 = depth + 1;
129
130
  long id = oj_check_circular(a, out);
130
131
 
@@ -136,7 +137,7 @@ static void dump_array(VALUE a, int depth, Out out, bool as_ok) {
136
137
  dump_to_json(a, out);
137
138
  return;
138
139
  }
139
- cnt = (int)RARRAY_LEN(a);
140
+ cnt = RARRAY_LEN(a);
140
141
  *out->cur++ = '[';
141
142
  assure_size(out, 2);
142
143
  if (0 == cnt) {
@@ -147,10 +148,10 @@ static void dump_array(VALUE a, int depth, Out out, bool as_ok) {
147
148
  } else {
148
149
  size = d2 * out->indent + 2;
149
150
  }
150
- assure_size(out, size * cnt);
151
151
  cnt--;
152
152
  for (i = 0; i <= cnt; i++) {
153
153
  if (out->opts->dump_opts.use) {
154
+ assure_size(out, size);
154
155
  if (0 < out->opts->dump_opts.array_size) {
155
156
  APPEND_CHARS(out->cur, out->opts->dump_opts.array_nl, out->opts->dump_opts.array_size);
156
157
  }
@@ -552,7 +553,7 @@ static void dump_float(VALUE obj, int depth, Out out, bool as_ok) {
552
553
  char buf[64];
553
554
  char *b;
554
555
  double d = rb_num2dbl(obj);
555
- int cnt = 0;
556
+ size_t cnt = 0;
556
557
 
557
558
  if (0.0 == d) {
558
559
  b = buf;
@@ -590,7 +591,7 @@ static void dump_float(VALUE obj, int depth, Out out, bool as_ok) {
590
591
  volatile VALUE rstr = oj_safe_string_convert(obj);
591
592
 
592
593
  strcpy(buf, RSTRING_PTR(rstr));
593
- cnt = (int)RSTRING_LEN(rstr);
594
+ cnt = RSTRING_LEN(rstr);
594
595
  }
595
596
  assure_size(out, cnt);
596
597
  APPEND_CHARS(out->cur, buf, cnt);
@@ -604,6 +605,11 @@ static int hash_cb(VALUE key, VALUE value, VALUE ov) {
604
605
  if (out->omit_nil && Qnil == value) {
605
606
  return ST_CONTINUE;
606
607
  }
608
+ if (NULL != out->opts->dump_opts.only || NULL != out->opts->dump_opts.except) {
609
+ if (oj_key_skip(key, out->opts->dump_opts.only, out->opts->dump_opts.except)) {
610
+ return ST_CONTINUE;
611
+ }
612
+ }
607
613
  if (!out->opts->dump_opts.use) {
608
614
  assure_size(out, depth * out->indent + 1);
609
615
  fill_indent(out, depth);
@@ -800,7 +806,7 @@ static void dump_bignum(VALUE obj, int depth, Out out, bool as_ok) {
800
806
  // rb_big2str can not so unless overridden by using add_to_json(Integer)
801
807
  // this must use to_s to pass the json gem unit tests.
802
808
  volatile VALUE rs;
803
- int cnt;
809
+ size_t cnt;
804
810
  bool dump_as_string = false;
805
811
 
806
812
  if (use_bignum_alt) {
@@ -809,7 +815,7 @@ static void dump_bignum(VALUE obj, int depth, Out out, bool as_ok) {
809
815
  rs = oj_safe_string_convert(obj);
810
816
  }
811
817
  rb_check_type(rs, T_STRING);
812
- cnt = (int)RSTRING_LEN(rs);
818
+ cnt = RSTRING_LEN(rs);
813
819
 
814
820
  if (out->opts->int_range_min != 0 || out->opts->int_range_max != 0) {
815
821
  dump_as_string = true; // Bignum cannot be inside of Fixnum range
data/ext/oj/dump_leaf.c CHANGED
@@ -17,7 +17,7 @@ inline static void dump_chars(const char *s, size_t size, Out out) {
17
17
  static void dump_leaf_str(Leaf leaf, Out out) {
18
18
  switch (leaf->value_type) {
19
19
  case STR_VAL: oj_dump_cstr(leaf->str, strlen(leaf->str), 0, 0, out); break;
20
- case RUBY_VAL: oj_dump_cstr(StringValueCStr(leaf->value), (int)RSTRING_LEN(leaf->value), 0, 0, out); break;
20
+ case RUBY_VAL: oj_dump_cstr(StringValueCStr(leaf->value), RSTRING_LEN(leaf->value), 0, 0, out); break;
21
21
  case COL_VAL:
22
22
  default: rb_raise(rb_eTypeError, "Unexpected value type %02x.\n", leaf->value_type); break;
23
23
  }
data/ext/oj/dump_object.c CHANGED
@@ -33,7 +33,7 @@ static void dump_data(VALUE obj, int depth, Out out, bool as_ok) {
33
33
  if (oj_bigdecimal_class == clas) {
34
34
  volatile VALUE rstr = oj_safe_string_convert(obj);
35
35
  const char *str = RSTRING_PTR(rstr);
36
- int len = (int)RSTRING_LEN(rstr);
36
+ size_t len = RSTRING_LEN(rstr);
37
37
 
38
38
  if (No != out->opts->bigdec_as_num) {
39
39
  oj_dump_raw(str, len, out);
@@ -62,7 +62,7 @@ static void dump_obj(VALUE obj, int depth, Out out, bool as_ok) {
62
62
  if (oj_bigdecimal_class == clas) {
63
63
  volatile VALUE rstr = oj_safe_string_convert(obj);
64
64
  const char *str = RSTRING_PTR(rstr);
65
- int len = (int)RSTRING_LEN(rstr);
65
+ size_t len = RSTRING_LEN(rstr);
66
66
 
67
67
  if (0 == strcasecmp("Infinity", str)) {
68
68
  str = oj_nan_str(obj, out->opts->dump_opts.nan_dump, out->opts->mode, true, &len);
@@ -95,7 +95,8 @@ static void dump_class(VALUE obj, int depth, Out out, bool as_ok) {
95
95
 
96
96
  static void dump_array_class(VALUE a, VALUE clas, int depth, Out out) {
97
97
  size_t size;
98
- int i, cnt;
98
+ size_t i;
99
+ size_t cnt;
99
100
  int d2 = depth + 1;
100
101
  long id = oj_check_circular(a, out);
101
102
 
@@ -106,7 +107,7 @@ static void dump_array_class(VALUE a, VALUE clas, int depth, Out out) {
106
107
  dump_obj_attrs(a, clas, 0, depth, out);
107
108
  return;
108
109
  }
109
- cnt = (int)RARRAY_LEN(a);
110
+ cnt = RARRAY_LEN(a);
110
111
  *out->cur++ = '[';
111
112
  if (0 < id) {
112
113
  assure_size(out, d2 * out->indent + 16);
@@ -181,7 +182,7 @@ static void dump_str_class(VALUE obj, VALUE clas, int depth, Out out) {
181
182
  dump_obj_attrs(obj, clas, 0, depth, out);
182
183
  } else {
183
184
  const char *s = RSTRING_PTR(obj);
184
- size_t len = (int)RSTRING_LEN(obj);
185
+ size_t len = RSTRING_LEN(obj);
185
186
  char s1 = s[1];
186
187
 
187
188
  oj_dump_cstr(s, len, 0, (':' == *s || ('^' == *s && ('r' == s1 || 'i' == s1))), out);
@@ -195,7 +196,7 @@ static void dump_str(VALUE obj, int depth, Out out, bool as_ok) {
195
196
  static void dump_sym(VALUE obj, int depth, Out out, bool as_ok) {
196
197
  volatile VALUE s = rb_sym2str(obj);
197
198
 
198
- oj_dump_cstr(RSTRING_PTR(s), (int)RSTRING_LEN(s), 1, 0, out);
199
+ oj_dump_cstr(RSTRING_PTR(s), RSTRING_LEN(s), 1, 0, out);
199
200
  }
200
201
 
201
202
  static int hash_cb(VALUE key, VALUE value, VALUE ov) {
@@ -209,6 +210,11 @@ static int hash_cb(VALUE key, VALUE value, VALUE ov) {
209
210
  if (out->omit_nil && Qnil == value) {
210
211
  return ST_CONTINUE;
211
212
  }
213
+ if (NULL != out->opts->dump_opts.only || NULL != out->opts->dump_opts.except) {
214
+ if (oj_key_skip(key, out->opts->dump_opts.only, out->opts->dump_opts.except)) {
215
+ return ST_CONTINUE;
216
+ }
217
+ }
212
218
  assure_size(out, size);
213
219
  fill_indent(out, depth);
214
220
  switch (rb_type(key)) {
@@ -389,7 +395,7 @@ static void dump_odd(VALUE obj, Odd odd, VALUE clas, int depth, Out out) {
389
395
  rb_raise(rb_eEncodingError, "Invalid type for raw JSON.");
390
396
  } else {
391
397
  const char *s = RSTRING_PTR(v);
392
- int len = (int)RSTRING_LEN(v);
398
+ size_t len = RSTRING_LEN(v);
393
399
  const char *name = rb_id2name(*odd->attrs);
394
400
  size_t nlen = strlen(name);
395
401
 
@@ -489,7 +495,7 @@ static void dump_obj_attrs(VALUE obj, VALUE clas, slot_t id, int depth, Out out)
489
495
  *out->cur++ = ',';
490
496
  fill_indent(out, d2);
491
497
  APPEND_CHARS(out->cur, "\"self\":", 7);
492
- oj_dump_cstr(RSTRING_PTR(obj), (int)RSTRING_LEN(obj), 0, 0, out);
498
+ oj_dump_cstr(RSTRING_PTR(obj), RSTRING_LEN(obj), 0, 0, out);
493
499
  break;
494
500
  case T_ARRAY:
495
501
  assure_size(out, d2 * out->indent + 14);
@@ -564,11 +570,12 @@ static void dump_regexp(VALUE obj, int depth, Out out, bool as_ok) {
564
570
  static void dump_struct(VALUE obj, int depth, Out out, bool as_ok) {
565
571
  VALUE clas = rb_obj_class(obj);
566
572
  const char *class_name = rb_class2name(clas);
567
- int i;
568
- int d2 = depth + 1;
569
- int d3 = d2 + 1;
570
- size_t len = strlen(class_name);
571
- size_t size = d2 * out->indent + d3 * out->indent + 10 + len;
573
+ size_t i;
574
+ int d2 = depth + 1;
575
+ int d3 = d2 + 1;
576
+ size_t len = strlen(class_name);
577
+ size_t size = d2 * out->indent + d3 * out->indent + 10 + len;
578
+ char circular = out->opts->circular;
572
579
 
573
580
  assure_size(out, size);
574
581
  *out->cur++ = '{';
@@ -577,14 +584,14 @@ static void dump_struct(VALUE obj, int depth, Out out, bool as_ok) {
577
584
  if ('#' == *class_name) {
578
585
  VALUE ma = rb_struct_s_members(clas);
579
586
  const char *name;
580
- int cnt = (int)RARRAY_LEN(ma);
587
+ size_t cnt = RARRAY_LEN(ma);
581
588
 
582
589
  *out->cur++ = '[';
583
590
  for (i = 0; i < cnt; i++) {
584
591
  volatile VALUE s = rb_sym2str(RARRAY_AREF(ma, i));
585
592
 
586
593
  name = RSTRING_PTR(s);
587
- len = (int)RSTRING_LEN(s);
594
+ len = RSTRING_LEN(s);
588
595
  size = len + 3;
589
596
  assure_size(out, size);
590
597
  if (0 < i) {
@@ -607,14 +614,18 @@ static void dump_struct(VALUE obj, int depth, Out out, bool as_ok) {
607
614
  {
608
615
  VALUE v;
609
616
  int cnt;
617
+
610
618
  #if RSTRUCT_LEN_RETURNS_INTEGER_OBJECT
611
619
  cnt = (int)NUM2LONG(RSTRUCT_LEN(obj));
612
620
  #else // RSTRUCT_LEN_RETURNS_INTEGER_OBJECT
613
621
  cnt = (int)RSTRUCT_LEN(obj);
614
622
  #endif // RSTRUCT_LEN_RETURNS_INTEGER_OBJECT
615
623
 
616
- for (i = 0; i < cnt; i++) {
617
- v = RSTRUCT_GET(obj, i);
624
+ if (0 == strcmp(class_name, "Range")) {
625
+ out->opts->circular = 'n';
626
+ }
627
+ for (i = 0; i < (size_t)cnt; i++) {
628
+ v = RSTRUCT_GET(obj, (int)i);
618
629
  if (dump_ignore(out->opts, v)) {
619
630
  v = Qnil;
620
631
  }
@@ -630,6 +641,9 @@ static void dump_struct(VALUE obj, int depth, Out out, bool as_ok) {
630
641
  // class in interpreted Ruby so length() may not be defined.
631
642
  int slen = FIX2INT(rb_funcall2(obj, oj_length_id, 0, 0));
632
643
 
644
+ if (0 == strcmp(class_name, "Range")) {
645
+ out->opts->circular = 'n';
646
+ }
633
647
  for (i = 0; i < slen; i++) {
634
648
  assure_size(out, size);
635
649
  fill_indent(out, d3);
@@ -641,6 +655,7 @@ static void dump_struct(VALUE obj, int depth, Out out, bool as_ok) {
641
655
  }
642
656
  }
643
657
  #endif
658
+ out->opts->circular = circular;
644
659
  out->cur--;
645
660
  APPEND_CHARS(out->cur, "]}", 2);
646
661
  *out->cur = '\0';
data/ext/oj/dump_strict.c CHANGED
@@ -30,7 +30,7 @@ static void dump_float(VALUE obj, int depth, Out out, bool as_ok) {
30
30
  char buf[64];
31
31
  char* b;
32
32
  double d = rb_num2dbl(obj);
33
- int cnt = 0;
33
+ size_t cnt = 0;
34
34
 
35
35
  if (0.0 == d) {
36
36
  b = buf;
@@ -92,7 +92,7 @@ static void dump_float(VALUE obj, int depth, Out out, bool as_ok) {
92
92
  } else if (0 == out->opts->float_prec) {
93
93
  volatile VALUE rstr = oj_safe_string_convert(obj);
94
94
 
95
- cnt = (int)RSTRING_LEN(rstr);
95
+ cnt = RSTRING_LEN(rstr);
96
96
  if ((int)sizeof(buf) <= cnt) {
97
97
  cnt = sizeof(buf) - 1;
98
98
  }
@@ -109,7 +109,8 @@ static void dump_float(VALUE obj, int depth, Out out, bool as_ok) {
109
109
 
110
110
  static void dump_array(VALUE a, int depth, Out out, bool as_ok) {
111
111
  size_t size;
112
- int i, cnt;
112
+ size_t i;
113
+ size_t cnt;
113
114
  int d2 = depth + 1;
114
115
 
115
116
  if (Yes == out->opts->circular) {
@@ -118,7 +119,7 @@ static void dump_array(VALUE a, int depth, Out out, bool as_ok) {
118
119
  return;
119
120
  }
120
121
  }
121
- cnt = (int)RARRAY_LEN(a);
122
+ cnt = RARRAY_LEN(a);
122
123
  *out->cur++ = '[';
123
124
  size = 2;
124
125
  assure_size(out, size);
@@ -192,14 +193,19 @@ static int hash_cb(VALUE key, VALUE value, VALUE ov) {
192
193
  if (out->omit_nil && Qnil == value) {
193
194
  return ST_CONTINUE;
194
195
  }
196
+ if (NULL != out->opts->dump_opts.only || NULL != out->opts->dump_opts.except) {
197
+ if (oj_key_skip(key, out->opts->dump_opts.only, out->opts->dump_opts.except)) {
198
+ return ST_CONTINUE;
199
+ }
200
+ }
195
201
  if (!out->opts->dump_opts.use) {
196
202
  size = depth * out->indent + 1;
197
203
  assure_size(out, size);
198
204
  fill_indent(out, depth);
199
- if (rtype == T_STRING) {
200
- oj_dump_str(key, 0, out, false);
201
- } else {
202
- oj_dump_sym(key, 0, out, false);
205
+ switch (rtype) {
206
+ case T_STRING: oj_dump_str(key, 0, out, false); break;
207
+ case T_SYMBOL: oj_dump_sym(key, 0, out, false); break;
208
+ default: oj_dump_str(oj_safe_string_convert(key), 0, out, false); break;
203
209
  }
204
210
  *out->cur++ = ':';
205
211
  } else {
@@ -214,10 +220,10 @@ static int hash_cb(VALUE key, VALUE value, VALUE ov) {
214
220
  APPEND_CHARS(out->cur, out->opts->dump_opts.indent_str, out->opts->dump_opts.indent_size);
215
221
  }
216
222
  }
217
- if (rtype == T_STRING) {
218
- oj_dump_str(key, 0, out, false);
219
- } else {
220
- oj_dump_sym(key, 0, out, false);
223
+ switch (rtype) {
224
+ case T_STRING: oj_dump_str(key, 0, out, false); break;
225
+ case T_SYMBOL: oj_dump_sym(key, 0, out, false); break;
226
+ default: oj_dump_str(oj_safe_string_convert(key), 0, out, false); break;
221
227
  }
222
228
  size = out->opts->dump_opts.before_size + out->opts->dump_opts.after_size + 2;
223
229
  assure_size(out, size);
@@ -290,7 +296,7 @@ static void dump_data_strict(VALUE obj, int depth, Out out, bool as_ok) {
290
296
  if (oj_bigdecimal_class == clas) {
291
297
  volatile VALUE rstr = oj_safe_string_convert(obj);
292
298
 
293
- oj_dump_raw(RSTRING_PTR(rstr), (int)RSTRING_LEN(rstr), out);
299
+ oj_dump_raw(RSTRING_PTR(rstr), RSTRING_LEN(rstr), out);
294
300
  } else {
295
301
  raise_strict(obj);
296
302
  }
@@ -302,7 +308,7 @@ static void dump_data_null(VALUE obj, int depth, Out out, bool as_ok) {
302
308
  if (oj_bigdecimal_class == clas) {
303
309
  volatile VALUE rstr = oj_safe_string_convert(obj);
304
310
 
305
- oj_dump_raw(RSTRING_PTR(rstr), (int)RSTRING_LEN(rstr), out);
311
+ oj_dump_raw(RSTRING_PTR(rstr), RSTRING_LEN(rstr), out);
306
312
  } else {
307
313
  oj_dump_nil(Qnil, depth, out, false);
308
314
  }
data/ext/oj/extconf.rb CHANGED
@@ -35,13 +35,16 @@ have_func('rb_ext_ractor_safe', 'ruby.h')
35
35
 
36
36
  dflags['OJ_DEBUG'] = true unless ENV['OJ_DEBUG'].nil?
37
37
 
38
- if with_config('--with-sse42')
39
- if try_cflags('-msse4.2')
40
- $CPPFLAGS += ' -msse4.2'
41
- dflags['OJ_USE_SSE4_2'] = 1
42
- else
43
- warn 'SSE 4.2 is not supported on this platform.'
44
- end
38
+ # SIMD optimizations use runtime CPU detection and function-level target attributes
39
+ # We do NOT add global -msse4.2/-msse2 flags here because:
40
+ # 1. It would cause illegal instruction errors on CPUs without SSE4.2
41
+ # 2. The code uses __attribute__((target("sse4.2"))) for SSE4.2 functions
42
+ # 3. Runtime detection in oj_get_simd_implementation() selects the right path
43
+ #
44
+ # We only add -msse2 if available, since SSE2 is baseline for all x86_64 CPUs
45
+ # and needed for compiling the SSE2 fallback code on 32-bit x86
46
+ if try_cflags('-msse2')
47
+ $CPPFLAGS += ' -msse2'
45
48
  end
46
49
 
47
50
  if enable_config('trace-log', false)
data/ext/oj/fast.c CHANGED
@@ -80,21 +80,10 @@ static void each_leaf(Doc doc, VALUE self);
80
80
  static int move_step(Doc doc, const char *path, int loc);
81
81
  static Leaf get_doc_leaf(Doc doc, const char *path);
82
82
  static Leaf get_leaf(Leaf *stack, Leaf *lp, const char *path);
83
- static void each_value(Doc doc, Leaf leaf);
83
+ static void each_value(Doc doc, Leaf leaf, VALUE self);
84
84
 
85
85
  VALUE oj_doc_class = Qundef;
86
86
 
87
- // This is only for CentOS 5.4 with Ruby 1.9.3-p0.
88
- #ifndef HAVE_STPCPY
89
- char *stpcpy(char *dest, const char *src) {
90
- size_t cnt = strlen(src);
91
-
92
- strcpy(dest, src);
93
-
94
- return dest + cnt;
95
- }
96
- #endif
97
-
98
87
  inline static void next_non_white(ParseInfo pi) {
99
88
  for (; 1; pi->s++) {
100
89
  switch (*pi->s) {
@@ -193,8 +182,7 @@ static VALUE leaf_value(Doc doc, Leaf leaf) {
193
182
  case T_FIXNUM: leaf_fixnum_value(leaf); break;
194
183
  case T_FLOAT: leaf_float_value(leaf); break;
195
184
  case T_STRING:
196
- leaf->value = rb_str_new2(leaf->str);
197
- leaf->value = oj_encode(leaf->value);
185
+ leaf->value = rb_utf8_str_new_cstr(leaf->str);
198
186
  leaf->value_type = RUBY_VAL;
199
187
  break;
200
188
  case T_ARRAY: return leaf_array_value(doc, leaf); break;
@@ -247,6 +235,19 @@ static void skip_comment(ParseInfo pi) {
247
235
  #define NUM_MAX (FIXNUM_MAX >> 8)
248
236
  #endif
249
237
 
238
+ static void validate_integer_size(size_t limit, char *head, char *tail) {
239
+ size_t total = (size_t)(tail - head);
240
+ bool has_sign = (head[0] == '-' || head[0] == '+');
241
+ size_t digit_count = total - (has_sign ? 1 : 0);
242
+
243
+ if (digit_count > limit) {
244
+ rb_raise(oj_parse_error_class,
245
+ "integer exceeds :max_integer_digits (%lu > %lu)",
246
+ (unsigned long)digit_count,
247
+ (unsigned long)limit);
248
+ }
249
+ }
250
+
250
251
  static void leaf_fixnum_value(Leaf leaf) {
251
252
  char *s = leaf->str;
252
253
  int64_t n = 0;
@@ -266,7 +267,12 @@ static void leaf_fixnum_value(Leaf leaf) {
266
267
  }
267
268
  }
268
269
  if (big) {
269
- char c = *s;
270
+ size_t limit = oj_default_options.max_integer_digits;
271
+ char c = *s;
272
+
273
+ if (0 < limit) {
274
+ validate_integer_size(limit, leaf->str, s);
275
+ }
270
276
 
271
277
  *s = '\0';
272
278
  leaf->value = rb_cstr_to_inum(leaf->str, 10, 0);
@@ -309,8 +315,7 @@ static VALUE leaf_hash_value(Doc doc, Leaf leaf) {
309
315
  volatile VALUE key;
310
316
 
311
317
  do {
312
- key = rb_str_new2(e->key);
313
- key = oj_encode(key);
318
+ key = rb_utf8_str_new_cstr(e->key);
314
319
  rb_hash_aset(h, key, leaf_value(doc, e));
315
320
  e = e->next;
316
321
  } while (e != first);
@@ -952,6 +957,9 @@ static void each_leaf(Doc doc, VALUE self) {
952
957
  }
953
958
  } else {
954
959
  rb_yield(self);
960
+ if (NULL == DATA_PTR(self)) {
961
+ rb_raise(rb_eIOError, "Document closed.");
962
+ }
955
963
  }
956
964
  }
957
965
 
@@ -1045,19 +1053,22 @@ static int move_step(Doc doc, const char *path, int loc) {
1045
1053
  return loc;
1046
1054
  }
1047
1055
 
1048
- static void each_value(Doc doc, Leaf leaf) {
1056
+ static void each_value(Doc doc, Leaf leaf, VALUE self) {
1049
1057
  if (COL_VAL == leaf->value_type) {
1050
1058
  if (0 != leaf->elements) {
1051
1059
  Leaf first = leaf->elements->next;
1052
1060
  Leaf e = first;
1053
1061
 
1054
1062
  do {
1055
- each_value(doc, e);
1063
+ each_value(doc, e, self);
1056
1064
  e = e->next;
1057
1065
  } while (e != first);
1058
1066
  }
1059
1067
  } else {
1060
1068
  rb_yield(leaf_value(doc, leaf));
1069
+ if (NULL == DATA_PTR(self)) {
1070
+ rb_raise(rb_eIOError, "Document closed.");
1071
+ }
1061
1072
  }
1062
1073
  }
1063
1074
 
@@ -1088,7 +1099,7 @@ static VALUE doc_open(VALUE clas, VALUE str) {
1088
1099
  int given = rb_block_given_p();
1089
1100
 
1090
1101
  Check_Type(str, T_STRING);
1091
- len = (int)RSTRING_LEN(str) + 1;
1102
+ len = RSTRING_LEN(str) + 1;
1092
1103
  json = OJ_R_ALLOC_N(char, len);
1093
1104
 
1094
1105
  memcpy(json, StringValuePtr(str), len);
@@ -1257,8 +1268,7 @@ static VALUE doc_local_key(VALUE self) {
1257
1268
  volatile VALUE key = Qnil;
1258
1269
 
1259
1270
  if (T_HASH == leaf->parent_type) {
1260
- key = rb_str_new2(leaf->key);
1261
- key = oj_encode(key);
1271
+ key = rb_utf8_str_new_cstr(leaf->key);
1262
1272
  } else if (T_ARRAY == leaf->parent_type) {
1263
1273
  key = LONG2NUM(leaf->index);
1264
1274
  }
@@ -1494,12 +1504,19 @@ static VALUE doc_each_child(int argc, VALUE *argv, VALUE self) {
1494
1504
  Leaf first = (*doc->where)->elements->next;
1495
1505
  Leaf e = first;
1496
1506
 
1507
+ if (MAX_STACK <= (doc->where + 1) - doc->where_path) {
1508
+ rb_raise(rb_const_get_at(Oj, rb_intern("DepthError")), "Path too deep. Limit is %d levels.", MAX_STACK);
1509
+ }
1497
1510
  doc->where++;
1498
1511
  do {
1499
1512
  *doc->where = e;
1500
1513
  rb_yield(self);
1514
+ if (NULL == DATA_PTR(self)) {
1515
+ rb_raise(rb_eIOError, "Document closed.");
1516
+ }
1501
1517
  e = e->next;
1502
1518
  } while (e != first);
1519
+ doc->where--;
1503
1520
  }
1504
1521
  if (0 < wlen) {
1505
1522
  memcpy(doc->where_path, save_path, sizeof(Leaf) * (wlen + 1));
@@ -1543,7 +1560,7 @@ static VALUE doc_each_value(int argc, VALUE *argv, VALUE self) {
1543
1560
  path = StringValuePtr(*argv);
1544
1561
  }
1545
1562
  if (0 != (leaf = get_doc_leaf(doc, path))) {
1546
- each_value(doc, leaf);
1563
+ each_value(doc, leaf, self);
1547
1564
  }
1548
1565
  }
1549
1566
  return Qnil;
data/ext/oj/intern.c CHANGED
@@ -69,7 +69,7 @@ static VALUE form_attr(const char *str, size_t len) {
69
69
  memcpy(b + 1, str, len);
70
70
  b[len + 1] = '\0';
71
71
  }
72
- id = rb_intern3(buf, len + 1, oj_utf8_encoding);
72
+ id = rb_intern3(b, len + 1, oj_utf8_encoding);
73
73
  OJ_R_FREE(b);
74
74
  return id;
75
75
  }
data/ext/oj/mimic_json.c CHANGED
@@ -246,8 +246,7 @@ static VALUE mimic_dump(int argc, VALUE *argv, VALUE self) {
246
246
  if (0 == out.buf) {
247
247
  rb_raise(rb_eNoMemError, "Not enough memory.");
248
248
  }
249
- rstr = rb_str_new2(out.buf);
250
- rstr = oj_encode(rstr);
249
+ rstr = rb_utf8_str_new_cstr(out.buf);
251
250
  if (2 <= argc && Qnil != argv[1] && rb_respond_to(argv[1], oj_write_id)) {
252
251
  VALUE io = argv[1];
253
252
  VALUE args[1];
@@ -396,8 +395,7 @@ static VALUE mimic_generate_core(int argc, VALUE *argv, Options copts) {
396
395
  if (0 == out.buf) {
397
396
  rb_raise(rb_eNoMemError, "Not enough memory.");
398
397
  }
399
- rstr = rb_str_new2(out.buf);
400
- rstr = oj_encode(rstr);
398
+ rstr = rb_utf8_str_new_cstr(out.buf);
401
399
 
402
400
  oj_out_free(&out);
403
401
 
@@ -713,6 +711,7 @@ static struct _options mimic_object_to_json_options = {0, // indent
713
711
  0, // cache_str
714
712
  0, // int_range_min
715
713
  0, // int_range_max
714
+ 0, // max_integer_digits
716
715
  oj_json_class, // create_id
717
716
  10, // create_id_len
718
717
  3, // sec_prec
@@ -737,6 +736,8 @@ static struct _options mimic_object_to_json_options = {0, // indent
737
736
  false, // omit_nil
738
737
  false, // omit_null_byte
739
738
  100, // max_depth
739
+ NULL, // only
740
+ NULL, // except
740
741
  },
741
742
  {
742
743
  // str_rx
@@ -768,8 +769,7 @@ static VALUE mimic_object_to_json(int argc, VALUE *argv, VALUE self) {
768
769
  if (NULL == out.buf) {
769
770
  rb_raise(rb_eNoMemError, "Not enough memory.");
770
771
  }
771
- rstr = rb_str_new2(out.buf);
772
- rstr = oj_encode(rstr);
772
+ rstr = rb_utf8_str_new_cstr(out.buf);
773
773
 
774
774
  oj_out_free(&out);
775
775
 
@@ -837,11 +837,15 @@ void oj_mimic_json_methods(VALUE json) {
837
837
  } else {
838
838
  json_error = rb_define_class_under(json, "JSONError", rb_eStandardError);
839
839
  }
840
+
841
+ rb_global_variable(&oj_json_parser_error_class);
840
842
  if (rb_const_defined_at(json, rb_intern("ParserError"))) {
841
843
  oj_json_parser_error_class = rb_const_get(json, rb_intern("ParserError"));
842
844
  } else {
843
845
  oj_json_parser_error_class = rb_define_class_under(json, "ParserError", json_error);
844
846
  }
847
+
848
+ rb_global_variable(&oj_json_generator_error_class);
845
849
  if (rb_const_defined_at(json, rb_intern("GeneratorError"))) {
846
850
  oj_json_generator_error_class = rb_const_get(json, rb_intern("GeneratorError"));
847
851
  } else {
@@ -867,8 +871,8 @@ void oj_mimic_json_methods(VALUE json) {
867
871
  rb_require("oj/state");
868
872
  }
869
873
  // Pull in the JSON::State mimic file.
874
+ rb_global_variable(&state_class);
870
875
  state_class = rb_const_get_at(generator, rb_intern("State"));
871
- rb_gc_register_mark_object(state_class);
872
876
  }
873
877
 
874
878
  /* Document-module: JSON