Dict, HashSet, Queue, RingBuffer, Stack

This commit is contained in:
neuecc 2024-08-27 18:36:01 +09:00
parent ce624265f3
commit 295cef5ae5
7 changed files with 418 additions and 248 deletions

View File

@ -9,7 +9,7 @@ namespace ObservableCollections
{ {
public sealed partial class ObservableDictionary<TKey, TValue> public sealed partial class ObservableDictionary<TKey, TValue>
{ {
public ISynchronizedView<KeyValuePair<TKey, TValue>, TView> CreateView<TView>(Func<KeyValuePair<TKey, TValue>, TView> transform, bool _ = false) public ISynchronizedView<KeyValuePair<TKey, TValue>, TView> CreateView<TView>(Func<KeyValuePair<TKey, TValue>, TView> transform)
{ {
// reverse is no used. // reverse is no used.
return new View<TView>(this, transform); return new View<TView>(this, transform);
@ -19,32 +19,45 @@ namespace ObservableCollections
{ {
readonly ObservableDictionary<TKey, TValue> source; readonly ObservableDictionary<TKey, TValue> source;
readonly Func<KeyValuePair<TKey, TValue>, TView> selector; readonly Func<KeyValuePair<TKey, TValue>, TView> selector;
ISynchronizedViewFilter<KeyValuePair<TKey, TValue>, TView> filter; ISynchronizedViewFilter<KeyValuePair<TKey, TValue>> filter;
readonly Dictionary<TKey, (TValue, TView)> dict; readonly Dictionary<TKey, (TValue, TView)> dict;
int filteredCount;
public View(ObservableDictionary<TKey, TValue> source, Func<KeyValuePair<TKey, TValue>, TView> selector) public View(ObservableDictionary<TKey, TValue> source, Func<KeyValuePair<TKey, TValue>, TView> selector)
{ {
this.source = source; this.source = source;
this.selector = selector; this.selector = selector;
this.filter = SynchronizedViewFilter<KeyValuePair<TKey, TValue>, TView>.Null; this.filter = SynchronizedViewFilter<KeyValuePair<TKey, TValue>>.Null;
this.SyncRoot = new object(); this.SyncRoot = new object();
lock (source.SyncRoot) lock (source.SyncRoot)
{ {
this.dict = source.dictionary.ToDictionary(x => x.Key, x => (x.Value, selector(x))); this.dict = source.dictionary.ToDictionary(x => x.Key, x => (x.Value, selector(x)));
this.filteredCount = dict.Count;
this.source.CollectionChanged += SourceCollectionChanged; this.source.CollectionChanged += SourceCollectionChanged;
} }
} }
public object SyncRoot { get; } public object SyncRoot { get; }
public event NotifyCollectionChangedEventHandler<KeyValuePair<TKey, TValue>>? RoutingCollectionChanged; public event Action<SynchronizedViewChangedEventArgs<KeyValuePair<TKey, TValue>, TView>>? ViewChanged;
public event Action<NotifyCollectionChangedAction>? CollectionStateChanged; public event Action<NotifyCollectionChangedAction>? CollectionStateChanged;
public ISynchronizedViewFilter<KeyValuePair<TKey, TValue>, TView> CurrentFilter public ISynchronizedViewFilter<KeyValuePair<TKey, TValue>> Filter
{ {
get { lock (SyncRoot) return filter; } get { lock (SyncRoot) return filter; }
} }
public int Count public int Count
{
get
{
lock (SyncRoot)
{
return filteredCount;
}
}
}
public int UnfilteredCount
{ {
get get
{ {
@ -60,76 +73,104 @@ namespace ObservableCollections
this.source.CollectionChanged -= SourceCollectionChanged; this.source.CollectionChanged -= SourceCollectionChanged;
} }
public void AttachFilter(ISynchronizedViewFilter<KeyValuePair<TKey, TValue>, TView> filter, bool invokeAddEventForCurrentElements = false) public void AttachFilter(ISynchronizedViewFilter<KeyValuePair<TKey, TValue>> filter)
{ {
if (filter.IsNullFilter())
{
ResetFilter();
return;
}
lock (SyncRoot) lock (SyncRoot)
{ {
this.filter = filter; this.filter = filter;
this.filteredCount = 0;
foreach (var v in dict) foreach (var v in dict)
{ {
var value = new KeyValuePair<TKey, TValue>(v.Key, v.Value.Item1); var value = new KeyValuePair<TKey, TValue>(v.Key, v.Value.Item1);
var view = v.Value.Item2; if (filter.IsMatch(value))
if (invokeAddEventForCurrentElements)
{ {
filter.InvokeOnAdd(value, view, -1); filteredCount++;
}
else
{
filter.InvokeOnAttach(value, view);
} }
} }
ViewChanged?.Invoke(new SynchronizedViewChangedEventArgs<KeyValuePair<TKey, TValue>, TView>(NotifyViewChangedAction.FilterReset));
} }
} }
public void ResetFilter(Action<KeyValuePair<TKey, TValue>, TView>? resetAction) public void ResetFilter()
{ {
lock (SyncRoot) lock (SyncRoot)
{ {
this.filter = SynchronizedViewFilter<KeyValuePair<TKey, TValue>, TView>.Null; this.filter = SynchronizedViewFilter<KeyValuePair<TKey, TValue>>.Null;
if (resetAction != null) this.filteredCount = dict.Count;
{ ViewChanged?.Invoke(new SynchronizedViewChangedEventArgs<KeyValuePair<TKey, TValue>, TView>(NotifyViewChangedAction.FilterReset));
foreach (var v in dict)
{
resetAction(new KeyValuePair<TKey, TValue>(v.Key, v.Value.Item1), v.Value.Item2);
}
}
} }
} }
public ISynchronizedViewList<TView> ToViewList()
{
return new SynchronizedViewList<KeyValuePair<TKey, TValue>, TView>(this);
}
public INotifyCollectionChangedSynchronizedView<TView> ToNotifyCollectionChanged() public INotifyCollectionChangedSynchronizedView<TView> ToNotifyCollectionChanged()
{ {
lock (SyncRoot) return new NotifyCollectionChangedSynchronizedView<KeyValuePair<TKey, TValue>, TView>(this, null);
{
return new NotifyCollectionChangedSynchronizedView<KeyValuePair<TKey, TValue>, TView>(this, null);
}
} }
public INotifyCollectionChangedSynchronizedView<TView> ToNotifyCollectionChanged(ICollectionEventDispatcher? collectionEventDispatcher) public INotifyCollectionChangedSynchronizedView<TView> ToNotifyCollectionChanged(ICollectionEventDispatcher? collectionEventDispatcher)
{ {
lock (SyncRoot) return new NotifyCollectionChangedSynchronizedView<KeyValuePair<TKey, TValue>, TView>(this, collectionEventDispatcher);
{
return new NotifyCollectionChangedSynchronizedView<KeyValuePair<TKey, TValue>, TView>(this, collectionEventDispatcher);
}
} }
public IEnumerator<(KeyValuePair<TKey, TValue>, TView)> GetEnumerator() public IEnumerator<TView> GetEnumerator()
{ {
lock (SyncRoot) lock (SyncRoot)
{ {
foreach (var item in dict) foreach (var item in dict)
{ {
var v = (new KeyValuePair<TKey, TValue>(item.Key, item.Value.Item1), item.Value.Item2); var v = (new KeyValuePair<TKey, TValue>(item.Key, item.Value.Item1), item.Value.Item2);
if (filter.IsMatch(v.Item1, v.Item2)) if (filter.IsMatch(v.Item1))
{ {
yield return v; yield return v.Item2;
} }
} }
} }
} }
IEnumerator IEnumerable.GetEnumerator() IEnumerator IEnumerable.GetEnumerator() => GetEnumerator();
public IEnumerable<(KeyValuePair<TKey, TValue> Value, TView View)> Filtered
{ {
return GetEnumerator(); get
{
lock (SyncRoot)
{
foreach (var item in dict)
{
var v = (new KeyValuePair<TKey, TValue>(item.Key, item.Value.Item1), item.Value.Item2);
if (filter.IsMatch(v.Item1))
{
yield return v;
}
}
}
}
}
public IEnumerable<(KeyValuePair<TKey, TValue> Value, TView View)> Unfiltered
{
get
{
lock (SyncRoot)
{
foreach (var item in dict)
{
var v = (new KeyValuePair<TKey, TValue>(item.Key, item.Value.Item1), item.Value.Item2);
yield return v;
}
}
}
} }
private void SourceCollectionChanged(in NotifyCollectionChangedEventArgs<KeyValuePair<TKey, TValue>> e) private void SourceCollectionChanged(in NotifyCollectionChangedEventArgs<KeyValuePair<TKey, TValue>> e)
@ -140,41 +181,40 @@ namespace ObservableCollections
switch (e.Action) switch (e.Action)
{ {
case NotifyCollectionChangedAction.Add: case NotifyCollectionChangedAction.Add:
{ {
var v = selector(e.NewItem); var v = selector(e.NewItem);
dict.Add(e.NewItem.Key, (e.NewItem.Value, v)); dict.Add(e.NewItem.Key, (e.NewItem.Value, v));
filter.InvokeOnAdd(e.NewItem, v, -1); this.InvokeOnAdd(ref filteredCount, ViewChanged, e.NewItem, v, -1);
} }
break; break;
case NotifyCollectionChangedAction.Remove: case NotifyCollectionChangedAction.Remove:
{
if (dict.Remove(e.OldItem.Key, out var v))
{ {
filter.InvokeOnRemove(e.OldItem, v.Item2, -1); if (dict.Remove(e.OldItem.Key, out var v))
{
this.InvokeOnRemove(ref filteredCount, ViewChanged, e.OldItem, v.Item2, -1);
}
} }
}
break; break;
case NotifyCollectionChangedAction.Replace: case NotifyCollectionChangedAction.Replace:
{ {
var v = selector(e.NewItem); var v = selector(e.NewItem);
dict.Remove(e.OldItem.Key, out var ov); dict.Remove(e.OldItem.Key, out var ov);
dict[e.NewItem.Key] = (e.NewItem.Value, v); dict[e.NewItem.Key] = (e.NewItem.Value, v);
filter.InvokeOnReplace(e.NewItem, v, e.OldItem, ov.Item2, -1); this.InvokeOnReplace(ref filteredCount, ViewChanged, e.NewItem, v, e.OldItem, ov.Item2, -1);
} }
break; break;
case NotifyCollectionChangedAction.Reset: case NotifyCollectionChangedAction.Reset:
{ {
dict.Clear(); dict.Clear();
filter.InvokeOnReset(); this.InvokeOnReset(ref filteredCount, ViewChanged);
} }
break; break;
case NotifyCollectionChangedAction.Move: // ObservableDictionary have no Move operation. case NotifyCollectionChangedAction.Move: // ObservableDictionary have no Move operation.
default: default:
break; break;
} }
RoutingCollectionChanged?.Invoke(e);
CollectionStateChanged?.Invoke(e.Action); CollectionStateChanged?.Invoke(e.Action);
} }
} }

View File

@ -7,8 +7,7 @@ using System.Linq;
namespace ObservableCollections namespace ObservableCollections
{ {
public sealed partial class ObservableDictionary<TKey, TValue> : IDictionary<TKey, TValue>, public sealed partial class ObservableDictionary<TKey, TValue> : IDictionary<TKey, TValue>, IReadOnlyObservableDictionary<TKey, TValue>
IReadOnlyObservableDictionary<TKey, TValue>
where TKey : notnull where TKey : notnull
{ {
readonly Dictionary<TKey, TValue> dictionary; readonly Dictionary<TKey, TValue> dictionary;

View File

@ -4,19 +4,20 @@ using System.Collections.Generic;
using System.Collections.Specialized; using System.Collections.Specialized;
using System; using System;
using System.Linq; using System.Linq;
using System.Threading.Tasks;
namespace ObservableCollections namespace ObservableCollections
{ {
public sealed partial class ObservableHashSet<T> : IReadOnlyCollection<T>, IObservableCollection<T> public sealed partial class ObservableHashSet<T> : IReadOnlyCollection<T>, IObservableCollection<T>
{ {
public ISynchronizedView<T, TView> CreateView<TView>(Func<T, TView> transform, bool _ = false) public ISynchronizedView<T, TView> CreateView<TView>(Func<T, TView> transform)
{ {
return new View<TView>(this, transform); return new View<TView>(this, transform);
} }
sealed class View<TView> : ISynchronizedView<T, TView> sealed class View<TView> : ISynchronizedView<T, TView>
{ {
public ISynchronizedViewFilter<T, TView> CurrentFilter public ISynchronizedViewFilter<T> Filter
{ {
get { lock (SyncRoot) return filter; } get { lock (SyncRoot) return filter; }
} }
@ -24,10 +25,11 @@ namespace ObservableCollections
readonly ObservableHashSet<T> source; readonly ObservableHashSet<T> source;
readonly Func<T, TView> selector; readonly Func<T, TView> selector;
readonly Dictionary<T, (T, TView)> dict; readonly Dictionary<T, (T, TView)> dict;
int filteredCount;
ISynchronizedViewFilter<T, TView> filter; ISynchronizedViewFilter<T> filter;
public event NotifyCollectionChangedEventHandler<T>? RoutingCollectionChanged; public event Action<SynchronizedViewChangedEventArgs<T, TView>>? ViewChanged;
public event Action<NotifyCollectionChangedAction>? CollectionStateChanged; public event Action<NotifyCollectionChangedAction>? CollectionStateChanged;
public object SyncRoot { get; } public object SyncRoot { get; }
@ -36,16 +38,28 @@ namespace ObservableCollections
{ {
this.source = source; this.source = source;
this.selector = selector; this.selector = selector;
this.filter = SynchronizedViewFilter<T, TView>.Null; this.filter = SynchronizedViewFilter<T>.Null;
this.SyncRoot = new object(); this.SyncRoot = new object();
lock (source.SyncRoot) lock (source.SyncRoot)
{ {
this.dict = source.set.ToDictionary(x => x, x => (x, selector(x))); this.dict = source.set.ToDictionary(x => x, x => (x, selector(x)));
this.filteredCount = dict.Count;
this.source.CollectionChanged += SourceCollectionChanged; this.source.CollectionChanged += SourceCollectionChanged;
} }
} }
public int Count public int Count
{
get
{
lock (SyncRoot)
{
return filteredCount;
}
}
}
public int UnfilteredCount
{ {
get get
{ {
@ -56,65 +70,62 @@ namespace ObservableCollections
} }
} }
public void AttachFilter(ISynchronizedViewFilter<T, TView> filter, bool invokeAddEventForCurrentElements = false) public void AttachFilter(ISynchronizedViewFilter<T> filter)
{ {
if (filter.IsNullFilter())
{
ResetFilter();
return;
}
lock (SyncRoot) lock (SyncRoot)
{ {
this.filter = filter; this.filter = filter;
this.filteredCount = 0;
foreach (var (_, (value, view)) in dict) foreach (var (_, (value, view)) in dict)
{ {
if (invokeAddEventForCurrentElements) if (filter.IsMatch(value))
{ {
filter.InvokeOnAdd((value, view), -1); filteredCount++;
}
else
{
filter.InvokeOnAttach(value, view);
} }
} }
} }
} }
public void ResetFilter(Action<T, TView>? resetAction) public void ResetFilter()
{ {
lock (SyncRoot) lock (SyncRoot)
{ {
this.filter = SynchronizedViewFilter<T, TView>.Null; this.filter = SynchronizedViewFilter<T>.Null;
if (resetAction != null) this.filteredCount = dict.Count;
{ ViewChanged?.Invoke(new SynchronizedViewChangedEventArgs<T, TView>(NotifyViewChangedAction.FilterReset));
foreach (var (_, (value, view)) in dict)
{
resetAction(value, view);
}
}
} }
} }
public ISynchronizedViewList<TView> ToViewList()
{
return new SynchronizedViewList<T, TView>(this);
}
public INotifyCollectionChangedSynchronizedView<TView> ToNotifyCollectionChanged() public INotifyCollectionChangedSynchronizedView<TView> ToNotifyCollectionChanged()
{ {
lock (SyncRoot) return new NotifyCollectionChangedSynchronizedView<T, TView>(this, null);
{
return new NotifyCollectionChangedSynchronizedView<T, TView>(this, null);
}
} }
public INotifyCollectionChangedSynchronizedView<TView> ToNotifyCollectionChanged(ICollectionEventDispatcher? collectionEventDispatcher) public INotifyCollectionChangedSynchronizedView<TView> ToNotifyCollectionChanged(ICollectionEventDispatcher? collectionEventDispatcher)
{ {
lock (SyncRoot) return new NotifyCollectionChangedSynchronizedView<T, TView>(this, collectionEventDispatcher);
{
return new NotifyCollectionChangedSynchronizedView<T, TView>(this, collectionEventDispatcher);
}
} }
public IEnumerator<(T, TView)> GetEnumerator() public IEnumerator<TView> GetEnumerator()
{ {
lock (SyncRoot) lock (SyncRoot)
{ {
foreach (var item in dict) foreach (var item in dict)
{ {
if (filter.IsMatch(item.Value.Item1, item.Value.Item2)) if (filter.IsMatch(item.Value.Item1))
{ {
yield return item.Value; yield return item.Value.Item2;
} }
} }
} }
@ -122,6 +133,37 @@ namespace ObservableCollections
IEnumerator IEnumerable.GetEnumerator() => GetEnumerator(); IEnumerator IEnumerable.GetEnumerator() => GetEnumerator();
public IEnumerable<(T Value, TView View)> Filtered
{
get
{
lock (SyncRoot)
{
foreach (var item in dict)
{
if (filter.IsMatch(item.Value.Item1))
{
yield return item.Value;
}
}
}
}
}
public IEnumerable<(T Value, TView View)> Unfiltered
{
get
{
lock (SyncRoot)
{
foreach (var item in dict)
{
yield return item.Value;
}
}
}
}
public void Dispose() public void Dispose()
{ {
this.source.CollectionChanged -= SourceCollectionChanged; this.source.CollectionChanged -= SourceCollectionChanged;
@ -138,7 +180,7 @@ namespace ObservableCollections
{ {
var v = (e.NewItem, selector(e.NewItem)); var v = (e.NewItem, selector(e.NewItem));
dict.Add(e.NewItem, v); dict.Add(e.NewItem, v);
filter.InvokeOnAdd(v, -1); this.InvokeOnAdd(ref filteredCount, ViewChanged, v, -1);
} }
else else
{ {
@ -147,7 +189,7 @@ namespace ObservableCollections
{ {
var v = (item, selector(item)); var v = (item, selector(item));
dict.Add(item, v); dict.Add(item, v);
filter.InvokeOnAdd(v, i++); this.InvokeOnAdd(ref filteredCount, ViewChanged, v, i++);
} }
} }
break; break;
@ -156,7 +198,7 @@ namespace ObservableCollections
{ {
if (dict.Remove(e.OldItem, out var value)) if (dict.Remove(e.OldItem, out var value))
{ {
filter.InvokeOnRemove(value, -1); this.InvokeOnRemove(ref filteredCount, ViewChanged, value, -1);
} }
} }
else else
@ -165,14 +207,14 @@ namespace ObservableCollections
{ {
if (dict.Remove(item, out var value)) if (dict.Remove(item, out var value))
{ {
filter.InvokeOnRemove(value, -1); this.InvokeOnRemove(ref filteredCount, ViewChanged, value, -1);
} }
} }
} }
break; break;
case NotifyCollectionChangedAction.Reset: case NotifyCollectionChangedAction.Reset:
dict.Clear(); dict.Clear();
filter.InvokeOnReset(); this.InvokeOnReset(ref filteredCount, ViewChanged);
break; break;
case NotifyCollectionChangedAction.Replace: case NotifyCollectionChangedAction.Replace:
case NotifyCollectionChangedAction.Move: case NotifyCollectionChangedAction.Move:
@ -180,7 +222,6 @@ namespace ObservableCollections
break; break;
} }
RoutingCollectionChanged?.Invoke(e);
CollectionStateChanged?.Invoke(e.Action); CollectionStateChanged?.Invoke(e.Action);
} }
} }

View File

@ -98,7 +98,6 @@ namespace ObservableCollections
lock (SyncRoot) lock (SyncRoot)
{ {
this.filter = filter; this.filter = filter;
this.filteredCount = 0; this.filteredCount = 0;
for (var i = 0; i < list.Count; i++) for (var i = 0; i < list.Count; i++)
{ {

View File

@ -4,14 +4,15 @@ using System.Collections.Specialized;
using System; using System;
using System.Collections.Generic; using System.Collections.Generic;
using System.Linq; using System.Linq;
using System.Threading.Tasks;
namespace ObservableCollections namespace ObservableCollections
{ {
public sealed partial class ObservableQueue<T> : IReadOnlyCollection<T>, IObservableCollection<T> public sealed partial class ObservableQueue<T> : IReadOnlyCollection<T>, IObservableCollection<T>
{ {
public ISynchronizedView<T, TView> CreateView<TView>(Func<T, TView> transform, bool reverse = false) public ISynchronizedView<T, TView> CreateView<TView>(Func<T, TView> transform)
{ {
return new View<TView>(this, transform, reverse); return new View<TView>(this, transform);
} }
class View<TView> : ISynchronizedView<T, TView> class View<TView> : ISynchronizedView<T, TView>
@ -20,34 +21,46 @@ namespace ObservableCollections
readonly Func<T, TView> selector; readonly Func<T, TView> selector;
readonly bool reverse; readonly bool reverse;
protected readonly Queue<(T, TView)> queue; protected readonly Queue<(T, TView)> queue;
int filteredCount;
ISynchronizedViewFilter<T, TView> filter; ISynchronizedViewFilter<T> filter;
public event NotifyCollectionChangedEventHandler<T>? RoutingCollectionChanged; public event Action<SynchronizedViewChangedEventArgs<T, TView>>? ViewChanged;
public event Action<NotifyCollectionChangedAction>? CollectionStateChanged; public event Action<NotifyCollectionChangedAction>? CollectionStateChanged;
public object SyncRoot { get; } public object SyncRoot { get; }
public ISynchronizedViewFilter<T, TView> CurrentFilter public ISynchronizedViewFilter<T> Filter
{ {
get { lock (SyncRoot) return filter; } get { lock (SyncRoot) return filter; }
} }
public View(ObservableQueue<T> source, Func<T, TView> selector, bool reverse) public View(ObservableQueue<T> source, Func<T, TView> selector)
{ {
this.source = source; this.source = source;
this.selector = selector; this.selector = selector;
this.reverse = reverse; this.filter = SynchronizedViewFilter<T>.Null;
this.filter = SynchronizedViewFilter<T, TView>.Null;
this.SyncRoot = new object(); this.SyncRoot = new object();
lock (source.SyncRoot) lock (source.SyncRoot)
{ {
this.queue = new Queue<(T, TView)>(source.queue.Select(x => (x, selector(x)))); this.queue = new Queue<(T, TView)>(source.queue.Select(x => (x, selector(x))));
this.filteredCount = queue.Count;
this.source.CollectionChanged += SourceCollectionChanged; this.source.CollectionChanged += SourceCollectionChanged;
} }
} }
public int Count public int Count
{
get
{
lock (SyncRoot)
{
return filteredCount;
}
}
}
public int UnfilteredCount
{ {
get get
{ {
@ -58,79 +71,63 @@ namespace ObservableCollections
} }
} }
public void AttachFilter(ISynchronizedViewFilter<T, TView> filter, bool invokeAddEventForCurrentElements = false) public void AttachFilter(ISynchronizedViewFilter<T> filter)
{ {
if (filter.IsNullFilter())
{
ResetFilter();
return;
}
lock (SyncRoot) lock (SyncRoot)
{ {
this.filter = filter; this.filter = filter;
var i = 0; this.filteredCount = 0;
foreach (var (value, view) in queue) foreach (var (value, view) in queue)
{ {
if (invokeAddEventForCurrentElements) if (filter.IsMatch(value))
{ {
filter.InvokeOnAdd(value, view, i++); filteredCount++;
}
else
{
filter.InvokeOnAttach(value, view);
} }
} }
ViewChanged?.Invoke(new SynchronizedViewChangedEventArgs<T, TView>(NotifyViewChangedAction.FilterReset));
} }
} }
public void ResetFilter(Action<T, TView>? resetAction) public void ResetFilter()
{ {
lock (SyncRoot) lock (SyncRoot)
{ {
this.filter = SynchronizedViewFilter<T, TView>.Null; this.filter = SynchronizedViewFilter<T>.Null;
if (resetAction != null) this.filteredCount = queue.Count;
{ ViewChanged?.Invoke(new SynchronizedViewChangedEventArgs<T, TView>(NotifyViewChangedAction.FilterReset));
foreach (var (item, view) in queue)
{
resetAction(item, view);
}
}
} }
} }
public ISynchronizedViewList<TView> ToViewList()
{
return new SynchronizedViewList<T, TView>(this);
}
public INotifyCollectionChangedSynchronizedView<TView> ToNotifyCollectionChanged() public INotifyCollectionChangedSynchronizedView<TView> ToNotifyCollectionChanged()
{ {
lock (SyncRoot) return new NotifyCollectionChangedSynchronizedView<T, TView>(this, null);
{
return new NotifyCollectionChangedSynchronizedView<T, TView>(this, null);
}
} }
public INotifyCollectionChangedSynchronizedView<TView> ToNotifyCollectionChanged(ICollectionEventDispatcher? collectionEventDispatcher) public INotifyCollectionChangedSynchronizedView<TView> ToNotifyCollectionChanged(ICollectionEventDispatcher? collectionEventDispatcher)
{ {
lock (SyncRoot) return new NotifyCollectionChangedSynchronizedView<T, TView>(this, collectionEventDispatcher);
{
return new NotifyCollectionChangedSynchronizedView<T, TView>(this, collectionEventDispatcher);
}
} }
public IEnumerator<(T, TView)> GetEnumerator() public IEnumerator<TView> GetEnumerator()
{ {
lock (SyncRoot) lock (SyncRoot)
{ {
if (!reverse) foreach (var item in queue)
{ {
foreach (var item in queue) if (filter.IsMatch(item.Item1))
{ {
if (filter.IsMatch(item.Item1, item.Item2)) yield return item.Item2;
{
yield return item;
}
}
}
else
{
foreach (var item in queue.AsEnumerable().Reverse())
{
if (filter.IsMatch(item.Item1, item.Item2))
{
yield return item;
}
} }
} }
} }
@ -138,6 +135,37 @@ namespace ObservableCollections
IEnumerator IEnumerable.GetEnumerator() => GetEnumerator(); IEnumerator IEnumerable.GetEnumerator() => GetEnumerator();
public IEnumerable<(T Value, TView View)> Filtered
{
get
{
lock (SyncRoot)
{
foreach (var item in queue)
{
if (filter.IsMatch(item.Item1))
{
yield return item;
}
}
}
}
}
public IEnumerable<(T Value, TView View)> Unfiltered
{
get
{
lock (SyncRoot)
{
foreach (var item in queue)
{
yield return item;
}
}
}
}
public void Dispose() public void Dispose()
{ {
this.source.CollectionChanged -= SourceCollectionChanged; this.source.CollectionChanged -= SourceCollectionChanged;
@ -155,7 +183,7 @@ namespace ObservableCollections
{ {
var v = (e.NewItem, selector(e.NewItem)); var v = (e.NewItem, selector(e.NewItem));
queue.Enqueue(v); queue.Enqueue(v);
filter.InvokeOnAdd(v, e.NewStartingIndex); this.InvokeOnAdd(ref filteredCount, ViewChanged, v, e.NewStartingIndex);
} }
else else
{ {
@ -164,7 +192,7 @@ namespace ObservableCollections
{ {
var v = (item, selector(item)); var v = (item, selector(item));
queue.Enqueue(v); queue.Enqueue(v);
filter.InvokeOnAdd(v, i++); this.InvokeOnAdd(ref filteredCount, ViewChanged, v, i++);
} }
} }
break; break;
@ -173,7 +201,7 @@ namespace ObservableCollections
if (e.IsSingleItem) if (e.IsSingleItem)
{ {
var v = queue.Dequeue(); var v = queue.Dequeue();
filter.InvokeOnRemove(v.Item1, v.Item2, 0); this.InvokeOnRemove(ref filteredCount, ViewChanged, v.Item1, v.Item2, 0);
} }
else else
{ {
@ -181,13 +209,13 @@ namespace ObservableCollections
for (int i = 0; i < len; i++) for (int i = 0; i < len; i++)
{ {
var v = queue.Dequeue(); var v = queue.Dequeue();
filter.InvokeOnRemove(v.Item1, v.Item2, 0); this.InvokeOnRemove(ref filteredCount, ViewChanged, v.Item1, v.Item2, 0);
} }
} }
break; break;
case NotifyCollectionChangedAction.Reset: case NotifyCollectionChangedAction.Reset:
queue.Clear(); queue.Clear();
filter.InvokeOnReset(); this.InvokeOnReset(ref filteredCount, ViewChanged);
break; break;
case NotifyCollectionChangedAction.Replace: case NotifyCollectionChangedAction.Replace:
case NotifyCollectionChangedAction.Move: case NotifyCollectionChangedAction.Move:
@ -195,7 +223,6 @@ namespace ObservableCollections
break; break;
} }
RoutingCollectionChanged?.Invoke(e);
CollectionStateChanged?.Invoke(e.Action); CollectionStateChanged?.Invoke(e.Action);
} }
} }

View File

@ -4,51 +4,63 @@ using System.Collections;
using System.Collections.Generic; using System.Collections.Generic;
using System.Collections.Specialized; using System.Collections.Specialized;
using System.Linq; using System.Linq;
using System.Threading.Tasks;
namespace ObservableCollections namespace ObservableCollections
{ {
public sealed partial class ObservableRingBuffer<T> public sealed partial class ObservableRingBuffer<T>
{ {
public ISynchronizedView<T, TView> CreateView<TView>(Func<T, TView> transform, bool reverse = false) public ISynchronizedView<T, TView> CreateView<TView>(Func<T, TView> transform)
{ {
return new View<TView>(this, transform, reverse); return new View<TView>(this, transform);
} }
// used with ObservableFixedSizeRingBuffer // used with ObservableFixedSizeRingBuffer
internal sealed class View<TView> : ISynchronizedView<T, TView> internal sealed class View<TView> : ISynchronizedView<T, TView>
{ {
public ISynchronizedViewFilter<T, TView> CurrentFilter public ISynchronizedViewFilter<T> Filter
{ {
get { lock (SyncRoot) return filter; } get { lock (SyncRoot) return filter; }
} }
readonly IObservableCollection<T> source; readonly IObservableCollection<T> source;
readonly Func<T, TView> selector; readonly Func<T, TView> selector;
readonly bool reverse;
readonly RingBuffer<(T, TView)> ringBuffer; readonly RingBuffer<(T, TView)> ringBuffer;
int filteredCount;
ISynchronizedViewFilter<T, TView> filter; ISynchronizedViewFilter<T> filter;
public event NotifyCollectionChangedEventHandler<T>? RoutingCollectionChanged; public event Action<SynchronizedViewChangedEventArgs<T, TView>>? ViewChanged;
public event Action<NotifyCollectionChangedAction>? CollectionStateChanged; public event Action<NotifyCollectionChangedAction>? CollectionStateChanged;
public object SyncRoot { get; } public object SyncRoot { get; }
public View(IObservableCollection<T> source, Func<T, TView> selector, bool reverse) public View(IObservableCollection<T> source, Func<T, TView> selector)
{ {
this.source = source; this.source = source;
this.selector = selector; this.selector = selector;
this.reverse = reverse; this.filter = SynchronizedViewFilter<T>.Null;
this.filter = SynchronizedViewFilter<T, TView>.Null;
this.SyncRoot = new object(); this.SyncRoot = new object();
lock (source.SyncRoot) lock (source.SyncRoot)
{ {
this.ringBuffer = new RingBuffer<(T, TView)>(source.Select(x => (x, selector(x)))); this.ringBuffer = new RingBuffer<(T, TView)>(source.Select(x => (x, selector(x))));
this.filteredCount = ringBuffer.Count;
this.source.CollectionChanged += SourceCollectionChanged; this.source.CollectionChanged += SourceCollectionChanged;
} }
} }
public int Count public int Count
{
get
{
lock (SyncRoot)
{
return filteredCount;
}
}
}
public int UnfilteredCount
{ {
get get
{ {
@ -59,41 +71,44 @@ namespace ObservableCollections
} }
} }
public void AttachFilter(ISynchronizedViewFilter<T, TView> filter, bool invokeAddEventForCurrentElements = false) public void AttachFilter(ISynchronizedViewFilter<T> filter)
{ {
if (filter.IsNullFilter())
{
ResetFilter();
return;
}
lock (SyncRoot) lock (SyncRoot)
{ {
this.filter = filter; this.filter = filter;
this.filteredCount = 0;
for (var i = 0; i < ringBuffer.Count; i++) for (var i = 0; i < ringBuffer.Count; i++)
{ {
var (value, view) = ringBuffer[i]; var (value, view) = ringBuffer[i];
if (invokeAddEventForCurrentElements) if (filter.IsMatch(value))
{ {
filter.InvokeOnAdd(value, view, i); filteredCount++;
}
else
{
filter.InvokeOnAttach(value, view);
} }
} }
} }
} }
public void ResetFilter(Action<T, TView>? resetAction) public void ResetFilter()
{ {
lock (SyncRoot) lock (SyncRoot)
{ {
this.filter = SynchronizedViewFilter<T, TView>.Null; this.filter = SynchronizedViewFilter<T>.Null;
if (resetAction != null) this.filteredCount = ringBuffer.Count;
{ ViewChanged?.Invoke(new SynchronizedViewChangedEventArgs<T, TView>(NotifyViewChangedAction.FilterReset));
foreach (var (item, view) in ringBuffer)
{
resetAction(item, view);
}
}
} }
} }
public ISynchronizedViewList<TView> ToViewList()
{
return new SynchronizedViewList<T, TView>(this);
}
public INotifyCollectionChangedSynchronizedView<TView> ToNotifyCollectionChanged() public INotifyCollectionChangedSynchronizedView<TView> ToNotifyCollectionChanged()
{ {
lock (SyncRoot) lock (SyncRoot)
@ -110,25 +125,31 @@ namespace ObservableCollections
} }
} }
public IEnumerator<(T, TView)> GetEnumerator() public IEnumerator<TView> GetEnumerator()
{ {
lock (SyncRoot) lock (SyncRoot)
{ {
if (!reverse) foreach (var item in ringBuffer)
{
if (filter.IsMatch(item.Item1))
{
yield return item.Item2;
}
}
}
}
IEnumerator IEnumerable.GetEnumerator() => GetEnumerator();
public IEnumerable<(T Value, TView View)> Filtered
{
get
{
lock (SyncRoot)
{ {
foreach (var item in ringBuffer) foreach (var item in ringBuffer)
{ {
if (filter.IsMatch(item.Item1, item.Item2)) if (filter.IsMatch(item.Item1))
{
yield return item;
}
}
}
else
{
foreach (var item in ringBuffer.AsEnumerable().Reverse())
{
if (filter.IsMatch(item.Item1, item.Item2))
{ {
yield return item; yield return item;
} }
@ -137,7 +158,19 @@ namespace ObservableCollections
} }
} }
IEnumerator IEnumerable.GetEnumerator() => GetEnumerator(); public IEnumerable<(T Value, TView View)> Unfiltered
{
get
{
lock (SyncRoot)
{
foreach (var item in ringBuffer)
{
yield return item;
}
}
}
}
public void Dispose() public void Dispose()
{ {
@ -162,7 +195,7 @@ namespace ObservableCollections
{ {
var v = (e.NewItem, selector(e.NewItem)); var v = (e.NewItem, selector(e.NewItem));
ringBuffer.AddFirst(v); ringBuffer.AddFirst(v);
filter.InvokeOnAdd(v, 0); this.InvokeOnAdd(ref filteredCount, ViewChanged, v, 0);
} }
else else
{ {
@ -170,7 +203,7 @@ namespace ObservableCollections
{ {
var v = (item, selector(item)); var v = (item, selector(item));
ringBuffer.AddFirst(v); ringBuffer.AddFirst(v);
filter.InvokeOnAdd(v, 0); this.InvokeOnAdd(ref filteredCount, ViewChanged, v, 0);
} }
} }
} }
@ -181,7 +214,7 @@ namespace ObservableCollections
{ {
var v = (e.NewItem, selector(e.NewItem)); var v = (e.NewItem, selector(e.NewItem));
ringBuffer.AddLast(v); ringBuffer.AddLast(v);
filter.InvokeOnAdd(v, ringBuffer.Count - 1); this.InvokeOnAdd(ref filteredCount, ViewChanged, v, ringBuffer.Count - 1);
} }
else else
{ {
@ -189,7 +222,7 @@ namespace ObservableCollections
{ {
var v = (item, selector(item)); var v = (item, selector(item));
ringBuffer.AddLast(v); ringBuffer.AddLast(v);
filter.InvokeOnAdd(v, ringBuffer.Count - 1); this.InvokeOnAdd(ref filteredCount, ViewChanged, v, ringBuffer.Count - 1);
} }
} }
} }
@ -202,14 +235,14 @@ namespace ObservableCollections
if (e.IsSingleItem) if (e.IsSingleItem)
{ {
var v = ringBuffer.RemoveFirst(); var v = ringBuffer.RemoveFirst();
filter.InvokeOnRemove(v, 0); this.InvokeOnRemove(ref filteredCount, ViewChanged, v, 0);
} }
else else
{ {
for (int i = 0; i < e.OldItems.Length; i++) for (int i = 0; i < e.OldItems.Length; i++)
{ {
var v = ringBuffer.RemoveFirst(); var v = ringBuffer.RemoveFirst();
filter.InvokeOnRemove(v, 0); this.InvokeOnRemove(ref filteredCount, ViewChanged, v, 0);
} }
} }
} }
@ -220,7 +253,7 @@ namespace ObservableCollections
{ {
var index = ringBuffer.Count - 1; var index = ringBuffer.Count - 1;
var v = ringBuffer.RemoveLast(); var v = ringBuffer.RemoveLast();
filter.InvokeOnRemove(v, index); this.InvokeOnRemove(ref filteredCount, ViewChanged, v, index);
} }
else else
{ {
@ -228,14 +261,14 @@ namespace ObservableCollections
{ {
var index = ringBuffer.Count - 1; var index = ringBuffer.Count - 1;
var v = ringBuffer.RemoveLast(); var v = ringBuffer.RemoveLast();
filter.InvokeOnRemove(v, index); this.InvokeOnRemove(ref filteredCount, ViewChanged, v, index);
} }
} }
} }
break; break;
case NotifyCollectionChangedAction.Reset: case NotifyCollectionChangedAction.Reset:
ringBuffer.Clear(); ringBuffer.Clear();
filter.InvokeOnReset(); this.InvokeOnReset(ref filteredCount, ViewChanged);
break; break;
case NotifyCollectionChangedAction.Replace: case NotifyCollectionChangedAction.Replace:
// range is not supported // range is not supported
@ -243,7 +276,7 @@ namespace ObservableCollections
var ov = ringBuffer[e.OldStartingIndex]; var ov = ringBuffer[e.OldStartingIndex];
var v = (e.NewItem, selector(e.NewItem)); var v = (e.NewItem, selector(e.NewItem));
ringBuffer[e.NewStartingIndex] = v; ringBuffer[e.NewStartingIndex] = v;
filter.InvokeOnReplace(v, ov, e.NewStartingIndex); this.InvokeOnReplace(ref filteredCount, ViewChanged, v, ov, e.NewStartingIndex);
break; break;
} }
case NotifyCollectionChangedAction.Move: case NotifyCollectionChangedAction.Move:
@ -251,7 +284,6 @@ namespace ObservableCollections
break; break;
} }
RoutingCollectionChanged?.Invoke(e);
CollectionStateChanged?.Invoke(e.Action); CollectionStateChanged?.Invoke(e.Action);
} }
} }

View File

@ -9,45 +9,56 @@ namespace ObservableCollections
{ {
public sealed partial class ObservableStack<T> : IReadOnlyCollection<T>, IObservableCollection<T> public sealed partial class ObservableStack<T> : IReadOnlyCollection<T>, IObservableCollection<T>
{ {
public ISynchronizedView<T, TView> CreateView<TView>(Func<T, TView> transform, bool reverse = false) public ISynchronizedView<T, TView> CreateView<TView>(Func<T, TView> transform)
{ {
return new View<TView>(this, transform, reverse); return new View<TView>(this, transform);
} }
class View<TView> : ISynchronizedView<T, TView> class View<TView> : ISynchronizedView<T, TView>
{ {
readonly ObservableStack<T> source; readonly ObservableStack<T> source;
readonly Func<T, TView> selector; readonly Func<T, TView> selector;
readonly bool reverse;
protected readonly Stack<(T, TView)> stack; protected readonly Stack<(T, TView)> stack;
int filteredCount;
ISynchronizedViewFilter<T, TView> filter; ISynchronizedViewFilter<T> filter;
public event NotifyCollectionChangedEventHandler<T>? RoutingCollectionChanged; public event Action<SynchronizedViewChangedEventArgs<T, TView>>? ViewChanged;
public event Action<NotifyCollectionChangedAction>? CollectionStateChanged; public event Action<NotifyCollectionChangedAction>? CollectionStateChanged;
public object SyncRoot { get; } public object SyncRoot { get; }
public ISynchronizedViewFilter<T, TView> CurrentFilter public ISynchronizedViewFilter<T> Filter
{ {
get { lock (SyncRoot) return filter; } get { lock (SyncRoot) return filter; }
} }
public View(ObservableStack<T> source, Func<T, TView> selector, bool reverse) public View(ObservableStack<T> source, Func<T, TView> selector)
{ {
this.source = source; this.source = source;
this.selector = selector; this.selector = selector;
this.reverse = reverse; this.filter = SynchronizedViewFilter<T>.Null;
this.filter = SynchronizedViewFilter<T, TView>.Null;
this.SyncRoot = new object(); this.SyncRoot = new object();
lock (source.SyncRoot) lock (source.SyncRoot)
{ {
this.stack = new Stack<(T, TView)>(source.stack.Select(x => (x, selector(x)))); this.stack = new Stack<(T, TView)>(source.stack.Select(x => (x, selector(x))));
this.filteredCount = stack.Count;
this.source.CollectionChanged += SourceCollectionChanged; this.source.CollectionChanged += SourceCollectionChanged;
} }
} }
public int Count public int Count
{
get
{
lock (SyncRoot)
{
return filteredCount;
}
}
}
public int UnfilteredCount
{ {
get get
{ {
@ -58,40 +69,44 @@ namespace ObservableCollections
} }
} }
public void AttachFilter(ISynchronizedViewFilter<T, TView> filter, bool invokeAddEventForCurrentElements = false) public void AttachFilter(ISynchronizedViewFilter<T> filter)
{ {
if (filter.IsNullFilter())
{
ResetFilter();
return;
}
lock (SyncRoot) lock (SyncRoot)
{ {
this.filter = filter; this.filter = filter;
this.filteredCount = 0;
foreach (var (value, view) in stack) foreach (var (value, view) in stack)
{ {
if (invokeAddEventForCurrentElements) if (filter.IsMatch(value))
{ {
filter.InvokeOnAdd(value, view, 0); filteredCount++;
}
else
{
filter.InvokeOnAttach(value, view);
} }
} }
ViewChanged?.Invoke(new SynchronizedViewChangedEventArgs<T, TView>(NotifyViewChangedAction.FilterReset));
} }
} }
public void ResetFilter(Action<T, TView>? resetAction) public void ResetFilter()
{ {
lock (SyncRoot) lock (SyncRoot)
{ {
this.filter = SynchronizedViewFilter<T, TView>.Null; this.filter = SynchronizedViewFilter<T>.Null;
if (resetAction != null) this.filteredCount = stack.Count;
{ ViewChanged?.Invoke(new SynchronizedViewChangedEventArgs<T, TView>(NotifyViewChangedAction.FilterReset));
foreach (var (item, view) in stack)
{
resetAction(item, view);
}
}
} }
} }
public ISynchronizedViewList<TView> ToViewList()
{
return new SynchronizedViewList<T, TView>(this);
}
public INotifyCollectionChangedSynchronizedView<TView> ToNotifyCollectionChanged() public INotifyCollectionChangedSynchronizedView<TView> ToNotifyCollectionChanged()
{ {
lock (SyncRoot) lock (SyncRoot)
@ -108,25 +123,31 @@ namespace ObservableCollections
} }
} }
public IEnumerator<(T, TView)> GetEnumerator() public IEnumerator<TView> GetEnumerator()
{ {
lock (SyncRoot) lock (SyncRoot)
{ {
if (!reverse) foreach (var item in stack)
{
if (filter.IsMatch(item.Item1))
{
yield return item.Item2;
}
}
}
}
IEnumerator IEnumerable.GetEnumerator() => GetEnumerator();
public IEnumerable<(T Value, TView View)> Filtered
{
get
{
lock (SyncRoot)
{ {
foreach (var item in stack) foreach (var item in stack)
{ {
if (filter.IsMatch(item.Item1, item.Item2)) if (filter.IsMatch(item.Item1))
{
yield return item;
}
}
}
else
{
foreach (var item in stack.AsEnumerable().Reverse())
{
if (filter.IsMatch(item.Item1, item.Item2))
{ {
yield return item; yield return item;
} }
@ -135,7 +156,19 @@ namespace ObservableCollections
} }
} }
IEnumerator IEnumerable.GetEnumerator() => GetEnumerator(); public IEnumerable<(T Value, TView View)> Unfiltered
{
get
{
lock (SyncRoot)
{
foreach (var item in stack)
{
yield return item;
}
}
}
}
public void Dispose() public void Dispose()
{ {
@ -154,7 +187,7 @@ namespace ObservableCollections
{ {
var v = (e.NewItem, selector(e.NewItem)); var v = (e.NewItem, selector(e.NewItem));
stack.Push(v); stack.Push(v);
filter.InvokeOnAdd(v, 0); this.InvokeOnAdd(ref filteredCount, ViewChanged, v, 0);
} }
else else
{ {
@ -162,7 +195,7 @@ namespace ObservableCollections
{ {
var v = (item, selector(item)); var v = (item, selector(item));
stack.Push(v); stack.Push(v);
filter.InvokeOnAdd(v, 0); this.InvokeOnAdd(ref filteredCount, ViewChanged, v, 0);
} }
} }
break; break;
@ -171,7 +204,7 @@ namespace ObservableCollections
if (e.IsSingleItem) if (e.IsSingleItem)
{ {
var v = stack.Pop(); var v = stack.Pop();
filter.InvokeOnRemove(v.Item1, v.Item2, 0); this.InvokeOnRemove(ref filteredCount, ViewChanged, v.Item1, v.Item2, 0);
} }
else else
{ {
@ -179,13 +212,13 @@ namespace ObservableCollections
for (int i = 0; i < len; i++) for (int i = 0; i < len; i++)
{ {
var v = stack.Pop(); var v = stack.Pop();
filter.InvokeOnRemove(v.Item1, v.Item2, 0); this.InvokeOnRemove(ref filteredCount, ViewChanged, v.Item1, v.Item2, 0);
} }
} }
break; break;
case NotifyCollectionChangedAction.Reset: case NotifyCollectionChangedAction.Reset:
stack.Clear(); stack.Clear();
filter.InvokeOnReset(); this.InvokeOnReset(ref filteredCount, ViewChanged);
break; break;
case NotifyCollectionChangedAction.Replace: case NotifyCollectionChangedAction.Replace:
case NotifyCollectionChangedAction.Move: case NotifyCollectionChangedAction.Move:
@ -193,7 +226,6 @@ namespace ObservableCollections
break; break;
} }
RoutingCollectionChanged?.Invoke(e);
CollectionStateChanged?.Invoke(e.Action); CollectionStateChanged?.Invoke(e.Action);
} }
} }