Skip to content

Commit

Permalink
Fix the index provided by SortedView to filters
Browse files Browse the repository at this point in the history
  • Loading branch information
hadashiA committed Feb 2, 2024
1 parent bcf250c commit b848a80
Show file tree
Hide file tree
Showing 11 changed files with 429 additions and 219 deletions.
Original file line number Diff line number Diff line change
Expand Up @@ -49,7 +49,7 @@ public CloneCollection(IEnumerable<T> source)
}
else
{
var array = ArrayPool<T>.Shared.Rent(count);
var array = ArrayPool<T>.Shared.Rent(16);

var i = 0;
foreach (var item in source)
Expand All @@ -75,8 +75,8 @@ static void TryEnsureCapacity(ref T[] array, int index)
if (array.Length == index)
{
ArrayPool<T>.Shared.Return(array, RuntimeHelpersEx.IsReferenceOrContainsReferences<T>());
array = ArrayPool<T>.Shared.Rent(index * 2);
}
array = ArrayPool<T>.Shared.Rent(index * 2);
}

public void Dispose()
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -114,7 +114,7 @@ internal sealed class FreezedSortableView<T, TView> : ISortableSynchronizedView<
public event Action<NotifyCollectionChangedAction> CollectionStateChanged;
public event NotifyCollectionChangedEventHandler<T> RoutingCollectionChanged;

public object SyncRoot { get; } = new object();
public object SyncRoot { get; } = new();

