public IObservable <IChangeSet <T> > Run() { return(Observable.Create <IChangeSet <T> >(observer => { var disposable = new CompositeDisposable(); var sourceLists = new List <ReferenceCountTracker <T> >(); var resultList = new ChangeAwareListWithRefCounts <T>(); lock (_locker) { foreach (var item in _source) { var list = new ReferenceCountTracker <T>(); sourceLists.Add(list); disposable.Add(item.Synchronize(_locker).Subscribe(changes => { CloneSourceList(list, changes); var notifications = UpdateResultList(changes, sourceLists, resultList); if (notifications.Count != 0) { observer.OnNext(notifications); } })); } } return disposable; })); }
private void ProcessItem(MergeContainer[] sourceLists, ChangeAwareListWithRefCounts <T> resultingList, T item) { //check whether the item should be removed from the list var isInResult = resultingList.Contains(item); var shouldBeInResult = MatchesConstraint(sourceLists, item); if (shouldBeInResult) { if (!isInResult) { resultingList.Add(item); } } else { if (isInResult) { resultingList.Remove(item); } } }
private IChangeSet <T> UpdateResultList(IChangeSet <T> changes, List <ReferenceCountTracker <T> > sourceLists, ChangeAwareListWithRefCounts <T> resultList) { //child caches have been updated before we reached this point. foreach (var change in changes.Flatten()) { var item = change.Current; var isInResult = resultList.Contains(item); var shouldBeInResult = MatchesConstraint(sourceLists, item); if (shouldBeInResult) { if (!isInResult) { resultList.Add(item); } } else { if (isInResult) { resultList.Remove(item); } } } return(resultList.CaptureChanges()); }
public IObservable <IChangeSet <T> > Run() { return(Observable.Create <IChangeSet <T> >(observer => { //this is the resulting list which produces all notifications var resultList = new ChangeAwareListWithRefCounts <T>(); //Transform to a merge container. //This populates a RefTracker when the original source is subscribed to var sourceLists = _source.Connect() .Synchronize(_locker) .Transform(changeset => new MergeContainer(changeset)) .AsObservableList(); //merge the items back together var allChanges = sourceLists.Connect() .MergeMany(mc => mc.Source) .Synchronize(_locker) .Subscribe(changes => { //Populate result list and chck for changes var notifications = UpdateResultList(sourceLists.Items.AsArray(), resultList, changes); if (notifications.Count != 0) { observer.OnNext(notifications); } }); //when an list is removed, need to var removedItem = sourceLists.Connect() .OnItemRemoved(mc => { //Remove items if required var notifications = ProcessChanges(sourceLists.Items.AsArray(), resultList, mc.Tracker.Items); if (notifications.Count != 0) { observer.OnNext(notifications); } if (_type == CombineOperator.And || _type == CombineOperator.Except) { var itemsToCheck = sourceLists.Items.SelectMany(mc2 => mc2.Tracker.Items).ToArray(); var notification2 = ProcessChanges(sourceLists.Items.AsArray(), resultList, itemsToCheck); if (notification2.Count != 0) { observer.OnNext(notification2); } } }) .Subscribe(); //when an list is added or removed, need to var sourceChanged = sourceLists.Connect() .WhereReasonsAre(ListChangeReason.Add, ListChangeReason.AddRange) .ForEachItemChange(mc => { var notifications = ProcessChanges(sourceLists.Items.AsArray(), resultList, mc.Current.Tracker.Items); if (notifications.Count != 0) { observer.OnNext(notifications); } if (_type == CombineOperator.And || _type == CombineOperator.Except) { var notification2 = ProcessChanges(sourceLists.Items.AsArray(), resultList, resultList.ToArray()); if (notification2.Count != 0) { observer.OnNext(notification2); } } }) .Subscribe(); return new CompositeDisposable(sourceLists, allChanges, removedItem, sourceChanged); })); }
private IChangeSet <T> ProcessChanges(MergeContainer[] sourceLists, ChangeAwareListWithRefCounts <T> resultingList, IEnumerable <T> items) { //check whether the item should be removed from the list items.ForEach(item => { ProcessItem(sourceLists, resultingList, item); }); return(resultingList.CaptureChanges()); }
private IChangeSet <T> UpdateResultList(MergeContainer[] sourceLists, ChangeAwareListWithRefCounts <T> resultingList, IChangeSet <T> changes) { //child caches have been updated before we reached this point. changes.Flatten().ForEach(change => { ProcessItem(sourceLists, resultingList, change.Current); }); return(resultingList.CaptureChanges()); }