oj 3.12.0 → 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.
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) {
@@ -535,59 +535,57 @@ void oj_dump_xml_time(VALUE obj, Out out) {
535
535
  }
536
536
  if ((0 == nsec && !out->opts->sec_prec_set) || 0 == out->opts->sec_prec) {
537
537
  if (0 == tzsecs && rb_funcall2(obj, oj_utcq_id, 0, 0)) {
538
- sprintf(buf,
539
- "%04d-%02d-%02dT%02d:%02d:%02dZ",
540
- ti.year,
541
- ti.mon,
542
- ti.day,
543
- ti.hour,
544
- ti.min,
545
- ti.sec);
546
- oj_dump_cstr(buf, 20, 0, 0, out);
538
+ int len = sprintf(buf,
539
+ "%04d-%02d-%02dT%02d:%02d:%02dZ",
540
+ ti.year,
541
+ ti.mon,
542
+ ti.day,
543
+ ti.hour,
544
+ ti.min,
545
+ ti.sec);
546
+ oj_dump_cstr(buf, len, 0, 0, out);
547
547
  } else {
548
- sprintf(buf,
549
- "%04d-%02d-%02dT%02d:%02d:%02d%c%02d:%02d",
550
- ti.year,
551
- ti.mon,
552
- ti.day,
553
- ti.hour,
554
- ti.min,
555
- ti.sec,
556
- tzsign,
557
- tzhour,
558
- tzmin);
559
- oj_dump_cstr(buf, 25, 0, 0, out);
548
+ int len = sprintf(buf,
549
+ "%04d-%02d-%02dT%02d:%02d:%02d%c%02d:%02d",
550
+ ti.year,
551
+ ti.mon,
552
+ ti.day,
553
+ ti.hour,
554
+ ti.min,
555
+ ti.sec,
556
+ tzsign,
557
+ tzhour,
558
+ tzmin);
559
+ oj_dump_cstr(buf, len, 0, 0, out);
560
560
  }
561
561
  } else if (0 == tzsecs && rb_funcall2(obj, oj_utcq_id, 0, 0)) {
562
562
  char format[64] = "%04d-%02d-%02dT%02d:%02d:%02d.%09ldZ";
563
- int len = 30;
563
+ int len;
564
564
 
565
565
  if (9 > out->opts->sec_prec) {
566
566
  format[32] = '0' + out->opts->sec_prec;
567
- len -= 9 - out->opts->sec_prec;
568
567
  }
569
- sprintf(buf, format, ti.year, ti.mon, ti.day, ti.hour, ti.min, ti.sec, (long)nsec);
568
+ len = sprintf(buf, format, ti.year, ti.mon, ti.day, ti.hour, ti.min, ti.sec, (long)nsec);
570
569
  oj_dump_cstr(buf, len, 0, 0, out);
571
570
  } else {
572
571
  char format[64] = "%04d-%02d-%02dT%02d:%02d:%02d.%09ld%c%02d:%02d";
573
- int len = 35;
572
+ int len;
574
573
 
575
574
  if (9 > out->opts->sec_prec) {
576
575
  format[32] = '0' + out->opts->sec_prec;
577
- len -= 9 - out->opts->sec_prec;
578
576
  }
579
- sprintf(buf,
580
- format,
581
- ti.year,
582
- ti.mon,
583
- ti.day,
584
- ti.hour,
585
- ti.min,
586
- ti.sec,
587
- (long)nsec,
588
- tzsign,
589
- tzhour,
590
- tzmin);
577
+ len = sprintf(buf,
578
+ format,
579
+ ti.year,
580
+ ti.mon,
581
+ ti.day,
582
+ ti.hour,
583
+ ti.min,
584
+ ti.sec,
585
+ (long)nsec,
586
+ tzsign,
587
+ tzhour,
588
+ tzmin);
591
589
  oj_dump_cstr(buf, len, 0, 0, out);
592
590
  }
593
591
  }
@@ -710,12 +708,12 @@ void oj_write_obj_to_stream(VALUE obj, VALUE stream, Options copts) {
710
708
  }
711
709
 
