File Coverage

blib/lib/Hash/MultiKey.pm
Criterion Covered Total %
statement 43 43 100.0
branch 16 26 61.5
condition n/a
subroutine 14 14 100.0
pod n/a
total 73 83 87.9


line stmt bran cond sub pod time code
1             package Hash::MultiKey;
2              
3 17     17   493159 use 5.006;
  17         70  
  17         715  
4 17     17   99 use strict;
  17         34  
  17         2991  
5 17     17   101 use warnings;
  17         42  
  17         844  
6              
7 17     17   111 use Carp;
  17         28  
  17         1836  
8              
9 17     17   91 use vars qw($VERSION);
  17         47  
  17         12204  
10             $VERSION = '0.06';
11              
12             # ---[ Implementation Overview ]----------------------------------------
13             #
14             # The first implementation of this module was based in an explicit tree.
15             # Right after its announcement in news:comp.lang.perl.modules Benjamin
16             # Goldberg suggested a radically different approach, far much simple and
17             # efficient. The current code is entirely based on his idea.
18             #
19             # Multi-key hashes are implemented now with a plain hash. There is no
20             # nesting involved.
21             #
22             # Lists of keys are converted to strings with pack():
23             #
24             # $key = pack 'N' . ('w/a*' x @$keys), scalar(@$keys), @$keys;
25             #
26             # and that $key is what's used in the underlying hash. The first chunk
27             # stores the number of keys, to be used afterwards when we decode it.
28             # Then, pairs length_of_key/key follow.
29             #
30             # Conversely, to retrieve the original list of keys from a real key we
31             # use unpack():
32             #
33             # $n = unpack 'N', $key;
34             # [ unpack 'x4' . ('w/a*' x $n), $key ];
35             #
36             # Iteration is delegated to the iterator of the very hash.
37             #
38             # Knowing that the following code is crystal clear, so comments have
39             # been removed altogether.
40             #
41             # ----------------------------------------------------------------------
42              
43              
44             sub TIEHASH {
45 17     17   259 bless {}, shift;
46             }
47              
48             sub CLEAR {
49 2     2   14 %{ shift() } = ();
  2         10  
50             }
51              
52             sub FETCH {
53 273     273   23701 my ($self, $keys) = @_;
54 273 50       810 $keys = [$keys eq '' ? ('') : split /$;/, $keys, -1] unless ref $keys eq 'ARRAY';
    100          
55 273 100       671 @$keys or croak "Empty multi-key\n";
56 272         1777 $self->{pack 'N' . ('w/a*' x @$keys), scalar(@$keys), @$keys};
57             }
58              
59             sub STORE {
60 153     153   8798 my ($self, $keys, $value) = @_;
61 153 0       722 $keys = [$keys eq '' ? ('') : split /$;/, $keys, -1] unless ref $keys eq 'ARRAY';
    50          
62 153 100       420 @$keys or croak "Empty multi-key\n";
63 152         1255 $self->{pack 'N' . ('w/a*' x @$keys), scalar(@$keys), @$keys} = $value;
64             }
65              
66             sub DELETE {
67 68     68   23982 my ($self, $keys) = @_;
68 68 0       210 $keys = [$keys eq '' ? ('') : split /$;/, $keys, -1] unless ref $keys eq 'ARRAY';
    50          
69 68 100       229 @$keys or croak "Empty multi-key\n";
70 67         564 delete $self->{pack 'N' . ('w/a*' x @$keys), scalar(@$keys), @$keys};
71             }
72              
73             sub EXISTS {
74 103     103   30507 my ($self, $keys) = @_;
75 103 0       2542 $keys = [$keys eq '' ? ('') : split /$;/, $keys, -1] unless ref $keys eq 'ARRAY';
    50          
76 103 100       293 @$keys or croak "Empty multi-key\n";
77 102         1472 exists $self->{pack 'N' . ('w/a*' x @$keys), scalar(@$keys), @$keys};
78             }
79              
80             sub FIRSTKEY {
81 95     95   9260 my ($self) = @_;
82 95         142 keys %$self; # reset iterator
83 95         201 $self->NEXTKEY;
84             }
85              
86             sub NEXTKEY {
87 425     425   35691 my ($self) = @_;
88 425 100       1343 defined(my $key = each %$self) or return;
89 330         3032 my $n = unpack 'N', $key;
90 330         1938 [ unpack 'x4' . ('w/a*' x $n), $key ];
91             }
92              
93             sub SCALAR {
94 4     4   761 my ($self) = @_;
95 4         21 scalar %$self;
96             }
97              
98             1;
99              
100              
101             __END__