oj 3.12.3 → 3.13.0

Sign up to get free protection for your applications and to get access to all the features.
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(rb_string_value_ptr((VALUE *)&rstr), (int)RSTRING_LEN(rstr), 0, 0, out);
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 = rb_to_encoding(rb_obj_encoding(obj));
711
+ rb_encoding *enc = rb_enc_get(obj);
712
712
 
713
- if (rb_utf8_encoding() != enc) {
714
- obj = rb_str_conv_enc(obj, enc, rb_utf8_encoding());
713
+ if (oj_utf8_encoding != enc) {
714
+ obj = rb_str_conv_enc(obj, enc, oj_utf8_encoding);
715
715
  }
716
- oj_dump_cstr(rb_string_value_ptr((VALUE *)&obj), (int)RSTRING_LEN(obj), 0, 0, out);
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(rb_string_value_ptr((VALUE *)&s), (int)RSTRING_LEN(s), 0, 0, out);
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(rb_string_value_ptr((VALUE *)&jv), (size_t)RSTRING_LEN(jv), out);
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(rb_string_value_ptr((VALUE *)&rstr), (int)RSTRING_LEN(rstr), 0, 0, out);
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, rb_string_value_ptr((VALUE *)&rs), cnt);
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, rb_string_value_ptr((VALUE *)&rstr), cnt);
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, rb_string_value_ptr((VALUE *)&rstr));
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 = rb_string_value_ptr((VALUE*)&rs);
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, rb_string_value_ptr((VALUE*)&rstr));
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, rb_string_value_ptr((VALUE*)&rs), cnt);
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 = rb_string_value_ptr((VALUE *)&rstr);
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 = rb_string_value_ptr((VALUE *)&rstr);
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 = rb_string_value_ptr((VALUE *)&obj);
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(rb_string_value_ptr((VALUE *)&s), (int)RSTRING_LEN(s), 1, 0, out);
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 = rb_string_value_ptr((VALUE *)&v);
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(rb_string_value_ptr((VALUE *)&obj), (int)RSTRING_LEN(obj), 0, 0, out);
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 = rb_string_value_ptr((VALUE *)&s);
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, rb_string_value_ptr((VALUE *)&rstr), cnt);
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(rb_string_value_ptr((VALUE *)&rstr), (int)RSTRING_LEN(rstr), out);
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(rb_string_value_ptr((VALUE *)&rstr), (int)RSTRING_LEN(rstr), out);
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 "hash.h"
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
- v = oj_class_hash_get(d->str, d->len, &slot);
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
- char *s = oj_strndup(d->str, d->len);
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
+ }