oj 3.13.9 → 3.16.1

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 (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/fast.c CHANGED
@@ -11,13 +11,15 @@
11
11
  #include <stdlib.h>
12
12
  #include <string.h>
13
13
 
14
+ #include "dump.h"
14
15
  #include "encode.h"
16
+ #include "mem.h"
15
17
  #include "oj.h"
16
18
 
17
19
  // maximum to allocate on the stack, arbitrary limit
18
20
  #define SMALL_JSON 65536
19
21
  #define MAX_STACK 100
20
- //#define BATCH_SIZE (4096 / sizeof(struct _leaf) - 1)
22
+ // #define BATCH_SIZE (4096 / sizeof(struct _leaf) - 1)
21
23
  #define BATCH_SIZE 100
22
24
 
23
25
  // Support for compaction
@@ -31,25 +33,25 @@ typedef struct _batch {
31
33
  struct _batch *next;
32
34
  int next_avail;
33
35
  struct _leaf leaves[BATCH_SIZE];
34
- } * Batch;
36
+ } *Batch;
35
37
 
36
38
  typedef struct _doc {
37
39
  Leaf data;
38
- Leaf * where; // points to current location
40
+ Leaf *where; // points to current location
39
41
  Leaf where_path[MAX_STACK]; // points to head of path
40
- char * json;
41
- unsigned long size; // number of leaves/branches in the doc
42
+ char *json;
43
+ unsigned long size; // number of leaves/branches in the doc
42
44
  VALUE self;
43
45
  Batch batches;
44
46
  struct _batch batch0;
45
- } * Doc;
47
+ } *Doc;
46
48
 
47
49
  typedef struct _parseInfo {
48
50
  char *str; // buffer being read from
49
51
  char *s; // current position in buffer
50
52
  Doc doc;
51
53
  void *stack_min;
52
- } * ParseInfo;
54
+ } *ParseInfo;
53
55
 
54
56
  static void leaf_init(Leaf leaf, int type);
55
57
  static Leaf leaf_new(Doc doc, int type);
@@ -73,7 +75,7 @@ static char *read_quoted_value(ParseInfo pi);
73
75
  static void skip_comment(ParseInfo pi);
74
76
 
75
77
  static VALUE protect_open_proc(VALUE x);
76
- static VALUE parse_json(VALUE clas, char *json, bool given, bool allocated);
78
+ static VALUE parse_json(VALUE clas, char *json, bool given);
77
79
  static void each_leaf(Doc doc, VALUE self);
78
80
  static int move_step(Doc doc, const char *path, int loc);
79
81
  static Leaf get_doc_leaf(Doc doc, const char *path);
