my $h = TwoWayHash->new(100); # 100 is the "size", ignore for now
$h->insert("mam", "dad");
print $h->retrieveOneWay("L2R", "mam") # Left 2 Right
# dad
print $h->retrieveOneWay("R2L", "dad") # Right 2 Left
# mam
####
tie %r2l, $twowayhash, "R2L"; # right to left
tie %l2r, $twowayhash, "L2R"; # left to right
####
use strict;
use warnings;
package TwoWayHash;
sub new
{
my $pkg = shift;
my $size = shift;
my $self = bless {Size => $size}, $pkg;
# preextend the buckets
$self->{R2L} = [];
$#{$self->{R2L}} = $size - 1;
$self->{L2R} = [];
$#{$self->{L2R}} = $size - 1;
return $self;
}
sub insert
{
my $self = shift;
my ($v1, $v2) = @_;
$self->insertOneWay("L2R", \$v1, \$v2);
$self->insertOneWay("R2L", \$v2, \$v1);
}
sub insertOneWay
{
my $self = shift;
my $which = shift;
my $key = shift; # these are refs to the strings
my $value = shift;
my $h = _hashit($key) % $self->{Size}; # turn the key into something much smaller and hopefully unique
my $buckets = $self->{$which};
# find the already existing bucket or create a
# new one then put the key/value into the bucket
my $bucket = $buckets->[$h] ||= [];
push(@$bucket, $key, $value);
}
sub _hashit
{
# a terrible hash function! It just takes the first 2 characters of the string
# and turns them into a number between 0 and 65535
# You'll need something better for real life
my $rstr = shift;
return unpack("S", substr($$rstr, 0, 2));
}
sub retrieveOneWay
{
my $self = shift;
my $which = shift;
my $key = shift; # not a ref this time
my $h = _hashit(\$key) % $self->{Size};
my $buckets = $self->{$which};
if (defined(my $list = $buckets->[$h]))
{
# go through the list of pairs of key/values and see if any are the ones
# we want
my $i = 0;
while ($i < $#$list)
{
if ($key eq ${$list->[$i]})
{
return ${$list->[$i + 1]};
}
$i += 2;
}
}
# if we get here then we didn't find anything nice
return undef;
}
1;
####
use strict;
use warnings;
use Test::More 'no_plan';
use Test::NoWarnings; # comment out if you don't have this installed
use TwoWayHash;
my $h = TwoWayHash->new(100);
my @tests = (
["abcd123", "efgh123"],
["wxyz456", "lmno456"],
["abcd456", "efgh456"],
);
foreach my $test (@tests)
{
my ($v1, $v2) = @$test;
$h->insert($v1, $v2);
}
use Data::Dumper;
#print Dumper(\$h);
foreach my $test (@tests)
{
my ($v1, $v2) = @$test;
is($h->retrieveOneWay("L2R", $v1), $v2, "L2R retrieve '$v1'");
is($h->retrieveOneWay("L2R", $v2), undef, "L2R don't retrieve '$v2'");
is($h->retrieveOneWay("R2L", $v2), $v1, "R2L retrieve '$v2'");
is($h->retrieveOneWay("R2L", $v1), undef, "R2L don't retrieve '$v1'");
}
is($h->retrieveOneWay("L2R", "abcd234"), undef, "L2R don't retrieve");