oj 3.13.23 → 3.14.0

Sign up to get free protection for your applications and to get access to all the features.
checksums.yaml CHANGED
@@ -1,7 +1,7 @@
1
1
  ---
2
2
  SHA256:
3
- metadata.gz: 3d2f8a01b7a59da7cd25ed3551065dddd9e31e5184989804d172c2e39cc769d6
4
- data.tar.gz: 7211a96856ec44173fa9dcc7245e3cb2f6b7c2e22a746ef35f168126873f4c88
3
+ metadata.gz: 5864f273679d1441d9731976eb4f4c3cdcccaa86c877fae2aeb719cd03f45167
4
+ data.tar.gz: 815abc1a8572ce907b280ca632fd010c766ad55e581c3a59d76c0f94ede24234
5
5
  SHA512:
6
- metadata.gz: ee3ad5cac6cac48bcf7fdf682e69770dfee08b502735cc75b84ae1635196fdcdaf2fde021e32e6d897bdc6935e111882ddc48fa5a274fe0d98ad45c2fdf68917
7
- data.tar.gz: 3e05212fa84a2bf05954ec870ac27da7c845335b411507aa0bf5e45497403cccf4c40990f0ee8cee6d21f19163f33116bb240836795482737eaa744bc5ff6d94
6
+ metadata.gz: 3318017139004f712665ff2fda5dcfc761b33079bb96dd1d8f5baf59d146a45956e3c58f1e700044a714ca2643d5a54196e3b306566130c9bda7242d8c688b91
7
+ data.tar.gz: f8f6f637c883ca2b4fa8c76f349940f6be3c1af524d43f3cc0ed4df27a21896f480da520b2897e191d38e50ef939139bdd242c3e3f33aa0c0e3aa8bd3a008a6b
data/CHANGELOG.md CHANGED
@@ -1,5 +1,11 @@
1
1
  # CHANGELOG
2
2
 
3
+ ## 3.14.0 - 2022-01-30
4
+
5
+ - Tracing is now a compile time option giving a 15 to 20% performance boost.
6
+
7
+ - Some cleanup in teh fast parser.
8
+
3
9
  ## 3.13.23 - 2022-11-06
4
10
 
5
11
  - Fixed issue with Oj::Parser extension regarding GC timeing.
data/README.md CHANGED
@@ -1,6 +1,6 @@
1
1
  # [![{}j](http://www.ohler.com/dev/images/oj_comet_64.svg)](http://www.ohler.com/oj) gem
2
2
 
3
- [![Build Status](https://img.shields.io/github/workflow/status/ohler55/oj/CI?logo=github)](https://github.com/ohler55/oj/actions/workflows/CI.yml)
3
+ [![CI](https://github.com/ohler55/oj/actions/workflows/CI.yml/badge.svg)](https://github.com/ohler55/oj/actions/workflows/CI.yml)
4
4
  ![Gem](https://img.shields.io/gem/v/oj.svg)
5
5
  ![Gem](https://img.shields.io/gem/dt/oj.svg)
6
6
  [![SemVer compatibility](https://api.dependabot.com/badges/compatibility_score?dependency-name=oj&package-manager=bundler&version-scheme=semver)](https://dependabot.com/compatibility-score.html?dependency-name=oj&package-manager=bundler&version-scheme=semver)
@@ -70,6 +70,7 @@ links.
70
70
  - [{file:Compatibility.md}](pages/Compatibility.md) lists current compatibility with Rubys and Rails.
71
71
  - [{file:Advanced.md}](pages/Advanced.md) for fast parser and marshalling features.
72
72
  - [{file:Security.md}](pages/Security.md) for security considerations.
73
+ - [{file:InstallOptions.md}](pages/InstallOptions.md) for install option.
73
74
 
74
75
  ## Releases
75
76
 
data/ext/oj/compat.c CHANGED
@@ -54,9 +54,7 @@ static void hash_set_cstr(ParseInfo pi, Val kval, const char *str, size_t len, c
54
54
  } else {
55
55
  rb_hash_aset(parent->val, rkey, rstr);
56
56
  }
57
- if (RB_UNLIKELY(Yes == pi->options.trace)) {
58
- oj_trace_parse_call("set_string", pi, __FILE__, __LINE__, rstr);
59
- }
57
+ TRACE_PARSE_CALL(pi->options.trace, "set_string", pi, rstr);
60
58
  }
61
59
  }
62
60
 
@@ -68,9 +66,7 @@ static VALUE start_hash(ParseInfo pi) {
68
66
  } else {
69
67
  h = rb_hash_new();
70
68
  }
71
- if (RB_UNLIKELY(Yes == pi->options.trace)) {
72
- oj_trace_parse_in("start_hash", pi, __FILE__, __LINE__);
73
- }
69
+ TRACE_PARSE_IN(pi->options.trace, "start_hash", pi);
74
70
  return h;
75
71
  }
76
72
 
@@ -93,9 +89,7 @@ static void end_hash(struct _parseInfo *pi) {
93
89
  parent->classname = 0;
94
90
  }
95
91
  }
96
- if (RB_UNLIKELY(Yes == pi->options.trace)) {
97
- oj_trace_parse_hash_end(pi, __FILE__, __LINE__);
98
- }
92
+ TRACE_PARSE_HASH_END(pi->options.trace, pi);
99
93
  }
100
94
 
101
95
  static void add_cstr(ParseInfo pi, const char *str, size_t len, const char *orig) {
@@ -110,16 +104,12 @@ static void add_cstr(ParseInfo pi, const char *str, size_t len, const char *orig
110
104
  }
111
105
  }
112
106
  pi->stack.head->val = rstr;
113
- if (RB_UNLIKELY(Yes == pi->options.trace)) {
114
- oj_trace_parse_call("add_string", pi, __FILE__, __LINE__, rstr);
115
- }
107
+ TRACE_PARSE_CALL(pi->options.trace, "add_string", pi, rstr);
116
108
  }
117
109
 
118
110
  static void add_num(ParseInfo pi, NumInfo ni) {
119
111
  pi->stack.head->val = oj_num_as_value(ni);
120
- if (RB_UNLIKELY(Yes == pi->options.trace)) {
121
- oj_trace_parse_call("add_number", pi, __FILE__, __LINE__, pi->stack.head->val);
122
- }
112
+ TRACE_PARSE_CALL(pi->options.trace, "add_number", pi, pi->stack.head->val);
123
113
  }
124
114
 
125
115
  static void hash_set_num(struct _parseInfo *pi, Val parent, NumInfo ni) {
@@ -138,9 +128,7 @@ static void hash_set_num(struct _parseInfo *pi, Val parent, NumInfo ni) {
138
128
  } else {
139
129
  rb_hash_aset(stack_peek(&pi->stack)->val, oj_calc_hash_key(pi, parent), rval);
140
130
  }
141
- if (RB_UNLIKELY(Yes == pi->options.trace)) {
142
- oj_trace_parse_call("set_number", pi, __FILE__, __LINE__, rval);
143
- }
131
+ TRACE_PARSE_CALL(pi->options.trace, "set_number", pi, rval);
144
132
  }
145
133
 
146
134
  static void hash_set_value(ParseInfo pi, Val parent, VALUE value) {
@@ -157,18 +145,14 @@ static void hash_set_value(ParseInfo pi, Val parent, VALUE value) {
157
145
  } else {
158
146
  rb_hash_aset(stack_peek(&pi->stack)->val, oj_calc_hash_key(pi, parent), value);
159
147
  }
160
- if (RB_UNLIKELY(Yes == pi->options.trace)) {
161
- oj_trace_parse_call("set_value", pi, __FILE__, __LINE__, value);
162
- }
148
+ TRACE_PARSE_CALL(pi->options.trace, "set_value", pi, value);
163
149
  }
164
150
 
165
151
  static VALUE start_array(ParseInfo pi) {
166
152
  if (Qnil != pi->options.array_class) {
167
153
  return rb_class_new_instance(0, NULL, pi->options.array_class);
168
154
  }
169
- if (RB_UNLIKELY(Yes == pi->options.trace)) {
170
- oj_trace_parse_in("start_array", pi, __FILE__, __LINE__);
171
- }
155
+ TRACE_PARSE_IN(pi->options.trace, "start_array", pi);
172
156
  return rb_ary_new();
173
157
  }
174
158
 
@@ -184,9 +168,7 @@ static void array_append_num(ParseInfo pi, NumInfo ni) {
184
168
  } else {
185
169
  rb_ary_push(parent->val, rval);
186
170
  }
187
- if (RB_UNLIKELY(Yes == pi->options.trace)) {
188
- oj_trace_parse_call("append_number", pi, __FILE__, __LINE__, rval);
189
- }
171
+ TRACE_PARSE_CALL(pi->options.trace, "append_number", pi, rval);
190
172
  }
191
173
 
192
174
  static void array_append_cstr(ParseInfo pi, const char *str, size_t len, const char *orig) {
@@ -201,9 +183,7 @@ static void array_append_cstr(ParseInfo pi, const char *str, size_t len, const c
201
183
  }
202
184
  }
203
185
  rb_ary_push(stack_peek(&pi->stack)->val, rstr);
204
- if (RB_UNLIKELY(Yes == pi->options.trace)) {
205
- oj_trace_parse_call("append_string", pi, __FILE__, __LINE__, rstr);
206
- }
186
+ TRACE_PARSE_CALL(pi->options.trace, "append_string", pi, rstr);
207
187
  }
