oj 3.12.3 → 3.13.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/README.md +1 -2
- data/ext/oj/buf.h +9 -0
- data/ext/oj/cache.c +187 -0
- data/ext/oj/cache.h +20 -0
- data/ext/oj/compat.c +8 -22
- data/ext/oj/custom.c +13 -12
- data/ext/oj/debug.c +131 -0
- data/ext/oj/dump.c +11 -11
- data/ext/oj/dump_compat.c +3 -3
- data/ext/oj/dump_object.c +7 -7
- data/ext/oj/dump_strict.c +3 -3
- data/ext/oj/err.h +19 -0
- data/ext/oj/extconf.rb +4 -0
- data/ext/oj/hash_test.c +3 -30
- data/ext/oj/intern.c +398 -0
- data/ext/oj/intern.h +27 -0
- data/ext/oj/object.c +10 -58
- data/ext/oj/odd.c +1 -1
- data/ext/oj/oj.c +111 -88
- data/ext/oj/oj.h +1 -1
- data/ext/oj/parse.c +4 -4
- data/ext/oj/parser.c +1527 -0
- data/ext/oj/parser.h +90 -0
- data/ext/oj/rails.c +4 -4
- data/ext/oj/resolve.c +2 -20
- data/ext/oj/saj2.c +346 -0
- data/ext/oj/scp.c +1 -1
- data/ext/oj/sparse.c +1 -1
- data/ext/oj/stream_writer.c +3 -3
- data/ext/oj/strict.c +10 -27
- data/ext/oj/usual.c +1222 -0
- data/ext/oj/validate.c +50 -0
- data/ext/oj/wab.c +9 -17
- data/lib/oj/version.rb +1 -1
- data/pages/Parser.md +309 -0
- data/test/json_gem/json_common_interface_test.rb +1 -1
- data/test/perf_parser.rb +184 -0
- data/test/test_parser.rb +27 -0
- data/test/test_parser_saj.rb +245 -0
- data/test/test_parser_usual.rb +213 -0
- metadata +22 -4
- data/ext/oj/hash.c +0 -168
- data/ext/oj/hash.h +0 -21
data/ext/oj/dump.c
CHANGED
@@ -472,7 +472,7 @@ void oj_dump_time(VALUE obj, Out out, int withZone) {
|
|
472
472
|
void oj_dump_ruby_time(VALUE obj, Out out) {
|
473
473
|
volatile VALUE rstr = rb_funcall(obj, oj_to_s_id, 0);
|
474
474
|
|
475
|
-
oj_dump_cstr(
|
475
|
+
oj_dump_cstr(RSTRING_PTR(rstr), (int)RSTRING_LEN(rstr), 0, 0, out);
|
476
476
|
}
|
477
477
|
|
478
478
|
void oj_dump_xml_time(VALUE obj, Out out) {
|
@@ -708,12 +708,12 @@ void oj_write_obj_to_stream(VALUE obj, VALUE stream, Options copts) {
|
|
708
708
|
}
|
709
709
|
|
710
710
|
void oj_dump_str(VALUE obj, int depth, Out out, bool as_ok) {
|
711
|
-
rb_encoding *enc =
|
711
|
+
rb_encoding *enc = rb_enc_get(obj);
|
712
712
|
|
713
|
-
if (
|
714
|
-
obj = rb_str_conv_enc(obj, enc,
|
713
|
+
if (oj_utf8_encoding != enc) {
|
714
|
+
obj = rb_str_conv_enc(obj, enc, oj_utf8_encoding);
|
715
715
|
}
|
716
|
-
oj_dump_cstr(
|
716
|
+
oj_dump_cstr(RSTRING_PTR(obj), (int)RSTRING_LEN(obj), 0, 0, out);
|
717
717
|
}
|
718
718
|
|
719
719
|
void oj_dump_sym(VALUE obj, int depth, Out out, bool as_ok) {
|
@@ -722,7 +722,7 @@ void oj_dump_sym(VALUE obj, int depth, Out out, bool as_ok) {
|
|
722
722
|
|
723
723
|
volatile VALUE s = rb_sym_to_s(obj);
|
724
724
|
|
725
|
-
oj_dump_cstr(
|
725
|
+
oj_dump_cstr(RSTRING_PTR(s), (int)RSTRING_LEN(s), 0, 0, out);
|
726
726
|
}
|
727
727
|
|
728
728
|
static void debug_raise(const char *orig, size_t cnt, int line) {
|
@@ -760,7 +760,7 @@ void oj_dump_raw_json(VALUE obj, int depth, Out out) {
|
|
760
760
|
if (Yes == out->opts->trace) {
|
761
761
|
oj_trace("raw_json", obj, __FILE__, __LINE__, depth + 1, TraceRubyOut);
|
762
762
|
}
|
763
|
-
oj_dump_raw(
|
763
|
+
oj_dump_raw(RSTRING_PTR(jv), (size_t)RSTRING_LEN(jv), out);
|
764
764
|
}
|
765
765
|
}
|
766
766
|
|
@@ -958,7 +958,7 @@ void oj_dump_class(VALUE obj, int depth, Out out, bool as_ok) {
|
|
958
958
|
void oj_dump_obj_to_s(VALUE obj, Out out) {
|
959
959
|
volatile VALUE rstr = rb_funcall(obj, oj_to_s_id, 0);
|
960
960
|
|
961
|
-
oj_dump_cstr(
|
961
|
+
oj_dump_cstr(RSTRING_PTR(rstr), (int)RSTRING_LEN(rstr), 0, 0, out);
|
962
962
|
}
|
963
963
|
|
964
964
|
void oj_dump_raw(const char *str, size_t cnt, Out out) {
|
@@ -1075,7 +1075,7 @@ void oj_dump_bignum(VALUE obj, int depth, Out out, bool as_ok) {
|
|
1075
1075
|
} else {
|
1076
1076
|
assure_size(out, cnt);
|
1077
1077
|
}
|
1078
|
-
memcpy(out->cur,
|
1078
|
+
memcpy(out->cur, RSTRING_PTR(rs), cnt);
|
1079
1079
|
out->cur += cnt;
|
1080
1080
|
if (dump_as_string) {
|
1081
1081
|
*out->cur++ = '"';
|
@@ -1203,7 +1203,7 @@ void oj_dump_float(VALUE obj, int depth, Out out, bool as_ok) {
|
|
1203
1203
|
if ((int)sizeof(buf) <= cnt) {
|
1204
1204
|
cnt = sizeof(buf) - 1;
|
1205
1205
|
}
|
1206
|
-
memcpy(buf,
|
1206
|
+
memcpy(buf, RSTRING_PTR(rstr), cnt);
|
1207
1207
|
buf[cnt] = '\0';
|
1208
1208
|
} else {
|
1209
1209
|
cnt = oj_dump_float_printf(buf, sizeof(buf), obj, d, out->opts->float_fmt);
|
@@ -1223,7 +1223,7 @@ int oj_dump_float_printf(char *buf, size_t blen, VALUE obj, double d, const char
|
|
1223
1223
|
if (17 <= cnt && (0 == strcmp("0001", buf + cnt - 4) || 0 == strcmp("9999", buf + cnt - 4))) {
|
1224
1224
|
volatile VALUE rstr = rb_funcall(obj, oj_to_s_id, 0);
|
1225
1225
|
|
1226
|
-
strcpy(buf,
|
1226
|
+
strcpy(buf, RSTRING_PTR(rstr));
|
1227
1227
|
cnt = (int)RSTRING_LEN(rstr);
|
1228
1228
|
}
|
1229
1229
|
return cnt;
|
data/ext/oj/dump_compat.c
CHANGED
@@ -129,7 +129,7 @@ dump_to_json(VALUE obj, Out out) {
|
|
129
129
|
oj_trace("to_json", obj, __FILE__, __LINE__, 0, TraceRubyOut);
|
130
130
|
}
|
131
131
|
|
132
|
-
s =
|
132
|
+
s = RSTRING_PTR(rs);
|
133
133
|
len = (int)RSTRING_LEN(rs);
|
134
134
|
|
135
135
|
assure_size(out, len + 1);
|
@@ -635,7 +635,7 @@ dump_float(VALUE obj, int depth, Out out, bool as_ok) {
|
|
635
635
|
} else {
|
636
636
|
volatile VALUE rstr = rb_funcall(obj, oj_to_s_id, 0);
|
637
637
|
|
638
|
-
strcpy(buf,
|
638
|
+
strcpy(buf, RSTRING_PTR(rstr));
|
639
639
|
cnt = (int)RSTRING_LEN(rstr);
|
640
640
|
}
|
641
641
|
assure_size(out, cnt);
|
@@ -886,7 +886,7 @@ dump_bignum(VALUE obj, int depth, Out out, bool as_ok) {
|
|
886
886
|
} else {
|
887
887
|
assure_size(out, cnt);
|
888
888
|
}
|
889
|
-
memcpy(out->cur,
|
889
|
+
memcpy(out->cur, RSTRING_PTR(rs), cnt);
|
890
890
|
out->cur += cnt;
|
891
891
|
if (dump_as_string) {
|
892
892
|
*out->cur++ = '"';
|
data/ext/oj/dump_object.c
CHANGED
@@ -36,7 +36,7 @@ static void dump_data(VALUE obj, int depth, Out out, bool as_ok) {
|
|
36
36
|
} else {
|
37
37
|
if (oj_bigdecimal_class == clas) {
|
38
38
|
volatile VALUE rstr = rb_funcall(obj, oj_to_s_id, 0);
|
39
|
-
const char * str =
|
39
|
+
const char * str = RSTRING_PTR(rstr);
|
40
40
|
int len = (int)RSTRING_LEN(rstr);
|
41
41
|
|
42
42
|
if (No != out->opts->bigdec_as_num) {
|
@@ -65,7 +65,7 @@ static void dump_obj(VALUE obj, int depth, Out out, bool as_ok) {
|
|
65
65
|
|
66
66
|
if (oj_bigdecimal_class == clas) {
|
67
67
|
volatile VALUE rstr = rb_funcall(obj, oj_to_s_id, 0);
|
68
|
-
const char * str =
|
68
|
+
const char * str = RSTRING_PTR(rstr);
|
69
69
|
int len = (int)RSTRING_LEN(rstr);
|
70
70
|
|
71
71
|
if (0 == strcasecmp("Infinity", str)) {
|
@@ -195,7 +195,7 @@ static void dump_str_class(VALUE obj, VALUE clas, int depth, Out out) {
|
|
195
195
|
if (Qundef != clas && rb_cString != clas) {
|
196
196
|
dump_obj_attrs(obj, clas, 0, depth, out);
|
197
197
|
} else {
|
198
|
-
const char *s =
|
198
|
+
const char *s = RSTRING_PTR(obj);
|
199
199
|
size_t len = (int)RSTRING_LEN(obj);
|
200
200
|
char s1 = s[1];
|
201
201
|
|
@@ -210,7 +210,7 @@ static void dump_str(VALUE obj, int depth, Out out, bool as_ok) {
|
|
210
210
|
static void dump_sym(VALUE obj, int depth, Out out, bool as_ok) {
|
211
211
|
volatile VALUE s = rb_sym_to_s(obj);
|
212
212
|
|
213
|
-
oj_dump_cstr(
|
213
|
+
oj_dump_cstr(RSTRING_PTR(s), (int)RSTRING_LEN(s), 1, 0, out);
|
214
214
|
}
|
215
215
|
|
216
216
|
static int hash_cb(VALUE key, VALUE value, VALUE ov) {
|
@@ -414,7 +414,7 @@ static void dump_odd(VALUE obj, Odd odd, VALUE clas, int depth, Out out) {
|
|
414
414
|
if (Qundef == v || T_STRING != rb_type(v)) {
|
415
415
|
rb_raise(rb_eEncodingError, "Invalid type for raw JSON.");
|
416
416
|
} else {
|
417
|
-
const char *s =
|
417
|
+
const char *s = RSTRING_PTR(v);
|
418
418
|
int len = (int)RSTRING_LEN(v);
|
419
419
|
const char *name = rb_id2name(*odd->attrs);
|
420
420
|
size_t nlen = strlen(name);
|
@@ -532,7 +532,7 @@ static void dump_obj_attrs(VALUE obj, VALUE clas, slot_t id, int depth, Out out)
|
|
532
532
|
*out->cur++ = 'f';
|
533
533
|
*out->cur++ = '"';
|
534
534
|
*out->cur++ = ':';
|
535
|
-
oj_dump_cstr(
|
535
|
+
oj_dump_cstr(RSTRING_PTR(obj), (int)RSTRING_LEN(obj), 0, 0, out);
|
536
536
|
break;
|
537
537
|
case T_ARRAY:
|
538
538
|
assure_size(out, d2 * out->indent + 14);
|
@@ -696,7 +696,7 @@ static void dump_struct(VALUE obj, int depth, Out out, bool as_ok) {
|
|
696
696
|
for (i = 0; i < cnt; i++) {
|
697
697
|
volatile VALUE s = rb_sym_to_s(rb_ary_entry(ma, i));
|
698
698
|
|
699
|
-
name =
|
699
|
+
name = RSTRING_PTR(s);
|
700
700
|
len = (int)RSTRING_LEN(s);
|
701
701
|
size = len + 3;
|
702
702
|
assure_size(out, size);
|
data/ext/oj/dump_strict.c
CHANGED
@@ -98,7 +98,7 @@ static void dump_float(VALUE obj, int depth, Out out, bool as_ok) {
|
|
98
98
|
if ((int)sizeof(buf) <= cnt) {
|
99
99
|
cnt = sizeof(buf) - 1;
|
100
100
|
}
|
101
|
-
memcpy(buf,
|
101
|
+
memcpy(buf, RSTRING_PTR(rstr), cnt);
|
102
102
|
buf[cnt] = '\0';
|
103
103
|
} else {
|
104
104
|
cnt = oj_dump_float_printf(buf, sizeof(buf), obj, d, out->opts->float_fmt);
|
@@ -304,7 +304,7 @@ static void dump_data_strict(VALUE obj, int depth, Out out, bool as_ok) {
|
|
304
304
|
if (oj_bigdecimal_class == clas) {
|
305
305
|
volatile VALUE rstr = rb_funcall(obj, oj_to_s_id, 0);
|
306
306
|
|
307
|
-
oj_dump_raw(
|
307
|
+
oj_dump_raw(RSTRING_PTR(rstr), (int)RSTRING_LEN(rstr), out);
|
308
308
|
} else {
|
309
309
|
raise_strict(obj);
|
310
310
|
}
|
@@ -316,7 +316,7 @@ static void dump_data_null(VALUE obj, int depth, Out out, bool as_ok) {
|
|
316
316
|
if (oj_bigdecimal_class == clas) {
|
317
317
|
volatile VALUE rstr = rb_funcall(obj, oj_to_s_id, 0);
|
318
318
|
|
319
|
-
oj_dump_raw(
|
319
|
+
oj_dump_raw(RSTRING_PTR(rstr), (int)RSTRING_LEN(rstr), out);
|
320
320
|
} else {
|
321
321
|
oj_dump_nil(Qnil, depth, out, false);
|
322
322
|
}
|
data/ext/oj/err.h
CHANGED
@@ -4,12 +4,31 @@
|
|
4
4
|
#ifndef OJ_ERR_H
|
5
5
|
#define OJ_ERR_H
|
6
6
|
|
7
|
+
#include <errno.h>
|
7
8
|
#include "ruby.h"
|
9
|
+
|
8
10
|
// Needed to silence 2.4.0 warnings.
|
9
11
|
#ifndef NORETURN
|
10
12
|
#define NORETURN(x) x
|
11
13
|
#endif
|
12
14
|
|
15
|
+
#define OJ_ERR_START 300
|
16
|
+
|
17
|
+
typedef enum {
|
18
|
+
OJ_OK = 0,
|
19
|
+
OJ_ERR_MEMORY = ENOMEM,
|
20
|
+
OJ_ERR_PARSE = OJ_ERR_START,
|
21
|
+
OJ_ERR_READ,
|
22
|
+
OJ_ERR_WRITE,
|
23
|
+
OJ_ERR_OVERFLOW,
|
24
|
+
OJ_ERR_ARG,
|
25
|
+
OJ_ERR_TOO_MANY,
|
26
|
+
OJ_ERR_TYPE,
|
27
|
+
OJ_ERR_KEY,
|
28
|
+
OJ_ABORT,
|
29
|
+
OJ_ERR_LAST,
|
30
|
+
} ojStatus;
|
31
|
+
|
13
32
|
#define set_error(err, eclas, msg, json, current) \
|
14
33
|
_oj_err_set_with_location(err, eclas, msg, json, current, FILE, LINE)
|
15
34
|
|
data/ext/oj/extconf.rb
CHANGED
@@ -30,6 +30,10 @@ 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_ext_ractor_safe', 'ruby.h')
|
35
|
+
# rb_hash_bulk_insert is deep down in a header not included in normal build and that seems to fool have_func.
|
36
|
+
have_func('rb_hash_bulk_insert', 'ruby.h') unless '2' == version[0] && '6' == version[1]
|
33
37
|
|
34
38
|
dflags['OJ_DEBUG'] = true unless ENV['OJ_DEBUG'].nil?
|
35
39
|
|
data/ext/oj/hash_test.c
CHANGED
@@ -3,7 +3,7 @@
|
|
3
3
|
|
4
4
|
// if windows, comment out the whole file. It's only a performance test.
|
5
5
|
#ifndef _WIN32
|
6
|
-
#include "
|
6
|
+
#include "intern.h"
|
7
7
|
|
8
8
|
#include <stdint.h>
|
9
9
|
#include <sys/time.h>
|
@@ -424,8 +424,6 @@ static uint64_t micro_time() {
|
|
424
424
|
|
425
425
|
static void perf() {
|
426
426
|
StrLen d;
|
427
|
-
VALUE v;
|
428
|
-
VALUE * slot = 0;
|
429
427
|
uint64_t dt, start;
|
430
428
|
int i, iter = 1000000;
|
431
429
|
int dataCnt = sizeof(data) / sizeof(*data);
|
@@ -434,13 +432,7 @@ static void perf() {
|
|
434
432
|
start = micro_time();
|
435
433
|
for (i = iter; 0 < i; i--) {
|
436
434
|
for (d = data; 0 != d->str; d++) {
|
437
|
-
|
438
|
-
if (Qundef == v) {
|
439
|
-
if (0 != slot) {
|
440
|
-
v = ID2SYM(rb_intern(d->str));
|
441
|
-
*slot = v;
|
442
|
-
}
|
443
|
-
}
|
435
|
+
oj_class_intern(d->str, d->len, false, NULL, false, Qnil);
|
444
436
|
}
|
445
437
|
}
|
446
438
|
dt = micro_time() - start;
|
@@ -459,29 +451,10 @@ static void perf() {
|
|
459
451
|
|
460
452
|
void oj_hash_test() {
|
461
453
|
StrLen d;
|
462
|
-
VALUE v;
|
463
|
-
VALUE *slot = 0;
|
464
|
-
;
|
465
454
|
|
466
455
|
oj_hash_init();
|
467
456
|
for (d = data; 0 != d->str; d++) {
|
468
|
-
|
469
|
-
v = oj_class_hash_get(d->str, d->len, &slot);
|
470
|
-
if (Qnil == v) {
|
471
|
-
if (0 == slot) {
|
472
|
-
printf("*** failed to get a slot for %s\n", s);
|
473
|
-
} else {
|
474
|
-
v = ID2SYM(rb_intern(d->str));
|
475
|
-
*slot = v;
|
476
|
-
}
|
477
|
-
} else {
|
478
|
-
VALUE rs = rb_funcall2(v, rb_intern("to_s"), 0, 0);
|
479
|
-
|
480
|
-
printf("*** get on '%s' returned '%s' (%s)\n",
|
481
|
-
s,
|
482
|
-
StringValuePtr(rs),
|
483
|
-
rb_class2name(rb_obj_class(v)));
|
484
|
-
}
|
457
|
+
oj_class_intern(d->str, d->len, false, NULL, false, Qnil);
|
485
458
|
/*oj_hash_print(c);*/
|
486
459
|
}
|
487
460
|
printf("*** ---------- hash table ------------\n");
|
data/ext/oj/intern.c
ADDED
@@ -0,0 +1,398 @@
|
|
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 "parse.h"
|
12
|
+
|
13
|
+
#define HASH_SLOT_CNT ((uint32_t)8192)
|
14
|
+
#define HASH_MASK (HASH_SLOT_CNT - 1)
|
15
|
+
|
16
|
+
typedef struct _keyVal {
|
17
|
+
struct _keyVal *next;
|
18
|
+
const char * key;
|
19
|
+
size_t len;
|
20
|
+
VALUE val;
|
21
|
+
} * KeyVal;
|
22
|
+
|
23
|
+
typedef struct _hash {
|
24
|
+
struct _keyVal slots[HASH_SLOT_CNT];
|
25
|
+
#if HAVE_PTHREAD_MUTEX_INIT
|
26
|
+
pthread_mutex_t mutex;
|
27
|
+
#else
|
28
|
+
VALUE mutex;
|
29
|
+
#endif
|
30
|
+
} * Hash;
|
31
|
+
|
32
|
+
struct _hash class_hash;
|
33
|
+
struct _hash str_hash;
|
34
|
+
struct _hash sym_hash;
|
35
|
+
struct _hash attr_hash;
|
36
|
+
|
37
|
+
// almost the Murmur hash algorithm
|
38
|
+
#define M 0x5bd1e995
|
39
|
+
#define C1 0xCC9E2D51
|
40
|
+
#define C2 0x1B873593
|
41
|
+
#define N 0xE6546B64
|
42
|
+
|
43
|
+
static uint32_t hash_calc(const uint8_t *key, size_t len) {
|
44
|
+
const uint8_t *end = key + len;
|
45
|
+
const uint8_t *endless = key + (len & 0xFFFFFFFC);
|
46
|
+
uint32_t h = (uint32_t)len;
|
47
|
+
uint32_t k;
|
48
|
+
|
49
|
+
while (key < endless) {
|
50
|
+
k = (uint32_t)*key++;
|
51
|
+
k |= (uint32_t)*key++ << 8;
|
52
|
+
k |= (uint32_t)*key++ << 16;
|
53
|
+
k |= (uint32_t)*key++ << 24;
|
54
|
+
|
55
|
+
k *= M;
|
56
|
+
k ^= k >> 24;
|
57
|
+
h *= M;
|
58
|
+
h ^= k * M;
|
59
|
+
}
|
60
|
+
if (1 < end - key) {
|
61
|
+
uint16_t k16 = (uint16_t)*key++;
|
62
|
+
|
63
|
+
k16 |= (uint16_t)*key++ << 8;
|
64
|
+
h ^= k16 << 8;
|
65
|
+
}
|
66
|
+
if (key < end) {
|
67
|
+
h ^= *key;
|
68
|
+
}
|
69
|
+
h *= M;
|
70
|
+
h ^= h >> 13;
|
71
|
+
h *= M;
|
72
|
+
h ^= h >> 15;
|
73
|
+
|
74
|
+
return h;
|
75
|
+
}
|
76
|
+
|
77
|
+
void oj_hash_init() {
|
78
|
+
memset(class_hash.slots, 0, sizeof(class_hash.slots));
|
79
|
+
memset(str_hash.slots, 0, sizeof(str_hash.slots));
|
80
|
+
memset(sym_hash.slots, 0, sizeof(sym_hash.slots));
|
81
|
+
memset(attr_hash.slots, 0, sizeof(attr_hash.slots));
|
82
|
+
#if HAVE_PTHREAD_MUTEX_INIT
|
83
|
+
pthread_mutex_init(&class_hash.mutex, NULL);
|
84
|
+
pthread_mutex_init(&str_hash.mutex, NULL);
|
85
|
+
pthread_mutex_init(&sym_hash.mutex, NULL);
|
86
|
+
pthread_mutex_init(&attr_hash.mutex, NULL);
|
87
|
+
#else
|
88
|
+
class_hash.mutex = rb_mutex_new();
|
89
|
+
rb_gc_register_address(&class_hash.mutex);
|
90
|
+
str_hash.mutex = rb_mutex_new();
|
91
|
+
rb_gc_register_address(&str_hash.mutex);
|
92
|
+
sym_hash.mutex = rb_mutex_new();
|
93
|
+
rb_gc_register_address(&sym_hash.mutex);
|
94
|
+
attr_hash.mutex = rb_mutex_new();
|
95
|
+
rb_gc_register_address(&attr_hash.mutex);
|
96
|
+
#endif
|
97
|
+
}
|
98
|
+
|
99
|
+
void oj_hash_print() {
|
100
|
+
uint32_t i;
|
101
|
+
KeyVal b;
|
102
|
+
|
103
|
+
for (i = 0; i < HASH_SLOT_CNT; i++) {
|
104
|
+
printf("%4d:", i);
|
105
|
+
for (b = class_hash.slots + i; 0 != b && 0 != b->key; b = b->next) {
|
106
|
+
printf(" %s", b->key);
|
107
|
+
}
|
108
|
+
printf("\n");
|
109
|
+
}
|
110
|
+
}
|
111
|
+
|
112
|
+
void oj_hash_sizes() {
|
113
|
+
uint32_t i;
|
114
|
+
KeyVal b;
|
115
|
+
int max = 0;
|
116
|
+
int min = 1000000;
|
117
|
+
|
118
|
+
for (i = 0; i < HASH_SLOT_CNT; i++) {
|
119
|
+
int cnt = 0;
|
120
|
+
|
121
|
+
for (b = str_hash.slots + i; 0 != b && 0 != b->key; b = b->next) {
|
122
|
+
cnt++;
|
123
|
+
}
|
124
|
+
// printf(" %4d\n", cnt);
|
125
|
+
if (max < cnt) {
|
126
|
+
max = cnt;
|
127
|
+
}
|
128
|
+
if (cnt < min) {
|
129
|
+
min = cnt;
|
130
|
+
}
|
131
|
+
}
|
132
|
+
printf("min: %d max: %d\n", min, max);
|
133
|
+
}
|
134
|
+
|
135
|
+
VALUE
|
136
|
+
oj_str_intern(const char *key, size_t len) {
|
137
|
+
uint32_t h = hash_calc((const uint8_t *)key, len) & HASH_MASK;
|
138
|
+
KeyVal bucket = str_hash.slots + h;
|
139
|
+
KeyVal b;
|
140
|
+
|
141
|
+
#if HAVE_PTHREAD_MUTEX_INIT
|
142
|
+
pthread_mutex_lock(&str_hash.mutex);
|
143
|
+
#else
|
144
|
+
rb_mutex_lock(str_hash.mutex);
|
145
|
+
#endif
|
146
|
+
if (NULL != bucket->key) { // not the top slot
|
147
|
+
for (b = bucket; 0 != b; b = b->next) {
|
148
|
+
if (len == b->len && 0 == strncmp(b->key, key, len)) {
|
149
|
+
#if HAVE_PTHREAD_MUTEX_INIT
|
150
|
+
pthread_mutex_unlock(&str_hash.mutex);
|
151
|
+
#else
|
152
|
+
rb_mutex_unlock(str_hash.mutex);
|
153
|
+
#endif
|
154
|
+
return b->val;
|
155
|
+
}
|
156
|
+
bucket = b;
|
157
|
+
}
|
158
|
+
b = ALLOC(struct _keyVal);
|
159
|
+
b->next = NULL;
|
160
|
+
bucket->next = b;
|
161
|
+
bucket = b;
|
162
|
+
}
|
163
|
+
bucket->key = oj_strndup(key, len);
|
164
|
+
bucket->len = len;
|
165
|
+
bucket->val = rb_utf8_str_new(key, len);
|
166
|
+
bucket->val = rb_str_freeze(bucket->val);
|
167
|
+
rb_gc_register_address(&bucket->val);
|
168
|
+
#if HAVE_PTHREAD_MUTEX_INIT
|
169
|
+
pthread_mutex_unlock(&str_hash.mutex);
|
170
|
+
#else
|
171
|
+
rb_mutex_unlock(str_hash.mutex);
|
172
|
+
#endif
|
173
|
+
return bucket->val;
|
174
|
+
}
|
175
|
+
|
176
|
+
VALUE
|
177
|
+
oj_sym_intern(const char *key, size_t len) {
|
178
|
+
uint32_t h = hash_calc((const uint8_t *)key, len) & HASH_MASK;
|
179
|
+
KeyVal bucket = sym_hash.slots + h;
|
180
|
+
KeyVal b;
|
181
|
+
|
182
|
+
#if HAVE_PTHREAD_MUTEX_INIT
|
183
|
+
pthread_mutex_lock(&sym_hash.mutex);
|
184
|
+
#else
|
185
|
+
rb_mutex_lock(sym_hash.mutex);
|
186
|
+
#endif
|
187
|
+
if (NULL != bucket->key) { // not the top slot
|
188
|
+
for (b = bucket; 0 != b; b = b->next) {
|
189
|
+
if (len == b->len && 0 == strncmp(b->key, key, len)) {
|
190
|
+
#if HAVE_PTHREAD_MUTEX_INIT
|
191
|
+
pthread_mutex_unlock(&sym_hash.mutex);
|
192
|
+
#else
|
193
|
+
rb_mutex_unlock(sym_hash.mutex);
|
194
|
+
#endif
|
195
|
+
return b->val;
|
196
|
+
}
|
197
|
+
bucket = b;
|
198
|
+
}
|
199
|
+
b = ALLOC(struct _keyVal);
|
200
|
+
b->next = NULL;
|
201
|
+
bucket->next = b;
|
202
|
+
bucket = b;
|
203
|
+
}
|
204
|
+
bucket->key = oj_strndup(key, len);
|
205
|
+
bucket->len = len;
|
206
|
+
bucket->val = ID2SYM(rb_intern3(key, len, oj_utf8_encoding));
|
207
|
+
rb_gc_register_address(&bucket->val);
|
208
|
+
#if HAVE_PTHREAD_MUTEX_INIT
|
209
|
+
pthread_mutex_unlock(&sym_hash.mutex);
|
210
|
+
#else
|
211
|
+
rb_mutex_unlock(sym_hash.mutex);
|
212
|
+
#endif
|
213
|
+
return bucket->val;
|
214
|
+
}
|
215
|
+
|
216
|
+
static ID form_attr(const char *key, size_t klen) {
|
217
|
+
char attr[256];
|
218
|
+
ID var_id;
|
219
|
+
|
220
|
+
if ((int)sizeof(attr) <= klen + 2) {
|
221
|
+
char *buf = ALLOC_N(char, klen + 2);
|
222
|
+
|
223
|
+
if ('~' == *key) {
|
224
|
+
memcpy(buf, key + 1, klen - 1);
|
225
|
+
buf[klen - 1] = '\0';
|
226
|
+
} else {
|
227
|
+
*buf = '@';
|
228
|
+
memcpy(buf + 1, key, klen);
|
229
|
+
buf[klen + 1] = '\0';
|
230
|
+
}
|
231
|
+
var_id = rb_intern(buf);
|
232
|
+
xfree(buf);
|
233
|
+
} else {
|
234
|
+
if ('~' == *key) {
|
235
|
+
memcpy(attr, key + 1, klen - 1);
|
236
|
+
attr[klen - 1] = '\0';
|
237
|
+
} else {
|
238
|
+
*attr = '@';
|
239
|
+
memcpy(attr + 1, key, klen);
|
240
|
+
attr[klen + 1] = '\0';
|
241
|
+
}
|
242
|
+
var_id = rb_intern(attr);
|
243
|
+
}
|
244
|
+
return var_id;
|
245
|
+
}
|
246
|
+
|
247
|
+
ID oj_attr_intern(const char *key, size_t len) {
|
248
|
+
uint32_t h = hash_calc((const uint8_t *)key, len) & HASH_MASK;
|
249
|
+
KeyVal bucket = attr_hash.slots + h;
|
250
|
+
KeyVal b;
|
251
|
+
|
252
|
+
#if HAVE_PTHREAD_MUTEX_INIT
|
253
|
+
pthread_mutex_lock(&attr_hash.mutex);
|
254
|
+
#else
|
255
|
+
rb_mutex_lock(attr_hash.mutex);
|
256
|
+
#endif
|
257
|
+
if (NULL != bucket->key) { // not the top slot
|
258
|
+
for (b = bucket; 0 != b; b = b->next) {
|
259
|
+
if (len == b->len && 0 == strncmp(b->key, key, len)) {
|
260
|
+
#if HAVE_PTHREAD_MUTEX_INIT
|
261
|
+
pthread_mutex_unlock(&attr_hash.mutex);
|
262
|
+
#else
|
263
|
+
rb_mutex_unlock(attr_hash.mutex);
|
264
|
+
#endif
|
265
|
+
return (ID)b->val;
|
266
|
+
}
|
267
|
+
bucket = b;
|
268
|
+
}
|
269
|
+
b = ALLOC(struct _keyVal);
|
270
|
+
b->next = NULL;
|
271
|
+
bucket->next = b;
|
272
|
+
bucket = b;
|
273
|
+
}
|
274
|
+
bucket->key = oj_strndup(key, len);
|
275
|
+
bucket->len = len;
|
276
|
+
bucket->val = (VALUE)form_attr(key, len);
|
277
|
+
#if HAVE_PTHREAD_MUTEX_INIT
|
278
|
+
pthread_mutex_unlock(&attr_hash.mutex);
|
279
|
+
#else
|
280
|
+
rb_mutex_unlock(attr_hash.mutex);
|
281
|
+
#endif
|
282
|
+
return (ID)bucket->val;
|
283
|
+
}
|
284
|
+
|
285
|
+
static VALUE resolve_classname(VALUE mod, const char *classname, int auto_define) {
|
286
|
+
VALUE clas;
|
287
|
+
ID ci = rb_intern(classname);
|
288
|
+
|
289
|
+
if (rb_const_defined_at(mod, ci)) {
|
290
|
+
clas = rb_const_get_at(mod, ci);
|
291
|
+
} else if (auto_define) {
|
292
|
+
clas = rb_define_class_under(mod, classname, oj_bag_class);
|
293
|
+
} else {
|
294
|
+
clas = Qundef;
|
295
|
+
}
|
296
|
+
return clas;
|
297
|
+
}
|
298
|
+
|
299
|
+
static VALUE resolve_classpath(ParseInfo pi, const char *name, size_t len, int auto_define, VALUE error_class) {
|
300
|
+
char class_name[1024];
|
301
|
+
VALUE clas;
|
302
|
+
char * end = class_name + sizeof(class_name) - 1;
|
303
|
+
char * s;
|
304
|
+
const char *n = name;
|
305
|
+
|
306
|
+
clas = rb_cObject;
|
307
|
+
for (s = class_name; 0 < len; n++, len--) {
|
308
|
+
if (':' == *n) {
|
309
|
+
*s = '\0';
|
310
|
+
n++;
|
311
|
+
len--;
|
312
|
+
if (':' != *n) {
|
313
|
+
return Qundef;
|
314
|
+
}
|
315
|
+
if (Qundef == (clas = resolve_classname(clas, class_name, auto_define))) {
|
316
|
+
return Qundef;
|
317
|
+
}
|
318
|
+
s = class_name;
|
319
|
+
} else if (end <= s) {
|
320
|
+
return Qundef;
|
321
|
+
} else {
|
322
|
+
*s++ = *n;
|
323
|
+
}
|
324
|
+
}
|
325
|
+
*s = '\0';
|
326
|
+
if (Qundef == (clas = resolve_classname(clas, class_name, auto_define))) {
|
327
|
+
oj_set_error_at(pi, error_class, __FILE__, __LINE__, "class %s is not defined", name);
|
328
|
+
if (Qnil != error_class) {
|
329
|
+
pi->err_class = error_class;
|
330
|
+
}
|
331
|
+
}
|
332
|
+
return clas;
|
333
|
+
}
|
334
|
+
|
335
|
+
VALUE oj_class_intern(const char *key, size_t len, bool safe, ParseInfo pi, int auto_define, VALUE error_class) {
|
336
|
+
uint32_t h = hash_calc((const uint8_t *)key, len) & HASH_MASK;
|
337
|
+
KeyVal bucket = class_hash.slots + h;
|
338
|
+
KeyVal b;
|
339
|
+
|
340
|
+
if (safe) {
|
341
|
+
#if HAVE_PTHREAD_MUTEX_INIT
|
342
|
+
pthread_mutex_lock(&class_hash.mutex);
|
343
|
+
#else
|
344
|
+
rb_mutex_lock(class_hash.mutex);
|
345
|
+
#endif
|
346
|
+
if (NULL != bucket->key) { // not the top slot
|
347
|
+
for (b = bucket; 0 != b; b = b->next) {
|
348
|
+
if (len == b->len && 0 == strncmp(b->key, key, len)) {
|
349
|
+
#if HAVE_PTHREAD_MUTEX_INIT
|
350
|
+
pthread_mutex_unlock(&class_hash.mutex);
|
351
|
+
#else
|
352
|
+
rb_mutex_unlock(class_hash.mutex);
|
353
|
+
#endif
|
354
|
+
return b->val;
|
355
|
+
}
|
356
|
+
bucket = b;
|
357
|
+
}
|
358
|
+
b = ALLOC(struct _keyVal);
|
359
|
+
b->next = NULL;
|
360
|
+
bucket->next = b;
|
361
|
+
bucket = b;
|
362
|
+
}
|
363
|
+
bucket->key = oj_strndup(key, len);
|
364
|
+
bucket->len = len;
|
365
|
+
bucket->val = resolve_classpath(pi, key, len, auto_define, error_class);
|
366
|
+
#if HAVE_PTHREAD_MUTEX_INIT
|
367
|
+
pthread_mutex_unlock(&class_hash.mutex);
|
368
|
+
#else
|
369
|
+
rb_mutex_unlock(class_hash.mutex);
|
370
|
+
#endif
|
371
|
+
} else {
|
372
|
+
if (NULL != bucket->key) {
|
373
|
+
for (b = bucket; 0 != b; b = b->next) {
|
374
|
+
if (len == b->len && 0 == strncmp(b->key, key, len)) {
|
375
|
+
return (ID)b->val;
|
376
|
+
}
|
377
|
+
bucket = b;
|
378
|
+
}
|
379
|
+
b = ALLOC(struct _keyVal);
|
380
|
+
b->next = NULL;
|
381
|
+
bucket->next = b;
|
382
|
+
bucket = b;
|
383
|
+
}
|
384
|
+
bucket->key = oj_strndup(key, len);
|
385
|
+
bucket->len = len;
|
386
|
+
bucket->val = resolve_classpath(pi, key, len, auto_define, error_class);
|
387
|
+
}
|
388
|
+
return bucket->val;
|
389
|
+
}
|
390
|
+
|
391
|
+
char *oj_strndup(const char *s, size_t len) {
|
392
|
+
char *d = ALLOC_N(char, len + 1);
|
393
|
+
|
394
|
+
memcpy(d, s, len);
|
395
|
+
d[len] = '\0';
|
396
|
+
|
397
|
+
return d;
|
398
|
+
}
|