hash.t revision 7c478bd95313f5f23a4c958a745db2134aa03244
#!./perl -w
BEGIN {
chdir 't' if -d 't';
}
use strict;
my %h;
foreach (1..10) {
$h{"\0"x$_}++;
}
foreach (11..20) {
$h{"\0"x$_}++;
}
# second part using an emulation of the PERL_HASH in perl, mounting an
# attack on a prepopulated hash. This is also useful if you need normal
# keys which don't contain \0 -- suitable for stashes
# some initial hash data
"starting with pre-populated non-pathalogical hash (rehash flag if off)");
sub get_keys {
my $hr = shift;
# the minimum of bits required to mount the attack on a hash
# if the hash has already been populated with a significant amount
# of entries the number of mask bits can be higher
# need to add 2 bits to cover the internal split cases
$bits += 2;
my @keys;
my $s = START;
my $c = 0;
# get 2 keys on top of the THRESHOLD
my $hash;
# next if exists $hash->{$s};
$c++;
} continue {
$s++;
}
return @keys;
}
# trying to provide the fastest equivalent of C macro's PERL_HASH in
# Perl - the main complication is that it uses U32 integer, which we
# can't do it perl, without doing some tricks
sub hash {
my $s = shift;
my @c = split //, $s;
my $u = HASH_SEED;
for (@c) {
# (A % M) + (B % M) == (A + B) % M
# This works because '+' produces a NV, which is big enough to hold
# the intermidiate result. We only need the % before any "^" and "&"
# to get the result in the range for an I32.
# and << doesn't work on NV, so using 1 << 10
$u += ord;
$u ^= $u >> 6;
}
$u += $u << 3; $u %= MASK_U32;
$u ^= $u >> 11; $u %= MASK_U32;
$u += $u << 15; $u %= MASK_U32;
$u;
}