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()); }
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); }
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); }
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); }
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()); }
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()); }
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))); }