Example #1
0
        private static int CountEqual <T> (
            IList <T> listA, IList <T> listB, int startA, int endA, int startB, int endB, DiffComparison update, DiffCache cache)
            where T : IDiffComparable
        {
            int length = 0;

            while (startA < endA && startB < endB)
            {
                var comp = cache.Compare(listA, startA, listB, startB);
                if (comp != DiffComparison.Same && comp != update)
                {
                    break;
                }
                startA++;
                startB++;
                length++;
            }
            return(length);
        }
Example #2
0
        /// <summary>
        /// Calculates move and replace operation (besides add and remove) and adjusts indices
        /// so events can be applied sequentially (included moves) to the source list
        /// </summary>
        public static IList <DiffSection <T> > Calculate <T> (IList <T> listA, IList <T> listB)
            where T : IDiffComparable
        {
            var cache = new DiffCache();
            var diffs = Calculate(listA, listB, 0, listA.Count, 0, listB.Count, DiffComparison.SoftUpdate, cache);

            var diffsWithReplace = diffs.Select(x => {
                if (x.Type == DiffType.Copy && cache.Compare(listA, x.OldIndex, listB, x.NewIndex) != DiffComparison.Same)
                {
                    x.Type = DiffType.Replace;
                }
                return(x);
            });

            var diffsDic = diffsWithReplace
                           .Where(x => x.Type != DiffType.Copy)
                           .GroupBy(diff => diff.Type)
                           .ToDictionary(gr => gr.Key, gr => gr.ToList());

            // Calculate Move diffs
            if (diffsDic.ContainsKey(DiffType.Add) && diffsDic.ContainsKey(DiffType.Remove))
            {
                foreach (var addDiff in diffsDic[DiffType.Add])
                {
                    var rmDiff = diffsDic [DiffType.Remove].FirstOrDefault(x =>
                                                                           cache.Compare(listA, x.OldIndex, listB, addDiff.NewIndex) == DiffComparison.Update);

                    if (rmDiff != null)
                    {
                        addDiff.Link     = rmDiff;
                        rmDiff.Link      = addDiff;
                        addDiff.OldIndex = rmDiff.NewIndex;
                        rmDiff.Move      = addDiff.Move = rmDiff.NewIndex < addDiff.NewIndex
                                                     ? DiffMove.Forward : DiffMove.Backward;
                    }
                }
            }

            var fwOffset    = 0;
            var bwOffsetDic = new Dictionary <DiffSection <T>, int> ();

            return(diffsDic
                   .SelectMany(x => x.Value)
                   .OrderBy(x => x.NewIndex)

                   // Deletes must happen before inserts in the same position to prevent problems with indices
                   .ThenBy(x => x.Type == DiffType.Remove ? -1 : 0)

                   // Add offset to indices so events can be raised linearly without conflicting with moves
                   .Select(x => {
                if (x.Type == DiffType.Add)
                {
                    if (x.IsMove)
                    {
                        if (x.Move == DiffMove.Forward)
                        {
                            fwOffset--;
                        }
                        else
                        {
                            bwOffsetDic.Add(x.Link, 0);
                        }
                        x.Link = null;  // Reference is not needed any more
                        x.Type = DiffType.Move;
                    }
                    foreach (var k in bwOffsetDic.Keys.ToList())
                    {
                        bwOffsetDic[k] -= 1;
                    }
                }
                else if (x.Type == DiffType.Remove)
                {
                    if (!x.IsMove)
                    {
                        foreach (var k in bwOffsetDic.Keys.ToList())
                        {
                            bwOffsetDic[k] += 1;
                        }
                    }
                    else if (x.Move == DiffMove.Forward)
                    {
                        fwOffset++;
                    }
                    else     // Move == Diff.Backward
                    {
                        x.Link.OldIndex += bwOffsetDic[x];
                        bwOffsetDic.Remove(x);
                    }
                }
                x.NewIndex += fwOffset;
                return x;
            })
                   .Where(x => !(x.Type == DiffType.Remove && x.IsMove))
                   .ToList());
        }