diff.ts ×23

Frontier kind: Code frontier

unlabeled · c_e4184cda32c4

82 tests · 6145 LOC · 31 files · introduces 0 tests · 158 LOC · 1 file

Introduces — evidence that enters the hierarchy at this concept

Code
23 ranges158 lines · 1 files
Tests
0 tests

Contains — complete concept membership

All code (extent)
897 ranges6145 lines · 31 files · Browse complete extent
All tests (intent)
82 testsBrowse complete intent

Neighbourhood graph

The orange circle is the focus. Violet and green circles are every ancestor and descendant, broader and narrower, at any distance; blue squares and pink diamonds are the introduced files and exact introduced tests of every visible concept, not only the focus's. Arrows point from broader to narrower concepts and bridge only concepts omitted from this view. Undirected links show source or test introduction. Concept and file size follows LOC; exact test nodes use test-count units.

Introduced files, introduced tests, and structurally relevant concept specialization

In the embedded map, ordinary wheel input scrolls the page; use the visible controls to zoom and drag to pan. Open the full-screen map for canvas navigation: wheel pans, Ctrl/Command plus wheel zooms, and arrow keys pan when this region is focused. On touch screens, open the full-screen map to pan or pinch. If JavaScript or WebGL is unavailable, use the native relationship evidence on this page.

Graph controls are ready.

Interactive rendering requires JavaScript and WebGL. Use the native relationship evidence on this page while the interactive map is unavailable.

Native relationship evidence

Every exact file and test below is linked only from the concept that introduces it.

Introduced tests

Every collected test enters the hierarchy at exactly one concept.

No tests are introduced at this concept. Its intent tests are introduced by other concepts.

Introduced code

Every collected source range enters the hierarchy at exactly one concept.

1 file ranked by introduced lines: 158 introduced LOC across 23 ranges. Expand a file to inspect source; the > gutter marks introduced lines.

src/vs/base/common/diff/diff.ts 158 introduced LOC · 23 ranges

Open complete file

