oj 3.11.1 → 3.11.6

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 (65) hide show
  1. checksums.yaml +4 -4
  2. data/README.md +6 -1
  3. data/ext/oj/buf.h +34 -38
  4. data/ext/oj/cache8.c +59 -62
  5. data/ext/oj/cache8.h +8 -7
  6. data/ext/oj/circarray.c +33 -35
  7. data/ext/oj/circarray.h +11 -9
  8. data/ext/oj/code.c +170 -174
  9. data/ext/oj/code.h +21 -20
  10. data/ext/oj/compat.c +159 -166
  11. data/ext/oj/custom.c +802 -851
  12. data/ext/oj/dump.c +766 -778
  13. data/ext/oj/dump.h +49 -51
  14. data/ext/oj/dump_compat.c +1 -0
  15. data/ext/oj/dump_leaf.c +116 -157
  16. data/ext/oj/dump_object.c +609 -628
  17. data/ext/oj/dump_strict.c +318 -327
  18. data/ext/oj/encode.h +3 -4
  19. data/ext/oj/err.c +39 -25
  20. data/ext/oj/err.h +24 -15
  21. data/ext/oj/extconf.rb +2 -1
  22. data/ext/oj/fast.c +1042 -1041
  23. data/ext/oj/hash.c +62 -66
  24. data/ext/oj/hash.h +7 -6
  25. data/ext/oj/hash_test.c +450 -443
  26. data/ext/oj/mimic_json.c +412 -402
  27. data/ext/oj/object.c +559 -528
  28. data/ext/oj/odd.c +123 -128
  29. data/ext/oj/odd.h +27 -25
  30. data/ext/oj/oj.c +1123 -924
  31. data/ext/oj/oj.h +286 -298
  32. data/ext/oj/parse.c +938 -930
  33. data/ext/oj/parse.h +70 -69
  34. data/ext/oj/rails.c +836 -839
  35. data/ext/oj/rails.h +7 -7
  36. data/ext/oj/reader.c +135 -140
  37. data/ext/oj/reader.h +66 -79
  38. data/ext/oj/resolve.c +43 -43
  39. data/ext/oj/resolve.h +3 -2
  40. data/ext/oj/rxclass.c +67 -68
  41. data/ext/oj/rxclass.h +12 -10
  42. data/ext/oj/saj.c +451 -479
  43. data/ext/oj/scp.c +93 -103
  44. data/ext/oj/sparse.c +770 -730
  45. data/ext/oj/stream_writer.c +120 -149
  46. data/ext/oj/strict.c +71 -86
  47. data/ext/oj/string_writer.c +198 -243
  48. data/ext/oj/trace.c +29 -33
  49. data/ext/oj/trace.h +14 -11
  50. data/ext/oj/util.c +103 -103
  51. data/ext/oj/util.h +3 -2
  52. data/ext/oj/val_stack.c +47 -47
  53. data/ext/oj/val_stack.h +79 -86
  54. data/ext/oj/wab.c +291 -309
  55. data/lib/oj/bag.rb +1 -0
  56. data/lib/oj/easy_hash.rb +5 -4
  57. data/lib/oj/mimic.rb +0 -12
  58. data/lib/oj/version.rb +1 -1
  59. data/test/activerecord/result_test.rb +7 -2
  60. data/test/foo.rb +35 -32
  61. data/test/test_fast.rb +32 -2
  62. data/test/test_generate.rb +21 -0
  63. data/test/test_hash.rb +10 -0
  64. data/test/test_scp.rb +1 -1
  65. metadata +4 -2
data/ext/oj/compat.c CHANGED
@@ -1,295 +1,288 @@
1
1
  // Copyright (c) 2012 Peter Ohler. All rights reserved.
2
+ // Licensed under the MIT License. See LICENSE file in the project root for license details.
2
3
 
3
4
  #include <stdio.h>
4
5
 
5
- #include "oj.h"
6
+ #include "encode.h"
6
7
  #include "err.h"
8
+ #include "hash.h"
9
+ #include "oj.h"
7
10
  #include "parse.h"
8
11
  #include "resolve.h"
9
- #include "hash.h"
10
- #include "encode.h"
11
12
  #include "trace.h"
12
13
 
