oj 3.13.17 → 3.16.3

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 (156) hide show
  1. checksums.yaml +4 -4
  2. data/CHANGELOG.md +77 -0
  3. data/README.md +4 -2
  4. data/ext/oj/buf.h +7 -6
  5. data/ext/oj/cache.c +29 -26
  6. data/ext/oj/cache.h +3 -2
  7. data/ext/oj/cache8.c +10 -9
  8. data/ext/oj/circarray.c +7 -5
  9. data/ext/oj/circarray.h +2 -2
  10. data/ext/oj/code.c +5 -12
  11. data/ext/oj/code.h +2 -2
  12. data/ext/oj/compat.c +20 -60
  13. data/ext/oj/custom.c +44 -96
  14. data/ext/oj/debug.c +3 -9
  15. data/ext/oj/dump.c +69 -39
  16. data/ext/oj/dump.h +1 -4
  17. data/ext/oj/dump_compat.c +557 -592
  18. data/ext/oj/dump_leaf.c +3 -5
  19. data/ext/oj/dump_object.c +42 -48
  20. data/ext/oj/dump_strict.c +10 -22
  21. data/ext/oj/encoder.c +1 -1
  22. data/ext/oj/err.c +2 -13
  23. data/ext/oj/err.h +9 -12
  24. data/ext/oj/extconf.rb +16 -6
  25. data/ext/oj/fast.c +76 -106
  26. data/ext/oj/intern.c +63 -51
  27. data/ext/oj/intern.h +3 -7
  28. data/ext/oj/mem.c +318 -0
  29. data/ext/oj/mem.h +53 -0
  30. data/ext/oj/mimic_json.c +43 -30
  31. data/ext/oj/object.c +61 -70
  32. data/ext/oj/odd.c +8 -6
  33. data/ext/oj/odd.h +4 -4
  34. data/ext/oj/oj.c +243 -205
  35. data/ext/oj/oj.h +82 -78
  36. data/ext/oj/parse.c +123 -188
  37. data/ext/oj/parse.h +23 -24
  38. data/ext/oj/parser.c +103 -63
  39. data/ext/oj/parser.h +19 -9
  40. data/ext/oj/rails.c +68 -92
  41. data/ext/oj/reader.c +10 -15
  42. data/ext/oj/reader.h +4 -2
  43. data/ext/oj/resolve.c +3 -4
  44. data/ext/oj/rxclass.c +6 -5
  45. data/ext/oj/rxclass.h +1 -1
  46. data/ext/oj/saj.c +10 -9
  47. data/ext/oj/saj2.c +74 -92
  48. data/ext/oj/saj2.h +23 -0
  49. data/ext/oj/scp.c +3 -14
  50. data/ext/oj/sparse.c +22 -70
  51. data/ext/oj/stream_writer.c +43 -35
  52. data/ext/oj/strict.c +20 -52
  53. data/ext/oj/string_writer.c +60 -34
  54. data/ext/oj/trace.h +31 -4
  55. data/ext/oj/usual.c +125 -150
  56. data/ext/oj/usual.h +69 -0
  57. data/ext/oj/util.h +1 -1
  58. data/ext/oj/val_stack.c +14 -3
  59. data/ext/oj/val_stack.h +8 -7
  60. data/ext/oj/wab.c +25 -57
  61. data/lib/oj/active_support_helper.rb +1 -3
  62. data/lib/oj/bag.rb +7 -1
  63. data/lib/oj/easy_hash.rb +4 -5
  64. data/lib/oj/error.rb +0 -1
  65. data/lib/oj/json.rb +162 -150
  66. data/lib/oj/mimic.rb +6 -2
  67. data/lib/oj/state.rb +9 -6
  68. data/lib/oj/version.rb +1 -2
  69. data/lib/oj.rb +2 -0
  70. data/pages/Compatibility.md +1 -1
  71. data/pages/InstallOptions.md +20 -0
  72. data/pages/Options.md +10 -0
  73. data/test/_test_active.rb +8 -9
  74. data/test/_test_active_mimic.rb +7 -8
  75. data/test/_test_mimic_rails.rb +17 -20
  76. data/test/activerecord/result_test.rb +5 -6
  77. data/test/files.rb +15 -15
  78. data/test/foo.rb +9 -72
  79. data/test/helper.rb +11 -8
  80. data/test/isolated/shared.rb +3 -2
  81. data/test/json_gem/json_addition_test.rb +2 -2
  82. data/test/json_gem/json_common_interface_test.rb +8 -6
  83. data/test/json_gem/json_encoding_test.rb +0 -0
  84. data/test/json_gem/json_ext_parser_test.rb +1 -0
  85. data/test/json_gem/json_fixtures_test.rb +3 -2
  86. data/test/json_gem/json_generator_test.rb +53 -37
  87. data/test/json_gem/json_generic_object_test.rb +11 -11
  88. data/test/json_gem/json_parser_test.rb +47 -47
  89. data/test/json_gem/json_string_matching_test.rb +9 -9
  90. data/test/json_gem/test_helper.rb +7 -3
  91. data/test/mem.rb +13 -12
  92. data/test/perf.rb +21 -26
  93. data/test/perf_compat.rb +31 -33
  94. data/test/perf_dump.rb +28 -28
  95. data/test/perf_fast.rb +80 -82
  96. data/test/perf_file.rb +27 -29
  97. data/test/perf_object.rb +65 -69
  98. data/test/perf_once.rb +12 -11
  99. data/test/perf_parser.rb +42 -48
  100. data/test/perf_saj.rb +46 -54
  101. data/test/perf_scp.rb +57 -69
  102. data/test/perf_simple.rb +41 -39
  103. data/test/perf_strict.rb +68 -70
  104. data/test/perf_wab.rb +67 -69
  105. data/test/prec.rb +5 -5
  106. data/test/sample/change.rb +0 -1
  107. data/test/sample/dir.rb +0 -1
  108. data/test/sample/doc.rb +0 -1
  109. data/test/sample/file.rb +0 -1
  110. data/test/sample/group.rb +0 -1
  111. data/test/sample/hasprops.rb +0 -1
  112. data/test/sample/layer.rb +0 -1
  113. data/test/sample/rect.rb +0 -1
  114. data/test/sample/shape.rb +0 -1
  115. data/test/sample/text.rb +0 -1
  116. data/test/sample.rb +16 -16
  117. data/test/sample_json.rb +8 -8
  118. data/test/test_compat.rb +80 -53
  119. data/test/test_custom.rb +73 -51
  120. data/test/test_debian.rb +7 -10
  121. data/test/test_fast.rb +86 -90
  122. data/test/test_file.rb +28 -35
  123. data/test/test_gc.rb +16 -5
  124. data/test/test_generate.rb +5 -5
  125. data/test/test_hash.rb +4 -4
  126. data/test/test_integer_range.rb +9 -9
  127. data/test/test_null.rb +20 -20
  128. data/test/test_object.rb +94 -96
  129. data/test/test_parser.rb +6 -22
  130. data/test/test_parser_debug.rb +27 -0
  131. data/test/test_parser_saj.rb +61 -22
  132. data/test/test_parser_usual.rb +16 -6
  133. data/test/test_rails.rb +2 -2
  134. data/test/test_saj.rb +10 -8
  135. data/test/test_scp.rb +37 -39
  136. data/test/test_strict.rb +40 -32
  137. data/test/test_various.rb +148 -100
  138. data/test/test_wab.rb +48 -44
  139. data/test/test_writer.rb +47 -47
  140. data/test/tests.rb +13 -4
  141. data/test/tests_mimic.rb +12 -3
  142. data/test/tests_mimic_addition.rb +12 -3
  143. metadata +36 -27
  144. data/test/activesupport4/decoding_test.rb +0 -108
  145. data/test/activesupport4/encoding_test.rb +0 -531
  146. data/test/activesupport4/test_helper.rb +0 -41
  147. data/test/activesupport5/abstract_unit.rb +0 -45
  148. data/test/activesupport5/decoding_test.rb +0 -133
  149. data/test/activesupport5/encoding_test.rb +0 -500
  150. data/test/activesupport5/encoding_test_cases.rb +0 -98
  151. data/test/activesupport5/test_helper.rb +0 -72
  152. data/test/activesupport5/time_zone_test_helpers.rb +0 -39
  153. data/test/bar.rb +0 -11
  154. data/test/baz.rb +0 -16
  155. data/test/bug.rb +0 -16
  156. data/test/zoo.rb +0 -13