public FreezedSortableView(IEnumerable<T> source, Func<T, TView> selector)
{
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -12,7 +12,7 @@ internal class SortedView<T, TKey, TView> : ISynchronizedView<T, TView>
readonly IObservableCollection<T> source;
readonly Func<T, TView> transform;
readonly Func<T, TKey> identitySelector;
readonly SortedDictionary<(T Value, TKey Key), (T Value, TView View)> dict;
readonly SortedList<(T Value, TKey Key), (T Value, TView View)> list;

ISynchronizedViewFilter<T, TView> filter;

Expand All @@ -29,13 +29,13 @@ public SortedView(IObservableCollection<T> source, Func<T, TKey> identitySelecto
this.filter = SynchronizedViewFilter<T, TView>.Null;
lock (source.SyncRoot)
{
var dict = new SortedDictionary<(T, TKey), (T, TView)>(new Comparer(comparer));
var dict = new Dictionary<(T, TKey), (T, TView)>(source.Count);
foreach (var v in source)
{
dict.Add((v, identitySelector(v)), (v, transform(v)));
}

this.dict = dict;
this.list = new SortedList<(T Value, TKey Key), (T Value, TView View)>(dict, new Comparer(comparer));
this.source.CollectionChanged += SourceCollectionChanged;
}
}
Expand All @@ -46,7 +46,7 @@ public int Count
{
lock (SyncRoot)
{
return dict.Count;
return list.Count;
}
}
}
Expand All @@ -56,7 +56,7 @@ public void AttachFilter(ISynchronizedViewFilter<T, TView> filter)
lock (SyncRoot)
{
this.filter = filter;
foreach (var (_, (value, view)) in dict)
foreach (var (_, (value, view)) in list)
{
filter.InvokeOnAttach(value, view);
}
Expand All @@ -70,7 +70,7 @@ public void ResetFilter(Action<T, TView> resetAction)
this.filter = SynchronizedViewFilter<T, TView>.Null;
if (resetAction != null)
{
foreach (var (_, (value, view)) in dict)
foreach (var (_, (value, view)) in list)
{
resetAction(value, view);
}
Expand All @@ -90,7 +90,7 @@ public INotifyCollectionChangedSynchronizedView<T, TView> WithINotifyCollectionC
{
lock (SyncRoot)
{
foreach (var item in dict)
foreach (var item in list)
{
if (filter.IsMatch(item.Value.Value, item.Value.View))
{
Expand All @@ -114,83 +114,101 @@ private void SourceCollectionChanged(in NotifyCollectionChangedEventArgs<T> e)
switch (e.Action)
{
case NotifyCollectionChangedAction.Add:
{
// Add, Insert
if (e.IsSingleItem)
{
var value = e.NewItem;
var view = transform(value);
var id = identitySelector(value);
list.Add((value, id), (value, view));
var index = list.IndexOfKey((value, id));
filter.InvokeOnAdd(value, view, NotifyCollectionChangedEventArgs<T>.Add(value, index));
}
else
{
// Add, Insert
if (e.IsSingleItem)
foreach (var value in e.NewItems)
{
var value = e.NewItem;
var view = transform(value);
var id = identitySelector(value);
dict.Add((value, id), (value, view));
filter.InvokeOnAdd(value, view, e);
}
else
{
foreach (var value in e.NewItems)
{
var view = transform(value);
var id = identitySelector(value);
dict.Add((value, id), (value, view));
filter.InvokeOnAdd(value, view, e);
}
list.Add((value, id), (value, view));
var index = list.IndexOfKey((value, id));
filter.InvokeOnAdd(value, view, NotifyCollectionChangedEventArgs<T>.Add(value, index));
}
}
}
break;
case NotifyCollectionChangedAction.Remove:
{
if (e.IsSingleItem)
{
if (e.IsSingleItem)
var value = e.OldItem;
var id = identitySelector(value);
var key = (value, id);
if (list.TryGetValue(key, out var v))
{
var value = e.OldItem;
var id = identitySelector(value);
dict.Remove((value, id), out var v);
filter.InvokeOnRemove(v.Value, v.View, e);
var index = list.IndexOfKey(key);
list.RemoveAt(index);
filter.InvokeOnRemove(v.Value, v.View, NotifyCollectionChangedEventArgs<T>.Remove(v.Value, index));
}
else
}
else
{
foreach (var value in e.OldItems)
{
foreach (var value in e.OldItems)
var id = identitySelector(value);
var key = (value, id);
if (list.TryGetValue(key, out var v))
{
var id = identitySelector(value);
dict.Remove((value, id), out var v);
filter.InvokeOnRemove(v.Value, v.View, e);
var index = list.IndexOfKey((value, id));
list.RemoveAt(index);
filter.InvokeOnRemove(v.Value, v.View, NotifyCollectionChangedEventArgs<T>.Remove(v.Value, index));
}
}
}
}
break;
case NotifyCollectionChangedAction.Replace:
// ReplaceRange is not supported in all ObservableCollections collections
// Replace is remove old item and insert new item.
{
var oldValue = e.OldItem;
var oldKey = (oldValue, identitySelector(oldValue));
if (list.TryGetValue(oldKey, out var o))
{
var oldValue = e.OldItem;
dict.Remove((oldValue, identitySelector(oldValue)), out var oldView);
var oldIndex = list.IndexOfKey(oldKey);
list.RemoveAt(oldIndex);
filter.InvokeOnRemove(o, NotifyCollectionChangedEventArgs<T>.Remove(oldValue, oldIndex));
}

var value = e.NewItem;
var view = transform(value);
var id = identitySelector(value);
dict.Add((value, id), (value, view));
var value = e.NewItem;
var view = transform(value);
var id = identitySelector(value);
list.Add((value, id), (value, view));
var newIndex = list.IndexOfKey((value, id));

filter.InvokeOnRemove(oldView, e);
filter.InvokeOnAdd(value, view, e);
}
filter.InvokeOnAdd(value, view, NotifyCollectionChangedEventArgs<T>.Add(value, newIndex));
}
break;
case NotifyCollectionChangedAction.Move:
{
// Move(index change) does not affect sorted list.
var oldValue = e.OldItem;
if (list.TryGetValue((oldValue, identitySelector(oldValue)), out var view))
{
// Move(index change) does not affect sorted list.
var oldValue = e.OldItem;
if (dict.TryGetValue((oldValue, identitySelector(oldValue)), out var view))
{
filter.InvokeOnMove(view, e);
}
filter.InvokeOnMove(view, e);
}
}
break;
case NotifyCollectionChangedAction.Reset:
if (!filter.IsNullFilter())
{
foreach (var item in dict)
foreach (var item in list)
{
filter.InvokeOnRemove(item.Value, e);
}
}
dict.Clear();
list.Clear();
break;
default:
break;
Expand Down Expand Up @@ -222,4 +240,4 @@ public int Compare((T value, TKey id) x, (T value, TKey id) y)
}
}
}
}
}
Loading

0 comments on commit b848a80

Please sign in to comment.