Пример #1
0
        private IChangeSet <TDestination> Process(ChangeAwareList <TDestination> transformed, IChangeSet <TSource> source)
        {
            //TODO: This is very inefficient as it flattens range operation
            //need to find a means of re-forming ranges
            var children = source.Unified().SelectMany(change =>
            {
                var many = _manyselector(change.Current);
                return(many.Select(m => new TransformedItem <TDestination>(change.Reason, m)));
            });

            foreach (var child in children)
            {
                switch (child.Reason)
                {
                case ListChangeReason.Add:
                    transformed.Add(child.Current);
                    break;

                case ListChangeReason.Replace:
                    transformed.Remove(child.Previous.Value);
                    transformed.Add(child.Current);
                    break;

                case ListChangeReason.Remove:
                    transformed.Remove(child.Current);
                    break;

                case ListChangeReason.Clear:
                    transformed.Clear();
                    break;
                }
            }
            return(transformed.CaptureChanges());
        }
Пример #2
0
        private IChangeSet <IGroup <TObject, TGroupKey> > Regroup(ChangeAwareList <IGroup <TObject, TGroupKey> > result,
                                                                  IDictionary <TGroupKey, Group <TObject, TGroupKey> > groupCollection,
                                                                  IReadOnlyCollection <ItemWithValue <TObject, TGroupKey> > currentItems)
        {
            //TODO: We need to update ItemWithValue>

            foreach (var itemWithValue in currentItems)
            {
                var currentGroupKey = itemWithValue.Value;
                var newGroupKey     = _groupSelector(itemWithValue.Item);
                if (newGroupKey.Equals(currentGroupKey))
                {
                    continue;
                }


                //remove from the old group
                var currentGroupLookup = GetCache(groupCollection, currentGroupKey);
                var currentGroupCache  = currentGroupLookup.Group;
                currentGroupCache.Edit(innerList => innerList.Remove(itemWithValue.Item));

                if (currentGroupCache.List.Count == 0)
                {
                    groupCollection.Remove(currentGroupKey);
                    result.Remove(currentGroupCache);
                }

                //Mark the old item with the new cache group
                itemWithValue.Value = newGroupKey;

                //add to the new group
                var newGroupLookup = GetCache(groupCollection, newGroupKey);
                var newGroupCache  = newGroupLookup.Group;
                newGroupCache.Edit(innerList => innerList.Add(itemWithValue.Item));

                if (newGroupLookup.WasCreated)
                {
                    result.Add(newGroupCache);
                }
            }

            return(result.CaptureChanges());
        }
Пример #3
0
        private void Transform(ChangeAwareList <TransformedItemContainer> transformed, IChangeSet <TSource> changes)
        {
            if (changes == null)
            {
                throw new ArgumentNullException(nameof(changes));
            }

            transformed.EnsureCapacityFor(changes);

            foreach (var item in changes)
            {
                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;
                }
                }
            }
        }
Пример #4
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());
        }
Пример #5
0
        private IChangeSet <TValue> Process(IChangeSet <ItemWithValue <T, TValue> > updates)
        {
            Action <TValue> addAction = value => _valueCounters.Lookup(value)
                                        .IfHasValue(count => _valueCounters[value] = count + 1)
                                        .Else(() =>
            {
                _valueCounters[value] = 1;
                _result.Add(value);
            });

            Action <TValue> removeAction = value =>
            {
                var counter = _valueCounters.Lookup(value);
                if (!counter.HasValue)
                {
                    return;
                }

                //decrement counter
                var newCount = counter.Value - 1;
                _valueCounters[value] = newCount;
                if (newCount != 0)
                {
                    return;
                }

                //if there are none, then remove and notify
                _result.Remove(value);
            };

            foreach (var change in updates)
            {
                switch (change.Reason)
                {
                case ListChangeReason.Add:
                {
                    var value = change.Item.Current.Value;
                    addAction(value);
                    break;
                }

                case ListChangeReason.AddRange:
                {
                    change.Range.Select(item => item.Value).ForEach(addAction);
                    break;
                }

                //	case ListChangeReason.Evaluate:
                case ListChangeReason.Replace:
                {
                    var value    = change.Item.Current.Value;
                    var previous = change.Item.Previous.Value.Value;
                    if (value.Equals(previous))
                    {
                        return(_result.CaptureChanges());
                    }

                    removeAction(previous);
                    addAction(value);
                    break;
                }

                case ListChangeReason.Remove:
                {
                    var previous = change.Item.Current.Value;
                    removeAction(previous);
                    break;
                }

                case ListChangeReason.RemoveRange:
                {
                    change.Range.Select(item => item.Value).ForEach(removeAction);
                    break;
                }

                case ListChangeReason.Clear:
                {
                    _result.Clear();
                    _valueCounters.Clear();
                    break;
                }
                }
            }
            return(_result.CaptureChanges());
        }