#!/usr/bin/env perl
use 5.012;
use warnings;
use Data::Dump qw/dump/;
my %hash = (
some => 'original',
keys => 'for reference',
);
tie my %local, 'RJT::LocalHash', \%hash;
$local{foo} = 'bar';
delete $local{some};
$local{keys} =~ y/e/E/; # Still uses FETCH
$hash{both} = 'Operations on original hash affect both';
dump \%local;
dump \%hash;
####
{
# tied RJT::LocalHash
both => "Operations on original hash affect both",
foo => "bar",
keys => "for rEfErEncE",
}
{
both => "Operations on original hash affect both",
keys => "for reference",
some => "original",
}
##
##
package RJT::LocalHash {
use parent 'Tie::Hash';
use List::MoreUtils qw/uniq/;
use Carp;
sub TIEHASH {
my ($class, $orig) = @_;
croak 'Expected HASH ref, not `'.ref($orig)."'"
unless 'HASH' eq ref $orig;
bless { orig => $orig, del => { }, new => { } }, $class;
}
sub STORE { delete $_[0]{del}{$_[1]}; $_[0]{new}{$_[1]} = $_[2] }
sub EXISTS { not exists $_[0]{del}{$_[1]} and
(exists $_[0]{new}{$_[1]} or exists $_[0]{orig}{$_[1]}) }
sub FETCH { return if exists $_[0]{del}{$_[1]};
exists $_[0]{new}{$_[1]} ? $_[0]{new}{$_[1]}
: $_[0]{orig}{$_[1]} }
sub FIRSTKEY {
# Initialize the iterator as union of both hash key sets
# minus anything that's been locally deleted
my @each = grep { not exists $_[0]{del}{$_} }
uniq keys $_[0]{orig}, keys $_[0]{new};
$_[0]{each} = \@each;
shift @each;
}
sub NEXTKEY { shift $_[0]{each} }
sub DELETE {
$_[0]{del}{$_[1]} = 1;
$_[0]{new}{$_[1]} // $_[0]{orig}{$_[1]};
}
}