34         array_walk($from_lines, array($this, 
'_trimNewlines'));
 
   35         array_walk($to_lines, array($this, 
'_trimNewlines'));
 
   37         if (extension_loaded(
'xdiff')) {
 
   43         $this->_edits = $engine->diff($from_lines, $to_lines);
 
   72         $rev->_edits = array();
 
   73         foreach ($this->_edits as $edit) {
 
   74             $rev->_edits[] = $edit->reverse();
 
   86         foreach ($this->_edits as $edit) {
 
  104         foreach ($this->_edits as $edit) {
 
  106                 $lcs += count($edit->orig);
 
  122         foreach ($this->_edits as $edit) {
 
  124                 array_splice($lines, count($lines), 0, $edit->orig);
 
  140         foreach ($this->_edits as $edit) {
 
  142                 array_splice($lines, count($lines), 0, $edit->final);
 
  157         $line = str_replace(array(
"\n", 
"\r"), 
'', $line);
 
  167         if (serialize($from_lines) != serialize($this->
getOriginal())) {
 
  168             trigger_error(
"Reconstructed original doesn't match", E_USER_ERROR);
 
  170         if (serialize($to_lines) != serialize($this->
getFinal())) {
 
  171             trigger_error(
"Reconstructed final doesn't match", E_USER_ERROR);
 
  175         if (serialize($to_lines) != serialize($rev->getOriginal())) {
 
  176             trigger_error(
"Reversed original doesn't match", E_USER_ERROR);
 
  178         if (serialize($from_lines) != serialize($rev->getFinal())) {
 
  179             trigger_error(
"Reversed final doesn't match", E_USER_ERROR);
 
  183         foreach ($this->_edits as $edit) {
 
  184             if ($prevtype == get_class($edit)) {
 
  185                 trigger_error(
"Edit sequence is non-optimal", E_USER_ERROR);
 
  187             $prevtype = get_class($edit);
 
  220                              $mapped_from_lines, $mapped_to_lines)
 
  222         assert(count($from_lines) == count($mapped_from_lines));
 
  223         assert(count($to_lines) == count($mapped_to_lines));
 
  228         for ($i = 0; $i < count($this->_edits); $i++) {
 
  229             $orig = &$this->_edits[$i]->orig;
 
  230             if (is_array($orig)) {
 
  231                 $orig = array_slice($from_lines, $xi, count($orig));
 
  235             $final = &$this->_edits[$i]->final;
 
  236             if (is_array($final)) {
 
  237                 $final = array_slice($to_lines, $yi, count($final));
 
  238                 $yi += count($final);
 
  257     function diff($from_lines, $to_lines)
 
  260         $from_string = implode(
"\n", $from_lines);
 
  261         $to_string = implode(
"\n", $to_lines);
 
  264         $diff = xdiff_string_diff($from_string, $to_string, count($to_lines));
 
  265         $diff = explode(
"\n", $diff);
 
  276         foreach ($diff as $line) {
 
  323     function diff($from_lines, $to_lines)
 
  325         $n_from = count($from_lines);
 
  326         $n_to = count($to_lines);
 
  328         $this->xchanged = $this->ychanged = array();
 
  329         $this->xv = $this->yv = array();
 
  330         $this->xind = $this->yind = array();
 
  332         unset($this->in_seq);
 
  340             $this->xchanged[
$skip] = $this->ychanged[
$skip] = 
false;
 
  344         $xi = $n_from; $yi = $n_to;
 
  345         for ($endskip = 0; --$xi > 
$skip && --$yi > 
$skip; $endskip++) {
 
  346             if ($from_lines[$xi] != $to_lines[$yi]) {
 
  349             $this->xchanged[$xi] = $this->ychanged[$yi] = 
false;
 
  353         for ($xi = $skip; $xi < $n_from - $endskip; $xi++) {
 
  354             $xhash[$from_lines[$xi]] = 1;
 
  356         for ($yi = $skip; $yi < $n_to - $endskip; $yi++) {
 
  357             $line = $to_lines[$yi];
 
  358             if (($this->ychanged[$yi] = empty($xhash[$line]))) {
 
  365         for ($xi = $skip; $xi < $n_from - $endskip; $xi++) {
 
  366             $line = $from_lines[$xi];
 
  367             if (($this->xchanged[$xi] = empty($yhash[$line]))) {
 
  375         $this->
_compareseq(0, count($this->xv), 0, count($this->yv));
 
  384         while ($xi < $n_from || $yi < $n_to) {
 
  385             assert($yi < $n_to || $this->xchanged[$xi]);
 
  386             assert($xi < $n_from || $this->ychanged[$yi]);
 
  390             while ($xi < $n_from && $yi < $n_to
 
  391                    && !$this->xchanged[$xi] && !$this->ychanged[$yi]) {
 
  392                 $copy[] = $from_lines[$xi++];
 
  401             while ($xi < $n_from && $this->xchanged[$xi]) {
 
  402                 $delete[] = $from_lines[$xi++];
 
  406             while ($yi < $n_to && $this->ychanged[$yi]) {
 
  407                 $add[] = $to_lines[$yi++];
 
  410             if ($delete && $add) {
 
  438     function _diag ($xoff, $xlim, $yoff, $ylim, $nchunks)
 
  442         if ($xlim - $xoff > $ylim - $yoff) {
 
  446             list ($xoff, $xlim, $yoff, $ylim)
 
  447                 = array($yoff, $ylim, $xoff, $xlim);
 
  451             for ($i = $ylim - 1; $i >= $yoff; $i--) {
 
  452                 $ymatches[$this->xv[$i]][] = $i;
 
  455             for ($i = $ylim - 1; $i >= $yoff; $i--) {
 
  456                 $ymatches[$this->yv[$i]][] = $i;
 
  461         $this->seq[0]= $yoff - 1;
 
  462         $this->in_seq = array();
 
  465         $numer = $xlim - $xoff + $nchunks - 1;
 
  467         for ($chunk = 0; $chunk < $nchunks; $chunk++) {
 
  469                 for ($i = 0; $i <= $this->lcs; $i++) {
 
  470                     $ymids[$i][$chunk - 1] = $this->seq[$i];
 
  474             $x1 = $xoff + (int)(($numer + ($xlim-$xoff)*$chunk) / $nchunks);
 
  475             for (; $x < $x1; $x++) {
 
  476                 $line = $flip ? $this->yv[$x] : $this->xv[$x];
 
  477                 if (empty($ymatches[$line])) {
 
  480                 $matches = $ymatches[$line];
 
  481                 foreach ($matches as $y) {
 
  482                     if (empty($this->in_seq[$y])) {
 
  485                         $ymids[$k] = $ymids[$k - 1];
 
  490                 while (list($junk, $y) = each($matches)) {
 
  491                     if ($y > $this->seq[$k - 1]) {
 
  492                         assert($y < $this->seq[$k]);
 
  495                         $this->in_seq[$this->seq[$k]] = 
false;
 
  497                         $this->in_seq[$y] = 1;
 
  498                     } elseif (empty($this->in_seq[$y])) {
 
  501                         $ymids[$k] = $ymids[$k - 1];
 
  507         $seps[] = $flip ? array($yoff, $xoff) : array($xoff, $yoff);
 
  508         $ymid = $ymids[$this->lcs];
 
  509         for (
$n = 0; 
$n < $nchunks - 1; 
$n++) {
 
  510             $x1 = $xoff + (int)(($numer + ($xlim - $xoff) * 
$n) / $nchunks);
 
  512             $seps[] = $flip ? array($y1, $x1) : array($x1, $y1);
 
  514         $seps[] = $flip ? array($ylim, $xlim) : array($xlim, $ylim);
 
  516         return array($this->lcs, $seps);
 
  522         if ($end == 0 || $ypos > $this->seq[$end]) {
 
  523             $this->seq[++$this->lcs] = $ypos;
 
  524             $this->in_seq[$ypos] = 1;
 
  529         while ($beg < $end) {
 
  530             $mid = (int)(($beg + $end) / 2);
 
  531             if ($ypos > $this->seq[$mid]) {
 
  538         assert($ypos != $this->seq[$end]);
 
  540         $this->in_seq[$this->seq[$end]] = 
false;
 
  541         $this->seq[$end] = $ypos;
 
  542         $this->in_seq[$ypos] = 1;
 
  561         while ($xoff < $xlim && $yoff < $ylim
 
  562                && $this->xv[$xoff] == $this->yv[$yoff]) {
 
  568         while ($xlim > $xoff && $ylim > $yoff
 
  569                && $this->xv[$xlim - 1] == $this->yv[$ylim - 1]) {
 
  574         if ($xoff == $xlim || $yoff == $ylim) {
 
  580             $nchunks = min(7, $xlim - $xoff, $ylim - $yoff) + 1;
 
  582                 = $this->
_diag($xoff, $xlim, $yoff, $ylim, $nchunks);
 
  588             while ($yoff < $ylim) {
 
  589                 $this->ychanged[$this->yind[$yoff++]] = 1;
 
  591             while ($xoff < $xlim) {
 
  592                 $this->xchanged[$this->xind[$xoff++]] = 1;
 
  598             while ($pt2 = next($seps)) {
 
  599                 $this->
_compareseq ($pt1[0], $pt2[0], $pt1[1], $pt2[1]);
 
  622         assert(
'count($lines) == count($changed)');
 
  623         $len = count($lines);
 
  624         $other_len = count($other_changed);
 
  638             while ($j < $other_len && $other_changed[$j]) {
 
  642             while ($i < $len && ! 
$changed[$i]) {
 
  643                 assert(
'$j < $other_len && ! $other_changed[$j]');
 
  645                 while ($j < $other_len && $other_changed[$j]) {
 
  657             while (++$i < $len && 
$changed[$i]) {
 
  664                 $runlength = $i - $start;
 
  669                 while ($start > 0 && $lines[$start - 1] == $lines[$i - 1]) {
 
  672                     while ($start > 0 && 
$changed[$start - 1]) {
 
  676                     while ($other_changed[--$j]) {
 
  679                     assert(
'$j >= 0 && !$other_changed[$j]');
 
  686                 $corresponding = $j < $other_len ? $i : $len;
 
  693                 while ($i < $len && $lines[$start] == $lines[$i]) {
 
  700                     assert(
'$j < $other_len && ! $other_changed[$j]');
 
  702                     if ($j < $other_len && $other_changed[$j]) {
 
  704                         while ($j < $other_len && $other_changed[$j]) {
 
  709             } 
while ($runlength != $i - $start);
 
  713             while ($corresponding < $i) {
 
  717                 while ($other_changed[--$j]) {
 
  720                 assert(
'$j >= 0 && !$other_changed[$j]');
 
  740         trigger_error(
'Abstract method', E_USER_ERROR);
 
  745         return $this->orig ? count($this->orig) : 0;
 
  750         return $this->
final ? count($this->
final) : 0;
 
  789         $this->orig = $lines;
 
  790         $this->
final = 
false;
 
  810         $this->
final = $lines;