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;