File Coverage

blib/lib/Tie/AliasHash.pm
Criterion Covered Total %
statement 105 116 90.5
branch 28 36 77.7
condition 8 9 88.8
subroutine 20 21 95.2
pod 10 11 90.9
total 171 193 88.6


line stmt bran cond sub pod time code
1             package Tie::AliasHash;
2            
3 1     1   8063 use strict;
  1         2  
  1         41  
4            
5 1     1   6 use vars qw( @ISA @EXPORT_OK $VERSION );
  1         2  
  1         1845  
6            
7             require Exporter;
8             @ISA = qw(Exporter);
9             @EXPORT_OK = qw( allkeys );
10            
11             $VERSION = '1.01';
12            
13             #### constants
14            
15             sub _HASH () { 0 }
16             sub _ALIAS () { 1 }
17             sub _ALIAS_REV () { 2 }
18             sub _ALIAS_REV_IDX () { 3 }
19             sub _JOLLY () { 4 }
20            
21             #### data structure is:
22             #### $self = [
23             #### _HASH (the real hash)
24             #### realkey => value
25             #### _ALIAS (the aliases (forward lookup))
26             #### alias => realkey
27             #### _ALIAS_REV (the aliases (reverse lookup))
28             #### realkey => [alias1, alias2, aliasN]
29             #### _ALIAS_REV_IDX (the alias indices in _ALIAS_REV)
30             #### alias1 => 0
31             #### alias2 => 1
32             #### aliasN => N
33             #### _JOLLY (where unknown keys will be sent)
34             #### ]
35            
36             #### tie stuff
37            
38             sub TIEHASH {
39 1     1   127 my($class, @aliases) = @_;
40 1         6 my $self = bless [ {}, {}, {}, {}, undef ], $class;
41 1         3 my($key, $alias);
42 1         4 foreach $alias ( @aliases ) {
43 3 50       12 if(ref($alias) eq "ARRAY") {
44 3         11 $self->add_alias( @$alias );
45             } else {
46 0 0       0 if($^W) {
47 0         0 warn( "Tie::AliasHash: argument '$alias' to hash is not an ARRAY ref!" );
48             }
49             }
50             }
51 1         6 return $self;
52             }
53            
54             sub FETCH {
55 25     25   189 my($self, $key) = @_;
56 25 100       43 $key = $self->realkey($key) if $self->is_alias($key);
57 25 100 100     57 $key = $self->[_JOLLY]
58             if not $self->is_key($key)
59             and defined $self->[_JOLLY];
60 25         128 return $self->[_HASH]->{$key};
61             }
62            
63             sub STORE ($\@$) {
64 13     13   199 my($self, $key, $value) = @_;
65 13         14 my @keys;
66 13 100       27 if( ref($key) eq "ARRAY" ) {
67 1         3 @keys = @$key;
68             } else {
69 12         64 @keys = split( $;, $key);
70             }
71 13 100       32 $key = $keys[0] if scalar(@keys) > 1;
72 13 100       28 $key = $self->realkey($key) if $self->is_alias($key);
73 13 100 100     33 $key = $self->[_JOLLY] if not $self->is_key($key) and defined $self->[_JOLLY];
74 13         130 $self->[_HASH]->{$key} = $value;
75 13 100       48 if(@keys > 1) {
76 4         8 $self->add_alias( @keys );
77             }
78             }
79            
80             sub FIRSTKEY {
81 1     1   11 my($self) = @_;
82 1         2 my @init = keys %{ $self->[_HASH] };
  1         6  
83 1         3 my ($k, $v) = each %{ $self->[_HASH] };
  1         4  
84 1         7 return $k;
85             }
86            
87             sub NEXTKEY {
88 3     3   5 my($self) = @_;
89 3         3 my ($k, $v) = each %{ $self->[_HASH] };
  3         7  
90 3         15 return $k;
91             }
92            
93             sub EXISTS {
94 2     2   1203 my($self, $key) = @_;
95 2   66     6 return ( $self->is_key($key)
96             or $self->is_alias($key) );
97             }
98            
99             sub DELETE {
100 3     3   47 my($self, $key) = @_;
101 3 50       6 $key = $self->realkey($key) if $self->is_alias($key);
102 3         6 $self->remove_aliases( $key );
103 3 100       14 delete ${ $self->[_HASH] }{$key}
  1         6  
104             if exists $self->[_HASH]->{$key};
105             }
106            
107             sub CLEAR {
108 0     0   0 my($self) = @_;
109 0         0 $self->[_HASH] = {};
110 0         0 $self->[_ALIAS] = {};
111 0         0 $self->[_ALIAS_REV] = {};
112 0         0 $self->[_ALIAS_REV_IDX] = {};
113 0         0 $self->[_JOLLY] = undef;
114             }
115            
116             #### methods
117            
118             sub add_alias {
119 10     10 1 63 my $self = shift;
120 10         13 my $key = shift;
121 10 100       22 $key = $self->realkey($key) if $self->is_alias($key);
122 10         12 my $alias;
123 10         28 while(defined( $alias = shift )) {
124 20         68 $self->[_ALIAS]->{$alias} = $key;
125 20 100       21 if(exists ${ $self->[_ALIAS_REV] }{$key}) {
  20         45  
126 14         14 push( @{ $self->[_ALIAS_REV]->{$key} }, $alias );
  14         188  
127 14         18 $self->[_ALIAS_REV_IDX]->{$alias} = $#{ $self->[_ALIAS_REV]->{$key} };
  14         71  
128             } else {
129 6         17 $self->[_ALIAS_REV]->{$key} = [ $alias ];
130 6         26 $self->[_ALIAS_REV_IDX]->{$alias} = 0;
131             }
132             }
133             }
134            
135             sub remove_alias {
136 1     1 1 32 my($self, $alias) = @_;
137 1         4 my $key = $self->realkey( $alias );
138 1         4 delete ${ $self->[_ALIAS] }{$alias};
  1         94  
139 1         5 splice(
140 1         2 @{ $self->[_ALIAS_REV]->{$key} },
141             $self->[_ALIAS_REV_IDX]->{$alias},
142             1
143             );
144 1         3 delete ${ $self->[_ALIAS_REV_IDX] }{$alias};
  1         3  
145             }
146            
147             sub remove_aliases {
148 5     5 1 9 my($self, $key) = @_;
149 5         4 my $alias;
150 5         13 foreach $alias ( @{ $self->[_ALIAS_REV]->{$key} } ) {
  5         13  
151 6         6 delete ${ $self->[_ALIAS] }{$alias};
  6         11  
152 6         7 delete ${ $self->[_ALIAS_REV_IDX] }{$alias};
  6         14  
153             }
154 5         6 delete ${ $self->[_ALIAS_REV] }{$key};
  5         12  
155             }
156            
157             sub aliases {
158 1     1 1 100 my($self, $key) = @_;
159 1         2 return @{ $self->[_ALIAS_REV]->{$key} };
  1         9  
160             }
161            
162             sub remove {
163 1     1 1 3 my($self, @keys) = @_;
164 1         3 foreach my $key (@keys) {
165 3 50       8 if( $self->is_alias( $key ) ) {
    100          
166 0         0 $self->remove_alias( $key );
167             } elsif( $self->is_key( $key ) ) {
168 2         6 $self->remove_aliases( $key );
169 2         2 delete ${ $self->[_HASH] }{$key};
  2         84  
170             }
171             }
172             }
173            
174             sub allkeys(\%) {
175 2     2 1 55 my $self = shift;
176 2 100       7 $self = tied %{ $self } if ref $self eq "HASH";
  1         3  
177 2         3 return (keys %{$self->[_HASH]}), (keys %{$self->[_ALIAS]});
  2         6  
  2         30  
178             }
179            
180             sub realkey {
181 18     18 0 23 my($self, $key) = @_;
182 18 50       39 if($self->is_alias($key)) {
    0          
183 18         46 return $self->[_ALIAS]->{$key};
184             } elsif($self->is_key($key)) {
185 0         0 return $key;
186             } else {
187 0         0 return undef;
188             }
189             }
190            
191             sub is_alias {
192 75     75 1 97 my($self, $key) = @_;
193 75         77 return exists ${ $self->[_ALIAS] }{$key};
  75         280  
194             }
195            
196             sub is_key {
197 45     45 1 65 my($self, $key) = @_;
198 45         47 return exists ${ $self->[_HASH] }{$key};
  45         198  
199             }
200            
201             sub set_jolly {
202 1     1 1 6 my($self, $key) = @_;
203 1         3 $self->[_JOLLY] = $key;
204             }
205            
206             sub remove_jolly {
207 1     1 1 29 my($self) = @_;
208 1         3 $self->[_JOLLY] = undef;
209             }
210            
211             1;
212            
213             __END__