package Algorithm::LCS; use 5.008; use strict; use warnings; our $VERSION = '1.04'; require XSLoader; XSLoader::load('Algorithm::LCS', $VERSION); ############################## # code adapted from Algorithm::Diff sub line_map { my $ctx = shift; my %lines; push @{ $lines{$_[$_]} }, $_ for 0..$#_; # values MUST be SvIOK \%lines; } sub callback { my ($ctx, @b) = @_; my $h = $ctx->line_map(@b); sub { @_ ? _core_loop($ctx, $_[0], 0, $#{$_[0]}, $h) : @b } } sub LCS { my ($ctx, $a, $b) = @_; my ($amin, $amax, $bmin, $bmax) = (0, $#$a, 0, $#$b); while ($amin <= $amax and $bmin <= $bmax and $a->[$amin] eq $b->[$bmin]) { $amin++; $bmin++; } while ($amin <= $amax and $bmin <= $bmax and $a->[$amax] eq $b->[$bmax]) { $amax--; $bmax--; } my $h = $ctx->line_map(@$b[$bmin..$bmax]); # line numbers are off by $bmin return $amin + _core_loop($ctx, $a, $amin, $amax, $h) + ($#$a - $amax) unless wantarray; my @lcs = _core_loop($ctx,$a,$amin,$amax,$h); if ($bmin > 0) { $_->[1] += $bmin for @lcs; # correct line numbers } map([$_ => $_], 0 .. ($amin-1)), @lcs, map([$_ => ++$bmax], ($amax+1) .. $#$a); } 1; __END__ =head1 NAME Algorithm::LCS - Fast (XS) implementation of the Longest Common Subsequence (LCS) Algorithm =head1 SYNOPSIS use Algorithm::LCS; $alg = Algorithm::LCS->new; @lcs = $alg->LCS(\@a,\@b); $cb = $alg->callback(@b); # closure @lcs = $cb->(\@a); # same result as prior LCS() call =head1 ABSTRACT Algorithm::LCS reimplements Algorithm::Diff's core loop in XS, and provides a simple OO interface to it. Extract from the Algorithm::Diff v1.15 manpage: The algorithm is that described in I, CACM, vol.20, no.5, pp.350-353, May 1977, with a few minor improvements to improve the speed. =head1 DESCRIPTION =head2 CONSTRUCTOR =over 4 =item new() Creates a new object which maintains internal storage areas for the LCS computation. Use one of these per concurrent LCS() call. =back =head2 METHODS =over 4 =item line_map(@lines) Send @lines to a hashref containing elements of the form value => [(increasing) list of matching indices] =item callback(@lines) Generates a closure capturing the object and line_map hash for @lines. Most useful when computing multiple LCSs against a single file. =item LCS(\@a,\@b) Finds a Longest Common Subsequence, taking two arrayrefs as method arguments. In scalar context the return value is the length of the subsequence. In list context it yields a list of corresponding indices, which are represented by 2-element array refs. See the L manpage for more details. =back =head2 EXPORT None by design. =head1 SEE ALSO Algorithm::Diff =head1 AUTHOR Joe Schaefer, Ejoe+cpan@sunstarsys.comE =head1 COPYRIGHT AND LICENSE Copyright 2003 by Joe Schaefer This library is free software; you can redistribute it and/or modify it under the same terms as Perl itself. =cut