File Coverage

blib/lib/Tie/LLHash.pm
Criterion Covered Total %
statement 96 114 84.2
branch 33 44 75.0
condition n/a
subroutine 15 22 68.1
pod 10 10 100.0
total 154 190 81.0


line stmt bran cond sub pod time code
1             package Tie::LLHash;
2              
3 2     2   15085 use strict;
  2         4  
  2         58  
4 2     2   6 use warnings;
  2         2  
  2         44  
5 2     2   11 use Carp;
  2         2  
  2         1885  
6              
7             our $VERSION = '1.004';
8              
9             sub TIEHASH {
10 5     5   1402 my $pkg = shift;
11              
12 5         10 my $self = bless {}, $pkg;
13 5 100       14 %$self = ( %$self, %{shift()} ) if ref $_[0];
  2         5  
14 5         10 $self->CLEAR;
15              
16             # Initialize the hash if more arguments are given
17 5         8 while (@_) {
18 11         16 $self->last( splice(@_, 0, 2) );
19             }
20              
21 5         10 return $self;
22             }
23              
24             # Standard access methods:
25              
26             sub FETCH {
27 24     24   325 my $self = shift;
28 24         17 my $key = shift;
29              
30 24 50       24 return undef unless $self->EXISTS($key);
31 24         51 return $self->{'nodes'}{$key}{'value'};
32             }
33              
34             sub STORE {
35 4     4   16 my $self = shift;
36 4         4 my $name = shift;
37 4         4 my $value = shift;
38              
39 4 50       7 if (exists $self->{'nodes'}{$name}) {
40 0         0 return $self->{'nodes'}{$name}{'value'} = $value;
41             }
42              
43 4 50       8 croak ("No such key '$name', use first() or insert() to add keys") unless $self->{lazy};
44 4         6 return $self->last($name, $value);
45             }
46              
47              
48             sub FIRSTKEY {
49 12     12   737 my $self = shift;
50 12         32 return $self->{'current'} = $self->{'first'};
51             }
52              
53             sub NEXTKEY {
54 57     57   49 my $self = shift;
55 57 100       178 return $self->{'current'} = (defined $self->{'current'}
56             ? $self->{'nodes'}{ $self->{'current'} }{'next'}
57             : $self->{'first'});
58             }
59              
60             sub EXISTS {
61 81     81   912 my $self = shift;
62 81         52 my $name = shift;
63 81         165 return exists $self->{'nodes'}{$name};
64             }
65              
66             sub DELETE {
67 6     6   1543 my $self = shift;
68 6         6 my $key = shift;
69              
70 6 50       9 return unless $self->EXISTS($key);
71 6         10 my $node = $self->{'nodes'}{$key};
72              
73 6 100       20 if ($self->{'first'} eq $self->{'last'}) {
    100          
    50          
74 2         3 $self->{'first'} = undef;
75 2         3 $self->{'current'} = undef;
76 2         4 $self->{'last'} = undef;
77              
78             } elsif ($self->{'first'} eq $key) {
79 3         5 $self->{'first'} = $node->{'next'};
80 3         7 $self->{'nodes'}{ $self->{'first'} }{'prev'} = undef;
81 3         2 $self->{'current'} = undef;
82              
83             } elsif ($self->{'last'} eq $key) {
84 1         2 $self->{'current'} = $self->{'last'} = $node->{'prev'};
85 1         2 $self->{'nodes'}{ $self->{'last'} }{'next'} = undef;
86              
87             } else {
88 0         0 my $key_one = $node->{'prev'};
89 0         0 my $key_three = $node->{'next'};
90 0         0 $self->{'nodes'}{$key_one }{'next'} = $key_three;
91 0         0 $self->{'nodes'}{$key_three}{'prev'} = $key_one;
92 0         0 $self->{'current'} = $key_one;
93             }
94              
95 6         17 return +(delete $self->{'nodes'}{$key})->{value};
96             }
97              
98             sub CLEAR {
99 6     6   193 my $self = shift;
100              
101 6         11 $self->{'first'} = undef;
102 6         6 $self->{'last'} = undef;
103 6         7 $self->{'current'} = undef;
104 6         17 $self->{'nodes'} = {};
105             }
106              
107             sub SCALAR {
108 3     3   454 my $self = shift;
109 3         4 return scalar %{$self->{'nodes'}};
  3         11  
110             }
111              
112             # Special access methods
113             # Use (tied %hash)->method to get at them
114              
115             sub insert {
116 3     3 1 265 my $self = shift;
117 3         4 my $two_key = shift;
118 3         2 my $two_value = shift;
119 3         4 my $one_key = shift;
120              
121             # insert(key,val) and insert(key,val,undef) == first(key,val)
122 3 100       8 return $self->first($two_key, $two_value) unless defined $one_key;
123              
124 2 50       3 croak ("No such key '$one_key'") unless $self->EXISTS($one_key);
125 2 50       4 croak ("'$two_key' already exists") if $self->EXISTS($two_key);
126              
127 2         4 my $three_key = $self->{'nodes'}{$one_key}{'next'};
128              
129 2         3 $self->{'nodes'}{$one_key}{'next'} = $two_key;
130              
131 2         3 $self->{'nodes'}{$two_key}{'prev'} = $one_key;
132 2         4 $self->{'nodes'}{$two_key}{'next'} = $three_key;
133 2         3 $self->{'nodes'}{$two_key}{'value'} = $two_value;
134              
135 2 50       3 if (defined $three_key) {
136 0         0 $self->{'nodes'}{$three_key}{'prev'} = $two_key;
137             }
138              
139             # If we're adding to the end of the hash, adjust the {last} pointer:
140 2 50       6 if ($one_key eq $self->{'last'}) {
141 2         3 $self->{'last'} = $two_key;
142             }
143              
144 2         4 return $two_value;
145             }
146              
147             sub first {
148 7     7 1 380 my $self = shift;
149              
150 7 100       14 if (@_) { # Set it
151 6         6 my $newkey = shift;
152 6         5 my $newvalue = shift;
153              
154 6 50       10 croak ("'$newkey' already exists") if $self->EXISTS($newkey);
155              
156             # Create the new node
157 6         17 $self->{'nodes'}{$newkey} =
158             {
159             'next' => undef,
160             'value' => $newvalue,
161             'prev' => undef,
162             };
163              
164             # Put it in its relative place
165 6 100       11 if (defined $self->{'first'}) {
166 4         5 $self->{'nodes'}{$newkey}{'next'} = $self->{'first'};
167 4         5 $self->{'nodes'}{ $self->{'first'} }{'prev'} = $newkey;
168             }
169              
170             # Finally, make this node the first node
171 6         7 $self->{'first'} = $newkey;
172              
173             # If this is an empty hash, make it the last node too
174 6 100       10 $self->{'last'} = $newkey unless (defined $self->{'last'});
175             }
176 7         9 return $self->{'first'};
177             }
178              
179             sub last {
180 30     30 1 249 my $self = shift;
181              
182 30 100       39 if (@_) { # Set it
183 29         21 my $newkey = shift;
184 29         19 my $newvalue = shift;
185              
186 29 50       33 croak ("'$newkey' already exists") if $self->EXISTS($newkey);
187              
188             # Create the new node
189 29         58 $self->{'nodes'}{$newkey} =
190             {
191             'next' => undef,
192             'value' => $newvalue,
193             'prev' => undef,
194             };
195              
196             # Put it in its relative place
197 29 100       449 if (defined $self->{'last'}) {
198 24         27 $self->{'nodes'}{$newkey}{'prev'} = $self->{'last'};
199 24         28 $self->{'nodes'}{ $self->{'last'} }{'next'} = $newkey;
200             }
201              
202             # Finally, make this node the last node
203 29         23 $self->{'last'} = $newkey;
204              
205             # If this is an empty hash, make it the first node too
206 29 100       47 $self->{'first'} = $newkey unless (defined $self->{'first'});
207             }
208 30         46 return $self->{'last'};
209             }
210              
211             sub key_before {
212 0     0 1   return $_[0]->{'nodes'}{$_[1]}{'prev'};
213             }
214              
215             sub key_after {
216 0     0 1   return $_[0]->{'nodes'}{$_[1]}{'next'};
217             }
218              
219             sub current_key {
220 0     0 1   return $_[0]->{'current'};
221             }
222              
223             sub current_value {
224 0     0 1   my $self = shift;
225 0           return $self->FETCH($self->{'current'});
226             }
227              
228             sub next {
229 0     0 1   my $self = shift;
230 0           return $self->NEXTKEY;
231             }
232              
233             sub prev {
234 0     0 1   my $self = shift;
235 0           return $self->{'current'} = $self->{'nodes'}{ $self->{'current'} }{'prev'};
236             }
237              
238             sub reset {
239 0     0 1   my $self = shift;
240 0           return $self->FIRSTKEY;
241             }
242              
243             1;
244             __END__