oj 3.13.11 → 3.15.0

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 +74 -0
  3. data/README.md +4 -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 +17 -24
  10. data/ext/oj/code.h +2 -2
  11. data/ext/oj/compat.c +17 -44
  12. data/ext/oj/custom.c +70 -141
  13. data/ext/oj/debug.c +3 -9
  14. data/ext/oj/dump.c +128 -118
  15. data/ext/oj/dump.h +12 -8
  16. data/ext/oj/dump_compat.c +564 -641
  17. data/ext/oj/dump_leaf.c +17 -63
  18. data/ext/oj/dump_object.c +70 -199
  19. data/ext/oj/dump_strict.c +22 -46
  20. data/ext/oj/encoder.c +1 -1
  21. data/ext/oj/err.c +2 -13
  22. data/ext/oj/err.h +9 -12
  23. data/ext/oj/extconf.rb +14 -5
  24. data/ext/oj/fast.c +75 -103
  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 +75 -47
  30. data/ext/oj/object.c +49 -66
  31. data/ext/oj/odd.c +89 -67
  32. data/ext/oj/odd.h +15 -15
  33. data/ext/oj/oj.c +140 -99
  34. data/ext/oj/oj.h +80 -51
  35. data/ext/oj/parse.c +162 -184
  36. data/ext/oj/parse.h +7 -10
  37. data/ext/oj/parser.c +89 -34
  38. data/ext/oj/parser.h +18 -7
  39. data/ext/oj/rails.c +82 -146
  40. data/ext/oj/rails.h +1 -1
  41. data/ext/oj/reader.c +11 -12
  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 +20 -31
  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 -21
  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 +31 -68
  62. data/lib/oj/active_support_helper.rb +0 -1
  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 +4 -2
  67. data/lib/oj/mimic.rb +4 -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/Options.md +10 -0
  75. data/test/_test_active.rb +8 -9
  76. data/test/_test_active_mimic.rb +7 -8
  77. data/test/_test_mimic_rails.rb +17 -20
  78. data/test/activerecord/result_test.rb +5 -6
  79. data/test/{activesupport5 → activesupport7}/abstract_unit.rb +16 -12
  80. data/test/{activesupport5 → activesupport7}/decoding_test.rb +2 -10
  81. data/test/{activesupport5 → activesupport7}/encoding_test.rb +20 -34
  82. data/test/{activesupport5 → activesupport7}/encoding_test_cases.rb +6 -0
  83. data/test/{activesupport5 → activesupport7}/time_zone_test_helpers.rb +8 -0
  84. data/test/files.rb +15 -15
  85. data/test/foo.rb +9 -71
  86. data/test/helper.rb +11 -8
  87. data/test/isolated/shared.rb +3 -2
  88. data/test/json_gem/json_addition_test.rb +2 -2
  89. data/test/json_gem/json_common_interface_test.rb +4 -4
  90. data/test/json_gem/json_encoding_test.rb +0 -0
  91. data/test/json_gem/json_ext_parser_test.rb +1 -0
  92. data/test/json_gem/json_fixtures_test.rb +3 -2
  93. data/test/json_gem/json_generator_test.rb +48 -36
  94. data/test/json_gem/json_generic_object_test.rb +11 -11
  95. data/test/json_gem/json_parser_test.rb +54 -47
  96. data/test/json_gem/json_string_matching_test.rb +9 -9
  97. data/test/json_gem/test_helper.rb +7 -3
  98. data/test/mem.rb +13 -12
  99. data/test/perf.rb +21 -26
  100. data/test/perf_compat.rb +31 -33
  101. data/test/perf_dump.rb +50 -0
  102. data/test/perf_fast.rb +80 -82
  103. data/test/perf_file.rb +27 -29
  104. data/test/perf_object.rb +65 -69
  105. data/test/perf_once.rb +12 -11
  106. data/test/perf_parser.rb +42 -48
  107. data/test/perf_saj.rb +46 -54
  108. data/test/perf_scp.rb +57 -69
  109. data/test/perf_simple.rb +41 -39
  110. data/test/perf_strict.rb +68 -70
  111. data/test/perf_wab.rb +67 -69
  112. data/test/prec.rb +3 -3
  113. data/test/sample/change.rb +0 -1
  114. data/test/sample/dir.rb +0 -1
  115. data/test/sample/doc.rb +0 -1
  116. data/test/sample/file.rb +0 -1
  117. data/test/sample/group.rb +0 -1
  118. data/test/sample/hasprops.rb +0 -1
  119. data/test/sample/layer.rb +0 -1
  120. data/test/sample/rect.rb +0 -1
  121. data/test/sample/shape.rb +0 -1
  122. data/test/sample/text.rb +0 -1
  123. data/test/sample.rb +16 -16
  124. data/test/sample_json.rb +8 -8
  125. data/test/test_compat.rb +76 -42
  126. data/test/test_custom.rb +72 -51
  127. data/test/test_debian.rb +7 -10
  128. data/test/test_fast.rb +86 -90
  129. data/test/test_file.rb +41 -30
  130. data/test/test_gc.rb +16 -5
  131. data/test/test_generate.rb +5 -5
  132. data/test/test_hash.rb +4 -4
  133. data/test/test_integer_range.rb +9 -9
  134. data/test/test_null.rb +20 -20
  135. data/test/test_object.rb +85 -96
  136. data/test/test_parser.rb +6 -22
  137. data/test/test_parser_debug.rb +27 -0
  138. data/test/test_parser_saj.rb +115 -23
  139. data/test/test_parser_usual.rb +6 -6
  140. data/test/test_rails.rb +2 -2
  141. data/test/test_saj.rb +10 -8
  142. data/test/test_scp.rb +37 -39
  143. data/test/test_strict.rb +30 -32
  144. data/test/test_various.rb +147 -99
  145. data/test/test_wab.rb +48 -44
  146. data/test/test_writer.rb +47 -47
  147. data/test/tests.rb +13 -4
  148. data/test/tests_mimic.rb +12 -3
  149. data/test/tests_mimic_addition.rb +12 -3
  150. metadata +33 -144
  151. data/test/activesupport4/decoding_test.rb +0 -108
  152. data/test/activesupport4/encoding_test.rb +0 -531
  153. data/test/activesupport4/test_helper.rb +0 -41
  154. data/test/activesupport5/test_helper.rb +0 -72
  155. data/test/bar.rb +0 -16
  156. data/test/baz.rb +0 -16
  157. data/test/bug.rb +0 -16
  158. 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;
