Exemplo n.º 1
0
        private IChangeSet <IGroup <TObject, TGroupKey> > Process(ChangeAwareList <IGroup <TObject, TGroupKey> > result, IDictionary <TGroupKey, Group <TObject, TGroupKey> > groupCollection, IChangeSet <ItemWithValue <TObject, TGroupKey> > changes)
        {
            //TODO.This flattened enumerator is inefficient as range operations are lost.
            //maybe can infer within each grouping whether we can regroup i.e. Another enumerator!!!

            foreach (var grouping in changes.Unified().GroupBy(change => change.Current.Value))
            {
                //lookup group and if created, add to result set
                var currentGroup = grouping.Key;
                var lookup       = GetCache(groupCollection, currentGroup);
                var groupCache   = lookup.Group;

                if (lookup.WasCreated)
                {
                    result.Add(groupCache);
                }

                //start a group edit session, so all changes are batched
                groupCache.Edit(
                    list =>
                {
                    //iterate through the group's items and process
                    foreach (var change in grouping)
                    {
                        switch (change.Reason)
                        {
                        case ListChangeReason.Add:
                            {
                                list.Add(change.Current.Item);
                                break;
                            }

                        case ListChangeReason.Replace:
                            {
                                var previousItem  = change.Previous.Value.Item;
                                var previousGroup = change.Previous.Value.Value;

                                //check whether an item changing has resulted in a different group
                                if (previousGroup.Equals(currentGroup))
                                {
                                    //find and replace
                                    var index   = list.IndexOf(previousItem);
                                    list[index] = change.Current.Item;
                                }
                                else
                                {
                                    //add to new group
                                    list.Add(change.Current.Item);

                                    //remove from old group
                                    groupCollection.Lookup(previousGroup)
                                    .IfHasValue(g =>
                                    {
                                        g.Edit(oldList => oldList.Remove(previousItem));
                                        if (g.List.Count != 0)
                                        {
                                            return;
                                        }
                                        groupCollection.Remove(g.GroupKey);
                                        result.Remove(g);
                                    });
                                }

                                break;
                            }

                        case ListChangeReason.Remove:
                            {
                                list.Remove(change.Current.Item);
                                break;
                            }

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

                if (groupCache.List.Count == 0)
                {
                    groupCollection.Remove(groupCache.GroupKey);
                    result.Remove(groupCache);
                }
            }
            return(result.CaptureChanges());
        }
Exemplo n.º 2
0
        private void Transform(IChangeSet <TSource> changes)
        {
            if (changes == null)
            {
                throw new ArgumentNullException(nameof(changes));
            }

            _transformed.EnsureCapacityFor(changes);

            changes.ForEach(item =>
            {
                switch (item.Reason)
                {
                case ListChangeReason.Add:
                    {
                        var change = item.Item;
                        if (change.CurrentIndex < 0 | change.CurrentIndex >= _transformed.Count)
                        {
                            _transformed.Add(_containerFactory(change.Current));
                        }
                        else
                        {
                            _transformed.Insert(change.CurrentIndex, _containerFactory(change.Current));
                        }
                        break;
                    }

                case ListChangeReason.AddRange:
                    {
                        _transformed.AddOrInsertRange(item.Range.Select(_containerFactory), item.Range.Index);
                        break;
                    }

                case ListChangeReason.Replace:
                    {
                        var change = item.Item;
                        if (change.CurrentIndex == change.PreviousIndex)
                        {
                            _transformed[change.CurrentIndex] = _containerFactory(change.Current);
                        }
                        else
                        {
                            _transformed.RemoveAt(change.PreviousIndex);
                            _transformed.Insert(change.CurrentIndex, _containerFactory(change.Current));
                        }
                    }
                    break;

                case ListChangeReason.Remove:
                    {
                        var change    = item.Item;
                        bool hasIndex = change.CurrentIndex >= 0;

                        if (hasIndex)
                        {
                            _transformed.RemoveAt(item.Item.CurrentIndex);
                        }
                        else
                        {
                            var toremove = _transformed.FirstOrDefault(t => ReferenceEquals(t.Source, t));

                            if (toremove != null)
                            {
                                _transformed.Remove(toremove);
                            }
                        }
                    }
                    break;

                case ListChangeReason.RemoveRange:
                    {
                        if (item.Range.Index >= 0)
                        {
                            _transformed.RemoveRange(item.Range.Index, item.Range.Count);
                        }
                        else
                        {
                            var toremove = _transformed.Where(t => ReferenceEquals(t.Source, t)).ToArray();
                            _transformed.RemoveMany(toremove);
                        }
                    }
                    break;

                case ListChangeReason.Clear:
                    {
                        //i.e. need to store transformed reference so we can correctly clear
                        var toClear = new Change <TransformedItemContainer>(ListChangeReason.Clear, _transformed);
                        _transformed.ClearOrRemoveMany(toClear);
                    }
                    break;

                case ListChangeReason.Moved:
                    {
                        var change    = item.Item;
                        bool hasIndex = change.CurrentIndex >= 0;
                        if (!hasIndex)
                        {
                            throw new UnspecifiedIndexException("Cannot move as an index was not specified");
                        }

                        var collection = _transformed as IExtendedList <TransformedItemContainer>;
                        if (collection != null)
                        {
                            collection.Move(change.PreviousIndex, change.CurrentIndex);
                        }
                        else
                        {
                            var current = _transformed[change.PreviousIndex];
                            _transformed.RemoveAt(change.PreviousIndex);
                            _transformed.Insert(change.CurrentIndex, current);
                        }
                        break;
                    }
                }
            });
        }