private FilteringItemInfo registerSourceItem(TSourceItem sourceItem, int sourceIndex, Position position, Position nextItemPosition, ExpressionWatcher watcher = null, Func <bool> predicateFunc = null, List <IComputingInternal> nestedComputings = null) { FilteringItemInfo itemInfo = _sourcePositions.Insert(sourceIndex); itemInfo.FilteredPosition = position; itemInfo.NextFilteredItemPosition = nextItemPosition; if (watcher == null /*&& predicateFunc == null*/) { Utils.getItemInfoContent( new object[] { sourceItem }, out watcher, out predicateFunc, out nestedComputings, _predicateExpression, out _predicateExpressionCallCount, this, _predicateContainsParametrizedObservableComputationsCalls, _predicateExpressionInfo); } itemInfo.PredicateFunc = predicateFunc; watcher.ValueChanged = _thisAsFiltering.expressionWatcher_OnValueChanged; watcher._position = itemInfo; itemInfo.ExpressionWatcher = watcher; itemInfo.NestedComputings = nestedComputings; return(itemInfo); }
internal static void modifyNextFilteredItemIndex(int sourceIndex, Position nextItemPosition, List <FilteringItemInfo> filteringItemInfos) { for (int previousSourceIndex = sourceIndex - 1; previousSourceIndex >= 0; previousSourceIndex--) { FilteringItemInfo itemInfo = filteringItemInfos[previousSourceIndex]; itemInfo.NextFilteredItemPosition = nextItemPosition; if (itemInfo.FilteredPosition != null) { break; } } }
internal static Position processAddSourceItem(int newSourceIndex, bool predicateValue, ref Position newItemPosition, ref int?newFilteredIndex, List <FilteringItemInfo> filteringItemInfos, Positions <Position> filteredPositions, int count) { Position nextItemPosition; if (newSourceIndex < filteringItemInfos.Count) { FilteringItemInfo oldItemInfo = filteringItemInfos[newSourceIndex]; Position oldItemInfoNextFilteredItemPosition = oldItemInfo.NextFilteredItemPosition; Position oldItemInfoFilteredPosition = oldItemInfo.FilteredPosition; if (predicateValue) { if (oldItemInfoFilteredPosition == null) { newItemPosition = filteredPositions.Insert(oldItemInfoNextFilteredItemPosition.Index); nextItemPosition = oldItemInfoNextFilteredItemPosition; newFilteredIndex = newItemPosition.Index; } else { int filteredIndex = oldItemInfoFilteredPosition.Index; newFilteredIndex = filteredIndex; newItemPosition = filteredPositions.Insert(filteredIndex); nextItemPosition = oldItemInfoFilteredPosition; } modifyNextFilteredItemIndex(newSourceIndex, newItemPosition, filteringItemInfos); } else { nextItemPosition = oldItemInfoFilteredPosition ?? oldItemInfoNextFilteredItemPosition; } } else { if (predicateValue) { newItemPosition = filteredPositions.List[count]; newFilteredIndex = count; nextItemPosition = filteredPositions.Add(); } else { //здесь newPositionIndex = null; так и должно быть nextItemPosition = filteredPositions.List[count]; } } return(nextItemPosition); }
internal static bool ProcessChangeSourceItem <TSourceItem>(int sourceIndex, TSourceItem sourceItem, List <FilteringItemInfo> filteringItemInfos, IFiltering <TSourceItem> filtering, Positions <Position> filteredPositions, CollectionComputing <TSourceItem> current, ExpressionWatcher expressionWatcher) { if (expressionWatcher._disposed) { return(false); } FilteringItemInfo itemInfo = filteringItemInfos[sourceIndex]; bool newPredicateValue = filtering.applyPredicate(sourceItem, itemInfo.PredicateFunc); bool oldPredicateValue = itemInfo.FilteredPosition != null; if (newPredicateValue != oldPredicateValue) { if (newPredicateValue) { int newIndex = itemInfo.NextFilteredItemPosition.Index; itemInfo.FilteredPosition = filteredPositions.Insert(newIndex); newIndex = itemInfo.FilteredPosition.Index; modifyNextFilteredItemIndex(sourceIndex, itemInfo.FilteredPosition, filteringItemInfos); current.baseInsertItem(newIndex, sourceItem); return(true); } else // if (oldPredicaeValue) { int index = itemInfo.FilteredPosition.Index; filteredPositions.Remove(index); itemInfo.FilteredPosition = null; modifyNextFilteredItemIndex(sourceIndex, itemInfo.NextFilteredItemPosition, filteringItemInfos); current.baseRemoveItem(index); return(true); } } return(false); }
internal static bool ProcessReplaceSourceItem <TExpression, TSourceItem>( FilteringItemInfo replacingItemInfo, TSourceItem sourceItem, object[] sourceItems, int sourceIndex, bool predicateContainsParametrizedObservableComputationsCalls, Expression <TExpression> predicateExpression, out int predicateExpressionCallCount, ExpressionWatcher.ExpressionInfo orderingValueSelectorExpressionInfo, List <FilteringItemInfo> filteringItemInfos, Positions <Position> filteredPositions, IFiltering <TSourceItem> thisAsFiltering, CollectionComputing <TSourceItem> current) { ExpressionWatcher oldExpressionWatcher = replacingItemInfo.ExpressionWatcher; Utils.disposeExpressionWatcher(oldExpressionWatcher, replacingItemInfo.NestedComputings, thisAsFiltering, predicateContainsParametrizedObservableComputationsCalls); Utils.getItemInfoContent( sourceItems, out ExpressionWatcher watcher, out Func <bool> predicateFunc, out List <IComputingInternal> nestedComputings1, predicateExpression, out predicateExpressionCallCount, thisAsFiltering, predicateContainsParametrizedObservableComputationsCalls, orderingValueSelectorExpressionInfo); replacingItemInfo.PredicateFunc = predicateFunc; watcher.ValueChanged = thisAsFiltering.expressionWatcher_OnValueChanged; watcher._position = oldExpressionWatcher._position; replacingItemInfo.ExpressionWatcher = watcher; replacingItemInfo.NestedComputings = nestedComputings1; bool replace = !ProcessChangeSourceItem(sourceIndex, sourceItem, filteringItemInfos, thisAsFiltering, filteredPositions, current) && replacingItemInfo.FilteredPosition != null; return(replace); }
private void unregisterSourceItem(int sourceIndex) { int?removeIndex = null; FilteringItemInfo itemInfo = _itemInfos[sourceIndex]; Utils.disposeExpressionWatcher(itemInfo.ExpressionWatcher, itemInfo.NestedComputings, this, _predicateContainsParametrizedObservableComputationsCalls); Position itemInfoFilteredPosition = itemInfo.FilteredPosition; if (itemInfoFilteredPosition != null) { removeIndex = itemInfoFilteredPosition.Index; _filteredPositions.Remove(itemInfoFilteredPosition.Index); FilteringUtils.modifyNextFilteredItemIndex(sourceIndex, itemInfo.NextFilteredItemPosition, _itemInfos); } _sourcePositions.Remove(sourceIndex); if (removeIndex.HasValue) { baseRemoveItem(removeIndex.Value); } }
internal static void ProcessMoveSourceItems <TSourceItem1>(int oldSourceIndex, int newSourceIndex1, List <FilteringItemInfo> filteringItemInfos, Positions <Position> filteredPositions, Positions <FilteringItemInfo> sourcePositions, CollectionComputing <TSourceItem1> current) { if (newSourceIndex1 != oldSourceIndex) { FilteringItemInfo itemInfoOfOldSourceIndex = filteringItemInfos[oldSourceIndex]; FilteringItemInfo itemInfoOfNewSourceIndex = filteringItemInfos[newSourceIndex1]; Position nextPosition1; Position itemInfoOfOldSourceIndexFilteredPosition = itemInfoOfOldSourceIndex.FilteredPosition; Position itemInfoOfNewSourceIndexNextFilteredItemPosition = itemInfoOfNewSourceIndex.NextFilteredItemPosition; Position itemInfoOfNewSourceIndexFilteredPosition = itemInfoOfNewSourceIndex.FilteredPosition; if (itemInfoOfOldSourceIndexFilteredPosition != null) { int oldFilteredIndex = itemInfoOfOldSourceIndexFilteredPosition.Index; int newFilteredIndex1; Position newPosition1 = itemInfoOfOldSourceIndexFilteredPosition; if (itemInfoOfNewSourceIndexFilteredPosition == null) { //nextPositionIndex = itemInfoOfNewSourceIndex.NextFilteredItemIndex; nextPosition1 = itemInfoOfNewSourceIndexNextFilteredItemPosition != itemInfoOfOldSourceIndexFilteredPosition ? itemInfoOfNewSourceIndexNextFilteredItemPosition : itemInfoOfOldSourceIndex.NextFilteredItemPosition; newFilteredIndex1 = oldSourceIndex < newSourceIndex1 ? itemInfoOfNewSourceIndexNextFilteredItemPosition.Index - 1 : itemInfoOfNewSourceIndexNextFilteredItemPosition.Index; } else { nextPosition1 = oldSourceIndex < newSourceIndex1 ? itemInfoOfNewSourceIndexNextFilteredItemPosition : itemInfoOfNewSourceIndexFilteredPosition; newFilteredIndex1 = itemInfoOfNewSourceIndexFilteredPosition.Index; } filteredPositions.Move( oldFilteredIndex, newFilteredIndex1); modifyNextFilteredItemIndex(oldSourceIndex, itemInfoOfOldSourceIndex.NextFilteredItemPosition, filteringItemInfos); sourcePositions.Move(oldSourceIndex, newSourceIndex1); itemInfoOfOldSourceIndex.NextFilteredItemPosition = nextPosition1; modifyNextFilteredItemIndex(newSourceIndex1, newPosition1, filteringItemInfos); current.baseMoveItem(oldFilteredIndex, newFilteredIndex1); } else { nextPosition1 = oldSourceIndex < newSourceIndex1 ? itemInfoOfNewSourceIndexNextFilteredItemPosition : (itemInfoOfNewSourceIndexFilteredPosition ?? itemInfoOfNewSourceIndexNextFilteredItemPosition); itemInfoOfOldSourceIndex.NextFilteredItemPosition = nextPosition1; sourcePositions.Move(oldSourceIndex, newSourceIndex1); } } }
internal void ValidateConsistency() { _filteredPositions.ValidateConsistency(); _sourcePositions.ValidateConsistency(); IList <TSourceItem> source = _sourceScalar.getValue(_source, new ObservableCollection <TSourceItem>()) as IList <TSourceItem>; // ReSharper disable once PossibleNullReferenceException if (_itemInfos.Count != source.Count) { throw new ObservableComputationsException(this, "Consistency violation: Filtering.9"); } Func <TSourceItem, bool> predicate1 = _predicateExpression.Compile(); Func <TSourceItem, FilteringItemInfo, bool> predicate = (si, fii) => fii.PredicateFunc != null?fii.PredicateFunc() : predicate1(si); // ReSharper disable once ConditionIsAlwaysTrueOrFalse if (source != null) { if (_itemInfos.Count != source.Count) { throw new ObservableComputationsException(this, "Consistency violation: Filtering.14"); } if (_source != null && _filteredPositions.List.Count - 1 != Count) { throw new ObservableComputationsException(this, "Consistency violation: Filtering.15"); } if (_source == null && _filteredPositions.List.Count != 0) { throw new ObservableComputationsException(this, "Consistency violation: Filtering.16"); } int count = 0; int index = 0; for (int sourceIndex = 0; sourceIndex < source.Count; sourceIndex++) { TSourceItem sourceItem = source[sourceIndex]; FilteringItemInfo itemInfo = _itemInfos[sourceIndex]; if (predicate(sourceItem, itemInfo)) { if (itemInfo.FilteredPosition == null) { throw new ObservableComputationsException(this, "Consistency violation: Filtering.2"); } if (!EqualityComparer <TSourceItem> .Default.Equals(this[index], sourceItem)) { throw new ObservableComputationsException(this, "Consistency violation: Filtering.1"); } if (itemInfo.FilteredPosition.Index != index) { throw new ObservableComputationsException(this, "Consistency violation: Filtering.5"); } count++; index++; } else { if (itemInfo.FilteredPosition != null) { throw new ObservableComputationsException(this, "Consistency violation: Filtering.3"); } } if (_itemInfos[sourceIndex].Index != sourceIndex) { throw new ObservableComputationsException(this, "Consistency violation: Filtering.7"); } if (itemInfo.ExpressionWatcher._position != _itemInfos[sourceIndex]) { throw new ObservableComputationsException(this, "Consistency violation: Filtering.8"); } if (itemInfo.FilteredPosition != null && !_filteredPositions.List.Contains(itemInfo.FilteredPosition)) { throw new ObservableComputationsException(this, "Consistency violation: Filtering.10"); } if (!_filteredPositions.List.Contains(itemInfo.NextFilteredItemPosition)) { throw new ObservableComputationsException(this, "Consistency violation: Filtering.11"); } if (!_itemInfos.Contains(itemInfo.ExpressionWatcher._position)) { throw new ObservableComputationsException(this, "Consistency violation: Filtering.12"); } } if (_source != null) { Position nextFilteredItemPosition = _filteredPositions.List[count]; for (int sourceIndex = source.Count - 1; sourceIndex >= 0; sourceIndex--) { TSourceItem sourceItem = source[sourceIndex]; FilteringItemInfo itemInfo = _itemInfos[sourceIndex]; if (itemInfo.NextFilteredItemPosition != nextFilteredItemPosition) { throw new ObservableComputationsException(this, "Consistency violation: Filtering.4"); } if (predicate(sourceItem, itemInfo)) { nextFilteredItemPosition = itemInfo.FilteredPosition; } } if (_filteredPositions.List.Count != count + 1) { throw new ObservableComputationsException(this, "Consistency violation: Filtering.6"); } } } }
void ISourceCollectionChangeProcessor.processSourceCollectionChanged(object sender, NotifyCollectionChangedEventArgs e) { switch (e.Action) { case NotifyCollectionChangedAction.Add: int newSourceIndex = e.NewStartingIndex; TSourceItem addedSourceItem = (TSourceItem)e.NewItems[0]; Position newItemPosition = null; Position nextItemPosition; int?newFilteredIndex = null; Utils.getItemInfoContent( new object[] { addedSourceItem }, out ExpressionWatcher newWatcher, out Func <bool> newPredicateFunc, out List <IComputingInternal> nestedComputings, _predicateExpression, out _predicateExpressionCallCount, this, _predicateContainsParametrizedObservableComputationsCalls, _predicateExpressionInfo); bool predicateValue = _thisAsFiltering.applyPredicate(addedSourceItem, newPredicateFunc); nextItemPosition = FilteringUtils.processAddSourceItem(newSourceIndex, predicateValue, ref newItemPosition, ref newFilteredIndex, _itemInfos, _filteredPositions, Count); registerSourceItem(addedSourceItem, newSourceIndex, newItemPosition, nextItemPosition, newWatcher, newPredicateFunc, nestedComputings); if (newFilteredIndex != null) { baseInsertItem(newFilteredIndex.Value, addedSourceItem); } break; case NotifyCollectionChangedAction.Remove: unregisterSourceItem(e.OldStartingIndex); break; case NotifyCollectionChangedAction.Move: FilteringUtils.ProcessMoveSourceItems(e.OldStartingIndex, e.NewStartingIndex, _itemInfos, _filteredPositions, _sourcePositions, this); break; case NotifyCollectionChangedAction.Reset: processSource(); break; case NotifyCollectionChangedAction.Replace: int sourceIndex = e.NewStartingIndex; TSourceItem replacingSourceItem = (TSourceItem)e.NewItems[0]; FilteringItemInfo replacingItemInfo = _itemInfos[sourceIndex]; bool replace = FilteringUtils.ProcessReplaceSourceItem(replacingItemInfo, replacingSourceItem, new object[] { replacingSourceItem }, sourceIndex, _predicateContainsParametrizedObservableComputationsCalls, _predicateExpression, out _predicateExpressionCallCount, _predicateExpressionInfo, _itemInfos, _filteredPositions, _thisAsFiltering, this); if (replace) { baseSetItem(replacingItemInfo.FilteredPosition.Index, replacingSourceItem); } break; } }
//TODO Uncomment new feature and write test //[ObservableComputationsCall] //public Filtering<TSourceItem> TryConstructInsertOrRemoveRequestHandlers() //{ // ConstructInsertOrRemoveActionsVisitor // constructInsertOrRemoveActionsVisitor = // new ConstructInsertOrRemoveActionsVisitor(); // constructInsertOrRemoveActionsVisitor.Visit(_predicateExpressionOriginal); // Action<TSourceItem> transformSourceItemIntoMember = // constructInsertOrRemoveActionsVisitor.TransformSourceItemIntoMember; // if (transformSourceItemIntoMember != null) // { // InsertItemRequestHandler = (index, item) => transformSourceItemIntoMember(item); // } // Action<TSourceItem> transformSourceItemNotIntoMember = // constructInsertOrRemoveActionsVisitor.TransformSourceItemIntoNotMember; // if (transformSourceItemNotIntoMember != null) // { // RemoveItemRequestHandler = index => transformSourceItemNotIntoMember(this[index]); // } // return this; //} //private class ConstructInsertOrRemoveActionsVisitor : ExpressionVisitor //{ // public Action<TSourceItem> TransformSourceItemIntoMember; // public Action<TSourceItem> TransformSourceItemIntoNotMember; // #region Overrides of ExpressionVisitor // //TODO !sourceItem.NullableProp.HasValue должно преобразооваться в sourceItem.NullableProp == null // // TODO обрабытывать выражения типа '25 == sourceItem.Id' // protected override Expression VisitBinary(BinaryExpression node) // { // ExpressionType nodeType = node.NodeType; // if (nodeType == ExpressionType.Equal || nodeType == ExpressionType.NotEqual) // { // if (node.Left is MemberExpression memberExpression) // { // Expression rightExpression = node.Right; // // ReSharper disable once PossibleNullReferenceException // MemberInfo memberExpressionMember = memberExpression.Member; // Type declaringType = memberExpressionMember.DeclaringType; // // ReSharper disable once PossibleNullReferenceException // if (declaringType.IsConstructedGenericType // && declaringType.GetGenericTypeDefinition() == typeof(Nullable<>) // && memberExpressionMember.Name == "Value") // { // memberExpression = (MemberExpression) memberExpression.Expression; // rightExpression = Expression.Convert(rightExpression, // typeof (Nullable<>).MakeGenericType(node.Left.Type)); // } // ParameterExpression parameterExpression = getParameterExpression(memberExpression); // if (parameterExpression != null) // { // if (memberExpression.Type != rightExpression.Type) // { // rightExpression = Expression.Convert(rightExpression, memberExpression.Type); // } // if (!memberExpressionMember.IsReadOnly()) // { // if (nodeType == ExpressionType.Equal) // { // TransformSourceItemIntoMember = Expression.Lambda<Action<TSourceItem>>(Expression.Assign(memberExpression, rightExpression), parameterExpression).Compile(); // } // else if (nodeType == ExpressionType.NotEqual) // { // TransformSourceItemIntoNotMember = Expression.Lambda<Action<TSourceItem>>(Expression.Assign(memberExpression, rightExpression), parameterExpression).Compile(); // } // } // } // } // } // return node; // } // private ParameterExpression getParameterExpression(MemberExpression memberExpression) // { // if (memberExpression.Expression is ParameterExpression parameterExpression) // { // return parameterExpression; // } // if (memberExpression.Expression is MemberExpression expressionMemberExpression) // { // return getParameterExpression(expressionMemberExpression); // memberExpression.Expression может быть не MemberExpression // } // return null; // } // #endregion //} protected override void processSource() { int originalCount = _items.Count; if (_sourceReadAndSubscribed) { Utils.disposeExpressionItemInfos(_itemInfos, _predicateExpressionCallCount, this); Utils.removeDownstreamConsumedComputing(_itemInfos, this); _filteredPositions = new Positions <Position>(new List <Position>(_initialCapacity)); Utils.disposeSource( _sourceScalar, _source, out _itemInfos, out _sourcePositions, _sourceAsList, handleSourceCollectionChanged); _sourceReadAndSubscribed = false; } Utils.changeSource(ref _source, _sourceScalar, _downstreamConsumedComputings, _consumers, this, out _sourceAsList, false); if (_source != null && _isActive) { Utils.initializeFromObservableCollectionWithChangeMarker( _source, ref _sourceAsList, ref _rootSourceWrapper, ref _lastProcessedSourceChangeMarker); Position nextItemPosition = _filteredPositions.Add(); int count = _sourceAsList.Count; TSourceItem[] sourceCopy = new TSourceItem[count]; _sourceAsList.CopyTo(sourceCopy, 0); _sourceAsList.CollectionChanged += handleSourceCollectionChanged; int insertingIndex = 0; int sourceIndex; for (sourceIndex = 0; sourceIndex < count; sourceIndex++) { TSourceItem sourceItem = sourceCopy[sourceIndex]; Position currentFilteredItemPosition = null; FilteringItemInfo itemInfo = registerSourceItem(sourceItem, sourceIndex, null, null); if (_thisAsFiltering.applyPredicate(sourceItem, itemInfo.PredicateFunc)) { if (originalCount > insertingIndex) { _items[insertingIndex++] = sourceItem; } else { _items.Insert(insertingIndex++, sourceItem); } currentFilteredItemPosition = nextItemPosition; nextItemPosition = _filteredPositions.Add(); } itemInfo.FilteredPosition = currentFilteredItemPosition; itemInfo.NextFilteredItemPosition = nextItemPosition; } for (int index = originalCount - 1; index >= insertingIndex; index--) { _items.RemoveAt(index); } _sourceReadAndSubscribed = true; } else { _items.Clear(); } reset(); }