public static Progressor <T> CreateDistinct(Progressor <T> wrapped) { if (wrapped == null) { throw new ArgumentNullException("wrapped"); } var control = 0; SafeDictionary <T, bool> buffer = new SafeDictionary <T, bool>(); Predicate <T> newFilter = item => Thread.VolatileRead(ref control) == 0; var proxy = new ProxyObservable <T>(); Progressor <T> result = new Progressor <T>( (out T value) => { Interlocked.Increment(ref control); try { again: foreach (KeyValuePair <T, bool> item in buffer) { if (!item.Value) { value = item.Key; buffer.Set(value, true); proxy.OnNext(value); return(true); } } if (wrapped.TryTake(out value)) { bool seen; if (!buffer.TryGetValue(value, out seen) || !seen) { buffer.Set(value, true); proxy.OnNext(value); return(true); } else { goto again; } } else { return(false); } } finally { Interlocked.Decrement(ref control); } }, proxy ); wrapped.Subscribe ( new CustomObserver <T> ( () => result._done = true, exception => result._done = true, item => { if (newFilter(item)) { buffer.TryAdd(item, false); } } ) ); return(result); }
public static Progressor <T> CreatedFilteredConverted <TInput>(Progressor <TInput> wrapped, Predicate <TInput> filter, Converter <TInput, T> converter) { if (wrapped == null) { throw new ArgumentNullException("wrapped"); } if (filter == null) { throw new ArgumentNullException("filter"); } if (converter == null) { throw new ArgumentNullException("converter"); } var control = 0; Predicate <TInput> newFilter = item => Thread.VolatileRead(ref control) == 0 && filter(item); var buffer = new SafeQueue <T>(); var proxy = new ProxyObservable <T>(); var result = new Progressor <T>( (out T value) => { Interlocked.Increment(ref control); try { TInput item; again: if (buffer.TryTake(out value)) { proxy.OnNext(value); return(true); } else if (wrapped.TryTake(out item)) { if (filter(item)) { value = converter(item); proxy.OnNext(value); return(true); } else { goto again; } } value = default(T); return(false); } finally { Interlocked.Decrement(ref control); } }, proxy ); wrapped.Subscribe ( new CustomObserver <TInput> ( () => result._done = true, exception => result._done = true, item => { if (newFilter(item)) { buffer.Add(converter(item)); } } ) ); return(result); }