line |
stmt |
bran |
cond |
sub |
pod |
time |
code |
1
|
|
|
|
|
|
|
package B::OptreeShortestPath; |
2
|
|
|
|
|
|
|
|
3
|
1
|
|
|
1
|
|
26888
|
use warnings; |
|
1
|
|
|
|
|
3
|
|
|
1
|
|
|
|
|
42
|
|
4
|
1
|
|
|
1
|
|
7
|
use strict; |
|
1
|
|
|
|
|
3
|
|
|
1
|
|
|
|
|
42
|
|
5
|
1
|
|
|
1
|
|
6
|
use B qw( svref_2object ); |
|
1
|
|
|
|
|
3
|
|
|
1
|
|
|
|
|
1049
|
|
6
|
|
|
|
|
|
|
|
7
|
|
|
|
|
|
|
=head1 NAME |
8
|
|
|
|
|
|
|
|
9
|
|
|
|
|
|
|
B::OptreeShortestPath - The great new B::OptreeShortestPath! |
10
|
|
|
|
|
|
|
|
11
|
|
|
|
|
|
|
=head1 VERSION |
12
|
|
|
|
|
|
|
|
13
|
|
|
|
|
|
|
Version 0.02 |
14
|
|
|
|
|
|
|
|
15
|
|
|
|
|
|
|
=cut |
16
|
|
|
|
|
|
|
|
17
|
|
|
|
|
|
|
our $VERSION = '0.02'; |
18
|
|
|
|
|
|
|
|
19
|
|
|
|
|
|
|
=head1 DESCRIPTION |
20
|
|
|
|
|
|
|
|
21
|
|
|
|
|
|
|
This module adds the methods ->shortest_path( $op ) and ->all_paths() |
22
|
|
|
|
|
|
|
to all B::OP objects in an optree. |
23
|
|
|
|
|
|
|
|
24
|
|
|
|
|
|
|
=head1 SYNOPSIS |
25
|
|
|
|
|
|
|
|
26
|
|
|
|
|
|
|
use B qw( main_root main_start ); |
27
|
|
|
|
|
|
|
use B::OptreeShortestPath; |
28
|
|
|
|
|
|
|
|
29
|
|
|
|
|
|
|
for ( main_start()->shortest_path( main_root() ) ) { |
30
|
|
|
|
|
|
|
print "$_\n"; |
31
|
|
|
|
|
|
|
} |
32
|
|
|
|
|
|
|
|
33
|
|
|
|
|
|
|
=head1 METHODS |
34
|
|
|
|
|
|
|
|
35
|
|
|
|
|
|
|
=over 4 |
36
|
|
|
|
|
|
|
|
37
|
|
|
|
|
|
|
=item $op->shortest_path( $other_op ) |
38
|
|
|
|
|
|
|
|
39
|
|
|
|
|
|
|
Returns a list of the shortest paths from $op to $other_op. Each path |
40
|
|
|
|
|
|
|
is a string approximating a bunch of chained method calls. |
41
|
|
|
|
|
|
|
|
42
|
|
|
|
|
|
|
"->next->sibling->next", |
43
|
|
|
|
|
|
|
"->sibling->sibling->next" |
44
|
|
|
|
|
|
|
|
45
|
|
|
|
|
|
|
=cut |
46
|
|
|
|
|
|
|
|
47
|
|
|
|
|
|
|
sub B::OP::shortest_path { |
48
|
0
|
|
|
0
|
|
|
my ( $op, $target ) = @_; |
49
|
0
|
|
|
|
|
|
my $search = qr/\b$$op\b(.+)\b$$target\b/; |
50
|
|
|
|
|
|
|
|
51
|
0
|
0
|
|
|
|
|
return if $$op == $$target; |
52
|
|
|
|
|
|
|
|
53
|
0
|
|
|
|
|
|
my @paths; |
54
|
|
|
|
|
|
|
my $len; |
55
|
0
|
|
|
|
|
|
for ( $op->all_paths ) { |
56
|
0
|
0
|
|
|
|
|
next unless /$search/; |
57
|
0
|
|
|
|
|
|
$_ = $1; |
58
|
0
|
|
|
|
|
|
tr/NOFS//cd; |
59
|
|
|
|
|
|
|
|
60
|
0
|
0
|
|
|
|
|
if ( not defined $len ) { |
|
|
0
|
|
|
|
|
|
|
|
0
|
|
|
|
|
|
|
|
0
|
|
|
|
|
|
61
|
0
|
|
|
|
|
|
$len = length; |
62
|
0
|
|
|
|
|
|
@paths = $_; |
63
|
|
|
|
|
|
|
} |
64
|
|
|
|
|
|
|
elsif ( $len < length ) { |
65
|
|
|
|
|
|
|
|
66
|
|
|
|
|
|
|
} |
67
|
|
|
|
|
|
|
elsif ( $len == length ) { |
68
|
0
|
|
|
|
|
|
my %seen; |
69
|
0
|
|
|
|
|
|
@paths = grep !$seen{$_}++, @paths, $_; |
70
|
|
|
|
|
|
|
} |
71
|
|
|
|
|
|
|
elsif ( $len > length ) { |
72
|
0
|
|
|
|
|
|
$len = length; |
73
|
0
|
|
|
|
|
|
@paths = $_; |
74
|
|
|
|
|
|
|
} |
75
|
|
|
|
|
|
|
|
76
|
0
|
0
|
|
|
|
|
die "@paths" if grep length() != $len, @paths; |
77
|
|
|
|
|
|
|
} |
78
|
|
|
|
|
|
|
|
79
|
|
|
|
|
|
|
# Shortest paths, now fixing up for |
80
|
0
|
|
|
|
|
|
for (@paths) { |
81
|
0
|
|
|
|
|
|
s/N/->next/g; |
82
|
0
|
|
|
|
|
|
s/F/->first/g; |
83
|
0
|
|
|
|
|
|
s/O/->other/g; |
84
|
0
|
|
|
|
|
|
s/S/->sibling/g; |
85
|
|
|
|
|
|
|
} |
86
|
|
|
|
|
|
|
|
87
|
0
|
|
|
|
|
|
return @paths; |
88
|
|
|
|
|
|
|
} |
89
|
|
|
|
|
|
|
|
90
|
|
|
|
|
|
|
=item $op->all_paths() |
91
|
|
|
|
|
|
|
|
92
|
|
|
|
|
|
|
Returns a list of paths from this node to all other nodes. |
93
|
|
|
|
|
|
|
|
94
|
|
|
|
|
|
|
=back |
95
|
|
|
|
|
|
|
|
96
|
|
|
|
|
|
|
=cut |
97
|
|
|
|
|
|
|
|
98
|
|
|
|
|
|
|
sub B::OP::all_paths { |
99
|
0
|
|
|
0
|
|
|
my ( $op, $cx ) = @_; |
100
|
0
|
0
|
|
|
|
|
$cx = '' if not defined $cx; |
101
|
0
|
0
|
|
|
|
|
return "$cx SELF" if $cx =~ /\b$$op\b/; |
102
|
|
|
|
|
|
|
|
103
|
|
|
|
|
|
|
return ( |
104
|
0
|
0
|
0
|
|
|
|
( $cx =~ /^(?:\d+ S )*(?:\d+ N )*$/ |
|
|
0
|
0
|
|
|
|
|
|
|
0
|
|
|
|
|
|
105
|
|
|
|
|
|
|
? $op->next->all_paths("$cx$$op N ") |
106
|
|
|
|
|
|
|
: () |
107
|
|
|
|
|
|
|
), |
108
|
|
|
|
|
|
|
( $cx =~ /^(?:\d+ S )*(?:\d+ N )*(?:\d+ [FS] )*$/ |
109
|
|
|
|
|
|
|
&& $op->can('first') ? $op->first->all_paths("$cx$$op F ") |
110
|
|
|
|
|
|
|
: () |
111
|
|
|
|
|
|
|
), |
112
|
|
|
|
|
|
|
( $cx =~ /^(?:\d+ S )*(?:\d+ N )*(?:\d+ [FS] )*$/ |
113
|
|
|
|
|
|
|
&& $op->can('sibling') ? $op->sibling->all_paths("$cx$$op S ") |
114
|
|
|
|
|
|
|
: () |
115
|
|
|
|
|
|
|
), |
116
|
|
|
|
|
|
|
); |
117
|
|
|
|
|
|
|
} |
118
|
|
|
|
|
|
|
|
119
|
0
|
|
|
0
|
|
|
sub B::NULL::all_paths {"$_[1]NULL"} |
120
|
|
|
|
|
|
|
|
121
|
|
|
|
|
|
|
sub compile { |
122
|
|
|
|
|
|
|
return sub { |
123
|
0
|
|
|
0
|
|
|
my $sub = svref_2object( sub { 1 for 1; } ); |
|
0
|
|
|
|
|
|
|
124
|
0
|
|
|
|
|
|
print "$_\n" for $sub->START->shortest_path( $sub->ROOT ); |
125
|
|
|
|
|
|
|
|
126
|
0
|
|
|
0
|
0
|
|
}; |
127
|
|
|
|
|
|
|
} |
128
|
|
|
|
|
|
|
|
129
|
|
|
|
|
|
|
=head1 AUTHOR |
130
|
|
|
|
|
|
|
|
131
|
|
|
|
|
|
|
Joshua ben Jore, C<< >> |
132
|
|
|
|
|
|
|
|
133
|
|
|
|
|
|
|
=head1 BUGS |
134
|
|
|
|
|
|
|
|
135
|
|
|
|
|
|
|
Please report any bugs or feature requests to |
136
|
|
|
|
|
|
|
C, or through the web interface at |
137
|
|
|
|
|
|
|
L. |
138
|
|
|
|
|
|
|
I will be notified, and then you'll automatically be notified of progress on |
139
|
|
|
|
|
|
|
your bug as I make changes. |
140
|
|
|
|
|
|
|
|
141
|
|
|
|
|
|
|
=head1 ACKNOWLEDGEMENTS |
142
|
|
|
|
|
|
|
|
143
|
|
|
|
|
|
|
=head1 COPYRIGHT & LICENSE |
144
|
|
|
|
|
|
|
|
145
|
|
|
|
|
|
|
Copyright 2005 Joshua ben Jore, all rights reserved. |
146
|
|
|
|
|
|
|
|
147
|
|
|
|
|
|
|
This program is free software; you can redistribute it and/or modify it |
148
|
|
|
|
|
|
|
under the same terms as Perl itself. |
149
|
|
|
|
|
|
|
|
150
|
|
|
|
|
|
|
=cut |
151
|
|
|
|
|
|
|
|
152
|
|
|
|
|
|
|
qq[ "Hey, what does this switch labeled 'Pulsating Ejector' do?" |
153
|
|
|
|
|
|
|
"I don't know... I've always been too afraid to find out" ]; |