oj 3.13.23 → 3.16.9

Sign up to get free protection for your applications and to get access to all the features.
Files changed (158) hide show
  1. checksums.yaml +4 -4
  2. data/CHANGELOG.md +81 -0
  3. data/README.md +2 -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 +26 -59
  14. data/ext/oj/debug.c +3 -9
  15. data/ext/oj/dump.c +103 -53
  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 -7
  25. data/ext/oj/fast.c +60 -92
  26. data/ext/oj/intern.c +62 -47
  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 +51 -32
  31. data/ext/oj/object.c +33 -43
  32. data/ext/oj/odd.c +8 -6
  33. data/ext/oj/odd.h +4 -4
  34. data/ext/oj/oj.c +243 -212
  35. data/ext/oj/oj.h +83 -81
  36. data/ext/oj/parse.c +94 -148
  37. data/ext/oj/parse.h +21 -24
  38. data/ext/oj/parser.c +80 -67
  39. data/ext/oj/parser.h +7 -8
  40. data/ext/oj/rails.c +70 -92
  41. data/ext/oj/reader.c +9 -14
  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 +37 -49
  48. data/ext/oj/saj2.h +1 -1
  49. data/ext/oj/scp.c +3 -14
  50. data/ext/oj/sparse.c +22 -70
  51. data/ext/oj/stream_writer.c +45 -41
  52. data/ext/oj/strict.c +20 -52
  53. data/ext/oj/string_writer.c +64 -38
  54. data/ext/oj/trace.h +31 -4
  55. data/ext/oj/usual.c +125 -114
  56. data/ext/oj/usual.h +7 -6
  57. data/ext/oj/util.h +1 -1
  58. data/ext/oj/val_stack.c +13 -2
  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 +7 -7
  67. data/lib/oj/schandler.rb +5 -4
  68. data/lib/oj/state.rb +8 -5
  69. data/lib/oj/version.rb +1 -2
  70. data/lib/oj.rb +2 -0
  71. data/pages/InstallOptions.md +20 -0
  72. data/pages/Options.md +4 -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/activesupport6/encoding_test.rb +63 -28
  78. data/test/activesupport7/abstract_unit.rb +4 -1
  79. data/test/activesupport7/encoding_test.rb +72 -22
  80. data/test/files.rb +15 -15
  81. data/test/foo.rb +18 -69
  82. data/test/helper.rb +5 -8
  83. data/test/isolated/shared.rb +3 -2
  84. data/test/json_gem/json_addition_test.rb +2 -2
  85. data/test/json_gem/json_common_interface_test.rb +8 -6
  86. data/test/json_gem/json_encoding_test.rb +0 -0
  87. data/test/json_gem/json_ext_parser_test.rb +1 -0
  88. data/test/json_gem/json_fixtures_test.rb +3 -2
  89. data/test/json_gem/json_generator_test.rb +50 -33
  90. data/test/json_gem/json_generic_object_test.rb +11 -11
  91. data/test/json_gem/json_parser_test.rb +46 -46
  92. data/test/json_gem/json_string_matching_test.rb +9 -9
  93. data/test/mem.rb +13 -12
  94. data/test/perf.rb +21 -26
  95. data/test/perf_compat.rb +31 -33
  96. data/test/perf_dump.rb +28 -28
  97. data/test/perf_fast.rb +80 -82
  98. data/test/perf_file.rb +27 -29
  99. data/test/perf_object.rb +65 -69
  100. data/test/perf_once.rb +12 -11
  101. data/test/perf_parser.rb +42 -48
  102. data/test/perf_saj.rb +46 -54
  103. data/test/perf_scp.rb +57 -69
  104. data/test/perf_simple.rb +41 -39
  105. data/test/perf_strict.rb +68 -70
  106. data/test/perf_wab.rb +67 -69
  107. data/test/prec.rb +5 -5
  108. data/test/sample/change.rb +0 -1
  109. data/test/sample/dir.rb +0 -1
  110. data/test/sample/doc.rb +0 -1
  111. data/test/sample/file.rb +0 -1
  112. data/test/sample/group.rb +0 -1
  113. data/test/sample/hasprops.rb +0 -1
  114. data/test/sample/layer.rb +0 -1
  115. data/test/sample/rect.rb +0 -1
  116. data/test/sample/shape.rb +0 -1
  117. data/test/sample/text.rb +0 -1
  118. data/test/sample.rb +16 -16
  119. data/test/sample_json.rb +8 -8
  120. data/test/test_compat.rb +81 -54
  121. data/test/test_custom.rb +63 -52
  122. data/test/test_debian.rb +7 -10
  123. data/test/test_fast.rb +86 -90
  124. data/test/test_file.rb +24 -29
  125. data/test/test_gc.rb +5 -5
  126. data/test/test_generate.rb +5 -5
  127. data/test/test_hash.rb +4 -4
  128. data/test/test_integer_range.rb +9 -9
  129. data/test/test_null.rb +20 -20
  130. data/test/test_object.rb +92 -87
  131. data/test/test_parser.rb +4 -4
  132. data/test/test_parser_debug.rb +5 -5
  133. data/test/test_parser_saj.rb +27 -25
  134. data/test/test_parser_usual.rb +44 -6
  135. data/test/test_rails.rb +2 -2
  136. data/test/test_saj.rb +10 -8
  137. data/test/test_scp.rb +35 -35
  138. data/test/test_strict.rb +38 -32
  139. data/test/test_various.rb +146 -97
  140. data/test/test_wab.rb +46 -44
  141. data/test/test_writer.rb +63 -47
  142. data/test/tests.rb +7 -7
  143. data/test/tests_mimic.rb +6 -6
  144. data/test/tests_mimic_addition.rb +6 -6
  145. metadata +46 -26
  146. data/test/activesupport4/decoding_test.rb +0 -108
  147. data/test/activesupport4/encoding_test.rb +0 -531
  148. data/test/activesupport4/test_helper.rb +0 -41
  149. data/test/activesupport5/abstract_unit.rb +0 -45
  150. data/test/activesupport5/decoding_test.rb +0 -133
  151. data/test/activesupport5/encoding_test.rb +0 -500
  152. data/test/activesupport5/encoding_test_cases.rb +0 -98
  153. data/test/activesupport5/test_helper.rb +0 -72
  154. data/test/activesupport5/time_zone_test_helpers.rb +0 -39
  155. data/test/bar.rb +0 -11
  156. data/test/baz.rb +0 -16
  157. data/test/bug.rb +0 -16
  158. data/test/zoo.rb +0 -13
