oj 3.13.0 → 3.13.4

Sign up to get free protection for your applications and to get access to all the features.
data/ext/oj/custom.c CHANGED
@@ -833,7 +833,7 @@ static void dump_struct(VALUE obj, int depth, Out out, bool as_ok) {
833
833
  v = rb_struct_aref(obj, INT2FIX(i));
834
834
  #endif
835
835
  if (ma != Qnil) {
836
- volatile VALUE s = rb_sym_to_s(rb_ary_entry(ma, i));
836
+ volatile VALUE s = rb_sym2str(rb_ary_entry(ma, i));
837
837
 
838
838
  name = RSTRING_PTR(s);
839
839
  len = (int)RSTRING_LEN(s);
@@ -956,16 +956,14 @@ static void hash_set_cstr(ParseInfo pi, Val kval, const char *str, size_t len, c
956
956
  }
957
957
  } else {
958
958
  //volatile VALUE rstr = oj_cstr_to_value(str, len, (size_t)pi->options.cache_str);
959
- volatile VALUE rstr = rb_str_new(str, len);
959
+ volatile VALUE rstr = rb_utf8_str_new(str, len);
960
960
 
961
961
  if (Qundef == rkey) {
962
962
  if (Yes == pi->options.sym_key) {
963
963
  rkey = ID2SYM(rb_intern3(key, klen, oj_utf8_encoding));
964
964
  } else {
965
- rkey = rb_str_new(key, klen);
966
- rkey = oj_encode(rkey);
965
+ rkey = rb_utf8_str_new(key, klen);
967
966
  }
968
- rstr = oj_encode(rstr);
969
967
  }
970
968
  if (Yes == pi->options.create_ok && NULL != pi->options.str_rx.head) {
971
969
  VALUE clas = oj_rxclass_match(&pi->options.str_rx, str, (int)len);
@@ -1032,7 +1030,7 @@ static void hash_set_num(struct _parseInfo *pi, Val kval, NumInfo ni) {
1032
1030
  }
1033
1031
  if (86400 == ni->exp) { // UTC time
1034
1032
  parent->val = rb_time_nano_new(ni->i, (long)nsec);
1035
- // Since the ruby C routines alway create local time, the
1033
+ // Since the ruby C routines always create local time, the
1036
1034
  // offset and then a conversion to UTC keeps makes the time
1037
1035
  // match the expected value.
1038
1036
  parent->val = rb_funcall2(parent->val, oj_utc_id, 0, 0);
@@ -1090,9 +1088,8 @@ static void array_append_num(ParseInfo pi, NumInfo ni) {
1090
1088
  }
1091
1089
 
1092
1090
  static void array_append_cstr(ParseInfo pi, const char *str, size_t len, const char *orig) {
1093
- volatile VALUE rstr = rb_str_new(str, len);
1091
+ volatile VALUE rstr = rb_utf8_str_new(str, len);
1094
1092
 
1095
- rstr = oj_encode(rstr);
1096
1093
  if (Yes == pi->options.create_ok && NULL != pi->options.str_rx.head) {
1097
1094
  VALUE clas = oj_rxclass_match(&pi->options.str_rx, str, (int)len);
1098
1095
 
data/ext/oj/debug.c CHANGED
@@ -109,8 +109,9 @@ static void mark(struct _ojParser *p) {
109
109
 
110
110
  void oj_set_parser_debug(ojParser p) {
111
111
  Funcs end = p->funcs + 3;
112
+ Funcs f;
112
113
 
113
- for (Funcs f = p->funcs; f < end; f++) {
114
+ for (f = p->funcs; f < end; f++) {
114
115
  f->add_null = add_null;
115
116
  f->add_true = add_true;
116
117
  f->add_false = add_false;
data/ext/oj/dump.c CHANGED
@@ -717,10 +717,7 @@ void oj_dump_str(VALUE obj, int depth, Out out, bool as_ok) {
717
717
  }
718
718
 
719
719
  void oj_dump_sym(VALUE obj, int depth, Out out, bool as_ok) {
720
- // This causes a memory leak in 2.5.1. Maybe in other versions as well.
721
- // const char *sym = rb_id2name(SYM2ID(obj));
722
-
723
- volatile VALUE s = rb_sym_to_s(obj);
720
+ volatile VALUE s = rb_sym2str(obj);
724
721
 
725
722
  oj_dump_cstr(RSTRING_PTR(s), (int)RSTRING_LEN(s), 0, 0, out);
726
723
  }
data/ext/oj/dump_object.c CHANGED
@@ -208,7 +208,7 @@ 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
213
  oj_dump_cstr(RSTRING_PTR(s), (int)RSTRING_LEN(s), 1, 0, out);
214
214
  }
@@ -694,7 +694,7 @@ 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
699
  name = RSTRING_PTR(s);
700
700
  len = (int)RSTRING_LEN(s);
data/ext/oj/extconf.rb CHANGED
@@ -31,6 +31,7 @@ have_func('rb_gc_mark_movable')
31
31
  have_func('stpcpy')
32
32
  have_func('pthread_mutex_init')
33
33
  have_func('rb_enc_associate')
34
+ have_func('rb_enc_interned_str')
34
35
  have_func('rb_ext_ractor_safe', 'ruby.h')
35
36
  # rb_hash_bulk_insert is deep down in a header not included in normal build and that seems to fool have_func.
36
37
  have_func('rb_hash_bulk_insert', 'ruby.h') unless '2' == version[0] && '6' == version[1]
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.
@@ -1483,7 +1472,7 @@ static VALUE doc_move(VALUE self, VALUE str) {
1483
1472
  * to the block on yield is the Doc instance after moving to the child
1484
1473
  * location.
1485
1474
  * @param [String] path if provided it identified the top of the branch to
1486
- * process the chilren of
1475
+ * process the children of
1487
1476
  * @yieldparam [Doc] Doc at the child location
1488
1477
  * @example
1489
1478
  * Oj::Doc.open('[3,[2,1]]') { |doc|
data/ext/oj/intern.c CHANGED
@@ -8,11 +8,16 @@
8
8
  #if HAVE_PTHREAD_MUTEX_INIT
9
9
  #include <pthread.h>
10
10
  #endif
11
+ #include "cache.h"
11
12
  #include "parse.h"
12
13
 
13
- #define HASH_SLOT_CNT ((uint32_t)8192)
14
+ // Only used for the class cache so 256 should be sufficient.
15
+ #define HASH_SLOT_CNT ((uint64_t)256)
14
16
  #define HASH_MASK (HASH_SLOT_CNT - 1)
15
17
 
18
+ // almost the Murmur hash algorithm
19
+ #define M 0x5bd1e995
20
+
16
21
  typedef struct _keyVal {
17
22
  struct _keyVal *next;
18
23
  const char * key;
@@ -30,256 +35,135 @@ typedef struct _hash {
30
35
  } * Hash;
31
36
 
32
37
  struct _hash class_hash;
33
- struct _hash str_hash;
34
- struct _hash sym_hash;
35
38
  struct _hash attr_hash;
36
39
 
37
- // almost the Murmur hash algorithm
38
- #define M 0x5bd1e995
39
- #define C1 0xCC9E2D51
40
- #define C2 0x1B873593
41
- #define N 0xE6546B64
40
+ static struct _cache *str_cache = NULL;
41
+ static VALUE str_cache_obj;
42
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;
43
+ static struct _cache *sym_cache = NULL;
44
+ static VALUE sym_cache_obj;
48
45
 
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;
46
+ static struct _cache *attr_cache = NULL;
47
+ static VALUE attr_cache_obj;
54
48
 
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++;
49
+ static VALUE form_str(const char *str, size_t len) {
50
+ return rb_str_freeze(rb_utf8_str_new(str, len));
51
+ }
62
52
 
63
- k16 |= (uint16_t)*key++ << 8;
64
- h ^= k16 << 8;
53
+ static VALUE form_sym(const char *str, size_t len) {
54
+ return rb_to_symbol(rb_str_intern(rb_utf8_str_new(str, len)));
55
+ }
56
+
57
+ static VALUE form_attr(const char *str, size_t len) {
58
+ char buf[256];
59
+
60
+ if (sizeof(buf) - 2 <= len) {
61
+ char *b = ALLOC_N(char, len + 2);
62
+ ID id;
63
+
64
+ if ('~' == *str) {
65
+ memcpy(b, str + 1, len - 1);
66
+ b[len - 1] = '\0';
67
+ len -= 2;
68
+ } else {
69
+ *b = '@';
70
+ memcpy(b + 1, str, len);
71
+ b[len + 1] = '\0';
72
+ }
73
+ id = rb_intern3(buf, len + 1, oj_utf8_encoding);
74
+ xfree(b);
75
+ return id;
65
76
  }
66
- if (key < end) {
67
- h ^= *key;
77
+ if ('~' == *str) {
78
+ memcpy(buf, str + 1, len - 1);
79
+ buf[len - 1] = '\0';
80
+ len -= 2;
81
+ } else {
82
+ *buf = '@';
83
+ memcpy(buf + 1, str, len);
84
+ buf[len + 1] = '\0';
68
85
  }
69
- h *= M;
70
- h ^= h >> 13;
71
- h *= M;
72
- h ^= h >> 15;
73
-
74
- return h;
86
+ return (VALUE)rb_intern3(buf, len + 1, oj_utf8_encoding);
75
87
  }
76
88
 
77
89
  void oj_hash_init() {
90
+ VALUE cache_class = rb_define_class_under(Oj, "Cache", rb_cObject);
91
+
92
+ str_cache = cache_create(0, form_str, true, true);
93
+ str_cache_obj = Data_Wrap_Struct(cache_class, cache_mark, cache_free, str_cache);
94
+ rb_gc_register_address(&str_cache_obj);
95
+
96
+ sym_cache = cache_create(0, form_sym, true, true);
97
+ sym_cache_obj = Data_Wrap_Struct(cache_class, cache_mark, cache_free, sym_cache);
98
+ rb_gc_register_address(&sym_cache_obj);
99
+
100
+ attr_cache = cache_create(0, form_attr, false, true);
101
+ attr_cache_obj = Data_Wrap_Struct(cache_class, cache_mark, cache_free, attr_cache);
102
+ rb_gc_register_address(&attr_cache_obj);
103
+
78
104
  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
105
  #if HAVE_PTHREAD_MUTEX_INIT
83
106
  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
107
  #else
88
108
  class_hash.mutex = rb_mutex_new();
89
109
  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
110
  #endif
97
111
  }
98
112
 
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
113
  VALUE
136
114
  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);
115
+ // For huge cache sizes over half a million the rb_enc_interned_str
116
+ // performs slightly better but at more "normal" size of a several
117
+ // thousands the cache intern performs about 20% better.
118
+ #if HAVE_RB_ENC_INTERNED_STR && 0
119
+ return rb_enc_interned_str(key, len, rb_utf8_encoding());
151
120
  #else
152
- rb_mutex_unlock(str_hash.mutex);
121
+ return cache_intern(str_cache, key, len);
153
122
  #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
123
  }
175
124
 
176
125
  VALUE
177
126
  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;
127
+ return cache_intern(sym_cache, key, len);
128
+ }
181
129
 
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;
130
+ ID
131
+ oj_attr_intern(const char *key, size_t len) {
132
+ return cache_intern(attr_cache, key, len);
214
133
  }
215
134
 
216
- static ID form_attr(const char *key, size_t klen) {
217
- char attr[256];
218
- ID var_id;
135
+ static uint64_t hash_calc(const uint8_t *key, size_t len) {
136
+ const uint8_t *end = key + len;
137
+ const uint8_t *endless = key + (len & 0xFFFFFFFC);
138
+ uint64_t h = (uint64_t)len;
139
+ uint64_t k;
219
140
 
220
- if ((int)sizeof(attr) <= klen + 2) {
221
- char *buf = ALLOC_N(char, klen + 2);
141
+ while (key < endless) {
142
+ k = (uint64_t)*key++;
143
+ k |= (uint64_t)*key++ << 8;
144
+ k |= (uint64_t)*key++ << 16;
145
+ k |= (uint64_t)*key++ << 24;
222
146
 
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);
147
+ k *= M;
148
+ k ^= k >> 24;
149
+ h *= M;
150
+ h ^= k * M;
243
151
  }
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;
152
+ if (1 < end - key) {
153
+ uint16_t k16 = (uint16_t)*key++;
251
154
 
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;
155
+ k16 |= (uint16_t)*key++ << 8;
156
+ h ^= k16 << 8;
273
157
  }
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;
158
+ if (key < end) {
159
+ h ^= *key;
160
+ }
161
+ h *= M;
162
+ h ^= h >> 13;
163
+ h *= M;
164
+ h ^= h >> 15;
165
+
166
+ return h;
283
167
  }
284
168
 
285
169
  static VALUE resolve_classname(VALUE mod, const char *classname, int auto_define) {
@@ -333,7 +217,7 @@ static VALUE resolve_classpath(ParseInfo pi, const char *name, size_t len, int a
333
217
  }
334
218
 
335
219
  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;
220
+ uint64_t h = hash_calc((const uint8_t *)key, len) & HASH_MASK;
337
221
  KeyVal bucket = class_hash.slots + h;
338
222
  KeyVal b;
339
223
 
@@ -396,3 +280,9 @@ char *oj_strndup(const char *s, size_t len) {
396
280
 
397
281
  return d;
398
282
  }
283
+
284
+ void intern_cleanup() {
285
+ cache_free(str_cache);
286
+ cache_free(sym_cache);
287
+ cache_free(attr_cache);
288
+ }