oj 3.13.14 → 3.13.22

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 (57) hide show
  1. checksums.yaml +4 -4
  2. data/CHANGELOG.md +32 -0
  3. data/README.md +2 -0
  4. data/ext/oj/buf.h +4 -0
  5. data/ext/oj/compat.c +10 -10
  6. data/ext/oj/custom.c +34 -53
  7. data/ext/oj/dump.c +24 -13
  8. data/ext/oj/dump_compat.c +5 -10
  9. data/ext/oj/dump_object.c +5 -60
  10. data/ext/oj/dump_strict.c +5 -5
  11. data/ext/oj/extconf.rb +5 -4
  12. data/ext/oj/fast.c +15 -13
  13. data/ext/oj/intern.c +6 -9
  14. data/ext/oj/introspect.c +96 -0
  15. data/ext/oj/mimic_json.c +18 -8
  16. data/ext/oj/object.c +42 -41
  17. data/ext/oj/oj.c +27 -4
  18. data/ext/oj/oj.h +4 -1
  19. data/ext/oj/parse.c +111 -76
  20. data/ext/oj/parse.h +2 -0
  21. data/ext/oj/parser.c +61 -4
  22. data/ext/oj/parser.h +12 -0
  23. data/ext/oj/rails.c +5 -10
  24. data/ext/oj/saj2.c +333 -85
  25. data/ext/oj/saj2.h +23 -0
  26. data/ext/oj/sparse.c +4 -0
  27. data/ext/oj/strict.c +13 -13
  28. data/ext/oj/usual.c +82 -129
  29. data/ext/oj/usual.h +68 -0
  30. data/ext/oj/val_stack.c +1 -1
  31. data/ext/oj/validate.c +21 -26
  32. data/ext/oj/wab.c +15 -20
  33. data/lib/oj/saj.rb +20 -6
  34. data/lib/oj/state.rb +1 -1
  35. data/lib/oj/version.rb +1 -1
  36. data/pages/Compatibility.md +1 -1
  37. data/test/bar.rb +3 -1
  38. data/test/helper.rb +8 -2
  39. data/test/json_gem/json_generator_test.rb +3 -4
  40. data/test/json_gem/json_parser_test.rb +8 -1
  41. data/test/json_gem/test_helper.rb +7 -3
  42. data/test/test_compat.rb +25 -0
  43. data/test/test_custom.rb +13 -2
  44. data/test/test_file.rb +23 -7
  45. data/test/test_gc.rb +11 -0
  46. data/test/test_object.rb +3 -10
  47. data/test/test_parser.rb +3 -19
  48. data/test/test_parser_debug.rb +27 -0
  49. data/test/test_parser_saj.rb +92 -2
  50. data/test/test_scp.rb +2 -4
  51. data/test/test_strict.rb +2 -0
  52. data/test/test_various.rb +8 -3
  53. data/test/test_wab.rb +2 -0
  54. data/test/tests.rb +9 -0
  55. data/test/tests_mimic.rb +9 -0
  56. data/test/tests_mimic_addition.rb +9 -0
  57. metadata +7 -107
checksums.yaml CHANGED
@@ -1,7 +1,7 @@
1
1
  ---
2
2
  SHA256:
3
- metadata.gz: 6b0eec52170402a3d26527fa072d57fef1647f767e8559b8462893ced4f4cf21
4
- data.tar.gz: 93bba77447858ae77366ff7d8c05ad3199457e2b55a3584dcb6ccca3288d0d4a
3
+ metadata.gz: d90ba7b2698041767008afd20cef0dbd6ba1af0d97affa2253b12e199e6c528d
4
+ data.tar.gz: f9a8219f0b6f66ef0608136068d78cbc6c8b1ee765bfaa68eeb828cae1401fd8
5
5
  SHA512:
6
- metadata.gz: 9c95fa98149c6b8686376ab6d0f5744ca8a1312f62336a04c23da68d1e76c66c1d0a82ed755e945478623abfae85dac0d58ea84715d61d42dc0441455c3982d6
7
- data.tar.gz: 00eb3b90452e1adc6cf58e4eec3be107076ee99544c7b0d70b7cff6aa9a758b9a330391669a0622f95681cf3e4dc3cf47bdc2be8496a322f1d9432f2557b052a
6
+ metadata.gz: e72d7030911b6609946437de78aaf4fa9003a598c77dca472c2998f9af6115436e817fb4c46ec0ead55cb1ccb0ba80298c2ab060fab9fe37d0ec825d0ec6e5e4
7
+ data.tar.gz: 4aacdb9f034a2548a3eb942b4a29fb66a9839a63770bd10d0b8b62d93d944070d78ee53ca26881f05108047cc9c120efb3a732048b0be51a608f144f2ad0a374
data/CHANGELOG.md CHANGED
@@ -1,5 +1,37 @@
1
1
  # CHANGELOG