data/ext/oj/trace.h CHANGED
@@ -17,12 +17,39 @@ typedef enum {
17
17
 
18
18
  struct _parseInfo;
19
19
 
20
- extern void
21
- oj_trace(const char *func, VALUE obj, const char *file, int line, int depth, TraceWhere where);
20
+ extern void oj_trace(const char *func, VALUE obj, const char *file, int line, int depth, TraceWhere where);
22
21
  extern void oj_trace_parse_in(const char *func, struct _parseInfo *pi, const char *file, int line);
23
- extern void
24
- oj_trace_parse_call(const char *func, struct _parseInfo *pi, const char *file, int line, VALUE obj);
22
+ extern void oj_trace_parse_call(const char *func, struct _parseInfo *pi, const char *file, int line, VALUE obj);
25
23
  extern void oj_trace_parse_hash_end(struct _parseInfo *pi, const char *file, int line);
26
24
  extern void oj_trace_parse_array_end(struct _parseInfo *pi, const char *file, int line);
27
25
 
26
+ #ifdef OJ_ENABLE_TRACE_LOG
27
+ #define TRACE(option, func, obj, depth, where) \
28
+ if (RB_UNLIKELY(Yes == option)) { \
29
+ oj_trace(func, obj, __FILE__, __LINE__, depth, where); \
30
+ }
31
+ #define TRACE_PARSE_IN(option, func, pi) \
32
+ if (RB_UNLIKELY(Yes == option)) { \
33
+ oj_trace_parse_in(func, pi, __FILE__, __LINE__); \
34
+ }
35
+ #define TRACE_PARSE_CALL(option, func, pi, obj) \
36
+ if (RB_UNLIKELY(Yes == option)) { \
37
+ oj_trace_parse_call(func, pi, __FILE__, __LINE__, obj); \
38
+ }
39
+ #define TRACE_PARSE_HASH_END(option, pi) \
40
+ if (RB_UNLIKELY(Yes == option)) { \
41
+ oj_trace_parse_hash_end(pi, __FILE__, __LINE__); \
42
+ }
43
+ #define TRACE_PARSE_ARRAY_END(option, pi) \
44
+ if (RB_UNLIKELY(Yes == option)) { \
45
+ oj_trace_parse_array_end(pi, __FILE__, __LINE__); \
46
+ }
47
+ #else
48
+ #define TRACE(option, func, obj, depth, where)
49
+ #define TRACE_PARSE_IN(option, func, pi)
50
+ #define TRACE_PARSE_CALL(option, func, pi, obj)
51
+ #define TRACE_PARSE_HASH_END(option, pi)
52
+ #define TRACE_PARSE_ARRAY_END(option, pi)
53
+ #endif
54
+
28
55
  #endif /* OJ_TRACE_H */
data/ext/oj/usual.c CHANGED
@@ -1,9 +1,11 @@
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
- #include "usual.h"
7
9
 
8
10
  // The Usual delegate builds Ruby objects during parsing. It makes use of
9
11
  // three stacks. The first is the value stack. This is where parsed values are
@@ -34,7 +36,7 @@ static ID ltlt_id = 0;
34
36
  static ID hset_id = 0;
35
37
 
36
38
  static char *str_dup(const char *s, size_t len) {
37
- char *d = ALLOC_N(char, len + 1);
39
+ char *d = OJ_R_ALLOC_N(char, len + 1);
38
40
 
39
41
  memcpy(d, s, len);
40
42
  d[len] = '\0';
@@ -54,7 +56,7 @@ static VALUE form_attr(const char *str, size_t len) {
54
56
  char buf[256];
55
57
 
56
58
  if (sizeof(buf) - 2 <= len) {
57
- char *b = ALLOC_N(char, len + 2);
59
+ char *b = OJ_R_ALLOC_N(char, len + 2);
58
60
  ID id;
59
61
 
60
62
  *b = '@';
@@ -62,7 +64,7 @@ static VALUE form_attr(const char *str, size_t len) {
62
64
  b[len + 1] = '\0';
63
65
 
64
66
  id = rb_intern3(buf, len + 1, oj_utf8_encoding);
65
- xfree(b);
67
+ OJ_R_FREE(b);
66
68
  return id;
67
69
  }
68
70
  *buf = '@';
@@ -89,8 +91,8 @@ static VALUE resolve_classname(VALUE mod, const char *classname, bool auto_defin
89
91
  static VALUE resolve_classpath(const char *name, size_t len, bool auto_define) {
90
92
  char class_name[1024];
91
93
  VALUE clas;
92
- char * end = class_name + sizeof(class_name) - 1;
93
- char * s;
94
+ char *end = class_name + sizeof(class_name) - 1;
95
+ char *s;
94
96
  const char *n = name;
95
97
 
96
98
  clas = rb_cObject;
@@ -130,7 +132,7 @@ static void assure_cstack(Usual d) {
130
132
  long pos = d->ctail - d->chead;
131
133
 
132
134
  cap *= 2;
133
- REALLOC_N(d->chead, struct _col, cap);
135
+ OJ_R_REALLOC_N(d->chead, struct _col, cap);
134
136
  d->ctail = d->chead + pos;
135
137
  d->cend = d->chead + cap;
136
138
  }
@@ -144,7 +146,7 @@ static void push(ojParser p, VALUE v) {
144
146
  long pos = d->vtail - d->vhead;
145
147
 
146
148
  cap *= 2;
147
- REALLOC_N(d->vhead, VALUE, cap);
149
+ OJ_R_REALLOC_N(d->vhead, VALUE, cap);
148
150
  d->vtail = d->vhead + pos;
149
151
  d->vend = d->vhead + cap;
150
152
  }
@@ -185,7 +187,7 @@ static ID get_attr_id(ojParser p, Key kp) {
185
187
  }
186
188
 
187
189
  static void push_key(ojParser p) {
188
- Usual d = (Usual)p->ctx;
190
+ Usual d = (Usual)p->ctx;
189
191
  size_t klen = buf_len(&p->key);
190
192
  const char *key = buf_str(&p->key);
191
193
 
@@ -194,7 +196,7 @@ static void push_key(ojParser p) {
194
196
  long pos = d->ktail - d->khead;
195
197
 
196
198
  cap *= 2;
197
- REALLOC_N(d->khead, union _key, cap);
199
+ OJ_R_REALLOC_N(d->khead, union _key, cap);
198
200
  d->ktail = d->khead + pos;
199
201
  d->kend = d->khead + cap;
200
202
  }
@@ -216,7 +218,7 @@ static void push2(ojParser p, VALUE v) {
216
218
  long pos = d->vtail - d->vhead;
217
219
 
218
220
  cap *= 2;
219
- REALLOC_N(d->vhead, VALUE, cap);
221
+ OJ_R_REALLOC_N(d->vhead, VALUE, cap);
220
222
  d->vtail = d->vhead + pos;
221
223
  d->vend = d->vhead + cap;
222
224
  }
@@ -269,53 +271,49 @@ static void open_array_key(ojParser p) {
269
271
  }
270
272
 
271
273
  static void close_object(ojParser p) {
272
- VALUE * vp;
273
- Usual d = (Usual)p->ctx;
274
+ VALUE *vp;
275
+ Usual d = (Usual)p->ctx;
274
276
 
275
277
  d->ctail--;
276
278
 
277
279
  Col c = d->ctail;
278
280
  Key kp = d->khead + c->ki;
279
- VALUE * head = d->vhead + c->vi + 1;
281
+ VALUE *head = d->vhead + c->vi + 1;
280
282
  volatile VALUE obj = rb_hash_new();
281
283
 
282
- #if HAVE_RB_HASH_BULK_INSERT
283
284
  for (vp = head; kp < d->ktail; kp++, vp += 2) {
284
285
  *vp = d->get_key(p, kp);
285
286
  if (sizeof(kp->buf) <= (size_t)kp->len) {
286
- xfree(kp->key);
287
+ OJ_R_FREE(kp->key);
287
288
  }
288
289
  }
289
290
  rb_hash_bulk_insert(d->vtail - head, head, obj);
290
- #else
291
- for (vp = head; kp < d->ktail; kp++, vp += 2) {
292
- rb_hash_aset(obj, d->get_key(p, kp), *(vp + 1));
293
- if (sizeof(kp->buf) <= (size_t)kp->len) {
294
- xfree(kp->key);
295
- }
296
- }
297
- #endif
298
291
  d->ktail = d->khead + c->ki;
292
+
299
293
  d->vtail = head;
300
294
  head--;
301
295
  *head = obj;
296
+ if (1 == d->vtail - d->vhead && rb_block_given_p()) {
297
+ d->vtail = d->vhead;
298
+ rb_yield(obj);
299
+ }
302
300
  }
303
301
 
304
302
  static void close_object_class(ojParser p) {
305
- VALUE * vp;
306
- Usual d = (Usual)p->ctx;
303
+ VALUE *vp;
304
+ Usual d = (Usual)p->ctx;
307
305
 
308
306
  d->ctail--;
309
307
 
310
308
  Col c = d->ctail;
311
309
  Key kp = d->khead + c->ki;
312
- VALUE * head = d->vhead + c->vi + 1;
310
+ VALUE *head = d->vhead + c->vi + 1;
313
311
  volatile VALUE obj = rb_class_new_instance(0, NULL, d->hash_class);
314
312
 
315
313
  for (vp = head; kp < d->ktail; kp++, vp += 2) {
316
314
  rb_funcall(obj, hset_id, 2, d->get_key(p, kp), *(vp + 1));
317
315
  if (sizeof(kp->buf) <= (size_t)kp->len) {
318
- xfree(kp->key);
316
+ OJ_R_FREE(kp->key);
319
317
  }
320
318
  }
321
319
  d->ktail = d->khead + c->ki;
@@ -325,42 +323,33 @@ static void close_object_class(ojParser p) {
325
323
  }
326
324
 
327
325
  static void close_object_create(ojParser p) {
328
- VALUE * vp;
329
- Usual d = (Usual)p->ctx;
326
+ VALUE *vp;
327
+ Usual d = (Usual)p->ctx;
330
328
 
331
329
  d->ctail--;
332
330
 
333
331
  Col c = d->ctail;
334
332
  Key kp = d->khead + c->ki;
335
- VALUE * head = d->vhead + c->vi;
333
+ VALUE *head = d->vhead + c->vi;
336
334
  volatile VALUE obj;
337
335
 
338
336
  if (Qundef == *head) {
339
337
  head++;
340
338
  if (Qnil == d->hash_class) {
341
339
  obj = rb_hash_new();
342
- #if HAVE_RB_HASH_BULK_INSERT
343
340
  for (vp = head; kp < d->ktail; kp++, vp += 2) {
344
341
  *vp = d->get_key(p, kp);
345
342
  if (sizeof(kp->buf) <= (size_t)kp->len) {
346
- xfree(kp->key);
343
+ OJ_R_FREE(kp->key);
347
344
  }
348
345
  }
349
346
  rb_hash_bulk_insert(d->vtail - head, head, obj);
350
- #else
351
- for (vp = head; kp < d->ktail; kp++, vp += 2) {
352
- rb_hash_aset(obj, d->get_key(p, kp), *(vp + 1));
353
- if (sizeof(kp->buf) <= (size_t)kp->len) {
354
- xfree(kp->key);
355
- }
356
- }
357
- #endif
358
347
  } else {
359
348
  obj = rb_class_new_instance(0, NULL, d->hash_class);
360
349
  for (vp = head; kp < d->ktail; kp++, vp += 2) {
361
350
  rb_funcall(obj, hset_id, 2, d->get_key(p, kp), *(vp + 1));
362
351
  if (sizeof(kp->buf) <= (size_t)kp->len) {
363
- xfree(kp->key);
352
+ OJ_R_FREE(kp->key);
364
353
  }
365
354
  }
366
355
  }
@@ -371,29 +360,20 @@ static void close_object_create(ojParser p) {
371
360
  if (!d->ignore_json_create && rb_respond_to(clas, oj_json_create_id)) {
372
361
  volatile VALUE arg = rb_hash_new();
373
362
 
374
- #if HAVE_RB_HASH_BULK_INSERT
375
363
  for (vp = head; kp < d->ktail; kp++, vp += 2) {
376
364
  *vp = d->get_key(p, kp);
377
365
  if (sizeof(kp->buf) <= (size_t)kp->len) {
378
- xfree(kp->key);
366
+ OJ_R_FREE(kp->key);
379
367
  }
380
368
  }
381
369
  rb_hash_bulk_insert(d->vtail - head, head, arg);
382
- #else
383
- for (vp = head; kp < d->ktail; kp++, vp += 2) {
384
- rb_hash_aset(arg, d->get_key(p, kp), *(vp + 1));
385
- if (sizeof(kp->buf) <= (size_t)kp->len) {
386
- xfree(kp->key);
387
- }
388
- }
389
- #endif
390
370
  obj = rb_funcall(clas, oj_json_create_id, 1, arg);
391
371
  } else {
392
372
  obj = rb_class_new_instance(0, NULL, clas);
393
373
  for (vp = head; kp < d->ktail; kp++, vp += 2) {
394
374
  rb_ivar_set(obj, get_attr_id(p, kp), *(vp + 1));
395
375
  if (sizeof(kp->buf) <= (size_t)kp->len) {
396
- xfree(kp->key);
376
+ OJ_R_FREE(kp->key);
397
377
  }
398
378
  }
399
379
  }
@@ -408,7 +388,7 @@ static void close_array(ojParser p) {
408
388
  Usual d = (Usual)p->ctx;
409
389
 
410
390
  d->ctail--;
411
- VALUE * head = d->vhead + d->ctail->vi + 1;
391
+ VALUE *head = d->vhead + d->ctail->vi + 1;
412
392
  volatile VALUE a = rb_ary_new_from_values(d->vtail - head, head);
413
393
 
414
394
  d->vtail = head;
@@ -417,11 +397,11 @@ static void close_array(ojParser p) {
417
397
  }
418
398
 
419
399
  static void close_array_class(ojParser p) {
420
- VALUE * vp;
421
- Usual d = (Usual)p->ctx;
400
+ VALUE *vp;
401
+ Usual d = (Usual)p->ctx;
422
402
 
423
403
  d->ctail--;
424
- VALUE * head = d->vhead + d->ctail->vi + 1;
404
+ VALUE *head = d->vhead + d->ctail->vi + 1;
425
405
  volatile VALUE a = rb_class_new_instance(0, NULL, d->array_class);
426
406
 
427
407
  for (vp = head; vp < d->vtail; vp++) {
@@ -531,9 +511,9 @@ static void add_big_as_ruby_key(ojParser p) {
531
511
  }
532
512
 
533
513
  static void add_str(ojParser p) {
534
- Usual d = (Usual)p->ctx;
514
+ Usual d = (Usual)p->ctx;
535
515
  volatile VALUE rstr;
536
- const char * str = buf_str(&p->buf);
516
+ const char *str = buf_str(&p->buf);
537
517
  size_t len = buf_len(&p->buf);
538
518
 
539
519
  if (len < d->cache_str) {
@@ -545,9 +525,9 @@ static void add_str(ojParser p) {
545
525
  }
546
526
 
547
527
  static void add_str_key(ojParser p) {
548
- Usual d = (Usual)p->ctx;
528
+ Usual d = (Usual)p->ctx;
549
529
  volatile VALUE rstr;
550
- const char * str = buf_str(&p->buf);
530
+ const char *str = buf_str(&p->buf);
551
531
  size_t len = buf_len(&p->buf);
552
532
 
553
533
  if (len < d->cache_str) {
@@ -560,11 +540,11 @@ static void add_str_key(ojParser p) {
560
540
  }
561
541
 
562
542
  static void add_str_key_create(ojParser p) {
563
- Usual d = (Usual)p->ctx;
543
+ Usual d = (Usual)p->ctx;
564
544
  volatile VALUE rstr;
565
- const char * str = buf_str(&p->buf);
545
+ const char *str = buf_str(&p->buf);
566
546
  size_t len = buf_len(&p->buf);
567
- const char * key = buf_str(&p->key);
547
+ const char *key = buf_str(&p->key);
568
548
  size_t klen = buf_len(&p->key);
569
549
 
570
550
  if (klen == (size_t)d->create_id_len && 0 == strncmp(d->create_id, key, klen)) {
@@ -597,7 +577,21 @@ static VALUE result(ojParser p) {
597
577
  Usual d = (Usual)p->ctx;
598
578
 
599
579
  if (d->vhead < d->vtail) {
600
- return *d->vhead;
580
+ long cnt = d->vtail - d->vhead;
581
+ volatile VALUE ary;
582
+ volatile VALUE *vp;
583
+
584
+ if (1 == cnt) {
585
+ return *d->vhead;
586
+ }
587
+ ary = rb_ary_new();
588
+ for (vp = d->vhead; vp < d->vtail; vp++) {
589
+ rb_ary_push(ary, *vp);
590
+ }
591
+ return ary;
592
+ }
593
+ if (d->raise_on_empty) {
594
+ rb_raise(oj_parse_error_class, "empty string");
601
595
  }
602
596
  return Qnil;
603
597
  }
@@ -621,11 +615,11 @@ static void dfree(ojParser p) {
621
615
  if (NULL != d->class_cache) {
622
616
  cache_free(d->class_cache);
623
617
  }
624
- xfree(d->vhead);
625
- xfree(d->chead);
626
- xfree(d->khead);
627
- xfree(d->create_id);
628
- xfree(p->ctx);
618
+ OJ_R_FREE(d->vhead);
619
+ OJ_R_FREE(d->chead);
620
+ OJ_R_FREE(d->khead);
621
+ OJ_R_FREE(d->create_id);
622
+ OJ_R_FREE(p->ctx);
629
623
  p->ctx = NULL;
630
624
  }
631
625
 
@@ -633,8 +627,8 @@ static void mark(ojParser p) {
633
627
  if (NULL == p || NULL == p->ctx) {
634
628
  return;
635
629
  }
636
- Usual d = (Usual)p->ctx;
637
- VALUE * vp;
630
+ Usual d = (Usual)p->ctx;
631
+ VALUE *vp;
638
632
 
639
633
  if (NULL == d) {
640
634
  return;
@@ -728,7 +722,7 @@ static VALUE opt_cache_strings(ojParser p, VALUE value) {
728
722
 
729
723
  static VALUE opt_cache_strings_set(ojParser p, VALUE value) {
730
724
  Usual d = (Usual)p->ctx;
731
- int limit = NUM2INT(value);
725
+ int limit = NUM2INT(value);
732
726
 
733
727
  if (CACHE_MAX_KEY < limit) {
734
728
  limit = CACHE_MAX_KEY;
@@ -748,7 +742,7 @@ static VALUE opt_cache_expunge(ojParser p, VALUE value) {
748
742
 
749
743
  static VALUE opt_cache_expunge_set(ojParser p, VALUE value) {
750
744
  Usual d = (Usual)p->ctx;
751
- int rate = NUM2INT(value);
745
+ int rate = NUM2INT(value);
752
746
 
753
747
  if (rate < 0) {
754
748
  rate = 0;
@@ -772,19 +766,19 @@ static VALUE opt_capacity(ojParser p, VALUE value) {
772
766
 
773
767
  static VALUE opt_capacity_set(ojParser p, VALUE value) {
774
768
  Usual d = (Usual)p->ctx;
775
- long cap = NUM2LONG(value);
769
+ long cap = NUM2LONG(value);
776
770
 
777
771
  if (d->vend - d->vhead < cap) {
778
772
  long pos = d->vtail - d->vhead;
779
773
 
780
- REALLOC_N(d->vhead, VALUE, cap);
774
+ OJ_R_REALLOC_N(d->vhead, VALUE, cap);
781
775
  d->vtail = d->vhead + pos;
782
776
  d->vend = d->vhead + cap;
783
777
  }
784
778
  if (d->kend - d->khead < cap) {
785
779
  long pos = d->ktail - d->khead;
786
780
 
787
- REALLOC_N(d->khead, union _key, cap);
781
+ OJ_R_REALLOC_N(d->khead, union _key, cap);
788
782
  d->ktail = d->khead + pos;
789
783
  d->kend = d->khead + cap;
790
784
  }
@@ -840,8 +834,8 @@ static VALUE opt_create_id_set(ojParser p, VALUE value) {
840
834
  rb_check_type(value, T_STRING);
841
835
  size_t len = RSTRING_LEN(value);
842
836
 
843
- if (1 << sizeof(d->create_id_len) <= len) {
844
- rb_raise(rb_eArgError, "The create_id values is limited to %d bytes.", 1 << sizeof(d->create_id_len));
837
+ if (1 << (8 * sizeof(d->create_id_len)) <= len) {
838
+ rb_raise(rb_eArgError, "The create_id values is limited to %d bytes.", 1 << (8 * sizeof(d->create_id_len)));
845
839
  }
846
840
  d->create_id_len = (uint8_t)len;
847
841
  d->create_id = str_dup(RSTRING_PTR(value), len);
@@ -870,7 +864,7 @@ static VALUE opt_decimal(ojParser p, VALUE value) {
870
864
  }
871
865
 
872
866
  static VALUE opt_decimal_set(ojParser p, VALUE value) {
873
- const char * mode;
867
+ const char *mode;
874
868
  volatile VALUE s;
875
869
 
876
870
  switch (rb_type(value)) {
@@ -986,8 +980,8 @@ static VALUE opt_missing_class(ojParser p, VALUE value) {
986
980
  }
987
981
 
988
982
  static VALUE opt_missing_class_set(ojParser p, VALUE value) {
989
- Usual d = (Usual)p->ctx;
990
- const char * mode;
983
+ Usual d = (Usual)p->ctx;
984
+ const char *mode;
991
985
  volatile VALUE s;
992
986
 
993
987
  switch (rb_type(value)) {
@@ -1064,36 +1058,52 @@ static VALUE opt_symbol_keys_set(ojParser p, VALUE value) {
1064
1058
  return (NULL != d->sym_cache) ? Qtrue : Qfalse;
1065
1059
  }
1066
1060
 
1061
+ static VALUE opt_raise_on_empty(ojParser p, VALUE value) {
1062
+ Usual d = (Usual)p->ctx;
1063
+
1064
+ return d->raise_on_empty ? Qtrue : Qfalse;
1065
+ }
1066
+
1067
+ static VALUE opt_raise_on_empty_set(ojParser p, VALUE value) {
1068
+ Usual d = (Usual)p->ctx;
1069
+
1070
+ d->raise_on_empty = (Qtrue == value);
1071
+
1072
+ return d->raise_on_empty ? Qtrue : Qfalse;
1073
+ }
1074
+
1067
1075
  static VALUE option(ojParser p, const char *key, VALUE value) {
1068
1076
  struct opt *op;
1069
1077
  struct opt opts[] = {
1070
- {.name = "array_class", .func = opt_array_class},
1071
- {.name = "array_class=", .func = opt_array_class_set},
1072
- {.name = "cache_keys", .func = opt_cache_keys},
1073
- {.name = "cache_keys=", .func = opt_cache_keys_set},
1074
- {.name = "cache_strings", .func = opt_cache_strings},
1075
- {.name = "cache_strings=", .func = opt_cache_strings_set},
1076
- {.name = "cache_expunge", .func = opt_cache_expunge},
1077
- {.name = "cache_expunge=", .func = opt_cache_expunge_set},
1078
- {.name = "capacity", .func = opt_capacity},
1079
- {.name = "capacity=", .func = opt_capacity_set},
1080
- {.name = "class_cache", .func = opt_class_cache},
1081
- {.name = "class_cache=", .func = opt_class_cache_set},
1082
- {.name = "create_id", .func = opt_create_id},
1083
- {.name = "create_id=", .func = opt_create_id_set},
1084
- {.name = "decimal", .func = opt_decimal},
1085
- {.name = "decimal=", .func = opt_decimal_set},
1086
- {.name = "hash_class", .func = opt_hash_class},
1087
- {.name = "hash_class=", .func = opt_hash_class_set},
1088
- {.name = "ignore_json_create", .func = opt_ignore_json_create},
1089
- {.name = "ignore_json_create=", .func = opt_ignore_json_create_set},
1090
- {.name = "missing_class", .func = opt_missing_class},
1091
- {.name = "missing_class=", .func = opt_missing_class_set},
1092
- {.name = "omit_null", .func = opt_omit_null},
1093
- {.name = "omit_null=", .func = opt_omit_null_set},
1094
- {.name = "symbol_keys", .func = opt_symbol_keys},
1095
- {.name = "symbol_keys=", .func = opt_symbol_keys_set},
1096
- {.name = NULL},
1078
+ {.name = "array_class", .func = opt_array_class},
1079
+ {.name = "array_class=", .func = opt_array_class_set},
1080
+ {.name = "cache_keys", .func = opt_cache_keys},
1081
+ {.name = "cache_keys=", .func = opt_cache_keys_set},
1082
+ {.name = "cache_strings", .func = opt_cache_strings},
1083
+ {.name = "cache_strings=", .func = opt_cache_strings_set},
1084
+ {.name = "cache_expunge", .func = opt_cache_expunge},
1085
+ {.name = "cache_expunge=", .func = opt_cache_expunge_set},
1086
+ {.name = "capacity", .func = opt_capacity},
1087
+ {.name = "capacity=", .func = opt_capacity_set},
1088
+ {.name = "class_cache", .func = opt_class_cache},
1089
+ {.name = "class_cache=", .func = opt_class_cache_set},
1090
+ {.name = "create_id", .func = opt_create_id},
1091
+ {.name = "create_id=", .func = opt_create_id_set},
1092
+ {.name = "decimal", .func = opt_decimal},
1093
+ {.name = "decimal=", .func = opt_decimal_set},
1094
+ {.name = "hash_class", .func = opt_hash_class},
1095
+ {.name = "hash_class=", .func = opt_hash_class_set},
1096
+ {.name = "ignore_json_create", .func = opt_ignore_json_create},
1097
+ {.name = "ignore_json_create=", .func = opt_ignore_json_create_set},
1098
+ {.name = "missing_class", .func = opt_missing_class},
1099
+ {.name = "missing_class=", .func = opt_missing_class_set},
1100
+ {.name = "omit_null", .func = opt_omit_null},
1101
+ {.name = "omit_null=", .func = opt_omit_null_set},
1102
+ {.name = "symbol_keys", .func = opt_symbol_keys},
1103
+ {.name = "symbol_keys=", .func = opt_symbol_keys_set},
1104
+ {.name = "raise_on_empty", .func = opt_raise_on_empty},
1105
+ {.name = "raise_on_empty=", .func = opt_raise_on_empty_set},
1106
+ {.name = NULL},
1097
1107
  };
1098
1108
 
1099
1109
  for (op = opts; NULL != op->name; op++) {
@@ -1109,24 +1119,25 @@ static VALUE option(ojParser p, const char *key, VALUE value) {
1109
1119
  ///// the set up //////////////////////////////////////////////////////////////
1110
1120
 
1111
1121
  void oj_init_usual(ojParser p, Usual d) {
1112
- int cap = 4096;
1122
+ int cap = 4096;
1113
1123
 
1114
- d->vhead = ALLOC_N(VALUE, cap);
1124
+ d->vhead = OJ_R_ALLOC_N(VALUE, cap);
1115
1125
  d->vend = d->vhead + cap;
1116
1126
  d->vtail = d->vhead;
1117
1127
 
1118
- d->khead = ALLOC_N(union _key, cap);
1128
+ d->khead = OJ_R_ALLOC_N(union _key, cap);
1119
1129
  d->kend = d->khead + cap;
1120
1130
  d->ktail = d->khead;
1121
1131
 
1122
1132
  cap = 256;
1123
- d->chead = ALLOC_N(struct _col, cap);
1133
+ d->chead = OJ_R_ALLOC_N(struct _col, cap);
1124
1134
  d->cend = d->chead + cap;
1125
1135
  d->ctail = d->chead;
1126
1136
 
1127
1137
  d->get_key = cache_key;
1128
1138
  d->cache_keys = true;
1129
1139
  d->ignore_json_create = false;
1140
+ d->raise_on_empty = false;
1130
1141
  d->cache_str = 6;
1131
1142
  d->array_class = Qnil;
1132
1143
  d->hash_class = Qnil;
@@ -1201,7 +1212,7 @@ void oj_init_usual(ojParser p, Usual d) {
1201
1212
  }
1202
1213
 
1203
1214
  void oj_set_parser_usual(ojParser p) {
1204
- Usual d = ALLOC(struct _usual);
1215
+ Usual d = OJ_R_ALLOC(struct _usual);
1205
1216
 
1206
1217
  oj_init_usual(p, d);
1207
1218
  }
data/ext/oj/usual.h CHANGED
@@ -13,7 +13,7 @@ struct _ojParser;
13
13
  typedef struct _col {
14
14
  long vi; // value stack index
15
15
  long ki; // key stack index if an hash else -1 for an array
16
- } * Col;
16
+ } *Col;
17
17
 
18
18
  typedef union _key {
19
19
  struct {
@@ -22,9 +22,9 @@ typedef union _key {
22
22
  };
23
23
  struct {
24
24
  int16_t xlen; // should be the same as len
25
- char * key;
25
+ char *key;
26
26
  };
27
- } * Key;
27
+ } *Key;
28
28
 
29
29
  #define MISS_AUTO 'A'
30
30
  #define MISS_RAISE 'R'
@@ -43,7 +43,7 @@ typedef struct _usual {
43
43
  Key ktail;
44
44
  Key kend;
45
45
 
46
- VALUE (*get_key)(ojParser p, Key kp);
46
+ VALUE (*get_key)(struct _ojParser *p, Key kp);
47
47
  struct _cache *key_cache; // same as str_cache or sym_cache
48
48
  struct _cache *str_cache;
49
49
  struct _cache *sym_cache;
@@ -53,14 +53,15 @@ typedef struct _usual {
53
53
  VALUE array_class;
54
54
  VALUE hash_class;
55
55
 
56
- char * create_id;
56
+ char *create_id;
57
57
  uint8_t create_id_len;
58
58
  uint8_t cache_str;
59
59
  uint8_t cache_xrate;
60
60
  uint8_t miss_class;
61
61
  bool cache_keys;
62
62
  bool ignore_json_create;
63
- } * Usual;
63
+ bool raise_on_empty;
64
+ } *Usual;
64
65
 
65
66
  // Initialize the parser with the usual delegate. If the usual delegate is
66
67
  // wrapped then this function is called first and then the parser functions
data/ext/oj/util.h CHANGED
@@ -13,7 +13,7 @@ typedef struct _timeInfo {
13
13
  int day;
14
14
  int mon;
15
15
  int year;
16
- } * TimeInfo;
16
+ }* TimeInfo;
17
17
 
18
18
  extern void sec_as_time(int64_t secs, TimeInfo ti);
19
19
 
data/ext/oj/val_stack.c CHANGED
@@ -8,7 +8,7 @@
8
8
  #include "odd.h"
9
9
  #include "oj.h"
10
10
 
11
- static void mark(void *ptr) {
11
+ static void stack_mark(void *ptr) {
12
12
  ValStack stack = (ValStack)ptr;
13
13
  Val v;
14
14
 
@@ -46,6 +46,17 @@ static void mark(void *ptr) {
46
46
  #endif
47
47
  }
48
48
 
49
+ static const rb_data_type_t oj_stack_type = {
50
+ "Oj/stack",
51
+ {
52
+ stack_mark,
53
+ NULL,
54
+ NULL,
55
+ },
56
+ 0,
57
+ 0,
58
+ };
59
+
49
60
  VALUE
50
61
  oj_stack_init(ValStack stack) {
51
62
  #ifdef HAVE_PTHREAD_MUTEX_INIT
@@ -70,7 +81,7 @@ oj_stack_init(ValStack stack) {
70
81
  stack->head->clen = 0;
71
82
  stack->head->next = NEXT_NONE;
72
83
 
73
- return Data_Wrap_Struct(oj_cstack_class, mark, 0, stack);
84
+ return TypedData_Wrap_Struct(oj_cstack_class, &oj_stack_type, stack);
74
85
  }
75
86
 
76
87
  const char *oj_stack_next_string(ValNext n) {