data/ext/oj/usual.c CHANGED
@@ -1,6 +1,9 @@
1
1
  // Copyright (c) 2021, Peter Ohler, All rights reserved.
2
2
 
3
+ #include "usual.h"
4
+
3
5
  #include "cache.h"
6
+ #include "mem.h"
4
7
  #include "oj.h"
5
8
  #include "parser.h"
6
9
 
@@ -28,67 +31,12 @@
28
31
 
29
32
  #define DEBUG 0
30
33
 
31
- // Used to mark the start of each Hash, Array, or Object. The members point at
32
- // positions of the start in the value stack and if not an Array into the key
33
- // stack.
34
- typedef struct _col {
35
- long vi; // value stack index
36
- long ki; // key stack index if an hash else -1 for an array
37
- } * Col;
38
-
39
- typedef union _key {
40
- struct {
41
- int16_t len;
42
- char buf[30];
43
- };
44
- struct {
45
- int16_t xlen; // should be the same as len
46
- char * key;
47
- };
48
- } * Key;
49
-
50
- #define MISS_AUTO 'A'
51
- #define MISS_RAISE 'R'
52
- #define MISS_IGNORE 'I'
53
-
54
- typedef struct _delegate {
55
- VALUE *vhead;
56
- VALUE *vtail;
57
- VALUE *vend;
58
-
59
- Col chead;
60
- Col ctail;
61
- Col cend;
62
-
63
- Key khead;
64
- Key ktail;
65
- Key kend;
66
-
67
- VALUE (*get_key)(ojParser p, Key kp);
68
- struct _cache *key_cache; // same as str_cache or sym_cache
69
- struct _cache *str_cache;
70
- struct _cache *sym_cache;
71
- struct _cache *class_cache;
72
- struct _cache *attr_cache;
73
-
74
- VALUE array_class;
75
- VALUE hash_class;
76
-
77
- char * create_id;
78
- uint8_t create_id_len;
79
- uint8_t cache_str;
80
- uint8_t cache_xrate;
81
- uint8_t miss_class;
82
- bool cache_keys;
83
- bool ignore_json_create;
84
- } * Delegate;
85
-
86
34
  static ID to_f_id = 0;
87
35
  static ID ltlt_id = 0;
88
36
  static ID hset_id = 0;
89
37
 
