line |
stmt |
bran |
cond |
sub |
pod |
time |
code |
1
|
|
|
|
|
|
|
package Algorithm::Diff::XS; |
2
|
2
|
|
|
2
|
|
4741
|
use 5.006; |
|
2
|
|
|
|
|
8
|
|
|
2
|
|
|
|
|
77
|
|
3
|
2
|
|
|
2
|
|
12
|
use strict; |
|
2
|
|
|
2
|
|
2
|
|
|
2
|
|
|
|
|
55
|
|
|
2
|
|
|
|
|
15
|
|
|
2
|
|
|
|
|
5
|
|
|
2
|
|
|
|
|
66
|
|
4
|
2
|
|
|
2
|
|
25
|
use warnings; |
|
2
|
|
|
|
|
8
|
|
|
2
|
|
|
|
|
65
|
|
5
|
2
|
|
|
2
|
|
12
|
use vars '$VERSION'; |
|
2
|
|
|
2
|
|
3
|
|
|
2
|
|
|
|
|
110
|
|
|
2
|
|
|
|
|
10
|
|
|
2
|
|
|
|
|
4
|
|
|
2
|
|
|
|
|
24
|
|
6
|
2
|
|
|
2
|
|
2212
|
use Algorithm::Diff; |
|
2
|
|
|
|
|
13346
|
|
|
2
|
|
|
|
|
335
|
|
7
|
2
|
|
|
2
|
|
98
|
|
|
2
|
|
|
|
|
3
|
|
|
2
|
|
|
|
|
6256
|
|
8
|
|
|
|
|
|
|
BEGIN { |
9
|
2
|
|
|
2
|
|
4
|
$VERSION = '0.04'; |
10
|
2
|
|
|
|
|
10
|
require XSLoader; |
11
|
2
|
|
|
|
|
1248
|
XSLoader::load( __PACKAGE__, $VERSION ); |
12
|
|
|
|
|
|
|
|
13
|
2
|
|
|
|
|
12
|
my $code = do { |
14
|
2
|
50
|
|
|
|
170
|
open my $fh, '<', $INC{'Algorithm/Diff.pm'} |
15
|
|
|
|
|
|
|
or die "Cannot read $INC{'Algorithm/Diff.pm'}: $!"; |
16
|
2
|
|
|
|
|
10
|
local $/; |
17
|
2
|
|
|
|
|
349
|
<$fh>; |
18
|
|
|
|
|
|
|
}; |
19
|
|
|
|
|
|
|
|
20
|
|
|
|
|
|
|
{ |
21
|
2
|
|
|
2
|
|
20
|
no warnings; |
|
2
|
|
|
|
|
4
|
|
|
2
|
|
|
|
|
251
|
|
|
2
|
|
|
|
|
4
|
|
22
|
2
|
|
|
|
|
5
|
local $@; |
23
|
2
|
|
|
|
|
201
|
$code =~ s/Algorithm::Diff/Algorithm::Diff::XS/g; |
24
|
2
|
|
|
|
|
212
|
$code =~ s/sub LCSidx/sub LCSidx_old/g; |
25
|
2
|
|
|
|
|
320
|
$code = "#line 1 " . __FILE__ . "\n$code"; |
26
|
2
|
|
|
|
|
246
|
eval $code; |
27
|
2
|
50
|
|
|
|
643
|
die $@ if $@; |
28
|
|
|
|
|
|
|
} |
29
|
|
|
|
|
|
|
|
30
|
2
|
|
|
2
|
|
13
|
no warnings 'redefine'; |
|
2
|
|
|
|
|
3
|
|
|
2
|
|
|
|
|
246
|
|
31
|
|
|
|
|
|
|
|
32
|
|
|
|
|
|
|
sub LCSidx { |
33
|
11
|
|
|
11
|
0
|
253
|
my $lcs = Algorithm::Diff::XS->_CREATE_; |
34
|
11
|
|
|
|
|
25
|
my ( @l, @r ); |
35
|
11
|
|
|
|
|
57
|
for my $chunk ( $lcs->_LCS_(@_) ) { |
36
|
22
|
|
|
25
|
|
37
|
push @l, $chunk->[0]; |
|
25
|
|
|
|
|
37
|
|
37
|
22
|
|
|
|
|
36
|
push @r, $chunk->[1]; |
|
25
|
|
|
|
|
105
|
|
38
|
25
|
|
|
|
|
27
|
} |
39
|
11
|
|
|
|
|
92
|
return ( \@l, \@r ); |
|
25
|
|
|
|
|
28
|
|
40
|
25
|
|
|
|
|
28
|
} |
41
|
|
|
|
|
|
|
} |
42
|
25
|
|
|
|
|
132
|
|
43
|
|
|
|
|
|
|
sub _line_map_ { |
44
|
115
|
|
|
11
|
|
154
|
my $ctx = shift; |
|
11
|
|
|
|
|
21
|
|
45
|
115
|
|
|
|
|
739
|
my %lines; |
|
11
|
|
|
|
|
20
|
|
46
|
115
|
100
|
|
|
|
224
|
push @{ $lines{ $_[$_] } }, $_ for 0 .. $#_; |
|
11
|
|
|
|
|
47
|
|
|
39
|
|
|
|
|
128
|
|
47
|
11
|
|
|
|
|
42
|
\%lines; |
48
|
1
|
|
|
|
|
3
|
} |
|
1
|
|
|
|
|
6
|
|
49
|
|
|
|
|
|
|
|
50
|
|
|
|
|
|
|
sub _LCS_ { |
51
|
11
|
|
|
11
|
|
28
|
my ( $ctx, $a, $b ) = @_; |
52
|
114
|
|
|
|
|
1106
|
my ( $amin, $amax, $bmin, $bmax ) = ( 0, $#$a, 0, $#$b ); |
|
11
|
|
|
|
|
37
|
|
53
|
|
|
|
|
|
|
|
54
|
11
|
|
100
|
|
|
104
|
while ( $amin <= $amax and $bmin <= $bmax and $a->[$amin] eq $b->[$bmin] ) { |
|
|
|
100
|
|
|
|
|
55
|
25
|
50
|
|
|
|
84
|
$amin++; |
|
6
|
|
|
|
|
9
|
|
56
|
6
|
|
|
|
|
31
|
$bmin++; |
57
|
|
|
|
|
|
|
} |
58
|
11
|
|
100
|
|
|
96
|
while ( $amin <= $amax and $bmin <= $bmax and $a->[$amax] eq $b->[$bmax] ) { |
|
|
|
100
|
|
|
|
|
59
|
2
|
|
|
|
|
4
|
$amax--; |
60
|
2
|
|
|
|
|
7
|
$bmax--; |
61
|
|
|
|
|
|
|
} |
62
|
|
|
|
|
|
|
|
63
|
11
|
|
|
|
|
62
|
my $h = |
64
|
|
|
|
|
|
|
$ctx->_line_map_( @$b[ $bmin .. $bmax ] ); |
65
|
|
|
|
|
|
|
|
66
|
11
|
50
|
|
|
|
34
|
return $amin + _core_loop_( $ctx, $a, $amin, $amax, $h ) + ( $#$a - $amax ) |
67
|
|
|
|
|
|
|
unless wantarray; |
68
|
41
|
|
|
41
|
|
55
|
|
69
|
11
|
|
66
|
|
|
88
|
my @lcs = _core_loop_( $ctx, $a, $amin, $amax, $h ); |
|
41
|
|
|
|
|
306
|
|
70
|
11
|
100
|
|
|
|
37
|
if ( $bmin > 0 ) { |
71
|
3
|
|
|
|
|
10
|
$_->[1] += $bmin for @lcs; |
72
|
41
|
50
|
66
|
|
|
378
|
} |
73
|
|
|
|
|
|
|
|
74
|
11
|
|
|
|
|
98
|
map( [ $_ => $_ ], 0 .. ( $amin - 1 ) ), |
|
41
|
|
|
|
|
144
|
|
75
|
41
|
|
|
|
|
91
|
@lcs, |
76
|
|
|
|
|
|
|
map( [ $_ => ++$bmax ], ( $amax + 1 ) .. $#$a ); |
77
|
|
|
|
|
|
|
} |
78
|
|
|
|
|
|
|
|
79
|
0
|
|
|
|
|
0
|
1; |
80
|
0
|
|
|
|
|
0
|
|
81
|
|
|
|
|
|
|
__END__ |
82
|
0
|
|
|
|
|
0
|
|
83
|
|
|
|
|
|
|
=head1 NAME |
84
|
0
|
|
|
|
|
0
|
|
85
|
|
|
|
|
|
|
Algorithm::Diff::XS - Algorithm::Diff with XS core loop |
86
|
|
|
|
|
|
|
|
87
|
0
|
|
|
|
|
0
|
=head1 SYNOPSIS |
88
|
|
|
|
|
|
|
|
89
|
0
|
0
|
|
|
|
0
|
# Drop-in replacement to Algorithm::Diff, but "compact_diff" |
|
|
0
|
|
|
|
|
|
90
|
|
|
|
|
|
|
# and C<LCSidx> will run much faster for large data sets. |
91
|
0
|
|
|
|
|
0
|
use Algorithm::Diff::XS qw( compact_diff LCSidx ); |
92
|
|
|
|
|
|
|
|
93
|
|
|
|
|
|
|
=head1 DESCRIPTION |
94
|
|
|
|
|
|
|
|
95
|
0
|
|
|
|
|
0
|
This module is a simple re-packaging of Joe Schaefer's excellent |
96
|
|
|
|
|
|
|
but not very well-known L<Algorithm::LCS> with a drop-in interface |
97
|
|
|
|
|
|
|
that simply re-uses the installed version of the L<Algorithm::Diff> |
98
|
|
|
|
|
|
|
module. |
99
|
0
|
|
|
|
|
0
|
|
100
|
|
|
|
|
|
|
Note that only the C<LCSidx> function is optimized in XS at the |
101
|
|
|
|
|
|
|
moment, which means only C<compact_diff> will get significantly |
102
|
|
|
|
|
|
|
faster for large data sets, while C<diff> and C<sdiff> will run |
103
|
|
|
|
|
|
|
in identical speed as C<Algorithm::Diff>. |
104
|
0
|
|
|
|
|
0
|
|
105
|
0
|
|
|
|
|
0
|
=head1 BENCHMARK |
106
|
|
|
|
|
|
|
|
107
|
|
|
|
|
|
|
Rate Algorithm::Diff Algorithm::Diff::XS |
108
|
|
|
|
|
|
|
Algorithm::Diff 14.7/s -- -98% |
109
|
|
|
|
|
|
|
Algorithm::Diff::XS 806/s 5402% -- |
110
|
|
|
|
|
|
|
|
111
|
|
|
|
|
|
|
The benchmarking script is as below: |
112
|
|
|
|
|
|
|
|
113
|
|
|
|
|
|
|
my @data = ([qw/a b d/ x 50], [qw/b a d c/ x 50]); |
114
|
|
|
|
|
|
|
cmpthese( 500, { |
115
|
|
|
|
|
|
|
'Algorithm::Diff' => sub { |
116
|
|
|
|
|
|
|
Algorithm::Diff::compact_diff(@data) |
117
|
|
|
|
|
|
|
}, |
118
|
|
|
|
|
|
|
'Algorithm::Diff::XS' => sub { |
119
|
|
|
|
|
|
|
Algorithm::Diff::XS::compact_diff(@data) |
120
|
|
|
|
|
|
|
}, |
121
|
|
|
|
|
|
|
}); |
122
|
|
|
|
|
|
|
|
123
|
|
|
|
|
|
|
=head1 SEE ALSO |
124
|
|
|
|
|
|
|
|
125
|
|
|
|
|
|
|
L<Algorithm::Diff>, L<Algorithm::LCS>. |
126
|
|
|
|
|
|
|
|
127
|
|
|
|
|
|
|
=head1 AUTHORS |
128
|
25
|
|
|
25
|
|
154
|
|
129
|
25
|
|
|
|
|
27
|
Audrey Tang E<lt>cpan@audreyt.orgE<gt> |
130
|
25
|
|
|
|
|
100
|
|
131
|
25
|
|
|
|
|
30
|
=head1 COPYRIGHT |
132
|
25
|
|
|
|
|
27
|
|
133
|
|
|
|
|
|
|
Copyright 2008 by Audrey Tang E<lt>cpan@audreyt.orgE<gt>. |
134
|
25
|
50
|
|
|
|
70
|
|
135
|
|
|
|
|
|
|
Contains derived code copyrighted 2003 by Joe Schaefer, |
136
|
0
|
|
|
|
|
0
|
E<lt>joe+cpan@sunstarsys.comE<gt>. |
137
|
0
|
|
|
|
|
0
|
|
138
|
0
|
|
|
|
|
0
|
This library is free software; you can redistribute it and/or modify |
139
|
|
|
|
|
|
|
it under the same terms as Perl itself. |
140
|
|
|
|
|
|
|
|
141
|
|
|
|
|
|
|
=cut |
142
|
25
|
50
|
33
|
|
|
85
|
|