Beispiel #1
0
        private static IChangeSet <T> Virtualise(List <T> all, ChangeAwareList <T> virtualised, IVirtualRequest request, IChangeSet <T> changeset = null)
        {
            if (changeset != null)
            {
                all.Clone(changeset);
            }

            var previous = virtualised;

            var current = all.Skip(request.StartIndex)
                          .Take(request.Size)
                          .ToList();

            var adds    = current.Except(previous);
            var removes = previous.Except(current);

            virtualised.RemoveMany(removes);

            adds.ForEach(t =>
            {
                var index = current.IndexOf(t);
                virtualised.Insert(index, t);
            });

            var moves = changeset.EmptyIfNull()
                        .Where(change => change.Reason == ListChangeReason.Moved &&
                               change.MovedWithinRange(request.StartIndex, request.StartIndex + request.Size));

            foreach (var change in moves)
            {
                //check whether an item has moved within the same page
                var currentIndex  = change.Item.CurrentIndex - request.StartIndex;
                var previousIndex = change.Item.PreviousIndex - request.StartIndex;
                virtualised.Move(previousIndex, currentIndex);
            }

            //find replaces [Is this ever the case that it can be reached]
            for (var i = 0; i < current.Count; i++)
            {
                var currentItem  = current[i];
                var previousItem = previous[i];

                if (ReferenceEquals(currentItem, previousItem))
                {
                    continue;
                }

                var index = virtualised.IndexOf(currentItem);
                virtualised.Move(i, index);
            }

            return(virtualised.CaptureChanges());
        }
Beispiel #2
0
        private int GetCurrentPosition(ChangeAwareList <T> target, T item)
        {
            int index = _sortOptions == SortOptions.UseBinarySearch
                ? target.BinarySearch(item, _comparer)
                : target.IndexOf(item);

            if (index < 0)
            {
                throw new SortException("Current item cannot be found");
            }

            return(index);
        }
Beispiel #3
0
        private int GetCurrentPosition(ChangeAwareList <T> target, T item)
        {
            var index = _sortOptions == SortOptions.UseBinarySearch
                ? target.BinarySearch(item, _comparer)
                : target.IndexOf(item);

            if (index < 0)
            {
                throw new SortException($"Cannot find item: {typeof(T).Name} -> {item}");
            }

            return(index);
        }
Beispiel #4
0
        private int GetCurrentPosition(ChangeAwareList <T> target, T item)
        {
            int index;

            if (_sortOptions == SortOptions.UseBinarySearch)
            {
                index = target.BinarySearch(item, _comparer);
            }
            else
            {
                var index1 = target.IndexOf(item);
                index = target.IndexOf(item, _referencEqualityComparer);

                Debug.Assert(index == index1);
            }

            if (index < 0)
            {
                throw new SortException("Current item cannot be found");
            }

            return(index);
        }
Beispiel #5
0
        private IChangeSet <T> Reorder(ChangeAwareList <T> target)
        {
            int index = -1;

            foreach (var item in target.OrderBy(t => t, _comparer).ToList())
            {
                index++;

                var existing = target[index];

                // if item is in the same place,
                if (ReferenceEquals(item, existing))
                {
                    continue;
                }

                // Cannot use binary search as Resort is implicit of a mutable change
                var old = target.IndexOf(item);
                target.Move(old, index);
            }

            return(target.CaptureChanges());
        }
Beispiel #6
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());
        }
Beispiel #7
0
        private PageChangeSet <T> Page(List <T> all, ChangeAwareList <T> paged, IPageRequest request, IChangeSet <T> changeset = null)
        {
            if (changeset != null)
            {
                all.Clone(changeset);
            }

            var previous = paged;

            int pages = CalculatePages(all, request);
            int page  = request.Page > pages ? pages : request.Page;
            int skip  = request.Size * (page - 1);

            var current = all.Skip(skip)
                          .Take(request.Size)
                          .ToList();

            var adds    = current.Except(previous);
            var removes = previous.Except(current);

            paged.RemoveMany(removes);

            adds.ForEach(t =>
            {
                var index = current.IndexOf(t);
                paged.Insert(index, t);
            });

            var startIndex = skip;

            var moves = changeset.EmptyIfNull()
                        .Where(change => change.Reason == ListChangeReason.Moved &&
                               change.MovedWithinRange(startIndex, startIndex + request.Size));

            foreach (var change in moves)
            {
                //check whether an item has moved within the same page
                var currentIndex  = change.Item.CurrentIndex - startIndex;
                var previousIndex = change.Item.PreviousIndex - startIndex;
                paged.Move(previousIndex, currentIndex);
            }

            //find replaces [Is this ever the case that it can be reached]
            for (int i = 0; i < current.Count; i++)
            {
                var currentItem  = current[i];
                var previousItem = previous[i];

                if (ReferenceEquals(currentItem, previousItem))
                {
                    continue;
                }

                var index = paged.IndexOf(currentItem);
                paged.Move(i, index);
            }

            var changed = paged.CaptureChanges();

            return(new PageChangeSet <T>(changed, new PageResponse(paged.Count, page, all.Count, pages)));
        }