File Coverage

blib/lib/Tie/LLHash.pm
Criterion Covered Total %
statement 93 111 83.7
branch 33 44 75.0
condition n/a
subroutine 14 21 66.6
pod 10 10 100.0
total 150 186 80.6


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