oj 3.13.23 → 3.16.9

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 (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/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;
@@ -195,14 +195,18 @@ static inline const char *scan_string_noSIMD(const char *str, const char *end) {
195
195
  #ifdef OJ_USE_SSE4_2
196
196
  static inline const char *scan_string_SIMD(const char *str, const char *end) {
197
197
  static const char chars[16] = "\x00\\\"";
198
- const __m128i terminate = _mm_loadu_si128((const __m128i *)&chars[0]);
199
- 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);
200
200
 
201
201
  for (; str <= _end; str += 16) {
202
202
  const __m128i string = _mm_loadu_si128((const __m128i *)str);
203
- 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);
204
208
  if (r != 16) {
205
- str = (char*)(str + r);
209
+ str = (char *)(str + r);
206
210
  return str;
207
211
  }
208
212
  }
@@ -211,7 +215,7 @@ static inline const char *scan_string_SIMD(const char *str, const char *end) {
211
215
  }
212
216
  #endif
213
217
 
214
- static const char *(*scan_func) (const char *str, const char *end) = scan_string_noSIMD;
218
+ static const char *(*scan_func)(const char *str, const char *end) = scan_string_noSIMD;
215
219
 
216
220
  void oj_scanner_init(void) {
217
221
  #ifdef OJ_USE_SSE4_2
@@ -232,16 +236,12 @@ static void read_escaped_str(ParseInfo pi, const char *start) {
232
236
 
233
237
  for (s = pi->cur; '"' != *s;) {
234
238
  const char *scanned = scan_func(s, pi->end);
235
- if (scanned >= pi->end) {
236
- oj_set_error_at(pi,
237
- oj_parse_error_class,
238
- __FILE__,
239
- __LINE__,
240
- "quoted string not terminated");
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");
241
242
  buf_cleanup(&buf);
242
243
  return;
243
244
  }
244
-
245
245
  buf_append_string(&buf, s, (size_t)(scanned - s));
246
246
  s = scanned;
247
247
 
@@ -275,11 +275,7 @@ static void read_escaped_str(ParseInfo pi, const char *start) {
275
275
  break;
276
276
  }
277
277
  pi->cur = s;
278
- oj_set_error_at(pi,
279
- oj_parse_error_class,
280
- __FILE__,
281
- __LINE__,
282
- "invalid escaped character");
278
+ oj_set_error_at(pi, oj_parse_error_class, __FILE__, __LINE__, "invalid escaped character");
283
279
  buf_cleanup(&buf);
284
280
  return;
285
281
  }
@@ -306,11 +302,7 @@ static void read_escaped_str(ParseInfo pi, const char *start) {
306
302
  break;
307
303
  }
308
304
  pi->cur = s;
309
- oj_set_error_at(pi,
310
- oj_parse_error_class,
311
- __FILE__,
312
- __LINE__,
313
- "invalid escaped character");
305
+ oj_set_error_at(pi, oj_parse_error_class, __FILE__, __LINE__, "invalid escaped character");
314
306
  buf_cleanup(&buf);
315
307
  return;
316
308
  }
@@ -330,7 +322,7 @@ static void read_escaped_str(ParseInfo pi, const char *start) {
330
322
  case NEXT_HASH_KEY:
331
323
  if (Qundef == (parent->key_val = pi->hash_key(pi, buf.head, buf_len(&buf)))) {
332
324
  parent->klen = buf_len(&buf);
333
- parent->key = malloc(parent->klen + 1);
325
+ parent->key = OJ_MALLOC(parent->klen + 1);
334
326
  memcpy((char *)parent->key, buf.head, parent->klen);
335
327
  *(char *)(parent->key + parent->klen) = '\0';
336
328
  } else {
@@ -342,9 +334,8 @@ static void read_escaped_str(ParseInfo pi, const char *start) {
342
334
  break;
343
335
  case NEXT_HASH_VALUE:
344
336
  pi->hash_set_cstr(pi, parent, buf.head, buf_len(&buf), start);
345
- if (0 != parent->key && 0 < parent->klen &&
346
- (parent->key < pi->json || pi->cur < parent->key)) {
347
- 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);
348
339
  parent->key = 0;
349
340
  }
350
341
  parent->next = NEXT_HASH_COMMA;
@@ -373,11 +364,7 @@ static void read_str(ParseInfo pi) {
373
364
 
374
365
  pi->cur = scan_func(pi->cur, pi->end);
375
366
  if (RB_UNLIKELY(pi->end <= pi->cur)) {
376
- oj_set_error_at(pi,
377
- oj_parse_error_class,
378
- __FILE__,
379
- __LINE__,
380
- "quoted string not terminated");
367
+ oj_set_error_at(pi, oj_parse_error_class, __FILE__, __LINE__, "quoted string not terminated");
381
368
  return;
382
369
  }
383
370
  if (RB_UNLIKELY('\0' == *pi->cur)) {
@@ -412,9 +399,8 @@ static void read_str(ParseInfo pi) {
412
399
  break;
413
400
  case NEXT_HASH_VALUE:
414
401
  pi->hash_set_cstr(pi, parent, str, pi->cur - str, str);
415
- if (0 != parent->key && 0 < parent->klen &&
416
- (parent->key < pi->json || pi->cur < parent->key)) {
417
- 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);
418
404
  parent->key = 0;
419
405
  }
420
406
  parent->next = NEXT_HASH_COMMA;
@@ -440,6 +426,7 @@ static void read_num(ParseInfo pi) {
440
426
  struct _numInfo ni;
441
427
  Val parent = stack_peek(&pi->stack);
442
428
 
429
+ ni.pi = pi;
443
430
  ni.str = pi->cur;
444
431
  ni.i = 0;
445
432
  ni.num = 0;
@@ -456,7 +443,7 @@ static void read_num(ParseInfo pi) {
456
443
  ni.no_big = !pi->options.compat_bigdec;
457
444
  ni.bigdec_load = pi->options.compat_bigdec;
458
445
  } else {
459
- 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 ||
460
447
  RubyDec == pi->options.bigdec_load);
461
448
  ni.bigdec_load = pi->options.bigdec_load;
462
449
  }
@@ -466,33 +453,21 @@ static void read_num(ParseInfo pi) {
466
453
  ni.neg = 1;
467
454
  } else if ('+' == *pi->cur) {
468
455
  if (StrictMode == pi->options.mode) {
469
- oj_set_error_at(pi,
470
- oj_parse_error_class,
471
- __FILE__,
472
- __LINE__,
473
- "not a number or other value");
456
+ oj_set_error_at(pi, oj_parse_error_class, __FILE__, __LINE__, "not a number or other value");
474
457
  return;
475
458
  }
476
459
  pi->cur++;
477
460
  }
478
461
  if ('I' == *pi->cur) {
479
462
  if (No == pi->options.allow_nan || 0 != strncmp("Infinity", pi->cur, 8)) {
480
- oj_set_error_at(pi,
481
- oj_parse_error_class,
482
- __FILE__,
483
- __LINE__,
484
- "not a number or other value");
463
+ oj_set_error_at(pi, oj_parse_error_class, __FILE__, __LINE__, "not a number or other value");
485
464
  return;
486
465
  }
487
466
  pi->cur += 8;
488
467
  ni.infinity = 1;
489
468
  } else if ('N' == *pi->cur || 'n' == *pi->cur) {
490
469
  if ('a' != pi->cur[1] || ('N' != pi->cur[2] && 'n' != pi->cur[2])) {
491
- oj_set_error_at(pi,
492
- oj_parse_error_class,
493
- __FILE__,
494
- __LINE__,
495
- "not a number or other value");
470
+ oj_set_error_at(pi, oj_parse_error_class, __FILE__, __LINE__, "not a number or other value");
496
471
  return;
497
472
  }
498
473
  pi->cur += 3;
@@ -515,11 +490,7 @@ static void read_num(ParseInfo pi) {
515
490
  ni.i = ni.i * 10 + d;
516
491
  }
517
492
  if (RB_UNLIKELY(0 != ni.i && zero1 && CompatMode == pi->options.mode)) {
518
- oj_set_error_at(pi,
519
- oj_parse_error_class,
520
- __FILE__,
521
- __LINE__,
522
- "not a number");
493
+ oj_set_error_at(pi, oj_parse_error_class, __FILE__, __LINE__, "not a number");
523
494
  return;
524
495
  }
525
496
  if (INT64_MAX <= ni.i || DEC_MAX < dec_cnt) {
@@ -611,9 +582,8 @@ static void read_num(ParseInfo pi) {
611
582
  break;
612
583
  case NEXT_HASH_VALUE:
613
584
  pi->hash_set_num(pi, parent, &ni);
614
- if (0 != parent->key && 0 < parent->klen &&
615
- (parent->key < pi->json || pi->cur < parent->key)) {
616
- 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);
617
587
  parent->key = 0;
618
588
  }
619
589
  parent->next = NEXT_HASH_COMMA;
@@ -711,7 +681,7 @@ void oj_parse2(ParseInfo pi) {
711
681
  pi->cur = pi->json;
712
682
  err_init(&pi->err);
713
683
  while (1) {
714
- if (0 < pi->max_depth && pi->max_depth <= pi->stack.tail - pi->stack.head - 1) {
684
+ if (RB_UNLIKELY(0 < pi->max_depth && pi->max_depth <= pi->stack.tail - pi->stack.head - 1)) {
715
685
  VALUE err_clas = oj_get_json_err_class("NestingError");
716
686
 
717
687
  oj_set_error_at(pi, err_clas, __FILE__, __LINE__, "Too deeply nested.");
@@ -719,18 +689,20 @@ void oj_parse2(ParseInfo pi) {
719
689
  return;
720
690
  }
721
691
  next_non_white(pi);
722
- if (!first && '\0' != *pi->cur) {
723
- oj_set_error_at(pi,
724
- oj_parse_error_class,
725
- __FILE__,
726
- __LINE__,
727
- "unexpected characters after the JSON document");
728
- }
729
-
730
- // If no tokens are consumed (i.e. empty string), throw a parse error
731
- // this is the behavior of JSON.parse in both Ruby and JS.
732
- if (No == pi->options.empty_string && 1 == first && '\0' == *pi->cur) {
733
- oj_set_error_at(pi, oj_parse_error_class, __FILE__, __LINE__, "unexpected character");
692
+ if (first) {
693
+ // If no tokens are consumed (i.e. empty string), throw a parse error
694
+ // this is the behavior of JSON.parse in both Ruby and JS.
695
+ if (RB_UNLIKELY('\0' == *pi->cur && No == pi->options.empty_string)) {
696
+ oj_set_error_at(pi, oj_parse_error_class, __FILE__, __LINE__, "unexpected character");
697
+ }
698
+ } else {
699
+ if (RB_UNLIKELY('\0' != *pi->cur)) {
700
+ oj_set_error_at(pi,
701
+ oj_parse_error_class,
702
+ __FILE__,
703
+ __LINE__,
704
+ "unexpected characters after the JSON document");
705
+ }
734
706
  }
735
707
 
736
708
  switch (*pi->cur++) {
@@ -740,17 +712,10 @@ void oj_parse2(ParseInfo pi) {
740
712
  case '[': array_start(pi); break;
741
713
  case ']': array_end(pi); break;
742
714
  case ',': comma(pi); break;
743
- case '"':
744
- read_str(pi);
745
- break;
746
- // case '+':
715
+ case '"': read_str(pi); break;
747
716
  case '+':
748
717
  if (CompatMode == pi->options.mode) {
749
- oj_set_error_at(pi,
750
- oj_parse_error_class,
751
- __FILE__,
752
- __LINE__,
753
- "unexpected character");
718
+ oj_set_error_at(pi, oj_parse_error_class, __FILE__, __LINE__, "unexpected character");
754
719
  return;
755
720
  }
756
721
  pi->cur--;
@@ -776,11 +741,7 @@ void oj_parse2(ParseInfo pi) {
776
741
  pi->cur--;
777
742
  read_num(pi);
778
743
  } else {
779
- oj_set_error_at(pi,
780
- oj_parse_error_class,
781
- __FILE__,
782
- __LINE__,
783
- "unexpected character");
744
+ oj_set_error_at(pi, oj_parse_error_class, __FILE__, __LINE__, "unexpected character");
784
745
  }
785
746
  break;
786
747
  case 't': read_true(pi); break;
@@ -800,11 +761,9 @@ void oj_parse2(ParseInfo pi) {
800
761
  }
801
762
  break;
802
763
  case '\0': pi->cur--; return;
803
- default:
804
- oj_set_error_at(pi, oj_parse_error_class, __FILE__, __LINE__, "unexpected character");
805
- return;
764
+ default: oj_set_error_at(pi, oj_parse_error_class, __FILE__, __LINE__, "unexpected character"); return;
806
765
  }
807
- if (err_has(&pi->err)) {
766
+ if (RB_UNLIKELY(err_has(&pi->err))) {
808
767
  return;
809
768
  }
810
769
  if (stack_empty(&pi->stack)) {
@@ -839,11 +798,10 @@ static VALUE parse_big_decimal(VALUE str) {
839
798
  }
840
799
 
841
800
  static long double exp_plus[] = {
842
- 1.0, 1.0e1, 1.0e2, 1.0e3, 1.0e4, 1.0e5, 1.0e6, 1.0e7, 1.0e8, 1.0e9,
843
- 1.0e10, 1.0e11, 1.0e12, 1.0e13, 1.0e14, 1.0e15, 1.0e16, 1.0e17, 1.0e18, 1.0e19,
844
- 1.0e20, 1.0e21, 1.0e22, 1.0e23, 1.0e24, 1.0e25, 1.0e26, 1.0e27, 1.0e28, 1.0e29,
845
- 1.0e30, 1.0e31, 1.0e32, 1.0e33, 1.0e34, 1.0e35, 1.0e36, 1.0e37, 1.0e38, 1.0e39,
846
- 1.0e40, 1.0e41, 1.0e42, 1.0e43, 1.0e44, 1.0e45, 1.0e46, 1.0e47, 1.0e48, 1.0e49,
801
+ 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,
802
+ 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,
803
+ 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,
804
+ 1.0e39, 1.0e40, 1.0e41, 1.0e42, 1.0e43, 1.0e44, 1.0e45, 1.0e46, 1.0e47, 1.0e48, 1.0e49,
847
805
  };
848
806
 
849
807
  VALUE
@@ -867,12 +825,12 @@ oj_num_as_value(NumInfo ni) {
867
825
  buf[ni->len] = '\0';
868
826
  rnum = rb_cstr_to_inum(buf, 10, 0);
869
827
  } else {
870
- char *buf = ALLOC_N(char, ni->len + 1);
828
+ char *buf = OJ_R_ALLOC_N(char, ni->len + 1);
871
829
 
872
830
  memcpy(buf, ni->str, ni->len);
873
831
  buf[ni->len] = '\0';
874
832
  rnum = rb_cstr_to_inum(buf, 10, 0);
875
- xfree(buf);
833
+ OJ_R_FREE(buf);
876
834
  }
877
835
  } else {
878
836
  if (ni->neg) {
@@ -915,11 +873,15 @@ oj_num_as_value(NumInfo ni) {
915
873
 
916
874
  rnum = rb_funcall(sv, rb_intern("to_f"), 0);
917
875
  } else {
918
- char * end;
876
+ char *end;
919
877
  double d = strtod(ni->str, &end);
920
878
 
921
879
  if ((long)ni->len != (long)(end - ni->str)) {
922
- rb_raise(oj_parse_error_class, "Invalid float");
880
+ if (Qnil == ni->pi->err_class) {
881
+ rb_raise(oj_parse_error_class, "Invalid float");
882
+ } else {
883
+ rb_raise(ni->pi->err_class, "Invalid float");
884
+ }
923
885
  }
924
886
  rnum = rb_float_new(d);
925
887
  }
@@ -927,28 +889,23 @@ oj_num_as_value(NumInfo ni) {
927
889
  return rnum;
928
890
  }
929
891
 
930
- void oj_set_error_at(ParseInfo pi,
931
- VALUE err_clas,
932
- const char *file,
933
- int line,
934
- const char *format,
935
- ...) {
892
+ void oj_set_error_at(ParseInfo pi, VALUE err_clas, const char *file, int line, const char *format, ...) {
936
893
  va_list ap;
937
894
  char msg[256];
938
- char * p = msg;
939
- char * end = p + sizeof(msg) - 2;
940
- char * start;
895
+ char *p = msg;
896
+ char *end = p + sizeof(msg) - 2;
897
+ char *start;
941
898
  Val vp;
942
- int mlen;
899
+ int mlen;
943
900
 
944
901
  va_start(ap, format);
945
902
  mlen = vsnprintf(msg, sizeof(msg) - 1, format, ap);
946
903
  if (0 < mlen) {
947
- if (sizeof(msg) - 2 < (size_t)mlen) {
948
- p = end - 2;
949
- } else {
950
- p += mlen;
951
- }
904
+ if (sizeof(msg) - 2 < (size_t)mlen) {
905
+ p = end - 2;
906
+ } else {
907
+ p += mlen;
908
+ }
952
909
  }
953
910
  va_end(ap);
954
911
  pi->err.clas = err_clas;
@@ -985,14 +942,7 @@ void oj_set_error_at(ParseInfo pi,
985
942
  }
986
943
  *p = '\0';
987
944
  if (0 == pi->json) {
988
- oj_err_set(&pi->err,
989
- err_clas,
990
- "%s at line %d, column %d [%s:%d]",
991
- msg,
992
- pi->rd.line,
993
- pi->rd.col,
994
- file,
995
- line);
945
+ oj_err_set(&pi->err, err_clas, "%s at line %d, column %d [%s:%d]", msg, pi->rd.line, pi->rd.col, file, line);
996
946
  } else {
997
947
  _oj_err_set_with_location(&pi->err, err_clas, msg, pi->json, pi->cur - 1, file, line);
998
948
  }
@@ -1011,7 +961,7 @@ static void oj_pi_set_input_str(ParseInfo pi, VALUE *inputp) {
1011
961
 
1012
962
  if (oj_utf8_encoding_index != idx) {
1013
963
  rb_encoding *enc = rb_enc_from_index(idx);
1014
- *inputp = rb_str_conv_enc(*inputp, enc, oj_utf8_encoding);
964
+ *inputp = rb_str_conv_enc(*inputp, enc, oj_utf8_encoding);
1015
965
  }
1016
966
  pi->json = RSTRING_PTR(*inputp);
1017
967
  pi->end = pi->json + RSTRING_LEN(*inputp);
@@ -1019,12 +969,12 @@ static void oj_pi_set_input_str(ParseInfo pi, VALUE *inputp) {
1019
969
 
1020
970
  VALUE
1021
971
  oj_pi_parse(int argc, VALUE *argv, ParseInfo pi, char *json, size_t len, int yieldOk) {
1022
- char * buf = 0;
1023
- VALUE input;
1024
- VALUE wrapped_stack;
1025
- VALUE result = Qnil;
1026
- int line = 0;
1027
- int free_json = 0;
972
+ char *buf = 0;
973
+ VALUE input;
974
+ VALUE wrapped_stack;
975
+ VALUE result = Qnil;
976
+ int line = 0;
977
+ int free_json = 0;
1028
978
 
1029
979
  if (argc < 1) {
1030
980
  rb_raise(rb_eArgError, "Wrong number of arguments to parse.");
@@ -1073,19 +1023,18 @@ oj_pi_parse(int argc, VALUE *argv, ParseInfo pi, char *json, size_t len, int yie
1073
1023
  size_t len = lseek(fd, 0, SEEK_END);
1074
1024
 
1075
1025
  lseek(fd, 0, SEEK_SET);
1076
- buf = ALLOC_N(char, len + 1);
1026
+ buf = OJ_R_ALLOC_N(char, len + 1);
1077
1027
  pi->json = buf;
1078
1028
  pi->end = buf + len;
1079
1029
  if (0 >= (cnt = read(fd, (char *)pi->json, len)) || cnt != (ssize_t)len) {
1080
1030
  if (0 != buf) {
1081
- xfree(buf);
1031
+ OJ_R_FREE(buf);
1082
1032
  }
1083
1033
  rb_raise(rb_eIOError, "failed to read from IO Object.");
1084
1034
  }
1085
1035
  ((char *)pi->json)[len] = '\0';
1086
1036
  /* skip UTF-8 BOM if present */
1087
- if (0xEF == (uint8_t)*pi->json && 0xBB == (uint8_t)pi->json[1] &&
1088
- 0xBF == (uint8_t)pi->json[2]) {
1037
+ if (0xEF == (uint8_t)*pi->json && 0xBB == (uint8_t)pi->json[1] && 0xBF == (uint8_t)pi->json[2]) {
1089
1038
  pi->cur += 3;
1090
1039
  }
1091
1040
  #endif
@@ -1111,8 +1060,7 @@ oj_pi_parse(int argc, VALUE *argv, ParseInfo pi, char *json, size_t len, int yie
1111
1060
  wrapped_stack = oj_stack_init(&pi->stack);
1112
1061
  rb_protect(protect_parse, (VALUE)pi, &line);
1113
1062
  if (Qundef == pi->stack.head->val && !empty_ok(&pi->options)) {
1114
- if (No == pi->options.nilnil ||
1115
- (CompatMode == pi->options.mode && 0 < pi->cur - pi->json)) {
1063
+ if (No == pi->options.nilnil || (CompatMode == pi->options.mode && 0 < pi->cur - pi->json)) {
1116
1064
  oj_set_error_at(pi, oj_json_parser_error_class, __FILE__, __LINE__, "Empty input");
1117
1065
  }
1118
1066
  }
@@ -1140,9 +1088,7 @@ oj_pi_parse(int argc, VALUE *argv, ParseInfo pi, char *json, size_t len, int yie
1140
1088
  switch (v->next) {
1141
1089
  case NEXT_ARRAY_NEW:
1142
1090
  case NEXT_ARRAY_ELEMENT:
1143
- case NEXT_ARRAY_COMMA:
1144
- oj_set_error_at(pi, err_class, __FILE__, __LINE__, "Array not terminated");
1145
- break;
1091
+ case NEXT_ARRAY_COMMA: oj_set_error_at(pi, err_class, __FILE__, __LINE__, "Array not terminated"); break;
1146
1092
  case NEXT_HASH_NEW:
1147
1093
  case NEXT_HASH_KEY:
1148
1094
  case NEXT_HASH_COLON:
@@ -1160,9 +1106,9 @@ CLEANUP:
1160
1106
  oj_circ_array_free(pi->circ_array);
1161
1107
  }
1162
1108
  if (0 != buf) {
1163
- xfree(buf);
1109
+ OJ_R_FREE(buf);
1164
1110
  } else if (free_json) {
1165
- xfree(json);
1111
+ OJ_R_FREE(json);
1166
1112
  }
1167
1113
  stack_cleanup(&pi->stack);
1168
1114
  if (pi->str_rx.head != oj_default_options.str_rx.head) {
data/ext/oj/parse.h CHANGED
@@ -16,23 +16,25 @@
16
16
  #include "val_stack.h"
17
17
 
18
18
  struct _rxClass;
19
+ struct _parseInfo;
19
20
 
20
21
  typedef struct _numInfo {
21
- int64_t i;
22
- int64_t num;
23
- int64_t div;
24
- int64_t di;
25
- const char *str;
26
- size_t len;
27
- long exp;
28
- int big;
29
- int infinity;
30
- int nan;
31
- int neg;
32
- int has_exp;
33
- int no_big;
34
- int bigdec_load;
35
- } * NumInfo;
22
+ int64_t i;
23
+ int64_t num;
24
+ int64_t div;
25
+ int64_t di;
26
+ const char *str;
27
+ size_t len;
28
+ long exp;
29
+ struct _parseInfo *pi;
30
+ int big;
31
+ int infinity;
32
+ int nan;
33
+ int neg;
34
+ int has_exp;
35
+ int no_big;
36
+ int bigdec_load;
37
+ } *NumInfo;
36
38
 
37
39
  typedef struct _parseInfo {
38
40
  // used for the string parser
@@ -54,11 +56,7 @@ typedef struct _parseInfo {
54
56
  VALUE (*start_hash)(struct _parseInfo *pi);
55
57
  void (*end_hash)(struct _parseInfo *pi);
56
58
  VALUE (*hash_key)(struct _parseInfo *pi, const char *key, size_t klen);
57
- void (*hash_set_cstr)(struct _parseInfo *pi,
58
- Val kval,
59
- const char * str,
60
- size_t len,
61
- const char * orig);
59
+ void (*hash_set_cstr)(struct _parseInfo *pi, Val kval, const char *str, size_t len, const char *orig);
62
60
  void (*hash_set_num)(struct _parseInfo *pi, Val kval, NumInfo ni);
63
61
  void (*hash_set_value)(struct _parseInfo *pi, Val kval, VALUE value);
64
62
 
@@ -73,11 +71,10 @@ typedef struct _parseInfo {
73
71
  void (*add_value)(struct _parseInfo *pi, VALUE val);
74
72
  VALUE err_class;
75
73
  bool has_callbacks;
76
- } * ParseInfo;
74
+ } *ParseInfo;
77
75
 
78
- extern void oj_parse2(ParseInfo pi);
79
- extern void
80
- oj_set_error_at(ParseInfo pi, VALUE err_clas, const char *file, int line, const char *format, ...);
76
+ extern void oj_parse2(ParseInfo pi);
77
+ extern void oj_set_error_at(ParseInfo pi, VALUE err_clas, const char *file, int line, const char *format, ...);
81
78
  extern VALUE oj_pi_parse(int argc, VALUE *argv, ParseInfo pi, char *json, size_t len, int yieldOk);
82
79
  extern VALUE oj_num_as_value(NumInfo ni);
83
80