@@ -112,10 +114,7 @@ inline static char *ulong_fill(char *s, size_t num) {
112
114
  char *b = buf + sizeof(buf) - 1;
113
115
 
114
116
  *b-- = '\0';
115
- for (; 0 < num; num /= 10, b--) {
116
- *b = (num % 10) + '0';
117
- }
118
- b++;
117
+ b = oj_longlong_to_string((long long)num, false, b);
119
118
  if ('\0' == *b) {
120
119
  b--;
121
120
  *b = '0';
@@ -159,7 +158,7 @@ inline static Leaf leaf_new(Doc doc, int type) {
159
158
  Leaf leaf;
160
159
 
161
160
  if (0 == doc->batches || BATCH_SIZE == doc->batches->next_avail) {
162
- Batch b = ALLOC(struct _batch);
161
+ Batch b = OJ_R_ALLOC(struct _batch);
163
162
 
164
163
  // Initializes all leaves with a NO_VAL value_type
165
164
  memset(b, 0, sizeof(struct _batch));
@@ -249,7 +248,7 @@ static void skip_comment(ParseInfo pi) {
249
248
  #endif
250
249
 
251
250
  static void leaf_fixnum_value(Leaf leaf) {
252
- char * s = leaf->str;
251
+ char *s = leaf->str;
253
252
  int64_t n = 0;
254
253
  int neg = 0;
255
254
  int big = 0;
@@ -355,7 +354,7 @@ static Leaf read_next(ParseInfo pi) {
355
354
 
356
355
  static Leaf read_obj(ParseInfo pi) {
357
356
  Leaf h = leaf_new(pi->doc, T_HASH);
358
- char * end;
357
+ char *end;
359
358
  const char *key = 0;
360
359
  Leaf val = 0;
361
360
 
@@ -574,7 +573,7 @@ static char *read_quoted_value(ParseInfo pi) {
574
573
  char *h = pi->s; // head
575
574
  char *t = h; // tail
576
575
 
577
- h++; // skip quote character
576
+ h++; // skip quote character
578
577
  t++;
579
578
  value = h;
580
579
  for (; '"' != *h; h++, t++) {
@@ -647,10 +646,11 @@ static void doc_free(Doc doc) {
647
646
  while (0 != (b = doc->batches)) {
648
647
  doc->batches = doc->batches->next;
649
648
  if (&doc->batch0 != b) {
650
- xfree(b);
649
+ OJ_R_FREE(b);
651
650
  }
652
651
  }
653
- // xfree(f);
652
+ OJ_R_FREE(doc->json);
653
+ OJ_R_FREE(doc);
654
654
  }
655
655
  }
656
656
 
@@ -670,27 +670,28 @@ static void free_doc_cb(void *x) {
670
670
  Doc doc = (Doc)x;
671
671
 
672
672
  if (0 != doc) {
673
- xfree(doc->json);
674
673
  doc_free(doc);
675
674
  }
676
675
  }
677
676
 
678
677
  static void mark_leaf(Leaf leaf) {
679
- switch (leaf->value_type) {
680
- case COL_VAL:
681
- if (NULL != leaf->elements) {
682
- Leaf first = leaf->elements->next;
683
- Leaf e = first;
678
+ if (NULL != leaf) {
679
+ switch (leaf->value_type) {
680
+ case COL_VAL:
681
+ if (NULL != leaf->elements) {
682
+ Leaf first = leaf->elements->next;
683
+ Leaf e = first;
684
684
 
685
- do {
686
- mark_leaf(e);
687
- e = e->next;
688
- } while (e != first);
689
- }
690
- break;
691
- case RUBY_VAL: mark(leaf->value); break;
685
+ do {
686
+ mark_leaf(e);
687
+ e = e->next;
688
+ } while (e != first);
689
+ }
690
+ break;
691
+ case RUBY_VAL: mark(leaf->value); break;
692
692
 
693
- default: break;
693
+ default: break;
694
+ }
694
695
  }
695
696
  }
696
697
 
@@ -746,20 +747,15 @@ static const rb_data_type_t oj_doc_type = {
746
747
  0,
747
748
  };
748
749
 
749
- static VALUE parse_json(VALUE clas, char *json, bool given, bool allocated) {
750
+ static VALUE parse_json(VALUE clas, char *json, bool given) {
750
751
  struct _parseInfo pi;
751
752
  volatile VALUE result = Qnil;
752
753
  Doc doc;
753
754
  int ex = 0;
754
755
  volatile VALUE self;
755
756
 
756
- // TBD are both needed? is stack allocation ever needed?
757
+ doc = OJ_R_ALLOC_N(struct _doc, 1);
757
758
 
758
- if (given) {
759
- doc = ALLOCA_N(struct _doc, 1);
760
- } else {
761
- doc = ALLOC(struct _doc);
762
- }
763
759
  // skip UTF-8 BOM if present
764
760
  if (0xEF == (uint8_t)*json && 0xBB == (uint8_t)json[1] && 0xBF == (uint8_t)json[2]) {
765
761
  pi.str = json + 3;
@@ -771,7 +767,7 @@ static VALUE parse_json(VALUE clas, char *json, bool given, bool allocated) {
771
767
  pi.doc = doc;
772
768
  #if IS_WINDOWS
773
769
  // assume a 1M stack and give half to ruby
774
- pi.stack_min = (void*)((char*)&pi - (512 * 1024));
770
+ pi.stack_min = (void *)((char *)&pi - (512L * 1024L));
775
771
  #else
776
772
  {
777
773
  struct rlimit lim;
@@ -784,18 +780,20 @@ static VALUE parse_json(VALUE clas, char *json, bool given, bool allocated) {
784
780
  }
785
781
  }
786
782
  #endif
783
+ doc->json = json;
787
784
  self = TypedData_Wrap_Struct(clas, &oj_doc_type, doc);
788
785
  doc->self = self;
789
- doc->json = json;
790
786
  DATA_PTR(doc->self) = doc;
791
787
  result = rb_protect(protect_open_proc, (VALUE)&pi, &ex);
792
788
  if (given || 0 != ex) {
793
789
  DATA_PTR(doc->self) = NULL;
790
+ // TBD is this needed?
791
+ /*
794
792
  doc_free(pi.doc);
795
- if (allocated && 0 != ex) { // will jump so caller will not free
796
- xfree(json);
793
+ if (0 != ex) { // will jump so caller will not free
794
+ OJ_R_FREE(json);
797
795
  }
798
- rb_gc_enable();
796
+ */
799
797
  } else {
800
798
  result = doc->self;
801
799
  }
@@ -1085,31 +1083,23 @@ static void each_value(Doc doc, Leaf leaf) {
1085
1083
  * doc.close()
1086
1084
  */
1087
1085
  static VALUE doc_open(VALUE clas, VALUE str) {
1088
- char * json;
1086
+ char *json;
1089
1087
  size_t len;
1090
1088
  volatile VALUE obj;
1091
1089
  int given = rb_block_given_p();
1092
- int allocate;
1093
1090
 
1094
1091
  Check_Type(str, T_STRING);
1095
- len = (int)RSTRING_LEN(str) + 1;
1096
- allocate = (SMALL_JSON < len || !given);
1097
- if (allocate) {
1098
- json = ALLOC_N(char, len);
1099
- } else {
1100
- json = ALLOCA_N(char, len);
1101
- }
1102
- // It should not be necessaary to stop GC but if it is not stopped and a
1103
- // large string is parsed that string is corrupted or freed during
1104
- // parsing. I'm not sure what is going on exactly but disabling GC avoids
1105
- // the issue.
1106
- rb_gc_disable();
1092
+ len = (int)RSTRING_LEN(str) + 1;
1093
+ json = OJ_R_ALLOC_N(char, len);
1094
+
1107
1095
  memcpy(json, StringValuePtr(str), len);
1108
- obj = parse_json(clas, json, given, allocate);
1109
- rb_gc_enable();
1110
- if (given && allocate) {
1111
- xfree(json);
1096
+ obj = parse_json(clas, json, given);
1097
+ // TBD is this needed
1098
+ /*
1099
+ if (given) {
1100
+ OJ_R_FREE(json);
1112
1101
  }
1102
+ */
1113
1103
  return obj;
1114
1104
  }
1115
1105
 
@@ -1133,27 +1123,21 @@ static VALUE doc_open(VALUE clas, VALUE str) {
1133
1123
  * doc.close()
1134
1124
  */
1135
1125
  static VALUE doc_open_file(VALUE clas, VALUE filename) {
1136
- char * path;
1137
- char * json;
1138
- FILE * f;
1126
+ char *path;
1127
+ char *json;
1128
+ FILE *f;
1139
1129
  size_t len;
1140
1130
  volatile VALUE obj;
1141
1131
  int given = rb_block_given_p();
1142
- int allocate;
1143
1132
 
1144
- Check_Type(filename, T_STRING);
1145
1133
  path = StringValuePtr(filename);
1146
1134
  if (0 == (f = fopen(path, "r"))) {
1147
1135
  rb_raise(rb_eIOError, "%s", strerror(errno));
1148
1136
  }
1149
1137
  fseek(f, 0, SEEK_END);
1150
- len = ftell(f);
1151
- allocate = (SMALL_JSON < len || !given);
1152
- if (allocate) {
1153
- json = ALLOC_N(char, len + 1);
1154
- } else {
1155
- json = ALLOCA_N(char, len + 1);
1156
- }
1138
+ len = ftell(f);
1139
+ json = OJ_R_ALLOC_N(char, len + 1);
1140
+
1157
1141
  fseek(f, 0, SEEK_SET);
1158
1142
  if (len != fread(json, 1, len, f)) {
1159
1143
  fclose(f);
@@ -1164,12 +1148,13 @@ static VALUE doc_open_file(VALUE clas, VALUE filename) {
1164
1148
  }
1165
1149
  fclose(f);
1166
1150
  json[len] = '\0';
1167
- rb_gc_disable();
1168
- obj = parse_json(clas, json, given, allocate);
1169
- rb_gc_enable();
1170
- if (given && allocate) {
1171
- xfree(json);
1151
+ obj = parse_json(clas, json, given);
1152
+ // TBD is this needed
1153
+ /*
1154
+ if (given) {
1155
+ OJ_R_FREE(json);
1172
1156
  }
1157
+ */
1173
1158
  return obj;
1174
1159
  }
1175
1160
 
@@ -1209,11 +1194,11 @@ static VALUE doc_where(VALUE self) {
1209
1194
  if (0 == *doc->where_path || doc->where == doc->where_path) {
1210
1195
  return oj_slash_string;
1211
1196
  } else {
1212
- Leaf * lp;
1197
+ Leaf *lp;
1213
1198
  Leaf leaf;
1214
1199
  size_t size = 3; // leading / and terminating \0
1215
- char * path;
1216
- char * p;
1200
+ char *path;
1201
+ char *p;
1217
1202
 
1218
1203
  for (lp = doc->where_path; lp <= doc->where; lp++) {
1219
1204
  leaf = *lp;
@@ -1316,7 +1301,6 @@ static VALUE doc_type(int argc, VALUE *argv, VALUE self) {
1316
1301
  VALUE type = Qnil;
1317
1302
 
1318
1303
  if (1 <= argc) {
1319
- Check_Type(*argv, T_STRING);
1320
1304
  path = StringValuePtr(*argv);
1321
1305
  }
1322
1306
  if (0 != (leaf = get_doc_leaf(doc, path))) {
@@ -1325,11 +1309,7 @@ static VALUE doc_type(int argc, VALUE *argv, VALUE self) {
1325
1309
  case T_TRUE: type = rb_cTrueClass; break;
1326
1310
  case T_FALSE: type = rb_cFalseClass; break;
1327
1311
  case T_STRING: type = rb_cString; break;
1328
- #ifdef RUBY_INTEGER_UNIFICATION
1329
1312
  case T_FIXNUM: type = rb_cInteger; break;
1330
- #else
1331
- case T_FIXNUM: type = rb_cFixnum; break;
1332
- #endif
1333
1313
  case T_FLOAT: type = rb_cFloat; break;
1334
1314
  case T_ARRAY: type = rb_cArray; break;
1335
1315
  case T_HASH: type = rb_cHash; break;
@@ -1356,11 +1336,10 @@ static VALUE doc_fetch(int argc, VALUE *argv, VALUE self) {
1356
1336
  Doc doc;
1357
1337
  Leaf leaf;
1358
1338
  volatile VALUE val = Qnil;
1359
- const char * path = 0;
1339
+ const char *path = 0;
1360
1340
 
1361
1341
  doc = self_doc(self);
1362
1342
  if (1 <= argc) {
1363
- Check_Type(*argv, T_STRING);
1364
1343
  path = StringValuePtr(*argv);
1365
1344
  if (2 == argc) {
1366
1345
  val = argv[1];
@@ -1385,7 +1364,6 @@ static VALUE doc_exists(VALUE self, VALUE str) {
1385
1364
  Leaf leaf;
1386
1365
 
1387
1366
  doc = self_doc(self);
1388
- Check_Type(str, T_STRING);
1389
1367
  if (0 != (leaf = get_doc_leaf(doc, StringValuePtr(str)))) {
1390
1368
  if (NULL != leaf) {
1391
1369
  return Qtrue;
@@ -1422,7 +1400,6 @@ static VALUE doc_each_leaf(int argc, VALUE *argv, VALUE self) {
1422
1400
  memcpy(save_path, doc->where_path, sizeof(Leaf) * (wlen + 1));
1423
1401
  }
1424
1402
  if (1 <= argc) {
1425
- Check_Type(*argv, T_STRING);
1426
1403
  path = StringValuePtr(*argv);
1427
1404
  if ('/' == *path) {
1428
1405
  doc->where = doc->where_path;
@@ -1457,7 +1434,6 @@ static VALUE doc_move(VALUE self, VALUE str) {
1457
1434
  const char *path;
1458
1435
  int loc;
1459
1436
 
1460
- Check_Type(str, T_STRING);
1461
1437
  path = StringValuePtr(str);
1462
1438
  if ('/' == *path) {
1463
1439
  doc->where = doc->where_path;
@@ -1492,13 +1468,13 @@ static VALUE doc_each_child(int argc, VALUE *argv, VALUE self) {
1492
1468
  Doc doc = self_doc(self);
1493
1469
  const char *path = 0;
1494
1470
  size_t wlen;
1471
+ Leaf *where_orig = doc->where;
1495
1472
 
1496
1473
  wlen = doc->where - doc->where_path;
1497
1474
  if (0 < wlen) {
1498
1475
  memcpy(save_path, doc->where_path, sizeof(Leaf) * (wlen + 1));
1499
1476
  }
1500
1477
  if (1 <= argc) {
1501
- Check_Type(*argv, T_STRING);
1502
1478
  path = StringValuePtr(*argv);
1503
1479
  if ('/' == *path) {
1504
1480
  doc->where = doc->where_path;
@@ -1508,9 +1484,13 @@ static VALUE doc_each_child(int argc, VALUE *argv, VALUE self) {
1508
1484
  if (0 < wlen) {
1509
1485
  memcpy(doc->where_path, save_path, sizeof(Leaf) * (wlen + 1));
1510
1486
  }
1487
+ doc->where = where_orig;
1511
1488
  return Qnil;
1512
1489
  }
1513
1490
  }
1491
+ if (NULL == doc->where || NULL == *doc->where) {
1492
+ return Qnil;
1493
+ }
1514
1494
  if (COL_VAL == (*doc->where)->value_type && 0 != (*doc->where)->elements) {
1515
1495
  Leaf first = (*doc->where)->elements->next;
1516
1496
  Leaf e = first;
@@ -1525,6 +1505,7 @@ static VALUE doc_each_child(int argc, VALUE *argv, VALUE self) {
1525
1505
  if (0 < wlen) {
1526
1506
  memcpy(doc->where_path, save_path, sizeof(Leaf) * (wlen + 1));
1527
1507
  }
1508
+ doc->where = where_orig;
1528
1509
  }
1529
1510
  return Qnil;
1530
1511
  }
@@ -1560,7 +1541,6 @@ static VALUE doc_each_value(int argc, VALUE *argv, VALUE self) {
1560
1541
  Leaf leaf;
1561
1542
 
1562
1543
  if (1 <= argc) {
1563
- Check_Type(*argv, T_STRING);
1564
1544
  path = StringValuePtr(*argv);
1565
1545
  }
1566
1546
  if (0 != (leaf = get_doc_leaf(doc, path))) {
@@ -1592,11 +1572,9 @@ static VALUE doc_dump(int argc, VALUE *argv, VALUE self) {
1592
1572
 
1593
1573
  if (1 <= argc) {
1594
1574
  if (Qnil != *argv) {
1595
- Check_Type(*argv, T_STRING);
1596
1575
  path = StringValuePtr(*argv);
1597
1576
  }
1598
1577
  if (2 <= argc) {
1599
- Check_Type(argv[1], T_STRING);
1600
1578
  filename = StringValuePtr(argv[1]);
1601
1579
  }
1602
1580
  }
@@ -1604,18 +1582,15 @@ static VALUE doc_dump(int argc, VALUE *argv, VALUE self) {
1604
1582
  volatile VALUE rjson;
1605
1583
 
1606
1584
  if (0 == filename) {
1607
- char buf[4096];
1608
1585
  struct _out out;
1609
1586
 
1610
- out.buf = buf;
1611
- out.end = buf + sizeof(buf) - 10;
1612
- out.allocated = false;
1613
- out.omit_nil = oj_default_options.dump_opts.omit_nil;
1587
+ oj_out_init(&out);
1588
+
1589
+ out.omit_nil = oj_default_options.dump_opts.omit_nil;
1614
1590
  oj_dump_leaf_to_json(leaf, &oj_default_options, &out);
1615
1591
  rjson = rb_str_new2(out.buf);
1616
- if (out.allocated) {
1617
- xfree(out.buf);
1618
- }
1592
+
1593
+ oj_out_free(&out);
1619
1594
  } else {
1620
1595
  oj_write_leaf_to_file(leaf, filename, &oj_default_options);
1621
1596
  rjson = Qnil;
@@ -1650,11 +1625,9 @@ static VALUE doc_close(VALUE self) {
1650
1625
  Doc doc = self_doc(self);
1651
1626
 
1652
1627
  rb_gc_unregister_address(&doc->self);
1653
- DATA_PTR(doc->self) = 0;
1628
+ DATA_PTR(doc->self) = NULL;
1654
1629
  if (0 != doc) {
1655
- xfree(doc->json);
1656
1630
  doc_free(doc);
1657
- xfree(doc);
1658
1631
  }
1659
1632
  return Qnil;
1660
1633
  }
@@ -1711,8 +1684,10 @@ static VALUE doc_not_implemented(VALUE self) {
1711
1684
  * # Now try again using a path to Oj::Doc.fetch() directly and not using a
1712
1685
  * block. doc = Oj::Doc.open(json) doc.fetch('/2/three') #=> 3 doc.close()
1713
1686
  */
1714
- void oj_init_doc() {
1687
+ void oj_init_doc(void) {
1715
1688
  oj_doc_class = rb_define_class_under(Oj, "Doc", rb_cObject);
1689
+ rb_gc_register_address(&oj_doc_class);
1690
+ rb_undef_alloc_func(oj_doc_class);
1716
1691
  rb_define_singleton_method(oj_doc_class, "open", doc_open, 1);
1717
1692
  rb_define_singleton_method(oj_doc_class, "open_file", doc_open_file, 1);
1718
1693
  rb_define_singleton_method(oj_doc_class, "parse", doc_open, 1);