From 59300d8ee8556eb042cad03119ba242ec14b3591 Mon Sep 17 00:00:00 2001 From: neuecc Date: Mon, 9 Aug 2021 19:06:01 +0900 Subject: [PATCH] new filter --- .../ISynchronizedViewFilter.cs | 59 ++++++- .../Internal/FreezedView.cs | 8 +- .../ObservableDictionary.Views.cs | 81 ++++++--- .../ObservableDictionary.cs | 4 +- .../ObservableLinkedList.cs | 15 ++ .../ObservableList.Views.cs | 105 ++++++++---- src/ObservableCollections/ObservableList.cs | 9 +- src/ObservableCollections/ObservableQueue.cs | 156 ++++++++++++++++++ .../ObservableRingBuffer.cs | 48 ++++++ src/ObservableCollections/ObservableStack.cs | 25 +++ 10 files changed, 444 insertions(+), 66 deletions(-) create mode 100644 src/ObservableCollections/ObservableLinkedList.cs create mode 100644 src/ObservableCollections/ObservableQueue.cs create mode 100644 src/ObservableCollections/ObservableRingBuffer.cs create mode 100644 src/ObservableCollections/ObservableStack.cs diff --git a/src/ObservableCollections/ISynchronizedViewFilter.cs b/src/ObservableCollections/ISynchronizedViewFilter.cs index 27c86cb..2974f0f 100644 --- a/src/ObservableCollections/ISynchronizedViewFilter.cs +++ b/src/ObservableCollections/ISynchronizedViewFilter.cs @@ -7,32 +7,42 @@ namespace ObservableCollections bool IsMatch(T value, TView view); void WhenTrue(T value, TView view); void WhenFalse(T value, TView view); + void OnCollectionChanged(ChangedKind changedKind, T value, TView view); + } + + public enum ChangedKind + { + Add, Remove } public class SynchronizedViewFilter : ISynchronizedViewFilter { - public static readonly ISynchronizedViewFilter AlwaysTrue = new TrueViewFilter(); + public static readonly ISynchronizedViewFilter Null = new NullViewFilter(); readonly Func isMatch; readonly Action? whenTrue; readonly Action? whenFalse; + readonly Action? onCollectionChanged; - public SynchronizedViewFilter(Func isMatch, Action? whenTrue, Action? whenFalse) + public SynchronizedViewFilter(Func isMatch, Action? whenTrue, Action? whenFalse, Action? onCollectionChanged) { this.isMatch = isMatch; this.whenTrue = whenTrue; this.whenFalse = whenFalse; + this.onCollectionChanged = onCollectionChanged; } public bool IsMatch(T value, TView view) => isMatch(value, view); public void WhenFalse(T value, TView view) => whenFalse?.Invoke(value, view); public void WhenTrue(T value, TView view) => whenTrue?.Invoke(value, view); + public void OnCollectionChanged(ChangedKind changedKind, T value, TView view) => onCollectionChanged?.Invoke(changedKind, value, view); - class TrueViewFilter : ISynchronizedViewFilter + class NullViewFilter : ISynchronizedViewFilter { public bool IsMatch(T value, TView view) => true; public void WhenFalse(T value, TView view) { } public void WhenTrue(T value, TView view) { } + public void OnCollectionChanged(ChangedKind changedKind, T value, TView view) { } } } @@ -40,20 +50,53 @@ namespace ObservableCollections { public static void AttachFilter(this ISynchronizedView source, Func filter) { - source.AttachFilter(new SynchronizedViewFilter(filter, null, null)); + source.AttachFilter(new SynchronizedViewFilter(filter, null, null, null)); } public static void AttachFilter(this ISynchronizedView source, Func isMatch, Action? whenTrue, Action? whenFalse) { - source.AttachFilter(new SynchronizedViewFilter(isMatch, whenTrue, whenFalse)); + source.AttachFilter(new SynchronizedViewFilter(isMatch, whenTrue, whenFalse, null)); } - public static void Invoke(this ISynchronizedViewFilter filter, (T, TView) value) + public static void AttachFilter(this ISynchronizedView source, Func isMatch, Action? whenTrue, Action? whenFalse, Action? onCollectionChanged) { - Invoke(filter, value.Item1, value.Item2); + source.AttachFilter(new SynchronizedViewFilter(isMatch, whenTrue, whenFalse, onCollectionChanged)); } - public static void Invoke(this ISynchronizedViewFilter filter, T value, TView view) + public static bool IsNullFilter(this ISynchronizedViewFilter filter) + { + return filter == SynchronizedViewFilter.Null; + } + + internal static void InvokeOnAdd(this ISynchronizedViewFilter filter, (T value, TView view) value) + { + InvokeOnAdd(filter, value.value, value.view); + } + + internal static void InvokeOnAdd(this ISynchronizedViewFilter filter, T value, TView view) + { + if (filter.IsMatch(value, view)) + { + filter.WhenTrue(value, view); + } + else + { + filter.WhenFalse(value, view); + } + filter.OnCollectionChanged(ChangedKind.Add, value, view); + } + + internal static void InvokeOnRemove(this ISynchronizedViewFilter filter, (T value, TView view) value) + { + InvokeOnRemove(filter, value.value, value.view); + } + + internal static void InvokeOnRemove(this ISynchronizedViewFilter filter, T value, TView view) + { + filter.OnCollectionChanged(ChangedKind.Remove, value, view); + } + + internal static void InvokeOnAttach(this ISynchronizedViewFilter filter, T value, TView view) { if (filter.IsMatch(value, view)) { diff --git a/src/ObservableCollections/Internal/FreezedView.cs b/src/ObservableCollections/Internal/FreezedView.cs index e696081..1a2fd52 100644 --- a/src/ObservableCollections/Internal/FreezedView.cs +++ b/src/ObservableCollections/Internal/FreezedView.cs @@ -23,7 +23,7 @@ namespace ObservableCollections.Internal public FreezedView(IEnumerable source, Func selector, bool reverse) { this.reverse = reverse; - this.filter = SynchronizedViewFilter.AlwaysTrue; + this.filter = SynchronizedViewFilter.Null; this.list = source.Select(x => (x, selector(x))).ToList(); } @@ -54,7 +54,7 @@ namespace ObservableCollections.Internal { lock (SyncRoot) { - this.filter = SynchronizedViewFilter.AlwaysTrue; + this.filter = SynchronizedViewFilter.Null; if (resetAction != null) { foreach (var (item, view) in list) @@ -103,7 +103,7 @@ namespace ObservableCollections.Internal public FreezedSortableView(IEnumerable source, Func selector) { - this.filter = SynchronizedViewFilter.AlwaysTrue; + this.filter = SynchronizedViewFilter.Null; this.array = source.Select(x => (x, selector(x))).ToArray(); } @@ -134,7 +134,7 @@ namespace ObservableCollections.Internal { lock (SyncRoot) { - this.filter = SynchronizedViewFilter.AlwaysTrue; + this.filter = SynchronizedViewFilter.Null; if (resetAction != null) { foreach (var (item, view) in array) diff --git a/src/ObservableCollections/ObservableDictionary.Views.cs b/src/ObservableCollections/ObservableDictionary.Views.cs index 3b57cf0..072f97d 100644 --- a/src/ObservableCollections/ObservableDictionary.Views.cs +++ b/src/ObservableCollections/ObservableDictionary.Views.cs @@ -47,7 +47,7 @@ namespace ObservableCollections { this.source = source; this.selector = selector; - this.filter = SynchronizedViewFilter, TView>.AlwaysTrue; + this.filter = SynchronizedViewFilter, TView>.Null; this.SyncRoot = new object(); lock (source.SyncRoot) { @@ -83,7 +83,7 @@ namespace ObservableCollections this.filter = filter; foreach (var v in dict) { - filter.Invoke(new KeyValuePair(v.Key, v.Value.Item1), v.Value.Item2); + filter.InvokeOnAttach(new KeyValuePair(v.Key, v.Value.Item1), v.Value.Item2); } } } @@ -92,7 +92,7 @@ namespace ObservableCollections { lock (SyncRoot) { - this.filter = SynchronizedViewFilter, TView>.AlwaysTrue; + this.filter = SynchronizedViewFilter, TView>.Null; if (resetAction != null) { foreach (var v in dict) @@ -134,25 +134,40 @@ namespace ObservableCollections { var v = selector(e.NewItem); dict.Add(e.NewItem.Key, (e.NewItem.Value, v)); - filter.Invoke(new KeyValuePair(e.NewItem.Key, e.NewItem.Value), v); + filter.InvokeOnAdd(new KeyValuePair(e.NewItem.Key, e.NewItem.Value), v); } break; case NotifyCollectionChangedAction.Remove: { - dict.Remove(e.OldItem.Key); + if (dict.Remove(e.OldItem.Key, out var v)) + { + filter.InvokeOnRemove((new KeyValuePair(e.OldItem.Key, v.Item1), v.Item2)); + } } break; case NotifyCollectionChangedAction.Move: case NotifyCollectionChangedAction.Replace: { - dict.Remove(e.OldItem.Key); + if (dict.Remove(e.OldItem.Key, out var oldView)) + { + filter.InvokeOnRemove((new KeyValuePair(e.OldItem.Key, oldView.Item1), oldView.Item2)); + } + var v = selector(e.NewItem); dict[e.NewItem.Key] = (e.NewItem.Value, v); - filter.Invoke(new KeyValuePair(e.NewItem.Key, e.NewItem.Value), v); + filter.InvokeOnAdd(new KeyValuePair(e.NewItem.Key, e.NewItem.Value), v); } break; case NotifyCollectionChangedAction.Reset: { + if (!filter.IsNullFilter()) + { + foreach (var item in dict) + { + filter.InvokeOnRemove((new KeyValuePair(item.Key, item.Value.Item1), item.Value.Item2)); + } + } + dict.Clear(); } break; @@ -177,7 +192,7 @@ namespace ObservableCollections { this.source = source; this.selector = selector; - this.filter = SynchronizedViewFilter, TView>.AlwaysTrue; + this.filter = SynchronizedViewFilter, TView>.Null; this.SyncRoot = new object(); lock (source.SyncRoot) { @@ -217,7 +232,7 @@ namespace ObservableCollections this.filter = filter; foreach (var v in dict) { - filter.Invoke(new KeyValuePair(v.Key.Key, v.Key.Value), v.Value); + filter.InvokeOnAttach(new KeyValuePair(v.Key.Key, v.Key.Value), v.Value); } } } @@ -226,7 +241,7 @@ namespace ObservableCollections { lock (SyncRoot) { - this.filter = SynchronizedViewFilter, TView>.AlwaysTrue; + this.filter = SynchronizedViewFilter, TView>.Null; if (resetAction != null) { foreach (var v in dict) @@ -269,27 +284,41 @@ namespace ObservableCollections var v = selector(e.NewItem); var k = new KeyValuePair(e.NewItem.Key, e.NewItem.Value); dict.Add(k, v); - filter.Invoke(k, v); + filter.InvokeOnAdd(k, v); } break; case NotifyCollectionChangedAction.Remove: { - dict.Remove(e.OldItem); + if (dict.Remove(e.OldItem, out var value)) + { + filter.InvokeOnRemove(e.OldItem, value); + } } break; case NotifyCollectionChangedAction.Move: case NotifyCollectionChangedAction.Replace: { var k = new KeyValuePair(e.OldItem.Key, e.OldItem.Value); - dict.Remove(k); + if (dict.Remove(k, out var oldValue)) + { + filter.InvokeOnRemove(k, oldValue); + } + var v = selector(e.NewItem); var nk = new KeyValuePair(e.NewItem.Key, e.NewItem.Value); dict[nk] = v; - filter.Invoke(nk, v); + filter.InvokeOnAdd(nk, v); } break; case NotifyCollectionChangedAction.Reset: { + if (!filter.IsNullFilter()) + { + foreach (var item in dict) + { + filter.InvokeOnRemove(item.Key, item.Value); + } + } dict.Clear(); } break; @@ -317,7 +346,7 @@ namespace ObservableCollections { this.source = source; this.selector = selector; - this.filter = SynchronizedViewFilter, TView>.AlwaysTrue; + this.filter = SynchronizedViewFilter, TView>.Null; this.SyncRoot = new object(); lock (source.SyncRoot) { @@ -360,7 +389,7 @@ namespace ObservableCollections this.filter = filter; foreach (var v in dict) { - filter.Invoke(v.Value, v.Key); + filter.InvokeOnAttach(v.Value, v.Key); } } } @@ -369,7 +398,7 @@ namespace ObservableCollections { lock (SyncRoot) { - this.filter = SynchronizedViewFilter, TView>.AlwaysTrue; + this.filter = SynchronizedViewFilter, TView>.Null; if (resetAction != null) { foreach (var v in dict) @@ -413,7 +442,7 @@ namespace ObservableCollections var k = new KeyValuePair(e.NewItem.Key, e.NewItem.Value); dict.Add(v, k); viewMap.Add(e.NewItem.Key, v); - filter.Invoke(k, v); + filter.InvokeOnAdd(k, v); } break; case NotifyCollectionChangedAction.Remove: @@ -421,6 +450,7 @@ namespace ObservableCollections if (viewMap.Remove(e.OldItem.Key, out var view)) { dict.Remove(view); + filter.InvokeOnRemove(e.OldItem, view); } } break; @@ -429,19 +459,30 @@ namespace ObservableCollections { if (viewMap.Remove(e.OldItem.Key, out var view)) { - dict.Remove(view); + if (dict.Remove(view, out var oldView)) + { + filter.InvokeOnRemove(e.OldItem, view); + } var v = selector(e.NewItem); var k = new KeyValuePair(e.NewItem.Key, e.NewItem.Value); dict[v] = k; viewMap[e.NewItem.Key] = v; - filter.Invoke(k, v); + filter.InvokeOnAdd(k, v); } break; } case NotifyCollectionChangedAction.Reset: { + if (!filter.IsNullFilter()) + { + foreach (var item in dict) + { + filter.InvokeOnRemove(item.Value, item.Key); + } + } dict.Clear(); + viewMap.Clear(); } break; default: diff --git a/src/ObservableCollections/ObservableDictionary.cs b/src/ObservableCollections/ObservableDictionary.cs index ab02016..7a4ddbd 100644 --- a/src/ObservableCollections/ObservableDictionary.cs +++ b/src/ObservableCollections/ObservableDictionary.cs @@ -18,9 +18,9 @@ namespace ObservableCollections this.dictionary = new Dictionary(); } - public ObservableDictionary(Dictionary dictionary) + public ObservableDictionary(IEnumerable> collection) { - this.dictionary = dictionary; + this.dictionary = new Dictionary(collection); } public event NotifyCollectionChangedEventHandler>? CollectionChanged; diff --git a/src/ObservableCollections/ObservableLinkedList.cs b/src/ObservableCollections/ObservableLinkedList.cs new file mode 100644 index 0000000..afd03ca --- /dev/null +++ b/src/ObservableCollections/ObservableLinkedList.cs @@ -0,0 +1,15 @@ +using System.Collections.Generic; + +namespace ObservableCollections +{ + public sealed partial class ObservableLinkedList + { + // TODO:not yet + readonly LinkedList list; + + public ObservableLinkedList(LinkedList list) + { + this.list = list; + } + } +} diff --git a/src/ObservableCollections/ObservableList.Views.cs b/src/ObservableCollections/ObservableList.Views.cs index 68dc148..bef3357 100644 --- a/src/ObservableCollections/ObservableList.Views.cs +++ b/src/ObservableCollections/ObservableList.Views.cs @@ -45,7 +45,7 @@ namespace ObservableCollections this.source = source; this.selector = selector; this.reverse = reverse; - this.filter = SynchronizedViewFilter.AlwaysTrue; + this.filter = SynchronizedViewFilter.Null; this.SyncRoot = new object(); lock (source.SyncRoot) { @@ -54,10 +54,6 @@ namespace ObservableCollections } } - protected virtual void DoSort() - { - } - public int Count { get @@ -76,7 +72,7 @@ namespace ObservableCollections this.filter = filter; foreach (var (value, view) in list) { - filter.Invoke(value, view); + filter.InvokeOnAttach(value, view); } } } @@ -85,7 +81,7 @@ namespace ObservableCollections { lock (SyncRoot) { - this.filter = SynchronizedViewFilter.AlwaysTrue; + this.filter = SynchronizedViewFilter.Null; if (resetAction != null) { foreach (var (item, view) in list) @@ -139,7 +135,7 @@ namespace ObservableCollections { var v = (e.NewItem, selector(e.NewItem)); list.Add(v); - filter.Invoke(v); + filter.InvokeOnAdd(v); } else { @@ -147,7 +143,7 @@ namespace ObservableCollections { var v = (item, selector(item)); list.Add(v); - filter.Invoke(v); + filter.InvokeOnAdd(v); } } } @@ -158,7 +154,7 @@ namespace ObservableCollections { var v = (e.NewItem, selector(e.NewItem)); list.Insert(e.NewStartingIndex, v); - filter.Invoke(v); + filter.InvokeOnAdd(v); } else { @@ -169,7 +165,7 @@ namespace ObservableCollections { var v = (span[i], selector(span[i])); newArray[i] = v; - filter.Invoke(v); + filter.InvokeOnAdd(v); } list.InsertRange(e.NewStartingIndex, newArray); } @@ -178,10 +174,22 @@ namespace ObservableCollections case NotifyCollectionChangedAction.Remove: if (e.IsSingleItem) { + var v = list[e.OldStartingIndex]; list.RemoveAt(e.OldStartingIndex); + filter.InvokeOnRemove(v.Item1, v.Item2); } else { + if (!filter.IsNullFilter()) + { + var len = e.OldStartingIndex + e.OldItems.Length; + for (int i = e.OldStartingIndex; i < len; i++) + { + var v = list[i]; + filter.InvokeOnRemove(v.Item1, v.Item2); + } + } + list.RemoveRange(e.OldStartingIndex, e.OldItems.Length); } break; @@ -189,25 +197,39 @@ namespace ObservableCollections // ObservableList does not support replace range { var v = (e.NewItem, selector(e.NewItem)); + + var oldItem = list[e.NewStartingIndex]; list[e.NewStartingIndex] = v; + + filter.InvokeOnRemove(oldItem); + filter.InvokeOnAdd(v); break; } case NotifyCollectionChangedAction.Move: { var v = (e.NewItem, selector(e.NewItem)); + var removeItem = list[e.OldStartingIndex]; list.RemoveAt(e.OldStartingIndex); list.Insert(e.NewStartingIndex, v); - filter.Invoke(v); + + filter.InvokeOnRemove(removeItem); + filter.InvokeOnAdd(v); } break; case NotifyCollectionChangedAction.Reset: + if (!filter.IsNullFilter()) + { + foreach (var item in list) + { + filter.InvokeOnRemove(item); + } + } list.Clear(); break; default: break; } - DoSort(); RoutingCollectionChanged?.Invoke(e); CollectionStateChanged?.Invoke(e.Action); } @@ -234,7 +256,7 @@ namespace ObservableCollections this.source = source; this.identitySelector = identitySelector; this.transform = transform; - this.filter = SynchronizedViewFilter.AlwaysTrue; + this.filter = SynchronizedViewFilter.Null; lock (source.SyncRoot) { var dict = new SortedDictionary<(T, TKey), (T, TView)>(new Comparer(comparer)); @@ -268,7 +290,7 @@ namespace ObservableCollections this.filter = filter; foreach (var (_, (value, view)) in list) { - filter.Invoke(value, view); + filter.InvokeOnAttach(value, view); } } } @@ -277,7 +299,7 @@ namespace ObservableCollections { lock (SyncRoot) { - this.filter = SynchronizedViewFilter.AlwaysTrue; + this.filter = SynchronizedViewFilter.Null; if (resetAction != null) { foreach (var (_, (value, view)) in list) @@ -323,7 +345,7 @@ namespace ObservableCollections var view = transform(value); var id = identitySelector(value); list.Add((value, id), (value, view)); - filter.Invoke(value, view); + filter.InvokeOnAdd(value, view); } else { @@ -332,7 +354,7 @@ namespace ObservableCollections var view = transform(value); var id = identitySelector(value); list.Add((value, id), (value, view)); - filter.Invoke(value, view); + filter.InvokeOnAdd(value, view); } } } @@ -343,14 +365,16 @@ namespace ObservableCollections { var value = e.OldItem; var id = identitySelector(value); - list.Remove((value, id)); + list.Remove((value, id), out var v); + filter.InvokeOnRemove(v.Value, v.View); } else { foreach (var value in e.OldItems) { var id = identitySelector(value); - list.Remove((value, id)); + list.Remove((value, id), out var v); + filter.InvokeOnRemove(v.Value, v.View); } } } @@ -361,16 +385,25 @@ namespace ObservableCollections // Replace is remove old item and insert new item(same index on replace, difference index on move). { var oldValue = e.OldItem; - list.Remove((oldValue, identitySelector(oldValue))); + list.Remove((oldValue, identitySelector(oldValue)), out var oldView); var value = e.NewItem; var view = transform(value); var id = identitySelector(value); list.Add((value, id), (value, view)); - filter.Invoke(value, view); + + filter.InvokeOnRemove(oldView); + filter.InvokeOnAdd(value, view); } break; case NotifyCollectionChangedAction.Reset: + if (!filter.IsNullFilter()) + { + foreach (var item in list) + { + filter.InvokeOnRemove(item.Value); + } + } list.Clear(); break; default: @@ -425,7 +458,7 @@ namespace ObservableCollections this.source = source; this.identitySelector = identitySelector; this.transform = transform; - this.filter = SynchronizedViewFilter.AlwaysTrue; + this.filter = SynchronizedViewFilter.Null; lock (source.SyncRoot) { var dict = new SortedDictionary<(TView, TKey), (T, TView)>(new Comparer(comparer)); @@ -462,7 +495,7 @@ namespace ObservableCollections this.filter = filter; foreach (var (_, (value, view)) in list) { - filter.Invoke(value, view); + filter.InvokeOnAttach(value, view); } } } @@ -471,7 +504,7 @@ namespace ObservableCollections { lock (SyncRoot) { - this.filter = SynchronizedViewFilter.AlwaysTrue; + this.filter = SynchronizedViewFilter.Null; if (resetAction != null) { foreach (var (_, (value, view)) in list) @@ -518,7 +551,7 @@ namespace ObservableCollections var id = identitySelector(value); list.Add((view, id), (value, view)); viewMap.Add(id, view); - filter.Invoke(value, view); + filter.InvokeOnAdd(value, view); } else { @@ -528,7 +561,7 @@ namespace ObservableCollections var id = identitySelector(value); list.Add((view, id), (value, view)); viewMap.Add(id, view); - filter.Invoke(value, view); + filter.InvokeOnAdd(value, view); } } } @@ -541,7 +574,8 @@ namespace ObservableCollections var id = identitySelector(value); if (viewMap.Remove(id, out var view)) { - list.Remove((view, id)); + list.Remove((view, id), out var v); + filter.InvokeOnRemove(v); } } else @@ -551,7 +585,8 @@ namespace ObservableCollections var id = identitySelector(value); if (viewMap.Remove(id, out var view)) { - list.Remove((view, id)); + list.Remove((view, id), out var v); + filter.InvokeOnRemove(v); } } } @@ -567,6 +602,7 @@ namespace ObservableCollections if (viewMap.Remove(oldKey, out var oldView)) { list.Remove((oldView, oldKey)); + filter.InvokeOnRemove(oldValue, oldView); } var value = e.NewItem; @@ -574,11 +610,20 @@ namespace ObservableCollections var id = identitySelector(value); list.Add((view, id), (value, view)); viewMap.Add(id, view); - filter.Invoke(value, view); + + filter.InvokeOnAdd(value, view); } break; case NotifyCollectionChangedAction.Reset: + if (!filter.IsNullFilter()) + { + foreach (var item in list) + { + filter.InvokeOnRemove(item.Value); + } + } list.Clear(); + viewMap.Clear(); break; default: break; diff --git a/src/ObservableCollections/ObservableList.cs b/src/ObservableCollections/ObservableList.cs index e280e9d..d761067 100644 --- a/src/ObservableCollections/ObservableList.cs +++ b/src/ObservableCollections/ObservableList.cs @@ -17,9 +17,14 @@ namespace ObservableCollections list = new List(); } - public ObservableList(IEnumerable source) + public ObservableList(int capacity) { - list = source.ToList(); + list = new List(capacity); + } + + public ObservableList(IEnumerable collection) + { + list = collection.ToList(); } public T this[int index] diff --git a/src/ObservableCollections/ObservableQueue.cs b/src/ObservableCollections/ObservableQueue.cs new file mode 100644 index 0000000..008fb1b --- /dev/null +++ b/src/ObservableCollections/ObservableQueue.cs @@ -0,0 +1,156 @@ +using ObservableCollections.Internal; +using System; +using System.Collections; +using System.Collections.Generic; +using System.Linq; +using System.Text; +using System.Threading.Tasks; + +namespace ObservableCollections +{ + public sealed partial class ObservableQueue : IReadOnlyCollection, IObservableCollection + { + readonly Queue queue; + public readonly object SyncRoot = new object(); + + public ObservableQueue() + { + this.queue = new Queue(); + } + + public ObservableQueue(int capacity) + { + this.queue = new Queue(capacity); + } + + public ObservableQueue(IEnumerable collection) + { + this.queue = new Queue(collection); + } + + public event NotifyCollectionChangedEventHandler? CollectionChanged; + + public int Count + { + get + { + lock (SyncRoot) + { + return queue.Count; + } + } + } + + public void Enqueue(T item) + { + lock (SyncRoot) + { + var index = queue.Count; + queue.Enqueue(item); + CollectionChanged?.Invoke(NotifyCollectionChangedEventArgs.Add(item, index)); + } + } + + public void EnqueueRange(IEnumerable items) + { + lock (SyncRoot) + { + var index = queue.Count; + using (var xs = new CopyedCollection(items)) + { + foreach (var item in xs.Span) + { + queue.Enqueue(item); + } + CollectionChanged?.Invoke(NotifyCollectionChangedEventArgs.Add(xs.Span, index)); + } + } + } + + public void EnqueueRange(T[] items) + { + lock (SyncRoot) + { + var index = queue.Count; + foreach (var item in items) + { + queue.Enqueue(item); + } + CollectionChanged?.Invoke(NotifyCollectionChangedEventArgs.Add(items, index)); + } + } + + public void EnqueueRange(ReadOnlySpan items) + { + lock (SyncRoot) + { + var index = queue.Count; + foreach (var item in items) + { + queue.Enqueue(item); + } + CollectionChanged?.Invoke(NotifyCollectionChangedEventArgs.Add(items, index)); + } + } + + public void Dequeue() + { + // this.queue. + + + + } + + // TryDequeue + + // DequeueRange + + void Clear() + { + } + + //bool Contains(T item) + //{ + //} + + //void CopyTo(T[] array, int arrayIndex); + + // Peek + + // ToArray + + // TrimExcess + + // EnsureCapacity + + + + // TryPeek + + + public IEnumerator GetEnumerator() + { + throw new NotImplementedException(); + } + + IEnumerator IEnumerable.GetEnumerator() + { + throw new NotImplementedException(); + } + + public ISynchronizedView CreateView(Func transform, bool reverse = false) + { + throw new NotImplementedException(); + } + + public ISynchronizedView CreateSortedView(Func identitySelector, Func transform, IComparer comparer) where TKey : notnull + { + throw new NotImplementedException(); + } + + public ISynchronizedView CreateSortedView(Func identitySelector, Func transform, IComparer viewComparer) where TKey : notnull + { + throw new NotImplementedException(); + } + } +} diff --git a/src/ObservableCollections/ObservableRingBuffer.cs b/src/ObservableCollections/ObservableRingBuffer.cs new file mode 100644 index 0000000..e025d6b --- /dev/null +++ b/src/ObservableCollections/ObservableRingBuffer.cs @@ -0,0 +1,48 @@ +namespace ObservableCollections +{ + public sealed partial class ObservableRingBuffer + { + // TODO:not yet. + readonly T[] buffer; + + public ObservableRingBuffer(int capacity) + { + this.buffer = new T[capacity]; + } + + public int Count => buffer.Length; + + public T this[int index] + { + get + { + return this.buffer[index]; + } + set + { + } + } + + public void AddLast() + { + // AddLast + // AddFirst + //new LinkedList().remo + //new Stack().Push + } + + public void AddFirst() + { + } + + public void RemoveLast() + { + } + + public void RemoveFirst() + { + } + + // GetReverseEnumerable + } +} diff --git a/src/ObservableCollections/ObservableStack.cs b/src/ObservableCollections/ObservableStack.cs new file mode 100644 index 0000000..010a691 --- /dev/null +++ b/src/ObservableCollections/ObservableStack.cs @@ -0,0 +1,25 @@ +using System.Collections.Generic; + +namespace ObservableCollections +{ + public sealed partial class ObservableStack + { + // TODO:not yet. + readonly Stack stack; + + public ObservableStack(Stack stack) + { + this.stack = stack; + } + + public void Push(T item) + { + stack.Push(item); + } + + public void Pop(T item) + { + stack.Pop(); + } + } +}