90
38
  static char *str_dup(const char *s, size_t len) {
91
- char *d = ALLOC_N(char, len + 1);
39
+ char *d = OJ_R_ALLOC_N(char, len + 1);
92
40
 
93
41
  memcpy(d, s, len);
94
42
  d[len] = '\0';
@@ -108,7 +56,7 @@ static VALUE form_attr(const char *str, size_t len) {
108
56
  char buf[256];
109
57
 
110
58
  if (sizeof(buf) - 2 <= len) {
111
- char *b = ALLOC_N(char, len + 2);
59
+ char *b = OJ_R_ALLOC_N(char, len + 2);
112
60
  ID id;
113
61
 
114
62
  *b = '@';
@@ -116,7 +64,7 @@ static VALUE form_attr(const char *str, size_t len) {
116
64
  b[len + 1] = '\0';
117
65
 
118
66
  id = rb_intern3(buf, len + 1, oj_utf8_encoding);
119
- xfree(b);
67
+ OJ_R_FREE(b);
120
68
  return id;
121
69
  }
122
70
  *buf = '@';
@@ -143,8 +91,8 @@ static VALUE resolve_classname(VALUE mod, const char *classname, bool auto_defin
143
91
  static VALUE resolve_classpath(const char *name, size_t len, bool auto_define) {
144
92
  char class_name[1024];
145
93
  VALUE clas;
146
- char * end = class_name + sizeof(class_name) - 1;
147
- char * s;
94
+ char *end = class_name + sizeof(class_name) - 1;
95
+ char *s;
148
96
  const char *n = name;
149
97
 
150
98
  clas = rb_cObject;
@@ -178,27 +126,27 @@ static VALUE form_class_auto(const char *str, size_t len) {
178
126
  return resolve_classpath(str, len, true);
179
127
  }
180
128
 
181
- static void assure_cstack(Delegate d) {
129
+ static void assure_cstack(Usual d) {
182
130
  if (d->cend <= d->ctail + 1) {
183
131
  size_t cap = d->cend - d->chead;
184
132
  long pos = d->ctail - d->chead;
185
133
 
186
134
  cap *= 2;
187
- REALLOC_N(d->chead, struct _col, cap);
135
+ OJ_R_REALLOC_N(d->chead, struct _col, cap);
188
136
  d->ctail = d->chead + pos;
189
137
  d->cend = d->chead + cap;
190
138
  }
191
139
  }
192
140
 
193
141
  static void push(ojParser p, VALUE v) {
194
- Delegate d = (Delegate)p->ctx;
142
+ Usual d = (Usual)p->ctx;
195
143
 
196
144
  if (d->vend <= d->vtail) {
197
145
  size_t cap = d->vend - d->vhead;
198
146
  long pos = d->vtail - d->vhead;
199
147
 
200
148
  cap *= 2;
201
- REALLOC_N(d->vhead, VALUE, cap);
149
+ OJ_R_REALLOC_N(d->vhead, VALUE, cap);
202
150
  d->vtail = d->vhead + pos;
203
151
  d->vend = d->vhead + cap;
204
152
  }
@@ -207,7 +155,7 @@ static void push(ojParser p, VALUE v) {
207
155
  }
208
156
 
209
157
  static VALUE cache_key(ojParser p, Key kp) {
210
- Delegate d = (Delegate)p->ctx;
158
+ Usual d = (Usual)p->ctx;
211
159
 
212
160
  if ((size_t)kp->len < sizeof(kp->buf)) {
213
161
  return cache_intern(d->key_cache, kp->buf, kp->len);
@@ -230,7 +178,7 @@ static VALUE sym_key(ojParser p, Key kp) {
230
178
  }
231
179
 
232
180
  static ID get_attr_id(ojParser p, Key kp) {
233
- Delegate d = (Delegate)p->ctx;
181
+ Usual d = (Usual)p->ctx;
234
182
 
235
183
  if ((size_t)kp->len < sizeof(kp->buf)) {
236
184
  return (ID)cache_intern(d->attr_cache, kp->buf, kp->len);
@@ -239,7 +187,7 @@ static ID get_attr_id(ojParser p, Key kp) {
239
187
  }
240
188
 
241
189
  static void push_key(ojParser p) {
242
- Delegate d = (Delegate)p->ctx;
190
+ Usual d = (Usual)p->ctx;
243
191
  size_t klen = buf_len(&p->key);
244
192
  const char *key = buf_str(&p->key);
245
193
 
@@ -248,7 +196,7 @@ static void push_key(ojParser p) {
248
196
  long pos = d->ktail - d->khead;
249
197
 
250
198
  cap *= 2;
251
- REALLOC_N(d->khead, union _key, cap);
199
+ OJ_R_REALLOC_N(d->khead, union _key, cap);
252
200
  d->ktail = d->khead + pos;
253
201
  d->kend = d->khead + cap;
254
202
  }
@@ -263,14 +211,14 @@ static void push_key(ojParser p) {
263
211
  }
264
212
 
265
213
  static void push2(ojParser p, VALUE v) {
266
- Delegate d = (Delegate)p->ctx;
214
+ Usual d = (Usual)p->ctx;
267
215
 
268
216
  if (d->vend <= d->vtail + 1) {
269
217
  size_t cap = d->vend - d->vhead;
270
218
  long pos = d->vtail - d->vhead;
271
219
 
272
220
  cap *= 2;
273
- REALLOC_N(d->vhead, VALUE, cap);
221
+ OJ_R_REALLOC_N(d->vhead, VALUE, cap);
274
222
  d->vtail = d->vhead + pos;
275
223
  d->vend = d->vhead + cap;
276
224
  }
@@ -281,7 +229,7 @@ static void push2(ojParser p, VALUE v) {
281
229
  }
282
230
 
283
231
  static void open_object(ojParser p) {
284
- Delegate d = (Delegate)p->ctx;
232
+ Usual d = (Usual)p->ctx;
285
233
 
286
234
  assure_cstack(d);
287
235
  d->ctail->vi = d->vtail - d->vhead;
@@ -291,7 +239,7 @@ static void open_object(ojParser p) {
291
239
  }
292
240
 
293
241
  static void open_object_key(ojParser p) {
294
- Delegate d = (Delegate)p->ctx;
242
+ Usual d = (Usual)p->ctx;
295
243
 
296
244
  push_key(p);
297
245
  assure_cstack(d);
@@ -302,7 +250,7 @@ static void open_object_key(ojParser p) {
302
250
  }
303
251
 
304
252
  static void open_array(ojParser p) {
305
- Delegate d = (Delegate)p->ctx;
253
+ Usual d = (Usual)p->ctx;
306
254
 
307
255
  assure_cstack(d);
308
256
  d->ctail->vi = d->vtail - d->vhead;
@@ -312,7 +260,7 @@ static void open_array(ojParser p) {
312
260
  }
313
261
 
314
262
  static void open_array_key(ojParser p) {
315
- Delegate d = (Delegate)p->ctx;
263
+ Usual d = (Usual)p->ctx;
316
264
 
317
265
  push_key(p);
318
266
  assure_cstack(d);
@@ -323,21 +271,21 @@ static void open_array_key(ojParser p) {
323
271
  }
324
272
 
325
273
  static void close_object(ojParser p) {
326
- VALUE * vp;
327
- Delegate d = (Delegate)p->ctx;
274
+ VALUE *vp;
275
+ Usual d = (Usual)p->ctx;
328
276
 
329
277
  d->ctail--;
330
278
 
331
279
  Col c = d->ctail;
332
280
  Key kp = d->khead + c->ki;
333
- VALUE * head = d->vhead + c->vi + 1;
281
+ VALUE *head = d->vhead + c->vi + 1;
334
282
  volatile VALUE obj = rb_hash_new();
335
283
 
336
284
  #if HAVE_RB_HASH_BULK_INSERT
337
285
  for (vp = head; kp < d->ktail; kp++, vp += 2) {
338
286
  *vp = d->get_key(p, kp);
339
287
  if (sizeof(kp->buf) <= (size_t)kp->len) {
340
- xfree(kp->key);
288
+ OJ_R_FREE(kp->key);
341
289
  }
342
290
  }
343
291
  rb_hash_bulk_insert(d->vtail - head, head, obj);
@@ -345,7 +293,7 @@ static void close_object(ojParser p) {
345
293
  for (vp = head; kp < d->ktail; kp++, vp += 2) {
346
294
  rb_hash_aset(obj, d->get_key(p, kp), *(vp + 1));
347
295
  if (sizeof(kp->buf) <= (size_t)kp->len) {
348
- xfree(kp->key);
296
+ OJ_R_FREE(kp->key);
349
297
  }
350
298
  }
351
299
  #endif
@@ -356,20 +304,20 @@ static void close_object(ojParser p) {
356
304
  }
357
305
 
358
306
  static void close_object_class(ojParser p) {
359
- VALUE * vp;
360
- Delegate d = (Delegate)p->ctx;
307
+ VALUE *vp;
308
+ Usual d = (Usual)p->ctx;
361
309
 
362
310
  d->ctail--;
363
311
 
364
312
  Col c = d->ctail;
365
313
  Key kp = d->khead + c->ki;
366
- VALUE * head = d->vhead + c->vi + 1;
314
+ VALUE *head = d->vhead + c->vi + 1;
367
315
  volatile VALUE obj = rb_class_new_instance(0, NULL, d->hash_class);
368
316
 
369
317
  for (vp = head; kp < d->ktail; kp++, vp += 2) {
370
318
  rb_funcall(obj, hset_id, 2, d->get_key(p, kp), *(vp + 1));
371
319
  if (sizeof(kp->buf) <= (size_t)kp->len) {
372
- xfree(kp->key);
320
+ OJ_R_FREE(kp->key);
373
321
  }
374
322
  }
375
323
  d->ktail = d->khead + c->ki;
@@ -379,14 +327,14 @@ static void close_object_class(ojParser p) {
379
327
  }
380
328
 
381
329
  static void close_object_create(ojParser p) {
382
- VALUE * vp;
383
- Delegate d = (Delegate)p->ctx;
330
+ VALUE *vp;
331
+ Usual d = (Usual)p->ctx;
384
332
 
385
333
  d->ctail--;
386
334
 
387
335
  Col c = d->ctail;
388
336
  Key kp = d->khead + c->ki;
389
- VALUE * head = d->vhead + c->vi;
337
+ VALUE *head = d->vhead + c->vi;
390
338
  volatile VALUE obj;
391
339
 
392
340
  if (Qundef == *head) {
@@ -397,7 +345,7 @@ static void close_object_create(ojParser p) {
397
345
  for (vp = head; kp < d->ktail; kp++, vp += 2) {
398
346
  *vp = d->get_key(p, kp);
399
347
  if (sizeof(kp->buf) <= (size_t)kp->len) {
400
- xfree(kp->key);
348
+ OJ_R_FREE(kp->key);
401
349
  }
402
350
  }
403
351
  rb_hash_bulk_insert(d->vtail - head, head, obj);
@@ -405,7 +353,7 @@ static void close_object_create(ojParser p) {
405
353
  for (vp = head; kp < d->ktail; kp++, vp += 2) {
406
354
  rb_hash_aset(obj, d->get_key(p, kp), *(vp + 1));
407
355
  if (sizeof(kp->buf) <= (size_t)kp->len) {
408
- xfree(kp->key);
356
+ OJ_R_FREE(kp->key);
409
357
  }
410
358
  }
411
359
  #endif
@@ -414,7 +362,7 @@ static void close_object_create(ojParser p) {
414
362
  for (vp = head; kp < d->ktail; kp++, vp += 2) {
415
363
  rb_funcall(obj, hset_id, 2, d->get_key(p, kp), *(vp + 1));
416
364
  if (sizeof(kp->buf) <= (size_t)kp->len) {
417
- xfree(kp->key);
365
+ OJ_R_FREE(kp->key);
418
366
  }
419
367
  }
420
368
  }
@@ -429,7 +377,7 @@ static void close_object_create(ojParser p) {
429
377
  for (vp = head; kp < d->ktail; kp++, vp += 2) {
430
378
  *vp = d->get_key(p, kp);
431
379
  if (sizeof(kp->buf) <= (size_t)kp->len) {
432
- xfree(kp->key);
380
+ OJ_R_FREE(kp->key);
433
381
  }
434
382
  }
435
383
  rb_hash_bulk_insert(d->vtail - head, head, arg);
@@ -437,7 +385,7 @@ static void close_object_create(ojParser p) {
437
385
  for (vp = head; kp < d->ktail; kp++, vp += 2) {
438
386
  rb_hash_aset(arg, d->get_key(p, kp), *(vp + 1));
439
387
  if (sizeof(kp->buf) <= (size_t)kp->len) {
440
- xfree(kp->key);
388
+ OJ_R_FREE(kp->key);
441
389
  }
442
390
  }
443
391
  #endif
@@ -447,7 +395,7 @@ static void close_object_create(ojParser p) {
447
395
  for (vp = head; kp < d->ktail; kp++, vp += 2) {
448
396
  rb_ivar_set(obj, get_attr_id(p, kp), *(vp + 1));
449
397
  if (sizeof(kp->buf) <= (size_t)kp->len) {
450
- xfree(kp->key);
398
+ OJ_R_FREE(kp->key);
451
399
  }
452
400
  }
453
401
  }
@@ -459,10 +407,10 @@ static void close_object_create(ojParser p) {
459
407
  }
460
408
 
461
409
  static void close_array(ojParser p) {
462
- Delegate d = (Delegate)p->ctx;
410
+ Usual d = (Usual)p->ctx;
463
411
 
464
412
  d->ctail--;
465
- VALUE * head = d->vhead + d->ctail->vi + 1;
413
+ VALUE *head = d->vhead + d->ctail->vi + 1;
466
414
  volatile VALUE a = rb_ary_new_from_values(d->vtail - head, head);
467
415
 
468
416
  d->vtail = head;
@@ -471,11 +419,11 @@ static void close_array(ojParser p) {
471
419
  }
472
420
 
473
421
  static void close_array_class(ojParser p) {
474
- VALUE * vp;
475
- Delegate d = (Delegate)p->ctx;
422
+ VALUE *vp;
423
+ Usual d = (Usual)p->ctx;
476
424
 
477
425
  d->ctail--;
478
- VALUE * head = d->vhead + d->ctail->vi + 1;
426
+ VALUE *head = d->vhead + d->ctail->vi + 1;
479
427
  volatile VALUE a = rb_class_new_instance(0, NULL, d->array_class);
480
428
 
481
429
  for (vp = head; vp < d->vtail; vp++) {
@@ -585,9 +533,9 @@ static void add_big_as_ruby_key(ojParser p) {
585
533
  }
586
534
 
587
535
  static void add_str(ojParser p) {
588
- Delegate d = (Delegate)p->ctx;
536
+ Usual d = (Usual)p->ctx;
589
537
  volatile VALUE rstr;
590
- const char * str = buf_str(&p->buf);
538
+ const char *str = buf_str(&p->buf);
591
539
  size_t len = buf_len(&p->buf);
592
540
 
593
541
  if (len < d->cache_str) {
@@ -599,9 +547,9 @@ static void add_str(ojParser p) {
599
547
  }
600
548
 
601
549
  static void add_str_key(ojParser p) {
602
- Delegate d = (Delegate)p->ctx;
550
+ Usual d = (Usual)p->ctx;
603
551
  volatile VALUE rstr;
604
- const char * str = buf_str(&p->buf);
552
+ const char *str = buf_str(&p->buf);
605
553
  size_t len = buf_len(&p->buf);
606
554
 
607
555
  if (len < d->cache_str) {
@@ -614,11 +562,11 @@ static void add_str_key(ojParser p) {
614
562
  }
615
563
 
616
564
  static void add_str_key_create(ojParser p) {
617
- Delegate d = (Delegate)p->ctx;
565
+ Usual d = (Usual)p->ctx;
618
566
  volatile VALUE rstr;
619
- const char * str = buf_str(&p->buf);
567
+ const char *str = buf_str(&p->buf);
620
568
  size_t len = buf_len(&p->buf);
621
- const char * key = buf_str(&p->key);
569
+ const char *key = buf_str(&p->key);
622
570
  size_t klen = buf_len(&p->key);
623
571
 
624
572
  if (klen == (size_t)d->create_id_len && 0 == strncmp(d->create_id, key, klen)) {
@@ -648,16 +596,19 @@ static void add_str_key_create(ojParser p) {
648
596
  }
649
597
 
650
598
  static VALUE result(ojParser p) {
651
- Delegate d = (Delegate)p->ctx;
599
+ Usual d = (Usual)p->ctx;
652
600
 
653
601
  if (d->vhead < d->vtail) {
654
602
  return *d->vhead;
655
603
  }
604
+ if (d->raise_on_empty) {
605
+ rb_raise(oj_parse_error_class, "empty string");
606
+ }
656
607
  return Qnil;
657
608
  }
658
609
 
659
610
  static void start(ojParser p) {
660
- Delegate d = (Delegate)p->ctx;
611
+ Usual d = (Usual)p->ctx;
661
612
 
662
613
  d->vtail = d->vhead;
663
614
  d->ctail = d->chead;
@@ -665,7 +616,7 @@ static void start(ojParser p) {
665
616
  }
666
617
 
667
618
  static void dfree(ojParser p) {
668
- Delegate d = (Delegate)p->ctx;
619
+ Usual d = (Usual)p->ctx;
669
620
 
670
621
  cache_free(d->str_cache);
671
622
  cache_free(d->attr_cache);
@@ -675,20 +626,20 @@ static void dfree(ojParser p) {
675
626
  if (NULL != d->class_cache) {
676
627
  cache_free(d->class_cache);
677
628
  }
678
- xfree(d->vhead);
679
- xfree(d->chead);
680
- xfree(d->khead);
681
- xfree(d->create_id);
682
- xfree(p->ctx);
629
+ OJ_R_FREE(d->vhead);
630
+ OJ_R_FREE(d->chead);
631
+ OJ_R_FREE(d->khead);
632
+ OJ_R_FREE(d->create_id);
633
+ OJ_R_FREE(p->ctx);
683
634
  p->ctx = NULL;
684
635
  }
685
636
 
686
637
  static void mark(ojParser p) {
687
- if (NULL == p->ctx) {
638
+ if (NULL == p || NULL == p->ctx) {
688
639
  return;
689
640
  }
690
- Delegate d = (Delegate)p->ctx;
691
- VALUE * vp;
641
+ Usual d = (Usual)p->ctx;
642
+ VALUE *vp;
692
643
 
693
644
  if (NULL == d) {
694
645
  return;
@@ -720,13 +671,13 @@ struct opt {
720
671
  };
721
672
 
722
673
  static VALUE opt_array_class(ojParser p, VALUE value) {
723
- Delegate d = (Delegate)p->ctx;
674
+ Usual d = (Usual)p->ctx;
724
675
 
725
676
  return d->array_class;
726
677
  }
727
678
 
728
679
  static VALUE opt_array_class_set(ojParser p, VALUE value) {
729
- Delegate d = (Delegate)p->ctx;
680
+ Usual d = (Usual)p->ctx;
730
681
 
731
682
  if (Qnil == value) {
732
683
  p->funcs[TOP_FUN].close_array = close_array;
@@ -747,13 +698,13 @@ static VALUE opt_array_class_set(ojParser p, VALUE value) {
747
698
  }
748
699
 
749
700
  static VALUE opt_cache_keys(ojParser p, VALUE value) {
750
- Delegate d = (Delegate)p->ctx;
701
+ Usual d = (Usual)p->ctx;
751
702
 
752
703
  return d->cache_keys ? Qtrue : Qfalse;
753
704
  }
754
705
 
755
706
  static VALUE opt_cache_keys_set(ojParser p, VALUE value) {
756
- Delegate d = (Delegate)p->ctx;
707
+ Usual d = (Usual)p->ctx;
757
708
 
758
709
  if (Qtrue == value) {
759
710
  d->cache_keys = true;
@@ -775,14 +726,14 @@ static VALUE opt_cache_keys_set(ojParser p, VALUE value) {
775
726
  }
776
727
 
777
728
  static VALUE opt_cache_strings(ojParser p, VALUE value) {
778
- Delegate d = (Delegate)p->ctx;
729
+ Usual d = (Usual)p->ctx;
779
730
 
780
731
  return INT2NUM((int)d->cache_str);
781
732
  }
782
733
 
783
734
  static VALUE opt_cache_strings_set(ojParser p, VALUE value) {
784
- Delegate d = (Delegate)p->ctx;
785
- int limit = NUM2INT(value);
735
+ Usual d = (Usual)p->ctx;
736
+ int limit = NUM2INT(value);
786
737
 
787
738
  if (CACHE_MAX_KEY < limit) {
788
739
  limit = CACHE_MAX_KEY;
@@ -795,14 +746,14 @@ static VALUE opt_cache_strings_set(ojParser p, VALUE value) {
795
746
  }
796
747
 
797
748
  static VALUE opt_cache_expunge(ojParser p, VALUE value) {
798
- Delegate d = (Delegate)p->ctx;
749
+ Usual d = (Usual)p->ctx;
799
750
 
800
751
  return INT2NUM((int)d->cache_xrate);
801
752
  }
802
753
 
803
754
  static VALUE opt_cache_expunge_set(ojParser p, VALUE value) {
804
- Delegate d = (Delegate)p->ctx;
805
- int rate = NUM2INT(value);
755
+ Usual d = (Usual)p->ctx;
756
+ int rate = NUM2INT(value);
806
757
 
807
758
  if (rate < 0) {
808
759
  rate = 0;
@@ -819,26 +770,26 @@ static VALUE opt_cache_expunge_set(ojParser p, VALUE value) {
819
770
  }
820
771
 
821
772
  static VALUE opt_capacity(ojParser p, VALUE value) {
822
- Delegate d = (Delegate)p->ctx;
773
+ Usual d = (Usual)p->ctx;
823
774
 
824
775
  return ULONG2NUM(d->vend - d->vhead);
825
776
  }
826
777
 
827
778
  static VALUE opt_capacity_set(ojParser p, VALUE value) {
828
- Delegate d = (Delegate)p->ctx;
829
- long cap = NUM2LONG(value);
779
+ Usual d = (Usual)p->ctx;
780
+ long cap = NUM2LONG(value);
830
781
 
831
782
  if (d->vend - d->vhead < cap) {
832
783
  long pos = d->vtail - d->vhead;
833
784
 
834
- REALLOC_N(d->vhead, VALUE, cap);
785
+ OJ_R_REALLOC_N(d->vhead, VALUE, cap);
835
786
  d->vtail = d->vhead + pos;
836
787
  d->vend = d->vhead + cap;
837
788
  }
838
789
  if (d->kend - d->khead < cap) {
839
790
  long pos = d->ktail - d->khead;
840
791
 
841
- REALLOC_N(d->khead, union _key, cap);
792
+ OJ_R_REALLOC_N(d->khead, union _key, cap);
842
793
  d->ktail = d->khead + pos;
843
794
  d->kend = d->khead + cap;
844
795
  }
@@ -846,13 +797,13 @@ static VALUE opt_capacity_set(ojParser p, VALUE value) {
846
797
  }
847
798
 
848
799
  static VALUE opt_class_cache(ojParser p, VALUE value) {
849
- Delegate d = (Delegate)p->ctx;
800
+ Usual d = (Usual)p->ctx;
850
801
 
851
802
  return (NULL != d->class_cache) ? Qtrue : Qfalse;
852
803
  }
853
804
 
854
805
  static VALUE opt_class_cache_set(ojParser p, VALUE value) {
855
- Delegate d = (Delegate)p->ctx;
806
+ Usual d = (Usual)p->ctx;
856
807
 
857
808
  if (Qtrue == value) {
858
809
  if (NULL == d->class_cache) {
@@ -866,7 +817,7 @@ static VALUE opt_class_cache_set(ojParser p, VALUE value) {
866
817
  }
867
818
 
868
819
  static VALUE opt_create_id(ojParser p, VALUE value) {
869
- Delegate d = (Delegate)p->ctx;
820
+ Usual d = (Usual)p->ctx;
870
821
 
871
822
  if (NULL == d->create_id) {
872
823
  return Qnil;
@@ -875,7 +826,7 @@ static VALUE opt_create_id(ojParser p, VALUE value) {
875
826
  }
876
827
 
877
828
  static VALUE opt_create_id_set(ojParser p, VALUE value) {
878
- Delegate d = (Delegate)p->ctx;
829
+ Usual d = (Usual)p->ctx;
879
830
 
880
831
  if (Qnil == value) {
881
832
  d->create_id = NULL;
@@ -924,7 +875,7 @@ static VALUE opt_decimal(ojParser p, VALUE value) {
924
875
  }
925
876
 
926
877
  static VALUE opt_decimal_set(ojParser p, VALUE value) {
927
- const char * mode;
878
+ const char *mode;
928
879
  volatile VALUE s;
929
880
 
930
881
  switch (rb_type(value)) {
@@ -985,13 +936,13 @@ static VALUE opt_decimal_set(ojParser p, VALUE value) {
985
936
  }
986
937
 
987
938
  static VALUE opt_hash_class(ojParser p, VALUE value) {
988
- Delegate d = (Delegate)p->ctx;
939
+ Usual d = (Usual)p->ctx;
989
940
 
990
941
  return d->hash_class;
991
942
  }
992
943
 
993
944
  static VALUE opt_hash_class_set(ojParser p, VALUE value) {
994
- Delegate d = (Delegate)p->ctx;
945
+ Usual d = (Usual)p->ctx;
995
946
 
996
947
  if (Qnil != value) {
997
948
  rb_check_type(value, T_CLASS);
@@ -1015,13 +966,13 @@ static VALUE opt_hash_class_set(ojParser p, VALUE value) {
1015
966
  }
1016
967
 
1017
968
  static VALUE opt_ignore_json_create(ojParser p, VALUE value) {
1018
- Delegate d = (Delegate)p->ctx;
969
+ Usual d = (Usual)p->ctx;
1019
970
 
1020
971
  return d->ignore_json_create ? Qtrue : Qfalse;
1021
972
  }
1022
973
 
1023
974
  static VALUE opt_ignore_json_create_set(ojParser p, VALUE value) {
1024
- Delegate d = (Delegate)p->ctx;
975
+ Usual d = (Usual)p->ctx;
1025
976
 
1026
977
  d->ignore_json_create = (Qtrue == value);
1027
978
 
@@ -1029,7 +980,7 @@ static VALUE opt_ignore_json_create_set(ojParser p, VALUE value) {
1029
980
  }
1030
981
 
1031
982
  static VALUE opt_missing_class(ojParser p, VALUE value) {
1032
- Delegate d = (Delegate)p->ctx;
983
+ Usual d = (Usual)p->ctx;
1033
984
 
1034
985
  switch (d->miss_class) {
1035
986
  case MISS_AUTO: return ID2SYM(rb_intern("auto"));
@@ -1040,8 +991,8 @@ static VALUE opt_missing_class(ojParser p, VALUE value) {
1040
991
  }
1041
992
 
1042
993
  static VALUE opt_missing_class_set(ojParser p, VALUE value) {
1043
- Delegate d = (Delegate)p->ctx;
1044
- const char * mode;
994
+ Usual d = (Usual)p->ctx;
995
+ const char *mode;
1045
996
  volatile VALUE s;
1046
997
 
1047
998
  switch (rb_type(value)) {
@@ -1091,13 +1042,13 @@ static VALUE opt_omit_null_set(ojParser p, VALUE value) {
1091
1042
  }
1092
1043
 
1093
1044
  static VALUE opt_symbol_keys(ojParser p, VALUE value) {
1094
- Delegate d = (Delegate)p->ctx;
1045
+ Usual d = (Usual)p->ctx;
1095
1046
 
1096
1047
  return (NULL != d->sym_cache) ? Qtrue : Qfalse;
1097
1048
  }
1098
1049
 
1099
1050
  static VALUE opt_symbol_keys_set(ojParser p, VALUE value) {
1100
- Delegate d = (Delegate)p->ctx;
1051
+ Usual d = (Usual)p->ctx;
1101
1052
 
1102
1053
  if (Qtrue == value) {
1103
1054
  d->sym_cache = cache_create(0, form_sym, true, false);
@@ -1118,6 +1069,20 @@ static VALUE opt_symbol_keys_set(ojParser p, VALUE value) {
1118
1069
  return (NULL != d->sym_cache) ? Qtrue : Qfalse;
1119
1070
  }
1120
1071
 
1072
+ static VALUE opt_raise_on_empty(ojParser p, VALUE value) {
1073
+ Usual d = (Usual)p->ctx;
1074
+
1075
+ return d->raise_on_empty ? Qtrue : Qfalse;
1076
+ }
1077
+
1078
+ static VALUE opt_raise_on_empty_set(ojParser p, VALUE value) {
1079
+ Usual d = (Usual)p->ctx;
1080
+
1081
+ d->raise_on_empty = (Qtrue == value);
1082
+
1083
+ return d->raise_on_empty ? Qtrue : Qfalse;
1084
+ }
1085
+
1121
1086
  static VALUE option(ojParser p, const char *key, VALUE value) {
1122
1087
  struct opt *op;
1123
1088
  struct opt opts[] = {
@@ -1147,6 +1112,8 @@ static VALUE option(ojParser p, const char *key, VALUE value) {
1147
1112
  {.name = "omit_null=", .func = opt_omit_null_set},
1148
1113
  {.name = "symbol_keys", .func = opt_symbol_keys},
1149
1114
  {.name = "symbol_keys=", .func = opt_symbol_keys_set},
1115
+ {.name = "raise_on_empty", .func = opt_raise_on_empty},
1116
+ {.name = "raise_on_empty=", .func = opt_raise_on_empty_set},
1150
1117
  {.name = NULL},
1151
1118
  };
1152
1119
 
@@ -1162,26 +1129,26 @@ static VALUE option(ojParser p, const char *key, VALUE value) {
1162
1129
 
1163
1130
  ///// the set up //////////////////////////////////////////////////////////////
1164
1131
 
1165
- void oj_set_parser_usual(ojParser p) {
1166
- Delegate d = ALLOC(struct _delegate);
1167
- int cap = 4096;
1132
+ void oj_init_usual(ojParser p, Usual d) {
1133
+ int cap = 4096;
1168
1134
 
1169
- d->vhead = ALLOC_N(VALUE, cap);
1135
+ d->vhead = OJ_R_ALLOC_N(VALUE, cap);
1170
1136
  d->vend = d->vhead + cap;
1171
1137
  d->vtail = d->vhead;
1172
1138
 
1173
- d->khead = ALLOC_N(union _key, cap);
1139
+ d->khead = OJ_R_ALLOC_N(union _key, cap);
1174
1140
  d->kend = d->khead + cap;
1175
1141
  d->ktail = d->khead;
1176
1142
 
1177
1143
  cap = 256;
1178
- d->chead = ALLOC_N(struct _col, cap);
1144
+ d->chead = OJ_R_ALLOC_N(struct _col, cap);
1179
1145
  d->cend = d->chead + cap;
1180
1146
  d->ctail = d->chead;
1181
1147
 
1182
1148
  d->get_key = cache_key;
1183
1149
  d->cache_keys = true;
1184
1150
  d->ignore_json_create = false;
1151
+ d->raise_on_empty = false;
1185
1152
  d->cache_str = 6;
1186
1153
  d->array_class = Qnil;
1187
1154
  d->hash_class = Qnil;
@@ -1235,6 +1202,8 @@ void oj_set_parser_usual(ojParser p) {
1235
1202
  d->class_cache = NULL;
1236
1203
  d->key_cache = d->str_cache;
1237
1204
 
1205
+ // The parser fields are set but the functions can be replaced by a
1206
+ // delegate that wraps the usual delegate.
1238
1207
  p->ctx = (void *)d;
1239
1208
  p->option = option;
1240
1209
  p->result = result;
@@ -1252,3 +1221,9 @@ void oj_set_parser_usual(ojParser p) {
1252
1221
  hset_id = rb_intern("[]=");
1253
1222
  }
1254
1223
  }
1224
+
1225
+ void oj_set_parser_usual(ojParser p) {
1226
+ Usual d = OJ_R_ALLOC(struct _usual);
1227
+
1228
+ oj_init_usual(p, d);
1229
+ }