oj 3.12.1 → 3.13.1

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) {
@@ -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,21 +708,18 @@ 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) {
722
- // This causes a memory leak in 2.5.1. Maybe in other versions as well.
723
- // const char *sym = rb_id2name(SYM2ID(obj));
720
+ volatile VALUE s = rb_sym2str(obj);
724
721
 
725
- volatile VALUE s = rb_sym_to_s(obj);
726
-
727
- oj_dump_cstr(rb_string_value_ptr((VALUE *)&s), (int)RSTRING_LEN(s), 0, 0, out);
722
+ oj_dump_cstr(RSTRING_PTR(s), (int)RSTRING_LEN(s), 0, 0, out);
728
723
  }
729
724
 
730
725
  static void debug_raise(const char *orig, size_t cnt, int line) {
@@ -762,7 +757,7 @@ void oj_dump_raw_json(VALUE obj, int depth, Out out) {
762
757
  if (Yes == out->opts->trace) {
763
758
  oj_trace("raw_json", obj, __FILE__, __LINE__, depth + 1, TraceRubyOut);
764
759
  }
765
- oj_dump_raw(rb_string_value_ptr((VALUE *)&jv), (size_t)RSTRING_LEN(jv), out);
760
+ oj_dump_raw(RSTRING_PTR(jv), (size_t)RSTRING_LEN(jv), out);
766
761
  }
767
762
  }
768
763
 
@@ -827,9 +822,8 @@ void oj_dump_cstr(const char *str, size_t cnt, bool is_sym, bool escape1, Out ou
827
822
  if (is_sym) {
828
823
  *out->cur++ = ':';
829
824
  }
830
- for (; '\0' != *str; str++) {
831
- *out->cur++ = *str;
832
- }
825
+ memcpy(out->cur, str, cnt);
826
+ out->cur += cnt;
833
827
  *out->cur++ = '"';
834
828
  } else {
835
829
  const char *end = str + cnt;
@@ -961,7 +955,7 @@ void oj_dump_class(VALUE obj, int depth, Out out, bool as_ok) {
961
955
  void oj_dump_obj_to_s(VALUE obj, Out out) {
962
956
  volatile VALUE rstr = rb_funcall(obj, oj_to_s_id, 0);
963
957
 
964
- oj_dump_cstr(rb_string_value_ptr((VALUE *)&rstr), (int)RSTRING_LEN(rstr), 0, 0, out);
958
+ oj_dump_cstr(RSTRING_PTR(rstr), (int)RSTRING_LEN(rstr), 0, 0, out);
965
959
  }
966
960
 
967
961
  void oj_dump_raw(const char *str, size_t cnt, Out out) {
@@ -1078,7 +1072,7 @@ void oj_dump_bignum(VALUE obj, int depth, Out out, bool as_ok) {
1078
1072
  } else {
1079
1073
  assure_size(out, cnt);
1080
1074
  }
1081
- memcpy(out->cur, rb_string_value_ptr((VALUE *)&rs), cnt);
1075
+ memcpy(out->cur, RSTRING_PTR(rs), cnt);
1082
1076
  out->cur += cnt;
1083
1077
  if (dump_as_string) {
1084
1078
  *out->cur++ = '"';
@@ -1206,7 +1200,7 @@ void oj_dump_float(VALUE obj, int depth, Out out, bool as_ok) {
1206
1200
  if ((int)sizeof(buf) <= cnt) {
1207
1201
  cnt = sizeof(buf) - 1;
1208
1202
  }
1209
- strncpy(buf, rb_string_value_ptr((VALUE *)&rstr), cnt);
1203
+ memcpy(buf, RSTRING_PTR(rstr), cnt);
1210
1204
  buf[cnt] = '\0';
1211
1205
  } else {
1212
1206
  cnt = oj_dump_float_printf(buf, sizeof(buf), obj, d, out->opts->float_fmt);
@@ -1226,7 +1220,7 @@ int oj_dump_float_printf(char *buf, size_t blen, VALUE obj, double d, const char
1226
1220
  if (17 <= cnt && (0 == strcmp("0001", buf + cnt - 4) || 0 == strcmp("9999", buf + cnt - 4))) {
1227
1221
  volatile VALUE rstr = rb_funcall(obj, oj_to_s_id, 0);
1228
1222
 
1229
- strcpy(buf, rb_string_value_ptr((VALUE *)&rstr));
1223
+ strcpy(buf, RSTRING_PTR(rstr));
1230
1224
  cnt = (int)RSTRING_LEN(rstr);
1231
1225
  }
1232
1226
  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
 
@@ -208,9 +208,9 @@ static void dump_str(VALUE obj, int depth, Out out, bool as_ok) {
208
208
  }
209
209
 
210
210
  static void dump_sym(VALUE obj, int depth, Out out, bool as_ok) {
211
- volatile VALUE s = rb_sym_to_s(obj);
211
+ volatile VALUE s = rb_sym2str(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);
@@ -694,9 +694,9 @@ static void dump_struct(VALUE obj, int depth, Out out, bool as_ok) {
694
694
 
695
695
  *out->cur++ = '[';
696
696
  for (i = 0; i < cnt; i++) {
697
- volatile VALUE s = rb_sym_to_s(rb_ary_entry(ma, i));
697
+ volatile VALUE s = rb_sym2str(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/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 *)((char *)&pi - (512 * 1024));
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.
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
+ }