Ejemplo n.º 1
0
            public static List <Patch3Set> Diff3MergeIndices(string[] a, string[] o, string[] b)
            {
                // Given three files, A, O, and B, where both A and B are
                // independently derived from O, returns a fairly complicated
                // internal representation of merge decisions it's taken. The
                // interested reader may wish to consult
                //
                // Sanjeev Khanna, Keshav Kunal, and Benjamin C. Pierce. "A
                // Formal Investigation of Diff3." In Arvind and Prasad,
                // editors, Foundations of Software Technology and Theoretical
                // Computer Science (FSTTCS), December 2007.
                //
                // (http://www.cis.upenn.edu/~bcpierce/papers/diff3-short.pdf)

                var m1 = Diff.DiffIndices(o, a);
                var m2 = Diff.DiffIndices(o, b);

                var hunks = new List <Diff3Set>();

                for (int i = 0; i < m1.Count; i++)
                {
                    AddHunk(m1[i], Side.Left, hunks);
                }
                for (int i = 0; i < m2.Count; i++)
                {
                    AddHunk(m2[i], Side.Right, hunks);
                }
                hunks.Sort();

                var result       = new List <Patch3Set>();
                var commonOffset = 0;

                for (var hunkIndex = 0; hunkIndex < hunks.Count; hunkIndex++)
                {
                    var firstHunkIndex = hunkIndex;
                    var hunk           = hunks[hunkIndex];
                    var regionLhs      = hunk.File1Offset;
                    var regionRhs      = regionLhs + hunk.File1Length;

                    while (hunkIndex < hunks.Count - 1)
                    {
                        var maybeOverlapping = hunks[hunkIndex + 1];
                        var maybeLhs         = maybeOverlapping.File1Offset;
                        if (maybeLhs > regionRhs)
                        {
                            break;
                        }

                        regionRhs = Math.Max(regionRhs, maybeLhs + maybeOverlapping.File1Length);
                        hunkIndex++;
                    }

                    CopyCommon2(regionLhs, ref commonOffset, result);
                    if (firstHunkIndex == hunkIndex)
                    {
                        // The "overlap" was only one hunk long, meaning that
                        // there's no conflict here. Either a and o were the
                        // same, or b and o were the same.
                        if (hunk.File2Length > 0)
                        {
                            result.Add(new Patch3Set
                            {
                                Side   = hunk.Side,
                                Offset = hunk.File2Offset,
                                Length = hunk.File2Length
                            });
                        }
                    }
                    else
                    {
                        // A proper conflict. Determine the extents of the
                        // regions involved from a, o and b. Effectively merge
                        // all the hunks on the left into one giant hunk, and
                        // do the same for the right; then, correct for skew
                        // in the regions of o that each Side changed, and
                        // report appropriate spans for the three sides.

                        var regions = new Dictionary <Side, ConflictRegion>
                        {
                            {
                                Side.Left,
                                new ConflictRegion
                                {
                                    File1RegionStart = a.Length,
                                    File1RegionEnd   = -1,
                                    File2RegionStart = o.Length,
                                    File2RegionEnd   = -1
                                }
                            },
                            {
                                Side.Right,
                                new ConflictRegion
                                {
                                    File1RegionStart = b.Length,
                                    File1RegionEnd   = -1,
                                    File2RegionStart = o.Length,
                                    File2RegionEnd   = -1
                                }
                            }
                        };

                        for (int i = firstHunkIndex; i <= hunkIndex; i++)
                        {
                            hunk = hunks[i];
                            var side  = hunk.Side;
                            var r     = regions[side];
                            var oLhs  = hunk.File1Offset;
                            var oRhs  = oLhs + hunk.File1Length;
                            var abLhs = hunk.File2Offset;
                            var abRhs = abLhs + hunk.File2Length;
                            r.File1RegionStart = Math.Min(abLhs, r.File1RegionStart);
                            r.File1RegionEnd   = Math.Max(abRhs, r.File1RegionEnd);
                            r.File2RegionStart = Math.Min(oLhs, r.File2RegionStart);
                            r.File2RegionEnd   = Math.Max(oRhs, r.File2RegionEnd);
                        }
                        var aLhs = regions[Side.Left].File1RegionStart + (regionLhs - regions[Side.Left].File2RegionStart);
                        var aRhs = regions[Side.Left].File1RegionEnd + (regionRhs - regions[Side.Left].File2RegionEnd);
                        var bLhs = regions[Side.Right].File1RegionStart + (regionLhs - regions[Side.Right].File2RegionStart);
                        var bRhs = regions[Side.Right].File1RegionEnd + (regionRhs - regions[Side.Right].File2RegionEnd);

                        result.Add(new Patch3Set
                        {
                            Side                = Side.Conflict,
                            Offset              = aLhs,
                            Length              = aRhs - aLhs,
                            ConflictOldOffset   = regionLhs,
                            ConflictOldLength   = regionRhs - regionLhs,
                            ConflictRightOffset = bLhs,
                            ConflictRightLength = bRhs - bLhs
                        });
                    }

                    commonOffset = regionRhs;
                }

                CopyCommon2(o.Length, ref commonOffset, result);
                return(result);
            }