예제 #1
0
        private IObservable <IChangeSet <TDestination> > CreateWithChangeset()
        {
            return(Observable.Create <IChangeSet <TDestination> >(observer =>
            {
                var result = new ChangeAwareList <TDestination>();

                var transformed = _source.Transform(t =>
                {
                    var locker = new object();
                    var collection = _manyselector(t);
                    var changes = _childChanges(t).Synchronize(locker).Skip(1);
                    return new ManyContainer(collection, changes);
                })
                                  .Publish();

                var outerLock = new object();
                var intial = transformed
                             .Synchronize(outerLock)
                             .Select(changes => new ChangeSet <TDestination>(new DestinationEnumerator(changes, _equalityComparer)));

                var subsequent = transformed
                                 .MergeMany(x => x.Changes)
                                 .Synchronize(outerLock);

                var allChanges = intial.Merge(subsequent).Select(changes =>
                {
                    result.Clone(changes);
                    return result.CaptureChanges();
                });

                return new CompositeDisposable(allChanges.SubscribeSafe(observer), transformed.Connect());
            }));
        }
예제 #2
0
        public IObservable <IChangeSet <T> > Run()
        {
            return(Observable.Create <IChangeSet <T> >(observer =>
            {
                var locker = new object();
                var orginal = new ChangeAwareList <T>();
                var target = new ChangeAwareList <T>();

                var changed = _source.Synchronize(locker).Select(changes =>
                {
                    if (_resetThreshold > 1)
                    {
                        orginal.Clone(changes);
                    }

                    return changes.TotalChanges > _resetThreshold && _comparer != null ? Reset(orginal, target) : Process(target, changes);
                });
                var resort = _resort.Synchronize(locker).Select(changes => Reorder(target));
                var changeComparer = _comparerObservable.Synchronize(locker).Select(comparer => ChangeComparer(target, comparer));

                return changed.Merge(resort).Merge(changeComparer)
                .Where(changes => changes.Count != 0)
                .SubscribeSafe(observer);
            }));
        }
예제 #3
0
        public IObservable <IChangeSet <TDestination> > Run()
        {
            if (_childChanges != null)
            {
                return(CreateWithChangeset());
            }

            return(Observable.Create <IChangeSet <TDestination> >(observer =>
            {
                //NB: ChangeAwareList is used internally by dd to capture changes to a list and ensure they can be replayed by subsequent operators
                var result = new ChangeAwareList <TDestination>();

                return _source.Transform(item => new ManyContainer(_manyselector(item).ToArray()), true)
                .Select(changes =>
                {
                    var destinationChanges = new ChangeSet <TDestination>(new DestinationEnumerator(changes, _equalityComparer));
                    result.Clone(destinationChanges, _equalityComparer);
                    return result.CaptureChanges();
                })

                .NotEmpty()
                .SubscribeSafe(observer);
            }
                                                                  ));
        }
예제 #4
0
        public IChangeSet <T> Write(IChangeSet <T> changes)
        {
            if (changes == null)
            {
                throw new ArgumentNullException(nameof(changes));
            }
            IChangeSet <T> result;

            lock (_locker)
            {
                _data.Clone(changes);
                result = _data.CaptureChanges();
            }
            return(result);
        }
예제 #5
0
        public IChangeSet <T> Write(IChangeSet <T> changes)
        {
            if (changes == null)
            {
                throw new ArgumentNullException(nameof(changes));
            }
            IChangeSet <T> result;

            _lock.EnterWriteLock();
            try
            {
                _data.Clone(changes);
                result = _data.CaptureChanges();
            }
            finally
            {
                _lock.ExitWriteLock();
            }
            return(result);
        }
예제 #6
0
        public Continuation <IChangeSet <T> > Write(IChangeSet <T> changes)
        {
            if (changes == null)
            {
                throw new ArgumentNullException(nameof(changes));
            }
            IChangeSet <T> result;

            lock (_locker)
            {
                try
                {
                    _data.Clone(changes);
                    result = _data.CaptureChanges();
                }
                catch (Exception ex)
                {
                    return(new Continuation <IChangeSet <T> >(ex));
                }
            }
            return(new Continuation <IChangeSet <T> >(result));
        }
