oj 3.13.11 → 3.13.23

Sign up to get free protection for your applications and to get access to all the features.
Files changed (76) hide show
  1. checksums.yaml +4 -4
  2. data/CHANGELOG.md +50 -0
  3. data/README.md +2 -0
  4. data/ext/oj/buf.h +4 -0
  5. data/ext/oj/circarray.c +1 -1
  6. data/ext/oj/code.c +15 -22
  7. data/ext/oj/compat.c +10 -10
  8. data/ext/oj/custom.c +62 -108
  9. data/ext/oj/dump.c +85 -97
  10. data/ext/oj/dump.h +12 -8
  11. data/ext/oj/dump_compat.c +46 -88
  12. data/ext/oj/dump_leaf.c +14 -58
  13. data/ext/oj/dump_object.c +33 -156
  14. data/ext/oj/dump_strict.c +17 -29
  15. data/ext/oj/extconf.rb +5 -4
  16. data/ext/oj/fast.c +24 -22
  17. data/ext/oj/intern.c +15 -11
  18. data/ext/oj/intern.h +1 -1
  19. data/ext/oj/mimic_json.c +44 -32
  20. data/ext/oj/object.c +42 -41
  21. data/ext/oj/odd.c +83 -63
  22. data/ext/oj/odd.h +13 -13
  23. data/ext/oj/oj.c +57 -22
  24. data/ext/oj/oj.h +24 -3
  25. data/ext/oj/parse.c +114 -78
  26. data/ext/oj/parse.h +2 -0
  27. data/ext/oj/parser.c +77 -21
  28. data/ext/oj/parser.h +12 -0
  29. data/ext/oj/rails.c +41 -65
  30. data/ext/oj/rails.h +1 -1
  31. data/ext/oj/reader.c +2 -0
  32. data/ext/oj/saj.c +11 -23
  33. data/ext/oj/saj2.c +333 -85
  34. data/ext/oj/saj2.h +23 -0
  35. data/ext/oj/sparse.c +4 -0
  36. data/ext/oj/stream_writer.c +3 -1
  37. data/ext/oj/strict.c +13 -13
  38. data/ext/oj/string_writer.c +12 -5
  39. data/ext/oj/usual.c +82 -129
  40. data/ext/oj/usual.h +68 -0
  41. data/ext/oj/val_stack.c +1 -1
  42. data/ext/oj/validate.c +21 -26
  43. data/ext/oj/wab.c +21 -26
  44. data/lib/oj/saj.rb +20 -6
  45. data/lib/oj/state.rb +1 -1
  46. data/lib/oj/version.rb +1 -1
  47. data/pages/Compatibility.md +1 -1
  48. data/pages/Options.md +6 -0
  49. data/test/activesupport7/abstract_unit.rb +49 -0
  50. data/test/activesupport7/decoding_test.rb +125 -0
  51. data/test/activesupport7/encoding_test.rb +486 -0
  52. data/test/activesupport7/encoding_test_cases.rb +104 -0
  53. data/test/activesupport7/time_zone_test_helpers.rb +47 -0
  54. data/test/bar.rb +3 -8
  55. data/test/foo.rb +3 -3
  56. data/test/helper.rb +8 -2
  57. data/test/json_gem/json_generator_test.rb +5 -4
  58. data/test/json_gem/json_parser_test.rb +8 -1
  59. data/test/json_gem/test_helper.rb +7 -3
  60. data/test/perf_dump.rb +50 -0
  61. data/test/test_compat.rb +25 -0
  62. data/test/test_custom.rb +13 -2
  63. data/test/test_file.rb +23 -7
  64. data/test/test_gc.rb +11 -0
  65. data/test/test_object.rb +8 -10
  66. data/test/test_parser.rb +3 -19
  67. data/test/test_parser_debug.rb +27 -0
  68. data/test/test_parser_saj.rb +92 -2
  69. data/test/test_scp.rb +2 -4
  70. data/test/test_strict.rb +2 -0
  71. data/test/test_various.rb +8 -3
  72. data/test/test_wab.rb +2 -0
  73. data/test/tests.rb +9 -0
  74. data/test/tests_mimic.rb +9 -0
  75. data/test/tests_mimic_addition.rb +9 -0
  76. metadata +13 -116
data/ext/oj/odd.c CHANGED
@@ -5,28 +5,27 @@
5
5
 
6
6
  #include <string.h>
7
7
 
8
- static struct _odd _odds[4]; // bump up if new initial Odd classes are added
9
- static struct _odd *odds = _odds;
10
- static long odd_cnt = 0;
11
- static ID sec_id;
12
- static ID sec_fraction_id;
13
- static ID to_f_id;
14
- static ID numerator_id;
15
- static ID denominator_id;
16
- static ID rational_id;
17
- static VALUE rational_class;
8
+ static Odd odds = NULL;
9
+ static ID sec_id;
10
+ static ID sec_fraction_id;
11
+ static ID to_f_id;
12
+ static ID numerator_id;
13
+ static ID denominator_id;
14
+ static ID rational_id;
18
15
 
19
16
  static void set_class(Odd odd, const char *classname) {
20
17
  const char **np;
21
- ID * idp;
18
+ ID *idp;
22
19
 
23
- odd->classname = classname;
24
- odd->clen = strlen(classname);
25
- odd->clas = rb_const_get(rb_cObject, rb_intern(classname));
20
+ odd->classname = classname;
21
+ odd->clen = strlen(classname);
22
+ odd->clas = rb_const_get(rb_cObject, rb_intern(classname));
23
+ rb_gc_register_mark_object(odd->clas);
26
24
  odd->create_obj = odd->clas;
27
- odd->create_op = rb_intern("new");
28
- odd->is_module = (T_MODULE == rb_type(odd->clas));
29
- odd->raw = 0;
25
+ rb_gc_register_mark_object(odd->create_obj);
26
+ odd->create_op = rb_intern("new");
27
+ odd->is_module = (T_MODULE == rb_type(odd->clas));
28
+ odd->raw = 0;
30
29
  for (np = odd->attr_names, idp = odd->attrs; 0 != *np; np++, idp++) {
31
30
  *idp = rb_intern(*np);
32
31
  }
@@ -37,15 +36,48 @@ static VALUE get_datetime_secs(VALUE obj) {
37
36
  volatile VALUE rsecs = rb_funcall(obj, sec_id, 0);
38
37
  volatile VALUE rfrac = rb_funcall(obj, sec_fraction_id, 0);
39
38
  long sec = NUM2LONG(rsecs);
40
- long long num = rb_num2ll(rb_funcall(rfrac, numerator_id, 0));
41
- long long den = rb_num2ll(rb_funcall(rfrac, denominator_id, 0));
39
+ long long num = NUM2LL(rb_funcall(rfrac, numerator_id, 0));
40
+ long long den = NUM2LL(rb_funcall(rfrac, denominator_id, 0));
42
41
 
43
42
  num += sec * den;
44
43
 
45
44
  return rb_funcall(rb_cObject, rational_id, 2, rb_ll2inum(num), rb_ll2inum(den));
46
45
  }
47
46
 
48
- void oj_odd_init() {
47
+ static void print_odd(Odd odd) {
48
+ const char **np;
49
+ int i;
50
+
51
+ printf(" %s {\n", odd->classname);
52
+ printf(" attr_cnt: %d %p\n", odd->attr_cnt, (void *)odd->attr_names);
53
+ printf(" attr_names: %p\n", (void *)*odd->attr_names);
54
+ printf(" attr_names: %c\n", **odd->attr_names);
55
+ for (i = odd->attr_cnt, np = odd->attr_names; 0 < i; i--, np++) {
56
+ printf(" %d %s\n", i, *np);
57
+ }
58
+ printf(" }\n");
59
+ }
60
+
61
+ void print_all_odds(const char *label) {
62
+ Odd odd;
63
+ printf("@ %s {\n", label);
64
+ for (odd = odds; NULL != odd; odd = odd->next) {
65
+ print_odd(odd);
66
+ }
67
+ printf("}\n");
68
+ }
69
+
70
+ static Odd odd_create(void) {
71
+ Odd odd = ALLOC(struct _odd);
72
+
73
+ memset(odd, 0, sizeof(struct _odd));
74
+ odd->next = odds;
75
+ odds = odd;
76
+
77
+ return odd;
78
+ }
79
+
80
+ void oj_odd_init(void) {
49
81
  Odd odd;
50
82
  const char **np;
51
83
 
@@ -55,11 +87,9 @@ void oj_odd_init() {
55
87
  numerator_id = rb_intern("numerator");
56
88
  denominator_id = rb_intern("denominator");
57
89
  rational_id = rb_intern("Rational");
58
- rational_class = rb_const_get(rb_cObject, rational_id);
59
90
 
60
- memset(_odds, 0, sizeof(_odds));
61
- odd = odds;
62
91
  // Rational
92
+ odd = odd_create();
63
93
  np = odd->attr_names;
64
94
  *np++ = "numerator";
65
95
  *np++ = "denominator";
@@ -68,8 +98,9 @@ void oj_odd_init() {
68
98
  odd->create_obj = rb_cObject;
69
99
  odd->create_op = rational_id;
70
100
  odd->attr_cnt = 2;
101
+
71
102
  // Date
72
- odd++;
103
+ odd = odd_create();
73
104
  np = odd->attr_names;
74
105
  *np++ = "year";
75
106
  *np++ = "month";
@@ -78,8 +109,9 @@ void oj_odd_init() {
78
109
  *np++ = 0;
79
110
  set_class(odd, "Date");
80
111
  odd->attr_cnt = 4;
112
+
81
113
  // DateTime
82
- odd++;
114
+ odd = odd_create();
83
115
  np = odd->attr_names;
84
116
  *np++ = "year";
85
117
  *np++ = "month";
@@ -93,8 +125,9 @@ void oj_odd_init() {
93
125
  set_class(odd, "DateTime");
94
126
  odd->attr_cnt = 8;
95
127
  odd->attrFuncs[5] = get_datetime_secs;
128
+
96
129
  // Range
97
- odd++;
130
+ odd = odd_create();
98
131
  np = odd->attr_names;
99
132
  *np++ = "begin";
100
133
  *np++ = "end";
@@ -102,15 +135,13 @@ void oj_odd_init() {
102
135
  *np++ = 0;
103
136
  set_class(odd, "Range");
104
137
  odd->attr_cnt = 3;
105
-
106
- odd_cnt = odd - odds + 1;
107
138
  }
108
139
 
109
140
  Odd oj_get_odd(VALUE clas) {
110
141
  Odd odd;
111
142
  const char *classname = NULL;
112
143
 
113
- for (odd = odds + odd_cnt - 1; odds <= odd; odd--) {
144
+ for (odd = odds; NULL != odd; odd = odd->next) {
114
145
  if (clas == odd->clas) {
115
146
  return odd;
116
147
  }
@@ -129,21 +160,20 @@ Odd oj_get_odd(VALUE clas) {
129
160
  Odd oj_get_oddc(const char *classname, size_t len) {
130
161
  Odd odd;
131
162
 
132
- for (odd = odds + odd_cnt - 1; odds <= odd; odd--) {
163
+ for (odd = odds; NULL != odd; odd = odd->next) {
133
164
  if (len == odd->clen && 0 == strncmp(classname, odd->classname, len)) {
134
165
  return odd;
135
166
  }
136
- if (odd->is_module && 0 == strncmp(odd->classname, classname, odd->clen) &&
137
- ':' == classname[odd->clen]) {
167
+ if (odd->is_module && 0 == strncmp(odd->classname, classname, odd->clen) && ':' == classname[odd->clen]) {
138
168
  return odd;
139
169
  }
140
170
  }
141
- return 0;
171
+ return NULL;
142
172
  }
143
173
 
144
174
  OddArgs oj_odd_alloc_args(Odd odd) {
145
175
  OddArgs oa = ALLOC_N(struct _oddArgs, 1);
146
- VALUE * a;
176
+ VALUE *a;
147
177
  int i;
148
178
 
149
179
  oa->odd = odd;
@@ -159,11 +189,10 @@ void oj_odd_free(OddArgs args) {
159
189
 
160
190
  int oj_odd_set_arg(OddArgs args, const char *key, size_t klen, VALUE value) {
161
191
  const char **np;
162
- VALUE * vp;
192
+ VALUE *vp;
163
193
  int i;
164
194
 
165
- for (i = args->odd->attr_cnt, np = args->odd->attr_names, vp = args->args; 0 < i;
166
- i--, np++, vp++) {
195
+ for (i = args->odd->attr_cnt, np = args->odd->attr_names, vp = args->args; 0 < i; i--, np++, vp++) {
167
196
  if (0 == strncmp(key, *np, klen) && '\0' == *((*np) + klen)) {
168
197
  *vp = value;
169
198
  return 0;
@@ -172,37 +201,26 @@ int oj_odd_set_arg(OddArgs args, const char *key, size_t klen, VALUE value) {
172
201
  return -1;
173
202
  }
174
203
 
175
- void oj_reg_odd(VALUE clas,
176
- VALUE create_object,
177
- VALUE create_method,
178
- int mcnt,
179
- VALUE *members,
180
- bool raw) {
204
+ void oj_reg_odd(VALUE clas, VALUE create_object, VALUE create_method, int mcnt, VALUE *members, bool raw) {
181
205
  Odd odd;
182
206
  const char **np;
183
- ID * ap;
207
+ ID *ap;
184
208
  AttrGetFunc *fp;
185
209
 
186
- if (_odds == odds) {
187
- odds = ALLOC_N(struct _odd, odd_cnt + 1);
188
-
189
- memcpy(odds, _odds, sizeof(struct _odd) * odd_cnt);
190
- } else {
191
- REALLOC_N(odds, struct _odd, odd_cnt + 1);
192
- }
193
- odd = odds + odd_cnt;
210
+ odd = odd_create();
194
211
  odd->clas = clas;
212
+ rb_gc_register_mark_object(odd->clas);
195
213
  if (NULL == (odd->classname = strdup(rb_class2name(clas)))) {
196
- rb_raise(rb_eNoMemError, "for attribute name.");
214
+ rb_raise(rb_eNoMemError, "for class name.");
197
215
  }
198
216
  odd->clen = strlen(odd->classname);
199
217
  odd->create_obj = create_object;
200
- odd->create_op = SYM2ID(create_method);
201
- odd->attr_cnt = mcnt;
202
- odd->is_module = (T_MODULE == rb_type(clas));
203
- odd->raw = raw;
204
- for (ap = odd->attrs, np = odd->attr_names, fp = odd->attrFuncs; 0 < mcnt;
205
- mcnt--, ap++, np++, members++, fp++) {
218
+ rb_gc_register_mark_object(odd->create_obj);
219
+ odd->create_op = SYM2ID(create_method);
220
+ odd->attr_cnt = mcnt;
221
+ odd->is_module = (T_MODULE == rb_type(clas));
222
+ odd->raw = raw;
223
+ for (ap = odd->attrs, np = odd->attr_names, fp = odd->attrFuncs; 0 < mcnt; mcnt--, ap++, np++, members++, fp++) {
206
224
  *fp = 0;
207
225
  switch (rb_type(*members)) {
208
226
  case T_STRING:
@@ -210,14 +228,16 @@ void oj_reg_odd(VALUE clas,
210
228
  rb_raise(rb_eNoMemError, "for attribute name.");
211
229
  }
212
230
  break;
213
- case T_SYMBOL: *np = rb_id2name(SYM2ID(*members)); break;
214
- default:
215
- rb_raise(rb_eArgError, "registered member identifiers must be Strings or Symbols.");
231
+ case T_SYMBOL:
232
+ // The symbol can move and invalidate the name so make a copy.
233
+ if (NULL == (*np = strdup(rb_id2name(SYM2ID(*members))))) {
234
+ rb_raise(rb_eNoMemError, "for attribute name.");
235
+ }
216
236
  break;
237
+ default: rb_raise(rb_eArgError, "registered member identifiers must be Strings or Symbols."); break;
217
238
  }
218
239
  *ap = rb_intern(*np);
219
240
  }
220
241
  *np = 0;
221
242
  *ap = 0;
222
- odd_cnt++;
223
243
  }
data/ext/oj/odd.h CHANGED
@@ -13,17 +13,18 @@
13
13
  typedef VALUE (*AttrGetFunc)(VALUE obj);
14
14
 
15
15
  typedef struct _odd {
16
- const char *classname;
17
- size_t clen;
18
- VALUE clas; // Ruby class or module
19
- VALUE create_obj;
20
- ID create_op;
21
- int attr_cnt;
22
- bool is_module;
23
- bool raw;
24
- const char *attr_names[MAX_ODD_ARGS]; // NULL terminated attr names
25
- ID attrs[MAX_ODD_ARGS]; // 0 terminated attr IDs
26
- AttrGetFunc attrFuncs[MAX_ODD_ARGS];
16
+ struct _odd *next;
17
+ const char * classname;
18
+ size_t clen;
19
+ VALUE clas; // Ruby class or module
20
+ VALUE create_obj;
21
+ ID create_op;
22
+ int attr_cnt;
23
+ bool is_module;
24
+ bool raw;
25
+ const char * attr_names[MAX_ODD_ARGS]; // NULL terminated attr names
26
+ ID attrs[MAX_ODD_ARGS]; // 0 terminated attr IDs
27
+ AttrGetFunc attrFuncs[MAX_ODD_ARGS];
27
28
  } * Odd;
28
29
 
29
30
  typedef struct _oddArgs {
@@ -37,7 +38,6 @@ extern Odd oj_get_oddc(const char *classname, size_t len);
37
38
  extern OddArgs oj_odd_alloc_args(Odd odd);
38
39
  extern void oj_odd_free(OddArgs args);
39
40
  extern int oj_odd_set_arg(OddArgs args, const char *key, size_t klen, VALUE value);
40
- extern void
41
- oj_reg_odd(VALUE clas, VALUE create_object, VALUE create_method, int mcnt, VALUE *members, bool raw);
41
+ extern void oj_reg_odd(VALUE clas, VALUE create_object, VALUE create_method, int mcnt, VALUE *members, bool raw);
42
42
 
43
43
  #endif /* OJ_ODD_H */
data/ext/oj/oj.c CHANGED
@@ -32,6 +32,7 @@ ID oj_array_append_id;
32
32
  ID oj_array_end_id;
33
33
  ID oj_array_start_id;
34
34
  ID oj_as_json_id;
35
+ ID oj_at_id;
35
36
  ID oj_begin_id;
36
37
  ID oj_bigdecimal_id;
37
38
  ID oj_end_id;
@@ -45,7 +46,6 @@ ID oj_hash_key_id;
45
46
  ID oj_hash_set_id;
46
47
  ID oj_hash_start_id;
47
48
  ID oj_iconv_id;
48
- ID oj_instance_variables_id;
49
49
  ID oj_json_create_id;
50
50
  ID oj_length_id;
51
51
  ID oj_new_id;
@@ -90,7 +90,9 @@ VALUE oj_array_class_sym;
90
90
  VALUE oj_create_additions_sym;
91
91
  VALUE oj_decimal_class_sym;
92
92
  VALUE oj_hash_class_sym;
93
+ VALUE oj_in_sym;
93
94
  VALUE oj_indent_sym;
95
+ VALUE oj_nanosecond_sym;
94
96
  VALUE oj_object_class_sym;
95
97
  VALUE oj_quirks_mode_sym;
96
98
  VALUE oj_safe_sym;
@@ -137,6 +139,7 @@ static VALUE rails_sym;
137
139
  static VALUE raise_sym;
138
140
  static VALUE ruby_sym;
139
141
  static VALUE sec_prec_sym;
142
+ static VALUE slash_sym;
140
143
  static VALUE strict_sym;
141
144
  static VALUE symbol_keys_sym;
142
145
  static VALUE time_format_sym;
@@ -153,6 +156,7 @@ static VALUE xmlschema_sym;
153
156
  static VALUE xss_safe_sym;
154
157
 
155
158
  rb_encoding *oj_utf8_encoding = 0;
159
+ int oj_utf8_encoding_index = 0;
156
160
 
157
161
  #ifdef HAVE_PTHREAD_MUTEX_INIT
158
162
  pthread_mutex_t oj_cache_mutex;
@@ -239,7 +243,7 @@ struct _options oj_default_options = {
239
243
  *references
240
244
  * - *:auto_define* [_Boolean_|_nil_] automatically define classes if they do not exist
241
245
  * - *:symbol_keys* [_Boolean_|_nil_] use symbols instead of strings for hash keys
242
- * - *: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
243
247
  *characters to escape
244
248
  * - *:class_cache* [_Boolean_|_nil_] cache classes for faster parsing (if dynamically modifying
245
249
  *classes or reloading classes then don't use this)
@@ -247,7 +251,7 @@ struct _options oj_default_options = {
247
251
  *to use for JSON
248
252
  * - *:time_format* [_:unix_|_:unix_zone_|_:xmlschema_|_:ruby_] time format when dumping
249
253
  * - *:bigdecimal_as_decimal* [_Boolean_|_nil_] dump BigDecimal as a decimal number or as a String
250
- * - *:bigdecimal_load* [_:bigdecimal_|_:float_|_:auto_|_:fast_] load decimals as BigDecimal instead
254
+ * - *:bigdecimal_load* [_:bigdecimal_|_:float_|_:auto_|_:fast_|_:ruby_] load decimals as BigDecimal instead
251
255
  *of as a Float. :auto pick the most precise for the number of digits. :float should be the same as
252
256
  *ruby. :fast may require rounding but is must faster.
253
257
  * - *:compat_bigdecimal* [_true_|_false_] load decimals as BigDecimal instead of as a Float when in
@@ -404,6 +408,7 @@ static VALUE get_def_opts(VALUE self) {
404
408
  switch (oj_default_options.escape_mode) {
405
409
  case NLEsc: rb_hash_aset(opts, escape_mode_sym, newline_sym); break;
406
410
  case JSONEsc: rb_hash_aset(opts, escape_mode_sym, json_sym); break;
411
+ case SlashEsc: rb_hash_aset(opts, escape_mode_sym, slash_sym); break;
407
412
  case XSSEsc: rb_hash_aset(opts, escape_mode_sym, xss_safe_sym); break;
408
413
  case ASCIIEsc: rb_hash_aset(opts, escape_mode_sym, ascii_sym); break;
409
414
  case JXEsc: rb_hash_aset(opts, escape_mode_sym, unicode_xss_sym); break;
@@ -733,6 +738,8 @@ static int parse_options_cb(VALUE k, VALUE v, VALUE opts) {
733
738
  copts->escape_mode = NLEsc;
734
739
  } else if (json_sym == v) {
735
740
  copts->escape_mode = JSONEsc;
741
+ } else if (slash_sym == v) {
742
+ copts->escape_mode = SlashEsc;
736
743
  } else if (xss_safe_sym == v) {
737
744
  copts->escape_mode = XSSEsc;
738
745
  } else if (ascii_sym == v) {
@@ -925,7 +932,7 @@ static int parse_options_cb(VALUE k, VALUE v, VALUE opts) {
925
932
  if (Qnil == v) {
926
933
  return ST_CONTINUE;
927
934
  }
928
- if (TYPE(v) == T_STRUCT && rb_obj_class(v) == rb_cRange) {
935
+ if (rb_obj_class(v) == rb_cRange) {
929
936
  VALUE min = rb_funcall(v, oj_begin_id, 0);
930
937
  VALUE max = rb_funcall(v, oj_end_id, 0);
931
938
 
@@ -1147,7 +1154,17 @@ static VALUE load_file(int argc, VALUE *argv, VALUE self) {
1147
1154
  }
1148
1155
  }
1149
1156
  path = StringValuePtr(*argv);
1150
- if (0 == (fd = open(path, O_RDONLY))) {
1157
+ #ifdef _WIN32
1158
+ {
1159
+ WCHAR *wide_path;
1160
+ wide_path = rb_w32_mbstr_to_wstr(CP_UTF8, path, -1, NULL);
1161
+ fd = rb_w32_wopen(wide_path, O_RDONLY);
1162
+ free(wide_path);
1163
+ }
1164
+ #else
1165
+ fd = open(path, O_RDONLY);
1166
+ #endif
1167
+ if (0 == fd) {
1151
1168
  rb_raise(rb_eIOError, "%s", strerror(errno));
1152
1169
  }
1153
1170
  switch (mode) {
@@ -1243,9 +1260,8 @@ static VALUE dump_body(VALUE a) {
1243
1260
  static VALUE dump_ensure(VALUE a) {
1244
1261
  volatile struct dump_arg *arg = (void *)a;
1245
1262
 
1246
- if (arg->out->allocated) {
1247
- xfree(arg->out->buf);
1248
- }
1263
+ oj_out_free(arg->out);
1264
+
1249
1265
  return Qnil;
1250
1266
  }
1251
1267
 
@@ -1257,7 +1273,6 @@ static VALUE dump_ensure(VALUE a) {
1257
1273
  * - *options* [_Hash_] same as default_options
1258
1274
  */
1259
1275
  static VALUE dump(int argc, VALUE *argv, VALUE self) {
1260
- char buf[4096];
1261
1276
  struct dump_arg arg;
1262
1277
  struct _out out;
1263
1278
  struct _options copts = oj_default_options;
@@ -1279,9 +1294,8 @@ static VALUE dump(int argc, VALUE *argv, VALUE self) {
1279
1294
  arg.argc = argc;
1280
1295
  arg.argv = argv;
1281
1296
 
1282
- arg.out->buf = buf;
1283
- arg.out->end = buf + sizeof(buf) - 10;
1284
- arg.out->allocated = false;
1297
+ oj_out_init(arg.out);
1298
+
1285
1299
  arg.out->omit_nil = copts.dump_opts.omit_nil;
1286
1300
  arg.out->caller = CALLER_DUMP;
1287
1301
 
@@ -1313,7 +1327,6 @@ static VALUE dump(int argc, VALUE *argv, VALUE self) {
1313
1327
  * Returns [_String_] the encoded JSON.
1314
1328
  */
1315
1329
  static VALUE to_json(int argc, VALUE *argv, VALUE self) {
1316
- char buf[4096];
1317
1330
  struct _out out;
1318
1331
  struct _options copts = oj_default_options;
1319
1332
  VALUE rstr;
@@ -1328,9 +1341,9 @@ static VALUE to_json(int argc, VALUE *argv, VALUE self) {
1328
1341
  }
1329
1342
  copts.mode = CompatMode;
1330
1343
  copts.to_json = Yes;
1331
- out.buf = buf;
1332
- out.end = buf + sizeof(buf) - 10;
1333
- out.allocated = false;
1344
+
1345
+ oj_out_init(&out);
1346
+
1334
1347
  out.omit_nil = copts.dump_opts.omit_nil;
1335
1348
  // For obj.to_json or generate nan is not allowed but if called from dump
1336
1349
  // it is.
@@ -1341,9 +1354,9 @@ static VALUE to_json(int argc, VALUE *argv, VALUE self) {
1341
1354
  }
1342
1355
  rstr = rb_str_new2(out.buf);
1343
1356
  rstr = oj_encode(rstr);
1344
- if (out.allocated) {
1345
- xfree(out.buf);
1346
- }
1357
+
1358
+ oj_out_free(&out);
1359
+
1347
1360
  return rstr;
1348
1361
  }
1349
1362
 
@@ -1703,6 +1716,15 @@ static VALUE protect_require(VALUE x) {
1703
1716
  return Qnil;
1704
1717
  }
1705
1718
 
1719
+ extern void print_all_odds(const char *label);
1720
+
1721
+ static VALUE
1722
+ debug_odd(VALUE self, VALUE label) {
1723
+ print_all_odds(RSTRING_PTR(label));
1724
+ return Qnil;
1725
+ }
1726
+
1727
+
1706
1728
  /* Document-module: Oj
1707
1729
  *
1708
1730
  * Optimized JSON (Oj), as the name implies was written to provide speed
@@ -1731,15 +1753,19 @@ static VALUE protect_require(VALUE x) {
1731
1753
  *
1732
1754
  * - *:wab* specifically for WAB data exchange.
1733
1755
  */
1734
- void Init_oj() {
1756
+ void Init_oj(void) {
1735
1757
  int err = 0;
1736
1758
 
1737
1759
  #if HAVE_RB_EXT_RACTOR_SAFE
1738
1760
  rb_ext_ractor_safe(true);
1739
1761
  #endif
1740
1762
  Oj = rb_define_module("Oj");
1763
+ rb_gc_register_address(&Oj);
1741
1764
 
1742
1765
  oj_cstack_class = rb_define_class_under(Oj, "CStack", rb_cObject);
1766
+ rb_gc_register_address(&oj_cstack_class);
1767
+
1768
+ rb_undef_alloc_func(oj_cstack_class);
1743
1769
 
1744
1770
  oj_string_writer_init();
1745
1771
  oj_stream_writer_init();
@@ -1748,9 +1774,11 @@ void Init_oj() {
1748
1774
  // On Rubinius the require fails but can be done from a ruby file.
1749
1775
  rb_protect(protect_require, Qnil, &err);
1750
1776
  rb_require("stringio");
1751
- oj_utf8_encoding = rb_enc_find("UTF-8");
1777
+ oj_utf8_encoding_index = rb_enc_find_index("UTF-8");
1778
+ oj_utf8_encoding = rb_enc_from_index(oj_utf8_encoding_index);
1752
1779
 
1753
1780
  // rb_define_module_function(Oj, "hash_test", hash_test, 0);
1781
+ rb_define_module_function(Oj, "debug_odd", debug_odd, 1);
1754
1782
 
1755
1783
  rb_define_module_function(Oj, "default_options", get_def_opts, 0);
1756
1784
  rb_define_module_function(Oj, "default_options=", set_def_opts, 1);
@@ -1789,6 +1817,7 @@ void Init_oj() {
1789
1817
  oj_array_end_id = rb_intern("array_end");
1790
1818
  oj_array_start_id = rb_intern("array_start");
1791
1819
  oj_as_json_id = rb_intern("as_json");
1820
+ oj_at_id = rb_intern("at");
1792
1821
  oj_begin_id = rb_intern("begin");
1793
1822
  oj_bigdecimal_id = rb_intern("BigDecimal");
1794
1823
  oj_end_id = rb_intern("end");
@@ -1802,7 +1831,6 @@ void Init_oj() {
1802
1831
  oj_hash_set_id = rb_intern("hash_set");
1803
1832
  oj_hash_start_id = rb_intern("hash_start");
1804
1833
  oj_iconv_id = rb_intern("iconv");
1805
- oj_instance_variables_id = rb_intern("instance_variables");
1806
1834
  oj_json_create_id = rb_intern("json_create");
1807
1835
  oj_length_id = rb_intern("length");
1808
1836
  oj_new_id = rb_intern("new");
@@ -1937,10 +1965,14 @@ void Init_oj() {
1937
1965
  rb_gc_register_address(&oj_decimal_class_sym);
1938
1966
  oj_hash_class_sym = ID2SYM(rb_intern("hash_class"));
1939
1967
  rb_gc_register_address(&oj_hash_class_sym);
1968
+ oj_in_sym = ID2SYM(rb_intern("in"));
1969
+ rb_gc_register_address(&oj_in_sym);
1940
1970
  oj_indent_sym = ID2SYM(rb_intern("indent"));
1941
1971
  rb_gc_register_address(&oj_indent_sym);
1942
1972
  oj_max_nesting_sym = ID2SYM(rb_intern("max_nesting"));
1943
1973
  rb_gc_register_address(&oj_max_nesting_sym);
1974
+ oj_nanosecond_sym = ID2SYM(rb_intern("nanosecond"));
1975
+ rb_gc_register_address(&oj_nanosecond_sym);
1944
1976
  oj_object_class_sym = ID2SYM(rb_intern("object_class"));
1945
1977
  rb_gc_register_address(&oj_object_class_sym);
1946
1978
  oj_object_nl_sym = ID2SYM(rb_intern("object_nl"));
@@ -1965,6 +1997,8 @@ void Init_oj() {
1965
1997
  rb_gc_register_address(&ruby_sym);
1966
1998
  sec_prec_sym = ID2SYM(rb_intern("second_precision"));
1967
1999
  rb_gc_register_address(&sec_prec_sym);
2000
+ slash_sym = ID2SYM(rb_intern("slash"));
2001
+ rb_gc_register_address(&slash_sym);
1968
2002
  strict_sym = ID2SYM(rb_intern("strict"));
1969
2003
  rb_gc_register_address(&strict_sym);
1970
2004
  symbol_keys_sym = ID2SYM(rb_intern("symbol_keys"));
@@ -2017,4 +2051,5 @@ void Init_oj() {
2017
2051
  oj_init_doc();
2018
2052
 
2019
2053
  oj_parser_init();
2054
+ oj_scanner_init();
2020
2055
  }
data/ext/oj/oj.h CHANGED
@@ -39,6 +39,16 @@ enum st_retval { ST_CONTINUE = 0, ST_STOP = 1, ST_DELETE = 2, ST_CHECK };
39
39
  #define NINF_VAL "-3.0e14159265358979323846"
40
40
  #define NAN_VAL "3.3e14159265358979323846"
41
41
 
42
+ #if __STDC_VERSION__ >= 199901L
43
+ // To avoid using ruby_snprintf with C99.
44
+ #undef snprintf
45
+ #include <stdio.h>
46
+ #endif
47
+
48
+ // To avoid using ruby_nonempty_memcpy().
49
+ #undef memcpy
50
+ #include <string.h>
51
+
42
52
  typedef enum { Yes = 'y', No = 'n', NotSet = 0 } YesNo;
43
53
 
44
54
  typedef enum {
@@ -56,6 +66,7 @@ typedef enum { UnixTime = 'u', UnixZTime = 'z', XmlTime = 'x', RubyTime = 'r' }
56
66
  typedef enum {
57
67
  NLEsc = 'n',
58
68
  JSONEsc = 'j',
69
+ SlashEsc = 's',
59
70
  XSSEsc = 'x',
60
71
  ASCIIEsc = 'a',
61
72
  JXEsc = 'g', // json gem
@@ -176,6 +187,7 @@ typedef struct _rOptTable {
176
187
  } * ROptTable;
177
188
 
178
189
  typedef struct _out {
190
+ char stack_buffer[4096];
179
191
  char * buf;
180
192
  char * end;
181
193
  char * cur;
@@ -265,8 +277,8 @@ extern void oj_str_writer_pop(StrWriter sw);
265
277
  extern void oj_str_writer_pop_all(StrWriter sw);
266
278
 
267
279
  extern void oj_init_doc(void);
268
- extern void oj_string_writer_init();
269
- extern void oj_stream_writer_init();
280
+ extern void oj_string_writer_init(void);
281
+ extern void oj_stream_writer_init(void);
270
282
  extern void oj_str_writer_init(StrWriter sw, int buf_size);
271
283
  extern VALUE oj_define_mimic_json(int argc, VALUE *argv, VALUE self);
272
284
  extern VALUE oj_mimic_generate(int argc, VALUE *argv, VALUE self);
@@ -282,6 +294,7 @@ extern VALUE oj_rails_encode(int argc, VALUE *argv, VALUE self);
282
294
  extern VALUE Oj;
283
295
  extern struct _options oj_default_options;
284
296
  extern rb_encoding * oj_utf8_encoding;
297
+ extern int oj_utf8_encoding_index;
285
298
 
286
299
  extern VALUE oj_bag_class;
287
300
  extern VALUE oj_bigdecimal_class;
@@ -304,7 +317,9 @@ extern VALUE oj_ascii_only_sym;
304
317
  extern VALUE oj_create_additions_sym;
305
318
  extern VALUE oj_decimal_class_sym;
306
319
  extern VALUE oj_hash_class_sym;
320
+ extern VALUE oj_in_sym;
307
321
  extern VALUE oj_indent_sym;
322
+ extern VALUE oj_nanosecond_sym;
308
323
  extern VALUE oj_max_nesting_sym;
309
324
  extern VALUE oj_object_class_sym;
310
325
  extern VALUE oj_object_nl_sym;
@@ -321,6 +336,7 @@ extern ID oj_array_append_id;
321
336
  extern ID oj_array_end_id;
322
337
  extern ID oj_array_start_id;
323
338
  extern ID oj_as_json_id;
339
+ extern ID oj_at_id;
324
340
  extern ID oj_begin_id;
325
341
  extern ID oj_bigdecimal_id;
326
342
  extern ID oj_end_id;
@@ -334,7 +350,6 @@ extern ID oj_hash_key_id;
334
350
  extern ID oj_hash_set_id;
335
351
  extern ID oj_hash_start_id;
336
352
  extern ID oj_iconv_id;
337
- extern ID oj_instance_variables_id;
338
353
  extern ID oj_json_create_id;
339
354
  extern ID oj_length_id;
340
355
  extern ID oj_new_id;
@@ -364,6 +379,12 @@ extern bool oj_use_hash_alt;
364
379
  extern bool oj_use_array_alt;
365
380
  extern bool string_writer_optimized;
366
381
 
382
+ #define APPEND_CHARS(buffer, chars, size) \
383
+ { \
384
+ memcpy(buffer, chars, size); \
385
+ buffer += size; \
386
+ }
387
+
367
388
  #ifdef HAVE_PTHREAD_MUTEX_INIT
368
389
  extern pthread_mutex_t oj_cache_mutex;
369
390
  #else