oj 3.13.17 → 3.16.3

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Files changed (156) hide show
  1. checksums.yaml +4 -4
  2. data/CHANGELOG.md +77 -0
  3. data/README.md +4 -2
  4. data/ext/oj/buf.h +7 -6
  5. data/ext/oj/cache.c +29 -26
  6. data/ext/oj/cache.h +3 -2
  7. data/ext/oj/cache8.c +10 -9
  8. data/ext/oj/circarray.c +7 -5
  9. data/ext/oj/circarray.h +2 -2
  10. data/ext/oj/code.c +5 -12
  11. data/ext/oj/code.h +2 -2
  12. data/ext/oj/compat.c +20 -60
  13. data/ext/oj/custom.c +44 -96
  14. data/ext/oj/debug.c +3 -9
  15. data/ext/oj/dump.c +69 -39
  16. data/ext/oj/dump.h +1 -4
  17. data/ext/oj/dump_compat.c +557 -592
  18. data/ext/oj/dump_leaf.c +3 -5
  19. data/ext/oj/dump_object.c +42 -48
  20. data/ext/oj/dump_strict.c +10 -22
  21. data/ext/oj/encoder.c +1 -1
  22. data/ext/oj/err.c +2 -13
  23. data/ext/oj/err.h +9 -12
  24. data/ext/oj/extconf.rb +16 -6
  25. data/ext/oj/fast.c +76 -106
  26. data/ext/oj/intern.c +63 -51
  27. data/ext/oj/intern.h +3 -7
  28. data/ext/oj/mem.c +318 -0
  29. data/ext/oj/mem.h +53 -0
  30. data/ext/oj/mimic_json.c +43 -30
  31. data/ext/oj/object.c +61 -70
  32. data/ext/oj/odd.c +8 -6
  33. data/ext/oj/odd.h +4 -4
  34. data/ext/oj/oj.c +243 -205
  35. data/ext/oj/oj.h +82 -78
  36. data/ext/oj/parse.c +123 -188
  37. data/ext/oj/parse.h +23 -24
  38. data/ext/oj/parser.c +103 -63
  39. data/ext/oj/parser.h +19 -9
  40. data/ext/oj/rails.c +68 -92
  41. data/ext/oj/reader.c +10 -15
  42. data/ext/oj/reader.h +4 -2
  43. data/ext/oj/resolve.c +3 -4
  44. data/ext/oj/rxclass.c +6 -5
  45. data/ext/oj/rxclass.h +1 -1
  46. data/ext/oj/saj.c +10 -9
  47. data/ext/oj/saj2.c +74 -92
  48. data/ext/oj/saj2.h +23 -0
  49. data/ext/oj/scp.c +3 -14
  50. data/ext/oj/sparse.c +22 -70
  51. data/ext/oj/stream_writer.c +43 -35
  52. data/ext/oj/strict.c +20 -52
  53. data/ext/oj/string_writer.c +60 -34
  54. data/ext/oj/trace.h +31 -4
  55. data/ext/oj/usual.c +125 -150
  56. data/ext/oj/usual.h +69 -0
  57. data/ext/oj/util.h +1 -1
  58. data/ext/oj/val_stack.c +14 -3
  59. data/ext/oj/val_stack.h +8 -7
  60. data/ext/oj/wab.c +25 -57
  61. data/lib/oj/active_support_helper.rb +1 -3
  62. data/lib/oj/bag.rb +7 -1
  63. data/lib/oj/easy_hash.rb +4 -5
  64. data/lib/oj/error.rb +0 -1
  65. data/lib/oj/json.rb +162 -150
  66. data/lib/oj/mimic.rb +6 -2
  67. data/lib/oj/state.rb +9 -6
  68. data/lib/oj/version.rb +1 -2
  69. data/lib/oj.rb +2 -0
  70. data/pages/Compatibility.md +1 -1
  71. data/pages/InstallOptions.md +20 -0
  72. data/pages/Options.md +10 -0
  73. data/test/_test_active.rb +8 -9
  74. data/test/_test_active_mimic.rb +7 -8
  75. data/test/_test_mimic_rails.rb +17 -20
  76. data/test/activerecord/result_test.rb +5 -6
  77. data/test/files.rb +15 -15
  78. data/test/foo.rb +9 -72
  79. data/test/helper.rb +11 -8
  80. data/test/isolated/shared.rb +3 -2
  81. data/test/json_gem/json_addition_test.rb +2 -2
  82. data/test/json_gem/json_common_interface_test.rb +8 -6
  83. data/test/json_gem/json_encoding_test.rb +0 -0
  84. data/test/json_gem/json_ext_parser_test.rb +1 -0
  85. data/test/json_gem/json_fixtures_test.rb +3 -2
  86. data/test/json_gem/json_generator_test.rb +53 -37
  87. data/test/json_gem/json_generic_object_test.rb +11 -11
  88. data/test/json_gem/json_parser_test.rb +47 -47
  89. data/test/json_gem/json_string_matching_test.rb +9 -9
  90. data/test/json_gem/test_helper.rb +7 -3
  91. data/test/mem.rb +13 -12
  92. data/test/perf.rb +21 -26
  93. data/test/perf_compat.rb +31 -33
  94. data/test/perf_dump.rb +28 -28
  95. data/test/perf_fast.rb +80 -82
  96. data/test/perf_file.rb +27 -29
  97. data/test/perf_object.rb +65 -69
  98. data/test/perf_once.rb +12 -11
  99. data/test/perf_parser.rb +42 -48
  100. data/test/perf_saj.rb +46 -54
  101. data/test/perf_scp.rb +57 -69
  102. data/test/perf_simple.rb +41 -39
  103. data/test/perf_strict.rb +68 -70
  104. data/test/perf_wab.rb +67 -69
  105. data/test/prec.rb +5 -5
  106. data/test/sample/change.rb +0 -1
  107. data/test/sample/dir.rb +0 -1
  108. data/test/sample/doc.rb +0 -1
  109. data/test/sample/file.rb +0 -1
  110. data/test/sample/group.rb +0 -1
  111. data/test/sample/hasprops.rb +0 -1
  112. data/test/sample/layer.rb +0 -1
  113. data/test/sample/rect.rb +0 -1
  114. data/test/sample/shape.rb +0 -1
  115. data/test/sample/text.rb +0 -1
  116. data/test/sample.rb +16 -16
  117. data/test/sample_json.rb +8 -8
  118. data/test/test_compat.rb +80 -53
  119. data/test/test_custom.rb +73 -51
  120. data/test/test_debian.rb +7 -10
  121. data/test/test_fast.rb +86 -90
  122. data/test/test_file.rb +28 -35
  123. data/test/test_gc.rb +16 -5
  124. data/test/test_generate.rb +5 -5
  125. data/test/test_hash.rb +4 -4
  126. data/test/test_integer_range.rb +9 -9
  127. data/test/test_null.rb +20 -20
  128. data/test/test_object.rb +94 -96
  129. data/test/test_parser.rb +6 -22
  130. data/test/test_parser_debug.rb +27 -0
  131. data/test/test_parser_saj.rb +61 -22
  132. data/test/test_parser_usual.rb +16 -6
  133. data/test/test_rails.rb +2 -2
  134. data/test/test_saj.rb +10 -8
  135. data/test/test_scp.rb +37 -39
  136. data/test/test_strict.rb +40 -32
  137. data/test/test_various.rb +148 -100
  138. data/test/test_wab.rb +48 -44
  139. data/test/test_writer.rb +47 -47
  140. data/test/tests.rb +13 -4
  141. data/test/tests_mimic.rb +12 -3
  142. data/test/tests_mimic_addition.rb +12 -3
  143. metadata +36 -27
  144. data/test/activesupport4/decoding_test.rb +0 -108
  145. data/test/activesupport4/encoding_test.rb +0 -531
  146. data/test/activesupport4/test_helper.rb +0 -41
  147. data/test/activesupport5/abstract_unit.rb +0 -45
  148. data/test/activesupport5/decoding_test.rb +0 -133
  149. data/test/activesupport5/encoding_test.rb +0 -500
  150. data/test/activesupport5/encoding_test_cases.rb +0 -98
  151. data/test/activesupport5/test_helper.rb +0 -72
  152. data/test/activesupport5/time_zone_test_helpers.rb +0 -39
  153. data/test/bar.rb +0 -11
  154. data/test/baz.rb +0 -16
  155. data/test/bug.rb +0 -16
  156. data/test/zoo.rb +0 -13