2
2
 
3
+ ## 3.13.22 - 2022-11-01
4
+
5
+ - Reorganized Oj::Parser code to allow for parser extensions in C.
6
+
7
+ ## 3.13.21 - 2022-08-19
8
+
9
+ - Bug parsing big numbers fixed in the SAJ parser.
10
+
11
+ ## 3.13.20 - 2022-08-07
12
+
13
+ - SSE4 made optional with a `--with-sse42` flag to the compile.
14
+
15
+ ## 3.13.19 - 2022-07-29
16
+
17
+ - TruffleRuby issues resolved.
18
+
19
+ ## 3.13.18 - 2022-07-25
20
+
21
+ - Fixed SSE detection at run time.
22
+
23
+ ## 3.13.17 - 2022-07-15
24
+
25
+ - Fixed Oj::Parser to detect unterminated arrays and objects.
26
+
27
+ ## 3.13.16 - 2022-07-06
28
+
29
+ - Added line and column as optional arguments to the Oj::Parser.saj parser.
30
+
31
+ ## 3.13.15 - 2022-07-03
32
+
33
+ - Fixed issue dumping NaN value in object mode.
34
+
3
35
  ## 3.13.14 - 2022-06-03
4
36
 
5
37
  - Double fclose() due to bad merger fixed by tonobo.