712
710
  void oj_dump_str(VALUE obj, int depth, Out out, bool as_ok) {
713
- rb_encoding *enc = rb_to_encoding(rb_obj_encoding(obj));
711
+ rb_encoding *enc = rb_enc_get(obj);
714
712
 
715
- if (rb_utf8_encoding() != enc) {
716
- 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);
717
715
  }
718
- 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);
719
717
  }
720
718
 
721
719
  void oj_dump_sym(VALUE obj, int depth, Out out, bool as_ok) {
@@ -724,7 +722,7 @@ void oj_dump_sym(VALUE obj, int depth, Out out, bool as_ok) {
724
722
 
725
723
  volatile VALUE s = rb_sym_to_s(obj);
726
724
 
727
- 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);
728
726
  }
729
727
 
730
728
  static void debug_raise(const char *orig, size_t cnt, int line) {
@@ -762,7 +760,7 @@ void oj_dump_raw_json(VALUE obj, int depth, Out out) {
762
760
  if (Yes == out->opts->trace) {
763
761
  oj_trace("raw_json", obj, __FILE__, __LINE__, depth + 1, TraceRubyOut);
764
762
  }
765
- 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);
766
764
  }
767
765
  }
768
766
 
@@ -827,9 +825,8 @@ void oj_dump_cstr(const char *str, size_t cnt, bool is_sym, bool escape1, Out ou
827
825
  if (is_sym) {
828
826
  *out->cur++ = ':';
829
827
  }
830
- for (; '\0' != *str; str++) {
831
- *out->cur++ = *str;
832
- }
828
+ memcpy(out->cur, str, cnt);
829
+ out->cur += cnt;
833
830
  *out->cur++ = '"';
834
831
  } else {
835
832
  const char *end = str + cnt;
@@ -961,7 +958,7 @@ void oj_dump_class(VALUE obj, int depth, Out out, bool as_ok) {
961
958
  void oj_dump_obj_to_s(VALUE obj, Out out) {
962
959
  volatile VALUE rstr = rb_funcall(obj, oj_to_s_id, 0);
963
960
 
964
- 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);
965
962
  }
966
963
 
967
964
  void oj_dump_raw(const char *str, size_t cnt, Out out) {
@@ -1078,7 +1075,7 @@ void oj_dump_bignum(VALUE obj, int depth, Out out, bool as_ok) {
1078
1075
  } else {
1079
1076
  assure_size(out, cnt);
1080
1077
  }
1081
- memcpy(out->cur, rb_string_value_ptr((VALUE *)&rs), cnt);
1078
+ memcpy(out->cur, RSTRING_PTR(rs), cnt);
1082
1079
  out->cur += cnt;
1083
1080
  if (dump_as_string) {
1084
1081
  *out->cur++ = '"';
@@ -1206,7 +1203,7 @@ void oj_dump_float(VALUE obj, int depth, Out out, bool as_ok) {
1206
1203
  if ((int)sizeof(buf) <= cnt) {
1207
1204
  cnt = sizeof(buf) - 1;
1208
1205
  }
1209
- strncpy(buf, rb_string_value_ptr((VALUE *)&rstr), cnt);
1206
+ memcpy(buf, RSTRING_PTR(rstr), cnt);
1210
1207
  buf[cnt] = '\0';
1211
1208
  } else {
1212
1209
  cnt = oj_dump_float_printf(buf, sizeof(buf), obj, d, out->opts->float_fmt);
@@ -1226,7 +1223,7 @@ int oj_dump_float_printf(char *buf, size_t blen, VALUE obj, double d, const char
1226
1223
  if (17 <= cnt && (0 == strcmp("0001", buf + cnt - 4) || 0 == strcmp("9999", buf + cnt - 4))) {
1227
1224
  volatile VALUE rstr = rb_funcall(obj, oj_to_s_id, 0);
1228
1225
 
1229
- strcpy(buf, rb_string_value_ptr((VALUE *)&rstr));
1226
+ strcpy(buf, RSTRING_PTR(rstr));
1230
1227
  cnt = (int)RSTRING_LEN(rstr);
1231
1228
  }
1232
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
- strncpy(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
+ }