line |
stmt |
bran |
cond |
sub |
pod |
time |
code |
1
|
|
|
|
|
|
|
package Hash::Filler;
|
2
|
|
|
|
|
|
|
|
3
|
1
|
|
|
1
|
|
2040
|
use strict;
|
|
1
|
|
|
|
|
2
|
|
|
1
|
|
|
|
|
64
|
|
4
|
1
|
|
|
1
|
|
8
|
use Carp;
|
|
1
|
|
|
|
|
3
|
|
|
1
|
|
|
|
|
131
|
|
5
|
1
|
|
|
1
|
|
6
|
use vars qw($VERSION $DEBUG $indent);
|
|
1
|
|
|
|
|
14
|
|
|
1
|
|
|
|
|
92
|
|
6
|
1
|
|
|
1
|
|
8955
|
use Time::HiRes qw(gettimeofday tv_interval);
|
|
1
|
|
|
|
|
7366
|
|
|
1
|
|
|
|
|
6
|
|
7
|
|
|
|
|
|
|
|
8
|
|
|
|
|
|
|
# How to check for the existence of an element
|
9
|
|
|
|
|
|
|
|
10
|
1
|
|
|
1
|
|
590
|
use constant TRUE => 0; # Test if the value is true
|
|
1
|
|
|
|
|
3
|
|
|
1
|
|
|
|
|
101
|
|
11
|
1
|
|
|
1
|
|
7
|
use constant DEFINED => 1; # Use defined()
|
|
1
|
|
|
|
|
2
|
|
|
1
|
|
|
|
|
49
|
|
12
|
1
|
|
|
1
|
|
6
|
use constant EXISTS => 2; # Use exists() (default)
|
|
1
|
|
|
|
|
4
|
|
|
1
|
|
|
|
|
47
|
|
13
|
|
|
|
|
|
|
|
14
|
1
|
|
|
1
|
|
5
|
use constant INDENT => 2; # How much to indent printouts
|
|
1
|
|
|
|
|
2
|
|
|
1
|
|
|
|
|
2694
|
|
15
|
|
|
|
|
|
|
|
16
|
|
|
|
|
|
|
$VERSION = '1.40';
|
17
|
|
|
|
|
|
|
$DEBUG = '0';
|
18
|
|
|
|
|
|
|
|
19
|
|
|
|
|
|
|
my $indent = 0;
|
20
|
|
|
|
|
|
|
|
21
|
|
|
|
|
|
|
# Preloaded methods go here.
|
22
|
|
|
|
|
|
|
|
23
|
|
|
|
|
|
|
sub new {
|
24
|
5
|
|
|
5
|
0
|
163
|
my $type = shift;
|
25
|
5
|
|
50
|
|
|
27
|
my $class = ref($type) || $type || "Hash::Filler";
|
26
|
|
|
|
|
|
|
|
27
|
5
|
|
|
|
|
32
|
my $self = {
|
28
|
|
|
|
|
|
|
'rules' => {}, # All the rules we know about
|
29
|
|
|
|
|
|
|
'wild' => [], # Wildcard rules
|
30
|
|
|
|
|
|
|
'times' => [], # Accumulated times for each rule
|
31
|
|
|
|
|
|
|
'calls' => [], # How many times each rule has been used
|
32
|
|
|
|
|
|
|
'id' => 0, # Current rule id
|
33
|
|
|
|
|
|
|
'loop' => 1, # Avoid loops by default
|
34
|
|
|
|
|
|
|
'method' => EXISTS, # Which method to use to check for
|
35
|
|
|
|
|
|
|
# existence of a hash key
|
36
|
|
|
|
|
|
|
};
|
37
|
|
|
|
|
|
|
|
38
|
5
|
|
|
|
|
21
|
bless $self, $class;
|
39
|
|
|
|
|
|
|
}
|
40
|
|
|
|
|
|
|
|
41
|
|
|
|
|
|
|
sub _sort { # This is to be used by the sort
|
42
|
|
|
|
|
|
|
# built-in
|
43
|
|
|
|
|
|
|
return
|
44
|
0
|
|
|
|
|
0
|
$b->{'pref'} <=> $a->{'pref'} or
|
45
|
11
|
0
|
0
|
11
|
|
37
|
@{$a->{'prereq'}} <=> @{$b->{'prereq'}} or
|
|
0
|
|
|
|
|
0
|
|
46
|
|
|
|
|
|
|
$a->{'used'} <=> $b->{'used'};
|
47
|
|
|
|
|
|
|
}
|
48
|
|
|
|
|
|
|
|
49
|
|
|
|
|
|
|
sub _print_rule {
|
50
|
0
|
|
|
0
|
|
0
|
my $self = shift;
|
51
|
0
|
|
|
|
|
0
|
my $rule = shift;
|
52
|
0
|
|
|
|
|
0
|
my $key = shift;
|
53
|
|
|
|
|
|
|
|
54
|
0
|
0
|
|
|
|
0
|
printf("%s[%d] rule for key %s, used %s, pref %s, %s be used\n",
|
|
|
0
|
|
|
|
|
|
55
|
|
|
|
|
|
|
' ' x $indent,
|
56
|
|
|
|
|
|
|
$rule->{'id'},
|
57
|
|
|
|
|
|
|
defined $rule->{'key'} ? $rule->{'key'} : '',
|
58
|
|
|
|
|
|
|
$rule->{'used'},
|
59
|
|
|
|
|
|
|
$rule->{'pref'},
|
60
|
|
|
|
|
|
|
$rule->{'use'} ? 'can' : 'cannot');
|
61
|
0
|
|
|
|
|
0
|
printf("%s|[called %d times (%0.6f secs)]\n",
|
62
|
|
|
|
|
|
|
' ' x $indent,
|
63
|
|
|
|
|
|
|
$self->{'calls'}->[$rule->{'id'}],
|
64
|
|
|
|
|
|
|
$self->{'times'}->[$rule->{'id'}]);
|
65
|
0
|
0
|
|
|
|
0
|
if (defined $key) {
|
66
|
0
|
|
|
|
|
0
|
printf("%s|[called to get key %s]\n",
|
67
|
|
|
|
|
|
|
' ' x $indent,
|
68
|
|
|
|
|
|
|
$key);
|
69
|
|
|
|
|
|
|
}
|
70
|
0
|
|
|
|
|
0
|
my $pre = 0;
|
71
|
0
|
|
|
|
|
0
|
foreach my $pr (sort @{$rule->{'prereq'}}) {
|
|
0
|
|
|
|
|
0
|
|
72
|
0
|
|
|
|
|
0
|
printf("%s+- prereq %s\n", ' ' x $indent, $pr);
|
73
|
0
|
|
|
|
|
0
|
++$pre;
|
74
|
|
|
|
|
|
|
}
|
75
|
0
|
0
|
|
|
|
0
|
printf("%s+- No prereq\n", ' ' x $indent) unless $pre;
|
76
|
|
|
|
|
|
|
}
|
77
|
|
|
|
|
|
|
|
78
|
|
|
|
|
|
|
sub dump_r_tree {
|
79
|
0
|
|
|
0
|
1
|
0
|
my $self = shift;
|
80
|
0
|
|
|
|
|
0
|
foreach my $key (keys %{$self->{'rules'}}) {
|
|
0
|
|
|
|
|
0
|
|
81
|
0
|
|
|
|
|
0
|
my $dumped = 0;
|
82
|
0
|
|
|
|
|
0
|
print "Rules for key $key:\n";
|
83
|
0
|
|
|
|
|
0
|
foreach my $rule (sort(_sort @{$self->{'rules'}->{$key}})) {
|
|
0
|
|
|
|
|
0
|
|
84
|
0
|
|
|
|
|
0
|
++$dumped;
|
85
|
0
|
|
|
|
|
0
|
$self->_print_rule($rule);
|
86
|
|
|
|
|
|
|
}
|
87
|
0
|
0
|
|
|
|
0
|
print " No rules.\n" unless $dumped;
|
88
|
|
|
|
|
|
|
}
|
89
|
0
|
|
|
|
|
0
|
my $dumped = 0;
|
90
|
0
|
|
|
|
|
0
|
print "Wildcard rules:\n";
|
91
|
0
|
|
|
|
|
0
|
foreach my $rule (sort(_sort @{$self->{'wild'}})) {
|
|
0
|
|
|
|
|
0
|
|
92
|
0
|
|
|
|
|
0
|
++$dumped;
|
93
|
0
|
|
|
|
|
0
|
$self->_print_rule($rule);
|
94
|
|
|
|
|
|
|
}
|
95
|
0
|
0
|
|
|
|
0
|
print " No rules.\n" unless $dumped;
|
96
|
|
|
|
|
|
|
}
|
97
|
|
|
|
|
|
|
|
98
|
|
|
|
|
|
|
sub loop {
|
99
|
0
|
|
|
0
|
1
|
0
|
$_[0]->{'loop'} = $_[1];
|
100
|
|
|
|
|
|
|
}
|
101
|
|
|
|
|
|
|
|
102
|
|
|
|
|
|
|
sub method {
|
103
|
0
|
|
|
0
|
1
|
0
|
$_[0]->{'method'} = $_[1];
|
104
|
|
|
|
|
|
|
}
|
105
|
|
|
|
|
|
|
|
106
|
|
|
|
|
|
|
sub stats {
|
107
|
1
|
|
|
1
|
1
|
5
|
@{$_[0]->{'calls'}};
|
|
1
|
|
|
|
|
5
|
|
108
|
|
|
|
|
|
|
}
|
109
|
|
|
|
|
|
|
|
110
|
|
|
|
|
|
|
sub profile {
|
111
|
0
|
|
|
0
|
1
|
0
|
@{$_[0]->{'times'}};
|
|
0
|
|
|
|
|
0
|
|
112
|
|
|
|
|
|
|
}
|
113
|
|
|
|
|
|
|
|
114
|
|
|
|
|
|
|
sub remove {
|
115
|
0
|
|
|
0
|
1
|
0
|
my $self = shift;
|
116
|
0
|
|
|
|
|
0
|
my $id = shift;
|
117
|
|
|
|
|
|
|
|
118
|
0
|
0
|
|
|
|
0
|
return unless $id;
|
119
|
|
|
|
|
|
|
|
120
|
0
|
|
|
|
|
0
|
foreach my $key (keys %{$self->{'rules'}}) {
|
|
0
|
|
|
|
|
0
|
|
121
|
0
|
|
|
|
|
0
|
foreach my $rule (@{$self->{'rules'}->{$key}}) {
|
|
0
|
|
|
|
|
0
|
|
122
|
0
|
0
|
|
|
|
0
|
if ($rule->{'id'} == $id) {
|
123
|
0
|
|
|
|
|
0
|
$rule->{'use'} = 0;
|
124
|
0
|
|
|
|
|
0
|
return;
|
125
|
|
|
|
|
|
|
}
|
126
|
|
|
|
|
|
|
}
|
127
|
|
|
|
|
|
|
}
|
128
|
0
|
|
|
|
|
0
|
foreach my $rule (@{$self->{'wild'}}) {
|
|
0
|
|
|
|
|
0
|
|
129
|
0
|
0
|
|
|
|
0
|
if ($rule->{'id'} == $id) {
|
130
|
0
|
|
|
|
|
0
|
$rule->{'use'} = 0;
|
131
|
0
|
|
|
|
|
0
|
return;
|
132
|
|
|
|
|
|
|
}
|
133
|
|
|
|
|
|
|
}
|
134
|
|
|
|
|
|
|
}
|
135
|
|
|
|
|
|
|
|
136
|
|
|
|
|
|
|
sub add {
|
137
|
15
|
|
|
15
|
1
|
106
|
my $ret;
|
138
|
|
|
|
|
|
|
|
139
|
15
|
100
|
|
|
|
30
|
if (defined $_[1]) { # Specific rule
|
140
|
13
|
100
|
|
|
|
13
|
push @{$_[0]->{'rules'}->{$_[1]}}, {
|
|
13
|
|
|
|
|
109
|
|
141
|
|
|
|
|
|
|
'key' => $_[1],
|
142
|
|
|
|
|
|
|
'code' => $_[2],
|
143
|
|
|
|
|
|
|
'prereq' => $_[3],
|
144
|
|
|
|
|
|
|
'pref' => $_[4] ? $_[4] : 100,
|
145
|
|
|
|
|
|
|
'used' => 0,
|
146
|
|
|
|
|
|
|
'use' => 1,
|
147
|
|
|
|
|
|
|
'id' => $ret = ++ $_[0]->{'id'},
|
148
|
|
|
|
|
|
|
};
|
149
|
|
|
|
|
|
|
}
|
150
|
|
|
|
|
|
|
else { # Wildcard rule
|
151
|
2
|
100
|
|
|
|
3
|
push @{$_[0]->{'wild'}}, {
|
|
2
|
|
|
|
|
14
|
|
152
|
|
|
|
|
|
|
'key' => undef,
|
153
|
|
|
|
|
|
|
'code' => $_[2],
|
154
|
|
|
|
|
|
|
'prereq' => $_[3],
|
155
|
|
|
|
|
|
|
'pref' => $_[4] ? $_[4] : 100,
|
156
|
|
|
|
|
|
|
'used' => 0,
|
157
|
|
|
|
|
|
|
'use' => 1,
|
158
|
|
|
|
|
|
|
'id' => $ret = ++ $_[0]->{'id'},
|
159
|
|
|
|
|
|
|
};
|
160
|
|
|
|
|
|
|
}
|
161
|
15
|
|
|
|
|
29
|
$ret;
|
162
|
|
|
|
|
|
|
}
|
163
|
|
|
|
|
|
|
|
164
|
|
|
|
|
|
|
sub _exists {
|
165
|
47
|
|
|
47
|
|
64
|
my $self = shift;
|
166
|
47
|
|
|
|
|
47
|
my $href = shift;
|
167
|
47
|
|
|
|
|
56
|
my $key = shift;
|
168
|
|
|
|
|
|
|
|
169
|
47
|
50
|
|
|
|
121
|
if ($self->{'method'} == DEFINED) {
|
|
|
50
|
|
|
|
|
|
|
|
0
|
|
|
|
|
|
170
|
0
|
0
|
|
|
|
0
|
return 1 if defined $href->{$key};
|
171
|
|
|
|
|
|
|
}
|
172
|
|
|
|
|
|
|
elsif ($self->{'method'} == EXISTS) {
|
173
|
47
|
100
|
|
|
|
158
|
return 1 if exists $href->{$key};
|
174
|
|
|
|
|
|
|
}
|
175
|
|
|
|
|
|
|
elsif (ref $self->{'method'} eq 'CODE') {
|
176
|
0
|
0
|
|
|
|
0
|
return 1 if $self->{'method'}->($href, $key);
|
177
|
|
|
|
|
|
|
}
|
178
|
|
|
|
|
|
|
else {
|
179
|
0
|
0
|
|
|
|
0
|
return 1 if $href->{$key};
|
180
|
|
|
|
|
|
|
}
|
181
|
25
|
|
|
|
|
59
|
return 0;
|
182
|
|
|
|
|
|
|
}
|
183
|
|
|
|
|
|
|
|
184
|
|
|
|
|
|
|
sub fill {
|
185
|
27
|
|
|
27
|
1
|
111
|
my $self = shift;
|
186
|
27
|
|
|
|
|
30
|
my $href = shift;
|
187
|
27
|
|
|
|
|
31
|
my $key = shift;
|
188
|
27
|
|
|
|
|
27
|
my $ret = 0;
|
189
|
|
|
|
|
|
|
|
190
|
27
|
50
|
|
|
|
94
|
croak "->fill() must be given a hash reference"
|
191
|
|
|
|
|
|
|
unless ref($href) eq 'HASH';
|
192
|
|
|
|
|
|
|
|
193
|
|
|
|
|
|
|
# Provide a quick exit if the hash
|
194
|
|
|
|
|
|
|
# key is already defined or if
|
195
|
|
|
|
|
|
|
# we have no rules to generate it.
|
196
|
|
|
|
|
|
|
|
197
|
27
|
|
|
|
|
42
|
++ $self->{'calls'}->[0]; # Keep the number of times ->fill
|
198
|
|
|
|
|
|
|
# has been called.
|
199
|
|
|
|
|
|
|
|
200
|
27
|
100
|
|
|
|
52
|
return 1
|
201
|
|
|
|
|
|
|
if $self->_exists($href, $key);
|
202
|
|
|
|
|
|
|
|
203
|
5
|
|
|
|
|
18
|
return 0
|
204
|
|
|
|
|
|
|
unless $self->{'rules'}->{$key} or
|
205
|
21
|
50
|
66
|
|
|
64
|
@{$self->{'wild'}};
|
206
|
|
|
|
|
|
|
|
207
|
|
|
|
|
|
|
# Look through the available rules
|
208
|
|
|
|
|
|
|
# and try to find an execution plan
|
209
|
|
|
|
|
|
|
# to fill the requested $key.
|
210
|
|
|
|
|
|
|
|
211
|
21
|
|
|
|
|
24
|
my @rulelist;
|
212
|
|
|
|
|
|
|
|
213
|
21
|
100
|
|
|
|
46
|
if ($self->{'rules'}->{$key}) {
|
214
|
16
|
|
|
|
|
17
|
push @rulelist, sort(_sort @{$self->{'rules'}->{$key}});
|
|
16
|
|
|
|
|
48
|
|
215
|
|
|
|
|
|
|
}
|
216
|
|
|
|
|
|
|
|
217
|
21
|
|
|
|
|
27
|
push @rulelist, sort(_sort @{$self->{'wild'}});
|
|
21
|
|
|
|
|
51
|
|
218
|
|
|
|
|
|
|
|
219
|
|
|
|
|
|
|
RULE:
|
220
|
21
|
|
|
|
|
32
|
foreach my $rule (@rulelist) {
|
221
|
|
|
|
|
|
|
|
222
|
|
|
|
|
|
|
next RULE # Watch out for infinite loops
|
223
|
23
|
100
|
66
|
|
|
106
|
if $self->{'loop'} and
|
224
|
|
|
|
|
|
|
$rule->{'used'};
|
225
|
|
|
|
|
|
|
|
226
|
20
|
|
|
|
|
25
|
$rule->{'used'} ++; # Mark this rule as being used
|
227
|
|
|
|
|
|
|
# to control infinite recursion
|
228
|
|
|
|
|
|
|
|
229
|
20
|
|
|
|
|
30
|
++ $self->{'calls'}->[$rule->{'id'}];
|
230
|
|
|
|
|
|
|
|
231
|
|
|
|
|
|
|
# Insure that all prerequisites
|
232
|
|
|
|
|
|
|
# are there before attempting to
|
233
|
|
|
|
|
|
|
# call this method
|
234
|
|
|
|
|
|
|
|
235
|
20
|
|
|
|
|
24
|
foreach my $pr (@{$rule->{'prereq'}}) {
|
|
20
|
|
|
|
|
37
|
|
236
|
|
|
|
|
|
|
|
237
|
|
|
|
|
|
|
# A rule cannot be invoked to resolve
|
238
|
|
|
|
|
|
|
# its own prerequisite as this might make
|
239
|
|
|
|
|
|
|
# no sense.
|
240
|
|
|
|
|
|
|
|
241
|
20
|
100
|
|
|
|
40
|
if ($pr eq $key) {
|
242
|
1
|
50
|
|
|
|
4
|
if (defined $rule->{'key'}) {
|
243
|
0
|
|
|
|
|
0
|
croak "Rule "
|
244
|
|
|
|
|
|
|
. $rule->{'id'}
|
245
|
|
|
|
|
|
|
. " has itself as prerequisite";
|
246
|
|
|
|
|
|
|
}
|
247
|
|
|
|
|
|
|
else { # A wildcard rule...
|
248
|
|
|
|
|
|
|
next RULE
|
249
|
1
|
50
|
|
|
|
2
|
unless $self->_exists($href, $pr);
|
250
|
|
|
|
|
|
|
}
|
251
|
|
|
|
|
|
|
}
|
252
|
|
|
|
|
|
|
|
253
|
|
|
|
|
|
|
# Recursive call. If required, attempt
|
254
|
|
|
|
|
|
|
# to fill this prerequisite using the
|
255
|
|
|
|
|
|
|
# available rules. If the prereq is
|
256
|
|
|
|
|
|
|
# already in the hash, this will return
|
257
|
|
|
|
|
|
|
# immediatly. The retval of this ->fill()
|
258
|
|
|
|
|
|
|
# is ignored as there might be more than
|
259
|
|
|
|
|
|
|
# one rule that can provide the missing
|
260
|
|
|
|
|
|
|
# prereq.
|
261
|
|
|
|
|
|
|
|
262
|
|
|
|
|
|
|
# XXX - Note that we might want to return false from this rule if the fill
|
263
|
|
|
|
|
|
|
# method for a prereq returns false. The current implementation allows the
|
264
|
|
|
|
|
|
|
# method's return value control the behavior of ->fill more fine-granedly.
|
265
|
|
|
|
|
|
|
|
266
|
19
|
|
|
|
|
26
|
$indent += INDENT;
|
267
|
19
|
|
|
|
|
76
|
$self->fill($href, $pr);
|
268
|
19
|
|
|
|
|
23
|
$indent -= INDENT;
|
269
|
|
|
|
|
|
|
|
270
|
|
|
|
|
|
|
# Insure that the required hash
|
271
|
|
|
|
|
|
|
# buckets are already filled
|
272
|
|
|
|
|
|
|
# before attempting to call the
|
273
|
|
|
|
|
|
|
# user supplied function.
|
274
|
|
|
|
|
|
|
|
275
|
|
|
|
|
|
|
next RULE
|
276
|
19
|
100
|
|
|
|
38
|
unless $self->_exists($href, $pr);
|
277
|
|
|
|
|
|
|
}
|
278
|
|
|
|
|
|
|
|
279
|
16
|
50
|
|
|
|
35
|
$self->_print_rule($rule, $key) if $DEBUG;
|
280
|
|
|
|
|
|
|
|
281
|
|
|
|
|
|
|
# Run and profile the execution of
|
282
|
|
|
|
|
|
|
# the user supplied method.
|
283
|
|
|
|
|
|
|
|
284
|
16
|
|
|
|
|
66
|
my $time = [gettimeofday];
|
285
|
16
|
|
|
|
|
51
|
$ret = $rule->{'code'}->($href, $key);
|
286
|
16
|
|
|
|
|
107
|
$time = tv_interval($time);
|
287
|
|
|
|
|
|
|
|
288
|
16
|
|
|
|
|
233
|
$self->{'times'}->[$rule->{'id'}] += $time;
|
289
|
16
|
|
|
|
|
28
|
$self->{'times'}->[0] += $time;
|
290
|
|
|
|
|
|
|
}
|
291
|
|
|
|
|
|
|
continue {
|
292
|
23
|
|
|
|
|
29
|
$rule->{'used'} --; # Rule is no longer used
|
293
|
23
|
100
|
|
|
|
69
|
return $ret # If a user-supplied sub was
|
294
|
|
|
|
|
|
|
if $ret; # succesful, we're done
|
295
|
|
|
|
|
|
|
}
|
296
|
|
|
|
|
|
|
|
297
|
5
|
|
|
|
|
13
|
return 0; # No rule matched or was succesful.
|
298
|
|
|
|
|
|
|
}
|
299
|
|
|
|
|
|
|
|
300
|
|
|
|
|
|
|
# Autoload methods go after =cut, and are processed by the autosplit program.
|
301
|
|
|
|
|
|
|
|
302
|
|
|
|
|
|
|
1;
|
303
|
|
|
|
|
|
|
__END__
|