oj 3.13.9 → 3.16.1

Sign up to get free protection for your applications and to get access to all the features.
Files changed (161) hide show
  1. checksums.yaml +4 -4
  2. data/CHANGELOG.md +101 -0
  3. data/README.md +13 -2
  4. data/ext/oj/buf.h +11 -6
  5. data/ext/oj/cache.c +25 -24
  6. data/ext/oj/cache8.c +10 -9
  7. data/ext/oj/circarray.c +8 -6
  8. data/ext/oj/circarray.h +2 -2
  9. data/ext/oj/code.c +19 -33
  10. data/ext/oj/code.h +2 -2
  11. data/ext/oj/compat.c +20 -60
  12. data/ext/oj/custom.c +76 -155
  13. data/ext/oj/debug.c +3 -9
  14. data/ext/oj/dump.c +203 -213
  15. data/ext/oj/dump.h +26 -12
  16. data/ext/oj/dump_compat.c +565 -642
  17. data/ext/oj/dump_leaf.c +17 -63
  18. data/ext/oj/dump_object.c +59 -181
  19. data/ext/oj/dump_strict.c +24 -48
  20. data/ext/oj/encoder.c +43 -0
  21. data/ext/oj/err.c +2 -13
  22. data/ext/oj/err.h +9 -12
  23. data/ext/oj/extconf.rb +18 -7
  24. data/ext/oj/fast.c +83 -108
  25. data/ext/oj/intern.c +52 -50
  26. data/ext/oj/intern.h +4 -8
  27. data/ext/oj/mem.c +318 -0
  28. data/ext/oj/mem.h +53 -0
  29. data/ext/oj/mimic_json.c +104 -81
  30. data/ext/oj/object.c +50 -67
  31. data/ext/oj/odd.c +89 -67
  32. data/ext/oj/odd.h +15 -15
  33. data/ext/oj/oj.c +171 -106
  34. data/ext/oj/oj.h +96 -74
  35. data/ext/oj/parse.c +169 -189
  36. data/ext/oj/parse.h +23 -24
  37. data/ext/oj/parser.c +89 -34
  38. data/ext/oj/parser.h +20 -9
  39. data/ext/oj/rails.c +86 -151
  40. data/ext/oj/rails.h +1 -1
  41. data/ext/oj/reader.c +12 -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 +21 -32
  47. data/ext/oj/saj2.c +329 -93
  48. data/ext/oj/saj2.h +23 -0
  49. data/ext/oj/scp.c +3 -14
  50. data/ext/oj/sparse.c +26 -70
  51. data/ext/oj/stream_writer.c +12 -22
  52. data/ext/oj/strict.c +20 -52
  53. data/ext/oj/string_writer.c +21 -22
  54. data/ext/oj/trace.h +31 -4
  55. data/ext/oj/usual.c +105 -150
  56. data/ext/oj/usual.h +68 -0
  57. data/ext/oj/util.h +1 -1
  58. data/ext/oj/val_stack.c +1 -1
  59. data/ext/oj/val_stack.h +8 -7
  60. data/ext/oj/validate.c +21 -26
  61. data/ext/oj/wab.c +32 -69
  62. data/lib/oj/active_support_helper.rb +1 -3
  63. data/lib/oj/bag.rb +7 -1
  64. data/lib/oj/easy_hash.rb +4 -5
  65. data/lib/oj/error.rb +0 -1
  66. data/lib/oj/json.rb +162 -150
  67. data/lib/oj/mimic.rb +6 -2
  68. data/lib/oj/saj.rb +20 -6
  69. data/lib/oj/state.rb +9 -6
  70. data/lib/oj/version.rb +1 -2
  71. data/lib/oj.rb +2 -0
  72. data/pages/Compatibility.md +1 -1
  73. data/pages/InstallOptions.md +20 -0
  74. data/pages/JsonGem.md +15 -0
  75. data/pages/Modes.md +6 -3
  76. data/pages/Options.md +10 -0
  77. data/pages/Rails.md +12 -0
  78. data/test/_test_active.rb +8 -9
  79. data/test/_test_active_mimic.rb +7 -8
  80. data/test/_test_mimic_rails.rb +17 -20
  81. data/test/activerecord/result_test.rb +5 -6
  82. data/test/{activesupport5 → activesupport7}/abstract_unit.rb +16 -12
  83. data/test/{activesupport5 → activesupport7}/decoding_test.rb +2 -10
  84. data/test/{activesupport5 → activesupport7}/encoding_test.rb +20 -34
  85. data/test/{activesupport5 → activesupport7}/encoding_test_cases.rb +6 -0
  86. data/test/{activesupport5 → activesupport7}/time_zone_test_helpers.rb +8 -0
  87. data/test/files.rb +15 -15
  88. data/test/foo.rb +15 -15
  89. data/test/helper.rb +11 -8
  90. data/test/isolated/shared.rb +3 -2
  91. data/test/json_gem/json_addition_test.rb +2 -2
  92. data/test/json_gem/json_common_interface_test.rb +8 -6
  93. data/test/json_gem/json_encoding_test.rb +0 -0
  94. data/test/json_gem/json_ext_parser_test.rb +1 -0
  95. data/test/json_gem/json_fixtures_test.rb +3 -2
  96. data/test/json_gem/json_generator_test.rb +49 -37
  97. data/test/json_gem/json_generic_object_test.rb +11 -11
  98. data/test/json_gem/json_parser_test.rb +54 -47
  99. data/test/json_gem/json_string_matching_test.rb +9 -9
  100. data/test/json_gem/test_helper.rb +7 -3
  101. data/test/mem.rb +13 -12
  102. data/test/perf.rb +21 -26
  103. data/test/perf_compat.rb +31 -33
  104. data/test/perf_dump.rb +50 -0
  105. data/test/perf_fast.rb +80 -82
  106. data/test/perf_file.rb +27 -29
  107. data/test/perf_object.rb +65 -69
  108. data/test/perf_once.rb +12 -11
  109. data/test/perf_parser.rb +42 -48
  110. data/test/perf_saj.rb +46 -54
  111. data/test/perf_scp.rb +57 -69
  112. data/test/perf_simple.rb +41 -39
  113. data/test/perf_strict.rb +68 -70
  114. data/test/perf_wab.rb +67 -69
  115. data/test/prec.rb +3 -3
  116. data/test/sample/change.rb +0 -1
  117. data/test/sample/dir.rb +0 -1
  118. data/test/sample/doc.rb +0 -1
  119. data/test/sample/file.rb +0 -1
  120. data/test/sample/group.rb +0 -1
  121. data/test/sample/hasprops.rb +0 -1
  122. data/test/sample/layer.rb +0 -1
  123. data/test/sample/rect.rb +0 -1
  124. data/test/sample/shape.rb +0 -1
  125. data/test/sample/text.rb +0 -1
  126. data/test/sample.rb +16 -16
  127. data/test/sample_json.rb +8 -8
  128. data/test/test_compat.rb +95 -43
  129. data/test/test_custom.rb +72 -51
  130. data/test/test_debian.rb +7 -10
  131. data/test/test_fast.rb +102 -87
  132. data/test/test_file.rb +41 -30
  133. data/test/test_gc.rb +16 -5
  134. data/test/test_generate.rb +5 -5
  135. data/test/test_hash.rb +4 -4
  136. data/test/test_integer_range.rb +9 -9
  137. data/test/test_null.rb +20 -20
  138. data/test/test_object.rb +85 -96
  139. data/test/test_parser.rb +6 -22
  140. data/test/test_parser_debug.rb +27 -0
  141. data/test/test_parser_saj.rb +115 -23
  142. data/test/test_parser_usual.rb +6 -6
  143. data/test/test_rails.rb +2 -2
  144. data/test/test_saj.rb +10 -8
  145. data/test/test_scp.rb +37 -39
  146. data/test/test_strict.rb +40 -32
  147. data/test/test_various.rb +163 -84
  148. data/test/test_wab.rb +48 -44
  149. data/test/test_writer.rb +47 -47
  150. data/test/tests.rb +13 -5
  151. data/test/tests_mimic.rb +12 -3
  152. data/test/tests_mimic_addition.rb +12 -3
  153. metadata +34 -144
  154. data/test/activesupport4/decoding_test.rb +0 -108
  155. data/test/activesupport4/encoding_test.rb +0 -531
  156. data/test/activesupport4/test_helper.rb +0 -41
  157. data/test/activesupport5/test_helper.rb +0 -72
  158. data/test/bar.rb +0 -16
  159. data/test/baz.rb +0 -16
  160. data/test/bug.rb +0 -16
  161. data/test/zoo.rb +0 -13
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
 
