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.
- checksums.yaml +4 -4
- data/CHANGELOG.md +74 -0
- data/README.md +4 -2
- data/ext/oj/buf.h +11 -6
- data/ext/oj/cache.c +25 -24
- data/ext/oj/cache8.c +10 -9
- data/ext/oj/circarray.c +8 -6
- data/ext/oj/circarray.h +2 -2
- data/ext/oj/code.c +17 -24
- data/ext/oj/code.h +2 -2
- data/ext/oj/compat.c +17 -44
- data/ext/oj/custom.c +70 -141
- data/ext/oj/debug.c +3 -9
- data/ext/oj/dump.c +128 -118
- data/ext/oj/dump.h +12 -8
- data/ext/oj/dump_compat.c +564 -641
- data/ext/oj/dump_leaf.c +17 -63
- data/ext/oj/dump_object.c +70 -199
- data/ext/oj/dump_strict.c +22 -46
- 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 +14 -5
- data/ext/oj/fast.c +75 -103
- data/ext/oj/intern.c +52 -50
- data/ext/oj/intern.h +4 -8
- data/ext/oj/mem.c +318 -0
- data/ext/oj/mem.h +53 -0
- data/ext/oj/mimic_json.c +75 -47
- data/ext/oj/object.c +49 -66
- data/ext/oj/odd.c +89 -67
- data/ext/oj/odd.h +15 -15
- data/ext/oj/oj.c +140 -99
- data/ext/oj/oj.h +80 -51
- data/ext/oj/parse.c +162 -184
- data/ext/oj/parse.h +7 -10
- data/ext/oj/parser.c +89 -34
- data/ext/oj/parser.h +18 -7
- data/ext/oj/rails.c +82 -146
- data/ext/oj/rails.h +1 -1
- data/ext/oj/reader.c +11 -12
- 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 +20 -31
- data/ext/oj/saj2.c +329 -93
- data/ext/oj/saj2.h +23 -0
- data/ext/oj/scp.c +3 -14
- data/ext/oj/sparse.c +26 -70
- data/ext/oj/stream_writer.c +12 -22
- data/ext/oj/strict.c +20 -52
- data/ext/oj/string_writer.c +21 -21
- data/ext/oj/trace.h +31 -4
- data/ext/oj/usual.c +105 -150
- data/ext/oj/usual.h +68 -0
- data/ext/oj/util.h +1 -1
- data/ext/oj/val_stack.c +1 -1
- data/ext/oj/val_stack.h +8 -7
- data/ext/oj/validate.c +21 -26
- data/ext/oj/wab.c +31 -68
- data/lib/oj/active_support_helper.rb +0 -1
- 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 +4 -2
- data/lib/oj/mimic.rb +4 -2
- data/lib/oj/saj.rb +20 -6
- data/lib/oj/state.rb +9 -6
- data/lib/oj/version.rb +1 -2
- data/lib/oj.rb +2 -0
- data/pages/Compatibility.md +1 -1
- data/pages/InstallOptions.md +20 -0
- data/pages/Options.md +10 -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/{activesupport5 → activesupport7}/abstract_unit.rb +16 -12
- data/test/{activesupport5 → activesupport7}/decoding_test.rb +2 -10
- data/test/{activesupport5 → activesupport7}/encoding_test.rb +20 -34
- data/test/{activesupport5 → activesupport7}/encoding_test_cases.rb +6 -0
- data/test/{activesupport5 → activesupport7}/time_zone_test_helpers.rb +8 -0
- data/test/files.rb +15 -15
- data/test/foo.rb +9 -71
- data/test/helper.rb +11 -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 +4 -4
- 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 +48 -36
- data/test/json_gem/json_generic_object_test.rb +11 -11
- data/test/json_gem/json_parser_test.rb +54 -47
- data/test/json_gem/json_string_matching_test.rb +9 -9
- data/test/json_gem/test_helper.rb +7 -3
- data/test/mem.rb +13 -12
- data/test/perf.rb +21 -26
- data/test/perf_compat.rb +31 -33
- data/test/perf_dump.rb +50 -0
- 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 +3 -3
- 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 +76 -42
- data/test/test_custom.rb +72 -51
- data/test/test_debian.rb +7 -10
- data/test/test_fast.rb +86 -90
- data/test/test_file.rb +41 -30
- data/test/test_gc.rb +16 -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 +85 -96
- data/test/test_parser.rb +6 -22
- data/test/test_parser_debug.rb +27 -0
- data/test/test_parser_saj.rb +115 -23
- data/test/test_parser_usual.rb +6 -6
- data/test/test_rails.rb +2 -2
- data/test/test_saj.rb +10 -8
- data/test/test_scp.rb +37 -39
- data/test/test_strict.rb +30 -32
- data/test/test_various.rb +147 -99
- data/test/test_wab.rb +48 -44
- data/test/test_writer.rb +47 -47
- data/test/tests.rb +13 -4
- data/test/tests_mimic.rb +12 -3
- data/test/tests_mimic_addition.rb +12 -3
- metadata +33 -144
- 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/test_helper.rb +0 -72
- data/test/bar.rb +0 -16
- 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,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
|
-
|
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
|
-
} *
|
36
|
+
} *Batch;
|
35
37
|
|
36
38
|
typedef struct _doc {
|
37
39
|
Leaf data;
|
38
|
-
Leaf
|
40
|
+
Leaf *where; // points to current location
|
39
41
|
Leaf where_path[MAX_STACK]; // points to head of path
|
40
|
-
char
|
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
|
-
} *
|
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
|
-
} *
|
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
|
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 =
|
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
|
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
|
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
|
-
|
652
|
+
OJ_R_FREE(b);
|
651
653
|
}
|
652
654
|
}
|
653
|
-
|
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
|
-
|
680
|
-
|
681
|
-
|
682
|
-
|
683
|
-
|
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
|
-
|
686
|
-
|
687
|
-
|
688
|
-
|
689
|
-
|
690
|
-
|
691
|
-
|
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
|
-
|
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
|
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
|
-
|
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 - (
|
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 (
|
796
|
-
|
796
|
+
if (0 != ex) { // will jump so caller will not free
|
797
|
+
OJ_R_FREE(json);
|
797
798
|
}
|
798
|
-
|
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
|
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
|
1096
|
-
|
1097
|
-
|
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
|
1109
|
-
|
1110
|
-
|
1111
|
-
|
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
|
1137
|
-
char
|
1138
|
-
FILE
|
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
|
1151
|
-
|
1152
|
-
|
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
|
-
|
1168
|
-
|
1169
|
-
|
1170
|
-
if (given
|
1171
|
-
|
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
|
1200
|
+
Leaf *lp;
|
1213
1201
|
Leaf leaf;
|
1214
1202
|
size_t size = 3; // leading / and terminating \0
|
1215
|
-
char
|
1216
|
-
char
|
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
|
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
|
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
|
1617
|
-
|
1618
|
-
out.
|
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
|
-
|
1623
|
-
|
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) =
|
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
|
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,19 +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
|
41
|
-
static VALUE str_cache_obj;
|
42
|
+
static VALUE str_cache_obj;
|
42
43
|
|
43
|
-
static
|
44
|
-
static VALUE sym_cache_obj;
|
44
|
+
static VALUE sym_cache_obj;
|
45
45
|
|
46
|
-
static
|
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 =
|
60
|
+
char *b = OJ_R_ALLOC_N(char, len + 2);
|
62
61
|
ID id;
|
63
62
|
|
64
63
|
if ('~' == *str) {
|
65
|
-
|
66
|
-
|
67
|
-
|
68
|
-
|
69
|
-
|
70
|
-
|
71
|
-
|
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
|
-
|
73
|
+
OJ_R_FREE(b);
|
75
74
|
return id;
|
76
75
|
}
|
77
76
|
if ('~' == *str) {
|
78
|
-
|
79
|
-
|
80
|
-
|
77
|
+
memcpy(buf, str + 1, len - 1);
|
78
|
+
buf[len - 1] = '\0';
|
79
|
+
len -= 2;
|
81
80
|
} else {
|
82
|
-
|
83
|
-
|
84
|
-
|
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
|
93
|
-
str_cache_obj
|
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
|
97
|
-
sym_cache_obj
|
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
|
101
|
-
attr_cache_obj
|
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(
|
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(
|
127
|
+
return cache_intern(DATA_PTR(sym_cache_obj), key, len);
|
128
128
|
}
|
129
129
|
|
130
|
-
ID
|
131
|
-
|
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
|
187
|
-
char
|
188
|
-
const char *n
|
189
|
-
size_t
|
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
|
-
|
213
|
-
|
214
|
-
|
215
|
-
|
216
|
-
|
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 =
|
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 =
|
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 =
|
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
|
-
|
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
|
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
|
|