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.
- checksums.yaml +4 -4
- data/CHANGELOG.md +77 -0
- data/README.md +4 -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 +44 -96
- data/ext/oj/debug.c +3 -9
- data/ext/oj/dump.c +69 -39
- 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 -6
- data/ext/oj/fast.c +76 -106
- data/ext/oj/intern.c +63 -51
- 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 +43 -30
- data/ext/oj/object.c +61 -70
- data/ext/oj/odd.c +8 -6
- data/ext/oj/odd.h +4 -4
- data/ext/oj/oj.c +243 -205
- data/ext/oj/oj.h +82 -78
- data/ext/oj/parse.c +123 -188
- data/ext/oj/parse.h +23 -24
- data/ext/oj/parser.c +103 -63
- data/ext/oj/parser.h +19 -9
- data/ext/oj/rails.c +68 -92
- data/ext/oj/reader.c +10 -15
- 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 +74 -92
- data/ext/oj/saj2.h +23 -0
- data/ext/oj/scp.c +3 -14
- data/ext/oj/sparse.c +22 -70
- data/ext/oj/stream_writer.c +43 -35
- data/ext/oj/strict.c +20 -52
- data/ext/oj/string_writer.c +60 -34
- data/ext/oj/trace.h +31 -4
- data/ext/oj/usual.c +125 -150
- data/ext/oj/usual.h +69 -0
- data/ext/oj/util.h +1 -1
- data/ext/oj/val_stack.c +14 -3
- 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 +6 -2
- 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/files.rb +15 -15
- data/test/foo.rb +9 -72
- 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 +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 +53 -37
- data/test/json_gem/json_generic_object_test.rb +11 -11
- data/test/json_gem/json_parser_test.rb +47 -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 +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 +80 -53
- data/test/test_custom.rb +73 -51
- data/test/test_debian.rb +7 -10
- data/test/test_fast.rb +86 -90
- data/test/test_file.rb +28 -35
- 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 +94 -96
- data/test/test_parser.rb +6 -22
- data/test/test_parser_debug.rb +27 -0
- data/test/test_parser_saj.rb +61 -22
- data/test/test_parser_usual.rb +16 -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 +40 -32
- data/test/test_various.rb +148 -100
- 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 +36 -27
- 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
|
-
unsigned long size;
|
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
|
-
} *
|
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
|
|
@@ -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++;
|
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
|
-
|
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,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
|
-
|
681
|
-
|
682
|
-
|
683
|
-
|
684
|
-
|
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
|
-
|
687
|
-
|
688
|
-
|
689
|
-
|
690
|
-
|
691
|
-
|
692
|
-
|
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
|
-
|
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
|
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
|
-
|
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
|
-
|
789
|
-
|
790
|
-
doc->
|
791
|
-
|
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 (
|
797
|
-
|
792
|
+
if (0 != ex) { // will jump so caller will not free
|
793
|
+
OJ_R_FREE(json);
|
798
794
|
}
|
799
|
-
|
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
|
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
|
1097
|
-
|
1098
|
-
|
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
|
1110
|
-
|
1111
|
-
|
1112
|
-
|
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
|
1138
|
-
char
|
1139
|
-
FILE
|
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
|
1152
|
-
|
1153
|
-
|
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
|
-
|
1169
|
-
|
1170
|
-
|
1171
|
-
if (given
|
1172
|
-
|
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
|
1196
|
+
Leaf *lp;
|
1214
1197
|
Leaf leaf;
|
1215
1198
|
size_t size = 3; // leading / and terminating \0
|
1216
|
-
char
|
1217
|
-
char
|
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
|
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
|
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
|
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
|
-
|
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) =
|
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
|
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,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 =
|
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
|
|
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
|
-
|
94
|
-
|
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
|
101
|
-
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);
|
102
109
|
rb_gc_register_address(&sym_cache_obj);
|
103
110
|
|
104
|
-
attr_cache
|
105
|
-
attr_cache_obj
|
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
|
-
|
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
|
-
|
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
|
-
|
136
|
-
|
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
|
191
|
-
char
|
192
|
-
const char *n
|
193
|
-
size_t
|
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
|
-
|
217
|
-
|
218
|
-
|
219
|
-
|
220
|
-
|
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 =
|
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 =
|
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 =
|
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
|
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
|
|