data/ext/oj/fast.c CHANGED
@@ -11,14 +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
- #include "dump.h"
17
18
 
18
19
  // maximum to allocate on the stack, arbitrary limit
19
20
  #define SMALL_JSON 65536
20
21
  #define MAX_STACK 100
21
- //#define BATCH_SIZE (4096 / sizeof(struct _leaf) - 1)
22
+ // #define BATCH_SIZE (4096 / sizeof(struct _leaf) - 1)
22
23
  #define BATCH_SIZE 100
23
24
 
24
25
  // Support for compaction
@@ -32,25 +33,25 @@ typedef struct _batch {
32
33
  struct _batch *next;
33
34
  int next_avail;
34
35
  struct _leaf leaves[BATCH_SIZE];
35
- } * Batch;
36
+ } *Batch;
36
37
 
37
38
  typedef struct _doc {
38
39
  Leaf data;
39
- Leaf * where; // points to current location
40
+ Leaf *where; // points to current location
40
41
  Leaf where_path[MAX_STACK]; // points to head of path
41
- char * json;
42
- unsigned long size; // number of leaves/branches in the doc
42
+ char *json;
43
+ unsigned long size; // number of leaves/branches in the doc
43
44
  VALUE self;
44
45
  Batch batches;
45
46
  struct _batch batch0;
46
- } * Doc;
47
+ } *Doc;
47
48
 