208
188
 
209
189
  void oj_set_compat_callbacks(ParseInfo pi) {
data/ext/oj/custom.c CHANGED
@@ -24,20 +24,20 @@ static void dump_obj_str(VALUE obj, int depth, Out out) {
24
24
  {"s", 1, Qnil},
25
25
  {NULL, 0, Qnil},
26
26
  };
27
- attrs->value = rb_funcall(obj, oj_to_s_id, 0);
27
+ attrs->value = oj_safe_string_convert(obj);
28
28
 
29
29
  oj_code_attrs(obj, attrs, depth, out, Yes == out->opts->create_ok);
30
30
  }
31
31
 
32
32
  static void dump_obj_as_str(VALUE obj, int depth, Out out) {
33
- volatile VALUE rstr = rb_funcall(obj, oj_to_s_id, 0);
33
+ volatile VALUE rstr = oj_safe_string_convert(obj);
34
34
  const char *str = RSTRING_PTR(rstr);
35
35
 
36
36
  oj_dump_cstr(str, RSTRING_LEN(rstr), 0, 0, out);
37
37
  }
38
38
 
39
39
  static void bigdecimal_dump(VALUE obj, int depth, Out out) {
40
- volatile VALUE rstr = rb_funcall(obj, oj_to_s_id, 0);
40
+ volatile VALUE rstr = oj_safe_string_convert(obj);
41
41
  const char *str = RSTRING_PTR(rstr);
42
42
  int len = (int)RSTRING_LEN(rstr);
43
43
 
@@ -305,7 +305,7 @@ static int hash_cb(VALUE key, VALUE value, VALUE ov) {
305
305
  switch (rb_type(key)) {
306
306
  case T_STRING: oj_dump_str(key, 0, out, false); break;
307
307
  case T_SYMBOL: oj_dump_sym(key, 0, out, false); break;
308
- default: oj_dump_str(rb_funcall(key, oj_to_s_id, 0), 0, out, false); break;
308
+ default: oj_dump_str(oj_safe_string_convert(key), 0, out, false); break;
309
309
  }
310
310
  if (!out->opts->dump_opts.use) {
311
311
  *out->cur++ = ':';
@@ -479,17 +479,13 @@ static VALUE dump_common(VALUE obj, int depth, Out out) {
479
479
  const char *s;
480
480
  int len;
481
481
 
482
- if (RB_UNLIKELY(Yes == out->opts->trace)) {
483
- oj_trace("to_json", obj, __FILE__, __LINE__, depth + 1, TraceRubyIn);
484
- }
482
+ TRACE(out->opts->trace, "to_json", obj, depth + 1, TraceRubyIn);
485
483
  if (0 == rb_obj_method_arity(obj, oj_to_json_id)) {
486
484
  rs = rb_funcall(obj, oj_to_json_id, 0);
487
485
  } else {
488
486
  rs = rb_funcall2(obj, oj_to_json_id, out->argc, out->argv);
489
487
  }
490
- if (RB_UNLIKELY(Yes == out->opts->trace)) {
491
- oj_trace("to_json", obj, __FILE__, __LINE__, depth + 1, TraceRubyOut);
492
- }
488
+ TRACE(out->opts->trace, "to_json", obj, depth + 1, TraceRubyOut);
493
489
  s = RSTRING_PTR(rs);
494
490
  len = (int)RSTRING_LEN(rs);
495
491
 
@@ -499,9 +495,7 @@ static VALUE dump_common(VALUE obj, int depth, Out out) {
499
495
  } else if (Yes == out->opts->as_json && rb_respond_to(obj, oj_as_json_id)) {
500
496
  volatile VALUE aj;
501
497
 
502
- if (RB_UNLIKELY(Yes == out->opts->trace)) {
503
- oj_trace("as_json", obj, __FILE__, __LINE__, depth + 1, TraceRubyIn);
504
- }
498
+ TRACE(out->opts->trace, "as_json", obj, depth + 1, TraceRubyIn);
505
499
  // Some classes elect to not take an options argument so check the arity
506
500
  // of as_json.
507
501
  if (0 == rb_obj_method_arity(obj, oj_as_json_id)) {
@@ -509,12 +503,10 @@ static VALUE dump_common(VALUE obj, int depth, Out out) {
509
503
  } else {
510
504
  aj = rb_funcall2(obj, oj_as_json_id, out->argc, out->argv);
511
505
  }
512
- if (RB_UNLIKELY(Yes == out->opts->trace)) {
513
- oj_trace("as_json", obj, __FILE__, __LINE__, depth + 1, TraceRubyOut);
514
- }
506
+ TRACE(out->opts->trace, "as_json", obj, depth + 1, TraceRubyOut);
515
507
  // Catch the obvious brain damaged recursive dumping.
516
508
  if (aj == obj) {
517
- volatile VALUE rstr = rb_funcall(obj, oj_to_s_id, 0);
509
+ volatile VALUE rstr = oj_safe_string_convert(obj);
518
510
 
519
511
  oj_dump_cstr(RSTRING_PTR(rstr), (int)RSTRING_LEN(rstr), false, false, out);
520
512
  } else {
@@ -876,9 +868,7 @@ static DumpFunc custom_funcs[] = {
876
868
  void oj_dump_custom_val(VALUE obj, int depth, Out out, bool as_ok) {
877
869
  int type = rb_type(obj);
878
870
 
879
- if (RB_UNLIKELY(Yes == out->opts->trace)) {
880
- oj_trace("dump", obj, __FILE__, __LINE__, depth, TraceIn);
881
- }
871
+ TRACE(out->opts->trace, "dump", obj, depth, TraceIn);
882
872
  if (MAX_DEPTH < depth) {
883
873
  rb_raise(rb_eNoMemError, "Too deeply nested.\n");
884
874
  }
@@ -887,16 +877,12 @@ void oj_dump_custom_val(VALUE obj, int depth, Out out, bool as_ok) {
887
877
 
888
878
  if (NULL != f) {
889
879
  f(obj, depth, out, true);
890
- if (RB_UNLIKELY(Yes == out->opts->trace)) {
891
- oj_trace("dump", obj, __FILE__, __LINE__, depth, TraceOut);
892
- }
880
+ TRACE(out->opts->trace, "dump", obj, depth, TraceOut);
893
881
  return;
894
882
  }
895
883
  }
896
884
  oj_dump_nil(Qnil, depth, out, false);
897
- if (RB_UNLIKELY(Yes == out->opts->trace)) {
898
- oj_trace("dump", Qnil, __FILE__, __LINE__, depth, TraceOut);
899
- }
885
+ TRACE(out->opts->trace, "dump", Qnil, depth, TraceOut);
900
886
  }
901
887
 
902
888
  ///// load functions /////
@@ -969,9 +955,7 @@ static void end_hash(struct _parseInfo *pi) {
969
955
  }
970
956
  parent->clas = Qundef;
971
957
  }
972
- if (RB_UNLIKELY(Yes == pi->options.trace)) {
973
- oj_trace_parse_hash_end(pi, __FILE__, __LINE__);
974
- }
958
+ TRACE_PARSE_HASH_END(pi->options.trace, pi);
975
959
  }
976
960
 
977
961
  static void hash_set_num(struct _parseInfo *pi, Val kval, NumInfo ni) {
data/ext/oj/dump.c CHANGED
@@ -463,7 +463,7 @@ void oj_dump_time(VALUE obj, Out out, int withZone) {
463
463
  }
464
464
 
465
465
  void oj_dump_ruby_time(VALUE obj, Out out) {
466
- volatile VALUE rstr = rb_funcall(obj, oj_to_s_id, 0);
466
+ volatile VALUE rstr = oj_safe_string_convert(obj);
467
467
 
468
468
  oj_dump_cstr(RSTRING_PTR(rstr), (int)RSTRING_LEN(rstr), 0, 0, out);
469
469
  }
@@ -736,13 +736,9 @@ void oj_dump_raw_json(VALUE obj, int depth, Out out) {
736
736
  } else {
737
737
  volatile VALUE jv;
738
738
 
739
- if (RB_UNLIKELY(Yes == out->opts->trace)) {
740
- oj_trace("raw_json", obj, __FILE__, __LINE__, depth + 1, TraceRubyIn);
741
- }
739
+ TRACE(out->opts->trace, "raw_json", obj, depth + 1, TraceRubyIn);
742
740
  jv = rb_funcall(obj, oj_raw_json_id, 2, RB_INT2NUM(depth), RB_INT2NUM(out->indent));
743
- if (RB_UNLIKELY(Yes == out->opts->trace)) {
744
- oj_trace("raw_json", obj, __FILE__, __LINE__, depth + 1, TraceRubyOut);
745
- }
741
+ TRACE(out->opts->trace, "raw_json", obj, depth + 1, TraceRubyOut);
746
742
  oj_dump_raw(RSTRING_PTR(jv), (size_t)RSTRING_LEN(jv), out);
747
743
  }
748
744
  }
@@ -932,7 +928,7 @@ void oj_dump_class(VALUE obj, int depth, Out out, bool as_ok) {
932
928
  }
933
929
 
934
930
  void oj_dump_obj_to_s(VALUE obj, Out out) {
935
- volatile VALUE rstr = rb_funcall(obj, oj_to_s_id, 0);
931
+ volatile VALUE rstr = oj_safe_string_convert(obj);
936
932
 
937
933
  oj_dump_cstr(RSTRING_PTR(rstr), (int)RSTRING_LEN(rstr), 0, 0, out);
938
934
  }
@@ -1173,7 +1169,7 @@ void oj_dump_float(VALUE obj, int depth, Out out, bool as_ok) {
1173
1169
  } else if (d == (double)(long long int)d) {
1174
1170
  cnt = snprintf(buf, sizeof(buf), "%.1f", d);
1175
1171
  } else if (0 == out->opts->float_prec) {
1176
- volatile VALUE rstr = rb_funcall(obj, oj_to_s_id, 0);
1172
+ volatile VALUE rstr = oj_safe_string_convert(obj);
1177
1173
 
1178
1174
  cnt = (int)RSTRING_LEN(rstr);
1179
1175
  if ((int)sizeof(buf) <= cnt) {
@@ -1195,7 +1191,7 @@ int oj_dump_float_printf(char *buf, size_t blen, VALUE obj, double d, const char
1195
1191
  // Round off issues at 16 significant digits so check for obvious ones of
1196
1192
  // 0001 and 9999.
1197
1193
  if (17 <= cnt && (0 == strcmp("0001", buf + cnt - 4) || 0 == strcmp("9999", buf + cnt - 4))) {
1198
- volatile VALUE rstr = rb_funcall(obj, oj_to_s_id, 0);
1194
+ volatile VALUE rstr = oj_safe_string_convert(obj);
1199
1195
 
1200
1196
  strcpy(buf, RSTRING_PTR(rstr));
1201
1197
  cnt = (int)RSTRING_LEN(rstr);
data/ext/oj/dump_compat.c CHANGED
@@ -109,17 +109,13 @@ dump_to_json(VALUE obj, Out out) {
109
109
  const char *s;
110
110
  int len;
111
111
 
112
- if (RB_UNLIKELY(Yes == out->opts->trace)) {
113
- oj_trace("to_json", obj, __FILE__, __LINE__, 0, TraceRubyIn);
114
- }
112
+ TRACE(out->opts->trace, "to_json", obj, 0, TraceRubyIn);
115
113
  if (0 == rb_obj_method_arity(obj, oj_to_json_id)) {
116
114
  rs = rb_funcall(obj, oj_to_json_id, 0);
117
115
  } else {
118
116
  rs = rb_funcall2(obj, oj_to_json_id, out->argc, out->argv);
119
117
  }
120
- if (RB_UNLIKELY(Yes == out->opts->trace)) {
121
- oj_trace("to_json", obj, __FILE__, __LINE__, 0, TraceRubyOut);
122
- }
118
+ TRACE(out->opts->trace, "to_json", obj, 0, TraceRubyOut);
123
119
 
124
120
  s = RSTRING_PTR(rs);
125
121
  len = (int)RSTRING_LEN(rs);
@@ -299,7 +295,7 @@ datetime_alt(VALUE obj, int depth, Out out) {
299
295
  attrs[3].value = rb_funcall(obj, hour_id, 0);
300
296
  attrs[4].value = rb_funcall(obj, min_id, 0);
301
297
  attrs[5].value = rb_funcall(obj, sec_id, 0);
302
- attrs[6].value = rb_funcall(rb_funcall(obj, offset_id, 0), oj_to_s_id, 0);
298
+ attrs[6].value = oj_safe_string_convert(rb_funcall(obj, offset_id, 0));
303
299
  attrs[7].value = rb_funcall(obj, start_id, 0);
304
300
 
305
301
  oj_code_attrs(obj, attrs, depth, out, true);
@@ -606,7 +602,7 @@ dump_float(VALUE obj, int depth, Out out, bool as_ok) {
606
602
  } else if (oj_rails_float_opt) {
607
603
  cnt = oj_dump_float_printf(buf, sizeof(buf), obj, d, "%0.16g");
608
604
  } else {
609
- volatile VALUE rstr = rb_funcall(obj, oj_to_s_id, 0);
605
+ volatile VALUE rstr = oj_safe_string_convert(obj);
610
606
 
611
607
  strcpy(buf, RSTRING_PTR(rstr));
612
608
  cnt = (int)RSTRING_LEN(rstr);
@@ -648,7 +644,7 @@ hash_cb(VALUE key, VALUE value, VALUE ov) {
648
644
  break;
649
645
  default:
650
646
  /*rb_raise(rb_eTypeError, "In :compat mode all Hash keys must be Strings or Symbols, not %s.\n", rb_class2name(rb_obj_class(key)));*/
651
- oj_dump_str(rb_funcall(key, oj_to_s_id, 0), 0, out, false);
647
+ oj_dump_str(oj_safe_string_convert(key), 0, out, false);
652
648
  break;
653
649
  }
654
650
  if (!out->opts->dump_opts.use) {
@@ -833,7 +829,7 @@ dump_bignum(VALUE obj, int depth, Out out, bool as_ok) {
833
829
  if (use_bignum_alt) {
834
830
  rs = rb_big2str(obj, 10);
835
831
  } else {
836
- rs = rb_funcall(obj, oj_to_s_id, 0);
832
+ rs = oj_safe_string_convert(obj);
837
833
  }
838
834
  rb_check_type(rs, T_STRING);
839
835
  cnt = (int)RSTRING_LEN(rs);
@@ -893,9 +889,7 @@ void
893
889
  oj_dump_compat_val(VALUE obj, int depth, Out out, bool as_ok) {
894
890
  int type = rb_type(obj);
895
891
 
896
- if (RB_UNLIKELY(Yes == out->opts->trace)) {
897
- oj_trace("dump", obj, __FILE__, __LINE__, depth, TraceIn);
898
- }
892
+ TRACE(out->opts->trace, "dump", obj, depth, TraceIn);
899
893
  if (out->opts->dump_opts.max_depth <= depth) {
900
894
  // When JSON.dump is called then an ArgumentError is expected and the
901
895
  // limit is the depth inclusive. If JSON.generate is called then a
@@ -918,14 +912,10 @@ oj_dump_compat_val(VALUE obj, int depth, Out out, bool as_ok) {
918
912
 
919
913
  if (NULL != f) {
920
914
  f(obj, depth, out, as_ok);
921
- if (RB_UNLIKELY(Yes == out->opts->trace)) {
922
- oj_trace("dump", obj, __FILE__, __LINE__, depth, TraceOut);
923
- }
915
+ TRACE(out->opts->trace, "dump", obj, depth, TraceOut);
924
916
  return;
925
917
  }
926
918
  }
927
919
  oj_dump_nil(Qnil, depth, out, false);
928
- if (RB_UNLIKELY(Yes == out->opts->trace)) {
929
- oj_trace("dump", Qnil, __FILE__, __LINE__, depth, TraceOut);
930
- }
920
+ TRACE(out->opts->trace, "dump", Qnil, depth, TraceOut);
931
921
  }
data/ext/oj/dump_object.c CHANGED
@@ -30,7 +30,7 @@ static void dump_data(VALUE obj, int depth, Out out, bool as_ok) {
30
30
  *out->cur = '\0';
31
31
  } else {
32
32
  if (oj_bigdecimal_class == clas) {
33
- volatile VALUE rstr = rb_funcall(obj, oj_to_s_id, 0);
33
+ volatile VALUE rstr = oj_safe_string_convert(obj);
34
34
  const char * str = RSTRING_PTR(rstr);
35
35
  int len = (int)RSTRING_LEN(rstr);
36
36
 
@@ -59,7 +59,7 @@ static void dump_obj(VALUE obj, int depth, Out out, bool as_ok) {
59
59
  VALUE clas = rb_obj_class(obj);
60
60
 
61
61
  if (oj_bigdecimal_class == clas) {
62
- volatile VALUE rstr = rb_funcall(obj, oj_to_s_id, 0);
62
+ volatile VALUE rstr = oj_safe_string_convert(obj);
63
63
  const char * str = RSTRING_PTR(rstr);
64
64
  int len = (int)RSTRING_LEN(rstr);
65
65
 
@@ -682,9 +682,7 @@ static DumpFunc obj_funcs[] = {
682
682
  void oj_dump_obj_val(VALUE obj, int depth, Out out) {
683
683
  int type = rb_type(obj);
684
684
 
685
- if (RB_UNLIKELY(Yes == out->opts->trace)) {
686
- oj_trace("dump", obj, __FILE__, __LINE__, depth, TraceIn);
687
- }
685
+ TRACE(out->opts->trace, "dump", obj, depth, TraceIn);
688
686
  if (MAX_DEPTH < depth) {
689
687
  rb_raise(rb_eNoMemError, "Too deeply nested.\n");
690
688
  }
@@ -693,14 +691,10 @@ void oj_dump_obj_val(VALUE obj, int depth, Out out) {
693
691
 
694
692
  if (NULL != f) {
695
693
  f(obj, depth, out, false);
696
- if (RB_UNLIKELY(Yes == out->opts->trace)) {
697
- oj_trace("dump", obj, __FILE__, __LINE__, depth, TraceOut);
698
- }
694
+ TRACE(out->opts->trace, "dump", obj, depth, TraceOut);
699
695
  return;
700
696
  }
701
697
  }
702
698
  oj_dump_nil(Qnil, depth, out, false);
703
- if (RB_UNLIKELY(Yes == out->opts->trace)) {
704
- oj_trace("dump", Qnil, __FILE__, __LINE__, depth, TraceOut);
705
- }
699
+ TRACE(out->opts->trace, "dump", Qnil, depth, TraceOut);
706
700
  }
data/ext/oj/dump_strict.c CHANGED
@@ -92,7 +92,7 @@ static void dump_float(VALUE obj, int depth, Out out, bool as_ok) {
92
92
  } else if (d == (double)(long long int)d) {
93
93
  cnt = snprintf(buf, sizeof(buf), "%.1f", d);
94
94
  } else if (0 == out->opts->float_prec) {
95
- volatile VALUE rstr = rb_funcall(obj, oj_to_s_id, 0);
95
+ volatile VALUE rstr = oj_safe_string_convert(obj);
96
96
 
97
97
  cnt = (int)RSTRING_LEN(rstr);
98
98
  if ((int)sizeof(buf) <= cnt) {
@@ -290,7 +290,7 @@ static void dump_data_strict(VALUE obj, int depth, Out out, bool as_ok) {
290
290
  VALUE clas = rb_obj_class(obj);
291
291
 
292
292
  if (oj_bigdecimal_class == clas) {
293
- volatile VALUE rstr = rb_funcall(obj, oj_to_s_id, 0);
293
+ volatile VALUE rstr = oj_safe_string_convert(obj);
294
294
 
295
295
  oj_dump_raw(RSTRING_PTR(rstr), (int)RSTRING_LEN(rstr), out);
296
296
  } else {
@@ -302,7 +302,7 @@ static void dump_data_null(VALUE obj, int depth, Out out, bool as_ok) {
302
302
  VALUE clas = rb_obj_class(obj);
303
303
 
304
304
  if (oj_bigdecimal_class == clas) {
305
- volatile VALUE rstr = rb_funcall(obj, oj_to_s_id, 0);
305
+ volatile VALUE rstr = oj_safe_string_convert(obj);
306
306
 
307
307
  oj_dump_raw(RSTRING_PTR(rstr), (int)RSTRING_LEN(rstr), out);
308
308
  } else {
@@ -338,9 +338,7 @@ static DumpFunc strict_funcs[] = {
338
338
  void oj_dump_strict_val(VALUE obj, int depth, Out out) {
339
339
  int type = rb_type(obj);
340
340
 
341
- if (RB_UNLIKELY(Yes == out->opts->trace)) {
342
- oj_trace("dump", obj, __FILE__, __LINE__, depth, TraceIn);
343
- }
341
+ TRACE(out->opts->trace, "dump", obj, depth, TraceIn);
344
342
  if (MAX_DEPTH < depth) {
345
343
  rb_raise(rb_eNoMemError, "Too deeply nested.\n");
346
344
  }
@@ -349,9 +347,7 @@ void oj_dump_strict_val(VALUE obj, int depth, Out out) {
349
347
 
350
348
  if (NULL != f) {
351
349
  f(obj, depth, out, false);
352
- if (RB_UNLIKELY(Yes == out->opts->trace)) {
353
- oj_trace("dump", obj, __FILE__, __LINE__, depth, TraceOut);
354
- }
350
+ TRACE(out->opts->trace, "dump", obj, depth, TraceOut);
355
351
  return;
356
352
  }
357
353
  }
@@ -386,9 +382,7 @@ static DumpFunc null_funcs[] = {
386
382
  void oj_dump_null_val(VALUE obj, int depth, Out out) {
387
383
  int type = rb_type(obj);
388
384
 
389
- if (RB_UNLIKELY(Yes == out->opts->trace)) {
390
- oj_trace("dump", obj, __FILE__, __LINE__, depth, TraceOut);
391
- }
385
+ TRACE(out->opts->trace, "dump", obj, depth, TraceOut);
392
386
  if (MAX_DEPTH < depth) {
393
387
  rb_raise(rb_eNoMemError, "Too deeply nested.\n");
394
388
  }
@@ -397,14 +391,10 @@ void oj_dump_null_val(VALUE obj, int depth, Out out) {
397
391
 
398
392
  if (NULL != f) {
399
393
  f(obj, depth, out, false);
400
- if (RB_UNLIKELY(Yes == out->opts->trace)) {
401
- oj_trace("dump", obj, __FILE__, __LINE__, depth, TraceOut);
402
- }
394
+ TRACE(out->opts->trace, "dump", obj, depth, TraceOut);
403
395
  return;
404
396
  }
405
397
  }
406
398
  oj_dump_nil(Qnil, depth, out, false);
407
- if (RB_UNLIKELY(Yes == out->opts->trace)) {
408
- oj_trace("dump", Qnil, __FILE__, __LINE__, depth, TraceOut);
409
- }
399
+ TRACE(out->opts->trace, "dump", Qnil, depth, TraceOut);
410
400
  }
data/ext/oj/extconf.rb CHANGED
@@ -35,8 +35,16 @@ have_func('rb_hash_bulk_insert', 'ruby.h') unless '2' == version[0] && '6' == ve
35
35
  dflags['OJ_DEBUG'] = true unless ENV['OJ_DEBUG'].nil?
36
36
 
37
37
  if with_config('--with-sse42')
38
- $CPPFLAGS += ' -msse4.2'
39
- dflags['OJ_USE_SSE4_2'] = 1
38
+ if try_cflags('-msse4.2')
39
+ $CPPFLAGS += ' -msse4.2'
40
+ dflags['OJ_USE_SSE4_2'] = 1
41
+ else
42
+ warn 'SSE 4.2 is not supported on this platform.'
43
+ end
44
+ end
45
+
46
+ if enable_config('trace-log', false)
47
+ dflags['OJ_ENABLE_TRACE_LOG'] = 1
40
48
  end
41
49
 
42
50
  dflags.each do |k,v|
data/ext/oj/fast.c CHANGED
@@ -74,7 +74,7 @@ static char *read_quoted_value(ParseInfo pi);
74
74
  static void skip_comment(ParseInfo pi);
75
75
 
76
76
  static VALUE protect_open_proc(VALUE x);
77
- static VALUE parse_json(VALUE clas, char *json, bool given, bool allocated);
77
+ static VALUE parse_json(VALUE clas, char *json, bool given);
78
78
  static void each_leaf(Doc doc, VALUE self);
79
79
  static int move_step(Doc doc, const char *path, int loc);
80
80
  static Leaf get_doc_leaf(Doc doc, const char *path);
@@ -651,7 +651,8 @@ static void doc_free(Doc doc) {
651
651
  xfree(b);
652
652
  }
653
653
  }
654
- // xfree(f);
654
+ xfree(doc->json);
655
+ xfree(doc);
655
656
  }
656
657
  }
657
658
 
@@ -671,7 +672,6 @@ static void free_doc_cb(void *x) {
671
672
  Doc doc = (Doc)x;
672
673
 
673
674
  if (0 != doc) {
674
- xfree(doc->json);
675
675
  doc_free(doc);
676
676
  }
677
677
  }
@@ -749,20 +749,15 @@ static const rb_data_type_t oj_doc_type = {
749
749
  0,
750
750
  };
751
751
 
752
- static VALUE parse_json(VALUE clas, char *json, bool given, bool allocated) {
752
+ static VALUE parse_json(VALUE clas, char *json, bool given) {
753
753
  struct _parseInfo pi;
754
754
  volatile VALUE result = Qnil;
755
755
  Doc doc;
756
756
  int ex = 0;
757
757
  volatile VALUE self;
758
758
 
759
- // TBD are both needed? is stack allocation ever needed?
759
+ doc = RB_ALLOC_N(struct _doc, 1);
760
760
 
761
- if (given) {
762
- doc = ALLOCA_N(struct _doc, 1);
763
- } else {
764
- doc = ALLOC(struct _doc);
765
- }
766
761
  // skip UTF-8 BOM if present
767
762
  if (0xEF == (uint8_t)*json && 0xBB == (uint8_t)json[1] && 0xBF == (uint8_t)json[2]) {
768
763
  pi.str = json + 3;
@@ -787,18 +782,20 @@ static VALUE parse_json(VALUE clas, char *json, bool given, bool allocated) {
787
782
  }
788
783
  }
789
784
  #endif
785
+ doc->json = json;
790
786
  self = TypedData_Wrap_Struct(clas, &oj_doc_type, doc);
791
787
  doc->self = self;
792
- doc->json = json;
793
788
  DATA_PTR(doc->self) = doc;
794
789
  result = rb_protect(protect_open_proc, (VALUE)&pi, &ex);
795
790
  if (given || 0 != ex) {
796
791
  DATA_PTR(doc->self) = NULL;
792
+ // TBD is this needed?
793
+ /*
797
794
  doc_free(pi.doc);
798
- if (allocated && 0 != ex) { // will jump so caller will not free
795
+ if (0 != ex) { // will jump so caller will not free
799
796
  xfree(json);
800
797
  }
801
- rb_gc_enable();
798
+ */
802
799
  } else {
803
800
  result = doc->self;
804
801
  }
@@ -1092,27 +1089,19 @@ static VALUE doc_open(VALUE clas, VALUE str) {
1092
1089
  size_t len;
1093
1090
  volatile VALUE obj;
1094
1091
  int given = rb_block_given_p();
1095
- int allocate;
1096
1092
 
1097
1093
  Check_Type(str, T_STRING);
1098
1094
  len = (int)RSTRING_LEN(str) + 1;
1099
- allocate = (SMALL_JSON < len || !given);
1100
- if (allocate) {
1101
- json = ALLOC_N(char, len);
1102
- } else {
1103
- json = ALLOCA_N(char, len);
1104
- }
1105
- // It should not be necessaary to stop GC but if it is not stopped and a
1106
- // large string is parsed that string is corrupted or freed during
1107
- // parsing. I'm not sure what is going on exactly but disabling GC avoids
1108
- // the issue.
1109
- rb_gc_disable();
1095
+ json = RB_ALLOC_N(char, len);
1096
+
1110
1097
  memcpy(json, StringValuePtr(str), len);
1111
- obj = parse_json(clas, json, given, allocate);
1112
- rb_gc_enable();
1113
- if (given && allocate) {
1098
+ obj = parse_json(clas, json, given);
1099
+ // TBD is this needed
1100
+ /*
1101
+ if (given) {
1114
1102
  xfree(json);
1115
1103
  }
1104
+ */
1116
1105
  return obj;
1117
1106
  }
1118
1107
 
@@ -1142,7 +1131,6 @@ static VALUE doc_open_file(VALUE clas, VALUE filename) {
1142
1131
  size_t len;
1143
1132
  volatile VALUE obj;
1144
1133
  int given = rb_block_given_p();
1145
- int allocate;
1146
1134
 
1147
1135
  Check_Type(filename, T_STRING);
1148
1136
  path = StringValuePtr(filename);
@@ -1151,12 +1139,8 @@ static VALUE doc_open_file(VALUE clas, VALUE filename) {
1151
1139
  }
1152
1140
  fseek(f, 0, SEEK_END);
1153
1141
  len = ftell(f);
1154
- allocate = (SMALL_JSON < len || !given);
1155
- if (allocate) {
1156
- json = ALLOC_N(char, len + 1);
1157
- } else {
1158
- json = ALLOCA_N(char, len + 1);
1159
- }
1142
+ json = RB_ALLOC_N(char, len + 1);
1143
+
1160
1144
  fseek(f, 0, SEEK_SET);
1161
1145
  if (len != fread(json, 1, len, f)) {
1162
1146
  fclose(f);
@@ -1167,12 +1151,13 @@ static VALUE doc_open_file(VALUE clas, VALUE filename) {
1167
1151
  }
1168
1152
  fclose(f);
1169
1153
  json[len] = '\0';
1170
- rb_gc_disable();
1171
- obj = parse_json(clas, json, given, allocate);
1172
- rb_gc_enable();
1173
- if (given && allocate) {
1154
+ obj = parse_json(clas, json, given);
1155
+ // TBD is this needed
1156
+ /*
1157
+ if (given) {
1174
1158
  xfree(json);
1175
1159
  }
1160
+ */
1176
1161
  return obj;
1177
1162
  }
1178
1163
 
@@ -1656,11 +1641,9 @@ static VALUE doc_close(VALUE self) {
1656
1641
  Doc doc = self_doc(self);
1657
1642
 
1658
1643
  rb_gc_unregister_address(&doc->self);
1659
- DATA_PTR(doc->self) = 0;
1644
+ DATA_PTR(doc->self) = NULL;
1660
1645
  if (0 != doc) {
1661
- xfree(doc->json);
1662
1646
  doc_free(doc);
1663
- xfree(doc);
1664
1647
  }
1665
1648
  return Qnil;
1666
1649
  }
data/ext/oj/object.c CHANGED
@@ -609,9 +609,7 @@ WHICH_TYPE:
609
609
  }
610
610
 
611
611
  static VALUE start_hash(ParseInfo pi) {
612
- if (RB_UNLIKELY(Yes == pi->options.trace)) {
613
- oj_trace_parse_in("start_hash", pi, __FILE__, __LINE__);
614
- }
612
+ TRACE_PARSE_IN(pi->options.trace, "start_hash", pi);
615
613
  return Qnil;
616
614
  }
617
615
 
@@ -627,9 +625,7 @@ static void end_hash(ParseInfo pi) {
627
625
  oj_odd_free(oa);
628
626
  parent->odd_args = NULL;
629
627
  }
630
- if (RB_UNLIKELY(Yes == pi->options.trace)) {
631
- oj_trace_parse_hash_end(pi, __FILE__, __LINE__);
632
- }
628
+ TRACE_PARSE_HASH_END(pi->options.trace, pi);
633
629
  }
634
630
 
635
631
  static void array_append_cstr(ParseInfo pi, const char *str, size_t len, const char *orig) {
data/ext/oj/oj.h CHANGED
@@ -379,6 +379,12 @@ extern bool oj_use_hash_alt;
379
379
  extern bool oj_use_array_alt;
380
380
  extern bool string_writer_optimized;
381
381
 
382
+ static inline VALUE oj_safe_string_convert(VALUE obj) {
383
+ VALUE rstr = rb_funcall(obj, oj_to_s_id, 0);
384
+ StringValue(rstr);
385
+ return rstr;
386
+ }
387
+
382
388
  #define APPEND_CHARS(buffer, chars, size) \
383
389
  { \
384
390
  memcpy(buffer, chars, size); \
data/ext/oj/parse.c CHANGED
@@ -16,6 +16,10 @@
16
16
  #include "rxclass.h"
17
17
  #include "val_stack.h"
18
18
 
19
+ #ifdef OJ_USE_SSE4_2
20
+ #include <nmmintrin.h>
21
+ #endif
22
+
19
23
  // Workaround in case INFINITY is not defined in math.h or if the OS is CentOS
20
24
  #define OJ_INFINITY (1.0 / 0.0)
21
25
 
data/ext/oj/parser.c CHANGED
@@ -1263,7 +1263,7 @@ static VALUE parser_new(int argc, VALUE *argv, VALUE self) {
1263
1263
  // from this function. A delegate must be added before the parser can be
1264
1264
  // used. Optionally oj_parser_set_options can be called if the options are not
1265
1265
  // set directly.
1266
- VALUE oj_parser_new() {
1266
+ VALUE oj_parser_new(void) {
1267
1267
  ojParser p = ALLOC(struct _ojParser);
1268
1268
 
1269
1269
  #if HAVE_RB_EXT_RACTOR_SAFE
data/ext/oj/rails.c CHANGED
@@ -198,7 +198,7 @@ static void dump_enumerable(VALUE obj, int depth, Out out, bool as_ok) {
198
198
  }
199
199
 
200
200
  static void dump_bigdecimal(VALUE obj, int depth, Out out, bool as_ok) {
201
- volatile VALUE rstr = rb_funcall(obj, oj_to_s_id, 0);
201
+ volatile VALUE rstr = oj_safe_string_convert(obj);
202
202
  const char * str = RSTRING_PTR(rstr);
203
203
 
204
204
  if ('I' == *str || 'N' == *str || ('-' == *str && 'I' == str[1])) {
@@ -345,7 +345,7 @@ static void dump_timewithzone(VALUE obj, int depth, Out out, bool as_ok) {
345
345
  }
346
346
 
347
347
  static void dump_to_s(VALUE obj, int depth, Out out, bool as_ok) {
348
- volatile VALUE rstr = rb_funcall(obj, oj_to_s_id, 0);
348
+ volatile VALUE rstr = oj_safe_string_convert(obj);
349
349
 
350
350
  oj_dump_cstr(RSTRING_PTR(rstr), (int)RSTRING_LEN(rstr), 0, 0, out);
351
351
  }
@@ -377,7 +377,7 @@ static StrLen columns_array(VALUE rcols, int *ccnt) {
377
377
  for (i = 0, cp = cols; i < cnt; i++, cp++) {
378
378
  v = RARRAY_AREF(rcols, i);
379
379
  if (T_STRING != rb_type(v)) {
380
- v = rb_funcall(v, oj_to_s_id, 0);
380
+ v = oj_safe_string_convert(v);
381
381
  }
382
382
  cp->str = StringValuePtr(v);
383
383
  cp->len = (int)RSTRING_LEN(v);
@@ -517,9 +517,7 @@ static void dump_as_string(VALUE obj, int depth, Out out, bool as_ok) {
517
517
  static void dump_as_json(VALUE obj, int depth, Out out, bool as_ok) {
518
518
  volatile VALUE ja;
519
519
 
520
- if (RB_UNLIKELY(Yes == out->opts->trace)) {
521
- oj_trace("as_json", obj, __FILE__, __LINE__, depth + 1, TraceRubyIn);
522
- }
520
+ TRACE(out->opts->trace, "as_json", obj, depth + 1, TraceRubyIn);
523
521
  // Some classes elect to not take an options argument so check the arity
524
522
  // of as_json.
525
523
  if (0 == rb_obj_method_arity(obj, oj_as_json_id)) {
@@ -527,9 +525,7 @@ static void dump_as_json(VALUE obj, int depth, Out out, bool as_ok) {
527
525
  } else {
528
526
  ja = rb_funcall2(obj, oj_as_json_id, out->argc, out->argv);
529
527
  }
530
- if (RB_UNLIKELY(Yes == out->opts->trace)) {
531
- oj_trace("as_json", obj, __FILE__, __LINE__, depth + 1, TraceRubyOut);
532
- }
528
+ TRACE(out->opts->trace, "as_json", obj, depth + 1, TraceRubyOut);
533
529
 
534
530
  out->argc = 0;
535
531
  if (ja == obj || !as_ok) {
@@ -1208,7 +1204,7 @@ static void dump_float(VALUE obj, int depth, Out out, bool as_ok) {
1208
1204
  } else if (oj_rails_float_opt) {
1209
1205
  cnt = oj_dump_float_printf(buf, sizeof(buf), obj, d, "%0.16g");
1210
1206
  } else {
1211
- volatile VALUE rstr = rb_funcall(obj, oj_to_s_id, 0);
1207
+ volatile VALUE rstr = oj_safe_string_convert(obj);
1212
1208
 
1213
1209
  strcpy(buf, RSTRING_PTR(rstr));
1214
1210
  cnt = (int)RSTRING_LEN(rstr);
@@ -1301,7 +1297,7 @@ static int hash_cb(VALUE key, VALUE value, VALUE ov) {
1301
1297
  return ST_CONTINUE;
1302
1298
  }
1303
1299
  if (rtype != T_STRING && rtype != T_SYMBOL) {
1304
- key = rb_funcall(key, oj_to_s_id, 0);
1300
+ key = oj_safe_string_convert(key);
1305
1301
  rtype = rb_type(key);
1306
1302
  }
1307
1303
  if (!out->opts->dump_opts.use) {
@@ -1464,9 +1460,7 @@ static DumpFunc rails_funcs[] = {
1464
1460
  static void dump_rails_val(VALUE obj, int depth, Out out, bool as_ok) {
1465
1461
  int type = rb_type(obj);
1466
1462
 
1467
- if (RB_UNLIKELY(Yes == out->opts->trace)) {
1468
- oj_trace("dump", obj, __FILE__, __LINE__, depth, TraceIn);
1469
- }
1463
+ TRACE(out->opts->trace, "dump", obj, depth, TraceIn);
1470
1464
  if (MAX_DEPTH < depth) {
1471
1465
  rb_raise(rb_eNoMemError, "Too deeply nested.\n");
1472
1466
  }
@@ -1475,16 +1469,12 @@ static void dump_rails_val(VALUE obj, int depth, Out out, bool as_ok) {
1475
1469
 
1476
1470
  if (NULL != f) {
1477
1471
  f(obj, depth, out, as_ok);
1478
- if (RB_UNLIKELY(Yes == out->opts->trace)) {
1479
- oj_trace("dump", obj, __FILE__, __LINE__, depth, TraceOut);
1480
- }
1472
+ TRACE(out->opts->trace, "dump", obj, depth, TraceOut);
1481
1473
  return;
1482
1474
  }
1483
1475
  }
1484
1476
  oj_dump_nil(Qnil, depth, out, false);
1485
- if (RB_UNLIKELY(Yes == out->opts->trace)) {
1486
- oj_trace("dump", Qnil, __FILE__, __LINE__, depth, TraceOut);
1487
- }
1477
+ TRACE(out->opts->trace, "dump", Qnil, depth, TraceOut);
1488
1478
  }
1489
1479
 
1490
1480
  void oj_dump_rails_val(VALUE obj, int depth, Out out) {
data/ext/oj/reader.c CHANGED
@@ -75,7 +75,7 @@ void oj_reader_init(Reader reader, VALUE io, int fd, bool to_s) {
75
75
  reader->read_func = read_from_io;
76
76
  reader->io = io;
77
77
  } else if (to_s) {
78
- volatile VALUE rstr = rb_funcall(io, oj_to_s_id, 0);
78
+ volatile VALUE rstr = oj_safe_string_convert(io);
79
79
 
80
80
  reader->read_func = 0;
81
81
  reader->in_str = StringValuePtr(rstr);
data/ext/oj/strict.c CHANGED
@@ -50,15 +50,11 @@ VALUE oj_calc_hash_key(ParseInfo pi, Val parent) {
50
50
  }
51
51
 
52
52
  static void hash_end(ParseInfo pi) {
53
- if (RB_UNLIKELY(Yes == pi->options.trace)) {
54
- oj_trace_parse_hash_end(pi, __FILE__, __LINE__);
55
- }
53
+ TRACE_PARSE_HASH_END(pi->options.trace, pi);
56
54
  }
57
55
 
58
56
  static void array_end(ParseInfo pi) {
59
- if (RB_UNLIKELY(Yes == pi->options.trace)) {
60
- oj_trace_parse_array_end(pi, __FILE__, __LINE__);
61
- }
57
+ TRACE_PARSE_ARRAY_END(pi->options.trace, pi);
62
58
  }
63
59
 
64
60
  static VALUE noop_hash_key(ParseInfo pi, const char *key, size_t klen) {
@@ -95,9 +91,7 @@ static VALUE start_hash(ParseInfo pi) {
95
91
  if (Qnil != pi->options.hash_class) {
96
92
  return rb_class_new_instance(0, NULL, pi->options.hash_class);
97
93
  }
98
- if (RB_UNLIKELY(Yes == pi->options.trace)) {
99
- oj_trace_parse_in("start_hash", pi, __FILE__, __LINE__);
100
- }
94
+ TRACE_PARSE_IN(pi->options.trace, "start_hash", pi);
101
95
  return rb_hash_new();
102
96
  }
103
97
 
@@ -137,9 +131,7 @@ static void hash_set_value(ParseInfo pi, Val parent, VALUE value) {
137
131
  }
138
132
 
139
133
  static VALUE start_array(ParseInfo pi) {
140
- if (RB_UNLIKELY(Yes == pi->options.trace)) {
141
- oj_trace_parse_in("start_array", pi, __FILE__, __LINE__);
142
- }
134
+ TRACE_PARSE_IN(pi->options.trace, "start_array", pi);
143
135
  return rb_ary_new();
144
136
  }
145
137
 
data/ext/oj/trace.h CHANGED
@@ -25,4 +25,20 @@ extern void
25
25
  extern void oj_trace_parse_hash_end(struct _parseInfo *pi, const char *file, int line);
26
26
  extern void oj_trace_parse_array_end(struct _parseInfo *pi, const char *file, int line);
27
27
 
28
+
29
+ #ifdef OJ_ENABLE_TRACE_LOG
30
+ #define TRACE(option, func, obj, depth, where) if (RB_UNLIKELY(Yes == option)) { oj_trace(func, obj, __FILE__, __LINE__, depth, where); }
31
+ #define TRACE_PARSE_IN(option, func, pi) if (RB_UNLIKELY(Yes == option)) { oj_trace_parse_in(func, pi, __FILE__, __LINE__); }
32
+ #define TRACE_PARSE_CALL(option, func, pi, obj) if (RB_UNLIKELY(Yes == option)) { oj_trace_parse_call(func, pi, __FILE__, __LINE__, obj); }
33
+ #define TRACE_PARSE_HASH_END(option, pi) if (RB_UNLIKELY(Yes == option)) { oj_trace_parse_hash_end(pi, __FILE__, __LINE__); }
34
+ #define TRACE_PARSE_ARRAY_END(option, pi) if (RB_UNLIKELY(Yes == option)) { oj_trace_parse_array_end(pi, __FILE__, __LINE__); }
35
+ #else
36
+ #define TRACE(option, func, obj, depth, where)
37
+ #define TRACE_PARSE_IN(option, func, pi)
38
+ #define TRACE_PARSE_CALL(option, func, pi, obj)
39
+ #define TRACE_PARSE_HASH_END(option, pi)
40
+ #define TRACE_PARSE_ARRAY_END(option, pi)
41
+ #endif
42
+
43
+
28
44
  #endif /* OJ_TRACE_H */
data/ext/oj/wab.c CHANGED
@@ -226,13 +226,13 @@ static void dump_obj(VALUE obj, int depth, Out out, bool as_ok) {
226
226
  if (rb_cTime == clas) {
227
227
  dump_time(obj, out);
228
228
  } else if (oj_bigdecimal_class == clas) {
229
- volatile VALUE rstr = rb_funcall(obj, oj_to_s_id, 0);
229
+ volatile VALUE rstr = oj_safe_string_convert(obj);
230
230
 
231
231
  oj_dump_raw(RSTRING_PTR(rstr), (int)RSTRING_LEN(rstr), out);
232
232
  } else if (resolve_wab_uuid_class() == clas) {
233
- oj_dump_str(rb_funcall(obj, oj_to_s_id, 0), depth, out, false);
233
+ oj_dump_str(oj_safe_string_convert(obj), depth, out, false);
234
234
  } else if (resolve_uri_http_class() == clas) {
235
- oj_dump_str(rb_funcall(obj, oj_to_s_id, 0), depth, out, false);
235
+ oj_dump_str(oj_safe_string_convert(obj), depth, out, false);
236
236
  } else {
237
237
  raise_wab(obj);
238
238
  }
@@ -266,9 +266,7 @@ static DumpFunc wab_funcs[] = {
266
266
  void oj_dump_wab_val(VALUE obj, int depth, Out out) {
267
267
  int type = rb_type(obj);
268
268
 
269
- if (RB_UNLIKELY(Yes == out->opts->trace)) {
270
- oj_trace("dump", obj, __FILE__, __LINE__, depth, TraceIn);
271
- }
269
+ TRACE(out->opts->trace, "dump", obj, depth, TraceIn);
272
270
  if (MAX_DEPTH < depth) {
273
271
  rb_raise(rb_eNoMemError, "Too deeply nested.\n");
274
272
  }
@@ -277,9 +275,7 @@ void oj_dump_wab_val(VALUE obj, int depth, Out out) {
277
275
 
278
276
  if (NULL != f) {
279
277
  f(obj, depth, out, false);
280
- if (RB_UNLIKELY(Yes == out->opts->trace)) {
281
- oj_trace("dump", obj, __FILE__, __LINE__, depth, TraceOut);
282
- }
278
+ TRACE(out->opts->trace, "dump", obj, depth, TraceOut);
283
279
  return;
284
280
  }
285
281
  }
@@ -312,15 +308,11 @@ static VALUE calc_hash_key(ParseInfo pi, Val parent) {
312
308
  }
313
309
 
314
310
  static void hash_end(ParseInfo pi) {
315
- if (RB_UNLIKELY(Yes == pi->options.trace)) {
316
- oj_trace_parse_hash_end(pi, __FILE__, __LINE__);
317
- }
311
+ TRACE_PARSE_HASH_END(pi->options.trace, pi);
318
312
  }
319
313
 
320
314
  static void array_end(ParseInfo pi) {
321
- if (RB_UNLIKELY(Yes == pi->options.trace)) {
322
- oj_trace_parse_array_end(pi, __FILE__, __LINE__);
323
- }
315
+ TRACE_PARSE_ARRAY_END(pi->options.trace, pi);
324
316
  }
325
317
 
326
318
  static VALUE noop_hash_key(ParseInfo pi, const char *key, size_t klen) {
@@ -494,9 +486,7 @@ static void add_num(ParseInfo pi, NumInfo ni) {
494
486
  }
495
487
 
496
488
  static VALUE start_hash(ParseInfo pi) {
497
- if (RB_UNLIKELY(Yes == pi->options.trace)) {
498
- oj_trace_parse_in("start_hash", pi, __FILE__, __LINE__);
499
- }
489
+ TRACE_PARSE_IN(pi->options.trace, "start_hash", pi);
500
490
  if (Qnil != pi->options.hash_class) {
501
491
  return rb_class_new_instance(0, NULL, pi->options.hash_class);
502
492
  }
@@ -533,9 +523,7 @@ static void hash_set_value(ParseInfo pi, Val parent, VALUE value) {
533
523
  }
534
524
 
535
525
  static VALUE start_array(ParseInfo pi) {
536
- if (RB_UNLIKELY(Yes == pi->options.trace)) {
537
- oj_trace_parse_in("start_array", pi, __FILE__, __LINE__);
538
- }
526
+ TRACE_PARSE_IN(pi->options.trace, "start_array", pi);
539
527
  return rb_ary_new();
540
528
  }
541
529
 
data/lib/oj/version.rb CHANGED
@@ -1,5 +1,5 @@
1
1
 
2
2
  module Oj
3
3
  # Current version of the module.
4
- VERSION = '3.13.23'
4
+ VERSION = '3.14.0'
5
5
  end
@@ -0,0 +1,20 @@
1
+ # Oj Install Options
2
+
3
+ ### Enable trace log
4
+
5
+ ```
6
+ $ gem install oj -- --enable-trace-log
7
+ ```
8
+
9
+ To enable Oj trace feature, it uses `--enable-trace-log` option when installing the gem.
10
+ Then, the trace logs will be displayed when `:trace` option is set to `true`.
11
+
12
+
13
+ ### Enable SIMD instructions
14
+
15
+ ```
16
+ $ gem install oj -- --with-sse42
17
+ ```
18
+
19
+ To enable the use of SIMD instructions in Oj, it uses the `--with-sse42` option when installing the gem.
20
+ This will enable the use of the SSE4.2 instructions in the internal.
data/test/foo.rb CHANGED
@@ -5,73 +5,25 @@ $: << File.join(File.dirname(__FILE__), "../lib")
5
5
  $: << File.join(File.dirname(__FILE__), "../ext")
6
6
 
7
7
  require "oj"
8
- require "socket"
9
- require 'io/nonblock'
10
8
 
11
- #pid = spawn("nc -d 0.1 -l 5000", out: "/dev/null")
12
- pid = spawn("nc -i 1 -l 7777", out: "/dev/null")
13
- at_exit { Process.kill 9, pid }
14
- sleep 0.2
15
- s = Socket.tcp("localhost", 7777)
16
- s.nonblock = false
17
- 1_000_000.times do |x|
18
- Oj.to_stream(s, { x: [0, 1, 2, 3, 4, 5, 6, 7, 8, 9]})
19
- end
20
9
 
21
- =begin
22
- IO.pipe do |r, w|
23
- if fork
24
- r.close
25
- #w.nonblock = false
26
- 1_000_000.times do |i|
27
- begin
28
- Oj.to_stream(w, { x: i})
29
- rescue IOError => e
30
- puts "*** #{i} raised #{e.class}: #{e}"
31
- IO.select(nil, [w])
32
- retry
33
- end
34
- w.puts
35
- end
36
- else
37
- w.close
38
- sleep(0.1)
39
- r.each_line { |b|
40
- #print b
41
- }
42
- r.close
43
- Process.exit(0)
44
- end
45
- end
46
- =end
10
+ p = Oj::Parser.new(:saj)
11
+
12
+ json = %|{
13
+ "array": [
14
+ {
15
+ "num" : 3,
16
+ "string": "message",
17
+ "hash" : {
18
+ "h2" : {
19
+ "a" : [ 1, 2, 3 ]
20
+ }
21
+ }
22
+ }
23
+ ],
24
+ "boolean" : true
25
+ }|
47
26
 
48
- =begin
49
- IO.pipe do |r, w|
50
- if fork
51
- r.close
52
- #w.nonblock = false
53
- a = []
54
- 10_000.times do |i|
55
- a << i
56
- end
57
- begin
58
- Oj.to_stream(w, a, indent: 2)
59
- rescue IOError => e
60
- puts "*** raised #{e.class}: #{e}"
61
- puts "*** fileno: #{w.fileno}"
62
- puts "*** is an IO?: #{w.kind_of?(IO)}"
63
- IO.select(nil, [w])
64
- retry
65
- end
66
- w.puts
67
- else
68
- w.close
69
- sleep(0.5)
70
- r.each_line { |b|
71
- #print b
72
- }
73
- r.close
74
- Process.exit(0)
75
- end
27
+ 1_000_000.times do
28
+ e = Oj.load(json)
76
29
  end
77
- =end
data/test/test_compat.rb CHANGED
@@ -513,6 +513,15 @@ class CompatJuice < Minitest::Test
513
513
  assert_equal("aaaa\nbbbb\rcccc\tddd\feee\bf/\\ぴーたー ", Oj.load(json))
514
514
  end
515
515
 
516
+ def test_invalid_to_s
517
+ obj = Object.new
518
+ def obj.to_s
519
+ nil
520
+ end
521
+
522
+ assert_raises(TypeError) { Oj.dump(obj, mode: :compat) }
523
+ end
524
+
516
525
  def dump_and_load(obj, trace=false)
517
526
  json = Oj.dump(obj)
518
527
  puts json if trace
metadata CHANGED
@@ -1,14 +1,14 @@
1
1
  --- !ruby/object:Gem::Specification
2
2
  name: oj
3
3
  version: !ruby/object:Gem::Version
4
- version: 3.13.23
4
+ version: 3.14.0
5
5
  platform: ruby
6
6
  authors:
7
7
  - Peter Ohler
8
8
  autorequire:
9
9
  bindir: bin
10
10
  cert_chain: []
11
- date: 2022-11-06 00:00:00.000000000 Z
11
+ date: 2023-01-30 00:00:00.000000000 Z
12
12
  dependencies:
13
13
  - !ruby/object:Gem::Dependency
14
14
  name: rake-compiler
@@ -72,6 +72,7 @@ extra_rdoc_files:
72
72
  - pages/Compatibility.md
73
73
  - pages/Custom.md
74
74
  - pages/Encoding.md
75
+ - pages/InstallOptions.md
75
76
  - pages/JsonGem.md
76
77
  - pages/Modes.md
77
78
  - pages/Options.md
@@ -161,6 +162,7 @@ files:
161
162
  - pages/Compatibility.md
162
163
  - pages/Custom.md
163
164
  - pages/Encoding.md
165
+ - pages/InstallOptions.md
164
166
  - pages/JsonGem.md
165
167
  - pages/Modes.md
166
168
  - pages/Options.md