oj 3.13.23 → 3.16.9
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- checksums.yaml +4 -4
- data/CHANGELOG.md +81 -0
- data/README.md +2 -2
- data/ext/oj/buf.h +7 -6
- data/ext/oj/cache.c +29 -26
- data/ext/oj/cache.h +3 -2
- data/ext/oj/cache8.c +10 -9
- data/ext/oj/circarray.c +7 -5
- data/ext/oj/circarray.h +2 -2
- data/ext/oj/code.c +5 -12
- data/ext/oj/code.h +2 -2
- data/ext/oj/compat.c +20 -60
- data/ext/oj/custom.c +26 -59
- data/ext/oj/debug.c +3 -9
- data/ext/oj/dump.c +103 -53
- data/ext/oj/dump.h +1 -4
- data/ext/oj/dump_compat.c +557 -592
- data/ext/oj/dump_leaf.c +3 -5
- data/ext/oj/dump_object.c +42 -48
- data/ext/oj/dump_strict.c +10 -22
- data/ext/oj/encoder.c +1 -1
- data/ext/oj/err.c +2 -13
- data/ext/oj/err.h +9 -12
- data/ext/oj/extconf.rb +16 -7
- data/ext/oj/fast.c +60 -92
- data/ext/oj/intern.c +62 -47
- data/ext/oj/intern.h +3 -7
- data/ext/oj/mem.c +318 -0
- data/ext/oj/mem.h +53 -0
- data/ext/oj/mimic_json.c +51 -32
- data/ext/oj/object.c +33 -43
- data/ext/oj/odd.c +8 -6
- data/ext/oj/odd.h +4 -4
- data/ext/oj/oj.c +243 -212
- data/ext/oj/oj.h +83 -81
- data/ext/oj/parse.c +94 -148
- data/ext/oj/parse.h +21 -24
- data/ext/oj/parser.c +80 -67
- data/ext/oj/parser.h +7 -8
- data/ext/oj/rails.c +70 -92
- data/ext/oj/reader.c +9 -14
- data/ext/oj/reader.h +4 -2
- data/ext/oj/resolve.c +3 -4
- data/ext/oj/rxclass.c +6 -5
- data/ext/oj/rxclass.h +1 -1
- data/ext/oj/saj.c +10 -9
- data/ext/oj/saj2.c +37 -49
- data/ext/oj/saj2.h +1 -1
- data/ext/oj/scp.c +3 -14
- data/ext/oj/sparse.c +22 -70
- data/ext/oj/stream_writer.c +45 -41
- data/ext/oj/strict.c +20 -52
- data/ext/oj/string_writer.c +64 -38
- data/ext/oj/trace.h +31 -4
- data/ext/oj/usual.c +125 -114
- data/ext/oj/usual.h +7 -6
- data/ext/oj/util.h +1 -1
- data/ext/oj/val_stack.c +13 -2
- data/ext/oj/val_stack.h +8 -7
- data/ext/oj/wab.c +25 -57
- data/lib/oj/active_support_helper.rb +1 -3
- data/lib/oj/bag.rb +7 -1
- data/lib/oj/easy_hash.rb +4 -5
- data/lib/oj/error.rb +0 -1
- data/lib/oj/json.rb +162 -150
- data/lib/oj/mimic.rb +7 -7
- data/lib/oj/schandler.rb +5 -4
- data/lib/oj/state.rb +8 -5
- data/lib/oj/version.rb +1 -2
- data/lib/oj.rb +2 -0
- data/pages/InstallOptions.md +20 -0
- data/pages/Options.md +4 -0
- data/test/_test_active.rb +8 -9
- data/test/_test_active_mimic.rb +7 -8
- data/test/_test_mimic_rails.rb +17 -20
- data/test/activerecord/result_test.rb +5 -6
- data/test/activesupport6/encoding_test.rb +63 -28
- data/test/activesupport7/abstract_unit.rb +4 -1
- data/test/activesupport7/encoding_test.rb +72 -22
- data/test/files.rb +15 -15
- data/test/foo.rb +18 -69
- data/test/helper.rb +5 -8
- data/test/isolated/shared.rb +3 -2
- data/test/json_gem/json_addition_test.rb +2 -2
- data/test/json_gem/json_common_interface_test.rb +8 -6
- data/test/json_gem/json_encoding_test.rb +0 -0
- data/test/json_gem/json_ext_parser_test.rb +1 -0
- data/test/json_gem/json_fixtures_test.rb +3 -2
- data/test/json_gem/json_generator_test.rb +50 -33
- data/test/json_gem/json_generic_object_test.rb +11 -11
- data/test/json_gem/json_parser_test.rb +46 -46
- data/test/json_gem/json_string_matching_test.rb +9 -9
- data/test/mem.rb +13 -12
- data/test/perf.rb +21 -26
- data/test/perf_compat.rb +31 -33
- data/test/perf_dump.rb +28 -28
- data/test/perf_fast.rb +80 -82
- data/test/perf_file.rb +27 -29
- data/test/perf_object.rb +65 -69
- data/test/perf_once.rb +12 -11
- data/test/perf_parser.rb +42 -48
- data/test/perf_saj.rb +46 -54
- data/test/perf_scp.rb +57 -69
- data/test/perf_simple.rb +41 -39
- data/test/perf_strict.rb +68 -70
- data/test/perf_wab.rb +67 -69
- data/test/prec.rb +5 -5
- data/test/sample/change.rb +0 -1
- data/test/sample/dir.rb +0 -1
- data/test/sample/doc.rb +0 -1
- data/test/sample/file.rb +0 -1
- data/test/sample/group.rb +0 -1
- data/test/sample/hasprops.rb +0 -1
- data/test/sample/layer.rb +0 -1
- data/test/sample/rect.rb +0 -1
- data/test/sample/shape.rb +0 -1
- data/test/sample/text.rb +0 -1
- data/test/sample.rb +16 -16
- data/test/sample_json.rb +8 -8
- data/test/test_compat.rb +81 -54
- data/test/test_custom.rb +63 -52
- data/test/test_debian.rb +7 -10
- data/test/test_fast.rb +86 -90
- data/test/test_file.rb +24 -29
- data/test/test_gc.rb +5 -5
- data/test/test_generate.rb +5 -5
- data/test/test_hash.rb +4 -4
- data/test/test_integer_range.rb +9 -9
- data/test/test_null.rb +20 -20
- data/test/test_object.rb +92 -87
- data/test/test_parser.rb +4 -4
- data/test/test_parser_debug.rb +5 -5
- data/test/test_parser_saj.rb +27 -25
- data/test/test_parser_usual.rb +44 -6
- data/test/test_rails.rb +2 -2
- data/test/test_saj.rb +10 -8
- data/test/test_scp.rb +35 -35
- data/test/test_strict.rb +38 -32
- data/test/test_various.rb +146 -97
- data/test/test_wab.rb +46 -44
- data/test/test_writer.rb +63 -47
- data/test/tests.rb +7 -7
- data/test/tests_mimic.rb +6 -6
- data/test/tests_mimic_addition.rb +6 -6
- metadata +46 -26
- data/test/activesupport4/decoding_test.rb +0 -108
- data/test/activesupport4/encoding_test.rb +0 -531
- data/test/activesupport4/test_helper.rb +0 -41
- data/test/activesupport5/abstract_unit.rb +0 -45
- data/test/activesupport5/decoding_test.rb +0 -133
- data/test/activesupport5/encoding_test.rb +0 -500
- data/test/activesupport5/encoding_test_cases.rb +0 -98
- data/test/activesupport5/test_helper.rb +0 -72
- data/test/activesupport5/time_zone_test_helpers.rb +0 -39
- data/test/bar.rb +0 -11
- data/test/baz.rb +0 -16
- data/test/bug.rb +0 -16
- 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
|
-
|
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
|
-
} *
|
36
|
+
} *Batch;
|
36
37
|
|
37
38
|
typedef struct _doc {
|
38
39
|
Leaf data;
|
39
|
-
Leaf
|
40
|
+
Leaf *where; // points to current location
|
40
41
|
Leaf where_path[MAX_STACK]; // points to head of path
|
41
|
-
char
|
42
|
+
char *json;
|
42
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
|
-
} *
|
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
|
-
} *
|
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
|
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
|
-
|
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 =
|
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
|
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
|
357
|
+
char *end;
|
360
358
|
const char *key = 0;
|
361
359
|
Leaf val = 0;
|
362
360
|
|
@@ -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
|
-
|
649
|
+
OJ_R_FREE(b);
|
652
650
|
}
|
653
651
|
}
|
654
|
-
|
652
|
+
OJ_R_FREE(doc->json);
|
653
|
+
OJ_R_FREE(doc);
|
655
654
|
}
|
656
655
|
}
|
657
656
|
|
@@ -671,7 +670,6 @@ 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
|
}
|
@@ -749,20 +747,15 @@ static const rb_data_type_t oj_doc_type = {
|
|
749
747
|
0,
|
750
748
|
};
|
751
749
|
|
752
|
-
static VALUE parse_json(VALUE clas, char *json, bool given
|
750
|
+
static VALUE parse_json(VALUE clas, char *json, bool given) {
|
753
751
|
struct _parseInfo pi;
|
754
752
|
volatile VALUE result = Qnil;
|
755
753
|
Doc doc;
|
756
754
|
int ex = 0;
|
757
755
|
volatile VALUE self;
|
758
756
|
|
759
|
-
|
757
|
+
doc = OJ_R_ALLOC_N(struct _doc, 1);
|
760
758
|
|
761
|
-
if (given) {
|
762
|
-
doc = ALLOCA_N(struct _doc, 1);
|
763
|
-
} else {
|
764
|
-
doc = ALLOC(struct _doc);
|
765
|
-
}
|
766
759
|
// skip UTF-8 BOM if present
|
767
760
|
if (0xEF == (uint8_t)*json && 0xBB == (uint8_t)json[1] && 0xBF == (uint8_t)json[2]) {
|
768
761
|
pi.str = json + 3;
|
@@ -772,7 +765,7 @@ static VALUE parse_json(VALUE clas, char *json, bool given, bool allocated) {
|
|
772
765
|
pi.s = pi.str;
|
773
766
|
doc_init(doc);
|
774
767
|
pi.doc = doc;
|
775
|
-
#if IS_WINDOWS
|
768
|
+
#if IS_WINDOWS || !defined(HAVE_GETRLIMIT)
|
776
769
|
// assume a 1M stack and give half to ruby
|
777
770
|
pi.stack_min = (void *)((char *)&pi - (512L * 1024L));
|
778
771
|
#else
|
@@ -787,18 +780,19 @@ static VALUE parse_json(VALUE clas, char *json, bool given, bool allocated) {
|
|
787
780
|
}
|
788
781
|
}
|
789
782
|
#endif
|
790
|
-
|
791
|
-
|
792
|
-
doc->
|
793
|
-
|
794
|
-
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);
|
795
787
|
if (given || 0 != ex) {
|
796
788
|
DATA_PTR(doc->self) = NULL;
|
789
|
+
// TBD is this needed?
|
790
|
+
/*
|
797
791
|
doc_free(pi.doc);
|
798
|
-
if (
|
799
|
-
|
792
|
+
if (0 != ex) { // will jump so caller will not free
|
793
|
+
OJ_R_FREE(json);
|
800
794
|
}
|
801
|
-
|
795
|
+
*/
|
802
796
|
} else {
|
803
797
|
result = doc->self;
|
804
798
|
}
|
@@ -1088,31 +1082,23 @@ static void each_value(Doc doc, Leaf leaf) {
|
|
1088
1082
|
* doc.close()
|
1089
1083
|
*/
|
1090
1084
|
static VALUE doc_open(VALUE clas, VALUE str) {
|
1091
|
-
char
|
1085
|
+
char *json;
|
1092
1086
|
size_t len;
|
1093
1087
|
volatile VALUE obj;
|
1094
1088
|
int given = rb_block_given_p();
|
1095
|
-
int allocate;
|
1096
1089
|
|
1097
1090
|
Check_Type(str, T_STRING);
|
1098
|
-
len
|
1099
|
-
|
1100
|
-
|
1101
|
-
json = ALLOC_N(char, len);
|
1102
|
-
} else {
|
1103
|
-
json = ALLOCA_N(char, len);
|
1104
|
-
}
|
1105
|
-
// It should not be necessaary to stop GC but if it is not stopped and a
|
1106
|
-
// large string is parsed that string is corrupted or freed during
|
1107
|
-
// parsing. I'm not sure what is going on exactly but disabling GC avoids
|
1108
|
-
// the issue.
|
1109
|
-
rb_gc_disable();
|
1091
|
+
len = (int)RSTRING_LEN(str) + 1;
|
1092
|
+
json = OJ_R_ALLOC_N(char, len);
|
1093
|
+
|
1110
1094
|
memcpy(json, StringValuePtr(str), len);
|
1111
|
-
obj = parse_json(clas, json, given
|
1112
|
-
|
1113
|
-
|
1114
|
-
|
1095
|
+
obj = parse_json(clas, json, given);
|
1096
|
+
// TBD is this needed
|
1097
|
+
/*
|
1098
|
+
if (given) {
|
1099
|
+
OJ_R_FREE(json);
|
1115
1100
|
}
|
1101
|
+
*/
|
1116
1102
|
return obj;
|
1117
1103
|
}
|
1118
1104
|
|
@@ -1136,27 +1122,21 @@ static VALUE doc_open(VALUE clas, VALUE str) {
|
|
1136
1122
|
* doc.close()
|
1137
1123
|
*/
|
1138
1124
|
static VALUE doc_open_file(VALUE clas, VALUE filename) {
|
1139
|
-
char
|
1140
|
-
char
|
1141
|
-
FILE
|
1125
|
+
char *path;
|
1126
|
+
char *json;
|
1127
|
+
FILE *f;
|
1142
1128
|
size_t len;
|
1143
1129
|
volatile VALUE obj;
|
1144
1130
|
int given = rb_block_given_p();
|
1145
|
-
int allocate;
|
1146
1131
|
|
1147
|
-
Check_Type(filename, T_STRING);
|
1148
1132
|
path = StringValuePtr(filename);
|
1149
1133
|
if (0 == (f = fopen(path, "r"))) {
|
1150
1134
|
rb_raise(rb_eIOError, "%s", strerror(errno));
|
1151
1135
|
}
|
1152
1136
|
fseek(f, 0, SEEK_END);
|
1153
|
-
len
|
1154
|
-
|
1155
|
-
|
1156
|
-
json = ALLOC_N(char, len + 1);
|
1157
|
-
} else {
|
1158
|
-
json = ALLOCA_N(char, len + 1);
|
1159
|
-
}
|
1137
|
+
len = ftell(f);
|
1138
|
+
json = OJ_R_ALLOC_N(char, len + 1);
|
1139
|
+
|
1160
1140
|
fseek(f, 0, SEEK_SET);
|
1161
1141
|
if (len != fread(json, 1, len, f)) {
|
1162
1142
|
fclose(f);
|
@@ -1167,12 +1147,13 @@ static VALUE doc_open_file(VALUE clas, VALUE filename) {
|
|
1167
1147
|
}
|
1168
1148
|
fclose(f);
|
1169
1149
|
json[len] = '\0';
|
1170
|
-
|
1171
|
-
|
1172
|
-
|
1173
|
-
if (given
|
1174
|
-
|
1150
|
+
obj = parse_json(clas, json, given);
|
1151
|
+
// TBD is this needed
|
1152
|
+
/*
|
1153
|
+
if (given) {
|
1154
|
+
OJ_R_FREE(json);
|
1175
1155
|
}
|
1156
|
+
*/
|
1176
1157
|
return obj;
|
1177
1158
|
}
|
1178
1159
|
|
@@ -1212,11 +1193,11 @@ static VALUE doc_where(VALUE self) {
|
|
1212
1193
|
if (0 == *doc->where_path || doc->where == doc->where_path) {
|
1213
1194
|
return oj_slash_string;
|
1214
1195
|
} else {
|
1215
|
-
Leaf
|
1196
|
+
Leaf *lp;
|
1216
1197
|
Leaf leaf;
|
1217
1198
|
size_t size = 3; // leading / and terminating \0
|
1218
|
-
char
|
1219
|
-
char
|
1199
|
+
char *path;
|
1200
|
+
char *p;
|
1220
1201
|
|
1221
1202
|
for (lp = doc->where_path; lp <= doc->where; lp++) {
|
1222
1203
|
leaf = *lp;
|
@@ -1319,7 +1300,6 @@ static VALUE doc_type(int argc, VALUE *argv, VALUE self) {
|
|
1319
1300
|
VALUE type = Qnil;
|
1320
1301
|
|
1321
1302
|
if (1 <= argc) {
|
1322
|
-
Check_Type(*argv, T_STRING);
|
1323
1303
|
path = StringValuePtr(*argv);
|
1324
1304
|
}
|
1325
1305
|
if (0 != (leaf = get_doc_leaf(doc, path))) {
|
@@ -1328,11 +1308,7 @@ static VALUE doc_type(int argc, VALUE *argv, VALUE self) {
|
|
1328
1308
|
case T_TRUE: type = rb_cTrueClass; break;
|
1329
1309
|
case T_FALSE: type = rb_cFalseClass; break;
|
1330
1310
|
case T_STRING: type = rb_cString; break;
|
1331
|
-
#ifdef RUBY_INTEGER_UNIFICATION
|
1332
1311
|
case T_FIXNUM: type = rb_cInteger; break;
|
1333
|
-
#else
|
1334
|
-
case T_FIXNUM: type = rb_cFixnum; break;
|
1335
|
-
#endif
|
1336
1312
|
case T_FLOAT: type = rb_cFloat; break;
|
1337
1313
|
case T_ARRAY: type = rb_cArray; break;
|
1338
1314
|
case T_HASH: type = rb_cHash; break;
|
@@ -1359,11 +1335,10 @@ static VALUE doc_fetch(int argc, VALUE *argv, VALUE self) {
|
|
1359
1335
|
Doc doc;
|
1360
1336
|
Leaf leaf;
|
1361
1337
|
volatile VALUE val = Qnil;
|
1362
|
-
const char
|
1338
|
+
const char *path = 0;
|
1363
1339
|
|
1364
1340
|
doc = self_doc(self);
|
1365
1341
|
if (1 <= argc) {
|
1366
|
-
Check_Type(*argv, T_STRING);
|
1367
1342
|
path = StringValuePtr(*argv);
|
1368
1343
|
if (2 == argc) {
|
1369
1344
|
val = argv[1];
|
@@ -1388,7 +1363,6 @@ static VALUE doc_exists(VALUE self, VALUE str) {
|
|
1388
1363
|
Leaf leaf;
|
1389
1364
|
|
1390
1365
|
doc = self_doc(self);
|
1391
|
-
Check_Type(str, T_STRING);
|
1392
1366
|
if (0 != (leaf = get_doc_leaf(doc, StringValuePtr(str)))) {
|
1393
1367
|
if (NULL != leaf) {
|
1394
1368
|
return Qtrue;
|
@@ -1425,7 +1399,6 @@ static VALUE doc_each_leaf(int argc, VALUE *argv, VALUE self) {
|
|
1425
1399
|
memcpy(save_path, doc->where_path, sizeof(Leaf) * (wlen + 1));
|
1426
1400
|
}
|
1427
1401
|
if (1 <= argc) {
|
1428
|
-
Check_Type(*argv, T_STRING);
|
1429
1402
|
path = StringValuePtr(*argv);
|
1430
1403
|
if ('/' == *path) {
|
1431
1404
|
doc->where = doc->where_path;
|
@@ -1460,7 +1433,6 @@ static VALUE doc_move(VALUE self, VALUE str) {
|
|
1460
1433
|
const char *path;
|
1461
1434
|
int loc;
|
1462
1435
|
|
1463
|
-
Check_Type(str, T_STRING);
|
1464
1436
|
path = StringValuePtr(str);
|
1465
1437
|
if ('/' == *path) {
|
1466
1438
|
doc->where = doc->where_path;
|
@@ -1495,14 +1467,13 @@ static VALUE doc_each_child(int argc, VALUE *argv, VALUE self) {
|
|
1495
1467
|
Doc doc = self_doc(self);
|
1496
1468
|
const char *path = 0;
|
1497
1469
|
size_t wlen;
|
1498
|
-
Leaf
|
1470
|
+
Leaf *where_orig = doc->where;
|
1499
1471
|
|
1500
1472
|
wlen = doc->where - doc->where_path;
|
1501
1473
|
if (0 < wlen) {
|
1502
1474
|
memcpy(save_path, doc->where_path, sizeof(Leaf) * (wlen + 1));
|
1503
1475
|
}
|
1504
1476
|
if (1 <= argc) {
|
1505
|
-
Check_Type(*argv, T_STRING);
|
1506
1477
|
path = StringValuePtr(*argv);
|
1507
1478
|
if ('/' == *path) {
|
1508
1479
|
doc->where = doc->where_path;
|
@@ -1569,7 +1540,6 @@ static VALUE doc_each_value(int argc, VALUE *argv, VALUE self) {
|
|
1569
1540
|
Leaf leaf;
|
1570
1541
|
|
1571
1542
|
if (1 <= argc) {
|
1572
|
-
Check_Type(*argv, T_STRING);
|
1573
1543
|
path = StringValuePtr(*argv);
|
1574
1544
|
}
|
1575
1545
|
if (0 != (leaf = get_doc_leaf(doc, path))) {
|
@@ -1601,11 +1571,9 @@ static VALUE doc_dump(int argc, VALUE *argv, VALUE self) {
|
|
1601
1571
|
|
1602
1572
|
if (1 <= argc) {
|
1603
1573
|
if (Qnil != *argv) {
|
1604
|
-
Check_Type(*argv, T_STRING);
|
1605
1574
|
path = StringValuePtr(*argv);
|
1606
1575
|
}
|
1607
1576
|
if (2 <= argc) {
|
1608
|
-
Check_Type(argv[1], T_STRING);
|
1609
1577
|
filename = StringValuePtr(argv[1]);
|
1610
1578
|
}
|
1611
1579
|
}
|
@@ -1617,7 +1585,7 @@ static VALUE doc_dump(int argc, VALUE *argv, VALUE self) {
|
|
1617
1585
|
|
1618
1586
|
oj_out_init(&out);
|
1619
1587
|
|
1620
|
-
out.omit_nil
|
1588
|
+
out.omit_nil = oj_default_options.dump_opts.omit_nil;
|
1621
1589
|
oj_dump_leaf_to_json(leaf, &oj_default_options, &out);
|
1622
1590
|
rjson = rb_str_new2(out.buf);
|
1623
1591
|
|
@@ -1640,7 +1608,9 @@ static VALUE doc_dump(int argc, VALUE *argv, VALUE self) {
|
|
1640
1608
|
* Oj::Doc.open('[1,2,3]') { |doc| doc.size() } #=> 4
|
1641
1609
|
*/
|
1642
1610
|
static VALUE doc_size(VALUE self) {
|
1643
|
-
|
1611
|
+
Doc d;
|
1612
|
+
TypedData_Get_Struct(self, struct _doc, &oj_doc_type, d);
|
1613
|
+
return ULONG2NUM(d->size);
|
1644
1614
|
}
|
1645
1615
|
|
1646
1616
|
/* @overload close() => nil
|
@@ -1656,11 +1626,9 @@ static VALUE doc_close(VALUE self) {
|
|
1656
1626
|
Doc doc = self_doc(self);
|
1657
1627
|
|
1658
1628
|
rb_gc_unregister_address(&doc->self);
|
1659
|
-
DATA_PTR(doc->self) =
|
1629
|
+
DATA_PTR(doc->self) = NULL;
|
1660
1630
|
if (0 != doc) {
|
1661
|
-
xfree(doc->json);
|
1662
1631
|
doc_free(doc);
|
1663
|
-
xfree(doc);
|
1664
1632
|
}
|
1665
1633
|
return Qnil;
|
1666
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
|
25
|
+
const char *key;
|
24
26
|
size_t len;
|
25
27
|
VALUE val;
|
26
|
-
} *
|
28
|
+
} *KeyVal;
|
27
29
|
|
28
30
|
typedef struct _hash {
|
29
31
|
struct _keyVal slots[HASH_SLOT_CNT];
|
@@ -32,16 +34,16 @@ typedef struct _hash {
|
|
32
34
|
#else
|
33
35
|
VALUE mutex;
|
34
36
|
#endif
|
35
|
-
} *
|
37
|
+
} *Hash;
|
36
38
|
|
37
39
|
struct _hash class_hash;
|
38
40
|
struct _hash attr_hash;
|
39
41
|
|
40
|
-
static VALUE
|
42
|
+
static VALUE str_cache_obj;
|
41
43
|
|
42
|
-
static VALUE
|
44
|
+
static VALUE sym_cache_obj;
|
43
45
|
|
44
|
-
static VALUE
|
46
|
+
static VALUE attr_cache_obj;
|
45
47
|
|
46
48
|
static VALUE form_str(const char *str, size_t len) {
|
47
49
|
return rb_str_freeze(rb_utf8_str_new(str, len));
|
@@ -55,51 +57,59 @@ static VALUE form_attr(const char *str, size_t len) {
|
|
55
57
|
char buf[256];
|
56
58
|
|
57
59
|
if (sizeof(buf) - 2 <= len) {
|
58
|
-
char *b =
|
60
|
+
char *b = OJ_R_ALLOC_N(char, len + 2);
|
59
61
|
ID id;
|
60
62
|
|
61
63
|
if ('~' == *str) {
|
62
|
-
|
63
|
-
|
64
|
-
|
65
|
-
|
66
|
-
|
67
|
-
|
68
|
-
|
69
|
-
|
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
|
+
}
|
70
72
|
id = rb_intern3(buf, len + 1, oj_utf8_encoding);
|
71
|
-
|
73
|
+
OJ_R_FREE(b);
|
72
74
|
return id;
|
73
75
|
}
|
74
76
|
if ('~' == *str) {
|
75
|
-
|
76
|
-
|
77
|
-
|
77
|
+
memcpy(buf, str + 1, len - 1);
|
78
|
+
buf[len - 1] = '\0';
|
79
|
+
len -= 2;
|
78
80
|
} else {
|
79
|
-
|
80
|
-
|
81
|
-
|
81
|
+
*buf = '@';
|
82
|
+
memcpy(buf + 1, str, len);
|
83
|
+
buf[len + 1] = '\0';
|
82
84
|
}
|
83
85
|
return (VALUE)rb_intern3(buf, len + 1, oj_utf8_encoding);
|
84
86
|
}
|
85
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
|
+
|
86
99
|
void oj_hash_init(void) {
|
87
100
|
VALUE cache_class = rb_define_class_under(Oj, "Cache", rb_cObject);
|
88
101
|
rb_undef_alloc_func(cache_class);
|
89
102
|
|
90
|
-
|
91
|
-
|
92
|
-
|
93
|
-
struct _cache *str_cache = cache_create(0, form_str, true, true);
|
94
|
-
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);
|
95
105
|
rb_gc_register_address(&str_cache_obj);
|
96
106
|
|
97
|
-
struct _cache *sym_cache
|
98
|
-
sym_cache_obj
|
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);
|
99
109
|
rb_gc_register_address(&sym_cache_obj);
|
100
110
|
|
101
111
|
struct _cache *attr_cache = cache_create(0, form_attr, false, true);
|
102
|
-
attr_cache_obj
|
112
|
+
attr_cache_obj = TypedData_Wrap_Struct(cache_class, &oj_cache_type, attr_cache);
|
103
113
|
rb_gc_register_address(&attr_cache_obj);
|
104
114
|
|
105
115
|
memset(class_hash.slots, 0, sizeof(class_hash.slots));
|
@@ -119,18 +129,23 @@ oj_str_intern(const char *key, size_t len) {
|
|
119
129
|
#if HAVE_RB_ENC_INTERNED_STR && 0
|
120
130
|
return rb_enc_interned_str(key, len, rb_utf8_encoding());
|
121
131
|
#else
|
122
|
-
|
132
|
+
Cache c;
|
133
|
+
TypedData_Get_Struct(str_cache_obj, struct _cache, &oj_cache_type, c);
|
134
|
+
return cache_intern(c, key, len);
|
123
135
|
#endif
|
124
136
|
}
|
125
137
|
|
126
138
|
VALUE
|
127
139
|
oj_sym_intern(const char *key, size_t len) {
|
128
|
-
|
140
|
+
Cache c;
|
141
|
+
TypedData_Get_Struct(sym_cache_obj, struct _cache, &oj_cache_type, c);
|
142
|
+
return cache_intern(c, key, len);
|
129
143
|
}
|
130
144
|
|
131
|
-
ID
|
132
|
-
|
133
|
-
|
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);
|
134
149
|
}
|
135
150
|
|
136
151
|
static uint64_t hash_calc(const uint8_t *key, size_t len) {
|
@@ -184,10 +199,10 @@ static VALUE resolve_classname(VALUE mod, const char *classname, int auto_define
|
|
184
199
|
static VALUE resolve_classpath(ParseInfo pi, const char *name, size_t len, int auto_define, VALUE error_class) {
|
185
200
|
char class_name[1024];
|
186
201
|
VALUE clas;
|
187
|
-
char
|
188
|
-
char
|
189
|
-
const char *n
|
190
|
-
size_t
|
202
|
+
char *end = class_name + sizeof(class_name) - 1;
|
203
|
+
char *s;
|
204
|
+
const char *n = name;
|
205
|
+
size_t nlen = len;
|
191
206
|
|
192
207
|
clas = rb_cObject;
|
193
208
|
for (s = class_name; 0 < len; n++, len--) {
|
@@ -210,11 +225,11 @@ static VALUE resolve_classpath(ParseInfo pi, const char *name, size_t len, int a
|
|
210
225
|
}
|
211
226
|
*s = '\0';
|
212
227
|
if (Qundef == (clas = resolve_classname(clas, class_name, auto_define))) {
|
213
|
-
|
214
|
-
|
215
|
-
|
216
|
-
|
217
|
-
|
228
|
+
if (sizeof(class_name) <= nlen) {
|
229
|
+
nlen = sizeof(class_name) - 1;
|
230
|
+
}
|
231
|
+
strncpy(class_name, name, nlen);
|
232
|
+
class_name[nlen] = '\0';
|
218
233
|
oj_set_error_at(pi, error_class, __FILE__, __LINE__, "class '%s' is not defined", class_name);
|
219
234
|
if (Qnil != error_class) {
|
220
235
|
pi->err_class = error_class;
|
@@ -246,7 +261,7 @@ VALUE oj_class_intern(const char *key, size_t len, bool safe, ParseInfo pi, int
|
|
246
261
|
}
|
247
262
|
bucket = b;
|
248
263
|
}
|
249
|
-
b =
|
264
|
+
b = OJ_R_ALLOC(struct _keyVal);
|
250
265
|
b->next = NULL;
|
251
266
|
bucket->next = b;
|
252
267
|
bucket = b;
|
@@ -267,7 +282,7 @@ VALUE oj_class_intern(const char *key, size_t len, bool safe, ParseInfo pi, int
|
|
267
282
|
}
|
268
283
|
bucket = b;
|
269
284
|
}
|
270
|
-
b =
|
285
|
+
b = OJ_R_ALLOC(struct _keyVal);
|
271
286
|
b->next = NULL;
|
272
287
|
bucket->next = b;
|
273
288
|
bucket = b;
|
@@ -281,7 +296,7 @@ VALUE oj_class_intern(const char *key, size_t len, bool safe, ParseInfo pi, int
|
|
281
296
|
}
|
282
297
|
|
283
298
|
char *oj_strndup(const char *s, size_t len) {
|
284
|
-
char *d =
|
299
|
+
char *d = OJ_R_ALLOC_N(char, len + 1);
|
285
300
|
|
286
301
|
memcpy(d, s, len);
|
287
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
|
18
|
-
|
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
|
|