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