예제 #1
0
        private IChangeSet <T> ProcessImpl(ChangeAwareList <T> target, IChangeSet <T> changes)
        {
            var refreshes = new List <T>(changes.Refreshes);

            foreach (var change in changes)
            {
                switch (change.Reason)
                {
                case ListChangeReason.Add:
                {
                    var current = change.Item.Current;
                    Insert(target, current);
                    break;
                }

                case ListChangeReason.AddRange:
                {
                    var ordered = change.Range.OrderBy(t => t, _comparer).ToList();
                    if (target.Count == 0)
                    {
                        target.AddRange(ordered);
                    }
                    else
                    {
                        ordered.ForEach(item => Insert(target, item));
                    }

                    break;
                }

                case ListChangeReason.Remove:
                {
                    var current = change.Item.Current;
                    Remove(target, current);
                    break;
                }

                case ListChangeReason.Refresh:
                {
                    // add to refresh list so position can be calculated
                    refreshes.Add(change.Item.Current);

                    // add to current list so downstream operators can receive a refresh
                    // notification, so get the latest index and pass the index up the chain
                    var indexed = target.IndexOfOptional(change.Item.Current).ValueOrThrow(() => new SortException($"Cannot find index of {typeof(T).Name} -> {change.Item.Current}. Expected to be in the list"));

                    target.Refresh(indexed.Item, indexed.Index);
                    break;
                }

                case ListChangeReason.Replace:
                {
                    var current = change.Item.Current;

                    // TODO: check whether an item should stay in the same position
                    // i.e. update and move
                    Remove(target, change.Item.Previous.Value);
                    Insert(target, current);
                    break;
                }

                case ListChangeReason.RemoveRange:
                {
                    target.RemoveMany(change.Range);
                    break;
                }

                case ListChangeReason.Clear:
                {
                    target.Clear();
                    break;
                }
                }
            }

            // Now deal with refreshes [can be expensive]
            foreach (var item in refreshes)
            {
                var old = target.IndexOf(item);
                if (old == -1)
                {
                    continue;
                }

                int newPosition = GetInsertPositionLinear(target, item);
                if (old < newPosition)
                {
                    newPosition--;
                }

                if (old == newPosition)
                {
                    continue;
                }

                target.Move(old, newPosition);
            }

            return(target.CaptureChanges());
        }