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()); })); }
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); })); }
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); } )); }
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); }
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); }
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)); }
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()); }
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()); }