示例#1
0
        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;
            }));
        }
示例#2
0
        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);
                }
            }
        }
示例#3
0
        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());
        }
示例#4
0
        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);
            }));
        }
示例#5
0
 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());
 }
示例#6
0
 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());
 }