13
- static void
14
- hash_set_cstr(ParseInfo pi, Val kval, const char *str, size_t len, const char *orig) {
15
- const char *key = kval->key;
16
- int klen = kval->klen;
17
- Val parent = stack_peek(&pi->stack);
18
- volatile VALUE rkey = kval->key_val;
19
-
20
- if (Qundef == rkey &&
21
- Yes == pi->options.create_ok &&
22
- NULL != pi->options.create_id &&
23
- *pi->options.create_id == *key &&
24
- (int)pi->options.create_id_len == klen &&
25
- 0 == strncmp(pi->options.create_id, key, klen)) {
26
-
27
- parent->classname = oj_strndup(str, len);
28
- parent->clen = len;
14
+ static void hash_set_cstr(ParseInfo pi, Val kval, const char *str, size_t len, const char *orig) {
15
+ const char * key = kval->key;
16
+ int klen = kval->klen;
17
+ Val parent = stack_peek(&pi->stack);
18
+ volatile VALUE rkey = kval->key_val;
19
+
20
+ if (Qundef == rkey && Yes == pi->options.create_ok && NULL != pi->options.create_id &&
21
+ *pi->options.create_id == *key && (int)pi->options.create_id_len == klen &&
22
+ 0 == strncmp(pi->options.create_id, key, klen)) {
23
+ parent->classname = oj_strndup(str, len);
24
+ parent->clen = len;
29
25
  } else {
30
- volatile VALUE rstr = rb_str_new(str, len);
31
-
32
- if (Qundef == rkey) {
33
- rkey = rb_str_new(key, klen);
34
- rstr = oj_encode(rstr);
35
- rkey = oj_encode(rkey);
36
- if (Yes == pi->options.sym_key) {
37
- rkey = rb_str_intern(rkey);
38
- }
39
- }
40
- if (Yes == pi->options.create_ok && NULL != pi->options.str_rx.head) {
41
- VALUE clas = oj_rxclass_match(&pi->options.str_rx, str, (int)len);
42
-
43
- if (Qnil != clas) {
44
- rstr = rb_funcall(clas, oj_json_create_id, 1, rstr);
45
- }
46
- }
47
- if (rb_cHash != rb_obj_class(parent->val)) {
48
- // The rb_hash_set would still work but the unit tests for the
49
- // json gem require the less efficient []= method be called to set
50
- // values. Even using the store method to set the values will fail
51
- // the unit tests.
52
- rb_funcall(parent->val, rb_intern("[]="), 2, rkey, rstr);
53
- } else {
54
- rb_hash_aset(parent->val, rkey, rstr);
55
- }
56
- if (Yes == pi->options.trace) {
57
- oj_trace_parse_call("set_string", pi, __FILE__, __LINE__, rstr);
58
- }
26
+ volatile VALUE rstr = rb_str_new(str, len);
27
+
28
+ if (Qundef == rkey) {
29
+ rkey = rb_str_new(key, klen);
30
+ rstr = oj_encode(rstr);
31
+ rkey = oj_encode(rkey);
32
+ if (Yes == pi->options.sym_key) {
33
+ rkey = rb_str_intern(rkey);
34
+ }
35
+ }
36
+ if (Yes == pi->options.create_ok && NULL != pi->options.str_rx.head) {
37
+ VALUE clas = oj_rxclass_match(&pi->options.str_rx, str, (int)len);
38
+
39
+ if (Qnil != clas) {
40
+ rstr = rb_funcall(clas, oj_json_create_id, 1, rstr);
41
+ }
42
+ }
43
+ if (rb_cHash != rb_obj_class(parent->val)) {
44
+ // The rb_hash_set would still work but the unit tests for the
45
+ // json gem require the less efficient []= method be called to set
46
+ // values. Even using the store method to set the values will fail
47
+ // the unit tests.
48
+ rb_funcall(parent->val, rb_intern("[]="), 2, rkey, rstr);
49
+ } else {
50
+ rb_hash_aset(parent->val, rkey, rstr);
51
+ }
52
+ if (Yes == pi->options.trace) {
53
+ oj_trace_parse_call("set_string", pi, __FILE__, __LINE__, rstr);
54
+ }
59
55
  }
60
56
  }
61
57
 
62
- static VALUE
63
- start_hash(ParseInfo pi) {
64
- volatile VALUE h;
58
+ static VALUE start_hash(ParseInfo pi) {
59
+ volatile VALUE h;
65
60
 
66
61
  if (Qnil != pi->options.hash_class) {
67
- h = rb_class_new_instance(0, NULL, pi->options.hash_class);
62
+ h = rb_class_new_instance(0, NULL, pi->options.hash_class);
68
63
  } else {
69
- h = rb_hash_new();
64
+ h = rb_hash_new();
70
65
  }
71
66
  if (Yes == pi->options.trace) {
72
- oj_trace_parse_in("start_hash", pi, __FILE__, __LINE__);
67
+ oj_trace_parse_in("start_hash", pi, __FILE__, __LINE__);
73
68
  }
74
69
  return h;
75
70
  }
76
71
 
77
- static void
78
- end_hash(struct _parseInfo *pi) {
79
- Val parent = stack_peek(&pi->stack);
72
+ static void end_hash(struct _parseInfo *pi) {
73
+ Val parent = stack_peek(&pi->stack);
80
74
 
81
75
  if (0 != parent->classname) {
82
- volatile VALUE clas;
83
-
84
- clas = oj_name2class(pi, parent->classname, parent->clen, 0, rb_eArgError);
85
- if (Qundef != clas) { // else an error
86
- ID creatable = rb_intern("json_creatable?");
87
-
88
- if (!rb_respond_to(clas, creatable) || Qtrue == rb_funcall(clas, creatable, 0)) {
89
- parent->val = rb_funcall(clas, oj_json_create_id, 1, parent->val);
90
- }
91
- }
92
- if (0 != parent->classname) {
93
- xfree((char*)parent->classname);
94
- parent->classname = 0;
95
- }
76
+ volatile VALUE clas;
77
+
78
+ clas = oj_name2class(pi, parent->classname, parent->clen, 0, rb_eArgError);
79
+ if (Qundef != clas) { // else an error
80
+ ID creatable = rb_intern("json_creatable?");
81
+
82
+ if (!rb_respond_to(clas, creatable) || Qtrue == rb_funcall(clas, creatable, 0)) {
83
+ parent->val = rb_funcall(clas, oj_json_create_id, 1, parent->val);
84
+ }
85
+ }
86
+ if (0 != parent->classname) {
87
+ xfree((char *)parent->classname);
88
+ parent->classname = 0;
89
+ }
96
90
  }
97
91
  if (Yes == pi->options.trace) {
98
- oj_trace_parse_hash_end(pi, __FILE__, __LINE__);
92
+ oj_trace_parse_hash_end(pi, __FILE__, __LINE__);
99
93
  }
100
94
  }
101
95
 
102
- static VALUE
103
- calc_hash_key(ParseInfo pi, Val parent) {
104
- volatile VALUE rkey = parent->key_val;
96
+ static VALUE calc_hash_key(ParseInfo pi, Val parent) {
97
+ volatile VALUE rkey = parent->key_val;
105
98
 
106
99
  if (Qundef == rkey) {
107
- rkey = rb_str_new(parent->key, parent->klen);
100
+ rkey = rb_str_new(parent->key, parent->klen);
108
101
  }
109
102
  rkey = oj_encode(rkey);
110
103
  if (Yes == pi->options.sym_key) {
111
- rkey = rb_str_intern(rkey);
104
+ rkey = rb_str_intern(rkey);
112
105
  }
113
106
  return rkey;
114
107
  }
115
108
 
116
- static void
117
- add_cstr(ParseInfo pi, const char *str, size_t len, const char *orig) {
118
- volatile VALUE rstr = rb_str_new(str, len);
109
+ static void add_cstr(ParseInfo pi, const char *str, size_t len, const char *orig) {
110
+ volatile VALUE rstr = rb_str_new(str, len);
119
111
 
120
112
  rstr = oj_encode(rstr);
121
113
  if (Yes == pi->options.create_ok && NULL != pi->options.str_rx.head) {
122
- VALUE clas = oj_rxclass_match(&pi->options.str_rx, str, (int)len);
114
+ VALUE clas = oj_rxclass_match(&pi->options.str_rx, str, (int)len);
123
115
 
124
- if (Qnil != clas) {
125
- pi->stack.head->val = rb_funcall(clas, oj_json_create_id, 1, rstr);
126
- return;
127
- }
116
+ if (Qnil != clas) {
117
+ pi->stack.head->val = rb_funcall(clas, oj_json_create_id, 1, rstr);
118
+ return;
119
+ }
128
120
  }
129
121
  pi->stack.head->val = rstr;
130
122
  if (Yes == pi->options.trace) {
131
- oj_trace_parse_call("add_string", pi, __FILE__, __LINE__, rstr);
123
+ oj_trace_parse_call("add_string", pi, __FILE__, __LINE__, rstr);
132
124
  }
133
125
  }
134
126
 
135
- static void
136
- add_num(ParseInfo pi, NumInfo ni) {
127
+ static void add_num(ParseInfo pi, NumInfo ni) {
137
128
  pi->stack.head->val = oj_num_as_value(ni);
138
129
  if (Yes == pi->options.trace) {
139
- oj_trace_parse_call("add_number", pi, __FILE__, __LINE__, pi->stack.head->val);
130
+ oj_trace_parse_call("add_number", pi, __FILE__, __LINE__, pi->stack.head->val);
140
131
  }
141
132
  }
142
133
 
143
- static void
144
- hash_set_num(struct _parseInfo *pi, Val parent, NumInfo ni) {
145
- volatile VALUE rval = oj_num_as_value(ni);
134
+ static void hash_set_num(struct _parseInfo *pi, Val parent, NumInfo ni) {
135
+ volatile VALUE rval = oj_num_as_value(ni);
146
136
 
147
137
  if (!oj_use_hash_alt && rb_cHash != rb_obj_class(parent->val)) {
148
- // The rb_hash_set would still work but the unit tests for the
149
- // json gem require the less efficient []= method be called to set
150
- // values. Even using the store method to set the values will fail
151
- // the unit tests.
152
- rb_funcall(stack_peek(&pi->stack)->val, rb_intern("[]="), 2, calc_hash_key(pi, parent), rval);
138
+ // The rb_hash_set would still work but the unit tests for the
139
+ // json gem require the less efficient []= method be called to set
140
+ // values. Even using the store method to set the values will fail
141
+ // the unit tests.
142
+ rb_funcall(stack_peek(&pi->stack)->val,
143
+ rb_intern("[]="),
144
+ 2,
145
+ calc_hash_key(pi, parent),
146
+ rval);
153
147
  } else {
154
- rb_hash_aset(stack_peek(&pi->stack)->val, calc_hash_key(pi, parent), rval);
148
+ rb_hash_aset(stack_peek(&pi->stack)->val, calc_hash_key(pi, parent), rval);
155
149
  }
156
150
  if (Yes == pi->options.trace) {
157
- oj_trace_parse_call("set_number", pi, __FILE__, __LINE__, rval);
151
+ oj_trace_parse_call("set_number", pi, __FILE__, __LINE__, rval);
158
152
  }
159
153
  }
160
154
 
161
- static void
162
- hash_set_value(ParseInfo pi, Val parent, VALUE value) {
155
+ static void hash_set_value(ParseInfo pi, Val parent, VALUE value) {
163
156
  if (rb_cHash != rb_obj_class(parent->val)) {
164
- // The rb_hash_set would still work but the unit tests for the
165
- // json gem require the less efficient []= method be called to set
166
- // values. Even using the store method to set the values will fail
167
- // the unit tests.
168
- rb_funcall(stack_peek(&pi->stack)->val, rb_intern("[]="), 2, calc_hash_key(pi, parent), value);
157
+ // The rb_hash_set would still work but the unit tests for the
158
+ // json gem require the less efficient []= method be called to set
159
+ // values. Even using the store method to set the values will fail
160
+ // the unit tests.
161
+ rb_funcall(stack_peek(&pi->stack)->val,
162
+ rb_intern("[]="),
163
+ 2,
164
+ calc_hash_key(pi, parent),
165
+ value);
169
166
  } else {
170
- rb_hash_aset(stack_peek(&pi->stack)->val, calc_hash_key(pi, parent), value);
167
+ rb_hash_aset(stack_peek(&pi->stack)->val, calc_hash_key(pi, parent), value);
171
168
  }
172
169
  if (Yes == pi->options.trace) {
173
- oj_trace_parse_call("set_value", pi, __FILE__, __LINE__, value);
170
+ oj_trace_parse_call("set_value", pi, __FILE__, __LINE__, value);
174
171
  }
175
172
  }
176
173
 
177
- static VALUE
178
- start_array(ParseInfo pi) {
174
+ static VALUE start_array(ParseInfo pi) {
179
175
  if (Qnil != pi->options.array_class) {
180
- return rb_class_new_instance(0, NULL, pi->options.array_class);
176
+ return rb_class_new_instance(0, NULL, pi->options.array_class);
181
177
  }
182
178
  if (Yes == pi->options.trace) {
183
- oj_trace_parse_in("start_array", pi, __FILE__, __LINE__);
179
+ oj_trace_parse_in("start_array", pi, __FILE__, __LINE__);
184
180
  }
185
181
  return rb_ary_new();
186
182
  }
187
183
 
188
- static void
189
- array_append_num(ParseInfo pi, NumInfo ni) {
190
- Val parent = stack_peek(&pi->stack);
191
- volatile VALUE rval = oj_num_as_value(ni);
184
+ static void array_append_num(ParseInfo pi, NumInfo ni) {
185
+ Val parent = stack_peek(&pi->stack);
186
+ volatile VALUE rval = oj_num_as_value(ni);
192
187
 
193
188
  if (!oj_use_array_alt && rb_cArray != rb_obj_class(parent->val)) {
194
- // The rb_ary_push would still work but the unit tests for the json
195
- // gem require the less efficient << method be called to push the
196
- // values.
197
- rb_funcall(parent->val, rb_intern("<<"), 1, rval);
189
+ // The rb_ary_push would still work but the unit tests for the json
190
+ // gem require the less efficient << method be called to push the
191
+ // values.
192
+ rb_funcall(parent->val, rb_intern("<<"), 1, rval);
198
193
  } else {
199
- rb_ary_push(parent->val, rval);
194
+ rb_ary_push(parent->val, rval);
200
195
  }
201
196
  if (Yes == pi->options.trace) {
202
- oj_trace_parse_call("append_number", pi, __FILE__, __LINE__, rval);
197
+ oj_trace_parse_call("append_number", pi, __FILE__, __LINE__, rval);
203
198
  }
204
199
  }
205
200
 
206
- static void
207
- array_append_cstr(ParseInfo pi, const char *str, size_t len, const char *orig) {
208
- volatile VALUE rstr = rb_str_new(str, len);
201
+ static void array_append_cstr(ParseInfo pi, const char *str, size_t len, const char *orig) {
202
+ volatile VALUE rstr = rb_str_new(str, len);
209
203
 
210
204
  rstr = oj_encode(rstr);
211
205
  if (Yes == pi->options.create_ok && NULL != pi->options.str_rx.head) {
212
- VALUE clas = oj_rxclass_match(&pi->options.str_rx, str, (int)len);
206
+ VALUE clas = oj_rxclass_match(&pi->options.str_rx, str, (int)len);
213
207
 
214
- if (Qnil != clas) {
215
- rb_ary_push(stack_peek(&pi->stack)->val, rb_funcall(clas, oj_json_create_id, 1, rstr));
216
- return;
217
- }
208
+ if (Qnil != clas) {
209
+ rb_ary_push(stack_peek(&pi->stack)->val, rb_funcall(clas, oj_json_create_id, 1, rstr));
210
+ return;
211
+ }
218
212
  }
219
213
  rb_ary_push(stack_peek(&pi->stack)->val, rstr);
220
214
  if (Yes == pi->options.trace) {
221
- oj_trace_parse_call("append_string", pi, __FILE__, __LINE__, rstr);
215
+ oj_trace_parse_call("append_string", pi, __FILE__, __LINE__, rstr);
222
216
  }
223
217
  }
224
218
 
225
- void
226
- oj_set_compat_callbacks(ParseInfo pi) {
219
+ void oj_set_compat_callbacks(ParseInfo pi) {
227
220
  oj_set_strict_callbacks(pi);
228
- pi->start_hash = start_hash;
229
- pi->end_hash = end_hash;
230
- pi->hash_set_cstr = hash_set_cstr;
231
- pi->hash_set_num = hash_set_num;
232
- pi->hash_set_value = hash_set_value;
233
- pi->add_num = add_num;
234
- pi->add_cstr = add_cstr;
221
+ pi->start_hash = start_hash;
222
+ pi->end_hash = end_hash;
223
+ pi->hash_set_cstr = hash_set_cstr;
224
+ pi->hash_set_num = hash_set_num;
225
+ pi->hash_set_value = hash_set_value;
226
+ pi->add_num = add_num;
227
+ pi->add_cstr = add_cstr;
235
228
  pi->array_append_cstr = array_append_cstr;
236
- pi->start_array = start_array;
237
- pi->array_append_num = array_append_num;
229
+ pi->start_array = start_array;
230
+ pi->array_append_num = array_append_num;
238
231
  }
239
232
 
240
233
  VALUE
241
234
  oj_compat_parse(int argc, VALUE *argv, VALUE self) {
242
- struct _parseInfo pi;
235
+ struct _parseInfo pi;
243
236
 
244
237
  parse_info_init(&pi);
245
- pi.options = oj_default_options;
246
- pi.handler = Qnil;
247
- pi.err_class = Qnil;
248
- pi.max_depth = 0;
249
- pi.options.allow_nan = Yes;
250
- pi.options.nilnil = Yes;
238
+ pi.options = oj_default_options;
239
+ pi.handler = Qnil;
240
+ pi.err_class = Qnil;
241
+ pi.max_depth = 0;
242
+ pi.options.allow_nan = Yes;
243
+ pi.options.nilnil = Yes;
251
244
  pi.options.empty_string = No;
252
245
  oj_set_compat_callbacks(&pi);
253
246
 
254
247
  if (T_STRING == rb_type(*argv)) {
255
- return oj_pi_parse(argc, argv, &pi, 0, 0, false);
248
+ return oj_pi_parse(argc, argv, &pi, 0, 0, false);
256
249
  } else {
257
- return oj_pi_sparse(argc, argv, &pi, 0);
250
+ return oj_pi_sparse(argc, argv, &pi, 0);
258
251
  }
259
252
  }
260
253
 
261
254
  VALUE
262
255
  oj_compat_load(int argc, VALUE *argv, VALUE self) {
263
- struct _parseInfo pi;
256
+ struct _parseInfo pi;
264
257
 
265
258
  parse_info_init(&pi);
266
- pi.options = oj_default_options;
267
- pi.handler = Qnil;
268
- pi.err_class = Qnil;
269
- pi.max_depth = 0;
270
- pi.options.allow_nan = Yes;
271
- pi.options.nilnil = Yes;
259
+ pi.options = oj_default_options;
260
+ pi.handler = Qnil;
261
+ pi.err_class = Qnil;
262
+ pi.max_depth = 0;
263
+ pi.options.allow_nan = Yes;
264
+ pi.options.nilnil = Yes;
272
265
  pi.options.empty_string = Yes;
273
266
  oj_set_compat_callbacks(&pi);
274
267
 
275
268
  if (T_STRING == rb_type(*argv)) {
276
- return oj_pi_parse(argc, argv, &pi, 0, 0, false);
269
+ return oj_pi_parse(argc, argv, &pi, 0, 0, false);
277
270
  } else {
278
- return oj_pi_sparse(argc, argv, &pi, 0);
271
+ return oj_pi_sparse(argc, argv, &pi, 0);
279
272
  }
280
273
  }
281
274
 
282
275
  VALUE
283
276
  oj_compat_parse_cstr(int argc, VALUE *argv, char *json, size_t len) {
284
- struct _parseInfo pi;
277
+ struct _parseInfo pi;
285
278
 
286
279
  parse_info_init(&pi);
287
- pi.options = oj_default_options;
288
- pi.handler = Qnil;
289
- pi.err_class = Qnil;
290
- pi.max_depth = 0;
280
+ pi.options = oj_default_options;
281
+ pi.handler = Qnil;
282
+ pi.err_class = Qnil;
283
+ pi.max_depth = 0;
291
284
  pi.options.allow_nan = Yes;
292
- pi.options.nilnil = Yes;
285
+ pi.options.nilnil = Yes;
293
286
  oj_set_compat_callbacks(&pi);
294
287
 
295
288
  return oj_pi_parse(argc, argv, &pi, json, len, false);