oj 3.10.6 → 3.12.1

Sign up to get free protection for your applications and to get access to all the features.
Files changed (81) hide show
  1. checksums.yaml +4 -4
  2. data/README.md +6 -1
  3. data/ext/oj/buf.h +36 -68
  4. data/ext/oj/cache8.c +59 -62
  5. data/ext/oj/cache8.h +9 -36
  6. data/ext/oj/circarray.c +36 -42
  7. data/ext/oj/circarray.h +12 -13
  8. data/ext/oj/code.c +172 -179
  9. data/ext/oj/code.h +22 -24
  10. data/ext/oj/compat.c +176 -181
  11. data/ext/oj/custom.c +800 -864
  12. data/ext/oj/dump.c +774 -776
  13. data/ext/oj/dump.h +50 -55
  14. data/ext/oj/dump_compat.c +2 -4
  15. data/ext/oj/dump_leaf.c +118 -162
  16. data/ext/oj/dump_object.c +610 -632
  17. data/ext/oj/dump_strict.c +319 -331
  18. data/ext/oj/encode.h +4 -33
  19. data/ext/oj/err.c +40 -29
  20. data/ext/oj/err.h +25 -44
  21. data/ext/oj/extconf.rb +2 -1
  22. data/ext/oj/fast.c +1054 -1081
  23. data/ext/oj/hash.c +102 -97
  24. data/ext/oj/hash.h +10 -35
  25. data/ext/oj/hash_test.c +451 -472
  26. data/ext/oj/mimic_json.c +415 -402
  27. data/ext/oj/object.c +588 -532
  28. data/ext/oj/odd.c +124 -132
  29. data/ext/oj/odd.h +28 -29
  30. data/ext/oj/oj.c +1186 -906
  31. data/ext/oj/oj.h +289 -298
  32. data/ext/oj/parse.c +946 -870
  33. data/ext/oj/parse.h +81 -79
  34. data/ext/oj/rails.c +837 -842
  35. data/ext/oj/rails.h +8 -11
  36. data/ext/oj/reader.c +139 -147
  37. data/ext/oj/reader.h +68 -84
  38. data/ext/oj/resolve.c +44 -47
  39. data/ext/oj/resolve.h +4 -6
  40. data/ext/oj/rxclass.c +69 -73
  41. data/ext/oj/rxclass.h +13 -14
  42. data/ext/oj/saj.c +453 -484
  43. data/ext/oj/scp.c +88 -113
  44. data/ext/oj/sparse.c +783 -714
  45. data/ext/oj/stream_writer.c +123 -157
  46. data/ext/oj/strict.c +133 -106
  47. data/ext/oj/string_writer.c +199 -247
  48. data/ext/oj/trace.c +34 -41
  49. data/ext/oj/trace.h +15 -15
  50. data/ext/oj/util.c +104 -104
  51. data/ext/oj/util.h +4 -3
  52. data/ext/oj/val_stack.c +48 -76
  53. data/ext/oj/val_stack.h +80 -115
  54. data/ext/oj/wab.c +321 -325
  55. data/lib/oj.rb +0 -8
  56. data/lib/oj/bag.rb +1 -0
  57. data/lib/oj/easy_hash.rb +5 -4
  58. data/lib/oj/mimic.rb +47 -13
  59. data/lib/oj/version.rb +1 -1
  60. data/pages/Modes.md +1 -0
  61. data/pages/Options.md +23 -11
  62. data/test/activerecord/result_test.rb +7 -2
  63. data/test/foo.rb +8 -40
  64. data/test/helper.rb +10 -0
  65. data/test/json_gem/json_common_interface_test.rb +8 -3
  66. data/test/json_gem/json_generator_test.rb +15 -3
  67. data/test/json_gem/test_helper.rb +8 -0
  68. data/test/perf.rb +1 -1
  69. data/test/perf_scp.rb +11 -10
  70. data/test/perf_strict.rb +17 -23
  71. data/test/prec.rb +23 -0
  72. data/test/sample_json.rb +1 -1
  73. data/test/test_compat.rb +16 -3
  74. data/test/test_custom.rb +11 -0
  75. data/test/test_fast.rb +32 -2
  76. data/test/test_generate.rb +21 -0
  77. data/test/test_hash.rb +10 -0
  78. data/test/test_rails.rb +9 -0
  79. data/test/test_scp.rb +1 -1
  80. data/test/test_various.rb +4 -2
  81. metadata +89 -85
@@ -1,22 +1,18 @@
1
- /* stream_writer.c
2
- * Copyright (c) 2012, 2017, Peter Ohler
3
- * All rights reserved.
4
- */
1
+ // Copyright (c) 2012, 2017 Peter Ohler. All rights reserved.
2
+ // Licensed under the MIT License. See LICENSE file in the project root for license details.
5
3
 
6
4
  #include <errno.h>
7
-
8
5
  #include <ruby.h>
9
6
 
10
7
  #include "encode.h"
11
8
 
12
- extern VALUE Oj;
9
+ extern VALUE Oj;
13
10
 
14
- static void
15
- stream_writer_free(void *ptr) {
16
- StreamWriter sw;
11
+ static void stream_writer_free(void *ptr) {
12
+ StreamWriter sw;
17
13
 
18
14
  if (0 == ptr) {
19
- return;
15
+ return;
20
16
  }
21
17
  sw = (StreamWriter)ptr;
22
18
  xfree(sw->sw.out.buf);
@@ -24,41 +20,38 @@ stream_writer_free(void *ptr) {
24
20
  xfree(ptr);
25
21
  }
26
22
 
27
- static void
28
- stream_writer_reset_buf(StreamWriter sw) {
29
- sw->sw.out.cur = sw->sw.out.buf;
23
+ static void stream_writer_reset_buf(StreamWriter sw) {
24
+ sw->sw.out.cur = sw->sw.out.buf;
30
25
  *sw->sw.out.cur = '\0';
31
26
  }
32
27
 
33
- static void
34
- stream_writer_write(StreamWriter sw) {
35
- ssize_t size = sw->sw.out.cur - sw->sw.out.buf;
28
+ static void stream_writer_write(StreamWriter sw) {
29
+ ssize_t size = sw->sw.out.cur - sw->sw.out.buf;
36
30
 
37
31
  switch (sw->type) {
38
32
  case STRING_IO:
39
33
  case STREAM_IO: {
40
- volatile VALUE rs = rb_str_new(sw->sw.out.buf, size);
41
-
42
- // Oddly enough, when pushing ASCII characters with UTF-8 encoding or
43
- // even ASCII-8BIT does not change the output encoding. Pushing any
44
- // non-ASCII no matter what the encoding changes the output encoding
45
- // to ASCII-8BIT if it the string is not forced to UTF-8 here.
46
- rs = oj_encode(rs);
47
- rb_funcall(sw->stream, oj_write_id, 1, rs);
48
- break;
34
+ volatile VALUE rs = rb_str_new(sw->sw.out.buf, size);
35
+
36
+ // Oddly enough, when pushing ASCII characters with UTF-8 encoding or
37
+ // even ASCII-8BIT does not change the output encoding. Pushing any
38
+ // non-ASCII no matter what the encoding changes the output encoding
39
+ // to ASCII-8BIT if it the string is not forced to UTF-8 here.
40
+ rs = oj_encode(rs);
41
+ rb_funcall(sw->stream, oj_write_id, 1, rs);
42
+ break;
49
43
  }
50
44
  case FILE_IO:
51
- if (size != write(sw->fd, sw->sw.out.buf, size)) {
52
- rb_raise(rb_eIOError, "Write failed. [_%d_:%s]\n", errno, strerror(errno));
53
- }
54
- break;
55
- default:
56
- rb_raise(rb_eArgError, "expected an IO Object.");
45
+ if (size != write(sw->fd, sw->sw.out.buf, size)) {
46
+ rb_raise(rb_eIOError, "Write failed. [_%d_:%s]\n", errno, strerror(errno));
47
+ }
48
+ break;
49
+ default: rb_raise(rb_eArgError, "expected an IO Object.");
57
50
  }
58
51
  stream_writer_reset_buf(sw);
59
52
  }
60
53
 
61
- static VALUE buffer_size_sym = Qundef;
54
+ static VALUE buffer_size_sym = Qundef;
62
55
 
63
56
  /* Document-method: new
64
57
  * call-seq: new(io, options)
@@ -76,62 +69,60 @@ static VALUE buffer_size_sym = Qundef;
76
69
  * - *io* [_IO_] stream to write to
77
70
  * - *options* [_Hash_] formating options
78
71
  */
79
- static VALUE
80
- stream_writer_new(int argc, VALUE *argv, VALUE self) {
81
- StreamWriterType type = STREAM_IO;
82
- int fd = 0;
83
- VALUE stream = argv[0];
84
- VALUE clas = rb_obj_class(stream);
85
- StreamWriter sw;
72
+ static VALUE stream_writer_new(int argc, VALUE *argv, VALUE self) {
73
+ StreamWriterType type = STREAM_IO;
74
+ int fd = 0;
75
+ VALUE stream = argv[0];
76
+ VALUE clas = rb_obj_class(stream);
77
+ StreamWriter sw;
86
78
  #if !IS_WINDOWS
87
- VALUE s;
79
+ VALUE s;
88
80
  #endif
89
-
81
+
90
82
  if (oj_stringio_class == clas) {
91
- type = STRING_IO;
83
+ type = STRING_IO;
92
84
  #if !IS_WINDOWS
93
85
  } else if (rb_respond_to(stream, oj_fileno_id) &&
94
- Qnil != (s = rb_funcall(stream, oj_fileno_id, 0)) &&
95
- 0 != (fd = FIX2INT(s))) {
96
- type = FILE_IO;
86
+ Qnil != (s = rb_funcall(stream, oj_fileno_id, 0)) && 0 != (fd = FIX2INT(s))) {
87
+ type = FILE_IO;
97
88
  #endif
98
89
  } else if (rb_respond_to(stream, oj_write_id)) {
99
- type = STREAM_IO;
90
+ type = STREAM_IO;
100
91
  } else {
101
- rb_raise(rb_eArgError, "expected an IO Object.");
92
+ rb_raise(rb_eArgError, "expected an IO Object.");
102
93
  }
103
94
  sw = ALLOC(struct _streamWriter);
104
95
  if (2 == argc && T_HASH == rb_type(argv[1])) {
105
- volatile VALUE v;
106
- int buf_size = 0;
107
-
108
- if (Qundef == buffer_size_sym) {
109
- buffer_size_sym = ID2SYM(rb_intern("buffer_size")); rb_gc_register_address(&buffer_size_sym);
110
-
111
- }
112
- if (Qnil != (v = rb_hash_lookup(argv[1], buffer_size_sym))) {
96
+ volatile VALUE v;
97
+ int buf_size = 0;
98
+
99
+ if (Qundef == buffer_size_sym) {
100
+ buffer_size_sym = ID2SYM(rb_intern("buffer_size"));
101
+ rb_gc_register_address(&buffer_size_sym);
102
+ }
103
+ if (Qnil != (v = rb_hash_lookup(argv[1], buffer_size_sym))) {
113
104
  #ifdef RUBY_INTEGER_UNIFICATION
114
- if (rb_cInteger != rb_obj_class(v)) {
115
- rb_raise(rb_eArgError, ":buffer size must be a Integer.");
116
- }
105
+ if (rb_cInteger != rb_obj_class(v)) {
106
+ rb_raise(rb_eArgError, ":buffer size must be a Integer.");
107
+ }
117
108
  #else
118
- if (T_FIXNUM != rb_type(v)) {
119
- rb_raise(rb_eArgError, ":buffer size must be a Integer.");
120
- }
109
+ if (T_FIXNUM != rb_type(v)) {
110
+ rb_raise(rb_eArgError, ":buffer size must be a Integer.");
111
+ }
121
112
  #endif
122
- buf_size = FIX2INT(v);
123
- }
124
- oj_str_writer_init(&sw->sw, buf_size);
125
- oj_parse_options(argv[1], &sw->sw.opts);
126
- sw->flush_limit = buf_size;
113
+ buf_size = FIX2INT(v);
114
+ }
115
+ oj_str_writer_init(&sw->sw, buf_size);
116
+ oj_parse_options(argv[1], &sw->sw.opts);
117
+ sw->flush_limit = buf_size;
127
118
  } else {
128
- oj_str_writer_init(&sw->sw, 4096);
129
- sw->flush_limit = 0;
119
+ oj_str_writer_init(&sw->sw, 4096);
120
+ sw->flush_limit = 0;
130
121
  }
131
122
  sw->sw.out.indent = sw->sw.opts.indent;
132
- sw->stream = stream;
133
- sw->type = type;
134
- sw->fd = fd;
123
+ sw->stream = stream;
124
+ sw->type = type;
125
+ sw->fd = fd;
135
126
 
136
127
  return Data_Wrap_Struct(oj_stream_writer_class, 0, stream_writer_free, sw);
137
128
  }
@@ -145,14 +136,13 @@ stream_writer_new(int argc, VALUE *argv, VALUE self) {
145
136
  *
146
137
  * - *key* [_String_] the key pending for the next push
147
138
  */
148
- static VALUE
149
- stream_writer_push_key(VALUE self, VALUE key) {
150
- StreamWriter sw = (StreamWriter)DATA_PTR(self);
139
+ static VALUE stream_writer_push_key(VALUE self, VALUE key) {
140
+ StreamWriter sw = (StreamWriter)DATA_PTR(self);
151
141
 
152
142
  rb_check_type(key, T_STRING);
153
143
  oj_str_writer_push_key(&sw->sw, StringValuePtr(key));
154
144
  if (sw->flush_limit < sw->sw.out.cur - sw->sw.out.buf) {
155
- stream_writer_write(sw);
145
+ stream_writer_write(sw);
156
146
  }
157
147
  return Qnil;
158
148
  }
@@ -165,28 +155,23 @@ stream_writer_push_key(VALUE self, VALUE key) {
165
155
  *
166
156
  * - *key* [_String_] the key if adding to an object in the JSON document
167
157
  */
168
- static VALUE
169
- stream_writer_push_object(int argc, VALUE *argv, VALUE self) {
170
- StreamWriter sw = (StreamWriter)DATA_PTR(self);
158
+ static VALUE stream_writer_push_object(int argc, VALUE *argv, VALUE self) {
159
+ StreamWriter sw = (StreamWriter)DATA_PTR(self);
171
160
 
172
161
  switch (argc) {
173
- case 0:
174
- oj_str_writer_push_object(&sw->sw, 0);
175
- break;
162
+ case 0: oj_str_writer_push_object(&sw->sw, 0); break;
176
163
  case 1:
177
- if (Qnil == argv[0]) {
178
- oj_str_writer_push_object(&sw->sw, 0);
179
- } else {
180
- rb_check_type(argv[0], T_STRING);
181
- oj_str_writer_push_object(&sw->sw, StringValuePtr(argv[0]));
182
- }
183
- break;
184
- default:
185
- rb_raise(rb_eArgError, "Wrong number of argument to 'push_object'.");
186
- break;
164
+ if (Qnil == argv[0]) {
165
+ oj_str_writer_push_object(&sw->sw, 0);
166
+ } else {
167
+ rb_check_type(argv[0], T_STRING);
168
+ oj_str_writer_push_object(&sw->sw, StringValuePtr(argv[0]));
169
+ }
170
+ break;
171
+ default: rb_raise(rb_eArgError, "Wrong number of argument to 'push_object'."); break;
187
172
  }
188
173
  if (sw->flush_limit < sw->sw.out.cur - sw->sw.out.buf) {
189
- stream_writer_write(sw);
174
+ stream_writer_write(sw);
190
175
  }
191
176
  return Qnil;
192
177
  }
@@ -199,28 +184,23 @@ stream_writer_push_object(int argc, VALUE *argv, VALUE self) {
199
184
  *
200
185
  * - *key* [_String_] the key if adding to an object in the JSON document
201
186
  */
202
- static VALUE
203
- stream_writer_push_array(int argc, VALUE *argv, VALUE self) {
204
- StreamWriter sw = (StreamWriter)DATA_PTR(self);
187
+ static VALUE stream_writer_push_array(int argc, VALUE *argv, VALUE self) {
188
+ StreamWriter sw = (StreamWriter)DATA_PTR(self);
205
189
 
206
190
  switch (argc) {
207
- case 0:
208
- oj_str_writer_push_array(&sw->sw, 0);
209
- break;
191
+ case 0: oj_str_writer_push_array(&sw->sw, 0); break;
210
192
  case 1:
211
- if (Qnil == argv[0]) {
212
- oj_str_writer_push_array(&sw->sw, 0);
213
- } else {
214
- rb_check_type(argv[0], T_STRING);
215
- oj_str_writer_push_array(&sw->sw, StringValuePtr(argv[0]));
216
- }
217
- break;
218
- default:
219
- rb_raise(rb_eArgError, "Wrong number of argument to 'push_object'.");
220
- break;
193
+ if (Qnil == argv[0]) {
194
+ oj_str_writer_push_array(&sw->sw, 0);
195
+ } else {
196
+ rb_check_type(argv[0], T_STRING);
197
+ oj_str_writer_push_array(&sw->sw, StringValuePtr(argv[0]));
198
+ }
199
+ break;
200
+ default: rb_raise(rb_eArgError, "Wrong number of argument to 'push_object'."); break;
221
201
  }
222
202
  if (sw->flush_limit < sw->sw.out.cur - sw->sw.out.buf) {
223
- stream_writer_write(sw);
203
+ stream_writer_write(sw);
224
204
  }
225
205
  return Qnil;
226
206
  }
@@ -232,28 +212,23 @@ stream_writer_push_array(int argc, VALUE *argv, VALUE self) {
232
212
  * - *value* [_Object_] value to add to the JSON document
233
213
  * - *key* [_String_] the key if adding to an object in the JSON document
234
214
  */
235
- static VALUE
236
- stream_writer_push_value(int argc, VALUE *argv, VALUE self) {
237
- StreamWriter sw = (StreamWriter)DATA_PTR(self);
215
+ static VALUE stream_writer_push_value(int argc, VALUE *argv, VALUE self) {
216
+ StreamWriter sw = (StreamWriter)DATA_PTR(self);
238
217
 
239
218
  switch (argc) {
240
- case 1:
241
- oj_str_writer_push_value((StrWriter)DATA_PTR(self), *argv, 0);
242
- break;
219
+ case 1: oj_str_writer_push_value((StrWriter)DATA_PTR(self), *argv, 0); break;
243
220
  case 2:
244
- if (Qnil == argv[1]) {
245
- oj_str_writer_push_value((StrWriter)DATA_PTR(self), *argv, 0);
246
- } else {
247
- rb_check_type(argv[1], T_STRING);
248
- oj_str_writer_push_value((StrWriter)DATA_PTR(self), *argv, StringValuePtr(argv[1]));
249
- }
250
- break;
251
- default:
252
- rb_raise(rb_eArgError, "Wrong number of argument to 'push_value'.");
253
- break;
221
+ if (Qnil == argv[1]) {
222
+ oj_str_writer_push_value((StrWriter)DATA_PTR(self), *argv, 0);
223
+ } else {
224
+ rb_check_type(argv[1], T_STRING);
225
+ oj_str_writer_push_value((StrWriter)DATA_PTR(self), *argv, StringValuePtr(argv[1]));
226
+ }
227
+ break;
228
+ default: rb_raise(rb_eArgError, "Wrong number of argument to 'push_value'."); break;
254
229
  }
255
230
  if (sw->flush_limit < sw->sw.out.cur - sw->sw.out.buf) {
256
- stream_writer_write(sw);
231
+ stream_writer_write(sw);
257
232
  }
258
233
  return Qnil;
259
234
  }
@@ -267,29 +242,26 @@ stream_writer_push_value(int argc, VALUE *argv, VALUE self) {
267
242
  * - *value* [_Object_] value to add to the JSON document
268
243
  * - *key* [_String_] the key if adding to an object in the JSON document
269
244
  */
270
- static VALUE
271
- stream_writer_push_json(int argc, VALUE *argv, VALUE self) {
272
- StreamWriter sw = (StreamWriter)DATA_PTR(self);
245
+ static VALUE stream_writer_push_json(int argc, VALUE *argv, VALUE self) {
246
+ StreamWriter sw = (StreamWriter)DATA_PTR(self);
273
247
 
274
248
  rb_check_type(argv[0], T_STRING);
275
249
  switch (argc) {
276
- case 1:
277
- oj_str_writer_push_json((StrWriter)DATA_PTR(self), StringValuePtr(*argv), 0);
278
- break;
250
+ case 1: oj_str_writer_push_json((StrWriter)DATA_PTR(self), StringValuePtr(*argv), 0); break;
279
251
  case 2:
280
- if (Qnil == argv[1]) {
281
- oj_str_writer_push_json((StrWriter)DATA_PTR(self), StringValuePtr(*argv), 0);
282
- } else {
283
- rb_check_type(argv[1], T_STRING);
284
- oj_str_writer_push_json((StrWriter)DATA_PTR(self), StringValuePtr(*argv), StringValuePtr(argv[1]));
285
- }
286
- break;
287
- default:
288
- rb_raise(rb_eArgError, "Wrong number of argument to 'push_json'.");
289
- break;
252
+ if (Qnil == argv[1]) {
253
+ oj_str_writer_push_json((StrWriter)DATA_PTR(self), StringValuePtr(*argv), 0);
254
+ } else {
255
+ rb_check_type(argv[1], T_STRING);
256
+ oj_str_writer_push_json((StrWriter)DATA_PTR(self),
257
+ StringValuePtr(*argv),
258
+ StringValuePtr(argv[1]));
259
+ }
260
+ break;
261
+ default: rb_raise(rb_eArgError, "Wrong number of argument to 'push_json'."); break;
290
262
  }
291
263
  if (sw->flush_limit < sw->sw.out.cur - sw->sw.out.buf) {
292
- stream_writer_write(sw);
264
+ stream_writer_write(sw);
293
265
  }
294
266
  return Qnil;
295
267
  }
@@ -300,13 +272,12 @@ stream_writer_push_json(int argc, VALUE *argv, VALUE self) {
300
272
  * Pops up a level in the JSON document closing the array or object that is
301
273
  * currently open.
302
274
  */
303
- static VALUE
304
- stream_writer_pop(VALUE self) {
305
- StreamWriter sw = (StreamWriter)DATA_PTR(self);
275
+ static VALUE stream_writer_pop(VALUE self) {
276
+ StreamWriter sw = (StreamWriter)DATA_PTR(self);
306
277
 
307
278
  oj_str_writer_pop(&sw->sw);
308
279
  if (sw->flush_limit < sw->sw.out.cur - sw->sw.out.buf) {
309
- stream_writer_write(sw);
280
+ stream_writer_write(sw);
310
281
  }
311
282
  return Qnil;
312
283
  }
@@ -317,9 +288,8 @@ stream_writer_pop(VALUE self) {
317
288
  * Pops all level in the JSON document closing all the array or object that is
318
289
  * currently open.
319
290
  */
320
- static VALUE
321
- stream_writer_pop_all(VALUE self) {
322
- StreamWriter sw = (StreamWriter)DATA_PTR(self);
291
+ static VALUE stream_writer_pop_all(VALUE self) {
292
+ StreamWriter sw = (StreamWriter)DATA_PTR(self);
323
293
 
324
294
  oj_str_writer_pop_all(&sw->sw);
325
295
  stream_writer_write(sw);
@@ -332,22 +302,20 @@ stream_writer_pop_all(VALUE self) {
332
302
  *
333
303
  * Flush any remaining characters in the buffer.
334
304
  */
335
- static VALUE
336
- stream_writer_flush(VALUE self) {
305
+ static VALUE stream_writer_flush(VALUE self) {
337
306
  stream_writer_write((StreamWriter)DATA_PTR(self));
338
307
 
339
308
  return Qnil;
340
309
  }
341
310
 
342
311
  /* Document-class: Oj::StreamWriter
343
- *
312
+ *
344
313
  * Supports building a JSON document one element at a time. Build the IO stream
345
314
  * document by pushing values into the document. Pushing an array or an object
346
315
  * will create that element in the JSON document and subsequent pushes will add
347
316
  * the elements to that array or object until a pop() is called.
348
317
  */
349
- void
350
- oj_stream_writer_init() {
318
+ void oj_stream_writer_init() {
351
319
  oj_stream_writer_class = rb_define_class_under(Oj, "StreamWriter", rb_cObject);
352
320
  rb_define_module_function(oj_stream_writer_class, "new", stream_writer_new, -1);
353
321
  rb_define_method(oj_stream_writer_class, "push_key", stream_writer_push_key, 1);
@@ -359,5 +327,3 @@ oj_stream_writer_init() {
359
327
  rb_define_method(oj_stream_writer_class, "pop_all", stream_writer_pop_all, 0);
360
328
  rb_define_method(oj_stream_writer_class, "flush", stream_writer_flush, 0);
361
329
  }
362
-
363
-
data/ext/oj/strict.c CHANGED
@@ -1,210 +1,237 @@
1
- /* strict.c
2
- * Copyright (c) 2012, Peter Ohler
3
- * All rights reserved.
4
- */
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.
5
3
 
6
- #include <stdlib.h>
7
4
  #include <stdio.h>
5
+ #include <stdlib.h>
8
6
  #include <string.h>
9
7
  #include <unistd.h>
10
8
 
11
- #include "oj.h"
9
+ #include "encode.h"
12
10
  #include "err.h"
11
+ #include "hash.h"
12
+ #include "oj.h"
13
13
  #include "parse.h"
14
- #include "encode.h"
15
14
  #include "trace.h"
16
15
 
17
- static void
18
- hash_end(ParseInfo pi) {
16
+ VALUE oj_cstr_to_value(const char *str, size_t len, size_t cache_str) {
17
+ volatile VALUE rstr = Qnil;
18
+
19
+ if (len <= cache_str) {
20
+ VALUE *slot;
21
+
22
+ if (Qnil == (rstr = oj_str_hash_get(str, len, &slot))) {
23
+ rstr = rb_str_new(str, len);
24
+ rstr = oj_encode(rstr);
25
+ *slot = rstr;
26
+ rb_gc_register_address(slot);
27
+ }
28
+ } else {
29
+ rstr = rb_str_new(str, len);
30
+ rstr = oj_encode(rstr);
31
+ }
32
+ return rstr;
33
+ }
34
+
35
+ VALUE oj_calc_hash_key(ParseInfo pi, Val parent) {
36
+ volatile VALUE rkey = parent->key_val;
37
+
38
+ if (Qundef != rkey) {
39
+ return rkey;
40
+ }
41
+ if (Yes != pi->options.cache_keys) {
42
+ rkey = rb_str_new(parent->key, parent->klen);
43
+ rkey = oj_encode(rkey);
44
+ if (Yes == pi->options.sym_key) {
45
+ rkey = rb_str_intern(rkey);
46
+ }
47
+ return rkey;
48
+ }
49
+ VALUE *slot;
50
+
51
+ if (Yes == pi->options.sym_key) {
52
+ if (Qnil == (rkey = oj_sym_hash_get(parent->key, parent->klen, &slot))) {
53
+ rkey = rb_str_new(parent->key, parent->klen);
54
+ rkey = oj_encode(rkey);
55
+ rkey = rb_str_intern(rkey);
56
+ *slot = rkey;
57
+ rb_gc_register_address(slot);
58
+ }
59
+ } else {
60
+ if (Qnil == (rkey = oj_str_hash_get(parent->key, parent->klen, &slot))) {
61
+ rkey = rb_str_new(parent->key, parent->klen);
62
+ rkey = oj_encode(rkey);
63
+ *slot = rkey;
64
+ rb_gc_register_address(slot);
65
+ }
66
+ }
67
+ return rkey;
68
+ }
69
+
70
+ static void hash_end(ParseInfo pi) {
19
71
  if (Yes == pi->options.trace) {
20
- oj_trace_parse_hash_end(pi, __FILE__, __LINE__);
72
+ oj_trace_parse_hash_end(pi, __FILE__, __LINE__);
21
73
  }
22
74
  }
23
75
 
24
- static void
25
- array_end(ParseInfo pi) {
76
+ static void array_end(ParseInfo pi) {
26
77
  if (Yes == pi->options.trace) {
27
- oj_trace_parse_array_end(pi, __FILE__, __LINE__);
78
+ oj_trace_parse_array_end(pi, __FILE__, __LINE__);
28
79
  }
29
80
  }
30
81
 
31
- static VALUE
32
- noop_hash_key(ParseInfo pi, const char *key, size_t klen) {
82
+ static VALUE noop_hash_key(ParseInfo pi, const char *key, size_t klen) {
33
83
  return Qundef;
34
84
  }
35
85
 
36
- static void
37
- add_value(ParseInfo pi, VALUE val) {
86
+ static void add_value(ParseInfo pi, VALUE val) {
38
87
  if (Yes == pi->options.trace) {
39
- oj_trace_parse_call("add_value", pi, __FILE__, __LINE__, val);
88
+ oj_trace_parse_call("add_value", pi, __FILE__, __LINE__, val);
40
89
  }
41
90
  pi->stack.head->val = val;
42
91
  }
43
92
 
44
- static void
45
- add_cstr(ParseInfo pi, const char *str, size_t len, const char *orig) {
46
- volatile VALUE rstr = rb_str_new(str, len);
93
+ static void add_cstr(ParseInfo pi, const char *str, size_t len, const char *orig) {
94
+ volatile VALUE rstr = oj_cstr_to_value(str, len, (size_t)pi->options.cache_str);
47
95
 
48
- rstr = oj_encode(rstr);
49
96
  pi->stack.head->val = rstr;
50
97
  if (Yes == pi->options.trace) {
51
- oj_trace_parse_call("add_string", pi, __FILE__, __LINE__, rstr);
98
+ oj_trace_parse_call("add_string", pi, __FILE__, __LINE__, rstr);
52
99
  }
53
100
  }
54
101
 
55
- static void
56
- add_num(ParseInfo pi, NumInfo ni) {
102
+ static void add_num(ParseInfo pi, NumInfo ni) {
57
103
  if (ni->infinity || ni->nan) {
58
- oj_set_error_at(pi, oj_parse_error_class, __FILE__, __LINE__, "not a number or other value");
104
+ oj_set_error_at(pi, oj_parse_error_class, __FILE__, __LINE__, "not a number or other value");
59
105
  }
60
106
  pi->stack.head->val = oj_num_as_value(ni);
61
107
  if (Yes == pi->options.trace) {
62
- oj_trace_parse_call("add_number", pi, __FILE__, __LINE__, pi->stack.head->val);
108
+ oj_trace_parse_call("add_number", pi, __FILE__, __LINE__, pi->stack.head->val);
63
109
  }
64
110
  }
65
111
 
66
- static VALUE
67
- start_hash(ParseInfo pi) {
112
+ static VALUE start_hash(ParseInfo pi) {
68
113
  if (Qnil != pi->options.hash_class) {
69
- return rb_class_new_instance(0, NULL, pi->options.hash_class);
114
+ return rb_class_new_instance(0, NULL, pi->options.hash_class);
70
115
  }
71
116
  if (Yes == pi->options.trace) {
72
- oj_trace_parse_in("start_hash", pi, __FILE__, __LINE__);
117
+ oj_trace_parse_in("start_hash", pi, __FILE__, __LINE__);
73
118
  }
74
119
  return rb_hash_new();
75
120
  }
76
121
 
77
- static VALUE
78
- calc_hash_key(ParseInfo pi, Val parent) {
79
- volatile VALUE rkey = parent->key_val;
122
+ static void hash_set_cstr(ParseInfo pi, Val parent, const char *str, size_t len, const char *orig) {
123
+ volatile VALUE rstr = oj_cstr_to_value(str, len, (size_t)pi->options.cache_str);
80
124
 
81
- if (Qundef == rkey) {
82
- rkey = rb_str_new(parent->key, parent->klen);
83
- }
84
- rkey = oj_encode(rkey);
85
- if (Yes == pi->options.sym_key) {
86
- rkey = rb_str_intern(rkey);
87
- }
88
- return rkey;
89
- }
90
-
91
- static void
92
- hash_set_cstr(ParseInfo pi, Val parent, const char *str, size_t len, const char *orig) {
93
- volatile VALUE rstr = rb_str_new(str, len);
94
-
95
- rstr = oj_encode(rstr);
96
- rb_hash_aset(stack_peek(&pi->stack)->val, calc_hash_key(pi, parent), rstr);
125
+ rb_hash_aset(stack_peek(&pi->stack)->val,
126
+ oj_calc_hash_key(pi, parent),
127
+ rstr);
97
128
  if (Yes == pi->options.trace) {
98
- oj_trace_parse_call("set_string", pi, __FILE__, __LINE__, rstr);
129
+ oj_trace_parse_call("set_string", pi, __FILE__, __LINE__, rstr);
99
130
  }
100
131
  }
101
132
 
102
- static void
103
- hash_set_num(ParseInfo pi, Val parent, NumInfo ni) {
104
- volatile VALUE v;
105
-
133
+ static void hash_set_num(ParseInfo pi, Val parent, NumInfo ni) {
134
+ volatile VALUE v;
135
+
106
136
  if (ni->infinity || ni->nan) {
107
- oj_set_error_at(pi, oj_parse_error_class, __FILE__, __LINE__, "not a number or other value");
137
+ oj_set_error_at(pi, oj_parse_error_class, __FILE__, __LINE__, "not a number or other value");
108
138
  }
109
139
  v = oj_num_as_value(ni);
110
- rb_hash_aset(stack_peek(&pi->stack)->val, calc_hash_key(pi, parent), v);
140
+ rb_hash_aset(stack_peek(&pi->stack)->val,
141
+ oj_calc_hash_key(pi, parent),
142
+ v);
111
143
  if (Yes == pi->options.trace) {
112
- oj_trace_parse_call("set_number", pi, __FILE__, __LINE__, v);
144
+ oj_trace_parse_call("set_number", pi, __FILE__, __LINE__, v);
113
145
  }
114
146
  }
115
147
 
116
- static void
117
- hash_set_value(ParseInfo pi, Val parent, VALUE value) {
118
- rb_hash_aset(stack_peek(&pi->stack)->val, calc_hash_key(pi, parent), value);
148
+ static void hash_set_value(ParseInfo pi, Val parent, VALUE value) {
149
+ rb_hash_aset(stack_peek(&pi->stack)->val,
150
+ oj_calc_hash_key(pi, parent),
151
+ value);
119
152
  if (Yes == pi->options.trace) {
120
- oj_trace_parse_call("set_value", pi, __FILE__, __LINE__, value);
153
+ oj_trace_parse_call("set_value", pi, __FILE__, __LINE__, value);
121
154
  }
122
155
  }
123
156
 
124
- static VALUE
125
- start_array(ParseInfo pi) {
157
+ static VALUE start_array(ParseInfo pi) {
126
158
  if (Yes == pi->options.trace) {
127
- oj_trace_parse_in("start_array", pi, __FILE__, __LINE__);
159
+ oj_trace_parse_in("start_array", pi, __FILE__, __LINE__);
128
160
  }
129
161
  return rb_ary_new();
130
162
  }
131
163
 
132
- static void
133
- array_append_cstr(ParseInfo pi, const char *str, size_t len, const char *orig) {
134
- volatile VALUE rstr = rb_str_new(str, len);
164
+ static void array_append_cstr(ParseInfo pi, const char *str, size_t len, const char *orig) {
165
+ volatile VALUE rstr = oj_cstr_to_value(str, len, (size_t)pi->options.cache_str);
135
166
 
136
- rstr = oj_encode(rstr);
137
167
  rb_ary_push(stack_peek(&pi->stack)->val, rstr);
138
168
  if (Yes == pi->options.trace) {
139
- oj_trace_parse_call("append_string", pi, __FILE__, __LINE__, rstr);
169
+ oj_trace_parse_call("append_string", pi, __FILE__, __LINE__, rstr);
140
170
  }
141
171
  }
142
172
 
143
- static void
144
- array_append_num(ParseInfo pi, NumInfo ni) {
145
- volatile VALUE v;
146
-
173
+ static void array_append_num(ParseInfo pi, NumInfo ni) {
174
+ volatile VALUE v;
175
+
147
176
  if (ni->infinity || ni->nan) {
148
- oj_set_error_at(pi, oj_parse_error_class, __FILE__, __LINE__, "not a number or other value");
177
+ oj_set_error_at(pi, oj_parse_error_class, __FILE__, __LINE__, "not a number or other value");
149
178
  }
150
179
  v = oj_num_as_value(ni);
151
180
  rb_ary_push(stack_peek(&pi->stack)->val, v);
152
181
  if (Yes == pi->options.trace) {
153
- oj_trace_parse_call("append_number", pi, __FILE__, __LINE__, v);
182
+ oj_trace_parse_call("append_number", pi, __FILE__, __LINE__, v);
154
183
  }
155
184
  }
156
185
 
157
- static void
158
- array_append_value(ParseInfo pi, VALUE value) {
186
+ static void array_append_value(ParseInfo pi, VALUE value) {
159
187
  rb_ary_push(stack_peek(&pi->stack)->val, value);
160
188
  if (Yes == pi->options.trace) {
161
- oj_trace_parse_call("append_value", pi, __FILE__, __LINE__, value);
162
- }
163
- }
164
-
165
- void
166
- oj_set_strict_callbacks(ParseInfo pi) {
167
- pi->start_hash = start_hash;
168
- pi->end_hash = hash_end;
169
- pi->hash_key = noop_hash_key;
170
- pi->hash_set_cstr = hash_set_cstr;
171
- pi->hash_set_num = hash_set_num;
172
- pi->hash_set_value = hash_set_value;
173
- pi->start_array = start_array;
174
- pi->end_array = array_end;
175
- pi->array_append_cstr = array_append_cstr;
176
- pi->array_append_num = array_append_num;
189
+ oj_trace_parse_call("append_value", pi, __FILE__, __LINE__, value);
190
+ }
191
+ }
192
+
193
+ void oj_set_strict_callbacks(ParseInfo pi) {
194
+ pi->start_hash = start_hash;
195
+ pi->end_hash = hash_end;
196
+ pi->hash_key = noop_hash_key;
197
+ pi->hash_set_cstr = hash_set_cstr;
198
+ pi->hash_set_num = hash_set_num;
199
+ pi->hash_set_value = hash_set_value;
200
+ pi->start_array = start_array;
201
+ pi->end_array = array_end;
202
+ pi->array_append_cstr = array_append_cstr;
203
+ pi->array_append_num = array_append_num;
177
204
  pi->array_append_value = array_append_value;
178
- pi->add_cstr = add_cstr;
179
- pi->add_num = add_num;
180
- pi->add_value = add_value;
181
- pi->expect_value = 1;
205
+ pi->add_cstr = add_cstr;
206
+ pi->add_num = add_num;
207
+ pi->add_value = add_value;
208
+ pi->expect_value = 1;
182
209
  }
183
210
 
184
211
  VALUE
185
212
  oj_strict_parse(int argc, VALUE *argv, VALUE self) {
186
- struct _parseInfo pi;
213
+ struct _parseInfo pi;
187
214
 
188
215
  parse_info_init(&pi);
189
- pi.options = oj_default_options;
190
- pi.handler = Qnil;
216
+ pi.options = oj_default_options;
217
+ pi.handler = Qnil;
191
218
  pi.err_class = Qnil;
192
219
  oj_set_strict_callbacks(&pi);
193
220
 
194
221
  if (T_STRING == rb_type(*argv)) {
195
- return oj_pi_parse(argc, argv, &pi, 0, 0, true);
222
+ return oj_pi_parse(argc, argv, &pi, 0, 0, true);
196
223
  } else {
197
- return oj_pi_sparse(argc, argv, &pi, 0);
224
+ return oj_pi_sparse(argc, argv, &pi, 0);
198
225
  }
199
226
  }
200
227
 
201
228
  VALUE
202
229
  oj_strict_parse_cstr(int argc, VALUE *argv, char *json, size_t len) {
203
- struct _parseInfo pi;
230
+ struct _parseInfo pi;
204
231
 
205
232
  parse_info_init(&pi);
206
- pi.options = oj_default_options;
207
- pi.handler = Qnil;
233
+ pi.options = oj_default_options;
234
+ pi.handler = Qnil;
208
235
  pi.err_class = Qnil;
209
236
  oj_set_strict_callbacks(&pi);
210
237