96 */
97 public static Copy(sourceArray: unknown[], sourceIndex: number, destinationArray: unknown[], destinationIndex: number, length: number) {
98 > for (let i = 0; i < length; i++) { diff.ts
99 destinationArray[destinationIndex + i] = sourceArray[sourceIndex + i];
100 }
101 > } diff.ts
102 public static Copy2(sourceArray: Int32Array, sourceIndex: number, destinationArray: Int32Array, destinationIndex: number, length: number) {
103 for (let i = 0; i < length; i++) {
399 return changes;
400 }
401 > diff.ts
402 > // This problem can be solved using the Divide-And-Conquer technique.
403 > const midOriginalArr = [0];
404 > const midModifiedArr = [0];
405 > const result = this.ComputeRecursionPoint(originalStart, originalEnd, modifiedStart, modifiedEnd, midOriginalArr, midModifiedArr, quitEarlyArr);
406 >
407 > const midOriginal = midOriginalArr[0];
408 > const midModified = midModifiedArr[0];
409 >
410 > if (result !== null) {
411 // Result is not-null when there was enough memory to compute the changes while
412 // searching for the recursion point
413 return result;
414 > } else if (!quitEarlyArr[0]) { diff.ts
415 // We can break the problem down recursively by finding the changes in the
416 // First Half: (originalStart, modifiedStart) to (midOriginal, midModified)
583 */
584 private ComputeRecursionPoint(originalStart: number, originalEnd: number, modifiedStart: number, modifiedEnd: number, midOriginalArr: number[], midModifiedArr: number[], quitEarlyArr: boolean[]) {
585 > let originalIndex = 0, modifiedIndex = 0; diff.ts
586 > let diagonalForwardStart = 0, diagonalForwardEnd = 0;
587 > let diagonalReverseStart = 0, diagonalReverseEnd = 0;
588 >
589 > // To traverse the edit graph and produce the proper LCS, our actual
590 > // start position is just outside the given boundary
591 > originalStart--;
592 > modifiedStart--;
593 >
594 > // We set these up to make the compiler happy, but they will
595 > // be replaced before we return with the actual recursion point
596 > midOriginalArr[0] = 0;
597 > midModifiedArr[0] = 0;
598 >
599 > // Clear out the history
600 > this.m_forwardHistory = [];
601 > this.m_reverseHistory = [];
602 >
603 > // Each cell in the two arrays corresponds to a diagonal in the edit graph.
604 > // The integer value in the cell represents the originalIndex of the furthest
605 > // reaching point found so far that ends in that diagonal.
606 > // The modifiedIndex can be computed mathematically from the originalIndex and the diagonal number.
607 > const maxDifferences = (originalEnd - originalStart) + (modifiedEnd - modifiedStart);
608 > const numDiagonals = maxDifferences + 1;
609 > const forwardPoints = new Int32Array(numDiagonals);
610 > const reversePoints = new Int32Array(numDiagonals);
611 > // diagonalForwardBase: Index into forwardPoints of the diagonal which passes through (originalStart, modifiedStart)
612 > // diagonalReverseBase: Index into reversePoints of the diagonal which passes through (originalEnd, modifiedEnd)
613 > const diagonalForwardBase = (modifiedEnd - modifiedStart);
614 > const diagonalReverseBase = (originalEnd - originalStart);
615 > // diagonalForwardOffset: Geometric offset which allows modifiedIndex to be computed from originalIndex and the
616 > // diagonal number (relative to diagonalForwardBase)
617 > // diagonalReverseOffset: Geometric offset which allows modifiedIndex to be computed from originalIndex and the
618 > // diagonal number (relative to diagonalReverseBase)
619 > const diagonalForwardOffset = (originalStart - modifiedStart);
620 > const diagonalReverseOffset = (originalEnd - modifiedEnd);
621 >
622 > // delta: The difference between the end diagonal and the start diagonal. This is used to relate diagonal numbers
623 > // relative to the start diagonal with diagonal numbers relative to the end diagonal.
624 > // The Even/Oddn-ness of this delta is important for determining when we should check for overlap
625 > const delta = diagonalReverseBase - diagonalForwardBase;
626 > const deltaIsEven = (delta % 2 === 0);
627 >
628 > // Here we set up the start and end points as the furthest points found so far
629 > // in both the forward and reverse directions, respectively
630 > forwardPoints[diagonalForwardBase] = originalStart;
631 > reversePoints[diagonalReverseBase] = originalEnd;
632 >
633 > // Remember if we quit early, and thus need to do a best-effort result instead of a real result.
634 > quitEarlyArr[0] = false;
635 >
636 >
637 >
638 > // A couple of points:
639 > // --With this method, we iterate on the number of differences between the two sequences.
640 > // The more differences there actually are, the longer this will take.
641 > // --Also, as the number of differences increases, we have to search on diagonals further
642 > // away from the reference diagonal (which is diagonalForwardBase for forward, diagonalReverseBase for reverse).
643 > // --We extend on even diagonals (relative to the reference diagonal) only when numDifferences
644 > // is even and odd diagonals only when numDifferences is odd.
645 > for (let numDifferences = 1; numDifferences <= (maxDifferences / 2) + 1; numDifferences++) {
646 > let furthestOriginalIndex = 0;
647 > let furthestModifiedIndex = 0;
648 >
649 > // Run the algorithm in the forward direction
650 > diagonalForwardStart = this.ClipDiagonalBound(diagonalForwardBase - numDifferences, numDifferences, diagonalForwardBase, numDiagonals);
651 > diagonalForwardEnd = this.ClipDiagonalBound(diagonalForwardBase + numDifferences, numDifferences, diagonalForwardBase, numDiagonals);
652 > for (let diagonal = diagonalForwardStart; diagonal <= diagonalForwardEnd; diagonal += 2) {
653 > // STEP 1: We extend the furthest reaching point in the present diagonal
654 > // by looking at the diagonals above and below and picking the one whose point
655 > // is further away from the start point (originalStart, modifiedStart)
656 > if (diagonal === diagonalForwardStart || (diagonal < diagonalForwardEnd && forwardPoints[diagonal - 1] < forwardPoints[diagonal + 1])) {
657 > originalIndex = forwardPoints[diagonal + 1];
658 > } else {
659 > originalIndex = forwardPoints[diagonal - 1] + 1;
660 > }
661 > modifiedIndex = originalIndex - (diagonal - diagonalForwardBase) - diagonalForwardOffset;
662 >
663 > // Save the current originalIndex so we can test for false overlap in step 3
664 > const tempOriginalIndex = originalIndex;
665 >
666 > // STEP 2: We can continue to extend the furthest reaching point in the present diagonal
667 > // so long as the elements are equal.
668 > while (originalIndex < originalEnd && modifiedIndex < modifiedEnd && this.ElementsAreEqual(originalIndex + 1, modifiedIndex + 1)) {
669 originalIndex++;
670 modifiedIndex++;
671 }
672 > forwardPoints[diagonal] = originalIndex; diff.ts
673 >
674 > if (originalIndex + modifiedIndex > furthestOriginalIndex + furthestModifiedIndex) {
675 furthestOriginalIndex = originalIndex;
676 furthestModifiedIndex = modifiedIndex;
677 }
678 > diff.ts
679 > // STEP 3: If delta is odd (overlap first happens on forward when delta is odd)
680 > // and diagonal is in the range of reverse diagonals computed for numDifferences-1
681 > // (the previous iteration; we haven't computed reverse diagonals for numDifferences yet)
682 > // then check for overlap.
683 > if (!deltaIsEven && Math.abs(diagonal - diagonalReverseBase) <= (numDifferences - 1)) {
684 if (originalIndex >= reversePoints[diagonal]) {
685 midOriginalArr[0] = originalIndex;
702 }
703 }
704 > } diff.ts
705 >
706 > // Check to see if we should be quitting early, before moving on to the next iteration.
707 > const matchLengthOfLongest = ((furthestOriginalIndex - originalStart) + (furthestModifiedIndex - modifiedStart) - numDifferences) / 2;
708 >
709 > if (this.ContinueProcessingPredicate !== null && !this.ContinueProcessingPredicate(furthestOriginalIndex, matchLengthOfLongest)) {
710 // We can't finish, so skip ahead to generating a result from what we have.
711 quitEarlyArr[0] = true;
738 }
739 }
740 > diff.ts
741 > // Run the algorithm in the reverse direction
742 > diagonalReverseStart = this.ClipDiagonalBound(diagonalReverseBase - numDifferences, numDifferences, diagonalReverseBase, numDiagonals);
743 > diagonalReverseEnd = this.ClipDiagonalBound(diagonalReverseBase + numDifferences, numDifferences, diagonalReverseBase, numDiagonals);
744 > for (let diagonal = diagonalReverseStart; diagonal <= diagonalReverseEnd; diagonal += 2) {
745 > // STEP 1: We extend the furthest reaching point in the present diagonal
746 > // by looking at the diagonals above and below and picking the one whose point
747 > // is further away from the start point (originalEnd, modifiedEnd)
748 > if (diagonal === diagonalReverseStart || (diagonal < diagonalReverseEnd && reversePoints[diagonal - 1] >= reversePoints[diagonal + 1])) {
749 > originalIndex = reversePoints[diagonal + 1] - 1;
750 > } else {
751 originalIndex = reversePoints[diagonal - 1];
752 }
753 > modifiedIndex = originalIndex - (diagonal - diagonalReverseBase) - diagonalReverseOffset; diff.ts
754 >
755 > // Save the current originalIndex so we can test for false overlap
756 > const tempOriginalIndex = originalIndex;
757 >
758 > // STEP 2: We can continue to extend the furthest reaching point in the present diagonal
759 > // as long as the elements are equal.
760 > while (originalIndex > originalStart && modifiedIndex > modifiedStart && this.ElementsAreEqual(originalIndex, modifiedIndex)) {
761 originalIndex--;
762 modifiedIndex--;
763 }
764 > reversePoints[diagonal] = originalIndex; diff.ts
765 >
766 > // STEP 4: If delta is even (overlap first happens on reverse when delta is even)
767 > // and diagonal is in the range of forward diagonals computed for numDifferences
768 > // then check for overlap.
769 > if (deltaIsEven && Math.abs(diagonal - diagonalForwardBase) <= numDifferences) {
770 if (originalIndex <= forwardPoints[diagonal]) {
771 midOriginalArr[0] = originalIndex;
788 }
789 }
790 > } diff.ts
791
792 // Save current vectors to history before the next iteration
804 this.m_reverseHistory.push(temp);
805 }
806 > diff.ts
807 > }
808
809 // If we got here, then we have the full trace in history. We just have to convert it to a change list
816 deltaIsEven, quitEarlyArr
817 );
818 > } diff.ts
819
820 /**
1048 */
1049 private ConcatenateChanges(left: DiffChange[], right: DiffChange[]): DiffChange[] {
1050 > const mergedChangeArr: DiffChange[] = []; diff.ts
1051 >
1052 > if (left.length === 0 || right.length === 0) {
1053 return (right.length > 0) ? right : left;
1054 > } else if (this.ChangesOverlap(left[left.length - 1], right[0], mergedChangeArr)) { diff.ts
1055 // Since we break the problem down recursively, it is possible that we
1056 // might recurse in the middle of a change thereby splitting it into
1063
1064 return result;
1065 > } else { diff.ts
1066 const result = new Array<DiffChange>(left.length + right.length);
1067 MyArray.Copy(left, 0, result, 0, left.length);
1070 return result;
1071 }
1072 > } diff.ts
1073
1074 /**
1081 */
1082 private ChangesOverlap(left: DiffChange, right: DiffChange, mergedChangeArr: Array<DiffChange | null>): boolean {
1083 > Debug.Assert(left.originalStart <= right.originalStart, 'Left change is not less than or equal to right change'); diff.ts
1084 > Debug.Assert(left.modifiedStart <= right.modifiedStart, 'Left change is not less than or equal to right change');
1085 >
1086 > if (left.originalStart + left.originalLength >= right.originalStart || left.modifiedStart + left.modifiedLength >= right.modifiedStart) {
1087 const originalStart = left.originalStart;
1088 let originalLength = left.originalLength;
1099 mergedChangeArr[0] = new DiffChange(originalStart, originalLength, modifiedStart, modifiedLength);
1100 return true;
1101 > } else { diff.ts
1102 mergedChangeArr[0] = null;
1103 return false;
1104 }
1105 > } diff.ts
1106
1107 /**
1118 */
1119 private ClipDiagonalBound(diagonal: number, numDifferences: number, diagonalBaseIndex: number, numDiagonals: number): number {
1120 > if (diagonal >= 0 && diagonal < numDiagonals) { diff.ts
1121 > // Nothing to clip, its in range
1122 > return diagonal;
1123 > }
1124
1125 // diagonalsBelow: The number of diagonals below the reference diagonal
1136 return (diffEven === upperBoundEven) ? numDiagonals - 1 : numDiagonals - 2;
1137 }
1138 > } diff.ts
1139 }
1140