@@ -97,6 +94,8 @@ static inline void parse_info_init(ParseInfo pi) {
97
94
  memset(pi, 0, sizeof(struct _parseInfo));
98
95
  }
99
96
 
97
+ extern void oj_scanner_init(void);
98
+
100
99
  static inline bool empty_ok(Options options) {
101
100
  switch (options->mode) {
102
101
  case ObjectMode:
data/ext/oj/parser.c CHANGED
@@ -11,8 +11,8 @@
11
11
  #define USE_THREAD_LIMIT 0
12
12
  // #define USE_THREAD_LIMIT 100000
13
13
  #define MAX_EXP 4932
14
- // max in the pow_map
15
- #define MAX_POW 400
14
+ // max in the pow_map which is the limit for double
15
+ #define MAX_POW 308
16
16
 
17
17
  #define MIN_SLEEP (1000000000LL / (double)CLOCKS_PER_SEC)
18
18
  // 9,223,372,036,854,775,807
@@ -20,7 +20,7 @@
20
20
  #define FRAC_LIMIT 10000000000000000ULL
21
21
 
22
22
  // Give better performance with indented JSON but worse with unindented.
23
- //#define SPACE_JUMP
23
+ // #define SPACE_JUMP
24
24
 
25
25
  enum {
26
26
  SKIP_CHAR = 'a',
@@ -385,7 +385,7 @@ static const byte hex_map[256] = "\
385
385
  ................................\
386
386
  ................................";
387
387
 
388
- static long double pow_map[401] = {
388
+ static long double pow_map[309] = {
389
389
  1.0L, 1.0e1L, 1.0e2L, 1.0e3L, 1.0e4L, 1.0e5L, 1.0e6L, 1.0e7L, 1.0e8L, 1.0e9L, 1.0e10L,
390
390
  1.0e11L, 1.0e12L, 1.0e13L, 1.0e14L, 1.0e15L, 1.0e16L, 1.0e17L, 1.0e18L, 1.0e19L, 1.0e20L, 1.0e21L,
391
391
  1.0e22L, 1.0e23L, 1.0e24L, 1.0e25L, 1.0e26L, 1.0e27L, 1.0e28L, 1.0e29L, 1.0e30L, 1.0e31L, 1.0e32L,
@@ -414,15 +414,7 @@ static long double pow_map[401] = {
414
414
  1.0e275L, 1.0e276L, 1.0e277L, 1.0e278L, 1.0e279L, 1.0e280L, 1.0e281L, 1.0e282L, 1.0e283L, 1.0e284L, 1.0e285L,
415
415
  1.0e286L, 1.0e287L, 1.0e288L, 1.0e289L, 1.0e290L, 1.0e291L, 1.0e292L, 1.0e293L, 1.0e294L, 1.0e295L, 1.0e296L,
416
416
  1.0e297L, 1.0e298L, 1.0e299L, 1.0e300L, 1.0e301L, 1.0e302L, 1.0e303L, 1.0e304L, 1.0e305L, 1.0e306L, 1.0e307L,
417
- 1.0e308L, 1.0e309L, 1.0e310L, 1.0e311L, 1.0e312L, 1.0e313L, 1.0e314L, 1.0e315L, 1.0e316L, 1.0e317L, 1.0e318L,
418
- 1.0e319L, 1.0e320L, 1.0e321L, 1.0e322L, 1.0e323L, 1.0e324L, 1.0e325L, 1.0e326L, 1.0e327L, 1.0e328L, 1.0e329L,
419
- 1.0e330L, 1.0e331L, 1.0e332L, 1.0e333L, 1.0e334L, 1.0e335L, 1.0e336L, 1.0e337L, 1.0e338L, 1.0e339L, 1.0e340L,
420
- 1.0e341L, 1.0e342L, 1.0e343L, 1.0e344L, 1.0e345L, 1.0e346L, 1.0e347L, 1.0e348L, 1.0e349L, 1.0e350L, 1.0e351L,
421
- 1.0e352L, 1.0e353L, 1.0e354L, 1.0e355L, 1.0e356L, 1.0e357L, 1.0e358L, 1.0e359L, 1.0e360L, 1.0e361L, 1.0e362L,
422
- 1.0e363L, 1.0e364L, 1.0e365L, 1.0e366L, 1.0e367L, 1.0e368L, 1.0e369L, 1.0e370L, 1.0e371L, 1.0e372L, 1.0e373L,
423
- 1.0e374L, 1.0e375L, 1.0e376L, 1.0e377L, 1.0e378L, 1.0e379L, 1.0e380L, 1.0e381L, 1.0e382L, 1.0e383L, 1.0e384L,
424
- 1.0e385L, 1.0e386L, 1.0e387L, 1.0e388L, 1.0e389L, 1.0e390L, 1.0e391L, 1.0e392L, 1.0e393L, 1.0e394L, 1.0e395L,
425
- 1.0e396L, 1.0e397L, 1.0e398L, 1.0e399L, 1.0e400L};
417
+ 1.0e308L};
426
418
 
427
419
  static VALUE parser_class;
428
420
 
@@ -541,6 +533,7 @@ static void calc_num(ojParser p) {
541
533
  // nothing to do
542
534
  break;
543
535
  }
536
+ p->type = OJ_NONE;
544
537
  }
545
538
 
546
539
  static void big_change(ojParser p) {
@@ -606,6 +599,8 @@ static void parse(ojParser p, const byte *json) {
606
599
  const byte *b = json;
607
600
  int i;
608
601
 
602
+ p->line = 1;
603
+ p->col = -1;
609
604
  #if DEBUG
610
605
  printf("*** parse - mode: %c %s\n", p->map[256], (const char *)json);
611
606
  #endif
@@ -660,6 +655,7 @@ static void parse(ojParser p, const byte *json) {
660
655
  }
661
656
  buf_append_string(&p->buf, (const char *)start, b - start);
662
657
  if ('"' == *b) {
658
+ p->cur = b - json;
663
659
  p->funcs[p->stack[p->depth]].add_str(p);
664
660
  p->map = (0 == p->depth) ? value_map : after_map;
665
661
  break;
@@ -669,12 +665,14 @@ static void parse(ojParser p, const byte *json) {
669
665
  p->next_map = (0 == p->depth) ? value_map : after_map;
670
666
  break;
671
667
  case OPEN_OBJECT:
668
+ p->cur = b - json;
672
669
  p->funcs[p->stack[p->depth]].open_object(p);
673
670
  p->depth++;
674
671
  p->stack[p->depth] = OBJECT_FUN;
675
672
  p->map = key1_map;
676
673
  break;
677
674
  case NUM_CLOSE_OBJECT:
675
+ p->cur = b - json;
678
676
  calc_num(p);
679
677
  // flow through
680
678
  case CLOSE_OBJECT:
@@ -685,15 +683,18 @@ static void parse(ojParser p, const byte *json) {
685
683
  return;
686
684
  }
687
685
  p->depth--;
686
+ p->cur = b - json;
688
687
  p->funcs[p->stack[p->depth]].close_object(p);
689
688
  break;
690
689
  case OPEN_ARRAY:
690
+ p->cur = b - json;
691
691
  p->funcs[p->stack[p->depth]].open_array(p);
692
692
  p->depth++;
693
693
  p->stack[p->depth] = ARRAY_FUN;
694
694
  p->map = value_map;
695
695
  break;
696
696
  case NUM_CLOSE_ARRAY:
697
+ p->cur = b - json;
697
698
  calc_num(p);
698
699
  // flow through
699
700
  case CLOSE_ARRAY:
@@ -704,9 +705,11 @@ static void parse(ojParser p, const byte *json) {
704
705
  return;
705
706
  }
706
707
  p->depth--;
708
+ p->cur = b - json;
707
709
  p->funcs[p->stack[p->depth]].close_array(p);
708
710
  break;
709
711
  case NUM_COMMA:
712
+ p->cur = b - json;
710
713
  calc_num(p);
711
714
  if (0 < p->depth && OBJECT_FUN == p->stack[p->depth]) {
712
715
  p->map = key_map;
@@ -868,8 +871,14 @@ static void parse(ojParser p, const byte *json) {
868
871
  b--;
869
872
  p->map = big_exp_map;
870
873
  break;
871
- case NUM_SPC: calc_num(p); break;
872
- case NUM_NEWLINE: calc_num(p); b++;
874
+ case NUM_SPC:
875
+ p->cur = b - json;
876
+ calc_num(p);
877
+ break;
878
+ case NUM_NEWLINE:
879
+ p->cur = b - json;
880
+ calc_num(p);
881
+ b++;
873
882
  #ifdef SPACE_JUMP
874
883
  // for (uint32_t *sj = (uint32_t*)b; 0x20202020 == *sj; sj++) { b += 4; }
875
884
  for (uint16_t *sj = (uint16_t *)b; 0x2020 == *sj; sj++) {
@@ -890,6 +899,7 @@ static void parse(ojParser p, const byte *json) {
890
899
  buf_append_string(&p->buf, (const char *)start, b - start);
891
900
  }
892
901
  if ('"' == *b) {
902
+ p->cur = b - json;
893
903
  p->funcs[p->stack[p->depth]].add_str(p);
894
904
  p->map = p->next_map;
895
905
  break;
@@ -898,6 +908,7 @@ static void parse(ojParser p, const byte *json) {
898
908
  break;
899
909
  case STR_SLASH: p->map = esc_map; break;
900
910
  case STR_QUOTE:
911
+ p->cur = b - json;
901
912
  p->funcs[p->stack[p->depth]].add_str(p);
902
913
  p->map = p->next_map;
903
914
  break;
@@ -975,6 +986,7 @@ static void parse(ojParser p, const byte *json) {
975
986
  case VAL_NULL:
976
987
  if ('u' == b[1] && 'l' == b[2] && 'l' == b[3]) {
977
988
  b += 3;
989
+ p->cur = b - json;
978
990
  p->funcs[p->stack[p->depth]].add_null(p);
979
991
  p->map = (0 == p->depth) ? value_map : after_map;
980
992
  break;
@@ -1000,6 +1012,7 @@ static void parse(ojParser p, const byte *json) {
1000
1012
  case VAL_TRUE:
1001
1013
  if ('r' == b[1] && 'u' == b[2] && 'e' == b[3]) {
1002
1014
  b += 3;
1015
+ p->cur = b - json;
1003
1016
  p->funcs[p->stack[p->depth]].add_true(p);
1004
1017
  p->map = (0 == p->depth) ? value_map : after_map;
1005
1018
  break;
@@ -1025,6 +1038,7 @@ static void parse(ojParser p, const byte *json) {
1025
1038
  case VAL_FALSE:
1026
1039
  if ('a' == b[1] && 'l' == b[2] && 's' == b[3] && 'e' == b[4]) {
1027
1040
  b += 4;
1041
+ p->cur = b - json;
1028
1042
  p->funcs[p->stack[p->depth]].add_false(p);
1029
1043
  p->map = (0 == p->depth) ? value_map : after_map;
1030
1044
  break;
@@ -1058,6 +1072,7 @@ static void parse(ojParser p, const byte *json) {
1058
1072
  parse_error(p, "expected null");
1059
1073
  return;
1060
1074
  }
1075
+ p->cur = b - json;
1061
1076
  p->funcs[p->stack[p->depth]].add_null(p);
1062
1077
  p->map = (0 == p->depth) ? value_map : after_map;
1063
1078
  }
@@ -1069,6 +1084,7 @@ static void parse(ojParser p, const byte *json) {
1069
1084
  parse_error(p, "expected false");
1070
1085
  return;
1071
1086
  }
1087
+ p->cur = b - json;
1072
1088
  p->funcs[p->stack[p->depth]].add_false(p);
1073
1089
  p->map = (0 == p->depth) ? value_map : after_map;
1074
1090
  }
@@ -1080,6 +1096,7 @@ static void parse(ojParser p, const byte *json) {
1080
1096
  parse_error(p, "expected true");
1081
1097
  return;
1082
1098
  }
1099
+ p->cur = b - json;
1083
1100
  p->funcs[p->stack[p->depth]].add_true(p);
1084
1101
  p->map = (0 == p->depth) ? value_map : after_map;
1085
1102
  }
@@ -1097,6 +1114,9 @@ static void parse(ojParser p, const byte *json) {
1097
1114
  p->map = trail_map;
1098
1115
  }
1099
1116
  }
1117
+ if (0 < p->depth) {
1118
+ parse_error(p, "parse error, not closed");
1119
+ }
1100
1120
  if (0 == p->depth) {
1101
1121
  switch (p->map[256]) {
1102
1122
  case '0':
@@ -1107,7 +1127,10 @@ static void parse(ojParser p, const byte *json) {
1107
1127
  case 'D':
1108
1128
  case 'g':
1109
1129
  case 'B':
1110
- case 'Y': calc_num(p); break;
1130
+ case 'Y':
1131
+ p->cur = b - json;
1132
+ calc_num(p);
1133
+ break;
1111
1134
  }
1112
1135
  }
1113
1136
  return;
@@ -1122,8 +1145,10 @@ static void parser_free(void *ptr) {
1122
1145
  p = (ojParser)ptr;
1123
1146
  buf_cleanup(&p->key);
1124
1147
  buf_cleanup(&p->buf);
1125
- p->free(p);
1126
- xfree(ptr);
1148
+ if (NULL != p->free) {
1149
+ p->free(p);
1150
+ }
1151
+ OJ_R_FREE(ptr);
1127
1152
  }
1128
1153
 
1129
1154
  static void parser_mark(void *ptr) {
@@ -1133,7 +1158,9 @@ static void parser_mark(void *ptr) {
1133
1158
  if (0 != p->reader) {
1134
1159
  rb_gc_mark(p->reader);
1135
1160
  }
1136
- p->mark(p);
1161
+ if (NULL != p->mark) {
1162
+ p->mark(p);
1163
+ }
1137
1164
  }
1138
1165
  }
1139
1166
 
@@ -1153,7 +1180,7 @@ static int opt_cb(VALUE rkey, VALUE value, VALUE ptr) {
1153
1180
  rkey = rb_sym2str(rkey);
1154
1181
  // fall through
1155
1182
  case RUBY_T_STRING:
1156
- key = rb_string_value_ptr(&rkey);
1183
+ key = StringValuePtr(rkey);
1157
1184
  klen = RSTRING_LEN(rkey);
1158
1185
  break;
1159
1186
  default: rb_raise(rb_eArgError, "option keys must be a symbol or string");
@@ -1178,7 +1205,7 @@ static int opt_cb(VALUE rkey, VALUE value, VALUE ptr) {
1178
1205
  * Oj::Parser.new(:usual, cache_keys: true).
1179
1206
  */
1180
1207
  static VALUE parser_new(int argc, VALUE *argv, VALUE self) {
1181
- ojParser p = ALLOC(struct _ojParser);
1208
+ ojParser p = OJ_R_ALLOC(struct _ojParser);
1182
1209
 
1183
1210
  #if HAVE_RB_EXT_RACTOR_SAFE
1184
1211
  // This doesn't seem to do anything.
@@ -1190,7 +1217,7 @@ static VALUE parser_new(int argc, VALUE *argv, VALUE self) {
1190
1217
  p->map = value_map;
1191
1218
 
1192
1219
  if (argc < 1) {
1193
- oj_set_parser_validator(p);
1220
+ oj_set_parser_validator(p);
1194
1221
  } else {
1195
1222
  VALUE mode = argv[0];
1196
1223
 
@@ -1231,6 +1258,32 @@ static VALUE parser_new(int argc, VALUE *argv, VALUE self) {
1231
1258
  return Data_Wrap_Struct(parser_class, parser_mark, parser_free, p);
1232
1259
  }
1233
1260
 
1261
+ // Create a new parser without setting the delegate. The parser is
1262
+ // wrapped. The parser is (ojParser)DATA_PTR(value) where value is the return
1263
+ // from this function. A delegate must be added before the parser can be
1264
+ // used. Optionally oj_parser_set_options can be called if the options are not
1265
+ // set directly.
1266
+ VALUE oj_parser_new(void) {
1267
+ ojParser p = OJ_R_ALLOC(struct _ojParser);
1268
+
1269
+ #if HAVE_RB_EXT_RACTOR_SAFE
1270
+ // This doesn't seem to do anything.
1271
+ rb_ext_ractor_safe(true);
1272
+ #endif
1273
+ memset(p, 0, sizeof(struct _ojParser));
1274
+ buf_init(&p->key);
1275
+ buf_init(&p->buf);
1276
+ p->map = value_map;
1277
+
1278
+ return Data_Wrap_Struct(parser_class, parser_mark, parser_free, p);
1279
+ }
1280
+
1281
+ // Set set the options from a hash (ropts).
1282
+ void oj_parser_set_option(ojParser p, VALUE ropts) {
1283
+ Check_Type(ropts, T_HASH);
1284
+ rb_hash_foreach(ropts, opt_cb, (VALUE)p);
1285
+ }
1286
+
1234
1287
  /* Document-method: method_missing(value)
1235
1288
  * call-seq: method_missing(value)
1236
1289
  *
@@ -1284,7 +1337,7 @@ static VALUE parser_new(int argc, VALUE *argv, VALUE self) {
1284
1337
  */
1285
1338
  static VALUE parser_missing(int argc, VALUE *argv, VALUE self) {
1286
1339
  ojParser p = (ojParser)DATA_PTR(self);
1287
- const char * key = NULL;
1340
+ const char *key = NULL;
1288
1341
  volatile VALUE rkey = *argv;
1289
1342
  volatile VALUE rv = Qnil;
1290
1343
 
@@ -1296,7 +1349,7 @@ static VALUE parser_missing(int argc, VALUE *argv, VALUE self) {
1296
1349
  case RUBY_T_SYMBOL:
1297
1350
  rkey = rb_sym2str(rkey);
1298
1351
  // fall through
1299
- case RUBY_T_STRING: key = rb_string_value_ptr(&rkey); break;
1352
+ case RUBY_T_STRING: key = StringValuePtr(rkey); break;
1300
1353
  default: rb_raise(rb_eArgError, "option method must be a symbol or string");
1301
1354
  }
1302
1355
  if (1 < argc) {
@@ -1313,12 +1366,12 @@ static VALUE parser_missing(int argc, VALUE *argv, VALUE self) {
1313
1366
  * Returns the result according to the delegate of the parser.
1314
1367
  */
1315
1368
  static VALUE parser_parse(VALUE self, VALUE json) {
1316
- ojParser p = (ojParser)DATA_PTR(self);
1369
+ ojParser p = (ojParser)DATA_PTR(self);
1370
+ const byte *ptr = (const byte *)StringValuePtr(json);
1317
1371
 
1318
- Check_Type(json, T_STRING);
1319
1372
  parser_reset(p);
1320
1373
  p->start(p);
1321
- parse(p, (const byte *)rb_string_value_ptr(&json));
1374
+ parse(p, ptr);
1322
1375
 
1323
1376
  return p->result(p);
1324
1377
  }
@@ -1371,8 +1424,7 @@ static VALUE parser_file(VALUE self, VALUE filename) {
1371
1424
  const char *path;
1372
1425
  int fd;
1373
1426
 
1374
- Check_Type(filename, T_STRING);
1375
- path = rb_string_value_ptr(&filename);
1427
+ path = StringValuePtr(filename);
1376
1428
 
1377
1429
  parser_reset(p);
1378
1430
  p->start(p);
@@ -1446,7 +1498,7 @@ static VALUE usual_parser = Qundef;
1446
1498
  */
1447
1499
  static VALUE parser_usual(VALUE self) {
1448
1500
  if (Qundef == usual_parser) {
1449
- ojParser p = ALLOC(struct _ojParser);
1501
+ ojParser p = OJ_R_ALLOC(struct _ojParser);
1450
1502
 
1451
1503
  memset(p, 0, sizeof(struct _ojParser));
1452
1504
  buf_init(&p->key);
@@ -1464,12 +1516,12 @@ static VALUE saj_parser = Qundef;
1464
1516
  /* Document-method: saj
1465
1517
  * call-seq: saj
1466
1518
  *
1467
- * Returns the default saj parser. Note the default SAJ parser can not be used
1519
+ * Returns the default SAJ parser. Note the default SAJ parser can not be used
1468
1520
  * concurrently in more than one thread.
1469
1521
  */
1470
1522
  static VALUE parser_saj(VALUE self) {
1471
1523
  if (Qundef == saj_parser) {
1472
- ojParser p = ALLOC(struct _ojParser);
1524
+ ojParser p = OJ_R_ALLOC(struct _ojParser);
1473
1525
 
1474
1526
  memset(p, 0, sizeof(struct _ojParser));
1475
1527
  buf_init(&p->key);
@@ -1491,7 +1543,7 @@ static VALUE validate_parser = Qundef;
1491
1543
  */
1492
1544
  static VALUE parser_validate(VALUE self) {
1493
1545
  if (Qundef == validate_parser) {
1494
- ojParser p = ALLOC(struct _ojParser);
1546
+ ojParser p = OJ_R_ALLOC(struct _ojParser);
1495
1547
 
1496
1548
  memset(p, 0, sizeof(struct _ojParser));
1497
1549
  buf_init(&p->key);
@@ -1515,8 +1567,11 @@ static VALUE parser_validate(VALUE self) {
1515
1567
  * isolates options to just the parser so that other parts of the code are not
1516
1568
  * forced to use the same options.
1517
1569
  */
1518
- void oj_parser_init() {
1570
+ void oj_parser_init(void) {
1519
1571
  parser_class = rb_define_class_under(Oj, "Parser", rb_cObject);
1572
+ rb_gc_register_address(&parser_class);
1573
+ rb_undef_alloc_func(parser_class);
1574
+
1520
1575
  rb_define_module_function(parser_class, "new", parser_new, -1);
1521
1576
  rb_define_method(parser_class, "parse", parser_parse, 1);
1522
1577
  rb_define_method(parser_class, "load", parser_load, 1);
data/ext/oj/parser.h CHANGED
@@ -4,8 +4,8 @@
4
4
  #ifndef OJ_PARSER_H
5
5
  #define OJ_PARSER_H
6
6
 
7
- #include <stdbool.h>
8
7
  #include <ruby.h>
8
+ #include <stdbool.h>
9
9
 
10
10
  #include "buf.h"
11
11
 
@@ -32,13 +32,13 @@ typedef struct _num {
32
32
  long double dub;
33
33
  int64_t fixnum; // holds all digits
34
34
  uint32_t len;
35
- int16_t div; // 10^div
35
+ int16_t div; // 10^div
36
36
  int16_t exp;
37
- uint8_t shift; // shift of fixnum to get decimal
37
+ uint8_t shift; // shift of fixnum to get decimal
38
38
  bool neg;
39
39
  bool exp_neg;
40
40
  // for numbers as strings, reuse buf
41
- } * Num;
41
+ } *Num;
42
42
 
43
43
  struct _ojParser;
44
44
 
@@ -54,11 +54,11 @@ typedef struct _funcs {
54
54
  void (*close_array)(struct _ojParser *p);
55
55
  void (*open_object)(struct _ojParser *p);
56
56
  void (*close_object)(struct _ojParser *p);
57
- } * Funcs;
57
+ } *Funcs;
58
58
 
59
59
  typedef struct _ojParser {
60
- const char * map;
61
- const char * next_map;
60
+ const char *map;
61
+ const char *next_map;
62
62
  int depth;
63
63
  unsigned char stack[1024];
64
64
 
@@ -67,7 +67,7 @@ typedef struct _ojParser {
67
67
  struct _buf key;
68
68
  struct _buf buf;
69
69
 
70
- struct _funcs funcs[3]; // indexed by XXX_FUN defines
70
+ struct _funcs funcs[3]; // indexed by XXX_FUN defines
71
71
 
72
72
  void (*start)(struct _ojParser *p);
73
73
  VALUE (*option)(struct _ojParser *p, const char *key, VALUE value);
@@ -80,11 +80,22 @@ typedef struct _ojParser {
80
80
 
81
81
  char token[8];
82
82
  long line;
83
+ long cur; // only set before call to a function
83
84
  long col;
84
85
  int ri;
85
86
  uint32_t ucode;
86
87
  ojType type; // valType
87
88
  bool just_one;
88
- } * ojParser;
89
+ } *ojParser;
90
+
91
+ // Create a new parser without setting the delegate. The parser is
92
+ // wrapped. The parser is (ojParser)DATA_PTR(value) where value is the return
93
+ // from this function. A delegate must be added before the parser can be
94
+ // used. Optionally oj_parser_set_options can be called if the options are not
95
+ // set directly.
96
+ extern VALUE oj_parser_new();
97
+
98
+ // Set set the options from a hash (ropts).
99
+ extern void oj_parser_set_option(ojParser p, VALUE ropts);
89
100
 
90
101
  #endif /* OJ_PARSER_H */