42
+ char *json;
41
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);
@@ -159,7 +161,7 @@ inline static Leaf leaf_new(Doc doc, int type) {
159
161
  Leaf leaf;
160
162
 
161
163
  if (0 == doc->batches || BATCH_SIZE == doc->batches->next_avail) {
162
- Batch b = ALLOC(struct _batch);
164
+ Batch b = OJ_R_ALLOC(struct _batch);
163
165
 
164
166
  // Initializes all leaves with a NO_VAL value_type
165
167
  memset(b, 0, sizeof(struct _batch));
@@ -249,7 +251,7 @@ static void skip_comment(ParseInfo pi) {
249
251
  #endif
250
252
 
251
253
  static void leaf_fixnum_value(Leaf leaf) {
252
- char * s = leaf->str;
254
+ char *s = leaf->str;
253
255
  int64_t n = 0;
254
256
  int neg = 0;
255
257
  int big = 0;
@@ -355,7 +357,7 @@ static Leaf read_next(ParseInfo pi) {
355
357
 
356
358
  static Leaf read_obj(ParseInfo pi) {
357
359
  Leaf h = leaf_new(pi->doc, T_HASH);
358
- char * end;
360
+ char *end;
359
361
  const char *key = 0;
360
362
  Leaf val = 0;
361
363
 
@@ -647,10 +649,11 @@ static void doc_free(Doc doc) {
647
649
  while (0 != (b = doc->batches)) {
648
650
  doc->batches = doc->batches->next;
649
651
  if (&doc->batch0 != b) {
650
- xfree(b);
652
+ OJ_R_FREE(b);
651
653
  }
652
654
  }
653
- // xfree(f);
655
+ OJ_R_FREE(doc->json);
656
+ OJ_R_FREE(doc);
654
657
  }
655
658
  }
656
659
 
@@ -670,27 +673,28 @@ static void free_doc_cb(void *x) {
670
673
  Doc doc = (Doc)x;
671
674
 
672
675
  if (0 != doc) {
673
- xfree(doc->json);
674
676
  doc_free(doc);
675
677
  }
676
678
  }
677
679
 
678
680
  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;
681
+ if (NULL != leaf) {
682
+ switch (leaf->value_type) {
683
+ case COL_VAL:
684
+ if (NULL != leaf->elements) {
685
+ Leaf first = leaf->elements->next;
686
+ Leaf e = first;
684
687
 
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;
688
+ do {
689
+ mark_leaf(e);
690
+ e = e->next;
691
+ } while (e != first);
692
+ }
693
+ break;
694
+ case RUBY_VAL: mark(leaf->value); break;
692
695
 
693
- default: break;
696
+ default: break;
697
+ }
694
698
  }
695
699
  }
696
700
 
@@ -746,20 +750,15 @@ static const rb_data_type_t oj_doc_type = {
746
750
  0,
747
751
  };
748
752
 
749
- static VALUE parse_json(VALUE clas, char *json, bool given, bool allocated) {
753
+ static VALUE parse_json(VALUE clas, char *json, bool given) {
750
754
  struct _parseInfo pi;
751
755
  volatile VALUE result = Qnil;
752
756
  Doc doc;
753
757
  int ex = 0;
754
758
  volatile VALUE self;
755
759
 
756
- // TBD are both needed? is stack allocation ever needed?
760
+ doc = OJ_R_ALLOC_N(struct _doc, 1);
757
761
 
758
- if (given) {
759
- doc = ALLOCA_N(struct _doc, 1);
760
- } else {
761
- doc = ALLOC(struct _doc);
762
- }
763
762
  // skip UTF-8 BOM if present
764
763
  if (0xEF == (uint8_t)*json && 0xBB == (uint8_t)json[1] && 0xBF == (uint8_t)json[2]) {
765
764
  pi.str = json + 3;
@@ -771,7 +770,7 @@ static VALUE parse_json(VALUE clas, char *json, bool given, bool allocated) {
771
770
  pi.doc = doc;
772
771
  #if IS_WINDOWS
773
772
  // assume a 1M stack and give half to ruby
774
- pi.stack_min = (void *)((char *)&pi - (512 * 1024));
773
+ pi.stack_min = (void *)((char *)&pi - (512L * 1024L));
775
774
  #else
776
775
  {
777
776
  struct rlimit lim;
@@ -784,18 +783,20 @@ static VALUE parse_json(VALUE clas, char *json, bool given, bool allocated) {
784
783
  }
785
784
  }
786
785
  #endif
786
+ doc->json = json;
787
787
  self = TypedData_Wrap_Struct(clas, &oj_doc_type, doc);
788
788
  doc->self = self;
789
- doc->json = json;
790
789
  DATA_PTR(doc->self) = doc;
791
790
  result = rb_protect(protect_open_proc, (VALUE)&pi, &ex);
792
791
  if (given || 0 != ex) {
793
792
  DATA_PTR(doc->self) = NULL;
793
+ // TBD is this needed?
794
+ /*
794
795
  doc_free(pi.doc);
795
- if (allocated && 0 != ex) { // will jump so caller will not free
796
- xfree(json);
796
+ if (0 != ex) { // will jump so caller will not free
797
+ OJ_R_FREE(json);
797
798
  }
798
- rb_gc_enable();
799
+ */
799
800
  } else {
800
801
  result = doc->self;
801
802
  }
@@ -1085,31 +1086,23 @@ static void each_value(Doc doc, Leaf leaf) {
1085
1086
  * doc.close()
1086
1087
  */
1087
1088
  static VALUE doc_open(VALUE clas, VALUE str) {
1088
- char * json;
1089
+ char *json;
1089
1090
  size_t len;
1090
1091
  volatile VALUE obj;
1091
1092
  int given = rb_block_given_p();
1092
- int allocate;
1093
1093
 
1094
1094
  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();
1095
+ len = (int)RSTRING_LEN(str) + 1;
1096
+ json = OJ_R_ALLOC_N(char, len);
1097
+
1107
1098
  memcpy(json, StringValuePtr(str), len);
1108
- obj = parse_json(clas, json, given, allocate);
1109
- rb_gc_enable();
1110
- if (given && allocate) {
1111
- xfree(json);
1099
+ obj = parse_json(clas, json, given);
1100
+ // TBD is this needed
1101
+ /*
1102
+ if (given) {
1103
+ OJ_R_FREE(json);
1112
1104
  }
1105
+ */
1113
1106
  return obj;
1114
1107
  }
1115
1108
 
@@ -1133,27 +1126,21 @@ static VALUE doc_open(VALUE clas, VALUE str) {
1133
1126
  * doc.close()
1134
1127
  */
1135
1128
  static VALUE doc_open_file(VALUE clas, VALUE filename) {
1136
- char * path;
1137
- char * json;
1138
- FILE * f;
1129
+ char *path;
1130
+ char *json;
1131
+ FILE *f;
1139
1132
  size_t len;
1140
1133
  volatile VALUE obj;
1141
1134
  int given = rb_block_given_p();
1142
- int allocate;
1143
1135
 
1144
- Check_Type(filename, T_STRING);
1145
1136
  path = StringValuePtr(filename);
1146
1137
  if (0 == (f = fopen(path, "r"))) {
1147
1138
  rb_raise(rb_eIOError, "%s", strerror(errno));
1148
1139
  }
1149
1140
  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
- }
1141
+ len = ftell(f);
1142
+ json = OJ_R_ALLOC_N(char, len + 1);
1143
+
1157
1144
  fseek(f, 0, SEEK_SET);
1158
1145
  if (len != fread(json, 1, len, f)) {
1159
1146
  fclose(f);
@@ -1164,12 +1151,13 @@ static VALUE doc_open_file(VALUE clas, VALUE filename) {
1164
1151
  }
1165
1152
  fclose(f);
1166
1153
  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);
1154
+ obj = parse_json(clas, json, given);
1155
+ // TBD is this needed
1156
+ /*
1157
+ if (given) {
1158
+ OJ_R_FREE(json);
1172
1159
  }
1160
+ */
1173
1161
  return obj;
1174
1162
  }
1175
1163
 
@@ -1209,11 +1197,11 @@ static VALUE doc_where(VALUE self) {
1209
1197
  if (0 == *doc->where_path || doc->where == doc->where_path) {
1210
1198
  return oj_slash_string;
1211
1199
  } else {
1212
- Leaf * lp;
1200
+ Leaf *lp;
1213
1201
  Leaf leaf;
1214
1202
  size_t size = 3; // leading / and terminating \0
1215
- char * path;
1216
- char * p;
1203
+ char *path;
1204
+ char *p;
1217
1205
 
1218
1206
  for (lp = doc->where_path; lp <= doc->where; lp++) {
1219
1207
  leaf = *lp;
@@ -1316,7 +1304,6 @@ static VALUE doc_type(int argc, VALUE *argv, VALUE self) {
1316
1304
  VALUE type = Qnil;
1317
1305
 
1318
1306
  if (1 <= argc) {
1319
- Check_Type(*argv, T_STRING);
1320
1307
  path = StringValuePtr(*argv);
1321
1308
  }
1322
1309
  if (0 != (leaf = get_doc_leaf(doc, path))) {
@@ -1325,11 +1312,7 @@ static VALUE doc_type(int argc, VALUE *argv, VALUE self) {
1325
1312
  case T_TRUE: type = rb_cTrueClass; break;
1326
1313
  case T_FALSE: type = rb_cFalseClass; break;
1327
1314
  case T_STRING: type = rb_cString; break;
1328
- #ifdef RUBY_INTEGER_UNIFICATION
1329
1315
  case T_FIXNUM: type = rb_cInteger; break;
1330
- #else
1331
- case T_FIXNUM: type = rb_cFixnum; break;
1332
- #endif
1333
1316
  case T_FLOAT: type = rb_cFloat; break;
1334
1317
  case T_ARRAY: type = rb_cArray; break;
1335
1318
  case T_HASH: type = rb_cHash; break;
@@ -1356,11 +1339,10 @@ static VALUE doc_fetch(int argc, VALUE *argv, VALUE self) {
1356
1339
  Doc doc;
1357
1340
  Leaf leaf;
1358
1341
  volatile VALUE val = Qnil;
1359
- const char * path = 0;
1342
+ const char *path = 0;
1360
1343
 
1361
1344
  doc = self_doc(self);
1362
1345
  if (1 <= argc) {
1363
- Check_Type(*argv, T_STRING);
1364
1346
  path = StringValuePtr(*argv);
1365
1347
  if (2 == argc) {
1366
1348
  val = argv[1];
@@ -1385,7 +1367,6 @@ static VALUE doc_exists(VALUE self, VALUE str) {
1385
1367
  Leaf leaf;
1386
1368
 
1387
1369
  doc = self_doc(self);
1388
- Check_Type(str, T_STRING);
1389
1370
  if (0 != (leaf = get_doc_leaf(doc, StringValuePtr(str)))) {
1390
1371
  if (NULL != leaf) {
1391
1372
  return Qtrue;
@@ -1422,7 +1403,6 @@ static VALUE doc_each_leaf(int argc, VALUE *argv, VALUE self) {
1422
1403
  memcpy(save_path, doc->where_path, sizeof(Leaf) * (wlen + 1));
1423
1404
  }
1424
1405
  if (1 <= argc) {
1425
- Check_Type(*argv, T_STRING);
1426
1406
  path = StringValuePtr(*argv);
1427
1407
  if ('/' == *path) {
1428
1408
  doc->where = doc->where_path;
@@ -1457,7 +1437,6 @@ static VALUE doc_move(VALUE self, VALUE str) {
1457
1437
  const char *path;
1458
1438
  int loc;
1459
1439
 
1460
- Check_Type(str, T_STRING);
1461
1440
  path = StringValuePtr(str);
1462
1441
  if ('/' == *path) {
1463
1442
  doc->where = doc->where_path;
@@ -1492,14 +1471,13 @@ static VALUE doc_each_child(int argc, VALUE *argv, VALUE self) {
1492
1471
  Doc doc = self_doc(self);
1493
1472
  const char *path = 0;
1494
1473
  size_t wlen;
1495
- Leaf * where_orig = doc->where;
1474
+ Leaf *where_orig = doc->where;
1496
1475
 
1497
1476
  wlen = doc->where - doc->where_path;
1498
1477
  if (0 < wlen) {
1499
1478
  memcpy(save_path, doc->where_path, sizeof(Leaf) * (wlen + 1));
1500
1479
  }
1501
1480
  if (1 <= argc) {
1502
- Check_Type(*argv, T_STRING);
1503
1481
  path = StringValuePtr(*argv);
1504
1482
  if ('/' == *path) {
1505
1483
  doc->where = doc->where_path;
@@ -1566,7 +1544,6 @@ static VALUE doc_each_value(int argc, VALUE *argv, VALUE self) {
1566
1544
  Leaf leaf;
1567
1545
 
1568
1546
  if (1 <= argc) {
1569
- Check_Type(*argv, T_STRING);
1570
1547
  path = StringValuePtr(*argv);
1571
1548
  }
1572
1549
  if (0 != (leaf = get_doc_leaf(doc, path))) {
@@ -1598,11 +1575,9 @@ static VALUE doc_dump(int argc, VALUE *argv, VALUE self) {
1598
1575
 
1599
1576
  if (1 <= argc) {
1600
1577
  if (Qnil != *argv) {
1601
- Check_Type(*argv, T_STRING);
1602
1578
  path = StringValuePtr(*argv);
1603
1579
  }
1604
1580
  if (2 <= argc) {
1605
- Check_Type(argv[1], T_STRING);
1606
1581
  filename = StringValuePtr(argv[1]);
1607
1582
  }
1608
1583
  }
@@ -1610,18 +1585,15 @@ static VALUE doc_dump(int argc, VALUE *argv, VALUE self) {
1610
1585
  volatile VALUE rjson;
1611
1586
 
1612
1587
  if (0 == filename) {
1613
- char buf[4096];
1614
1588
  struct _out out;
1615
1589
 
1616
- out.buf = buf;
1617
- out.end = buf + sizeof(buf) - 10;
1618
- out.allocated = false;
1619
- out.omit_nil = oj_default_options.dump_opts.omit_nil;
1590
+ oj_out_init(&out);
1591
+
1592
+ out.omit_nil = oj_default_options.dump_opts.omit_nil;
1620
1593
  oj_dump_leaf_to_json(leaf, &oj_default_options, &out);
1621
1594
  rjson = rb_str_new2(out.buf);
1622
- if (out.allocated) {
1623
- xfree(out.buf);
1624
- }
1595
+
1596
+ oj_out_free(&out);
1625
1597
  } else {
1626
1598
  oj_write_leaf_to_file(leaf, filename, &oj_default_options);
1627
1599
  rjson = Qnil;
@@ -1656,11 +1628,9 @@ static VALUE doc_close(VALUE self) {
1656
1628
  Doc doc = self_doc(self);
1657
1629
 
1658
1630
  rb_gc_unregister_address(&doc->self);
1659
- DATA_PTR(doc->self) = 0;
1631
+ DATA_PTR(doc->self) = NULL;
1660
1632
  if (0 != doc) {
1661
- xfree(doc->json);
1662
1633
  doc_free(doc);
1663
- xfree(doc);
1664
1634
  }
1665
1635
  return Qnil;
1666
1636
  }
@@ -1717,8 +1687,10 @@ static VALUE doc_not_implemented(VALUE self) {
1717
1687
  * # Now try again using a path to Oj::Doc.fetch() directly and not using a
1718
1688
  * block. doc = Oj::Doc.open(json) doc.fetch('/2/three') #=> 3 doc.close()
1719
1689
  */
1720
- void oj_init_doc() {
1690
+ void oj_init_doc(void) {
1721
1691
  oj_doc_class = rb_define_class_under(Oj, "Doc", rb_cObject);
1692
+ rb_gc_register_address(&oj_doc_class);
1693
+ rb_undef_alloc_func(oj_doc_class);
1722
1694
  rb_define_singleton_method(oj_doc_class, "open", doc_open, 1);
1723
1695
  rb_define_singleton_method(oj_doc_class, "open_file", doc_open_file, 1);
1724
1696
  rb_define_singleton_method(oj_doc_class, "parse", doc_open, 1);
data/ext/oj/intern.c CHANGED
@@ -8,7 +8,9 @@
8
8
  #if HAVE_PTHREAD_MUTEX_INIT
9
9
  #include <pthread.h>
10
10
  #endif
11
+
11
12
  #include "cache.h"
13
+ #include "mem.h"
12
14
  #include "parse.h"
13
15
 
14
16
  // Only used for the class cache so 256 should be sufficient.
@@ -20,10 +22,10 @@
20
22
 
21
23
  typedef struct _keyVal {
22
24
  struct _keyVal *next;
23
- const char * key;
25
+ const char *key;
24
26
  size_t len;
25
27
  VALUE val;
26
- } * KeyVal;
28
+ } *KeyVal;
27
29
 
28
30
  typedef struct _hash {
29
31
  struct _keyVal slots[HASH_SLOT_CNT];
@@ -32,19 +34,16 @@ typedef struct _hash {
32
34
  #else
33
35
  VALUE mutex;
34
36
  #endif
35
- } * Hash;
37
+ } *Hash;
36
38
 
37
39
  struct _hash class_hash;
38
40
  struct _hash attr_hash;
39
41
 
40
- static struct _cache *str_cache = NULL;
41
- static VALUE str_cache_obj;
42
+ static VALUE str_cache_obj;
42
43
 
43
- static struct _cache *sym_cache = NULL;
44
- static VALUE sym_cache_obj;
44
+ static VALUE sym_cache_obj;
45
45
 
46
- static struct _cache *attr_cache = NULL;
47
- static VALUE attr_cache_obj;
46
+ static VALUE attr_cache_obj;
48
47
 
49
48
  static VALUE form_str(const char *str, size_t len) {
50
49
  return rb_str_freeze(rb_utf8_str_new(str, len));
@@ -58,47 +57,48 @@ static VALUE form_attr(const char *str, size_t len) {
58
57
  char buf[256];
59
58
 
60
59
  if (sizeof(buf) - 2 <= len) {
61
- char *b = ALLOC_N(char, len + 2);
60
+ char *b = OJ_R_ALLOC_N(char, len + 2);
62
61
  ID id;
63
62
 
64
63
  if ('~' == *str) {
65
- memcpy(b, str + 1, len - 1);
66
- b[len - 1] = '\0';
67
- len -= 2;
68
- } else {
69
- *b = '@';
70
- memcpy(b + 1, str, len);
71
- b[len + 1] = '\0';
72
- }
64
+ memcpy(b, str + 1, len - 1);
65
+ b[len - 1] = '\0';
66
+ len -= 2;
67
+ } else {
68
+ *b = '@';
69
+ memcpy(b + 1, str, len);
70
+ b[len + 1] = '\0';
71
+ }
73
72
  id = rb_intern3(buf, len + 1, oj_utf8_encoding);
74
- xfree(b);
73
+ OJ_R_FREE(b);
75
74
  return id;
76
75
  }
77
76
  if ('~' == *str) {
78
- memcpy(buf, str + 1, len - 1);
79
- buf[len - 1] = '\0';
80
- len -= 2;
77
+ memcpy(buf, str + 1, len - 1);
78
+ buf[len - 1] = '\0';
79
+ len -= 2;
81
80
  } else {
82
- *buf = '@';
83
- memcpy(buf + 1, str, len);
84
- buf[len + 1] = '\0';
81
+ *buf = '@';
82
+ memcpy(buf + 1, str, len);
83
+ buf[len + 1] = '\0';
85
84
  }
86
85
  return (VALUE)rb_intern3(buf, len + 1, oj_utf8_encoding);
87
86
  }
88
87
 
89
- void oj_hash_init() {
88
+ void oj_hash_init(void) {
90
89
  VALUE cache_class = rb_define_class_under(Oj, "Cache", rb_cObject);
90
+ rb_undef_alloc_func(cache_class);
91
91
 
92
- str_cache = cache_create(0, form_str, true, true);
93
- str_cache_obj = Data_Wrap_Struct(cache_class, cache_mark, cache_free, str_cache);
92
+ struct _cache *str_cache = cache_create(0, form_str, true, true);
93
+ str_cache_obj = Data_Wrap_Struct(cache_class, cache_mark, cache_free, str_cache);
94
94
  rb_gc_register_address(&str_cache_obj);
95
95
 
96
- sym_cache = cache_create(0, form_sym, true, true);
97
- sym_cache_obj = Data_Wrap_Struct(cache_class, cache_mark, cache_free, sym_cache);
96
+ struct _cache *sym_cache = cache_create(0, form_sym, true, true);
97
+ sym_cache_obj = Data_Wrap_Struct(cache_class, cache_mark, cache_free, sym_cache);
98
98
  rb_gc_register_address(&sym_cache_obj);
99
99
 
100
- attr_cache = cache_create(0, form_attr, false, true);
101
- attr_cache_obj = Data_Wrap_Struct(cache_class, cache_mark, cache_free, attr_cache);
100
+ struct _cache *attr_cache = cache_create(0, form_attr, false, true);
101
+ attr_cache_obj = Data_Wrap_Struct(cache_class, cache_mark, cache_free, attr_cache);
102
102
  rb_gc_register_address(&attr_cache_obj);
103
103
 
104
104
  memset(class_hash.slots, 0, sizeof(class_hash.slots));
@@ -118,18 +118,17 @@ oj_str_intern(const char *key, size_t len) {
118
118
  #if HAVE_RB_ENC_INTERNED_STR && 0
119
119
  return rb_enc_interned_str(key, len, rb_utf8_encoding());
120
120
  #else
121
- return cache_intern(str_cache, key, len);
121
+ return cache_intern(DATA_PTR(str_cache_obj), key, len);
122
122
  #endif
123
123
  }
124
124
 
125
125
  VALUE
126
126
  oj_sym_intern(const char *key, size_t len) {
127
- return cache_intern(sym_cache, key, len);
127
+ return cache_intern(DATA_PTR(sym_cache_obj), key, len);
128
128
  }
129
129
 
130
- ID
131
- oj_attr_intern(const char *key, size_t len) {
132
- return cache_intern(attr_cache, key, len);
130
+ ID oj_attr_intern(const char *key, size_t len) {
131
+ return cache_intern(DATA_PTR(attr_cache_obj), key, len);
133
132
  }
134
133
 
135
134
  static uint64_t hash_calc(const uint8_t *key, size_t len) {
@@ -183,10 +182,10 @@ static VALUE resolve_classname(VALUE mod, const char *classname, int auto_define
183
182
  static VALUE resolve_classpath(ParseInfo pi, const char *name, size_t len, int auto_define, VALUE error_class) {
184
183
  char class_name[1024];
185
184
  VALUE clas;
186
- char * end = class_name + sizeof(class_name) - 1;
187
- char * s;
188
- const char *n = name;
189
- size_t nlen = len;
185
+ char *end = class_name + sizeof(class_name) - 1;
186
+ char *s;
187
+ const char *n = name;
188
+ size_t nlen = len;
190
189
 
191
190
  clas = rb_cObject;
192
191
  for (s = class_name; 0 < len; n++, len--) {
@@ -209,11 +208,11 @@ static VALUE resolve_classpath(ParseInfo pi, const char *name, size_t len, int a
209
208
  }
210
209
  *s = '\0';
211
210
  if (Qundef == (clas = resolve_classname(clas, class_name, auto_define))) {
212
- if (sizeof(class_name) <= nlen) {
213
- nlen = sizeof(class_name) - 1;
214
- }
215
- strncpy(class_name, name, nlen);
216
- class_name[nlen] = '\0';
211
+ if (sizeof(class_name) <= nlen) {
212
+ nlen = sizeof(class_name) - 1;
213
+ }
214
+ strncpy(class_name, name, nlen);
215
+ class_name[nlen] = '\0';
217
216
  oj_set_error_at(pi, error_class, __FILE__, __LINE__, "class '%s' is not defined", class_name);
218
217
  if (Qnil != error_class) {
219
218
  pi->err_class = error_class;
@@ -245,7 +244,7 @@ VALUE oj_class_intern(const char *key, size_t len, bool safe, ParseInfo pi, int
245
244
  }
246
245
  bucket = b;
247
246
  }
248
- b = ALLOC(struct _keyVal);
247
+ b = OJ_R_ALLOC(struct _keyVal);
249
248
  b->next = NULL;
250
249
  bucket->next = b;
251
250
  bucket = b;
@@ -266,7 +265,7 @@ VALUE oj_class_intern(const char *key, size_t len, bool safe, ParseInfo pi, int
266
265
  }
267
266
  bucket = b;
268
267
  }
269
- b = ALLOC(struct _keyVal);
268
+ b = OJ_R_ALLOC(struct _keyVal);
270
269
  b->next = NULL;
271
270
  bucket->next = b;
272
271
  bucket = b;
@@ -275,11 +274,12 @@ VALUE oj_class_intern(const char *key, size_t len, bool safe, ParseInfo pi, int
275
274
  bucket->len = len;
276
275
  bucket->val = resolve_classpath(pi, key, len, auto_define, error_class);
277
276
  }
277
+ rb_gc_register_mark_object(bucket->val);
278
278
  return bucket->val;
279
279
  }
280
280
 
281
281
  char *oj_strndup(const char *s, size_t len) {
282
- char *d = ALLOC_N(char, len + 1);
282
+ char *d = OJ_R_ALLOC_N(char, len + 1);
283
283
 
284
284
  memcpy(d, s, len);
285
285
  d[len] = '\0';
@@ -287,8 +287,10 @@ char *oj_strndup(const char *s, size_t len) {
287
287
  return d;
288
288
  }
289
289
 
290
- void intern_cleanup() {
290
+ /*
291
+ void intern_cleanup(void) {
291
292
  cache_free(str_cache);
292
293
  cache_free(sym_cache);
293
294
  cache_free(attr_cache);
294
295
  }
296
+ */
data/ext/oj/intern.h CHANGED
@@ -4,22 +4,18 @@
4
4
  #ifndef OJ_INTERN_H
5
5
  #define OJ_INTERN_H
6
6
 
7
- #include <stdbool.h>
8
7
  #include <ruby.h>
8
+ #include <stdbool.h>
9
9
 
10
10
  struct _parseInfo;
11
11
 
12
- extern void oj_hash_init();
12
+ extern void oj_hash_init(void);
13
13
 
14
14
  extern VALUE oj_str_intern(const char *key, size_t len);
15
15
  extern VALUE oj_sym_intern(const char *key, size_t len);
16
16
  extern ID oj_attr_intern(const char *key, size_t len);
17
- extern VALUE oj_class_intern(const char * key,
18
- size_t len,
19
- bool safe,
20
- struct _parseInfo *pi,
21
- int auto_define,
22
- VALUE error_class);
17
+ extern VALUE
18
+ oj_class_intern(const char *key, size_t len, bool safe, struct _parseInfo *pi, int auto_define, VALUE error_class);
23
19
 
24
20
  extern char *oj_strndup(const char *s, size_t len);
25
21