MediaWiki  1.32.0
DiffEngine.php
Go to the documentation of this file.
1 <?php
26 
27 // FIXME: Don't use assert() in this file
28 // phpcs:disable MediaWiki.Usage.ForbiddenFunctions.assert
29 
47 class DiffEngine {
48 
49  // Input variables
50  private $from;
51  private $to;
52  private $m;
53  private $n;
54 
55  private $tooLong;
56  private $powLimit;
57 
58  protected $bailoutComplexity = 0;
59 
60  // State variables
61  private $maxDifferences;
63 
64  // Output variables
65  public $length;
66  public $removed;
67  public $added;
69 
70  function __construct( $tooLong = 2000000, $powLimit = 1.45 ) {
71  $this->tooLong = $tooLong;
72  $this->powLimit = $powLimit;
73  }
74 
84  public function diff( $from_lines, $to_lines ) {
85  // Diff and store locally
86  $this->diffInternal( $from_lines, $to_lines );
87 
88  // Merge edits when possible
89  $this->shiftBoundaries( $from_lines, $this->removed, $this->added );
90  $this->shiftBoundaries( $to_lines, $this->added, $this->removed );
91 
92  // Compute the edit operations.
93  $n_from = count( $from_lines );
94  $n_to = count( $to_lines );
95 
96  $edits = [];
97  $xi = $yi = 0;
98  while ( $xi < $n_from || $yi < $n_to ) {
99  assert( $yi < $n_to || $this->removed[$xi] );
100  assert( $xi < $n_from || $this->added[$yi] );
101 
102  // Skip matching "snake".
103  $copy = [];
104  while ( $xi < $n_from && $yi < $n_to
105  && !$this->removed[$xi] && !$this->added[$yi]
106  ) {
107  $copy[] = $from_lines[$xi++];
108  ++$yi;
109  }
110  if ( $copy ) {
111  $edits[] = new DiffOpCopy( $copy );
112  }
113 
114  // Find deletes & adds.
115  $delete = [];
116  while ( $xi < $n_from && $this->removed[$xi] ) {
117  $delete[] = $from_lines[$xi++];
118  }
119 
120  $add = [];
121  while ( $yi < $n_to && $this->added[$yi] ) {
122  $add[] = $to_lines[$yi++];
123  }
124 
125  if ( $delete && $add ) {
126  $edits[] = new DiffOpChange( $delete, $add );
127  } elseif ( $delete ) {
128  $edits[] = new DiffOpDelete( $delete );
129  } elseif ( $add ) {
130  $edits[] = new DiffOpAdd( $add );
131  }
132  }
133 
134  return $edits;
135  }
136 
141  public function setBailoutComplexity( $value ) {
142  $this->bailoutComplexity = $value;
143  }
144 
162  private function shiftBoundaries( array $lines, array &$changed, array $other_changed ) {
163  $i = 0;
164  $j = 0;
165 
166  assert( count( $lines ) == count( $changed ) );
167  $len = count( $lines );
168  $other_len = count( $other_changed );
169 
170  while ( 1 ) {
171  /*
172  * Scan forwards to find beginning of another run of changes.
173  * Also keep track of the corresponding point in the other file.
174  *
175  * Throughout this code, $i and $j are adjusted together so that
176  * the first $i elements of $changed and the first $j elements
177  * of $other_changed both contain the same number of zeros
178  * (unchanged lines).
179  * Furthermore, $j is always kept so that $j == $other_len or
180  * $other_changed[$j] == false.
181  */
182  while ( $j < $other_len && $other_changed[$j] ) {
183  $j++;
184  }
185 
186  while ( $i < $len && !$changed[$i] ) {
187  assert( $j < $other_len && !$other_changed[$j] );
188  $i++;
189  $j++;
190  while ( $j < $other_len && $other_changed[$j] ) {
191  $j++;
192  }
193  }
194 
195  if ( $i == $len ) {
196  break;
197  }
198 
199  $start = $i;
200 
201  // Find the end of this run of changes.
202  while ( ++$i < $len && $changed[$i] ) {
203  continue;
204  }
205 
206  do {
207  /*
208  * Record the length of this run of changes, so that
209  * we can later determine whether the run has grown.
210  */
211  $runlength = $i - $start;
212 
213  /*
214  * Move the changed region back, so long as the
215  * previous unchanged line matches the last changed one.
216  * This merges with previous changed regions.
217  */
218  while ( $start > 0 && $lines[$start - 1] == $lines[$i - 1] ) {
219  $changed[--$start] = 1;
220  $changed[--$i] = false;
221  while ( $start > 0 && $changed[$start - 1] ) {
222  $start--;
223  }
224  assert( $j > 0 );
225  while ( $other_changed[--$j] ) {
226  continue;
227  }
228  assert( $j >= 0 && !$other_changed[$j] );
229  }
230 
231  /*
232  * Set CORRESPONDING to the end of the changed run, at the last
233  * point where it corresponds to a changed run in the other file.
234  * CORRESPONDING == LEN means no such point has been found.
235  */
236  $corresponding = $j < $other_len ? $i : $len;
237 
238  /*
239  * Move the changed region forward, so long as the
240  * first changed line matches the following unchanged one.
241  * This merges with following changed regions.
242  * Do this second, so that if there are no merges,
243  * the changed region is moved forward as far as possible.
244  */
245  while ( $i < $len && $lines[$start] == $lines[$i] ) {
246  $changed[$start++] = false;
247  $changed[$i++] = 1;
248  while ( $i < $len && $changed[$i] ) {
249  $i++;
250  }
251 
252  assert( $j < $other_len && !$other_changed[$j] );
253  $j++;
254  if ( $j < $other_len && $other_changed[$j] ) {
255  $corresponding = $i;
256  while ( $j < $other_len && $other_changed[$j] ) {
257  $j++;
258  }
259  }
260  }
261  } while ( $runlength != $i - $start );
262 
263  /*
264  * If possible, move the fully-merged run of changes
265  * back to a corresponding run in the other file.
266  */
267  while ( $corresponding < $i ) {
268  $changed[--$start] = 1;
269  $changed[--$i] = 0;
270  assert( $j > 0 );
271  while ( $other_changed[--$j] ) {
272  continue;
273  }
274  assert( $j >= 0 && !$other_changed[$j] );
275  }
276  }
277  }
278 
284  protected function diffInternal( array $from, array $to ) {
285  // remember initial lengths
286  $m = count( $from );
287  $n = count( $to );
288 
289  $this->heuristicUsed = false;
290 
291  // output
292  $removed = $m > 0 ? array_fill( 0, $m, true ) : [];
293  $added = $n > 0 ? array_fill( 0, $n, true ) : [];
294 
295  // reduce the complexity for the next step (intentionally done twice)
296  // remove common tokens at the start
297  $i = 0;
298  while ( $i < $m && $i < $n && $from[$i] === $to[$i] ) {
299  $removed[$i] = $added[$i] = false;
300  unset( $from[$i], $to[$i] );
301  ++$i;
302  }
303 
304  // remove common tokens at the end
305  $j = 1;
306  while ( $i + $j <= $m && $i + $j <= $n && $from[$m - $j] === $to[$n - $j] ) {
307  $removed[$m - $j] = $added[$n - $j] = false;
308  unset( $from[$m - $j], $to[$n - $j] );
309  ++$j;
310  }
311 
312  $this->from = $newFromIndex = $this->to = $newToIndex = [];
313 
314  // remove tokens not in both sequences
315  $shared = [];
316  foreach ( $from as $key ) {
317  $shared[$key] = false;
318  }
319 
320  foreach ( $to as $index => &$el ) {
321  if ( array_key_exists( $el, $shared ) ) {
322  // keep it
323  $this->to[] = $el;
324  $shared[$el] = true;
325  $newToIndex[] = $index;
326  }
327  }
328  foreach ( $from as $index => &$el ) {
329  if ( $shared[$el] ) {
330  // keep it
331  $this->from[] = $el;
332  $newFromIndex[] = $index;
333  }
334  }
335 
336  unset( $shared, $from, $to );
337 
338  $this->m = count( $this->from );
339  $this->n = count( $this->to );
340 
341  if ( $this->bailoutComplexity > 0 && $this->m * $this->n > $this->bailoutComplexity ) {
342  throw new ComplexityException();
343  }
344 
345  $this->removed = $this->m > 0 ? array_fill( 0, $this->m, true ) : [];
346  $this->added = $this->n > 0 ? array_fill( 0, $this->n, true ) : [];
347 
348  if ( $this->m == 0 || $this->n == 0 ) {
349  $this->length = 0;
350  } else {
351  $this->maxDifferences = ceil( ( $this->m + $this->n ) / 2.0 );
352  if ( $this->m * $this->n > $this->tooLong ) {
353  // limit complexity to D^POW_LIMIT for long sequences
354  $this->maxDifferences = floor( $this->maxDifferences ** ( $this->powLimit - 1.0 ) );
355  wfDebug( "Limiting max number of differences to $this->maxDifferences\n" );
356  }
357 
358  /*
359  * The common prefixes and suffixes are always part of some LCS, include
360  * them now to reduce our search space
361  */
362  $max = min( $this->m, $this->n );
363  for ( $forwardBound = 0; $forwardBound < $max
364  && $this->from[$forwardBound] === $this->to[$forwardBound];
365  ++$forwardBound
366  ) {
367  $this->removed[$forwardBound] = $this->added[$forwardBound] = false;
368  }
369 
370  $backBoundL1 = $this->m - 1;
371  $backBoundL2 = $this->n - 1;
372 
373  while ( $backBoundL1 >= $forwardBound && $backBoundL2 >= $forwardBound
374  && $this->from[$backBoundL1] === $this->to[$backBoundL2]
375  ) {
376  $this->removed[$backBoundL1--] = $this->added[$backBoundL2--] = false;
377  }
378 
379  $temp = array_fill( 0, $this->m + $this->n + 1, 0 );
380  $V = [ $temp, $temp ];
381  $snake = [ 0, 0, 0 ];
382 
383  $this->length = $forwardBound + $this->m - $backBoundL1 - 1
384  + $this->lcs_rec(
385  $forwardBound,
386  $backBoundL1,
387  $forwardBound,
388  $backBoundL2,
389  $V,
390  $snake
391  );
392  }
393 
394  $this->m = $m;
395  $this->n = $n;
396 
397  $this->length += $i + $j - 1;
398 
399  foreach ( $this->removed as $key => &$removed_elem ) {
400  if ( !$removed_elem ) {
401  $removed[$newFromIndex[$key]] = false;
402  }
403  }
404  foreach ( $this->added as $key => &$added_elem ) {
405  if ( !$added_elem ) {
406  $added[$newToIndex[$key]] = false;
407  }
408  }
409  $this->removed = $removed;
410  $this->added = $added;
411  }
412 
413  function diff_range( $from_lines, $to_lines ) {
414  // Diff and store locally
415  $this->diff( $from_lines, $to_lines );
416  unset( $from_lines, $to_lines );
417 
418  $ranges = [];
419  $xi = $yi = 0;
420  while ( $xi < $this->m || $yi < $this->n ) {
421  // Matching "snake".
422  while ( $xi < $this->m && $yi < $this->n
423  && !$this->removed[$xi]
424  && !$this->added[$yi]
425  ) {
426  ++$xi;
427  ++$yi;
428  }
429  // Find deletes & adds.
430  $xstart = $xi;
431  while ( $xi < $this->m && $this->removed[$xi] ) {
432  ++$xi;
433  }
434 
435  $ystart = $yi;
436  while ( $yi < $this->n && $this->added[$yi] ) {
437  ++$yi;
438  }
439 
440  if ( $xi > $xstart || $yi > $ystart ) {
441  $ranges[] = new RangeDifference( $xstart, $xi, $ystart, $yi );
442  }
443  }
444 
445  return $ranges;
446  }
447 
448  private function lcs_rec( $bottoml1, $topl1, $bottoml2, $topl2, &$V, &$snake ) {
449  // check that both sequences are non-empty
450  if ( $bottoml1 > $topl1 || $bottoml2 > $topl2 ) {
451  return 0;
452  }
453 
454  $d = $this->find_middle_snake( $bottoml1, $topl1, $bottoml2,
455  $topl2, $V, $snake );
456 
457  // need to store these so we don't lose them when they're
458  // overwritten by the recursion
459  $len = $snake[2];
460  $startx = $snake[0];
461  $starty = $snake[1];
462 
463  // the middle snake is part of the LCS, store it
464  for ( $i = 0; $i < $len; ++$i ) {
465  $this->removed[$startx + $i] = $this->added[$starty + $i] = false;
466  }
467 
468  if ( $d > 1 ) {
469  return $len
470  + $this->lcs_rec( $bottoml1, $startx - 1, $bottoml2,
471  $starty - 1, $V, $snake )
472  + $this->lcs_rec( $startx + $len, $topl1, $starty + $len,
473  $topl2, $V, $snake );
474  } elseif ( $d == 1 ) {
475  /*
476  * In this case the sequences differ by exactly 1 line. We have
477  * already saved all the lines after the difference in the for loop
478  * above, now we need to save all the lines before the difference.
479  */
480  $max = min( $startx - $bottoml1, $starty - $bottoml2 );
481  for ( $i = 0; $i < $max; ++$i ) {
482  $this->removed[$bottoml1 + $i] =
483  $this->added[$bottoml2 + $i] = false;
484  }
485 
486  return $max + $len;
487  }
488 
489  return $len;
490  }
491 
492  private function find_middle_snake( $bottoml1, $topl1, $bottoml2, $topl2, &$V, &$snake ) {
493  $from = &$this->from;
494  $to = &$this->to;
495  $V0 = &$V[0];
496  $V1 = &$V[1];
497  $snake0 = &$snake[0];
498  $snake1 = &$snake[1];
499  $snake2 = &$snake[2];
500  $bottoml1_min_1 = $bottoml1 - 1;
501  $bottoml2_min_1 = $bottoml2 - 1;
502  $N = $topl1 - $bottoml1_min_1;
503  $M = $topl2 - $bottoml2_min_1;
504  $delta = $N - $M;
505  $maxabsx = $N + $bottoml1;
506  $maxabsy = $M + $bottoml2;
507  $limit = min( $this->maxDifferences, ceil( ( $N + $M ) / 2 ) );
508 
509  // value_to_add_forward: a 0 or 1 that we add to the start
510  // offset to make it odd/even
511  if ( ( $M & 1 ) == 1 ) {
512  $value_to_add_forward = 1;
513  } else {
514  $value_to_add_forward = 0;
515  }
516 
517  if ( ( $N & 1 ) == 1 ) {
518  $value_to_add_backward = 1;
519  } else {
520  $value_to_add_backward = 0;
521  }
522 
523  $start_forward = -$M;
524  $end_forward = $N;
525  $start_backward = -$N;
526  $end_backward = $M;
527 
528  $limit_min_1 = $limit - 1;
529  $limit_plus_1 = $limit + 1;
530 
531  $V0[$limit_plus_1] = 0;
532  $V1[$limit_min_1] = $N;
533  $limit = min( $this->maxDifferences, ceil( ( $N + $M ) / 2 ) );
534 
535  if ( ( $delta & 1 ) == 1 ) {
536  for ( $d = 0; $d <= $limit; ++$d ) {
537  $start_diag = max( $value_to_add_forward + $start_forward, -$d );
538  $end_diag = min( $end_forward, $d );
539  $value_to_add_forward = 1 - $value_to_add_forward;
540 
541  // compute forward furthest reaching paths
542  for ( $k = $start_diag; $k <= $end_diag; $k += 2 ) {
543  if ( $k == -$d || ( $k < $d
544  && $V0[$limit_min_1 + $k] < $V0[$limit_plus_1 + $k] )
545  ) {
546  $x = $V0[$limit_plus_1 + $k];
547  } else {
548  $x = $V0[$limit_min_1 + $k] + 1;
549  }
550 
551  $absx = $snake0 = $x + $bottoml1;
552  $absy = $snake1 = $x - $k + $bottoml2;
553 
554  while ( $absx < $maxabsx && $absy < $maxabsy && $from[$absx] === $to[$absy] ) {
555  ++$absx;
556  ++$absy;
557  }
558  $x = $absx - $bottoml1;
559 
560  $snake2 = $absx - $snake0;
561  $V0[$limit + $k] = $x;
562  if ( $k >= $delta - $d + 1 && $k <= $delta + $d - 1
563  && $x >= $V1[$limit + $k - $delta]
564  ) {
565  return 2 * $d - 1;
566  }
567 
568  // check to see if we can cut down the diagonal range
569  if ( $x >= $N && $end_forward > $k - 1 ) {
570  $end_forward = $k - 1;
571  } elseif ( $absy - $bottoml2 >= $M ) {
572  $start_forward = $k + 1;
573  $value_to_add_forward = 0;
574  }
575  }
576 
577  $start_diag = max( $value_to_add_backward + $start_backward, -$d );
578  $end_diag = min( $end_backward, $d );
579  $value_to_add_backward = 1 - $value_to_add_backward;
580 
581  // compute backward furthest reaching paths
582  for ( $k = $start_diag; $k <= $end_diag; $k += 2 ) {
583  if ( $k == $d
584  || ( $k != -$d && $V1[$limit_min_1 + $k] < $V1[$limit_plus_1 + $k] )
585  ) {
586  $x = $V1[$limit_min_1 + $k];
587  } else {
588  $x = $V1[$limit_plus_1 + $k] - 1;
589  }
590 
591  $y = $x - $k - $delta;
592 
593  $snake2 = 0;
594  while ( $x > 0 && $y > 0
595  && $from[$x + $bottoml1_min_1] === $to[$y + $bottoml2_min_1]
596  ) {
597  --$x;
598  --$y;
599  ++$snake2;
600  }
601  $V1[$limit + $k] = $x;
602 
603  // check to see if we can cut down our diagonal range
604  if ( $x <= 0 ) {
605  $start_backward = $k + 1;
606  $value_to_add_backward = 0;
607  } elseif ( $y <= 0 && $end_backward > $k - 1 ) {
608  $end_backward = $k - 1;
609  }
610  }
611  }
612  } else {
613  for ( $d = 0; $d <= $limit; ++$d ) {
614  $start_diag = max( $value_to_add_forward + $start_forward, -$d );
615  $end_diag = min( $end_forward, $d );
616  $value_to_add_forward = 1 - $value_to_add_forward;
617 
618  // compute forward furthest reaching paths
619  for ( $k = $start_diag; $k <= $end_diag; $k += 2 ) {
620  if ( $k == -$d
621  || ( $k < $d && $V0[$limit_min_1 + $k] < $V0[$limit_plus_1 + $k] )
622  ) {
623  $x = $V0[$limit_plus_1 + $k];
624  } else {
625  $x = $V0[$limit_min_1 + $k] + 1;
626  }
627 
628  $absx = $snake0 = $x + $bottoml1;
629  $absy = $snake1 = $x - $k + $bottoml2;
630 
631  while ( $absx < $maxabsx && $absy < $maxabsy && $from[$absx] === $to[$absy] ) {
632  ++$absx;
633  ++$absy;
634  }
635  $x = $absx - $bottoml1;
636  $snake2 = $absx - $snake0;
637  $V0[$limit + $k] = $x;
638 
639  // check to see if we can cut down the diagonal range
640  if ( $x >= $N && $end_forward > $k - 1 ) {
641  $end_forward = $k - 1;
642  } elseif ( $absy - $bottoml2 >= $M ) {
643  $start_forward = $k + 1;
644  $value_to_add_forward = 0;
645  }
646  }
647 
648  $start_diag = max( $value_to_add_backward + $start_backward, -$d );
649  $end_diag = min( $end_backward, $d );
650  $value_to_add_backward = 1 - $value_to_add_backward;
651 
652  // compute backward furthest reaching paths
653  for ( $k = $start_diag; $k <= $end_diag; $k += 2 ) {
654  if ( $k == $d
655  || ( $k != -$d && $V1[$limit_min_1 + $k] < $V1[$limit_plus_1 + $k] )
656  ) {
657  $x = $V1[$limit_min_1 + $k];
658  } else {
659  $x = $V1[$limit_plus_1 + $k] - 1;
660  }
661 
662  $y = $x - $k - $delta;
663 
664  $snake2 = 0;
665  while ( $x > 0 && $y > 0
666  && $from[$x + $bottoml1_min_1] === $to[$y + $bottoml2_min_1]
667  ) {
668  --$x;
669  --$y;
670  ++$snake2;
671  }
672  $V1[$limit + $k] = $x;
673 
674  if ( $k >= -$delta - $d && $k <= $d - $delta
675  && $x <= $V0[$limit + $k + $delta]
676  ) {
677  $snake0 = $bottoml1 + $x;
678  $snake1 = $bottoml2 + $y;
679 
680  return 2 * $d;
681  }
682 
683  // check to see if we can cut down our diagonal range
684  if ( $x <= 0 ) {
685  $start_backward = $k + 1;
686  $value_to_add_backward = 0;
687  } elseif ( $y <= 0 && $end_backward > $k - 1 ) {
688  $end_backward = $k - 1;
689  }
690  }
691  }
692  }
693  /*
694  * computing the true LCS is too expensive, instead find the diagonal
695  * with the most progress and pretend a midle snake of length 0 occurs
696  * there.
697  */
698 
699  $most_progress = self::findMostProgress( $M, $N, $limit, $V );
700 
701  $snake0 = $bottoml1 + $most_progress[0];
702  $snake1 = $bottoml2 + $most_progress[1];
703  $snake2 = 0;
704  wfDebug( "Computing the LCS is too expensive. Using a heuristic.\n" );
705  $this->heuristicUsed = true;
706 
707  return 5; /*
708  * HACK: since we didn't really finish the LCS computation
709  * we don't really know the length of the SES. We don't do
710  * anything with the result anyway, unless it's <=1. We know
711  * for a fact SES > 1 so 5 is as good a number as any to
712  * return here
713  */
714  }
715 
716  private static function findMostProgress( $M, $N, $limit, $V ) {
717  $delta = $N - $M;
718 
719  if ( ( $M & 1 ) == ( $limit & 1 ) ) {
720  $forward_start_diag = max( -$M, -$limit );
721  } else {
722  $forward_start_diag = max( 1 - $M, -$limit );
723  }
724 
725  $forward_end_diag = min( $N, $limit );
726 
727  if ( ( $N & 1 ) == ( $limit & 1 ) ) {
728  $backward_start_diag = max( -$N, -$limit );
729  } else {
730  $backward_start_diag = max( 1 - $N, -$limit );
731  }
732 
733  $backward_end_diag = -min( $M, $limit );
734 
735  $temp = [ 0, 0, 0 ];
736 
737  $max_progress = array_fill( 0, ceil( max( $forward_end_diag - $forward_start_diag,
738  $backward_end_diag - $backward_start_diag ) / 2 ), $temp );
739  $num_progress = 0; // the 1st entry is current, it is initialized
740  // with 0s
741 
742  // first search the forward diagonals
743  for ( $k = $forward_start_diag; $k <= $forward_end_diag; $k += 2 ) {
744  $x = $V[0][$limit + $k];
745  $y = $x - $k;
746  if ( $x > $N || $y > $M ) {
747  continue;
748  }
749 
750  $progress = $x + $y;
751  if ( $progress > $max_progress[0][2] ) {
752  $num_progress = 0;
753  $max_progress[0][0] = $x;
754  $max_progress[0][1] = $y;
755  $max_progress[0][2] = $progress;
756  } elseif ( $progress == $max_progress[0][2] ) {
757  ++$num_progress;
758  $max_progress[$num_progress][0] = $x;
759  $max_progress[$num_progress][1] = $y;
760  $max_progress[$num_progress][2] = $progress;
761  }
762  }
763 
764  $max_progress_forward = true; // initially the maximum
765  // progress is in the forward
766  // direction
767 
768  // now search the backward diagonals
769  for ( $k = $backward_start_diag; $k <= $backward_end_diag; $k += 2 ) {
770  $x = $V[1][$limit + $k];
771  $y = $x - $k - $delta;
772  if ( $x < 0 || $y < 0 ) {
773  continue;
774  }
775 
776  $progress = $N - $x + $M - $y;
777  if ( $progress > $max_progress[0][2] ) {
778  $num_progress = 0;
779  $max_progress_forward = false;
780  $max_progress[0][0] = $x;
781  $max_progress[0][1] = $y;
782  $max_progress[0][2] = $progress;
783  } elseif ( $progress == $max_progress[0][2] && !$max_progress_forward ) {
784  ++$num_progress;
785  $max_progress[$num_progress][0] = $x;
786  $max_progress[$num_progress][1] = $y;
787  $max_progress[$num_progress][2] = $progress;
788  }
789  }
790 
791  // return the middle diagonal with maximal progress.
792  return $max_progress[(int)floor( $num_progress / 2 )];
793  }
794 
798  public function getLcsLength() {
799  if ( $this->heuristicUsed && !$this->lcsLengthCorrectedForHeuristic ) {
800  $this->lcsLengthCorrectedForHeuristic = true;
801  $this->length = $this->m - array_sum( $this->added );
802  }
803 
804  return $this->length;
805  }
806 
807 }
808 
816 
818  public $leftstart;
819 
821  public $leftend;
822 
824  public $leftlength;
825 
827  public $rightstart;
828 
830  public $rightend;
831 
833  public $rightlength;
834 
836  $this->leftstart = $leftstart;
837  $this->leftend = $leftend;
838  $this->leftlength = $leftend - $leftstart;
839  $this->rightstart = $rightstart;
840  $this->rightend = $rightend;
841  $this->rightlength = $rightend - $rightstart;
842  }
843 
844 }
DiffEngine\$bailoutComplexity
$bailoutComplexity
Definition: DiffEngine.php:58
DiffEngine\$from
$from
Definition: DiffEngine.php:50
DiffEngine\shiftBoundaries
shiftBoundaries(array $lines, array &$changed, array $other_changed)
Adjust inserts/deletes of identical lines to join changes as much as possible.
Definition: DiffEngine.php:162
RangeDifference\$leftend
int $leftend
Definition: DiffEngine.php:821
RangeDifference\__construct
__construct( $leftstart, $leftend, $rightstart, $rightend)
Definition: DiffEngine.php:835
n
while(( $__line=Maintenance::readconsole()) !==false) print n
Definition: eval.php:64
DiffEngine\$heuristicUsed
$heuristicUsed
Definition: DiffEngine.php:68
DiffEngine\$maxDifferences
$maxDifferences
Definition: DiffEngine.php:61
DiffOpDelete
Extends DiffOp.
Definition: DairikiDiff.php:132
captcha-old.count
count
Definition: captcha-old.py:249
RangeDifference\$rightstart
int $rightstart
Definition: DiffEngine.php:827
RangeDifference\$rightlength
int $rightlength
Definition: DiffEngine.php:833
php
injection txt This is an overview of how MediaWiki makes use of dependency injection The design described here grew from the discussion of RFC T384 The term dependency this means that anything an object needs to operate should be injected from the the object itself should only know narrow no concrete implementation of the logic it relies on The requirement to inject everything typically results in an architecture that based on two main types of and essentially stateless service objects that use other service objects to operate on the value objects As of the beginning MediaWiki is only starting to use the DI approach Much of the code still relies on global state or direct resulting in a highly cyclical dependency which acts as the top level factory for services in MediaWiki which can be used to gain access to default instances of various services MediaWikiServices however also allows new services to be defined and default services to be redefined Services are defined or redefined by providing a callback the instantiator that will return a new instance of the service When it will create an instance of MediaWikiServices and populate it with the services defined in the files listed by thereby bootstrapping the DI framework Per $wgServiceWiringFiles lists includes ServiceWiring php
Definition: injection.txt:35
DiffOpChange
Extends DiffOp.
Definition: DairikiDiff.php:178
DiffEngine\diff
diff( $from_lines, $to_lines)
Performs diff.
Definition: DiffEngine.php:84
DiffEngine\getLcsLength
getLcsLength()
Definition: DiffEngine.php:798
DiffOpCopy
Extends DiffOp.
Definition: DairikiDiff.php:106
DiffEngine\$to
$to
Definition: DiffEngine.php:51
DiffEngine\$length
$length
Definition: DiffEngine.php:65
DiffOpAdd
Extends DiffOp.
Definition: DairikiDiff.php:155
DiffEngine\setBailoutComplexity
setBailoutComplexity( $value)
Sets the complexity (in comparison operations) that can't be exceeded.
Definition: DiffEngine.php:141
use
as see the revision history and available at free of to any person obtaining a copy of this software and associated documentation to deal in the Software without including without limitation the rights to use
Definition: MIT-LICENSE.txt:10
$lines
$lines
Definition: router.php:61
DiffEngine\findMostProgress
static findMostProgress( $M, $N, $limit, $V)
Definition: DiffEngine.php:716
array
The wiki should then use memcached to cache various data To use multiple just add more items to the array To increase the weight of a make its entry a array("192.168.0.1:11211", 2))
wfDebug
wfDebug( $text, $dest='all', array $context=[])
Sends a line to the debug log if enabled or, optionally, to a comment in output.
Definition: GlobalFunctions.php:988
DiffEngine\$m
$m
Definition: DiffEngine.php:52
RangeDifference\$rightend
int $rightend
Definition: DiffEngine.php:830
DiffEngine\diff_range
diff_range( $from_lines, $to_lines)
Definition: DiffEngine.php:413
RangeDifference\$leftlength
int $leftlength
Definition: DiffEngine.php:824
$value
$value
Definition: styleTest.css.php:49
DiffEngine\$tooLong
$tooLong
Definition: DiffEngine.php:55
DiffEngine\__construct
__construct( $tooLong=2000000, $powLimit=1.45)
Definition: DiffEngine.php:70
DiffEngine\$lcsLengthCorrectedForHeuristic
$lcsLengthCorrectedForHeuristic
Definition: DiffEngine.php:62
DiffEngine
This diff implementation is mainly lifted from the LCS algorithm of the Eclipse project which in turn...
Definition: DiffEngine.php:47
DiffEngine\$added
$added
Definition: DiffEngine.php:67
as
This document is intended to provide useful advice for parties seeking to redistribute MediaWiki to end users It s targeted particularly at maintainers for Linux since it s been observed that distribution packages of MediaWiki often break We ve consistently had to recommend that users seeking support use official tarballs instead of their distribution s and this often solves whatever problem the user is having It would be nice if this could such as
Definition: distributors.txt:9
MediaWiki\Diff\ComplexityException
Definition: ComplexityException.php:26
from
Apache License January AND DISTRIBUTION Definitions License shall mean the terms and conditions for and distribution as defined by Sections through of this document Licensor shall mean the copyright owner or entity authorized by the copyright owner that is granting the License Legal Entity shall mean the union of the acting entity and all other entities that control are controlled by or are under common control with that entity For the purposes of this definition control direct or to cause the direction or management of such whether by contract or including but not limited to software source documentation and configuration files Object form shall mean any form resulting from mechanical transformation or translation of a Source including but not limited to compiled object generated and conversions to other media types Work shall mean the work of whether in Source or Object made available under the as indicated by a copyright notice that is included in or attached to the whether in Source or Object that is based or other modifications as a an original work of authorship For the purposes of this Derivative Works shall not include works that remain separable from
Definition: APACHE-LICENSE-2.0.txt:43
RangeDifference\$leftstart
int $leftstart
Definition: DiffEngine.php:818
DiffEngine\lcs_rec
lcs_rec( $bottoml1, $topl1, $bottoml2, $topl2, &$V, &$snake)
Definition: DiffEngine.php:448
DiffEngine\$n
$n
Definition: DiffEngine.php:53
DiffEngine\$powLimit
$powLimit
Definition: DiffEngine.php:56
RangeDifference
Alternative representation of a set of changes, by the index ranges that are changed.
Definition: DiffEngine.php:815
DiffEngine\diffInternal
diffInternal(array $from, array $to)
Definition: DiffEngine.php:284
DiffEngine\find_middle_snake
find_middle_snake( $bottoml1, $topl1, $bottoml2, $topl2, &$V, &$snake)
Definition: DiffEngine.php:492
DiffEngine\$removed
$removed
Definition: DiffEngine.php:66