oj 3.10.6 → 3.12.1

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