const MAX_XREF_LENGTH = 10000;
+ protected $xchanged, $ychanged;
+
function diff ( $from_lines, $to_lines ) {
wfProfileIn( __METHOD__ );
$copy[] = $from_lines[$xi++];
++$yi;
}
- if ( $copy )
- $edits[] = new _DiffOp_Copy( $copy );
+ if ( $copy ) {
+ $edits[] = new _DiffOp_Copy( $copy );
+ }
// Find deletes & adds.
$delete = array();
- while ( $xi < $n_from && $this->xchanged[$xi] )
- $delete[] = $from_lines[$xi++];
+ while ( $xi < $n_from && $this->xchanged[$xi] ) {
+ $delete[] = $from_lines[$xi++];
+ }
$add = array();
- while ( $yi < $n_to && $this->ychanged[$yi] )
- $add[] = $to_lines[$yi++];
-
- if ( $delete && $add )
- $edits[] = new _DiffOp_Change( $delete, $add );
- elseif ( $delete )
- $edits[] = new _DiffOp_Delete( $delete );
- elseif ( $add )
- $edits[] = new _DiffOp_Add( $add );
+ while ( $yi < $n_to && $this->ychanged[$yi] ) {
+ $add[] = $to_lines[$yi++];
+ }
+
+ if ( $delete && $add ) {
+ $edits[] = new _DiffOp_Change( $delete, $add );
+ } elseif ( $delete ) {
+ $edits[] = new _DiffOp_Delete( $delete );
+ } elseif ( $add ) {
+ $edits[] = new _DiffOp_Add( $add );
+ }
}
wfProfileOut( __METHOD__ );
return $edits;
// Things seems faster (I'm not sure I understand why)
// when the shortest sequence in X.
$flip = true;
- list ( $xoff, $xlim, $yoff, $ylim )
- = array( $yoff, $ylim, $xoff, $xlim );
+ list ( $xoff, $xlim, $yoff, $ylim ) = array( $yoff, $ylim, $xoff, $xlim );
}
- if ( $flip )
- for ( $i = $ylim - 1; $i >= $yoff; $i-- )
- $ymatches[$this->xv[$i]][] = $i;
- else
- for ( $i = $ylim - 1; $i >= $yoff; $i-- )
- $ymatches[$this->yv[$i]][] = $i;
+ if ( $flip ) {
+ for ( $i = $ylim - 1; $i >= $yoff; $i-- ) {
+ $ymatches[$this->xv[$i]][] = $i;
+ }
+ } else {
+ for ( $i = $ylim - 1; $i >= $yoff; $i-- ) {
+ $ymatches[$this->yv[$i]][] = $i;
+ }
+ }
$this->lcs = 0;
$this->seq[0] = $yoff - 1;
$numer = $xlim - $xoff + $nchunks - 1;
$x = $xoff;
for ( $chunk = 0; $chunk < $nchunks; $chunk++ ) {
- if ( $chunk > 0 )
- for ( $i = 0; $i <= $this->lcs; $i++ )
- $ymids[$i][$chunk -1] = $this->seq[$i];
+ if ( $chunk > 0 ) {
+ for ( $i = 0; $i <= $this->lcs; $i++ ) {
+ $ymids[$i][$chunk -1] = $this->seq[$i];
+ }
+ }
$x1 = $xoff + (int)( ( $numer + ( $xlim -$xoff ) * $chunk ) / $nchunks );
for ( ; $x < $x1; $x++ ) {
--$ylim;
}
- if ( $xoff == $xlim || $yoff == $ylim )
- $lcs = 0;
- else {
+ if ( $xoff == $xlim || $yoff == $ylim ) {
+ $lcs = 0;
+ } else {
// This is ad hoc but seems to work well.
// $nchunks = sqrt(min($xlim - $xoff, $ylim - $yoff) / 2.5);
// $nchunks = max(2,min(8,(int)$nchunks));
if ( $lcs == 0 ) {
// X and Y sequences have no common subsequence:
// mark all changed.
- while ( $yoff < $ylim )
- $this->ychanged[$this->yind[$yoff++]] = 1;
- while ( $xoff < $xlim )
- $this->xchanged[$this->xind[$xoff++]] = 1;
+ while ( $yoff < $ylim ) {
+ $this->ychanged[$this->yind[$yoff++]] = 1;
+ }
+ while ( $xoff < $xlim ) {
+ $this->xchanged[$this->xind[$xoff++]] = 1;
+ }
} else {
// Use the partitions to split this problem into subproblems.
reset( $seps );
* Furthermore, $j is always kept so that $j == $other_len or
* $other_changed[$j] == false.
*/
- while ( $j < $other_len && $other_changed[$j] )
- $j++;
+ while ( $j < $other_len && $other_changed[$j] ) {
+ $j++;
+ }
while ( $i < $len && ! $changed[$i] ) {
assert( '$j < $other_len && ! $other_changed[$j]' );
$j++;
}
- if ( $i == $len )
- break;
+ if ( $i == $len ) {
+ break;
+ }
$start = $i;
// Find the end of this run of changes.
- while ( ++$i < $len && $changed[$i] )
- continue;
+ while ( ++$i < $len && $changed[$i] ) {
+ continue;
+ }
do {
/*
while ( $start > 0 && $lines[$start - 1] == $lines[$i - 1] ) {
$changed[--$start] = 1;
$changed[--$i] = false;
- while ( $start > 0 && $changed[$start - 1] )
- $start--;
+ while ( $start > 0 && $changed[$start - 1] ) {
+ $start--;
+ }
assert( '$j > 0' );
- while ( $other_changed[--$j] )
- continue;
+ while ( $other_changed[--$j] ) {
+ continue;
+ }
assert( '$j >= 0 && !$other_changed[$j]' );
}
while ( $i < $len && $lines[$start] == $lines[$i] ) {
$changed[$start++] = false;
$changed[$i++] = 1;
- while ( $i < $len && $changed[$i] )
- $i++;
+ while ( $i < $len && $changed[$i] ) {
+ $i++;
+ }
assert( '$j < $other_len && ! $other_changed[$j]' );
$j++;
if ( $j < $other_len && $other_changed[$j] ) {
$corresponding = $i;
- while ( $j < $other_len && $other_changed[$j] )
- $j++;
+ while ( $j < $other_len && $other_changed[$j] ) {
+ $j++;
+ }
}
}
} while ( $runlength != $i - $start );
$changed[--$start] = 1;
$changed[--$i] = 0;
assert( '$j > 0' );
- while ( $other_changed[--$j] )
- continue;
+ while ( $other_changed[--$j] ) {
+ continue;
+ }
assert( '$j >= 0 && !$other_changed[$j]' );
}
}
*/
function isEmpty () {
foreach ( $this->edits as $edit ) {
- if ( $edit->type != 'copy' )
- return false;
+ if ( $edit->type != 'copy' ) {
+ return false;
+ }
}
return true;
}
function lcs () {
$lcs = 0;
foreach ( $this->edits as $edit ) {
- if ( $edit->type == 'copy' )
- $lcs += sizeof( $edit->orig );
+ if ( $edit->type == 'copy' ) {
+ $lcs += sizeof( $edit->orig );
+ }
}
return $lcs;
}
$lines = array();
foreach ( $this->edits as $edit ) {
- if ( $edit->orig )
- array_splice( $lines, sizeof( $lines ), 0, $edit->orig );
+ if ( $edit->orig ) {
+ array_splice( $lines, sizeof( $lines ), 0, $edit->orig );
+ }
}
return $lines;
}
$lines = array();
foreach ( $this->edits as $edit ) {
- if ( $edit->closing )
- array_splice( $lines, sizeof( $lines ), 0, $edit->closing );
+ if ( $edit->closing ) {
+ array_splice( $lines, sizeof( $lines ), 0, $edit->closing );
+ }
}
return $lines;
}
*/
function _check ( $from_lines, $to_lines ) {
wfProfileIn( __METHOD__ );
- if ( serialize( $from_lines ) != serialize( $this->orig() ) )
- trigger_error( "Reconstructed original doesn't match", E_USER_ERROR );
- if ( serialize( $to_lines ) != serialize( $this->closing() ) )
- trigger_error( "Reconstructed closing doesn't match", E_USER_ERROR );
+ if ( serialize( $from_lines ) != serialize( $this->orig() ) ) {
+ trigger_error( "Reconstructed original doesn't match", E_USER_ERROR );
+ }
+ if ( serialize( $to_lines ) != serialize( $this->closing() ) ) {
+ trigger_error( "Reconstructed closing doesn't match", E_USER_ERROR );
+ }
$rev = $this->reverse();
- if ( serialize( $to_lines ) != serialize( $rev->orig() ) )
- trigger_error( "Reversed original doesn't match", E_USER_ERROR );
- if ( serialize( $from_lines ) != serialize( $rev->closing() ) )
- trigger_error( "Reversed closing doesn't match", E_USER_ERROR );
+ if ( serialize( $to_lines ) != serialize( $rev->orig() ) ) {
+ trigger_error( "Reversed original doesn't match", E_USER_ERROR );
+ }
+ if ( serialize( $from_lines ) != serialize( $rev->closing() ) ) {
+ trigger_error( "Reversed closing doesn't match", E_USER_ERROR );
+ }
$prevtype = 'none';
foreach ( $this->edits as $edit ) {
- if ( $prevtype == $edit->type )
- trigger_error( "Edit sequence is non-optimal", E_USER_ERROR );
+ if ( $prevtype == $edit->type ) {
+ trigger_error( "Edit sequence is non-optimal", E_USER_ERROR );
+ }
$prevtype = $edit->type;
}
* have the same number of elements as $to_lines.
*/
function __construct( $from_lines, $to_lines,
- $mapped_from_lines, $mapped_to_lines ) {
+ $mapped_from_lines, $mapped_to_lines ) {
wfProfileIn( __METHOD__ );
assert( sizeof( $from_lines ) == sizeof( $mapped_from_lines ) );
/**
* Format a diff.
*
- * @param $diff object A Diff object.
+ * @param $diff Diff A Diff object.
* @return string The formatted output.
*/
function format( $diff ) {
$block[] = new _DiffOp_Copy( $context );
}
$this->_block( $x0, $ntrail + $xi - $x0,
- $y0, $ntrail + $yi - $y0,
- $block );
+ $y0, $ntrail + $yi - $y0,
+ $block );
$block = false;
}
}
$x0 = $xi - sizeof( $context );
$y0 = $yi - sizeof( $context );
$block = array();
- if ( $context )
- $block[] = new _DiffOp_Copy( $context );
+ if ( $context ) {
+ $block[] = new _DiffOp_Copy( $context );
+ }
}
$block[] = $edit;
}
- if ( $edit->orig )
- $xi += sizeof( $edit->orig );
- if ( $edit->closing )
- $yi += sizeof( $edit->closing );
+ if ( $edit->orig ) {
+ $xi += sizeof( $edit->orig );
+ }
+ if ( $edit->closing ) {
+ $yi += sizeof( $edit->closing );
+ }
}
- if ( is_array( $block ) )
- $this->_block( $x0, $xi - $x0,
- $y0, $yi - $y0,
- $block );
+ if ( is_array( $block ) ) {
+ $this->_block( $x0, $xi - $x0,
+ $y0, $yi - $y0,
+ $block );
+ }
$end = $this->_end_diff();
wfProfileOut( __METHOD__ );
wfProfileIn( __METHOD__ );
$this->_start_block( $this->_block_header( $xbeg, $xlen, $ybeg, $ylen ) );
foreach ( $edits as $edit ) {
- if ( $edit->type == 'copy' )
- $this->_context( $edit->orig );
- elseif ( $edit->type == 'add' )
- $this->_added( $edit->closing );
- elseif ( $edit->type == 'delete' )
- $this->_deleted( $edit->orig );
- elseif ( $edit->type == 'change' )
- $this->_changed( $edit->orig, $edit->closing );
- else
- trigger_error( 'Unknown edit type', E_USER_ERROR );
+ if ( $edit->type == 'copy' ) {
+ $this->_context( $edit->orig );
+ } elseif ( $edit->type == 'add' ) {
+ $this->_added( $edit->closing );
+ } elseif ( $edit->type == 'delete' ) {
+ $this->_deleted( $edit->orig );
+ } elseif ( $edit->type == 'change' ) {
+ $this->_changed( $edit->orig, $edit->closing );
+ } else {
+ trigger_error( 'Unknown edit type', E_USER_ERROR );
+ }
}
$this->_end_block();
wfProfileOut( __METHOD__ );
}
function _block_header( $xbeg, $xlen, $ybeg, $ylen ) {
- if ( $xlen > 1 )
- $xbeg .= "," . ( $xbeg + $xlen - 1 );
- if ( $ylen > 1 )
- $ybeg .= "," . ( $ybeg + $ylen - 1 );
+ if ( $xlen > 1 ) {
+ $xbeg .= "," . ( $xbeg + $xlen - 1 );
+ }
+ if ( $ylen > 1 ) {
+ $ybeg .= "," . ( $ybeg + $ylen - 1 );
+ }
return $xbeg . ( $xlen ? ( $ylen ? 'c' : 'd' ) : 'a' ) . $ybeg;
}
}
function _lines( $lines, $prefix = ' ' ) {
- foreach ( $lines as $line )
- echo "$prefix $line\n";
+ foreach ( $lines as $line ) {
+ echo "$prefix $line\n";
+ }
}
function _context( $lines ) {
$oldline = 1;
$newline = 1;
$retval = array();
- foreach ( $diff->edits as $edit )
- switch( $edit->type ) {
- case 'add':
- foreach ( $edit->closing as $l ) {
- $retval[] = array(
- 'action' => 'add',
- 'new' => $l,
- 'newline' => $newline++
- );
- }
- break;
- case 'delete':
- foreach ( $edit->orig as $l ) {
- $retval[] = array(
- 'action' => 'delete',
- 'old' => $l,
- 'oldline' => $oldline++,
- );
- }
- break;
- case 'change':
- foreach ( $edit->orig as $i => $l ) {
- $retval[] = array(
- 'action' => 'change',
- 'old' => $l,
- 'new' => @$edit->closing[$i],
- 'oldline' => $oldline++,
- 'newline' => $newline++,
- );
- }
- break;
- case 'copy':
- $oldline += count( $edit->orig );
- $newline += count( $edit->orig );
+ foreach ( $diff->edits as $edit ) {
+ switch( $edit->type ) {
+ case 'add':
+ foreach ( $edit->closing as $l ) {
+ $retval[] = array(
+ 'action' => 'add',
+ 'new' => $l,
+ 'newline' => $newline++
+ );
+ }
+ break;
+ case 'delete':
+ foreach ( $edit->orig as $l ) {
+ $retval[] = array(
+ 'action' => 'delete',
+ 'old' => $l,
+ 'oldline' => $oldline++,
+ );
+ }
+ break;
+ case 'change':
+ foreach ( $edit->orig as $i => $l ) {
+ $retval[] = array(
+ 'action' => 'change',
+ 'old' => $l,
+ 'new' => @$edit->closing[$i],
+ 'oldline' => $oldline++,
+ 'newline' => $newline++,
+ );
+ }
+ break;
+ case 'copy':
+ $oldline += count( $edit->orig );
+ $newline += count( $edit->orig );
+ }
}
return $retval;
}
function _flushGroup ( $new_tag ) {
if ( $this->_group !== '' ) {
- if ( $this->_tag == 'ins' )
- $this->_line .= '<ins class="diffchange diffchange-inline">' .
- htmlspecialchars ( $this->_group ) . '</ins>';
- elseif ( $this->_tag == 'del' )
- $this->_line .= '<del class="diffchange diffchange-inline">' .
- htmlspecialchars ( $this->_group ) . '</del>';
- else
- $this->_line .= htmlspecialchars ( $this->_group );
+ if ( $this->_tag == 'ins' ) {
+ $this->_line .= '<ins class="diffchange diffchange-inline">' .
+ htmlspecialchars ( $this->_group ) . '</ins>';
+ } elseif ( $this->_tag == 'del' ) {
+ $this->_line .= '<del class="diffchange diffchange-inline">' .
+ htmlspecialchars ( $this->_group ) . '</del>';
+ } else {
+ $this->_line .= htmlspecialchars ( $this->_group );
+ }
}
$this->_group = '';
$this->_tag = $new_tag;
function _flushLine ( $new_tag ) {
$this->_flushGroup( $new_tag );
- if ( $this->_line != '' )
- array_push ( $this->_lines, $this->_line );
- else
- # make empty lines visible by inserting an NBSP
- array_push ( $this->_lines, NBSP );
+ if ( $this->_line != '' ) {
+ array_push ( $this->_lines, $this->_line );
+ } else {
+ # make empty lines visible by inserting an NBSP
+ array_push ( $this->_lines, NBSP );
+ }
$this->_line = '';
}
function addWords ( $words, $tag = '' ) {
- if ( $tag != $this->_tag )
- $this->_flushGroup( $tag );
+ if ( $tag != $this->_tag ) {
+ $this->_flushGroup( $tag );
+ }
foreach ( $words as $word ) {
// new-line should only come as first char of word.
- if ( $word == '' )
- continue;
+ if ( $word == '' ) {
+ continue;
+ }
if ( $word[0] == "\n" ) {
$this->_flushLine( $tag );
$word = substr( $word, 1 );
} else {
$m = array();
if ( preg_match_all( '/ ( [^\S\n]+ | [0-9_A-Za-z\x80-\xff]+ | . ) (?: (?!< \n) [^\S\n])? /xs',
- $line, $m ) )
+ $line, $m ) )
{
$words = array_merge( $words, $m[0] );
$stripped = array_merge( $stripped, $m[1] );
$orig = new _HWLDF_WordAccumulator;
foreach ( $this->edits as $edit ) {
- if ( $edit->type == 'copy' )
- $orig->addWords( $edit->orig );
- elseif ( $edit->orig )
- $orig->addWords( $edit->orig, 'del' );
+ if ( $edit->type == 'copy' ) {
+ $orig->addWords( $edit->orig );
+ } elseif ( $edit->orig ) {
+ $orig->addWords( $edit->orig, 'del' );
+ }
}
$lines = $orig->getLines();
wfProfileOut( __METHOD__ );
$closing = new _HWLDF_WordAccumulator;
foreach ( $this->edits as $edit ) {
- if ( $edit->type == 'copy' )
- $closing->addWords( $edit->closing );
- elseif ( $edit->closing )
- $closing->addWords( $edit->closing, 'ins' );
+ if ( $edit->type == 'copy' ) {
+ $closing->addWords( $edit->closing );
+ } elseif ( $edit->closing ) {
+ $closing->addWords( $edit->closing, 'ins' );
+ }
}
$lines = $closing->getLines();
wfProfileOut( __METHOD__ );