File Coverage

blib/lib/Tie/Cacher.pm
Criterion Covered Total %
statement 243 255 95.2
branch 90 98 91.8
condition 5 8 62.5
subroutine 28 28 100.0
pod 21 21 100.0
total 387 410 94.3


line stmt bran cond sub pod time code
1             package Tie::Cacher;
2 2     2   44589 use 5.006;
  2         8  
  2         72  
3 2     2   12 use strict;
  2         3  
  2         77  
4 2     2   9 use warnings;
  2         8  
  2         63  
5              
6 2     2   1673 use AutoLoader qw(AUTOLOAD);
  2         3060  
  2         9  
7              
8             our $VERSION = "0.09";
9 2     2   84 use Carp;
  2         3  
  2         188  
10              
11 2     2   9 use base qw(Tie::Hash);
  2         4  
  2         1844  
12              
13             # Object indices
14             sub TC_HEAD () { 0 };
15             sub TC_NODES () { 1 };
16             sub TC_HIT () { 2 };
17             sub TC_MISSED () { 3 };
18             # We could get the effect of count by using keys, but it would reset
19             # first_key/last_key
20             sub TC_COUNT () { 4 };
21             sub TC_MAX_COUNT() { 5 };
22             sub TC_VALIDATE () { 6 };
23             sub TC_LOAD () { 7 };
24             sub TC_SAVE () { 8 };
25             sub TC_USER_DATA() { 9 };
26              
27             # Node indices
28             sub TC_DATA () { 0 }; # Must be zero (documented accessmethod)
29             sub TC_KEY () { 1 };
30             sub TC_PREVIOUS () { 2 };
31             sub TC_NEXT () { 3 };
32             sub TC_NODE_SIZE() { 4 };
33              
34             # This should effectively give us +inf
35             sub INF () { 1e5000000000 };
36              
37             my %attributes = map {($_, 1)} qw(validate load save max_count user_data);
38             sub new {
39 52 50   52 1 8215 defined(my $class = shift) ||
40             croak "Too few arguments. Usage: Tie::Cacher->new(key-val-pairs)";
41 52         164 my $cacher = bless [], $class;
42 52         103 my $head = [];
43 52         190 $cacher->[TC_HEAD] = $head;
44 52         110 $head->[TC_NEXT] = $head;
45 52         100 $head->[TC_PREVIOUS] = $head;
46 52         128 $cacher->[TC_HIT] = $cacher->[TC_MISSED] = $cacher->[TC_COUNT] = 0;
47 52         119 $cacher->[TC_MAX_COUNT] = INF;
48 52         99 $cacher->[TC_NODES] = {};
49              
50 52 100       201 if (@_ % 2) {
51 6 50       24 if (@_ == 1) {
52 6 100       38 if (ref($_[0])) {
53 2         3 @_ = %{$_[0]};
  2         13  
54             } else {
55 4         17 @_ = (max_count => $_[0]);
56             }
57             }
58 6 50       20 croak "Odd number of arguments. Usage: $class->new(key-val-pairs)" if
59             @_ %2;
60             }
61 52         160 while (@_) {
62 84         125 my $key = shift;
63 84 100       641 $attributes{$key} || croak "Unknown key $key in $class->new, $class";
64 82         2351 $cacher->$key(shift);
65             }
66 50   50     142 $cacher->[TC_MAX_COUNT] ||= INF; # Infinity really
67 50         198 return $cacher;
68             }
69              
70             sub keys : method {
71 106     106 1 10279 return CORE::keys %{shift->[TC_NODES]};
  106         689  
72             }
73              
74             sub exists : method {
75 328     328 1 4965 my $cacher = shift;
76 328         1967 return exists $cacher->[TC_NODES]{shift()};
77             }
78              
79             sub count {
80 420     420 1 97462 return shift->[TC_COUNT]
81             }
82              
83             sub DESTROY {
84 84     84   24677 my $cacher = shift;
85              
86             # Make nodes single connected
87 84         234 $cacher->[TC_NODES] = {};
88 84         104245 my $head = $cacher->[TC_HEAD];
89 84         169 my $ptr = $head->[TC_PREVIOUS];
90 84         169 undef $ptr->[TC_NEXT];
91 84         719 $ptr = $head->[TC_NEXT];
92 84         177 $head->[TC_NEXT] = $head->[TC_PREVIOUS] = $head;
93 84         172 $cacher->[TC_COUNT] = 0;
94              
95 84         8233 while ($ptr) {
96             # We must remove both the forward and backward links, otherwise
97             # perl will do a recursive free and might run out of stackspace
98 200551         188409 undef $ptr->[TC_PREVIOUS];
99 200551         400329 $ptr = delete $ptr->[TC_NEXT];
100             }
101             }
102              
103             *clear = \&DESTROY;
104              
105             # Tie interface aliasas
106             *STORE = \&store;
107             *FETCH = \&fetch;
108             *TIEHASH = \&new;
109             *FIRSTKEY = \&first_key;
110             *NEXTKEY = \&next_key;
111             *EXISTS = \&exists;
112             *DELETE = \&delete;
113             *CLEAR = \&clear;
114              
115             1;
116              
117             __END__