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);
|
||