48
49
  typedef struct _parseInfo {
49
50
  char *str; // buffer being read from
50
51
  char *s; // current position in buffer
51
52
  Doc doc;
52
53
  void *stack_min;
53
- } * ParseInfo;
54
+ } *ParseInfo;
54
55
 
55
56
  static void leaf_init(Leaf leaf, int type);
56
57
  static Leaf leaf_new(Doc doc, int type);
@@ -74,7 +75,7 @@ static char *read_quoted_value(ParseInfo pi);
74
75
  static void skip_comment(ParseInfo pi);
75
76
 
76
77
  static VALUE protect_open_proc(VALUE x);
77
- static VALUE parse_json(VALUE clas, char *json, bool given, bool allocated);
78
+ static VALUE parse_json(VALUE clas, char *json, bool given);
78
79
  static void each_leaf(Doc doc, VALUE self);
79
80
  static int move_step(Doc doc, const char *path, int loc);
80
81
  static Leaf get_doc_leaf(Doc doc, const char *path);
@@ -113,10 +114,7 @@ inline static char *ulong_fill(char *s, size_t num) {
113
114
  char *b = buf + sizeof(buf) - 1;
114
115
 
115
116
  *b-- = '\0';
116
- for (; 0 < num; num /= 10, b--) {
117
- *b = (num % 10) + '0';
118
- }
119
- b++;
117
+ b = oj_longlong_to_string((long long)num, false, b);
120
118
  if ('\0' == *b) {
121
119
  b--;
122
120
  *b = '0';
@@ -160,7 +158,7 @@ inline static Leaf leaf_new(Doc doc, int type) {
160
158
  Leaf leaf;
161
159
 
162
160
  if (0 == doc->batches || BATCH_SIZE == doc->batches->next_avail) {
163
- Batch b = ALLOC(struct _batch);
161
+ Batch b = OJ_R_ALLOC(struct _batch);
164
162
 
165
163
  // Initializes all leaves with a NO_VAL value_type
166
164
  memset(b, 0, sizeof(struct _batch));
@@ -250,7 +248,7 @@ static void skip_comment(ParseInfo pi) {
250
248
  #endif
251
249
 
252
250
  static void leaf_fixnum_value(Leaf leaf) {
253
- char * s = leaf->str;
251
+ char *s = leaf->str;
254
252
  int64_t n = 0;
255
253
  int neg = 0;
256
254
  int big = 0;
@@ -356,7 +354,7 @@ static Leaf read_next(ParseInfo pi) {
356
354
 
357
355
  static Leaf read_obj(ParseInfo pi) {
358
356
  Leaf h = leaf_new(pi->doc, T_HASH);
359
- char * end;
357
+ char *end;
360
358
  const char *key = 0;
361
359
  Leaf val = 0;
362
360
 
@@ -575,7 +573,7 @@ static char *read_quoted_value(ParseInfo pi) {
575
573
  char *h = pi->s; // head
576
574
  char *t = h; // tail
577
575
 
578
- h++; // skip quote character
576
+ h++; // skip quote character
579
577
  t++;
580
578
  value = h;
581
579
  for (; '"' != *h; h++, t++) {
@@ -648,10 +646,11 @@ static void doc_free(Doc doc) {
648
646
  while (0 != (b = doc->batches)) {
649
647
  doc->batches = doc->batches->next;
650
648
  if (&doc->batch0 != b) {
651
- xfree(b);
649
+ OJ_R_FREE(b);
652
650
  }
653
651
  }
654
- // xfree(f);
652
+ OJ_R_FREE(doc->json);
653
+ OJ_R_FREE(doc);
655
654
  }
656
655
  }
657
656
 
@@ -671,27 +670,28 @@ static void free_doc_cb(void *x) {
671
670
  Doc doc = (Doc)x;
672
671
 
673
672
  if (0 != doc) {
674
- xfree(doc->json);
675
673
  doc_free(doc);
676
674
  }
677
675
  }
678
676
 
679
677
  static void mark_leaf(Leaf leaf) {
680
- switch (leaf->value_type) {
681
- case COL_VAL:
682
- if (NULL != leaf->elements) {
683
- Leaf first = leaf->elements->next;
684
- 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;
685
684
 
686
- do {
687
- mark_leaf(e);
688
- e = e->next;
689
- } while (e != first);
690
- }
691
- break;
692
- 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;
693
692
 
694
- default: break;
693
+ default: break;
694
+ }
695
695
  }
696
696
  }
697
697
 
@@ -747,20 +747,15 @@ static const rb_data_type_t oj_doc_type = {
747
747
  0,
748
748
  };
749
749
 
750
- static VALUE parse_json(VALUE clas, char *json, bool given, bool allocated) {
750
+ static VALUE parse_json(VALUE clas, char *json, bool given) {
751
751
  struct _parseInfo pi;
752
752
  volatile VALUE result = Qnil;
753
753
  Doc doc;
754
754
  int ex = 0;
755
755
  volatile VALUE self;
756
756
 
757
- // TBD are both needed? is stack allocation ever needed?
757
+ doc = OJ_R_ALLOC_N(struct _doc, 1);
758
758
 
759
- if (given) {
760
- doc = ALLOCA_N(struct _doc, 1);
761
- } else {
762
- doc = ALLOC(struct _doc);
763
- }
764
759
  // skip UTF-8 BOM if present
765
760
  if (0xEF == (uint8_t)*json && 0xBB == (uint8_t)json[1] && 0xBF == (uint8_t)json[2]) {
766
761
  pi.str = json + 3;
@@ -785,18 +780,19 @@ static VALUE parse_json(VALUE clas, char *json, bool given, bool allocated) {
785
780
  }
786
781
  }
787
782
  #endif
788
- self = TypedData_Wrap_Struct(clas, &oj_doc_type, doc);
789
- doc->self = self;
790
- doc->json = json;
791
- DATA_PTR(doc->self) = doc;
792
- result = rb_protect(protect_open_proc, (VALUE)&pi, &ex);
783
+ doc->json = json;
784
+ self = TypedData_Wrap_Struct(clas, &oj_doc_type, doc);
785
+ doc->self = self;
786
+ result = rb_protect(protect_open_proc, (VALUE)&pi, &ex);
793
787
  if (given || 0 != ex) {
794
788
  DATA_PTR(doc->self) = NULL;
789
+ // TBD is this needed?
790
+ /*
795
791
  doc_free(pi.doc);
796
- if (allocated && 0 != ex) { // will jump so caller will not free
797
- xfree(json);
792
+ if (0 != ex) { // will jump so caller will not free
793
+ OJ_R_FREE(json);
798
794
  }
799
- rb_gc_enable();
795
+ */
800
796
  } else {
801
797
  result = doc->self;
802
798
  }
@@ -1086,31 +1082,23 @@ static void each_value(Doc doc, Leaf leaf) {
1086
1082
  * doc.close()
1087
1083
  */
1088
1084
  static VALUE doc_open(VALUE clas, VALUE str) {
1089
- char * json;
1085
+ char *json;
1090
1086
  size_t len;
1091
1087
  volatile VALUE obj;
1092
1088
  int given = rb_block_given_p();
1093
- int allocate;
1094
1089
 
1095
1090
  Check_Type(str, T_STRING);
1096
- len = (int)RSTRING_LEN(str) + 1;
1097
- allocate = (SMALL_JSON < len || !given);
1098
- if (allocate) {
1099
- json = ALLOC_N(char, len);
1100
- } else {
1101
- json = ALLOCA_N(char, len);
1102
- }
1103
- // It should not be necessaary to stop GC but if it is not stopped and a
1104
- // large string is parsed that string is corrupted or freed during
1105
- // parsing. I'm not sure what is going on exactly but disabling GC avoids
1106
- // the issue.
1107
- rb_gc_disable();
1091
+ len = (int)RSTRING_LEN(str) + 1;
1092
+ json = OJ_R_ALLOC_N(char, len);
1093
+
1108
1094
  memcpy(json, StringValuePtr(str), len);
1109
- obj = parse_json(clas, json, given, allocate);
1110
- rb_gc_enable();
1111
- if (given && allocate) {
1112
- xfree(json);
1095
+ obj = parse_json(clas, json, given);
1096
+ // TBD is this needed
1097
+ /*
1098
+ if (given) {
1099
+ OJ_R_FREE(json);
1113
1100
  }
1101
+ */
1114
1102
  return obj;
1115
1103
  }
1116
1104
 
@@ -1134,27 +1122,21 @@ static VALUE doc_open(VALUE clas, VALUE str) {
1134
1122
  * doc.close()
1135
1123
  */
1136
1124
  static VALUE doc_open_file(VALUE clas, VALUE filename) {
1137
- char * path;
1138
- char * json;
1139
- FILE * f;
1125
+ char *path;
1126
+ char *json;
1127
+ FILE *f;
1140
1128
  size_t len;
1141
1129
  volatile VALUE obj;
1142
1130
  int given = rb_block_given_p();
1143
- int allocate;
1144
1131
 
1145
- Check_Type(filename, T_STRING);
1146
1132
  path = StringValuePtr(filename);
1147
1133
  if (0 == (f = fopen(path, "r"))) {
1148
1134
  rb_raise(rb_eIOError, "%s", strerror(errno));
1149
1135
  }
1150
1136
  fseek(f, 0, SEEK_END);
1151
- len = ftell(f);
1152
- allocate = (SMALL_JSON < len || !given);
1153
- if (allocate) {
1154
- json = ALLOC_N(char, len + 1);
1155
- } else {
1156
- json = ALLOCA_N(char, len + 1);
1157
- }
1137
+ len = ftell(f);
1138
+ json = OJ_R_ALLOC_N(char, len + 1);
1139
+
1158
1140
  fseek(f, 0, SEEK_SET);
1159
1141
  if (len != fread(json, 1, len, f)) {
1160
1142
  fclose(f);
@@ -1165,12 +1147,13 @@ static VALUE doc_open_file(VALUE clas, VALUE filename) {
1165
1147
  }
1166
1148
  fclose(f);
1167
1149
  json[len] = '\0';
1168
- rb_gc_disable();
1169
- obj = parse_json(clas, json, given, allocate);
1170
- rb_gc_enable();
1171
- if (given && allocate) {
1172
- xfree(json);
1150
+ obj = parse_json(clas, json, given);
1151
+ // TBD is this needed
1152
+ /*
1153
+ if (given) {
1154
+ OJ_R_FREE(json);
1173
1155
  }
1156
+ */
1174
1157
  return obj;
1175
1158
  }
1176
1159
 
@@ -1210,11 +1193,11 @@ static VALUE doc_where(VALUE self) {
1210
1193
  if (0 == *doc->where_path || doc->where == doc->where_path) {
1211
1194
  return oj_slash_string;
1212
1195
  } else {
1213
- Leaf * lp;
1196
+ Leaf *lp;
1214
1197
  Leaf leaf;
1215
1198
  size_t size = 3; // leading / and terminating \0
1216
- char * path;
1217
- char * p;
1199
+ char *path;
1200
+ char *p;
1218
1201
 
1219
1202
  for (lp = doc->where_path; lp <= doc->where; lp++) {
1220
1203
  leaf = *lp;
@@ -1317,7 +1300,6 @@ static VALUE doc_type(int argc, VALUE *argv, VALUE self) {
1317
1300
  VALUE type = Qnil;
1318
1301
 
1319
1302
  if (1 <= argc) {
1320
- Check_Type(*argv, T_STRING);
1321
1303
  path = StringValuePtr(*argv);
1322
1304
  }
1323
1305
  if (0 != (leaf = get_doc_leaf(doc, path))) {
@@ -1326,11 +1308,7 @@ static VALUE doc_type(int argc, VALUE *argv, VALUE self) {
1326
1308
  case T_TRUE: type = rb_cTrueClass; break;
1327
1309
  case T_FALSE: type = rb_cFalseClass; break;
1328
1310
  case T_STRING: type = rb_cString; break;
1329
- #ifdef RUBY_INTEGER_UNIFICATION
1330
1311
  case T_FIXNUM: type = rb_cInteger; break;
1331
- #else
1332
- case T_FIXNUM: type = rb_cFixnum; break;
1333
- #endif
1334
1312
  case T_FLOAT: type = rb_cFloat; break;
1335
1313
  case T_ARRAY: type = rb_cArray; break;
1336
1314
  case T_HASH: type = rb_cHash; break;
@@ -1357,11 +1335,10 @@ static VALUE doc_fetch(int argc, VALUE *argv, VALUE self) {
1357
1335
  Doc doc;
1358
1336
  Leaf leaf;
1359
1337
  volatile VALUE val = Qnil;
1360
- const char * path = 0;
1338
+ const char *path = 0;
1361
1339
 
1362
1340
  doc = self_doc(self);
1363
1341
  if (1 <= argc) {
1364
- Check_Type(*argv, T_STRING);
1365
1342
  path = StringValuePtr(*argv);
1366
1343
  if (2 == argc) {
1367
1344
  val = argv[1];
@@ -1386,7 +1363,6 @@ static VALUE doc_exists(VALUE self, VALUE str) {
1386
1363
  Leaf leaf;
1387
1364
 
1388
1365
  doc = self_doc(self);
1389
- Check_Type(str, T_STRING);
1390
1366
  if (0 != (leaf = get_doc_leaf(doc, StringValuePtr(str)))) {
1391
1367
  if (NULL != leaf) {
1392
1368
  return Qtrue;
@@ -1423,7 +1399,6 @@ static VALUE doc_each_leaf(int argc, VALUE *argv, VALUE self) {
1423
1399
  memcpy(save_path, doc->where_path, sizeof(Leaf) * (wlen + 1));
1424
1400
  }
1425
1401
  if (1 <= argc) {
1426
- Check_Type(*argv, T_STRING);
1427
1402
  path = StringValuePtr(*argv);
1428
1403
  if ('/' == *path) {
1429
1404
  doc->where = doc->where_path;
@@ -1458,7 +1433,6 @@ static VALUE doc_move(VALUE self, VALUE str) {
1458
1433
  const char *path;
1459
1434
  int loc;
1460
1435
 
1461
- Check_Type(str, T_STRING);
1462
1436
  path = StringValuePtr(str);
1463
1437
  if ('/' == *path) {
1464
1438
  doc->where = doc->where_path;
@@ -1493,14 +1467,13 @@ static VALUE doc_each_child(int argc, VALUE *argv, VALUE self) {
1493
1467
  Doc doc = self_doc(self);
1494
1468
  const char *path = 0;
1495
1469
  size_t wlen;
1496
- Leaf * where_orig = doc->where;
1470
+ Leaf *where_orig = doc->where;
1497
1471
 
1498
1472
  wlen = doc->where - doc->where_path;
1499
1473
  if (0 < wlen) {
1500
1474
  memcpy(save_path, doc->where_path, sizeof(Leaf) * (wlen + 1));
1501
1475
  }
1502
1476
  if (1 <= argc) {
1503
- Check_Type(*argv, T_STRING);
1504
1477
  path = StringValuePtr(*argv);
1505
1478
  if ('/' == *path) {
1506
1479
  doc->where = doc->where_path;
@@ -1567,7 +1540,6 @@ static VALUE doc_each_value(int argc, VALUE *argv, VALUE self) {
1567
1540
  Leaf leaf;
1568
1541
 
1569
1542
  if (1 <= argc) {
1570
- Check_Type(*argv, T_STRING);
1571
1543
  path = StringValuePtr(*argv);
1572
1544
  }
1573
1545
  if (0 != (leaf = get_doc_leaf(doc, path))) {
@@ -1599,11 +1571,9 @@ static VALUE doc_dump(int argc, VALUE *argv, VALUE self) {
1599
1571
 
1600
1572
  if (1 <= argc) {
1601
1573
  if (Qnil != *argv) {
1602
- Check_Type(*argv, T_STRING);
1603
1574
  path = StringValuePtr(*argv);
1604
1575
  }
1605
1576
  if (2 <= argc) {
1606
- Check_Type(argv[1], T_STRING);
1607
1577
  filename = StringValuePtr(argv[1]);
1608
1578
  }
1609
1579
  }
@@ -1615,7 +1585,7 @@ static VALUE doc_dump(int argc, VALUE *argv, VALUE self) {
1615
1585
 
1616
1586
  oj_out_init(&out);
1617
1587
 
1618
- out.omit_nil = oj_default_options.dump_opts.omit_nil;
1588
+ out.omit_nil = oj_default_options.dump_opts.omit_nil;
1619
1589
  oj_dump_leaf_to_json(leaf, &oj_default_options, &out);
1620
1590
  rjson = rb_str_new2(out.buf);
1621
1591
 
@@ -1638,7 +1608,9 @@ static VALUE doc_dump(int argc, VALUE *argv, VALUE self) {
1638
1608
  * Oj::Doc.open('[1,2,3]') { |doc| doc.size() } #=> 4
1639
1609
  */
1640
1610
  static VALUE doc_size(VALUE self) {
1641
- return ULONG2NUM(((Doc)DATA_PTR(self))->size);
1611
+ Doc d;
1612
+ TypedData_Get_Struct(self, struct _doc, &oj_doc_type, d);
1613
+ return ULONG2NUM(d->size);
1642
1614
  }
1643
1615
 
1644
1616
  /* @overload close() => nil
@@ -1654,11 +1626,9 @@ static VALUE doc_close(VALUE self) {
1654
1626
  Doc doc = self_doc(self);
1655
1627
 
1656
1628
  rb_gc_unregister_address(&doc->self);
1657
- DATA_PTR(doc->self) = 0;
1629
+ DATA_PTR(doc->self) = NULL;
1658
1630
  if (0 != doc) {
1659
- xfree(doc->json);
1660
1631
  doc_free(doc);
1661
- xfree(doc);
1662
1632
  }
1663
1633
  return Qnil;
1664
1634
  }
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,51 +57,59 @@ 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
 
88
+ static const rb_data_type_t oj_cache_type = {
89
+ "Oj/cache",
90
+ {
91
+ cache_mark,
92
+ cache_free,
93
+ NULL,
94
+ },
95
+ 0,
96
+ 0,
97
+ };
98
+
89
99
  void oj_hash_init(void) {
90
100
  VALUE cache_class = rb_define_class_under(Oj, "Cache", rb_cObject);
91
101
  rb_undef_alloc_func(cache_class);
92
102
 
93
- rb_gc_register_address(&cache_class);
94
- rb_undef_alloc_func(cache_class);
95
-
96
- str_cache = cache_create(0, form_str, true, true);
97
- str_cache_obj = Data_Wrap_Struct(cache_class, cache_mark, cache_free, str_cache);
103
+ struct _cache *str_cache = cache_create(0, form_str, true, true);
104
+ str_cache_obj = TypedData_Wrap_Struct(cache_class, &oj_cache_type, str_cache);
98
105
  rb_gc_register_address(&str_cache_obj);
99
106
 
100
- sym_cache = cache_create(0, form_sym, true, true);
101
- sym_cache_obj = Data_Wrap_Struct(cache_class, cache_mark, cache_free, sym_cache);
107
+ struct _cache *sym_cache = cache_create(0, form_sym, true, true);
108
+ sym_cache_obj = TypedData_Wrap_Struct(cache_class, &oj_cache_type, sym_cache);
102
109
  rb_gc_register_address(&sym_cache_obj);
103
110
 
104
- attr_cache = cache_create(0, form_attr, false, true);
105
- attr_cache_obj = Data_Wrap_Struct(cache_class, cache_mark, cache_free, attr_cache);
111
+ struct _cache *attr_cache = cache_create(0, form_attr, false, true);
112
+ attr_cache_obj = TypedData_Wrap_Struct(cache_class, &oj_cache_type, attr_cache);
106
113
  rb_gc_register_address(&attr_cache_obj);
107
114
 
108
115
  memset(class_hash.slots, 0, sizeof(class_hash.slots));
@@ -122,18 +129,23 @@ oj_str_intern(const char *key, size_t len) {
122
129
  #if HAVE_RB_ENC_INTERNED_STR && 0
123
130
  return rb_enc_interned_str(key, len, rb_utf8_encoding());
124
131
  #else
125
- return cache_intern(str_cache, key, len);
132
+ Cache c;
133
+ TypedData_Get_Struct(str_cache_obj, struct _cache, &oj_cache_type, c);
134
+ return cache_intern(c, key, len);
126
135
  #endif
127
136
  }
128
137
 
129
138
  VALUE
130
139
  oj_sym_intern(const char *key, size_t len) {
131
- return cache_intern(sym_cache, key, len);
140
+ Cache c;
141
+ TypedData_Get_Struct(sym_cache_obj, struct _cache, &oj_cache_type, c);
142
+ return cache_intern(c, key, len);
132
143
  }
133
144
 
134
- ID
135
- oj_attr_intern(const char *key, size_t len) {
136
- return cache_intern(attr_cache, key, len);
145
+ ID oj_attr_intern(const char *key, size_t len) {
146
+ Cache c;
147
+ TypedData_Get_Struct(attr_cache_obj, struct _cache, &oj_cache_type, c);
148
+ return cache_intern(c, key, len);
137
149
  }
138
150
 
139
151
  static uint64_t hash_calc(const uint8_t *key, size_t len) {
@@ -187,10 +199,10 @@ static VALUE resolve_classname(VALUE mod, const char *classname, int auto_define
187
199
  static VALUE resolve_classpath(ParseInfo pi, const char *name, size_t len, int auto_define, VALUE error_class) {
188
200
  char class_name[1024];
189
201
  VALUE clas;
190
- char * end = class_name + sizeof(class_name) - 1;
191
- char * s;
192
- const char *n = name;
193
- size_t nlen = len;
202
+ char *end = class_name + sizeof(class_name) - 1;
203
+ char *s;
204
+ const char *n = name;
205
+ size_t nlen = len;
194
206
 
195
207
  clas = rb_cObject;
196
208
  for (s = class_name; 0 < len; n++, len--) {
@@ -213,11 +225,11 @@ static VALUE resolve_classpath(ParseInfo pi, const char *name, size_t len, int a
213
225
  }
214
226
  *s = '\0';
215
227
  if (Qundef == (clas = resolve_classname(clas, class_name, auto_define))) {
216
- if (sizeof(class_name) <= nlen) {
217
- nlen = sizeof(class_name) - 1;
218
- }
219
- strncpy(class_name, name, nlen);
220
- class_name[nlen] = '\0';
228
+ if (sizeof(class_name) <= nlen) {
229
+ nlen = sizeof(class_name) - 1;
230
+ }
231
+ strncpy(class_name, name, nlen);
232
+ class_name[nlen] = '\0';
221
233
  oj_set_error_at(pi, error_class, __FILE__, __LINE__, "class '%s' is not defined", class_name);
222
234
  if (Qnil != error_class) {
223
235
  pi->err_class = error_class;
@@ -249,7 +261,7 @@ VALUE oj_class_intern(const char *key, size_t len, bool safe, ParseInfo pi, int
249
261
  }
250
262
  bucket = b;
251
263
  }
252
- b = ALLOC(struct _keyVal);
264
+ b = OJ_R_ALLOC(struct _keyVal);
253
265
  b->next = NULL;
254
266
  bucket->next = b;
255
267
  bucket = b;
@@ -270,7 +282,7 @@ VALUE oj_class_intern(const char *key, size_t len, bool safe, ParseInfo pi, int
270
282
  }
271
283
  bucket = b;
272
284
  }
273
- b = ALLOC(struct _keyVal);
285
+ b = OJ_R_ALLOC(struct _keyVal);
274
286
  b->next = NULL;
275
287
  bucket->next = b;
276
288
  bucket = b;
@@ -284,7 +296,7 @@ VALUE oj_class_intern(const char *key, size_t len, bool safe, ParseInfo pi, int
284
296
  }
285
297
 
286
298
  char *oj_strndup(const char *s, size_t len) {
287
- char *d = ALLOC_N(char, len + 1);
299
+ char *d = OJ_R_ALLOC_N(char, len + 1);
288
300
 
289
301
  memcpy(d, s, len);
290
302
  d[len] = '\0';
data/ext/oj/intern.h CHANGED
@@ -4,8 +4,8 @@
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
 
@@ -14,12 +14,8 @@ extern void oj_hash_init(void);
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