data/README.md CHANGED
@@ -109,6 +109,8 @@ Follow [@peterohler on Twitter](http://twitter.com/peterohler) for announcements
109
109
 
110
110
  - *Agoo-C, a high performance C web server supporting GraphQL on GitHub*: https://github.com/ohler55/agoo-c
111
111
 
112
+ - *oj-introspect, an example of creating an Oj parser extension in C*: https://github.com/meinac/oj-introspect
113
+
112
114
  #### Contributing
113
115
 
114
116
  + Provide a Pull Request off the `develop` branch.
data/ext/oj/buf.h CHANGED
@@ -39,6 +39,10 @@ inline static const char *buf_str(Buf buf) {
39
39
  }
40
40
 
41
41
  inline static void buf_append_string(Buf buf, const char *s, size_t slen) {
42
+ if (0 == slen) {
43
+ return;
44
+ }
45
+
42
46
  if (buf->end <= buf->tail + slen) {
43
47
  size_t len = buf->end - buf->head;
44
48
  size_t toff = buf->tail - buf->head;
data/ext/oj/compat.c CHANGED
@@ -54,7 +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 (Yes == pi->options.trace) {
57
+ if (RB_UNLIKELY(Yes == pi->options.trace)) {
58
58
  oj_trace_parse_call("set_string", pi, __FILE__, __LINE__, rstr);
59
59
  }
60
60
  }
@@ -68,7 +68,7 @@ static VALUE start_hash(ParseInfo pi) {
68
68
  } else {
69
69
  h = rb_hash_new();
70
70
  }
71
- if (Yes == pi->options.trace) {
71
+ if (RB_UNLIKELY(Yes == pi->options.trace)) {
72
72
  oj_trace_parse_in("start_hash", pi, __FILE__, __LINE__);
73
73
  }
74
74
  return h;
@@ -93,7 +93,7 @@ static void end_hash(struct _parseInfo *pi) {
93
93
  parent->classname = 0;
94
94
  }
95
95
  }
96
- if (Yes == pi->options.trace) {
96
+ if (RB_UNLIKELY(Yes == pi->options.trace)) {
97
97
  oj_trace_parse_hash_end(pi, __FILE__, __LINE__);
98
98
  }
99
99
  }
@@ -110,14 +110,14 @@ static void add_cstr(ParseInfo pi, const char *str, size_t len, const char *orig
110
110
  }
111
111
  }
112
112
  pi->stack.head->val = rstr;
113
- if (Yes == pi->options.trace) {
113
+ if (RB_UNLIKELY(Yes == pi->options.trace)) {
114
114
  oj_trace_parse_call("add_string", pi, __FILE__, __LINE__, rstr);
115
115
  }
116
116
  }
117
117
 
118
118
  static void add_num(ParseInfo pi, NumInfo ni) {
119
119
  pi->stack.head->val = oj_num_as_value(ni);
120
- if (Yes == pi->options.trace) {
120
+ if (RB_UNLIKELY(Yes == pi->options.trace)) {
121
121
  oj_trace_parse_call("add_number", pi, __FILE__, __LINE__, pi->stack.head->val);
122
122
  }
123
123
  }
@@ -138,7 +138,7 @@ static void hash_set_num(struct _parseInfo *pi, Val parent, NumInfo ni) {
138
138
  } else {
139
139
  rb_hash_aset(stack_peek(&pi->stack)->val, oj_calc_hash_key(pi, parent), rval);
140
140
  }
141
- if (Yes == pi->options.trace) {
141
+ if (RB_UNLIKELY(Yes == pi->options.trace)) {
142
142
  oj_trace_parse_call("set_number", pi, __FILE__, __LINE__, rval);
143
143
  }
144
144
  }
@@ -157,7 +157,7 @@ static void hash_set_value(ParseInfo pi, Val parent, VALUE value) {
157
157
  } else {
158
158
  rb_hash_aset(stack_peek(&pi->stack)->val, oj_calc_hash_key(pi, parent), value);
159
159
  }
160
- if (Yes == pi->options.trace) {
160
+ if (RB_UNLIKELY(Yes == pi->options.trace)) {
161
161
  oj_trace_parse_call("set_value", pi, __FILE__, __LINE__, value);
162
162
  }
163
163
  }
@@ -166,7 +166,7 @@ static VALUE start_array(ParseInfo pi) {
166
166
  if (Qnil != pi->options.array_class) {
167
167
  return rb_class_new_instance(0, NULL, pi->options.array_class);
168
168
  }
169
- if (Yes == pi->options.trace) {
169
+ if (RB_UNLIKELY(Yes == pi->options.trace)) {
170
170
  oj_trace_parse_in("start_array", pi, __FILE__, __LINE__);
171
171
  }
172
172
  return rb_ary_new();
@@ -184,7 +184,7 @@ static void array_append_num(ParseInfo pi, NumInfo ni) {
184
184
  } else {
185
185
  rb_ary_push(parent->val, rval);
186
186
  }
187
- if (Yes == pi->options.trace) {
187
+ if (RB_UNLIKELY(Yes == pi->options.trace)) {
188
188
  oj_trace_parse_call("append_number", pi, __FILE__, __LINE__, rval);
189
189
  }
190
190
  }
@@ -201,7 +201,7 @@ static void array_append_cstr(ParseInfo pi, const char *str, size_t len, const c
201
201
  }
202
202
  }
203
203
  rb_ary_push(stack_peek(&pi->stack)->val, rstr);
204
- if (Yes == pi->options.trace) {
204
+ if (RB_UNLIKELY(Yes == pi->options.trace)) {
205
205
  oj_trace_parse_call("append_string", pi, __FILE__, __LINE__, rstr);
206
206
  }
207
207
  }
data/ext/oj/custom.c CHANGED
@@ -31,14 +31,14 @@ static void dump_obj_str(VALUE obj, int depth, Out out) {
31
31
 
32
32
  static void dump_obj_as_str(VALUE obj, int depth, Out out) {
33
33
  volatile VALUE rstr = rb_funcall(obj, oj_to_s_id, 0);
34
- const char * str = RSTRING_PTR(rstr);
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
40
  volatile VALUE rstr = rb_funcall(obj, oj_to_s_id, 0);
41
- const char * str = RSTRING_PTR(rstr);
41
+ const char *str = RSTRING_PTR(rstr);
42
42
  int len = (int)RSTRING_LEN(rstr);
43
43
 
44
44
  if (0 == strcasecmp("Infinity", str)) {
@@ -82,8 +82,7 @@ static VALUE complex_load(VALUE clas, VALUE args) {
82
82
  real_id = rb_intern("real");
83
83
  imag_id = rb_intern("imag");
84
84
  }
85
- return rb_complex_new(rb_hash_aref(args, rb_id2str(real_id)),
86
- rb_hash_aref(args, rb_id2str(imag_id)));
85
+ return rb_complex_new(rb_hash_aref(args, rb_id2str(real_id)), rb_hash_aref(args, rb_id2str(imag_id)));
87
86
  }
88
87
 
89
88
  static void time_dump(VALUE obj, int depth, Out out) {
@@ -246,8 +245,7 @@ static VALUE rational_load(VALUE clas, VALUE args) {
246
245
  numerator_id = rb_intern("numerator");
247
246
  denominator_id = rb_intern("denominator");
248
247
  }
249
- return rb_rational_new(rb_hash_aref(args, rb_id2str(numerator_id)),
250
- rb_hash_aref(args, rb_id2str(denominator_id)));
248
+ return rb_rational_new(rb_hash_aref(args, rb_id2str(numerator_id)), rb_hash_aref(args, rb_id2str(denominator_id)));
251
249
  }
252
250
 
253
251
  static VALUE regexp_load(VALUE clas, VALUE args) {
@@ -292,8 +290,7 @@ static int hash_cb(VALUE key, VALUE value, VALUE ov) {
292
290
  assure_size(out, depth * out->indent + 1);
293
291
  fill_indent(out, depth);
294
292
  } else {
295
- assure_size(out,
296
- depth * out->opts->dump_opts.indent_size + out->opts->dump_opts.hash_size + 1);
293
+ assure_size(out, depth * out->opts->dump_opts.indent_size + out->opts->dump_opts.hash_size + 1);
297
294
  if (0 < out->opts->dump_opts.hash_size) {
298
295
  APPEND_CHARS(out->cur, out->opts->dump_opts.hash_nl, out->opts->dump_opts.hash_size);
299
296
  }
@@ -352,9 +349,7 @@ static void dump_hash(VALUE obj, int depth, Out out, bool as_ok) {
352
349
  assure_size(out, depth * out->indent + 2);
353
350
  fill_indent(out, depth);
354
351
  } else {
355
- assure_size(
356
- out,
357
- depth * out->opts->dump_opts.indent_size + out->opts->dump_opts.hash_size + 1);
352
+ assure_size(out, depth * out->opts->dump_opts.indent_size + out->opts->dump_opts.hash_size + 1);
358
353
  if (0 < out->opts->dump_opts.hash_size) {
359
354
  APPEND_CHARS(out->cur, out->opts->dump_opts.hash_nl, out->opts->dump_opts.hash_size);
360
355
  }
@@ -372,10 +367,10 @@ static void dump_hash(VALUE obj, int depth, Out out, bool as_ok) {
372
367
  }
373
368
 
374
369
  static void dump_odd(VALUE obj, Odd odd, VALUE clas, int depth, Out out) {
375
- ID * idp;
376
- AttrGetFunc * fp;
370
+ ID *idp;
371
+ AttrGetFunc *fp;
377
372
  volatile VALUE v;
378
- const char * name;
373
+ const char *name;
379
374
  size_t size;
380
375
  int d2 = depth + 1;
381
376
 
@@ -384,7 +379,7 @@ static void dump_odd(VALUE obj, Odd odd, VALUE clas, int depth, Out out) {
384
379
  if (NULL != out->opts->create_id && Yes == out->opts->create_ok) {
385
380
  const char *classname = rb_class2name(clas);
386
381
  int clen = (int)strlen(classname);
387
- size_t sep_len = out->opts->dump_opts.before_size + out->opts->dump_opts.after_size + 2;
382
+ size_t sep_len = out->opts->dump_opts.before_size + out->opts->dump_opts.after_size + 2;
388
383
 
389
384
  size = d2 * out->indent + 10 + clen + out->opts->create_id_len + sep_len;
390
385
  assure_size(out, size);
@@ -481,10 +476,10 @@ static VALUE dump_common(VALUE obj, int depth, Out out) {
481
476
  oj_dump_raw_json(obj, depth, out);
482
477
  } else if (Yes == out->opts->to_json && rb_respond_to(obj, oj_to_json_id)) {
483
478
  volatile VALUE rs;
484
- const char * s;
479
+ const char *s;
485
480
  int len;
486
481
 
487
- if (Yes == out->opts->trace) {
482
+ if (RB_UNLIKELY(Yes == out->opts->trace)) {
488
483
  oj_trace("to_json", obj, __FILE__, __LINE__, depth + 1, TraceRubyIn);
489
484
  }
490
485
  if (0 == rb_obj_method_arity(obj, oj_to_json_id)) {
@@ -492,7 +487,7 @@ static VALUE dump_common(VALUE obj, int depth, Out out) {
492
487
  } else {
493
488
  rs = rb_funcall2(obj, oj_to_json_id, out->argc, out->argv);
494
489
  }
495
- if (Yes == out->opts->trace) {
490
+ if (RB_UNLIKELY(Yes == out->opts->trace)) {
496
491
  oj_trace("to_json", obj, __FILE__, __LINE__, depth + 1, TraceRubyOut);
497
492
  }
498
493
  s = RSTRING_PTR(rs);
@@ -504,7 +499,7 @@ static VALUE dump_common(VALUE obj, int depth, Out out) {
504
499
  } else if (Yes == out->opts->as_json && rb_respond_to(obj, oj_as_json_id)) {
505
500
  volatile VALUE aj;
506
501
 
507
- if (Yes == out->opts->trace) {
502
+ if (RB_UNLIKELY(Yes == out->opts->trace)) {
508
503
  oj_trace("as_json", obj, __FILE__, __LINE__, depth + 1, TraceRubyIn);
509
504
  }
510
505
  // Some classes elect to not take an options argument so check the arity
@@ -514,18 +509,14 @@ static VALUE dump_common(VALUE obj, int depth, Out out) {
514
509
  } else {
515
510
  aj = rb_funcall2(obj, oj_as_json_id, out->argc, out->argv);
516
511
  }
517
- if (Yes == out->opts->trace) {
512
+ if (RB_UNLIKELY(Yes == out->opts->trace)) {
518
513
  oj_trace("as_json", obj, __FILE__, __LINE__, depth + 1, TraceRubyOut);
519
514
  }
520
515
  // Catch the obvious brain damaged recursive dumping.
521
516
  if (aj == obj) {
522
517
  volatile VALUE rstr = rb_funcall(obj, oj_to_s_id, 0);
523
518
 
524
- oj_dump_cstr(RSTRING_PTR(rstr),
525
- (int)RSTRING_LEN(rstr),
526
- false,
527
- false,
528
- out);
519
+ oj_dump_cstr(RSTRING_PTR(rstr), (int)RSTRING_LEN(rstr), false, false, out);
529
520
  } else {
530
521
  oj_dump_custom_val(aj, depth, out, true);
531
522
  }
@@ -609,7 +600,7 @@ static void dump_obj_attrs(VALUE obj, VALUE clas, slot_t id, int depth, Out out)
609
600
  assure_size(out, 2);
610
601
  *out->cur++ = '{';
611
602
  if (Qundef != clas && NULL != out->opts->create_id && Yes == out->opts->create_ok) {
612
- size_t sep_len = out->opts->dump_opts.before_size + out->opts->dump_opts.after_size + 2;
603
+ size_t sep_len = out->opts->dump_opts.before_size + out->opts->dump_opts.after_size + 2;
613
604
  const char *classname = rb_obj_classname(obj);
614
605
  size_t len = strlen(classname);
615
606
 
@@ -885,7 +876,7 @@ static DumpFunc custom_funcs[] = {
885
876
  void oj_dump_custom_val(VALUE obj, int depth, Out out, bool as_ok) {
886
877
  int type = rb_type(obj);
887
878
 
888
- if (Yes == out->opts->trace) {
879
+ if (RB_UNLIKELY(Yes == out->opts->trace)) {
889
880
  oj_trace("dump", obj, __FILE__, __LINE__, depth, TraceIn);
890
881
  }
891
882
  if (MAX_DEPTH < depth) {
@@ -896,14 +887,14 @@ void oj_dump_custom_val(VALUE obj, int depth, Out out, bool as_ok) {
896
887
 
897
888
  if (NULL != f) {
898
889
  f(obj, depth, out, true);
899
- if (Yes == out->opts->trace) {
890
+ if (RB_UNLIKELY(Yes == out->opts->trace)) {
900
891
  oj_trace("dump", obj, __FILE__, __LINE__, depth, TraceOut);
901
892
  }
902
893
  return;
903
894
  }
904
895
  }
905
896
  oj_dump_nil(Qnil, depth, out, false);
906
- if (Yes == out->opts->trace) {
897
+ if (RB_UNLIKELY(Yes == out->opts->trace)) {
907
898
  oj_trace("dump", Qnil, __FILE__, __LINE__, depth, TraceOut);
908
899
  }
909
900
  }
@@ -911,7 +902,7 @@ void oj_dump_custom_val(VALUE obj, int depth, Out out, bool as_ok) {
911
902
  ///// load functions /////
912
903
 
913
904
  static void hash_set_cstr(ParseInfo pi, Val kval, const char *str, size_t len, const char *orig) {
914
- const char * key = kval->key;
905
+ const char *key = kval->key;
915
906
  int klen = kval->klen;
916
907
  Val parent = stack_peek(&pi->stack);
917
908
  volatile VALUE rkey = kval->key_val;
@@ -928,14 +919,14 @@ static void hash_set_cstr(ParseInfo pi, Val kval, const char *str, size_t len, c
928
919
  }
929
920
  }
930
921
  } else {
931
- volatile VALUE rstr = oj_cstr_to_value(str, len, (size_t)pi->options.cache_str);
932
- //volatile VALUE rstr = rb_utf8_str_new(str, len);
922
+ volatile VALUE rstr = oj_cstr_to_value(str, len, (size_t)pi->options.cache_str);
923
+ // volatile VALUE rstr = rb_utf8_str_new(str, len);
933
924
 
934
925
  if (Qundef == rkey) {
935
926
  if (Yes == pi->options.sym_key) {
936
927
  rkey = ID2SYM(rb_intern3(key, klen, oj_utf8_encoding));
937
928
  } else {
938
- rkey = rb_utf8_str_new(key, klen);
929
+ rkey = rb_utf8_str_new(key, klen);
939
930
  }
940
931
  }
941
932
  if (Yes == pi->options.create_ok && NULL != pi->options.str_rx.head) {
@@ -959,7 +950,7 @@ static void hash_set_cstr(ParseInfo pi, Val kval, const char *str, size_t len, c
959
950
  break;
960
951
  default: break;
961
952
  }
962
- if (Yes == pi->options.trace) {
953
+ if (RB_UNLIKELY(Yes == pi->options.trace)) {
963
954
  oj_trace_parse_call("set_string", pi, __FILE__, __LINE__, rstr);
964
955
  }
965
956
  }
@@ -978,7 +969,7 @@ static void end_hash(struct _parseInfo *pi) {
978
969
  }
979
970
  parent->clas = Qundef;
980
971
  }
981
- if (Yes == pi->options.trace) {
972
+ if (RB_UNLIKELY(Yes == pi->options.trace)) {
982
973
  oj_trace_parse_hash_end(pi, __FILE__, __LINE__);
983
974
  }
984
975
  }
@@ -1008,20 +999,10 @@ static void hash_set_num(struct _parseInfo *pi, Val kval, NumInfo ni) {
1008
999
  // match the expected value.
1009
1000
  parent->val = rb_funcall2(parent->val, oj_utc_id, 0, 0);
1010
1001
  } else if (ni->has_exp) {
1011
- int64_t t = (int64_t)(ni->i + ni->exp);
1012
- struct _timeInfo ti;
1013
- VALUE args[8];
1014
-
1015
- sec_as_time(t, &ti);
1016
-
1017
- args[0] = LONG2NUM(ti.year);
1018
- args[1] = LONG2NUM(ti.mon);
1019
- args[2] = LONG2NUM(ti.day);
1020
- args[3] = LONG2NUM(ti.hour);
1021
- args[4] = LONG2NUM(ti.min);
1022
- args[5] = rb_float_new((double)ti.sec + ((double)nsec + 0.5) / 1000000000.0);
1023
- args[6] = LONG2NUM(ni->exp);
1024
- parent->val = rb_funcall2(rb_cTime, oj_new_id, 7, args);
1002
+ struct timespec ts;
1003
+ ts.tv_sec = ni->i;
1004
+ ts.tv_nsec = nsec;
1005
+ parent->val = rb_time_timespec_new(&ts, (int)ni->exp);
1025
1006
  } else {
1026
1007
  parent->val = rb_time_nano_new(ni->i, (long)nsec);
1027
1008
  }
@@ -1032,7 +1013,7 @@ static void hash_set_num(struct _parseInfo *pi, Val kval, NumInfo ni) {
1032
1013
  break;
1033
1014
  default: break;
1034
1015
  }
1035
- if (Yes == pi->options.trace) {
1016
+ if (RB_UNLIKELY(Yes == pi->options.trace)) {
1036
1017
  oj_trace_parse_call("set_string", pi, __FILE__, __LINE__, rval);
1037
1018
  }
1038
1019
  }
@@ -1045,7 +1026,7 @@ static void hash_set_value(ParseInfo pi, Val kval, VALUE value) {
1045
1026
  case T_HASH: rb_hash_aset(parent->val, oj_calc_hash_key(pi, kval), value); break;
1046
1027
  default: break;
1047
1028
  }
1048
- if (Yes == pi->options.trace) {
1029
+ if (RB_UNLIKELY(Yes == pi->options.trace)) {
1049
1030
  oj_trace_parse_call("set_value", pi, __FILE__, __LINE__, value);
1050
1031
  }
1051
1032
  }
@@ -1055,7 +1036,7 @@ static void array_append_num(ParseInfo pi, NumInfo ni) {
1055
1036
  volatile VALUE rval = oj_num_as_value(ni);
1056
1037
 
1057
1038
  rb_ary_push(parent->val, rval);
1058
- if (Yes == pi->options.trace) {
1039
+ if (RB_UNLIKELY(Yes == pi->options.trace)) {
1059
1040
  oj_trace_parse_call("append_number", pi, __FILE__, __LINE__, rval);
1060
1041
  }
1061
1042
  }
@@ -1072,7 +1053,7 @@ static void array_append_cstr(ParseInfo pi, const char *str, size_t len, const c
1072
1053
  }
1073
1054
  }
1074
1055
  rb_ary_push(stack_peek(&pi->stack)->val, rstr);
1075
- if (Yes == pi->options.trace) {
1056
+ if (RB_UNLIKELY(Yes == pi->options.trace)) {
1076
1057
  oj_trace_parse_call("append_string", pi, __FILE__, __LINE__, rstr);
1077
1058
  }
1078
1059
  }
data/ext/oj/dump.c CHANGED
@@ -32,6 +32,7 @@ static const char nan_val[] = NAN_VAL;
32
32
  typedef unsigned long ulong;
33
33
 
34
34
  static size_t hibit_friendly_size(const uint8_t *str, size_t len);
35
+ static size_t slash_friendly_size(const uint8_t *str, size_t len);
35
36
  static size_t xss_friendly_size(const uint8_t *str, size_t len);
36
37
  static size_t ascii_friendly_size(const uint8_t *str, size_t len);
37
38
 
@@ -59,6 +60,17 @@ static char hibit_friendly_chars[256] = "\
59
60
  11111111111111111111111111111111\
60
61
  11111111111111111111111111111111";
61
62
 
63
+ // JSON standard but escape forward slashes `/`
64
+ static char slash_friendly_chars[256] = "\
65
+ 66666666222622666666666666666666\
66
+ 11211111111111121111111111111111\
67
+ 11111111111111111111111111112111\
68
+ 11111111111111111111111111111111\
69
+ 11111111111111111111111111111111\
70
+ 11111111111111111111111111111111\
71
+ 11111111111111111111111111111111\
72
+ 11111111111111111111111111111111";
73
+
62
74
  // High bit set characters are always encoded as unicode. Worse case is 3
63
75
  // bytes per character in the output. That makes this conservative.
64
76
  static char ascii_friendly_chars[256] = "\
@@ -143,6 +155,10 @@ inline static size_t hibit_friendly_size(const uint8_t *str, size_t len) {
143
155
  return calculate_string_size(str, len, hibit_friendly_chars);
144
156
  }
145
157
 
158
+ inline static size_t slash_friendly_size(const uint8_t *str, size_t len) {
159
+ return calculate_string_size(str, len, slash_friendly_chars);
160
+ }
161
+
146
162
  inline static size_t ascii_friendly_size(const uint8_t *str, size_t len) {
147
163
  return calculate_string_size(str, len, ascii_friendly_chars);
148
164
  }
@@ -365,7 +381,6 @@ void oj_dump_time(VALUE obj, Out out, int withZone) {
365
381
  long long sec;
366
382
  long long nsec;
367
383
 
368
- #ifdef HAVE_RB_TIME_TIMESPEC
369
384
  // rb_time_timespec as well as rb_time_timeeval have a bug that causes an
370
385
  // exception to be raised if a time is before 1970 on 32 bit systems so
371
386
  // check the timespec size and use the ruby calls if a 32 bit system.
@@ -378,10 +393,6 @@ void oj_dump_time(VALUE obj, Out out, int withZone) {
378
393
  sec = NUM2LL(rb_funcall2(obj, oj_tv_sec_id, 0, 0));
379
394
  nsec = NUM2LL(rb_funcall2(obj, oj_tv_nsec_id, 0, 0));
380
395
  }
381
- #else
382
- sec = NUM2LL(rb_funcall2(obj, oj_tv_sec_id, 0, 0));
383
- nsec = NUM2LL(rb_funcall2(obj, oj_tv_nsec_id, 0, 0));
384
- #endif
385
396
 
386
397
  *b-- = '\0';
387
398
  if (withZone) {
@@ -467,7 +478,6 @@ void oj_dump_xml_time(VALUE obj, Out out) {
467
478
  int tzhour, tzmin;
468
479
  char tzsign = '+';
469
480
 
470
- #ifdef HAVE_RB_TIME_TIMESPEC
471
481
  if (16 <= sizeof(struct timespec)) {
472
482
  struct timespec ts = rb_time_timespec(obj);
473
483
 
@@ -477,10 +487,6 @@ void oj_dump_xml_time(VALUE obj, Out out) {
477
487
  sec = NUM2LL(rb_funcall2(obj, oj_tv_sec_id, 0, 0));
478
488
  nsec = NUM2LL(rb_funcall2(obj, oj_tv_nsec_id, 0, 0));
479
489
  }
480
- #else
481
- sec = NUM2LL(rb_funcall2(obj, oj_tv_sec_id, 0, 0));
482
- nsec = NUM2LL(rb_funcall2(obj, oj_tv_nsec_id, 0, 0));
483
- #endif
484
490
 
485
491
  assure_size(out, 36);
486
492
  if (9 > out->opts->sec_prec) {
@@ -730,11 +736,11 @@ void oj_dump_raw_json(VALUE obj, int depth, Out out) {
730
736
  } else {
731
737
  volatile VALUE jv;
732
738
 
733
- if (Yes == out->opts->trace) {
739
+ if (RB_UNLIKELY(Yes == out->opts->trace)) {
734
740
  oj_trace("raw_json", obj, __FILE__, __LINE__, depth + 1, TraceRubyIn);
735
741
  }
736
742
  jv = rb_funcall(obj, oj_raw_json_id, 2, RB_INT2NUM(depth), RB_INT2NUM(out->indent));
737
- if (Yes == out->opts->trace) {
743
+ if (RB_UNLIKELY(Yes == out->opts->trace)) {
738
744
  oj_trace("raw_json", obj, __FILE__, __LINE__, depth + 1, TraceRubyOut);
739
745
  }
740
746
  oj_dump_raw(RSTRING_PTR(jv), (size_t)RSTRING_LEN(jv), out);
@@ -756,6 +762,11 @@ void oj_dump_cstr(const char *str, size_t cnt, bool is_sym, bool escape1, Out ou
756
762
  cmap = ascii_friendly_chars;
757
763
  size = ascii_friendly_size((uint8_t *)str, cnt);
758
764
  break;
765
+ case SlashEsc:
766
+ has_hi = true;
767
+ cmap = slash_friendly_chars;
768
+ size = slash_friendly_size((uint8_t *)str, cnt);
769
+ break;
759
770
  case XSSEsc:
760
771
  cmap = xss_friendly_chars;
761
772
  size = xss_friendly_size((uint8_t *)str, cnt);
@@ -1130,7 +1141,7 @@ void oj_dump_float(VALUE obj, int depth, Out out, bool as_ok) {
1130
1141
  } else if (isnan(d)) {
1131
1142
  if (ObjectMode == out->opts->mode) {
1132
1143
  strcpy(buf, nan_val);
1133
- cnt = sizeof(ninf_val) - 1;
1144
+ cnt = sizeof(nan_val) - 1;
1134
1145
  } else {
1135
1146
  NanDump nd = out->opts->dump_opts.nan_dump;
1136
1147
 
data/ext/oj/dump_compat.c CHANGED
@@ -109,7 +109,7 @@ dump_to_json(VALUE obj, Out out) {
109
109
  const char *s;
110
110
  int len;
111
111
 
112
- if (Yes == out->opts->trace) {
112
+ if (RB_UNLIKELY(Yes == out->opts->trace)) {
113
113
  oj_trace("to_json", obj, __FILE__, __LINE__, 0, TraceRubyIn);
114
114
  }
115
115
  if (0 == rb_obj_method_arity(obj, oj_to_json_id)) {
@@ -117,7 +117,7 @@ dump_to_json(VALUE obj, Out out) {
117
117
  } else {
118
118
  rs = rb_funcall2(obj, oj_to_json_id, out->argc, out->argv);
119
119
  }
120
- if (Yes == out->opts->trace) {
120
+ if (RB_UNLIKELY(Yes == out->opts->trace)) {
121
121
  oj_trace("to_json", obj, __FILE__, __LINE__, 0, TraceRubyOut);
122
122
  }
123
123
 
@@ -444,7 +444,6 @@ time_alt(VALUE obj, int depth, Out out) {
444
444
  time_t sec;
445
445
  long long nsec;
446
446
 
447
- #ifdef HAVE_RB_TIME_TIMESPEC
448
447
  if (16 <= sizeof(struct timespec)) {
449
448
  struct timespec ts = rb_time_timespec(obj);
450
449
 
@@ -454,10 +453,6 @@ time_alt(VALUE obj, int depth, Out out) {
454
453
  sec = NUM2LL(rb_funcall2(obj, oj_tv_sec_id, 0, 0));
455
454
  nsec = NUM2LL(rb_funcall2(obj, oj_tv_nsec_id, 0, 0));
456
455
  }
457
- #else
458
- sec = NUM2LL(rb_funcall2(obj, oj_tv_sec_id, 0, 0));
459
- nsec = NUM2LL(rb_funcall2(obj, oj_tv_nsec_id, 0, 0));
460
- #endif
461
456
 
462
457
  attrs[0].num = sec;
463
458
  attrs[1].num = nsec;
@@ -898,7 +893,7 @@ void
898
893
  oj_dump_compat_val(VALUE obj, int depth, Out out, bool as_ok) {
899
894
  int type = rb_type(obj);
900
895
 
901
- if (Yes == out->opts->trace) {
896
+ if (RB_UNLIKELY(Yes == out->opts->trace)) {
902
897
  oj_trace("dump", obj, __FILE__, __LINE__, depth, TraceIn);
903
898
  }
904
899
  if (out->opts->dump_opts.max_depth <= depth) {
@@ -923,14 +918,14 @@ oj_dump_compat_val(VALUE obj, int depth, Out out, bool as_ok) {
923
918
 
924
919
  if (NULL != f) {
925
920
  f(obj, depth, out, as_ok);
926
- if (Yes == out->opts->trace) {
921
+ if (RB_UNLIKELY(Yes == out->opts->trace)) {
927
922
  oj_trace("dump", obj, __FILE__, __LINE__, depth, TraceOut);
928
923
  }
929
924
  return;
930
925
  }
931
926
  }
932
927
  oj_dump_nil(Qnil, depth, out, false);
933
- if (Yes == out->opts->trace) {
928
+ if (RB_UNLIKELY(Yes == out->opts->trace)) {
934
929
  oj_trace("dump", Qnil, __FILE__, __LINE__, depth, TraceOut);
935
930
  }
936
931
  }