ILIAS  release_5-3 Revision v5.3.23-19-g915713cf615
_DiffEngine Class Reference
+ Collaboration diagram for _DiffEngine:

Public Member Functions

 diff ($from_lines, $to_lines)
 
 _line_hash ($line)
 Returns the whole line if it's small enough, or the MD5 hash otherwise. More...
 
 _diag ($xoff, $xlim, $yoff, $ylim, $nchunks)
 
 _lcs_pos ($ypos)
 
 _compareseq ($xoff, $xlim, $yoff, $ylim)
 
 _shift_boundaries ($lines, &$changed, $other_changed)
 

Data Fields

const MAX_XREF_LENGTH = 10000
 

Detailed Description

Definition at line 830 of file class.WordLevelDiff.php.

Member Function Documentation

◆ _compareseq()

_DiffEngine::_compareseq (   $xoff,
  $xlim,
  $yoff,
  $ylim 
)

Definition at line 1095 of file class.WordLevelDiff.php.

1110  {
1111  $fname = '_DiffEngine::_compareseq';
1112  //wfProfileIn( $fname );
1113 
1114  // Slide down the bottom initial diagonal.
1115  while ($xoff < $xlim && $yoff < $ylim
1116  && $this->xv[$xoff] == $this->yv[$yoff]) {
1117  ++$xoff;
1118  ++$yoff;
1119  }
1120 
1121  // Slide up the top initial diagonal.
1122  while ($xlim > $xoff && $ylim > $yoff
1123  && $this->xv[$xlim - 1] == $this->yv[$ylim - 1]) {
1124  --$xlim;
1125  --$ylim;
1126  }
1127 
1128  if ($xoff == $xlim || $yoff == $ylim) {
1129  $lcs = 0;
1130  } else {
1131  // This is ad hoc but seems to work well.
1132  //$nchunks = sqrt(min($xlim - $xoff, $ylim - $yoff) / 2.5);
1133  //$nchunks = max(2,min(8,(int)$nchunks));
1134  $nchunks = min(7, $xlim - $xoff, $ylim - $yoff) + 1;
1135  list($lcs, $seps)
1136  = $this->_diag($xoff, $xlim, $yoff, $ylim, $nchunks);
1137  }
1138 
1139  if ($lcs == 0) {
1140  // X and Y sequences have no common subsequence:
1141  // mark all changed.
1142  while ($yoff < $ylim) {
1143  $this->ychanged[$this->yind[$yoff++]] = 1;
1144  }
_diag($xoff, $xlim, $yoff, $ylim, $nchunks)

◆ _diag()

_DiffEngine::_diag (   $xoff,
  $xlim,
  $yoff,
  $ylim,
  $nchunks 
)

Definition at line 966 of file class.WordLevelDiff.php.

References $i, $x, $y, array, and USE_ASSERTS.

981  {
982  $fname = '_DiffEngine::_diag';
983  //wfProfileIn( $fname );
984  $flip = false;
985 
986  if ($xlim - $xoff > $ylim - $yoff) {
987  // Things seems faster (I'm not sure I understand why)
988  // when the shortest sequence in X.
989  $flip = true;
990  list($xoff, $xlim, $yoff, $ylim)
991  = array( $yoff, $ylim, $xoff, $xlim);
992  }
993 
994  if ($flip) {
995  for ($i = $ylim - 1; $i >= $yoff; $i--) {
996  $ymatches[$this->xv[$i]][] = $i;
997  }
998  } else {
999  for ($i = $ylim - 1; $i >= $yoff; $i--) {
1000  $ymatches[$this->yv[$i]][] = $i;
1001  }
1002  }
1003 
1004  $this->lcs = 0;
1005  $this->seq[0]= $yoff - 1;
1006  $this->in_seq = array();
1007  $ymids[0] = array();
1008 
1009  $numer = $xlim - $xoff + $nchunks - 1;
1010  $x = $xoff;
1011  for ($chunk = 0; $chunk < $nchunks; $chunk++) {
1012  //wfProfileIn( "$fname-chunk" );
1013  if ($chunk > 0) {
1014  for ($i = 0; $i <= $this->lcs; $i++) {
1015  $ymids[$i][$chunk-1] = $this->seq[$i];
1016  }
1017  }
1018 
1019  $x1 = $xoff + (int) (($numer + ($xlim-$xoff)*$chunk) / $nchunks);
1020  for (; $x < $x1; $x++) {
1021  $line = $flip ? $this->yv[$x] : $this->xv[$x];
1022  if (empty($ymatches[$line])) {
1023  continue;
1024  }
1025  $matches = $ymatches[$line];
1026  reset($matches);
1027  while (list($junk, $y) = each($matches)) {
1028  if (empty($this->in_seq[$y])) {
1029  $k = $this->_lcs_pos($y);
1030  USE_ASSERTS && assert($k > 0);
1031  $ymids[$k] = $ymids[$k-1];
1032  break;
1033  }
1034  }
1035  while (list( /* $junk */, $y) = each($matches)) {
1036  if ($y > $this->seq[$k-1]) {
1037  USE_ASSERTS && assert($y < $this->seq[$k]);
1038  // Optimization: this is a common case:
1039  // next match is just replacing previous match.
1040  $this->in_seq[$this->seq[$k]] = false;
1041  $this->seq[$k] = $y;
1042  $this->in_seq[$y] = 1;
1043  } elseif (empty($this->in_seq[$y])) {
1044  $k = $this->_lcs_pos($y);
1045  USE_ASSERTS && assert($k > 0);
1046  $ymids[$k] = $ymids[$k-1];
1047  }
1048  }
1049  }
1050  //wfProfileOut( "$fname-chunk" );
$x
Definition: example_009.php:98
const USE_ASSERTS
$y
Definition: example_007.php:83
Create styles array
The data for the language used.
$i
Definition: disco.tpl.php:19

◆ _lcs_pos()

_DiffEngine::_lcs_pos (   $ypos)

Definition at line 1052 of file class.WordLevelDiff.php.

References $end, $n, array, and USE_ASSERTS.

1053  : array($xoff, $yoff);
1054  $ymid = $ymids[$this->lcs];
1055  for ($n = 0; $n < $nchunks - 1; $n++) {
1056  $x1 = $xoff + (int) (($numer + ($xlim - $xoff) * $n) / $nchunks);
1057  $y1 = $ymid[$n] + 1;
1058  $seps[] = $flip ? array($y1, $x1) : array($x1, $y1);
1059  }
1060  $seps[] = $flip ? array($ylim, $xlim) : array($xlim, $ylim);
1061 
1062  //wfProfileOut( $fname );
1063  return array($this->lcs, $seps);
1064  }
1065 
1066  public function _lcs_pos($ypos)
1067  {
1068  $fname = '_DiffEngine::_lcs_pos';
1069  //wfProfileIn( $fname );
1070 
1071  $end = $this->lcs;
1072  if ($end == 0 || $ypos > $this->seq[$end]) {
1073  $this->seq[++$this->lcs] = $ypos;
1074  $this->in_seq[$ypos] = 1;
1075  //wfProfileOut( $fname );
1076  return $this->lcs;
1077  }
1078 
1079  $beg = 1;
1080  while ($beg < $end) {
1081  $mid = (int) (($beg + $end) / 2);
1082  if ($ypos > $this->seq[$mid]) {
$end
Definition: saml1-acs.php:18
$n
Definition: RandomTest.php:85
Create styles array
The data for the language used.

◆ _line_hash()

_DiffEngine::_line_hash (   $line)

Returns the whole line if it's small enough, or the MD5 hash otherwise.

Definition at line 940 of file class.WordLevelDiff.php.

941  {
942  $edits[] = new _DiffOp_Delete($delete);
943  } elseif ($add) {
944  $edits[] = new _DiffOp_Add($add);
945  }
946  }
947  //wfProfileOut( $fname );

◆ _shift_boundaries()

_DiffEngine::_shift_boundaries (   $lines,
$changed,
  $other_changed 
)

Definition at line 1158 of file class.WordLevelDiff.php.

References $changed, $i, and USE_ASSERTS.

1173  {
1174  $fname = '_DiffEngine::_shift_boundaries';
1175  //wfProfileIn( $fname );
1176  $i = 0;
1177  $j = 0;
1178 
1179  USE_ASSERTS && assert('sizeof($lines) == sizeof($changed)');
1180  $len = sizeof($lines);
1181  $other_len = sizeof($other_changed);
1182 
1183  while (1) {
1184  /*
1185  * Scan forwards to find beginning of another run of changes.
1186  * Also keep track of the corresponding point in the other file.
1187  *
1188  * Throughout this code, $i and $j are adjusted together so that
1189  * the first $i elements of $changed and the first $j elements
1190  * of $other_changed both contain the same number of zeros
1191  * (unchanged lines).
1192  * Furthermore, $j is always kept so that $j == $other_len or
1193  * $other_changed[$j] == false.
1194  */
1195  while ($j < $other_len && $other_changed[$j]) {
1196  $j++;
1197  }
1198 
1199  while ($i < $len && !$changed[$i]) {
1200  USE_ASSERTS && assert('$j < $other_len && ! $other_changed[$j]');
1201  $i++;
1202  $j++;
1203  while ($j < $other_len && $other_changed[$j]) {
1204  $j++;
1205  }
1206  }
1207 
1208  if ($i == $len) {
1209  break;
1210  }
1211 
1212  $start = $i;
1213 
1214  // Find the end of this run of changes.
1215  while (++$i < $len && $changed[$i]) {
1216  continue;
1217  }
1218 
1219  do {
1220  /*
1221  * Record the length of this run of changes, so that
1222  * we can later determine whether the run has grown.
1223  */
1224  $runlength = $i - $start;
1225 
1226  /*
1227  * Move the changed region back, so long as the
1228  * previous unchanged line matches the last changed one.
1229  * This merges with previous changed regions.
1230  */
1231  while ($start > 0 && $lines[$start - 1] == $lines[$i - 1]) {
1232  $changed[--$start] = 1;
1233  $changed[--$i] = false;
1234  while ($start > 0 && $changed[$start - 1]) {
1235  $start--;
1236  }
1237  USE_ASSERTS && assert('$j > 0');
1238  while ($other_changed[--$j]) {
1239  continue;
1240  }
1241  USE_ASSERTS && assert('$j >= 0 && !$other_changed[$j]');
1242  }
1243 
1244  /*
1245  * Set CORRESPONDING to the end of the changed run, at the last
1246  * point where it corresponds to a changed run in the other file.
1247  * CORRESPONDING == LEN means no such point has been found.
1248  */
1249  $corresponding = $j < $other_len ? $i : $len;
1250 
1251  /*
1252  * Move the changed region forward, so long as the
1253  * first changed line matches the following unchanged one.
1254  * This merges with following changed regions.
1255  * Do this second, so that if there are no merges,
1256  * the changed region is moved forward as far as possible.
1257  */
1258  while ($i < $len && $lines[$start] == $lines[$i]) {
1259  $changed[$start++] = false;
1260  $changed[$i++] = 1;
1261  while ($i < $len && $changed[$i]) {
1262  $i++;
1263  }
1264 
1265  USE_ASSERTS && assert('$j < $other_len && ! $other_changed[$j]');
1266  $j++;
1267  if ($j < $other_len && $other_changed[$j]) {
1268  $corresponding = $i;
1269  while ($j < $other_len && $other_changed[$j]) {
1270  $j++;
1271  }
1272  }
1273  }
1274  } while ($runlength != $i - $start);
1275 
1276  /*
1277  * If possible, move the fully-merged run of changes
const USE_ASSERTS
$i
Definition: disco.tpl.php:19

◆ diff()

_DiffEngine::diff (   $from_lines,
  $to_lines 
)

Definition at line 834 of file class.WordLevelDiff.php.

845 {
846  const MAX_XREF_LENGTH = 10000;
847 
848  public function diff($from_lines, $to_lines)
849  {
850  $fname = '_DiffEngine::diff';
851  //wfProfileIn( $fname );
852 
853  $n_from = sizeof($from_lines);
854  $n_to = sizeof($to_lines);
855 
856  $this->xchanged = $this->ychanged = array();
857  $this->xv = $this->yv = array();
858  $this->xind = $this->yind = array();
859  unset($this->seq);
860  unset($this->in_seq);
861  unset($this->lcs);
862 
863  // Skip leading common lines.
864  for ($skip = 0; $skip < $n_from && $skip < $n_to; $skip++) {
865  if ($from_lines[$skip] !== $to_lines[$skip]) {
866  break;
867  }
868  $this->xchanged[$skip] = $this->ychanged[$skip] = false;
869  }
870  // Skip trailing common lines.
871  $xi = $n_from;
872  $yi = $n_to;
873  for ($endskip = 0; --$xi > $skip && --$yi > $skip; $endskip++) {
874  if ($from_lines[$xi] !== $to_lines[$yi]) {
875  break;
876  }
877  $this->xchanged[$xi] = $this->ychanged[$yi] = false;
878  }
879 
880  // Ignore lines which do not exist in both files.
881  for ($xi = $skip; $xi < $n_from - $endskip; $xi++) {
882  $xhash[$this->_line_hash($from_lines[$xi])] = 1;
883  }
884 
885  for ($yi = $skip; $yi < $n_to - $endskip; $yi++) {
886  $line = $to_lines[$yi];
887  if (($this->ychanged[$yi] = empty($xhash[$this->_line_hash($line)]))) {
888  continue;
889  }
890  $yhash[$this->_line_hash($line)] = 1;
891  $this->yv[] = $line;
892  $this->yind[] = $yi;
893  }
894  for ($xi = $skip; $xi < $n_from - $endskip; $xi++) {
895  $line = $from_lines[$xi];
896  if (($this->xchanged[$xi] = empty($yhash[$this->_line_hash($line)]))) {
897  continue;
898  }
899  $this->xv[] = $line;
900  $this->xind[] = $xi;
901  }
902 
903  // Find the LCS.
904  $this->_compareseq(0, sizeof($this->xv), 0, sizeof($this->yv));
905 
906  // Merge edits when possible
907  $this->_shift_boundaries($from_lines, $this->xchanged, $this->ychanged);
908  $this->_shift_boundaries($to_lines, $this->ychanged, $this->xchanged);
909 
910  // Compute the edit operations.
911  $edits = array();
912  $xi = $yi = 0;
913  while ($xi < $n_from || $yi < $n_to) {
914  USE_ASSERTS && assert($yi < $n_to || $this->xchanged[$xi]);
915  USE_ASSERTS && assert($xi < $n_from || $this->ychanged[$yi]);
916 
917  // Skip matching "snake".
918  $copy = array();
919  while ($xi < $n_from && $yi < $n_to
920  && !$this->xchanged[$xi] && !$this->ychanged[$yi]) {
921  $copy[] = $from_lines[$xi++];
922  ++$yi;
923  }
924  if ($copy) {
925  $edits[] = new _DiffOp_Copy($copy);
926  }
927 
928  // Find deletes & adds.
929  $delete = array();
930  while ($xi < $n_from && $this->xchanged[$xi]) {
931  $delete[] = $from_lines[$xi++];
932  }
933 
934  $add = array();
935  while ($yi < $n_to && $this->ychanged[$yi]) {
_line_hash($line)
Returns the whole line if it&#39;s small enough, or the MD5 hash otherwise.
diff($from_lines, $to_lines)
_compareseq($xoff, $xlim, $yoff, $ylim)
const USE_ASSERTS
_shift_boundaries($lines, &$changed, $other_changed)
Create styles array
The data for the language used.

Field Documentation

◆ MAX_XREF_LENGTH

const _DiffEngine::MAX_XREF_LENGTH = 10000

Definition at line 832 of file class.WordLevelDiff.php.


The documentation for this class was generated from the following file: