MediaWiki REL1_32
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
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
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 ) {
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
819
821 public $leftend;
822
825
828
830 public $rightend;
831
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}
Apache License January AND DISTRIBUTION Definitions License shall mean the terms and conditions for use
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
wfDebug( $text, $dest='all', array $context=[])
Sends a line to the debug log if enabled or, optionally, to a comment in output.
This diff implementation is mainly lifted from the LCS algorithm of the Eclipse project which in turn...
setBailoutComplexity( $value)
Sets the complexity (in comparison operations) that can't be exceeded.
diff_range( $from_lines, $to_lines)
__construct( $tooLong=2000000, $powLimit=1.45)
lcs_rec( $bottoml1, $topl1, $bottoml2, $topl2, &$V, &$snake)
shiftBoundaries(array $lines, array &$changed, array $other_changed)
Adjust inserts/deletes of identical lines to join changes as much as possible.
diff( $from_lines, $to_lines)
Performs diff.
diffInternal(array $from, array $to)
$lcsLengthCorrectedForHeuristic
find_middle_snake( $bottoml1, $topl1, $bottoml2, $topl2, &$V, &$snake)
static findMostProgress( $M, $N, $limit, $V)
Extends DiffOp.
Extends DiffOp.
Extends DiffOp.
Extends DiffOp.
Alternative representation of a set of changes, by the index ranges that are changed.
__construct( $leftstart, $leftend, $rightstart, $rightend)
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
also included in $newHeader if any indicating whether we should show just the diff
Definition hooks.txt:1311
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:37
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))
$lines
Definition router.php:61