oj 3.13.11 → 3.13.23

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 (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