oj 3.13.22 → 3.14.0

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.
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.c CHANGED
@@ -243,7 +243,7 @@ struct _options oj_default_options = {
243
243
  *references
244
244
  * - *:auto_define* [_Boolean_|_nil_] automatically define classes if they do not exist
245
245
  * - *:symbol_keys* [_Boolean_|_nil_] use symbols instead of strings for hash keys
246
- * - *:escape_mode* [_:newline_|_:json_|_:xss_safe_|_:ascii_|_unicode_xss_|_nil_] determines the
246
+ * - *:escape_mode* [_:newline_|_:json_|_:slash_|_:xss_safe_|_:ascii_|_:unicode_xss_|_nil_] determines the
247
247
  *characters to escape
248
248
  * - *:class_cache* [_Boolean_|_nil_] cache classes for faster parsing (if dynamically modifying
249
249
  *classes or reloading classes then don't use this)
@@ -251,7 +251,7 @@ struct _options oj_default_options = {
251
251
  *to use for JSON
252
252
  * - *:time_format* [_:unix_|_:unix_zone_|_:xmlschema_|_:ruby_] time format when dumping
253
253
  * - *:bigdecimal_as_decimal* [_Boolean_|_nil_] dump BigDecimal as a decimal number or as a String
254
- * - *:bigdecimal_load* [_:bigdecimal_|_:float_|_:auto_|_:fast_] load decimals as BigDecimal instead
254
+ * - *:bigdecimal_load* [_:bigdecimal_|_:float_|_:auto_|_:fast_|_:ruby_] load decimals as BigDecimal instead
255
255
  *of as a Float. :auto pick the most precise for the number of digits. :float should be the same as
256
256
  *ruby. :fast may require rounding but is must faster.
257
257
  * - *:compat_bigdecimal* [_true_|_false_] load decimals as BigDecimal instead of as a Float when in
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
@@ -1145,7 +1145,9 @@ static void parser_free(void *ptr) {
1145
1145
  p = (ojParser)ptr;
1146
1146
  buf_cleanup(&p->key);
1147
1147
  buf_cleanup(&p->buf);
1148
- p->free(p);
1148
+ if (NULL != p->free) {
1149
+ p->free(p);
1150
+ }
1149
1151
  xfree(ptr);
1150
1152
  }
1151
1153
 
@@ -1156,7 +1158,9 @@ static void parser_mark(void *ptr) {
1156
1158
  if (0 != p->reader) {
1157
1159
  rb_gc_mark(p->reader);
1158
1160
  }
1159
- p->mark(p);
1161
+ if (NULL != p->mark) {
1162
+ p->mark(p);
1163
+ }
1160
1164
  }
1161
1165
  }
1162
1166
 
@@ -1259,7 +1263,7 @@ static VALUE parser_new(int argc, VALUE *argv, VALUE self) {
1259
1263
  // from this function. A delegate must be added before the parser can be
1260
1264
  // used. Optionally oj_parser_set_options can be called if the options are not
1261
1265
  // set directly.
1262
- VALUE oj_parser_new() {
1266
+ VALUE oj_parser_new(void) {
1263
1267
  ojParser p = ALLOC(struct _ojParser);
1264
1268
 
1265
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.22'
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/pages/Options.md CHANGED
@@ -66,6 +66,10 @@ Determines how to load decimals.
66
66
 
67
67
  - `:auto` the most precise for the number of digits is used.
68
68
 
69
+ - `:fast` faster conversion to Float.
70
+
71
+ - `:ruby` convert to Float using the Ruby `to_f` conversion.
72
+
69
73
  This can also be set with `:decimal_class` when used as a load or
70
74
  parse option to match the JSON gem. In that case either `Float`,
71
75
  `BigDecimal`, or `nil` can be provided.
@@ -154,6 +158,8 @@ Determines the characters to escape when dumping. Only the :ascii and
154
158
 
155
159
  - `:json` follows the JSON specification. This is the default mode.
156
160
 
161
+ - `:slash` escapes `/` characters.
162
+
157
163
  - `:xss_safe` escapes HTML and XML characters such as `&` and `<`.
158
164
 
159
165
  - `:ascii` escapes all non-ascii or characters with the hi-bit set.
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