Feature #12142 » hash.patch
| hash.c | ||
|---|---|---|
|
long rb_objid_hash(st_index_t index);
|
||
|
static st_index_t
|
||
|
long
|
||
|
rb_dbl_long_hash(double d)
|
||
|
{
|
||
|
/* normalize -0.0 to 0.0 */
|
||
|
if (d == 0.0) d = 0.0;
|
||
|
#if SIZEOF_INT == SIZEOF_VOIDP
|
||
|
return rb_memhash(&d, sizeof(d));
|
||
|
#else
|
||
|
{
|
||
|
union {double d; uint64_t i;} u;
|
||
|
|
||
|
u.d = d;
|
||
|
return rb_objid_hash(u.i);
|
||
|
}
|
||
|
#endif
|
||
|
}
|
||
|
static inline st_index_t
|
||
|
any_hash(VALUE a, st_index_t (*other_func)(VALUE))
|
||
|
{
|
||
|
VALUE hval;
|
||
|
st_index_t hnum;
|
||
|
if (SPECIAL_CONST_P(a)) {
|
||
|
if (a == Qundef) return 0;
|
||
|
if (STATIC_SYM_P(a)) {
|
||
|
hnum = a >> (RUBY_SPECIAL_SHIFT + ID_SCOPE_SHIFT);
|
||
|
goto out;
|
||
| ... | ... | |
|
}
|
||
|
else if (BUILTIN_TYPE(a) == T_FLOAT) {
|
||
|
flt:
|
||
|
hval = rb_dbl_hash(rb_float_value(a));
|
||
|
hnum = FIX2LONG(hval);
|
||
|
hnum = rb_dbl_long_hash(rb_float_value(a));
|
||
|
}
|
||
|
else {
|
||
|
hnum = other_func(a);
|
||
| ... | ... | |
|
return any_hash(a, obj_any_hash);
|
||
|
}
|
||
|
static st_index_t
|
||
|
rb_num_hash_start(st_index_t n)
|
||
|
/* Here is a hash function for 64-bit key. It is about 5 times faster
|
||
|
(2 times faster when uint128 type is absent) on Haswell than
|
||
|
tailored Spooky or City hash function can be. */
|
||
|
/* Here we two primes with random bit generation. */
|
||
|
static const uint64_t prime1 = 0x2e0bb864e9ea7df5ULL;
|
||
|
static const uint64_t prime2 = 0xcdb32970830fcaa1ULL;
|
||
|
static inline uint64_t
|
||
|
mult_and_mix (uint64_t m1, uint64_t m2)
|
||
|
{
|
||
|
/*
|
||
|
* This hash function is lightly-tuned for Ruby. Further tuning
|
||
|
* should be possible. Notes:
|
||
|
*
|
||
|
* - (n >> 3) alone is great for heap objects and OK for fixnum,
|
||
|
* however symbols perform poorly.
|
||
|
* - (n >> (RUBY_SPECIAL_SHIFT+3)) was added to make symbols hash well,
|
||
|
* n.b.: +3 to remove most ID scope, +1 worked well initially, too
|
||
|
* n.b.: +1 (instead of 3) worked well initially, too
|
||
|
* - (n << 16) was finally added to avoid losing bits for fixnums
|
||
|
* - avoid expensive modulo instructions, it is currently only
|
||
|
* shifts and bitmask operations.
|
||
|
*/
|
||
|
return (n >> (RUBY_SPECIAL_SHIFT + 3) ^ (n << 16)) ^ (n >> 3);
|
||
|
#if defined(__GNUC__) && UINT_MAX != ULONG_MAX
|
||
|
__uint128_t r = (__uint128_t) m1 * (__uint128_t) m2;
|
||
|
return (uint64_t) (r >> 64) ^ (uint64_t) r;
|
||
|
#else
|
||
|
uint64_t hm1 = m1 >> 32, hm2 = m2 >> 32;
|
||
|
uint64_t lm1 = m1, lm2 = m2;
|
||
|
uint64_t v64_128 = hm1 * hm2;
|
||
|
uint64_t v32_96 = hm1 * lm2 + lm1 * hm2;
|
||
|
uint64_t v1_32 = lm1 * lm2;
|
||
|
|
||
|
return (v64_128 + (v32_96 >> 32)) ^ ((v32_96 << 32) + v1_32);
|
||
|
#endif
|
||
|
}
|
||
|
static inline uint64_t
|
||
|
key64_hash (uint64_t key, uint32_t seed)
|
||
|
{
|
||
|
return mult_and_mix(key + seed, prime1);
|
||
|
}
|
||
|
long
|
||
|
rb_objid_hash(st_index_t index)
|
||
|
{
|
||
|
st_index_t hnum = rb_num_hash_start(index);
|
||
|
hnum = rb_hash_start(hnum);
|
||
|
hnum = rb_hash_uint(hnum, (st_index_t)rb_any_hash);
|
||
|
hnum = rb_hash_end(hnum);
|
||
|
return hnum;
|
||
|
return key64_hash (index, prime2);
|
||
|
}
|
||
|
static st_index_t
|
||
| ... | ... | |
|
}
|
||
|
#endif
|
||
|
return (st_index_t)rb_num_hash_start((st_index_t)n);
|
||
|
return (st_index_t) key64_hash((st_index_t)n, prime2);
|
||
|
}
|
||
|
static const struct st_hash_type identhash = {
|
||
| numeric.c | ||
|---|---|---|
|
VALUE
|
||
|
rb_dbl_hash(double d)
|
||
|
{
|
||
|
st_index_t hash;
|
||
|
/* normalize -0.0 to 0.0 */
|
||
|
if (d == 0.0) d = 0.0;
|
||
|
hash = rb_memhash(&d, sizeof(d));
|
||
|
return LONG2FIX(hash);
|
||
|
return LONG2FIX(rb_dbl_long_hash (d));
|
||
|
}
|
||
|
VALUE
|
||
|
-- a/internal.h
|
||
|
++ b/internal.h
|
||
| ... | ... | |
|
VALUE rb_hash_default_value(VALUE hash, VALUE key);
|
||
|
VALUE rb_hash_set_default_proc(VALUE hash, VALUE proc);
|
||
|
long rb_objid_hash(st_index_t index);
|
||
|
long rb_dbl_long_hash(double d);
|
||
|
st_table *rb_init_identtable(void);
|
||
|
st_table *rb_init_identtable_with_size(st_index_t size);
|
||