File Coverage

blib/lib/Tie/Hash/MultiValueOrdered.pm
Criterion Covered Total %
statement 63 109 57.8
branch 6 14 42.8
condition 1 2 50.0
subroutine 18 29 62.0
pod 13 13 100.0
total 101 167 60.4


line stmt bran cond sub pod time code
1 5     5   65034 use 5.008;
  5         28  
2 5     5   26 use strict;
  5         11  
  5         100  
3 5     5   22 use warnings;
  5         17  
  5         386  
4              
5             {
6             package Tie::Hash::MultiValueOrdered;
7            
8             our $AUTHORITY = 'cpan:TOBYINK';
9             our $VERSION = '0.006';
10            
11             use constant {
12 5         753 IDX_DATA => 0,
13             IDX_ORDER => 1,
14             IDX_LAST => 2,
15             IDX_SEEN => 3,
16             IDX_MODE => 4,
17             NEXT_IDX => 5,
18 5     5   35 };
  5         8  
19             use constant {
20 5         3338 MODE_LAST => -1,
21             MODE_FIRST => 0,
22             MODE_REF => 'ref',
23             MODE_ITER => 'iter',
24 5     5   36 };
  5         9  
25            
26 1     1 1 4 sub fetch_first { $_[0][IDX_MODE] = MODE_FIRST }
27 1     1 1 4 sub fetch_last { $_[0][IDX_MODE] = MODE_LAST }
28 3     3 1 623 sub fetch_list { $_[0][IDX_MODE] = MODE_REF }
29 0     0 1 0 sub fetch_iterator { $_[0][IDX_MODE] = MODE_ITER }
30            
31             sub TIEHASH {
32 7     7   102 my $class = shift;
33 7         36 bless [{}, [], 0, {}, -1], $class;
34             }
35             sub STORE {
36 22     22   81 my ($tied, $key, $value) = @_;
37 22         31 $key = "$key";
38 22         37 push @{$tied->[IDX_ORDER]}, $key;
  22         73  
39 22         40 push @{$tied->[IDX_DATA]{$key}}, $value;
  22         171  
40             }
41             sub FETCH {
42 10     10   36 my ($tied, $key) = @_;
43 10         18 my $mode = $tied->[IDX_MODE];
44 10 100       40 if ($mode eq 'ref')
    50          
45             {
46 4   50     74 return $tied->[IDX_DATA]{$key} || [];
47             }
48             elsif ($mode eq 'iter')
49             {
50 0 0       0 my @values = @{ $tied->[IDX_DATA]{$key} || [] };
  0         0  
51 0     0   0 return sub { shift @values };
  0         0  
52             }
53             else
54             {
55 6 50       26 return unless exists $tied->[IDX_DATA]{"$key"};
56 6         30 return $tied->[IDX_DATA]{$key}[$mode];
57             }
58             }
59             sub EXISTS {
60 4     4   59 my ($tied, $key) = @_;
61 4         14 return exists $tied->[IDX_DATA]{"$key"};
62             }
63             sub DELETE {
64 0     0   0 my ($tied, $key) = @_;
65 0         0 my $r = delete $tied->[IDX_DATA]{"$key"};
66 0 0       0 return $r->[-1] if $r;
67 0         0 return;
68             }
69             sub CLEAR {
70 0     0   0 my $tied = shift;
71 0         0 $tied->[IDX_DATA] = {};
72 0         0 $tied->[IDX_ORDER] = [];
73 0         0 $tied->[IDX_LAST] = 0;
74 0         0 $tied->[IDX_SEEN] = {};
75 0         0 return;
76             }
77             sub FIRSTKEY {
78 7     7   790 my $tied = shift;
79 7         18 $tied->[IDX_LAST] = -1;
80 7         18 $tied->[IDX_SEEN] = {};
81 7         59 return $tied->NEXTKEY;
82             }
83             sub NEXTKEY {
84 5     5   48 no warnings qw(uninitialized);
  5         16  
  5         3411  
85 19     19   35 my $tied = shift;
86 19         32 my $i = ++$tied->[IDX_LAST];
87 19         67 $i++ while $tied->[IDX_SEEN]{ $tied->[IDX_ORDER][$i] };
88 19         57 $tied->[IDX_SEEN]{ $tied->[IDX_ORDER][$i] }++;
89 19         28 my $key = $tied->[IDX_ORDER][$i];
90 19 50       43 if (wantarray) {
91             return (
92 0         0 $tied->[IDX_ORDER][$i],
93             $tied->FETCH( $tied->[IDX_ORDER][$i] ),
94             );
95             }
96 19         70 return $tied->[IDX_ORDER][$i];
97             }
98             sub get {
99 1     1 1 322 my ($tied, $key) = @_;
100 1 50       3 return my @list = @{ $tied->[IDX_DATA]{"$key"} || [] };
  1         12  
101             }
102             # not deep clone but data clone
103             sub _dclone {
104 5     5   10 my $tied = shift;
105 5         8 my %data;
106 5         9 while (my ($key, $value) = each %{$tied->[IDX_DATA]}) {
  14         53  
107 9         30 $data{$key} = [@$value];
108             }
109 5         32 \%data;
110             }
111             sub pairs {
112 5     5 1 11 my $tied = shift;
113 5         9 my %clone = %{ $tied->_dclone };
  5         29  
114             return map {
115 18         28 $_, shift @{$clone{$_}}
  18         59  
116 5         14 } @{$tied->[IDX_ORDER]}
  5         15  
117             }
118             sub pair_refs {
119 0     0 1   my $tied = shift;
120 0           my %clone = %{ $tied->_dclone };
  0            
121             return map {
122 0           [ $_, shift @{$clone{$_}} ]
  0            
123 0           } @{$tied->[IDX_ORDER]}
  0            
124             }
125             sub all_keys {
126 0     0 1   my $tied = shift;
127 0           return @{$tied->[IDX_ORDER]};
  0            
128             }
129             sub keys {
130 0     0 1   my $tied = shift;
131 0           my %seen;
132 0           return grep { not $seen{$_}++ } @{$tied->[IDX_ORDER]};
  0            
  0            
133             }
134             sub rr_keys {
135 0     0 1   my $tied = shift;
136 0           my %seen;
137 0           return reverse grep { not $seen{$_}++ } reverse @{$tied->[IDX_ORDER]};
  0            
  0            
138             }
139             sub all_values {
140 0     0 1   my $tied = shift;
141 0           my $alt = 1;
142 0           return grep { $alt=!$alt } $tied->pairs;
  0            
143             }
144             sub values {
145 0     0 1   my $tied = shift;
146 0           return map { $tied->[IDX_DATA]{$_}[-1] } $tied->keys;
  0            
147             }
148             sub rr_values {
149 0     0 1   my $tied = shift;
150 0           return map { $tied->[IDX_DATA]{$_}[0] } $tied->keys;
  0            
151             }
152             }
153              
154             1;
155              
156              
157             __END__