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/parse.c CHANGED
@@ -12,14 +12,19 @@
12
12
 
13
13
  #include "buf.h"
14
14
  #include "encode.h"
15
+ #include "mem.h"
15
16
  #include "oj.h"
16
17
  #include "rxclass.h"
17
18
  #include "val_stack.h"
18
19
 
20
+ #ifdef OJ_USE_SSE4_2
21
+ #include <nmmintrin.h>
22
+ #endif
23
+
19
24
  // Workaround in case INFINITY is not defined in math.h or if the OS is CentOS
20
25
  #define OJ_INFINITY (1.0 / 0.0)
21
26
 
22
- //#define EXP_MAX 1023
27
+ // #define EXP_MAX 1023
23
28
  #define EXP_MAX 100000
24
29
  #define DEC_MAX 15
25
30
 
@@ -44,11 +49,7 @@ static void skip_comment(ParseInfo pi) {
44
49
  pi->cur += 2;
45
50
  return;
46
51
  } else if (pi->end <= pi->cur) {
47
- oj_set_error_at(pi,
48
- oj_parse_error_class,
49
- __FILE__,
50
- __LINE__,
51
- "comment not terminated");
52
+ oj_set_error_at(pi, oj_parse_error_class, __FILE__, __LINE__, "comment not terminated");
52
53
  return;
53
54
  }
54
55
  }
