oj 3.12.3 → 3.13.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/README.md +2 -3
- data/ext/oj/buf.h +9 -0
- data/ext/oj/cache.c +341 -0
- data/ext/oj/cache.h +21 -0
- data/ext/oj/compat.c +7 -22
- data/ext/oj/custom.c +15 -17
- data/ext/oj/debug.c +132 -0
- data/ext/oj/dump.c +12 -15
- data/ext/oj/dump_compat.c +3 -3
- data/ext/oj/dump_object.c +9 -9
- data/ext/oj/dump_strict.c +3 -3
- data/ext/oj/err.h +19 -0
- data/ext/oj/extconf.rb +5 -0
- data/ext/oj/fast.c +7 -18
- data/ext/oj/intern.c +281 -0
- data/ext/oj/intern.h +26 -0
- data/ext/oj/mimic_json.c +2 -2
- data/ext/oj/object.c +15 -92
- data/ext/oj/odd.c +1 -1
- data/ext/oj/oj.c +117 -94
- data/ext/oj/oj.h +1 -1
- data/ext/oj/parse.c +5 -5
- data/ext/oj/parser.c +1483 -0
- data/ext/oj/parser.h +90 -0
- data/ext/oj/rails.c +5 -5
- data/ext/oj/resolve.c +2 -20
- data/ext/oj/rxclass.c +1 -1
- data/ext/oj/saj.c +1 -1
- data/ext/oj/saj2.c +348 -0
- data/ext/oj/scp.c +1 -1
- data/ext/oj/sparse.c +2 -2
- data/ext/oj/stream_writer.c +4 -4
- data/ext/oj/strict.c +9 -27
- data/ext/oj/string_writer.c +2 -2
- data/ext/oj/usual.c +1252 -0
- data/ext/oj/validate.c +51 -0
- data/ext/oj/wab.c +14 -19
- data/lib/oj/error.rb +1 -1
- data/lib/oj/state.rb +8 -7
- data/lib/oj/version.rb +1 -1
- data/pages/Options.md +1 -1
- data/pages/Parser.md +309 -0
- data/pages/Rails.md +2 -2
- data/test/json_gem/json_generator_test.rb +1 -1
- data/test/mem.rb +33 -0
- data/test/perf_once.rb +58 -0
- data/test/perf_parser.rb +189 -0
- data/test/test_hash.rb +1 -1
- data/test/test_parser.rb +27 -0
- data/test/test_parser_saj.rb +245 -0
- data/test/test_parser_usual.rb +213 -0
- metadata +26 -5
- data/ext/oj/hash.c +0 -168
- data/ext/oj/hash.h +0 -21
- data/ext/oj/hash_test.c +0 -491
data/ext/oj/extconf.rb
CHANGED
@@ -30,6 +30,11 @@ have_func('rb_ivar_foreach')
|
|
30
30
|
have_func('rb_gc_mark_movable')
|
31
31
|
have_func('stpcpy')
|
32
32
|
have_func('pthread_mutex_init')
|
33
|
+
have_func('rb_enc_associate')
|
34
|
+
have_func('rb_enc_interned_str')
|
35
|
+
have_func('rb_ext_ractor_safe', 'ruby.h')
|
36
|
+
# rb_hash_bulk_insert is deep down in a header not included in normal build and that seems to fool have_func.
|
37
|
+
have_func('rb_hash_bulk_insert', 'ruby.h') unless '2' == version[0] && '6' == version[1]
|
33
38
|
|
34
39
|
dflags['OJ_DEBUG'] = true unless ENV['OJ_DEBUG'].nil?
|
35
40
|
|
data/ext/oj/fast.c
CHANGED
@@ -200,9 +200,7 @@ static VALUE leaf_value(Doc doc, Leaf leaf) {
|
|
200
200
|
break;
|
201
201
|
case T_ARRAY: return leaf_array_value(doc, leaf); break;
|
202
202
|
case T_HASH: return leaf_hash_value(doc, leaf); break;
|
203
|
-
default:
|
204
|
-
rb_raise(rb_const_get_at(Oj, rb_intern("Error")), "Unexpected type %02x.", leaf->rtype);
|
205
|
-
break;
|
203
|
+
default: rb_raise(rb_const_get_at(Oj, rb_intern("Error")), "Unexpected type %02x.", leaf->rtype); break;
|
206
204
|
}
|
207
205
|
}
|
208
206
|
return leaf->value;
|
@@ -773,7 +771,7 @@ static VALUE parse_json(VALUE clas, char *json, bool given, bool allocated) {
|
|
773
771
|
pi.doc = doc;
|
774
772
|
#if IS_WINDOWS
|
775
773
|
// assume a 1M stack and give half to ruby
|
776
|
-
pi.stack_min = (void
|
774
|
+
pi.stack_min = (void*)((char*)&pi - (512 * 1024));
|
777
775
|
#else
|
778
776
|
{
|
779
777
|
struct rlimit lim;
|
@@ -825,9 +823,7 @@ static Leaf get_doc_leaf(Doc doc, const char *path) {
|
|
825
823
|
size_t cnt = doc->where - doc->where_path;
|
826
824
|
|
827
825
|
if (MAX_STACK <= cnt) {
|
828
|
-
rb_raise(rb_const_get_at(Oj, rb_intern("DepthError")),
|
829
|
-
"Path too deep. Limit is %d levels.",
|
830
|
-
MAX_STACK);
|
826
|
+
rb_raise(rb_const_get_at(Oj, rb_intern("DepthError")), "Path too deep. Limit is %d levels.", MAX_STACK);
|
831
827
|
}
|
832
828
|
memcpy(stack, doc->where_path, sizeof(Leaf) * (cnt + 1));
|
833
829
|
lp = stack + cnt;
|
@@ -868,9 +864,7 @@ static Leaf get_leaf(Leaf *stack, Leaf *lp, const char *path) {
|
|
868
864
|
Leaf leaf = *lp;
|
869
865
|
|
870
866
|
if (MAX_STACK <= lp - stack) {
|
871
|
-
rb_raise(rb_const_get_at(Oj, rb_intern("DepthError")),
|
872
|
-
"Path too deep. Limit is %d levels.",
|
873
|
-
MAX_STACK);
|
867
|
+
rb_raise(rb_const_get_at(Oj, rb_intern("DepthError")), "Path too deep. Limit is %d levels.", MAX_STACK);
|
874
868
|
}
|
875
869
|
if ('\0' != *path) {
|
876
870
|
if ('.' == *path && '.' == *(path + 1)) {
|
@@ -946,9 +940,7 @@ static void each_leaf(Doc doc, VALUE self) {
|
|
946
940
|
|
947
941
|
doc->where++;
|
948
942
|
if (MAX_STACK <= doc->where - doc->where_path) {
|
949
|
-
rb_raise(rb_const_get_at(Oj, rb_intern("DepthError")),
|
950
|
-
"Path too deep. Limit is %d levels.",
|
951
|
-
MAX_STACK);
|
943
|
+
rb_raise(rb_const_get_at(Oj, rb_intern("DepthError")), "Path too deep. Limit is %d levels.", MAX_STACK);
|
952
944
|
}
|
953
945
|
do {
|
954
946
|
*doc->where = e;
|
@@ -964,9 +956,7 @@ static void each_leaf(Doc doc, VALUE self) {
|
|
964
956
|
|
965
957
|
static int move_step(Doc doc, const char *path, int loc) {
|
966
958
|
if (MAX_STACK <= doc->where - doc->where_path) {
|
967
|
-
rb_raise(rb_const_get_at(Oj, rb_intern("DepthError")),
|
968
|
-
"Path too deep. Limit is %d levels.",
|
969
|
-
MAX_STACK);
|
959
|
+
rb_raise(rb_const_get_at(Oj, rb_intern("DepthError")), "Path too deep. Limit is %d levels.", MAX_STACK);
|
970
960
|
}
|
971
961
|
if ('\0' == *path) {
|
972
962
|
loc = 0;
|
@@ -1264,7 +1254,6 @@ static VALUE doc_path(VALUE self) {
|
|
1264
1254
|
return doc_where(self);
|
1265
1255
|
}
|
1266
1256
|
|
1267
|
-
|
1268
1257
|
/* @overload local_key() => String, Fixnum, nil
|
1269
1258
|
*
|
1270
1259
|
* Returns the final key to the current location.
|
@@ -1483,7 +1472,7 @@ static VALUE doc_move(VALUE self, VALUE str) {
|
|
1483
1472
|
* to the block on yield is the Doc instance after moving to the child
|
1484
1473
|
* location.
|
1485
1474
|
* @param [String] path if provided it identified the top of the branch to
|
1486
|
-
* process the
|
1475
|
+
* process the children of
|
1487
1476
|
* @yieldparam [Doc] Doc at the child location
|
1488
1477
|
* @example
|
1489
1478
|
* Oj::Doc.open('[3,[2,1]]') { |doc|
|
data/ext/oj/intern.c
ADDED
@@ -0,0 +1,281 @@
|
|
1
|
+
// Copyright (c) 2011, 2021 Peter Ohler. All rights reserved.
|
2
|
+
// Licensed under the MIT License. See LICENSE file in the project root for license details.
|
3
|
+
|
4
|
+
#include "intern.h"
|
5
|
+
|
6
|
+
#include <stdint.h>
|
7
|
+
|
8
|
+
#if HAVE_PTHREAD_MUTEX_INIT
|
9
|
+
#include <pthread.h>
|
10
|
+
#endif
|
11
|
+
#include "cache.h"
|
12
|
+
#include "parse.h"
|
13
|
+
|
14
|
+
// Only used for the class cache so 256 should be sufficient.
|
15
|
+
#define HASH_SLOT_CNT ((uint64_t)256)
|
16
|
+
#define HASH_MASK (HASH_SLOT_CNT - 1)
|
17
|
+
|
18
|
+
// almost the Murmur hash algorithm
|
19
|
+
#define M 0x5bd1e995
|
20
|
+
|
21
|
+
typedef struct _keyVal {
|
22
|
+
struct _keyVal *next;
|
23
|
+
const char * key;
|
24
|
+
size_t len;
|
25
|
+
VALUE val;
|
26
|
+
} * KeyVal;
|
27
|
+
|
28
|
+
typedef struct _hash {
|
29
|
+
struct _keyVal slots[HASH_SLOT_CNT];
|
30
|
+
#if HAVE_PTHREAD_MUTEX_INIT
|
31
|
+
pthread_mutex_t mutex;
|
32
|
+
#else
|
33
|
+
VALUE mutex;
|
34
|
+
#endif
|
35
|
+
} * Hash;
|
36
|
+
|
37
|
+
struct _hash class_hash;
|
38
|
+
struct _hash attr_hash;
|
39
|
+
|
40
|
+
static struct _cache *str_cache = NULL;
|
41
|
+
static VALUE str_cache_obj;
|
42
|
+
|
43
|
+
static struct _cache *sym_cache = NULL;
|
44
|
+
static VALUE sym_cache_obj;
|
45
|
+
|
46
|
+
static struct _cache *attr_cache = NULL;
|
47
|
+
static VALUE attr_cache_obj;
|
48
|
+
|
49
|
+
static VALUE form_str(const char *str, size_t len) {
|
50
|
+
return rb_str_freeze(rb_utf8_str_new(str, len));
|
51
|
+
}
|
52
|
+
|
53
|
+
static VALUE form_sym(const char *str, size_t len) {
|
54
|
+
return rb_str_intern(rb_utf8_str_new(str, len));
|
55
|
+
}
|
56
|
+
|
57
|
+
static VALUE form_attr(const char *str, size_t len) {
|
58
|
+
char buf[256];
|
59
|
+
|
60
|
+
if (sizeof(buf) - 2 <= len) {
|
61
|
+
char *b = ALLOC_N(char, len + 2);
|
62
|
+
ID id;
|
63
|
+
|
64
|
+
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
|
+
}
|
73
|
+
id = rb_intern3(buf, len + 1, oj_utf8_encoding);
|
74
|
+
xfree(b);
|
75
|
+
return id;
|
76
|
+
}
|
77
|
+
if ('~' == *str) {
|
78
|
+
memcpy(buf, str + 1, len - 1);
|
79
|
+
buf[len - 1] = '\0';
|
80
|
+
len -= 2;
|
81
|
+
} else {
|
82
|
+
*buf = '@';
|
83
|
+
memcpy(buf + 1, str, len);
|
84
|
+
buf[len + 1] = '\0';
|
85
|
+
}
|
86
|
+
return (VALUE)rb_intern3(buf, len + 1, oj_utf8_encoding);
|
87
|
+
}
|
88
|
+
|
89
|
+
void oj_hash_init() {
|
90
|
+
VALUE cache_class = rb_define_class_under(Oj, "Cache", rb_cObject);
|
91
|
+
|
92
|
+
str_cache = cache_create(0, form_str, true, true);
|
93
|
+
str_cache_obj = Data_Wrap_Struct(cache_class, cache_mark, cache_free, str_cache);
|
94
|
+
rb_gc_register_address(&str_cache_obj);
|
95
|
+
|
96
|
+
sym_cache = cache_create(0, form_sym, true, true);
|
97
|
+
sym_cache_obj = Data_Wrap_Struct(cache_class, cache_mark, cache_free, sym_cache);
|
98
|
+
rb_gc_register_address(&sym_cache_obj);
|
99
|
+
|
100
|
+
attr_cache = cache_create(0, form_attr, false, true);
|
101
|
+
attr_cache_obj = Data_Wrap_Struct(cache_class, cache_mark, cache_free, attr_cache);
|
102
|
+
rb_gc_register_address(&attr_cache_obj);
|
103
|
+
|
104
|
+
memset(class_hash.slots, 0, sizeof(class_hash.slots));
|
105
|
+
#if HAVE_PTHREAD_MUTEX_INIT
|
106
|
+
pthread_mutex_init(&class_hash.mutex, NULL);
|
107
|
+
#else
|
108
|
+
class_hash.mutex = rb_mutex_new();
|
109
|
+
rb_gc_register_address(&class_hash.mutex);
|
110
|
+
#endif
|
111
|
+
}
|
112
|
+
|
113
|
+
VALUE
|
114
|
+
oj_str_intern(const char *key, size_t len) {
|
115
|
+
return cache_intern(str_cache, key, len);
|
116
|
+
}
|
117
|
+
|
118
|
+
VALUE
|
119
|
+
oj_sym_intern(const char *key, size_t len) {
|
120
|
+
return cache_intern(sym_cache, key, len);
|
121
|
+
}
|
122
|
+
|
123
|
+
ID
|
124
|
+
oj_attr_intern(const char *key, size_t len) {
|
125
|
+
return cache_intern(attr_cache, key, len);
|
126
|
+
}
|
127
|
+
|
128
|
+
static uint64_t hash_calc(const uint8_t *key, size_t len) {
|
129
|
+
const uint8_t *end = key + len;
|
130
|
+
const uint8_t *endless = key + (len & 0xFFFFFFFC);
|
131
|
+
uint64_t h = (uint64_t)len;
|
132
|
+
uint64_t k;
|
133
|
+
|
134
|
+
while (key < endless) {
|
135
|
+
k = (uint64_t)*key++;
|
136
|
+
k |= (uint64_t)*key++ << 8;
|
137
|
+
k |= (uint64_t)*key++ << 16;
|
138
|
+
k |= (uint64_t)*key++ << 24;
|
139
|
+
|
140
|
+
k *= M;
|
141
|
+
k ^= k >> 24;
|
142
|
+
h *= M;
|
143
|
+
h ^= k * M;
|
144
|
+
}
|
145
|
+
if (1 < end - key) {
|
146
|
+
uint16_t k16 = (uint16_t)*key++;
|
147
|
+
|
148
|
+
k16 |= (uint16_t)*key++ << 8;
|
149
|
+
h ^= k16 << 8;
|
150
|
+
}
|
151
|
+
if (key < end) {
|
152
|
+
h ^= *key;
|
153
|
+
}
|
154
|
+
h *= M;
|
155
|
+
h ^= h >> 13;
|
156
|
+
h *= M;
|
157
|
+
h ^= h >> 15;
|
158
|
+
|
159
|
+
return h;
|
160
|
+
}
|
161
|
+
|
162
|
+
static VALUE resolve_classname(VALUE mod, const char *classname, int auto_define) {
|
163
|
+
VALUE clas;
|
164
|
+
ID ci = rb_intern(classname);
|
165
|
+
|
166
|
+
if (rb_const_defined_at(mod, ci)) {
|
167
|
+
clas = rb_const_get_at(mod, ci);
|
168
|
+
} else if (auto_define) {
|
169
|
+
clas = rb_define_class_under(mod, classname, oj_bag_class);
|
170
|
+
} else {
|
171
|
+
clas = Qundef;
|
172
|
+
}
|
173
|
+
return clas;
|
174
|
+
}
|
175
|
+
|
176
|
+
static VALUE resolve_classpath(ParseInfo pi, const char *name, size_t len, int auto_define, VALUE error_class) {
|
177
|
+
char class_name[1024];
|
178
|
+
VALUE clas;
|
179
|
+
char * end = class_name + sizeof(class_name) - 1;
|
180
|
+
char * s;
|
181
|
+
const char *n = name;
|
182
|
+
|
183
|
+
clas = rb_cObject;
|
184
|
+
for (s = class_name; 0 < len; n++, len--) {
|
185
|
+
if (':' == *n) {
|
186
|
+
*s = '\0';
|
187
|
+
n++;
|
188
|
+
len--;
|
189
|
+
if (':' != *n) {
|
190
|
+
return Qundef;
|
191
|
+
}
|
192
|
+
if (Qundef == (clas = resolve_classname(clas, class_name, auto_define))) {
|
193
|
+
return Qundef;
|
194
|
+
}
|
195
|
+
s = class_name;
|
196
|
+
} else if (end <= s) {
|
197
|
+
return Qundef;
|
198
|
+
} else {
|
199
|
+
*s++ = *n;
|
200
|
+
}
|
201
|
+
}
|
202
|
+
*s = '\0';
|
203
|
+
if (Qundef == (clas = resolve_classname(clas, class_name, auto_define))) {
|
204
|
+
oj_set_error_at(pi, error_class, __FILE__, __LINE__, "class %s is not defined", name);
|
205
|
+
if (Qnil != error_class) {
|
206
|
+
pi->err_class = error_class;
|
207
|
+
}
|
208
|
+
}
|
209
|
+
return clas;
|
210
|
+
}
|
211
|
+
|
212
|
+
VALUE oj_class_intern(const char *key, size_t len, bool safe, ParseInfo pi, int auto_define, VALUE error_class) {
|
213
|
+
uint64_t h = hash_calc((const uint8_t *)key, len) & HASH_MASK;
|
214
|
+
KeyVal bucket = class_hash.slots + h;
|
215
|
+
KeyVal b;
|
216
|
+
|
217
|
+
if (safe) {
|
218
|
+
#if HAVE_PTHREAD_MUTEX_INIT
|
219
|
+
pthread_mutex_lock(&class_hash.mutex);
|
220
|
+
#else
|
221
|
+
rb_mutex_lock(class_hash.mutex);
|
222
|
+
#endif
|
223
|
+
if (NULL != bucket->key) { // not the top slot
|
224
|
+
for (b = bucket; 0 != b; b = b->next) {
|
225
|
+
if (len == b->len && 0 == strncmp(b->key, key, len)) {
|
226
|
+
#if HAVE_PTHREAD_MUTEX_INIT
|
227
|
+
pthread_mutex_unlock(&class_hash.mutex);
|
228
|
+
#else
|
229
|
+
rb_mutex_unlock(class_hash.mutex);
|
230
|
+
#endif
|
231
|
+
return b->val;
|
232
|
+
}
|
233
|
+
bucket = b;
|
234
|
+
}
|
235
|
+
b = ALLOC(struct _keyVal);
|
236
|
+
b->next = NULL;
|
237
|
+
bucket->next = b;
|
238
|
+
bucket = b;
|
239
|
+
}
|
240
|
+
bucket->key = oj_strndup(key, len);
|
241
|
+
bucket->len = len;
|
242
|
+
bucket->val = resolve_classpath(pi, key, len, auto_define, error_class);
|
243
|
+
#if HAVE_PTHREAD_MUTEX_INIT
|
244
|
+
pthread_mutex_unlock(&class_hash.mutex);
|
245
|
+
#else
|
246
|
+
rb_mutex_unlock(class_hash.mutex);
|
247
|
+
#endif
|
248
|
+
} else {
|
249
|
+
if (NULL != bucket->key) {
|
250
|
+
for (b = bucket; 0 != b; b = b->next) {
|
251
|
+
if (len == b->len && 0 == strncmp(b->key, key, len)) {
|
252
|
+
return (ID)b->val;
|
253
|
+
}
|
254
|
+
bucket = b;
|
255
|
+
}
|
256
|
+
b = ALLOC(struct _keyVal);
|
257
|
+
b->next = NULL;
|
258
|
+
bucket->next = b;
|
259
|
+
bucket = b;
|
260
|
+
}
|
261
|
+
bucket->key = oj_strndup(key, len);
|
262
|
+
bucket->len = len;
|
263
|
+
bucket->val = resolve_classpath(pi, key, len, auto_define, error_class);
|
264
|
+
}
|
265
|
+
return bucket->val;
|
266
|
+
}
|
267
|
+
|
268
|
+
char *oj_strndup(const char *s, size_t len) {
|
269
|
+
char *d = ALLOC_N(char, len + 1);
|
270
|
+
|
271
|
+
memcpy(d, s, len);
|
272
|
+
d[len] = '\0';
|
273
|
+
|
274
|
+
return d;
|
275
|
+
}
|
276
|
+
|
277
|
+
void intern_cleanup() {
|
278
|
+
cache_free(str_cache);
|
279
|
+
cache_free(sym_cache);
|
280
|
+
cache_free(attr_cache);
|
281
|
+
}
|
data/ext/oj/intern.h
ADDED
@@ -0,0 +1,26 @@
|
|
1
|
+
// Copyright (c) 2011, 2021 Peter Ohler. All rights reserved.
|
2
|
+
// Licensed under the MIT License. See LICENSE file in the project root for license details.
|
3
|
+
|
4
|
+
#ifndef OJ_INTERN_H
|
5
|
+
#define OJ_INTERN_H
|
6
|
+
|
7
|
+
#include <stdbool.h>
|
8
|
+
#include <ruby.h>
|
9
|
+
|
10
|
+
struct _parseInfo;
|
11
|
+
|
12
|
+
extern void oj_hash_init();
|
13
|
+
|
14
|
+
extern VALUE oj_str_intern(const char *key, size_t len);
|
15
|
+
extern VALUE oj_sym_intern(const char *key, size_t len);
|
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);
|
23
|
+
|
24
|
+
extern char *oj_strndup(const char *s, size_t len);
|
25
|
+
|
26
|
+
#endif /* OJ_INTERN_H */
|
data/ext/oj/mimic_json.c
CHANGED
@@ -682,7 +682,7 @@ static VALUE mimic_set_create_id(VALUE self, VALUE id) {
|
|
682
682
|
*/
|
683
683
|
static VALUE mimic_create_id(VALUE self) {
|
684
684
|
if (NULL != oj_default_options.create_id) {
|
685
|
-
return
|
685
|
+
return rb_utf8_str_new(oj_default_options.create_id, oj_default_options.create_id_len);
|
686
686
|
}
|
687
687
|
return rb_str_new_cstr(oj_json_class);
|
688
688
|
}
|
@@ -714,7 +714,7 @@ static struct _options mimic_object_to_json_options = {0, // indent
|
|
714
714
|
false, // sec_prec_set
|
715
715
|
No, // ignore_under
|
716
716
|
Yes, // cache_keys
|
717
|
-
|
717
|
+
0, // cache_str
|
718
718
|
0, // int_range_min
|
719
719
|
0, // int_range_max
|
720
720
|
oj_json_class, // create_id
|
data/ext/oj/object.c
CHANGED
@@ -7,7 +7,7 @@
|
|
7
7
|
|
8
8
|
#include "encode.h"
|
9
9
|
#include "err.h"
|
10
|
-
#include "
|
10
|
+
#include "intern.h"
|
11
11
|
#include "odd.h"
|
12
12
|
#include "oj.h"
|
13
13
|
#include "parse.h"
|
@@ -30,45 +30,18 @@ inline static long read_long(const char *str, size_t len) {
|
|
30
30
|
|
31
31
|
static VALUE calc_hash_key(ParseInfo pi, Val kval, char k1) {
|
32
32
|
volatile VALUE rkey;
|
33
|
-
#if 0
|
34
|
-
VALUE *slot;
|
35
33
|
|
36
34
|
if (':' == k1) {
|
37
|
-
|
38
|
-
rkey = rb_str_new(kval->key + 1, kval->klen - 1);
|
39
|
-
rkey = oj_encode(rkey);
|
40
|
-
rkey = rb_str_intern(rkey);
|
41
|
-
*slot = rkey;
|
42
|
-
rb_gc_register_address(slot);
|
43
|
-
}
|
44
|
-
} else if (Yes == pi->options.sym_key) {
|
45
|
-
if (Qnil == (rkey = oj_sym_hash_get(kval->key, kval->klen, &slot))) {
|
46
|
-
rkey = rb_str_new(kval->key, kval->klen);
|
47
|
-
rkey = oj_encode(rkey);
|
48
|
-
rkey = rb_str_intern(rkey);
|
49
|
-
*slot = rkey;
|
50
|
-
rb_gc_register_address(slot);
|
51
|
-
}
|
52
|
-
} else {
|
53
|
-
if (Qnil == (rkey = oj_str_hash_get(kval->key, kval->klen, &slot))) {
|
54
|
-
rkey = rb_str_new(kval->key, kval->klen);
|
55
|
-
rkey = oj_encode(rkey);
|
56
|
-
*slot = rkey;
|
57
|
-
rb_gc_register_address(slot);
|
58
|
-
}
|
35
|
+
return ID2SYM(rb_intern3(kval->key + 1, kval->klen - 1, oj_utf8_encoding));
|
59
36
|
}
|
60
|
-
|
61
|
-
|
62
|
-
rkey = rb_str_new(kval->key + 1, kval->klen - 1);
|
63
|
-
rkey = oj_encode(rkey);
|
64
|
-
rkey = rb_str_intern(rkey);
|
65
|
-
} else {
|
66
|
-
rkey = rb_str_new(kval->key, kval->klen);
|
67
|
-
rkey = oj_encode(rkey);
|
68
|
-
if (Yes == pi->options.sym_key) {
|
69
|
-
rkey = rb_str_intern(rkey);
|
70
|
-
}
|
37
|
+
if (Yes == pi->options.sym_key) {
|
38
|
+
return ID2SYM(rb_intern3(kval->key, kval->klen, oj_utf8_encoding));
|
71
39
|
}
|
40
|
+
#if HAVE_RB_ENC_INTERNED_STR
|
41
|
+
rkey = rb_enc_interned_str(kval->key, kval->klen, oj_utf8_encoding);
|
42
|
+
#else
|
43
|
+
rkey = rb_utf8_str_new(kval->key, kval->klen);
|
44
|
+
OBJ_FREEZE(rkey);
|
72
45
|
#endif
|
73
46
|
return rkey;
|
74
47
|
}
|
@@ -77,9 +50,7 @@ static VALUE str_to_value(ParseInfo pi, const char *str, size_t len, const char
|
|
77
50
|
volatile VALUE rstr = Qnil;
|
78
51
|
|
79
52
|
if (':' == *orig && 0 < len) {
|
80
|
-
rstr =
|
81
|
-
rstr = oj_encode(rstr);
|
82
|
-
rstr = rb_funcall(rstr, oj_to_sym_id, 0);
|
53
|
+
rstr = ID2SYM(rb_intern3(str + 1, len - 1, oj_utf8_encoding));
|
83
54
|
} else if (pi->circ_array && 3 <= len && '^' == *orig && 'r' == orig[1]) {
|
84
55
|
long i = read_long(str + 2, len - 2);
|
85
56
|
|
@@ -89,8 +60,7 @@ static VALUE str_to_value(ParseInfo pi, const char *str, size_t len, const char
|
|
89
60
|
}
|
90
61
|
rstr = oj_circ_array_get(pi->circ_array, i);
|
91
62
|
} else {
|
92
|
-
|
93
|
-
rstr = oj_encode(rstr);
|
63
|
+
rstr = rb_utf8_str_new(str, len);
|
94
64
|
}
|
95
65
|
return rstr;
|
96
66
|
}
|
@@ -258,13 +228,10 @@ static int hat_cstr(ParseInfo pi, Val parent, Val kval, const char *str, size_t
|
|
258
228
|
parent->odd_args = oj_odd_alloc_args(odd);
|
259
229
|
} break;
|
260
230
|
case 'm':
|
261
|
-
parent->val =
|
262
|
-
parent->val = oj_encode(parent->val);
|
263
|
-
parent->val = rb_funcall(parent->val, oj_to_sym_id, 0);
|
231
|
+
parent->val = ID2SYM(rb_intern3(str + 1, len - 1, oj_utf8_encoding));
|
264
232
|
break;
|
265
233
|
case 's':
|
266
|
-
|
267
|
-
parent->val = oj_encode(parent->val);
|
234
|
+
parent->val = rb_utf8_str_new(str, len);
|
268
235
|
break;
|
269
236
|
case 'c': // class
|
270
237
|
{
|
@@ -305,7 +272,7 @@ static int hat_num(ParseInfo pi, Val parent, Val kval, NumInfo ni) {
|
|
305
272
|
}
|
306
273
|
if (86400 == ni->exp) { // UTC time
|
307
274
|
parent->val = rb_time_nano_new(ni->i, (long)nsec);
|
308
|
-
// Since the ruby C routines
|
275
|
+
// Since the ruby C routines always create local time, the
|
309
276
|
// offset and then a conversion to UTC keeps makes the time
|
310
277
|
// match the expected value.
|
311
278
|
parent->val = rb_funcall2(parent->val, oj_utc_id, 0, 0);
|
@@ -416,51 +383,7 @@ static int hat_value(ParseInfo pi, Val parent, const char *key, size_t klen, vol
|
|
416
383
|
}
|
417
384
|
|
418
385
|
void oj_set_obj_ivar(Val parent, Val kval, VALUE value) {
|
419
|
-
|
420
|
-
int klen = kval->klen;
|
421
|
-
ID var_id;
|
422
|
-
ID * slot;
|
423
|
-
|
424
|
-
#ifdef HAVE_PTHREAD_MUTEX_INIT
|
425
|
-
pthread_mutex_lock(&oj_cache_mutex);
|
426
|
-
#else
|
427
|
-
rb_mutex_lock(oj_cache_mutex);
|
428
|
-
#endif
|
429
|
-
if (0 == (var_id = oj_attr_hash_get(key, klen, &slot))) {
|
430
|
-
char attr[256];
|
431
|
-
|
432
|
-
if ((int)sizeof(attr) <= klen + 2) {
|
433
|
-
char *buf = ALLOC_N(char, klen + 2);
|
434
|
-
|
435
|
-
if ('~' == *key) {
|
436
|
-
memcpy(buf, key + 1, klen - 1);
|
437
|
-
buf[klen - 1] = '\0';
|
438
|
-
} else {
|
439
|
-
*buf = '@';
|
440
|
-
memcpy(buf + 1, key, klen);
|
441
|
-
buf[klen + 1] = '\0';
|
442
|
-
}
|
443
|
-
var_id = rb_intern(buf);
|
444
|
-
xfree(buf);
|
445
|
-
} else {
|
446
|
-
if ('~' == *key) {
|
447
|
-
memcpy(attr, key + 1, klen - 1);
|
448
|
-
attr[klen - 1] = '\0';
|
449
|
-
} else {
|
450
|
-
*attr = '@';
|
451
|
-
memcpy(attr + 1, key, klen);
|
452
|
-
attr[klen + 1] = '\0';
|
453
|
-
}
|
454
|
-
var_id = rb_intern(attr);
|
455
|
-
}
|
456
|
-
*slot = var_id;
|
457
|
-
}
|
458
|
-
#ifdef HAVE_PTHREAD_MUTEX_INIT
|
459
|
-
pthread_mutex_unlock(&oj_cache_mutex);
|
460
|
-
#else
|
461
|
-
rb_mutex_unlock(oj_cache_mutex);
|
462
|
-
#endif
|
463
|
-
rb_ivar_set(parent->val, var_id, value);
|
386
|
+
rb_ivar_set(parent->val, oj_attr_intern(kval->key, kval->klen), value);
|
464
387
|
}
|
465
388
|
|
466
389
|
static void hash_set_cstr(ParseInfo pi, Val kval, const char *str, size_t len, const char *orig) {
|