File Coverage

blib/lib/Array/OrdHash.pm
Criterion Covered Total %
statement 98 246 39.8
branch 12 62 19.3
condition 0 6 0.0
subroutine 17 41 41.4
pod 11 11 100.0
total 138 366 37.7


line stmt bran cond sub pod time code
1             #Array::OrdHash =======================
2            
3             package Array::OrdHash;
4             our $VERSION = '1.03';
5            
6 1     1   23611 use Carp qw/croak/;
  1         3  
  1         72  
7 1     1   6 use strict;
  1         1  
  1         94  
8            
9             use overload
10 0     0   0 '""' => sub { $_[0] },
11 1     1   8 '%{}' => sub { tied(@{ $_[0] })->[0] },
  1         7  
12 1     1   1741 ;
  1         1356  
  1         11  
13            
14             sub new {
15 6     6 1 13967 my ($class) = shift;
16 6         10 my @me;
17 6         25 my $ar = tie @me, $class;#.'::_array';
18 6         8 my $hs = tie %{ $ar->[0] }, $class.'::_hash';
  6         63  
19 6         18 ($hs->[0], $hs->[1]) = ($ar->[1], $ar->[2]);
20 6         9 $ar->[4] = $hs;
21 6 100       25 push @me, @_ if scalar @_;
22 6         20 bless \@me, $class;
23             }
24            
25             sub List {
26 0     0 1 0 my $ar = tied @{ $_[0] };
  0         0  
27 0 0       0 $ar->[3] = 0 unless defined $ar->[3];
28 0 0       0 if ($ar->[3] > $#{ $ar->[2] }) {
  0         0  
29 0         0 undef($ar->[3]);
30 0         0 return ();
31             }
32 0         0 ($ar->[1][$ar->[3]], ${ $ar->[2][$ar->[3]] }, $ar->[3]++);
  0         0  
33             }
34            
35             sub Reset {
36 0     0 1 0 my $ar = tied @{ $_[0] };
  0         0  
37 0         0 undef($ar->[3]);
38 0         0 tied(%{ $ar->[0] })->[3] = -1;
  0         0  
39             }
40            
41             sub Sort {
42 0     0 1 0 my $ar = tied @{ (shift) };
  0         0  
43 0         0 my %args = ( src=>'keys', @_ );
44 0         0 my ($src_ind, $proc);
45 0         0 my ($src, $direction) = map { lc } split /\s+/, $args{ src };
  0         0  
46 0 0       0 if ($src eq 'keys') {
    0          
47 0         0 $src_ind = 0;
48             }
49             elsif ($src eq 'values') {
50 0         0 $src_ind = 1;
51             }
52             else {
53 0         0 return;
54             }
55 0 0 0     0 if (defined $args{ proc } && ref $args{ proc } eq 'CODE') {
56 0     0   0 $proc = sub { $args{ proc }->($a->[$src_ind], $b->[$src_ind]) }
57 0         0 }
58             else {
59 0 0   0   0 $proc = ($direction eq 'desc')? sub { $b->[$src_ind] cmp $a->[$src_ind] } : sub { $a->[$src_ind] cmp $b->[$src_ind] };
  0         0  
  0         0  
60             }
61 0         0 my $j=0;
62 0         0 foreach (sort $proc map { [$ar->[1][$_], ${ $ar->[2][$_] }, $ar->[2][$_]] } (0 .. $#{ $ar->[1] })) {
  0         0  
  0         0  
  0         0  
63 0         0 $ar->[1][$j] = $_->[0];
64 0         0 $ar->[2][$j] = $_->[2];
65 0         0 $j++;
66             }
67             }
68            
69             sub Reorder {
70 0     0 1 0 my $ar = tied @{ (shift) };
  0         0  
71 0         0 my (@ks, %ks, @vs);
72 0         0 foreach (@_) {
73 0 0 0     0 if (exists($ar->[4][2]{ $_ }) && !exists($ks{ $_ })) {
74 0         0 push @ks, $_;
75 0         0 push @vs, $ar->[4][2]{ $_ };
76 0         0 $ks{ $_ } = $ar->[4][2]{ $_ };
77             }
78             }
79 0         0 $ar->[4][0] = $ar->[1] = \@ks;
80 0         0 $ar->[4][1] = $ar->[2] = \@vs;
81 0         0 $ar->[4][2] = \%ks;
82             }
83            
84             sub Indices {
85 0     0 1 0 my $ar = tied @{ (shift) };
  0         0  
86 0         0 my @ret = ();
87 0 0       0 return @ret unless @_;
88 0         0 my %ks = map { $_, -1 } @_;
  0         0  
89 0         0 my $cnt = 0;
90 0         0 foreach (keys %ks) {
91 0 0       0 $cnt++ if (exists $ar->[4][2]{ $_ });
92             }
93 0 0       0 if ($cnt) {
94 0         0 my $i = 0;
95 0         0 foreach (@{ $ar->[1] }) {
  0         0  
96 0 0       0 if (exists $ks{ $_ }) {
97 0         0 $ks{ $_ } = $i;
98 0         0 $cnt--;
99 0 0       0 last unless $cnt;
100             }
101 0         0 $i++;
102             }
103 0         0 push @ret, $ks{ $_ } foreach (@_);
104             }
105 0         0 @ret;
106             }
107            
108             sub Last {
109 0     0 1 0 my $ar = tied @{ (shift) };
  0         0  
110 0         0 $ar->[4][3] == $#{ $ar->[2] };
  0         0  
111             }
112 0     0 1 0 sub First { (tied @{ (shift) })->[4][3] == 0 }
  0         0  
113            
114 0     0 1 0 sub Length { scalar @{ $_[0] } }
  0         0  
115            
116             sub Keys {
117 0     0 1 0 my $ar = tied @{ (shift) };
  0         0  
118 0 0       0 if (@_) { @{ $ar->[1] }[@_] }
  0         0  
  0         0  
119 0         0 else { @{ $ar->[1] } }
  0         0  
120             }
121            
122             sub Values {
123 0     0 1 0 my $ar = tied @{ (shift) };
  0         0  
124 0 0       0 if (@_) { (map { $$_ } @{ $ar->[2] })[@_] }
  0         0  
  0         0  
  0         0  
125 0         0 else { map { $$_ } @{ $ar->[2] } }
  0         0  
  0         0  
126             }
127            
128             sub TIEARRAY {
129 6     6   27 bless [
130             {}, #hash ref
131             [], #keys
132             [], #values refs
133             undef, #pointer
134             undef, #tied hash (array) ref
135             ], $_[0];
136             }
137            
138             sub FETCH {
139 0     0   0 ${ $_[0]->[2][$_[1]] };
  0         0  
140             }
141            
142             sub STORE {
143 0 0   0   0 croak("Index $_[1] doesn't exist") if $_[1] > $#{ $_[0]->[2] };
  0         0  
144 0         0 ${ $_[0]->[2][$_[1]] } = $_[2];
  0         0  
145             }
146            
147             sub EXISTS {
148 0     0   0 exists $_[0]->[2][$_[1]];
149             }
150            
151             sub FETCHSIZE {
152 2     2   3 scalar @{ $_[0]->[2] };
  2         5  
153             }
154            
155             sub DELETE {
156 2 50   2   4 return if $_[1] > $#{ $_[0]->[2] };
  2         11  
157 2         8 delete $_[0]->[4][2]{ $_[0]->[1][$_[1]] };
158 2         5 [splice(@{ $_[0]->[1] }, $_[1], 1), ${ splice(@{ $_[0]->[2] }, $_[1], 1) }];
  2         6  
  2         2  
  2         11  
159             }
160            
161             sub SPLICE {
162 1     1   31 my ($self, $offset, $len) = (shift, shift, shift);
163 1         2 my (@k, @v, @ki, @vi, @ret, $k);
164 0         0 my $start;
165 1         2 my $lastind = $#{ $self->[2] };
  1         3  
166 1 50       5 if ($offset < 0) {
    50          
167 0 0       0 croak("Offset $offset is illegal") if -$offset > $lastind+1;
168 0         0 $start = $lastind + $offset+1;
169             }
170             elsif ($offset > $lastind+1) {
171 0         0 $start = $lastind+1;
172             }
173             else {
174 1         2 $start = int $offset;
175             }
176 1 50       4 if ($len) {
177 1         2 @k = splice @{ $self->[1] }, $start, $len;
  1         4  
178 1         2 @v = splice @{ $self->[2] }, $start, $len;
  1         3  
179 1         596 while (@k) {
180 1         3 $k = shift @k;
181 1         4 delete $self->[4][2]{ $k };
182 1         2 push @ret, $k, ${ shift(@v) };
  1         4  
183             }
184             }
185 1         5 while (@_) {
186 1         3 ($k, my $v) = (shift, shift);
187 1 50       5 if (exists($self->[4][2]{ $k })) {
188 0         0 ${ $self->[4][2]{ $k } } = $v;
  0         0  
189             }
190             else {
191 1         2 push @ki, $k;
192 1         2 push @vi, \$v;
193 1         5 $self->[4][2]{ $k } = \$v;
194             }
195             }
196 1 50       3 if (@ki) {
197 1         1 splice @{ $self->[1] }, $start, 0, @ki;
  1         3  
198 1         2 splice @{ $self->[2] }, $start, 0, @vi;
  1         2  
199             }
200 1         6 @ret;
201             }
202            
203             sub PUSH {
204 5     5   10 my ($self) = shift;
205 5         5 my ($k);
206 5         14 while (@_) {
207 14         21 ($k, my $v) = (shift, shift);
208 14 50       34 if (exists($self->[4][2]{ $k })) {
209 0         0 ${ $self->[4][2]{ $k } } = $v;
  0         0  
210             }
211             else {
212 14         15 push @{ $self->[1] }, $k;
  14         22  
213 14         17 push @{ $self->[2] }, \$v;
  14         23  
214 14         46 $self->[4][2]{ $k } = \$v;
215             }
216             }
217 5         7 scalar @{ $self->[2] };
  5         15  
218             }
219            
220             sub UNSHIFT {
221 2     2   14 my ($self) = shift;
222 2         3 my ($k, @ki, @vi);
223 2         6 while (@_) {
224 7         8 ($k, my $v) = (shift, shift);
225 7 50       16 if (exists($self->[4][2]{ $k })) {
226 0         0 ${ $self->[4][2]{ $k } } = $v;
  0         0  
227             }
228             else {
229 7         8 push @ki, $k;
230 7         8 push @vi, \$v;
231 7         25 $self->[4][2]{ $k } = \$v;
232             }
233             }
234 2 50       5 if (scalar @ki) {
235 2         4 unshift @{ $self->[1] }, @ki;
  2         6  
236 2         4 unshift @{ $self->[2] }, @vi;
  2         4  
237             }
238 2         4 scalar @{ $self->[2] };
  2         7  
239             }
240            
241 1     1   5 sub POP { $_[0]->DELETE($#{ $_[0]->[2] }) }
  1         7  
242 1     1   10 sub SHIFT { $_[0]->DELETE(0) }
243            
244             #sub EXTEND { print "\tarray EXTEND($_[1])\n"; }
245             #sub STORESIZE { print "\tSTORESIZE\n"; }
246            
247             1;
248            
249             package Array::OrdHash::_hash;
250             #use warnings;
251 1     1   2566 use strict;
  1         2  
  1         544  
252            
253             sub TIEHASH {
254 6     6   19 my $ret = bless [
255             undef, #keys ref
256             undef, #values ref
257             {}, #keys - val refs
258             -1, #pointer
259             ], $_[0];
260 6         13 $ret;
261             }
262            
263             sub STORE {
264 0 0   0   0 if (exists $_[0]->[2]{ $_[1] }) {
265 0         0 ${ $_[0]->[2]{ $_[1] } } = $_[2];
  0         0  
266             }
267             else {
268 0         0 my $v = $_[2];
269 0         0 push(@{ $_[0]->[0] }, $_[1]);
  0         0  
270 0         0 push(@{ $_[0]->[1] }, \$v);
  0         0  
271 0         0 $_[0]->[2]{ $_[1] } = \$v;
272             }
273             }
274            
275             sub FETCH {
276 1 50   1   4 (exists $_[0]->[2]{ $_[1] }) ? ${ $_[0]->[2]{ $_[1] } } : undef;
  1         6  
277             }
278            
279             sub EXISTS {
280 0     0     exists $_[0]->[2]->{ $_[1] };
281             }
282            
283             sub FIRSTKEY {
284 0     0     $_[0]->[3] = 0;
285 0           $_[0]->[0][0];
286             }
287             sub NEXTKEY {
288 0 0   0     if ($_[0]->[3] >= $#{ $_[0]->[0] }) {
  0            
289 0           $_[0]->[3] = -1;
290 0           return;
291             }
292 0           $_[0]->[0][++$_[0]->[3]];
293             }
294             sub DELETE {
295 0 0   0     return unless (exists $_[0]->[2]->{ $_[1] });
296 0           my $ind = Array::OrdHash::_util::_keyindex($_[0]->[0], $_[1]);
297 0           delete $_[0]->[2]{ $_[1] };
298 0           splice(@{ $_[0]->[0] }, $ind, 1);
  0            
299 0           [$ind, ${ splice(@{ $_[0]->[1] }, $ind, 1) }];
  0            
  0            
300             }
301             sub CLEAR {
302 0     0     $_[0]->[0] = [];
303 0           $_[0]->[1] = [];
304 0           $_[0]->[2] = {};
305 0           $_[0]->[3] = -1;
306             }
307 0     0     sub SCALAR { scalar %{$_[0]->[2]} }
  0            
308            
309             1;
310            
311             package Array::OrdHash::_util;
312 1     1   6 use strict;
  1         2  
  1         134  
313            
314             sub _keyindex {
315 0     0     my $j = 0;
316 0           foreach (@{ $_[0] }) {
  0            
317 0 0         return $j if $_ eq $_[1];
318 0           $j++;
319             }
320 0           -1;
321             }
322             #=head1 DISCLAIMER
323             #BECAUSE THIS SOFTWARE IS LICENSED FREE OF CHARGE, THERE IS NO WARRANTY FOR THE SOFTWARE, TO THE EXTENT PERMITTED BY APPLICABLE LAW. EXCEPT WHEN OTHERWISE STATED IN WRITING THE COPYRIGHT HOLDERS AND/OR OTHER PARTIES PROVIDE THE SOFTWARE "AS IS" WITHOUT WARRANTY OF ANY KIND, EITHER EXPRESSED OR IMPLIED, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE. THE ENTIRE RISK AS TO THE QUALITY AND PERFORMANCE OF THE SOFTWARE IS WITH YOU. SHOULD THE SOFTWARE PROVE DEFECTIVE, YOU ASSUME THE COST OF ALL NECESSARY SERVICING, REPAIR, OR CORRECTION.
324             #IN NO EVENT UNLESS REQUIRED BY APPLICABLE LAW OR AGREED TO IN WRITING WILL ANY COPYRIGHT HOLDER, OR ANY OTHER PARTY WHO MAY MODIFY AND/OR REDISTRIBUTE THE SOFTWARE AS PERMITTED BY THE ABOVE LICENCE, BE LIABLE TO YOU FOR DAMAGES, INCLUDING ANY GENERAL, SPECIAL, INCIDENTAL, OR CONSEQUENTIAL DAMAGES ARISING OUT OF THE USE OR INABILITY TO USE THE SOFTWARE (INCLUDING BUT NOT LIMITED TO LOSS OF DATA OR DATA BEING RENDERED INACCURATE OR LOSSES SUSTAINED BY YOU OR THIRD PARTIES OR A FAILURE OF THE SOFTWARE TO OPERATE WITH ANY OTHER SOFTWARE), EVEN IF SUCH HOLDER OR OTHER PARTY HAS BEEN ADVISED OF THE POSSIBILITY OF SUCH DAMAGES.
325            
326             1;
327            
328             __END__