@@ -81,9 +82,8 @@ static void add_value(ParseInfo pi, VALUE rval) {
81
82
  break;
82
83
  case NEXT_HASH_VALUE:
83
84
  pi->hash_set_value(pi, parent, rval);
84
- if (0 != parent->key && 0 < parent->klen &&
85
- (parent->key < pi->json || pi->cur < parent->key)) {
86
- xfree((char *)parent->key);
85
+ if (0 != parent->key && 0 < parent->klen && (parent->key < pi->json || pi->cur < parent->key)) {
86
+ OJ_R_FREE((char *)parent->key);
87
87
  parent->key = 0;
88
88
  }
89
89
  parent->next = NEXT_HASH_COMMA;
@@ -192,19 +192,21 @@ static inline const char *scan_string_noSIMD(const char *str, const char *end) {
192
192
  return str;
193
193
  }
194
194
 
195
- #if defined(OJ_USE_SSE4_2)
196
- #include <nmmintrin.h>
197
-
195
+ #ifdef OJ_USE_SSE4_2
198
196
  static inline const char *scan_string_SIMD(const char *str, const char *end) {
199
197
  static const char chars[16] = "\x00\\\"";
200
- const __m128i terminate = _mm_loadu_si128((const __m128i *)&chars[0]);
201
- const char *_end = (const char *)(end - 16);
198
+ const __m128i terminate = _mm_loadu_si128((const __m128i *)&chars[0]);
199
+ const char *_end = (const char *)(end - 16);
202
200
 
203
201
  for (; str <= _end; str += 16) {
204
202
  const __m128i string = _mm_loadu_si128((const __m128i *)str);
205
- const int r = _mm_cmpestri(terminate, 3, string, 16, _SIDD_UBYTE_OPS | _SIDD_CMP_EQUAL_ANY | _SIDD_LEAST_SIGNIFICANT);
203
+ const int r = _mm_cmpestri(terminate,
204
+ 3,
205
+ string,
206
+ 16,
207
+ _SIDD_UBYTE_OPS | _SIDD_CMP_EQUAL_ANY | _SIDD_LEAST_SIGNIFICANT);
206
208
  if (r != 16) {
207
- str = (char*)(str + r);
209
+ str = (char *)(str + r);
208
210
  return str;
209
211
  }
210
212
  }
@@ -213,6 +215,14 @@ static inline const char *scan_string_SIMD(const char *str, const char *end) {
213
215
  }
214
216
  #endif
215
217
 
218
+ static const char *(*scan_func)(const char *str, const char *end) = scan_string_noSIMD;
219
+
220
+ void oj_scanner_init(void) {
221
+ #ifdef OJ_USE_SSE4_2
222
+ scan_func = scan_string_SIMD;
223
+ #endif
224
+ }
225
+
216
226
  // entered at /
217
227
  static void read_escaped_str(ParseInfo pi, const char *start) {
218
228
  struct _buf buf;
@@ -225,21 +235,13 @@ static void read_escaped_str(ParseInfo pi, const char *start) {
225
235
  buf_append_string(&buf, start, cnt);
226
236
 
227
237
  for (s = pi->cur; '"' != *s;) {
228
- #if defined(OJ_USE_SSE4_2)
229
- const char *scanned = scan_string_SIMD(s, pi->end);
230
- #else
231
- const char *scanned = scan_string_noSIMD(s, pi->end);
232
- #endif
233
- if (scanned >= pi->end) {
234
- oj_set_error_at(pi,
235
- oj_parse_error_class,
236
- __FILE__,
237
- __LINE__,
238
- "quoted string not terminated");
238
+ const char *scanned = scan_func(s, pi->end);
239
+ if (scanned >= pi->end || '\0' == *scanned) {
240
+ // if (scanned >= pi->end) {
241
+ oj_set_error_at(pi, oj_parse_error_class, __FILE__, __LINE__, "quoted string not terminated");
239
242
  buf_cleanup(&buf);
240
243
  return;
241
244
  }
242
-
243
245
  buf_append_string(&buf, s, (size_t)(scanned - s));
244
246
  s = scanned;
245
247
 
@@ -273,11 +275,7 @@ static void read_escaped_str(ParseInfo pi, const char *start) {
273
275
  break;
274
276
  }
275
277
  pi->cur = s;
276
- oj_set_error_at(pi,
277
- oj_parse_error_class,
278
- __FILE__,
279
- __LINE__,
280
- "invalid escaped character");
278
+ oj_set_error_at(pi, oj_parse_error_class, __FILE__, __LINE__, "invalid escaped character");
281
279
  buf_cleanup(&buf);
282
280
  return;
283
281
  }
@@ -304,11 +302,7 @@ static void read_escaped_str(ParseInfo pi, const char *start) {
304
302
  break;
305
303
  }
306
304
  pi->cur = s;
307
- oj_set_error_at(pi,
308
- oj_parse_error_class,
309
- __FILE__,
310
- __LINE__,
311
- "invalid escaped character");
305
+ oj_set_error_at(pi, oj_parse_error_class, __FILE__, __LINE__, "invalid escaped character");
312
306
  buf_cleanup(&buf);
313
307
  return;
314
308
  }
@@ -328,7 +322,7 @@ static void read_escaped_str(ParseInfo pi, const char *start) {
328
322
  case NEXT_HASH_KEY:
329
323
  if (Qundef == (parent->key_val = pi->hash_key(pi, buf.head, buf_len(&buf)))) {
330
324
  parent->klen = buf_len(&buf);
331
- parent->key = malloc(parent->klen + 1);
325
+ parent->key = OJ_MALLOC(parent->klen + 1);
332
326
  memcpy((char *)parent->key, buf.head, parent->klen);
333
327
  *(char *)(parent->key + parent->klen) = '\0';
334
328
  } else {
@@ -340,9 +334,8 @@ static void read_escaped_str(ParseInfo pi, const char *start) {
340
334
  break;
341
335
  case NEXT_HASH_VALUE:
342
336
  pi->hash_set_cstr(pi, parent, buf.head, buf_len(&buf), start);
343
- if (0 != parent->key && 0 < parent->klen &&
344
- (parent->key < pi->json || pi->cur < parent->key)) {
345
- xfree((char *)parent->key);
337
+ if (0 != parent->key && 0 < parent->klen && (parent->key < pi->json || pi->cur < parent->key)) {
338
+ OJ_R_FREE((char *)parent->key);
346
339
  parent->key = 0;
347
340
  }
348
341
  parent->next = NEXT_HASH_COMMA;
@@ -369,17 +362,9 @@ static void read_str(ParseInfo pi) {
369
362
  const char *str = pi->cur;
370
363
  Val parent = stack_peek(&pi->stack);
371
364
 
372
- #if defined(OJ_USE_SSE4_2)
373
- pi->cur = scan_string_SIMD(pi->cur, pi->end);
374
- #else
375
- pi->cur = scan_string_noSIMD(pi->cur, pi->end);
376
- #endif
365
+ pi->cur = scan_func(pi->cur, pi->end);
377
366
  if (RB_UNLIKELY(pi->end <= pi->cur)) {
378
- oj_set_error_at(pi,
379
- oj_parse_error_class,
380
- __FILE__,
381
- __LINE__,
382
- "quoted string not terminated");
367
+ oj_set_error_at(pi, oj_parse_error_class, __FILE__, __LINE__, "quoted string not terminated");
383
368
  return;
384
369
  }
385
370
  if (RB_UNLIKELY('\0' == *pi->cur)) {
@@ -414,9 +399,8 @@ static void read_str(ParseInfo pi) {
414
399
  break;
415
400
  case NEXT_HASH_VALUE:
416
401
  pi->hash_set_cstr(pi, parent, str, pi->cur - str, str);
417
- if (0 != parent->key && 0 < parent->klen &&
418
- (parent->key < pi->json || pi->cur < parent->key)) {
419
- xfree((char *)parent->key);
402
+ if (0 != parent->key && 0 < parent->klen && (parent->key < pi->json || pi->cur < parent->key)) {
403
+ OJ_R_FREE((char *)parent->key);
420
404
  parent->key = 0;
421
405
  }
422
406
  parent->next = NEXT_HASH_COMMA;
@@ -442,6 +426,7 @@ static void read_num(ParseInfo pi) {
442
426
  struct _numInfo ni;
443
427
  Val parent = stack_peek(&pi->stack);
444
428
 
429
+ ni.pi = pi;
445
430
  ni.str = pi->cur;
446
431
  ni.i = 0;
447
432
  ni.num = 0;
@@ -458,7 +443,7 @@ static void read_num(ParseInfo pi) {
458
443
  ni.no_big = !pi->options.compat_bigdec;
459
444
  ni.bigdec_load = pi->options.compat_bigdec;
460
445
  } else {
461
- ni.no_big = (FloatDec == pi->options.bigdec_load || FastDec == pi->options.bigdec_load ||
446
+ ni.no_big = (FloatDec == pi->options.bigdec_load || FastDec == pi->options.bigdec_load ||
462
447
  RubyDec == pi->options.bigdec_load);
463
448
  ni.bigdec_load = pi->options.bigdec_load;
464
449
  }
@@ -468,33 +453,21 @@ static void read_num(ParseInfo pi) {
468
453
  ni.neg = 1;
469
454
  } else if ('+' == *pi->cur) {
470
455
  if (StrictMode == pi->options.mode) {
471
- oj_set_error_at(pi,
472
- oj_parse_error_class,
473
- __FILE__,
474
- __LINE__,
475
- "not a number or other value");
456
+ oj_set_error_at(pi, oj_parse_error_class, __FILE__, __LINE__, "not a number or other value");
476
457
  return;
477
458
  }
478
459
  pi->cur++;
479
460
  }
480
461
  if ('I' == *pi->cur) {
481
462
  if (No == pi->options.allow_nan || 0 != strncmp("Infinity", pi->cur, 8)) {
482
- oj_set_error_at(pi,
483
- oj_parse_error_class,
484
- __FILE__,
485
- __LINE__,
486
- "not a number or other value");
463
+ oj_set_error_at(pi, oj_parse_error_class, __FILE__, __LINE__, "not a number or other value");
487
464
  return;
488
465
  }
489
466
  pi->cur += 8;
490
467
  ni.infinity = 1;
491
468
  } else if ('N' == *pi->cur || 'n' == *pi->cur) {
492
469
  if ('a' != pi->cur[1] || ('N' != pi->cur[2] && 'n' != pi->cur[2])) {
493
- oj_set_error_at(pi,
494
- oj_parse_error_class,
495
- __FILE__,
496
- __LINE__,
497
- "not a number or other value");
470
+ oj_set_error_at(pi, oj_parse_error_class, __FILE__, __LINE__, "not a number or other value");
498
471
  return;
499
472
  }
500
473
  pi->cur += 3;
@@ -503,33 +476,27 @@ static void read_num(ParseInfo pi) {
503
476
  int dec_cnt = 0;
504
477
  bool zero1 = false;
505
478
 
479
+ // Skip leading zeros.
480
+ for (; '0' == *pi->cur; pi->cur++) {
481
+ zero1 = true;
482
+ }
483
+
506
484
  for (; '0' <= *pi->cur && *pi->cur <= '9'; pi->cur++) {
507
- if (0 == ni.i && '0' == *pi->cur) {
508
- zero1 = true;
509
- }
510
- if (0 < ni.i) {
511
- dec_cnt++;
512
- }
513
- if (!ni.big) {
514
- int d = (*pi->cur - '0');
485
+ int d = (*pi->cur - '0');
515
486
 
516
- if (0 < d) {
517
- if (zero1 && CompatMode == pi->options.mode) {
518
- oj_set_error_at(pi,
519
- oj_parse_error_class,
520
- __FILE__,
521
- __LINE__,
522
- "not a number");
523
- return;
524
- }
525
- zero1 = false;
526
- }
527
- ni.i = ni.i * 10 + d;
528
- if (INT64_MAX <= ni.i || DEC_MAX < dec_cnt) {
529
- ni.big = 1;
530
- }
487
+ if (RB_LIKELY(0 != ni.i)) {
488
+ dec_cnt++;
531
489
  }
490
+ ni.i = ni.i * 10 + d;
491
+ }
492
+ if (RB_UNLIKELY(0 != ni.i && zero1 && CompatMode == pi->options.mode)) {
493
+ oj_set_error_at(pi, oj_parse_error_class, __FILE__, __LINE__, "not a number");
494
+ return;
495
+ }
496
+ if (INT64_MAX <= ni.i || DEC_MAX < dec_cnt) {
497
+ ni.big = true;
532
498
  }
499
+
533
500
  if ('.' == *pi->cur) {
534
501
  pi->cur++;
535
502
  // A trailing . is not a valid decimal but if encountered allow it
@@ -549,25 +516,20 @@ static void read_num(ParseInfo pi) {
549
516
  for (; '0' <= *pi->cur && *pi->cur <= '9'; pi->cur++) {
550
517
  int d = (*pi->cur - '0');
551
518
 
552
- if (0 < ni.num || 0 < ni.i) {
519
+ if (RB_LIKELY(0 != ni.num || 0 != ni.i)) {
553
520
  dec_cnt++;
554
521
  }
555
- if (INT64_MAX <= ni.div) {
556
- if (!ni.no_big) {
557
- ni.big = true;
558
- }
559
- } else {
560
- ni.num = ni.num * 10 + d;
561
- ni.div *= 10;
562
- ni.di++;
563
- if (INT64_MAX <= ni.div || DEC_MAX < dec_cnt) {
564
- if (!ni.no_big) {
565
- ni.big = true;
566
- }
567
- }
568
- }
522
+ ni.num = ni.num * 10 + d;
523
+ ni.div *= 10;
524
+ ni.di++;
569
525
  }
570
526
  }
527
+ if (INT64_MAX <= ni.div || DEC_MAX < dec_cnt) {
528
+ if (!ni.no_big) {
529
+ ni.big = true;
530
+ }
531
+ }
532
+
571
533
  if ('e' == *pi->cur || 'E' == *pi->cur) {
572
534
  int eneg = 0;
573
535
 
@@ -620,9 +582,8 @@ static void read_num(ParseInfo pi) {
620
582
  break;
621
583
  case NEXT_HASH_VALUE:
622
584
  pi->hash_set_num(pi, parent, &ni);
623
- if (0 != parent->key && 0 < parent->klen &&
624
- (parent->key < pi->json || pi->cur < parent->key)) {
625
- xfree((char *)parent->key);
585
+ if (0 != parent->key && 0 < parent->klen && (parent->key < pi->json || pi->cur < parent->key)) {
586
+ OJ_R_FREE((char *)parent->key);
626
587
  parent->key = 0;
627
588
  }
628
589
  parent->next = NEXT_HASH_COMMA;
@@ -640,7 +601,7 @@ static void read_num(ParseInfo pi) {
640
601
  }
641
602
 
642
603
  static void array_start(ParseInfo pi) {
643
- volatile VALUE v = pi->start_array(pi);
604
+ VALUE v = pi->start_array(pi);
644
605
 
645
606
  stack_push(&pi->stack, v, NEXT_ARRAY_NEW);
646
607
  }
@@ -664,13 +625,13 @@ static void array_end(ParseInfo pi) {
664
625
  }
665
626
 
666
627
  static void hash_start(ParseInfo pi) {
667
- volatile VALUE v = pi->start_hash(pi);
628
+ VALUE v = pi->start_hash(pi);
668
629
 
669
630
  stack_push(&pi->stack, v, NEXT_HASH_NEW);
670
631
  }
671
632
 
672
633
  static void hash_end(ParseInfo pi) {
673
- volatile Val hash = stack_peek(&pi->stack);
634
+ Val hash = stack_peek(&pi->stack);
674
635
 
675
636
  // leave hash on stack until just before
676
637
  if (0 == hash) {
@@ -749,17 +710,10 @@ void oj_parse2(ParseInfo pi) {
749
710
  case '[': array_start(pi); break;
750
711
  case ']': array_end(pi); break;
751
712
  case ',': comma(pi); break;
752
- case '"':
753
- read_str(pi);
754
- break;
755
- // case '+':
713
+ case '"': read_str(pi); break;
756
714
  case '+':
757
715
  if (CompatMode == pi->options.mode) {
758
- oj_set_error_at(pi,
759
- oj_parse_error_class,
760
- __FILE__,
761
- __LINE__,
762
- "unexpected character");
716
+ oj_set_error_at(pi, oj_parse_error_class, __FILE__, __LINE__, "unexpected character");
763
717
  return;
764
718
  }
765
719
  pi->cur--;
@@ -785,11 +739,7 @@ void oj_parse2(ParseInfo pi) {
785
739
  pi->cur--;
786
740
  read_num(pi);
787
741
  } else {
788
- oj_set_error_at(pi,
789
- oj_parse_error_class,
790
- __FILE__,
791
- __LINE__,
792
- "unexpected character");
742
+ oj_set_error_at(pi, oj_parse_error_class, __FILE__, __LINE__, "unexpected character");
793
743
  }
794
744
  break;
795
745
  case 't': read_true(pi); break;
@@ -809,9 +759,7 @@ void oj_parse2(ParseInfo pi) {
809
759
  }
810
760
  break;
811
761
  case '\0': pi->cur--; return;
812
- default:
813
- oj_set_error_at(pi, oj_parse_error_class, __FILE__, __LINE__, "unexpected character");
814
- return;
762
+ default: oj_set_error_at(pi, oj_parse_error_class, __FILE__, __LINE__, "unexpected character"); return;
815
763
  }
816
764
  if (err_has(&pi->err)) {
817
765
  return;
@@ -848,16 +796,15 @@ static VALUE parse_big_decimal(VALUE str) {
848
796
  }
849
797
 
850
798
  static long double exp_plus[] = {
851
- 1.0, 1.0e1, 1.0e2, 1.0e3, 1.0e4, 1.0e5, 1.0e6, 1.0e7, 1.0e8, 1.0e9,
852
- 1.0e10, 1.0e11, 1.0e12, 1.0e13, 1.0e14, 1.0e15, 1.0e16, 1.0e17, 1.0e18, 1.0e19,
853
- 1.0e20, 1.0e21, 1.0e22, 1.0e23, 1.0e24, 1.0e25, 1.0e26, 1.0e27, 1.0e28, 1.0e29,
854
- 1.0e30, 1.0e31, 1.0e32, 1.0e33, 1.0e34, 1.0e35, 1.0e36, 1.0e37, 1.0e38, 1.0e39,
855
- 1.0e40, 1.0e41, 1.0e42, 1.0e43, 1.0e44, 1.0e45, 1.0e46, 1.0e47, 1.0e48, 1.0e49,
799
+ 1.0, 1.0e1, 1.0e2, 1.0e3, 1.0e4, 1.0e5, 1.0e6, 1.0e7, 1.0e8, 1.0e9, 1.0e10, 1.0e11, 1.0e12,
800
+ 1.0e13, 1.0e14, 1.0e15, 1.0e16, 1.0e17, 1.0e18, 1.0e19, 1.0e20, 1.0e21, 1.0e22, 1.0e23, 1.0e24, 1.0e25,
801
+ 1.0e26, 1.0e27, 1.0e28, 1.0e29, 1.0e30, 1.0e31, 1.0e32, 1.0e33, 1.0e34, 1.0e35, 1.0e36, 1.0e37, 1.0e38,
802
+ 1.0e39, 1.0e40, 1.0e41, 1.0e42, 1.0e43, 1.0e44, 1.0e45, 1.0e46, 1.0e47, 1.0e48, 1.0e49,
856
803
  };
857
804
 
858
805
  VALUE
859
806
  oj_num_as_value(NumInfo ni) {
860
- volatile VALUE rnum = Qnil;
807
+ VALUE rnum = Qnil;
861
808
 
862
809
  if (ni->infinity) {
863
810
  if (ni->neg) {
@@ -876,12 +823,12 @@ oj_num_as_value(NumInfo ni) {
876
823
  buf[ni->len] = '\0';
877
824
  rnum = rb_cstr_to_inum(buf, 10, 0);
878
825
  } else {
879
- char *buf = ALLOC_N(char, ni->len + 1);
826
+ char *buf = OJ_R_ALLOC_N(char, ni->len + 1);
880
827
 
881
828
  memcpy(buf, ni->str, ni->len);
882
829
  buf[ni->len] = '\0';
883
830
  rnum = rb_cstr_to_inum(buf, 10, 0);
884
- xfree(buf);
831
+ OJ_R_FREE(buf);
885
832
  }
886
833
  } else {
887
834
  if (ni->neg) {
@@ -892,7 +839,7 @@ oj_num_as_value(NumInfo ni) {
892
839
  }
893
840
  } else { // decimal
894
841
  if (ni->big) {
895
- volatile VALUE bd = rb_str_new(ni->str, ni->len);
842
+ VALUE bd = rb_str_new(ni->str, ni->len);
896
843
 
897
844
  rnum = rb_rescue2(parse_big_decimal, bd, rescue_big_decimal, bd, rb_eException, 0);
898
845
  if (ni->no_big) {
@@ -920,15 +867,19 @@ oj_num_as_value(NumInfo ni) {
920
867
  }
921
868
  rnum = rb_float_new((double)ld);
922
869
  } else if (RubyDec == ni->bigdec_load) {
923
- volatile VALUE sv = rb_str_new(ni->str, ni->len);
870
+ VALUE sv = rb_str_new(ni->str, ni->len);
924
871
 
925
872
  rnum = rb_funcall(sv, rb_intern("to_f"), 0);
926
873
  } else {
927
- char * end;
874
+ char *end;
928
875
  double d = strtod(ni->str, &end);
929
876
 
930
877
  if ((long)ni->len != (long)(end - ni->str)) {
931
- rb_raise(oj_parse_error_class, "Invalid float");
878
+ if (Qnil == ni->pi->err_class) {
879
+ rb_raise(oj_parse_error_class, "Invalid float");
880
+ } else {
881
+ rb_raise(ni->pi->err_class, "Invalid float");
882
+ }
932
883
  }
933
884
  rnum = rb_float_new(d);
934
885
  }
@@ -936,28 +887,23 @@ oj_num_as_value(NumInfo ni) {
936
887
  return rnum;
937
888
  }
938
889
 
939
- void oj_set_error_at(ParseInfo pi,
940
- VALUE err_clas,
941
- const char *file,
942
- int line,
943
- const char *format,
944
- ...) {
890
+ void oj_set_error_at(ParseInfo pi, VALUE err_clas, const char *file, int line, const char *format, ...) {
945
891
  va_list ap;
946
892
  char msg[256];
947
- char * p = msg;
948
- char * end = p + sizeof(msg) - 2;
949
- char * start;
893
+ char *p = msg;
894
+ char *end = p + sizeof(msg) - 2;
895
+ char *start;
950
896
  Val vp;
951
- int mlen;
897
+ int mlen;
952
898
 
953
899
  va_start(ap, format);
954
900
  mlen = vsnprintf(msg, sizeof(msg) - 1, format, ap);
955
901
  if (0 < mlen) {
956
- if (sizeof(msg) - 2 < (size_t)mlen) {
957
- p = end - 2;
958
- } else {
959
- p += mlen;
960
- }
902
+ if (sizeof(msg) - 2 < (size_t)mlen) {
903
+ p = end - 2;
904
+ } else {
905
+ p += mlen;
906
+ }
961
907
  }
962
908
  va_end(ap);
963
909
  pi->err.clas = err_clas;
@@ -994,14 +940,7 @@ void oj_set_error_at(ParseInfo pi,
994
940
  }
995
941
  *p = '\0';
996
942
  if (0 == pi->json) {
997
- oj_err_set(&pi->err,
998
- err_clas,
999
- "%s at line %d, column %d [%s:%d]",
1000
- msg,
1001
- pi->rd.line,
1002
- pi->rd.col,
1003
- file,
1004
- line);
943
+ oj_err_set(&pi->err, err_clas, "%s at line %d, column %d [%s:%d]", msg, pi->rd.line, pi->rd.col, file, line);
1005
944
  } else {
1006
945
  _oj_err_set_with_location(&pi->err, err_clas, msg, pi->json, pi->cur - 1, file, line);
1007
946
  }
@@ -1015,12 +954,12 @@ static VALUE protect_parse(VALUE pip) {
1015
954
 
1016
955
  extern int oj_utf8_index;
1017
956
 
1018
- static void oj_pi_set_input_str(ParseInfo pi, volatile VALUE *inputp) {
957
+ static void oj_pi_set_input_str(ParseInfo pi, VALUE *inputp) {
1019
958
  int idx = RB_ENCODING_GET(*inputp);
1020
959
 
1021
960
  if (oj_utf8_encoding_index != idx) {
1022
961
  rb_encoding *enc = rb_enc_from_index(idx);
1023
- *inputp = rb_str_conv_enc(*inputp, enc, oj_utf8_encoding);
962
+ *inputp = rb_str_conv_enc(*inputp, enc, oj_utf8_encoding);
1024
963
  }
1025
964
  pi->json = RSTRING_PTR(*inputp);
1026
965
  pi->end = pi->json + RSTRING_LEN(*inputp);
@@ -1028,12 +967,12 @@ static void oj_pi_set_input_str(ParseInfo pi, volatile VALUE *inputp) {
1028
967
 
1029
968
  VALUE
1030
969
  oj_pi_parse(int argc, VALUE *argv, ParseInfo pi, char *json, size_t len, int yieldOk) {
1031
- char * buf = 0;
1032
- volatile VALUE input;
1033
- volatile VALUE wrapped_stack;
1034
- volatile VALUE result = Qnil;
1035
- int line = 0;
1036
- int free_json = 0;
970
+ char *buf = 0;
971
+ VALUE input;
972
+ VALUE wrapped_stack;
973
+ VALUE result = Qnil;
974
+ int line = 0;
975
+ int free_json = 0;
1037
976
 
1038
977
  if (argc < 1) {
1039
978
  rb_raise(rb_eArgError, "Wrong number of arguments to parse.");
@@ -1069,8 +1008,8 @@ oj_pi_parse(int argc, VALUE *argv, ParseInfo pi, char *json, size_t len, int yie
1069
1008
  rb_raise(rb_eTypeError, "Nil is not a valid JSON source.");
1070
1009
  }
1071
1010
  } else {
1072
- VALUE clas = rb_obj_class(input);
1073
- volatile VALUE s;
1011
+ VALUE clas = rb_obj_class(input);
1012
+ VALUE s;
1074
1013
 
1075
1014
  if (oj_stringio_class == clas) {
1076
1015
  s = rb_funcall2(input, oj_string_id, 0, 0);
@@ -1082,19 +1021,18 @@ oj_pi_parse(int argc, VALUE *argv, ParseInfo pi, char *json, size_t len, int yie
1082
1021
  size_t len = lseek(fd, 0, SEEK_END);
1083
1022
 
1084
1023
  lseek(fd, 0, SEEK_SET);
1085
- buf = ALLOC_N(char, len + 1);
1024
+ buf = OJ_R_ALLOC_N(char, len + 1);
1086
1025
  pi->json = buf;
1087
1026
  pi->end = buf + len;
1088
1027
  if (0 >= (cnt = read(fd, (char *)pi->json, len)) || cnt != (ssize_t)len) {
1089
1028
  if (0 != buf) {
1090
- xfree(buf);
1029
+ OJ_R_FREE(buf);
1091
1030
  }
1092
1031
  rb_raise(rb_eIOError, "failed to read from IO Object.");
1093
1032
  }
1094
1033
  ((char *)pi->json)[len] = '\0';
1095
1034
  /* skip UTF-8 BOM if present */
1096
- if (0xEF == (uint8_t)*pi->json && 0xBB == (uint8_t)pi->json[1] &&
1097
- 0xBF == (uint8_t)pi->json[2]) {
1035
+ if (0xEF == (uint8_t)*pi->json && 0xBB == (uint8_t)pi->json[1] && 0xBF == (uint8_t)pi->json[2]) {
1098
1036
  pi->cur += 3;
1099
1037
  }
1100
1038
  #endif
@@ -1120,8 +1058,7 @@ oj_pi_parse(int argc, VALUE *argv, ParseInfo pi, char *json, size_t len, int yie
1120
1058
  wrapped_stack = oj_stack_init(&pi->stack);
1121
1059
  rb_protect(protect_parse, (VALUE)pi, &line);
1122
1060
  if (Qundef == pi->stack.head->val && !empty_ok(&pi->options)) {
1123
- if (No == pi->options.nilnil ||
1124
- (CompatMode == pi->options.mode && 0 < pi->cur - pi->json)) {
1061
+ if (No == pi->options.nilnil || (CompatMode == pi->options.mode && 0 < pi->cur - pi->json)) {
1125
1062
  oj_set_error_at(pi, oj_json_parser_error_class, __FILE__, __LINE__, "Empty input");
1126
1063
  }
1127
1064
  }
@@ -1149,9 +1086,7 @@ oj_pi_parse(int argc, VALUE *argv, ParseInfo pi, char *json, size_t len, int yie
1149
1086
  switch (v->next) {
1150
1087
  case NEXT_ARRAY_NEW:
1151
1088
  case NEXT_ARRAY_ELEMENT:
1152
- case NEXT_ARRAY_COMMA:
1153
- oj_set_error_at(pi, err_class, __FILE__, __LINE__, "Array not terminated");
1154
- break;
1089
+ case NEXT_ARRAY_COMMA: oj_set_error_at(pi, err_class, __FILE__, __LINE__, "Array not terminated"); break;
1155
1090
  case NEXT_HASH_NEW:
1156
1091
  case NEXT_HASH_KEY:
1157
1092
  case NEXT_HASH_COLON:
@@ -1169,9 +1104,9 @@ CLEANUP:
1169
1104
  oj_circ_array_free(pi->circ_array);
1170
1105
  }
1171
1106
  if (0 != buf) {
1172
- xfree(buf);
1107
+ OJ_R_FREE(buf);
1173
1108
  } else if (free_json) {
1174
- xfree(json);
1109
+ OJ_R_FREE(json);
1175
1110
  }
1176
1111
  stack_cleanup(&pi->stack);
1177
1112
  if (pi->str_rx.head != oj_default_options.str_rx.head) {