oj 3.13.14 → 3.13.22

Sign up to get free protection for your applications and to get access to all the features.
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
  }