예제 #7
0
        private IChangeSet <T> ProcessImpl(ChangeAwareList <T> target, IChangeSet <T> changes)
        {
            if (_comparer == null)
            {
                target.Clone(changes);
                return(target.CaptureChanges());
            }

            foreach (var change in changes)
            {
                switch (change.Reason)
                {
                case ListChangeReason.Add:
                {
                    var current = change.Item.Current;
                    Insert(target, current);
                    break;
                }

                case ListChangeReason.AddRange:
                {
                    var ordered = change.Range.OrderBy(t => t, _comparer).ToList();
                    if (target.Count == 0)
                    {
                        target.AddRange(ordered);
                    }
                    else
                    {
                        ordered.ForEach(item => Insert(target, item));
                    }
                    break;
                }

                case ListChangeReason.Replace:
                {
                    var current = change.Item.Current;
                    //TODO: check whether an item should stay in the same position
                    //i.e. update and move
                    Remove(target, change.Item.Previous.Value);
                    Insert(target, current);
                    break;
                }

                case ListChangeReason.Remove:
                {
                    var current = change.Item.Current;
                    Remove(target, current);
                    break;
                }

                case ListChangeReason.RemoveRange:
                {
                    target.RemoveMany(change.Range);
                    break;
                }

                case ListChangeReason.Clear:
                {
                    target.Clear();
                    break;
                }
                }
            }
            return(target.CaptureChanges());
        }
예제 #8
0
        private IChangeSet <T> ProcessImpl(ChangeAwareList <T> target, IChangeSet <T> changes)
        {
            if (_comparer == null)
            {
                target.Clone(changes);
                return(target.CaptureChanges());
            }

            var refreshes = new List <T>(changes.Refreshes);

            foreach (var change in changes)
            {
                switch (change.Reason)
                {
                case ListChangeReason.Add:
                {
                    var current = change.Item.Current;
                    Insert(target, current);
                    break;
                }

                case ListChangeReason.AddRange:
                {
                    var ordered = change.Range.OrderBy(t => t, _comparer).ToList();
                    if (target.Count == 0)
                    {
                        target.AddRange(ordered);
                    }
                    else
                    {
                        ordered.ForEach(item => Insert(target, item));
                    }
                    break;
                }

                case ListChangeReason.Remove:
                {
                    var current = change.Item.Current;
                    Remove(target, current);
                    break;
                }

                case ListChangeReason.Refresh:
                {
                    //add to refresh list so position can be calculated
                    refreshes.Add(change.Item.Current);

                    //add to current list so downstream operators can receive a refresh
                    //notification, so get the latest index and pass the index up the chain
                    var indexed = target
                                  .IndexOfOptional(change.Item.Current)
                                  .ValueOrThrow(() => new SortException($"Cannot find index of {typeof(T).Name} -> {change.Item.Current}. Expected to be in the list"));

                    target.Refresh(indexed.Item, indexed.Index);
                    break;
                }

                case ListChangeReason.Replace:
                {
                    var current = change.Item.Current;
                    //TODO: check whether an item should stay in the same position
                    //i.e. update and move
                    Remove(target, change.Item.Previous.Value);
                    Insert(target, current);
                    break;
                }

                case ListChangeReason.RemoveRange:
                {
                    target.RemoveMany(change.Range);
                    break;
                }

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

            //Now deal with refreshes [can be expensive]
            foreach (var item in refreshes)
            {
                var old = target.IndexOf(item);
                if (old == -1)
                {
                    continue;
                }

                var newposition = GetInsertPositionLinear(target, item);
                if (old < newposition)
                {
                    newposition--;
                }

                if (old == newposition)
                {
                    continue;
                }

                target.Move(old, newposition);
            }
            return(target.CaptureChanges());
        }