WIP dictionary
This commit is contained in:
parent
b4ed8d5748
commit
2a85ffdac8
@ -1,4 +1,5 @@
|
|||||||
using System;
|
using ObservableCollections.Internal;
|
||||||
|
using System;
|
||||||
using System.Collections.Generic;
|
using System.Collections.Generic;
|
||||||
using System.Collections.Specialized;
|
using System.Collections.Specialized;
|
||||||
using System.ComponentModel;
|
using System.ComponentModel;
|
||||||
@ -7,15 +8,11 @@ namespace ObservableCollections
|
|||||||
{
|
{
|
||||||
public delegate void NotifyCollectionChangedEventHandler<T>(in NotifyCollectionChangedEventArgs<T> e);
|
public delegate void NotifyCollectionChangedEventHandler<T>(in NotifyCollectionChangedEventArgs<T> e);
|
||||||
|
|
||||||
public interface IObservableCollection<T>
|
public interface IObservableCollection<T> : IReadOnlyCollection<T>
|
||||||
{
|
{
|
||||||
event NotifyCollectionChangedEventHandler<T>? CollectionChanged;
|
event NotifyCollectionChangedEventHandler<T>? CollectionChanged;
|
||||||
|
object SyncRoot { get; }
|
||||||
ISynchronizedView<T, TView> CreateView<TView>(Func<T, TView> transform, bool reverse = false);
|
ISynchronizedView<T, TView> CreateView<TView>(Func<T, TView> transform, bool reverse = false);
|
||||||
ISynchronizedView<T, TView> CreateSortedView<TKey, TView>(Func<T, TKey> identitySelector, Func<T, TView> transform, IComparer<T> comparer)
|
|
||||||
where TKey : notnull;
|
|
||||||
ISynchronizedView<T, TView> CreateSortedView<TKey, TView>(Func<T, TKey> identitySelector, Func<T, TView> transform, IComparer<TView> viewComparer)
|
|
||||||
where TKey : notnull;
|
|
||||||
}
|
}
|
||||||
|
|
||||||
public interface IFreezedCollection<T>
|
public interface IFreezedCollection<T>
|
||||||
@ -26,7 +23,6 @@ namespace ObservableCollections
|
|||||||
|
|
||||||
public interface ISynchronizedView<T, TView> : IReadOnlyCollection<(T Value, TView View)>, IDisposable
|
public interface ISynchronizedView<T, TView> : IReadOnlyCollection<(T Value, TView View)>, IDisposable
|
||||||
{
|
{
|
||||||
// TODO:Remove SyncRoot
|
|
||||||
object SyncRoot { get; }
|
object SyncRoot { get; }
|
||||||
|
|
||||||
event NotifyCollectionChangedEventHandler<T>? RoutingCollectionChanged;
|
event NotifyCollectionChangedEventHandler<T>? RoutingCollectionChanged;
|
||||||
@ -34,7 +30,6 @@ namespace ObservableCollections
|
|||||||
|
|
||||||
void AttachFilter(ISynchronizedViewFilter<T, TView> filter);
|
void AttachFilter(ISynchronizedViewFilter<T, TView> filter);
|
||||||
void ResetFilter(Action<T, TView>? resetAction);
|
void ResetFilter(Action<T, TView>? resetAction);
|
||||||
|
|
||||||
INotifyCollectionChangedSynchronizedView<T, TView> WithINotifyCollectionChanged();
|
INotifyCollectionChangedSynchronizedView<T, TView> WithINotifyCollectionChanged();
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -44,12 +39,28 @@ namespace ObservableCollections
|
|||||||
void Sort(IComparer<TView> viewComparer);
|
void Sort(IComparer<TView> viewComparer);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
public interface IGroupedSynchoronizedView<T, TKey, TView> : ILookup<TKey, (T, TView)>, ISynchronizedView<T, TView>
|
||||||
|
{
|
||||||
|
}
|
||||||
|
|
||||||
public interface INotifyCollectionChangedSynchronizedView<T, TView> : ISynchronizedView<T, TView>, INotifyCollectionChanged, INotifyPropertyChanged
|
public interface INotifyCollectionChangedSynchronizedView<T, TView> : ISynchronizedView<T, TView>, INotifyCollectionChanged, INotifyPropertyChanged
|
||||||
{
|
{
|
||||||
}
|
}
|
||||||
|
|
||||||
public static class ObservableCollectionsExtensions
|
public static class ObservableCollectionsExtensions
|
||||||
{
|
{
|
||||||
|
public static ISynchronizedView<T, TView> CreateSortedView<T, TKey, TView>(this IObservableCollection<T> source, Func<T, TKey> identitySelector, Func<T, TView> transform, IComparer<T> comparer)
|
||||||
|
where TKey : notnull
|
||||||
|
{
|
||||||
|
return new SortedView<T, TKey, TView>(source, identitySelector, transform, comparer);
|
||||||
|
}
|
||||||
|
|
||||||
|
public static ISynchronizedView<T, TView> CreateSortedView<T, TKey, TView>(this IObservableCollection<T> source, Func<T, TKey> identitySelector, Func<T, TView> transform, IComparer<TView> viewComparer)
|
||||||
|
where TKey : notnull
|
||||||
|
{
|
||||||
|
return new SortedViewViewComparer<T, TKey, TView>(source, identitySelector, transform, viewComparer);
|
||||||
|
}
|
||||||
|
|
||||||
public static ISynchronizedView<T, TView> CreateSortedView<T, TKey, TView, TCompare>(this IObservableCollection<T> source, Func<T, TKey> identitySelector, Func<T, TView> transform, Func<T, TCompare> compareSelector, bool ascending = true)
|
public static ISynchronizedView<T, TView> CreateSortedView<T, TKey, TView, TCompare>(this IObservableCollection<T> source, Func<T, TKey> identitySelector, Func<T, TView> transform, Func<T, TCompare> compareSelector, bool ascending = true)
|
||||||
where TKey : notnull
|
where TKey : notnull
|
||||||
{
|
{
|
||||||
|
386
src/ObservableCollections/Internal/GroupedView.cs
Normal file
386
src/ObservableCollections/Internal/GroupedView.cs
Normal file
@ -0,0 +1,386 @@
|
|||||||
|
using System.Collections;
|
||||||
|
using System.Collections.Specialized;
|
||||||
|
|
||||||
|
namespace ObservableCollections.Internal
|
||||||
|
{
|
||||||
|
// mutable lookup.
|
||||||
|
internal class Lookup<TKey, TValue> : ILookup<TKey, TValue>
|
||||||
|
where TKey : notnull
|
||||||
|
{
|
||||||
|
Grouping<TKey, TValue>?[] groupingBuckets;
|
||||||
|
IEqualityComparer<TKey> keyComparer;
|
||||||
|
int count;
|
||||||
|
Grouping<TKey, TValue>? lastGroup;
|
||||||
|
|
||||||
|
// TODO:
|
||||||
|
public int Count => throw new NotImplementedException();
|
||||||
|
|
||||||
|
public int ItemsCount { get; private set; }
|
||||||
|
|
||||||
|
public IEnumerable<TValue> this[TKey key] => throw new NotImplementedException();
|
||||||
|
|
||||||
|
public Lookup(IEqualityComparer<TKey> keyComparer)
|
||||||
|
{
|
||||||
|
this.groupingBuckets = new Grouping<TKey, TValue>?[7]; // initial size
|
||||||
|
this.count = 0;
|
||||||
|
this.lastGroup = null;
|
||||||
|
this.keyComparer = keyComparer;
|
||||||
|
}
|
||||||
|
|
||||||
|
// TODO:
|
||||||
|
public bool Contains(TKey key)
|
||||||
|
{
|
||||||
|
throw new NotImplementedException();
|
||||||
|
}
|
||||||
|
|
||||||
|
public void Add(TKey key, TValue value)
|
||||||
|
{
|
||||||
|
var keyHash = keyComparer.GetHashCode(key);
|
||||||
|
var g = groupingBuckets[keyHash % groupingBuckets.Length];
|
||||||
|
var last = g;
|
||||||
|
while (g != null)
|
||||||
|
{
|
||||||
|
if (keyComparer.Equals(key, g.key))
|
||||||
|
{
|
||||||
|
break; // hit.
|
||||||
|
}
|
||||||
|
|
||||||
|
last = g;
|
||||||
|
g = g.hashNext;
|
||||||
|
}
|
||||||
|
|
||||||
|
if (g == null)
|
||||||
|
{
|
||||||
|
g = new Grouping<TKey, TValue>(key, keyHash);
|
||||||
|
if (last != null)
|
||||||
|
{
|
||||||
|
last.hashNext = g;
|
||||||
|
}
|
||||||
|
else
|
||||||
|
{
|
||||||
|
if (groupingBuckets.Length == count)
|
||||||
|
{
|
||||||
|
Resize();
|
||||||
|
}
|
||||||
|
|
||||||
|
groupingBuckets[keyHash % groupingBuckets.Length] = g;
|
||||||
|
}
|
||||||
|
count++; // new group added
|
||||||
|
}
|
||||||
|
|
||||||
|
g.Add(value);
|
||||||
|
|
||||||
|
if (lastGroup == null)
|
||||||
|
{
|
||||||
|
lastGroup = g;
|
||||||
|
lastGroup.nextGroup = g; // last's next is first.
|
||||||
|
}
|
||||||
|
else
|
||||||
|
{
|
||||||
|
g.nextGroup = lastGroup.nextGroup;
|
||||||
|
lastGroup.nextGroup = g;
|
||||||
|
lastGroup = g;
|
||||||
|
}
|
||||||
|
|
||||||
|
ItemsCount++;
|
||||||
|
}
|
||||||
|
|
||||||
|
public void RemoveKeyAll(TKey key)
|
||||||
|
{
|
||||||
|
throw new NotImplementedException();
|
||||||
|
}
|
||||||
|
|
||||||
|
public void RemoveValue(TKey key, TValue value)
|
||||||
|
{
|
||||||
|
}
|
||||||
|
|
||||||
|
void Resize()
|
||||||
|
{
|
||||||
|
var newSize = checked((count * 2) + 1);
|
||||||
|
var newGrouping = new Grouping<TKey, TValue>[newSize];
|
||||||
|
|
||||||
|
var g = lastGroup!; // when resize called, always lastGroup is not null.
|
||||||
|
do
|
||||||
|
{
|
||||||
|
g = g.nextGroup!; // nextGroup is always not null, initial last.next is first.
|
||||||
|
var index = g.hash % newSize;
|
||||||
|
g.hashNext = newGrouping[index];
|
||||||
|
newGrouping[index] = g;
|
||||||
|
}
|
||||||
|
while (g != lastGroup);
|
||||||
|
|
||||||
|
groupingBuckets = newGrouping;
|
||||||
|
}
|
||||||
|
|
||||||
|
public IEnumerator<IGrouping<TKey, TValue>> GetEnumerator()
|
||||||
|
{
|
||||||
|
if (lastGroup == null) yield break;
|
||||||
|
|
||||||
|
var g = lastGroup.nextGroup; // last's next is first.
|
||||||
|
do
|
||||||
|
{
|
||||||
|
if (g == null) yield break;
|
||||||
|
yield return g;
|
||||||
|
g = g.nextGroup;
|
||||||
|
}
|
||||||
|
while (g != lastGroup); // reaches end.
|
||||||
|
}
|
||||||
|
|
||||||
|
IEnumerator IEnumerable.GetEnumerator()
|
||||||
|
{
|
||||||
|
return GetEnumerator();
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
internal class Grouping<TKey, TValue> : IGrouping<TKey, TValue>
|
||||||
|
{
|
||||||
|
internal readonly TKey key;
|
||||||
|
internal readonly int hash;
|
||||||
|
internal readonly List<TValue> elements;
|
||||||
|
|
||||||
|
internal Grouping<TKey, TValue>? hashNext; // same buckets linknode
|
||||||
|
internal Grouping<TKey, TValue>? nextGroup; // guarantee added order
|
||||||
|
|
||||||
|
public TKey Key => key;
|
||||||
|
|
||||||
|
public Grouping(TKey key, int hash)
|
||||||
|
{
|
||||||
|
this.key = key;
|
||||||
|
this.hash = hash;
|
||||||
|
this.elements = new List<TValue>(1); // initial size is single.
|
||||||
|
}
|
||||||
|
|
||||||
|
public void Add(TValue value)
|
||||||
|
{
|
||||||
|
elements.Add(value);
|
||||||
|
}
|
||||||
|
|
||||||
|
public void Remove(TValue value)
|
||||||
|
{
|
||||||
|
elements.Remove(value);
|
||||||
|
}
|
||||||
|
|
||||||
|
public IEnumerator<TValue> GetEnumerator()
|
||||||
|
{
|
||||||
|
return elements.GetEnumerator();
|
||||||
|
}
|
||||||
|
|
||||||
|
IEnumerator IEnumerable.GetEnumerator()
|
||||||
|
{
|
||||||
|
return GetEnumerator();
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
internal class GroupedView<T, TKey, TView> : IGroupedSynchoronizedView<T, TKey, TView>
|
||||||
|
where TKey : notnull
|
||||||
|
{
|
||||||
|
readonly Lookup<TKey, (T Value, TView View)> lookup;
|
||||||
|
readonly IObservableCollection<T> source;
|
||||||
|
readonly Func<T, TKey> keySelector;
|
||||||
|
readonly Func<T, TView> viewSelector;
|
||||||
|
|
||||||
|
ISynchronizedViewFilter<T, TView> filter;
|
||||||
|
|
||||||
|
public GroupedView(IObservableCollection<T> source, Func<T, TKey> keySelector, Func<T, TView> viewSelector, IEqualityComparer<TKey> keyComparer)
|
||||||
|
{
|
||||||
|
this.source = source;
|
||||||
|
this.filter = SynchronizedViewFilter<T, TView>.Null;
|
||||||
|
this.keySelector = keySelector;
|
||||||
|
this.viewSelector = viewSelector;
|
||||||
|
|
||||||
|
lock (source.SyncRoot)
|
||||||
|
{
|
||||||
|
lookup = new Lookup<TKey, (T, TView)>(keyComparer);
|
||||||
|
|
||||||
|
foreach (var value in source)
|
||||||
|
{
|
||||||
|
var key = keySelector(value);
|
||||||
|
var view = viewSelector(value);
|
||||||
|
lookup.Add(key, (value, view));
|
||||||
|
}
|
||||||
|
|
||||||
|
source.CollectionChanged += SourceCollectionChanged;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
public IEnumerable<(T, TView)> this[TKey key]
|
||||||
|
{
|
||||||
|
get
|
||||||
|
{
|
||||||
|
lock (SyncRoot)
|
||||||
|
{
|
||||||
|
var v = lookup[key];
|
||||||
|
foreach (var item in v)
|
||||||
|
{
|
||||||
|
yield return item;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
public object SyncRoot { get; } = new object();
|
||||||
|
|
||||||
|
public int Count
|
||||||
|
{
|
||||||
|
get
|
||||||
|
{
|
||||||
|
lock (SyncRoot)
|
||||||
|
{
|
||||||
|
return lookup.Count;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
int IReadOnlyCollection<(T Value, TView View)>.Count
|
||||||
|
{
|
||||||
|
get
|
||||||
|
{
|
||||||
|
lock (SyncRoot)
|
||||||
|
{
|
||||||
|
return lookup.ItemsCount;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
public event NotifyCollectionChangedEventHandler<T>? RoutingCollectionChanged;
|
||||||
|
public event Action<NotifyCollectionChangedAction>? CollectionStateChanged;
|
||||||
|
|
||||||
|
public void AttachFilter(ISynchronizedViewFilter<T, TView> filter)
|
||||||
|
{
|
||||||
|
lock (SyncRoot)
|
||||||
|
{
|
||||||
|
this.filter = filter;
|
||||||
|
foreach (var item in lookup)
|
||||||
|
{
|
||||||
|
foreach (var (value, view) in item)
|
||||||
|
{
|
||||||
|
filter.InvokeOnAttach(value, view);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
public void ResetFilter(Action<T, TView>? resetAction)
|
||||||
|
{
|
||||||
|
lock (SyncRoot)
|
||||||
|
{
|
||||||
|
this.filter = SynchronizedViewFilter<T, TView>.Null;
|
||||||
|
if (resetAction != null)
|
||||||
|
{
|
||||||
|
foreach (var item in lookup)
|
||||||
|
{
|
||||||
|
foreach (var (value, view) in item)
|
||||||
|
{
|
||||||
|
resetAction(value, view);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
public bool Contains(TKey key)
|
||||||
|
{
|
||||||
|
lock (SyncRoot)
|
||||||
|
{
|
||||||
|
return lookup.Contains(key);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
public void Dispose()
|
||||||
|
{
|
||||||
|
source.CollectionChanged -= SourceCollectionChanged;
|
||||||
|
}
|
||||||
|
|
||||||
|
public INotifyCollectionChangedSynchronizedView<T, TView> WithINotifyCollectionChanged()
|
||||||
|
{
|
||||||
|
lock (SyncRoot)
|
||||||
|
{
|
||||||
|
return new NotifyCollectionChangedSynchronizedView<T, TView>(this);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
IEnumerator IEnumerable.GetEnumerator()
|
||||||
|
{
|
||||||
|
return GetEnumerator();
|
||||||
|
}
|
||||||
|
|
||||||
|
IEnumerator<(T Value, TView View)> IEnumerable<(T Value, TView View)>.GetEnumerator()
|
||||||
|
{
|
||||||
|
throw new NotImplementedException();
|
||||||
|
}
|
||||||
|
|
||||||
|
public IEnumerator<IGrouping<TKey, (T, TView)>> GetEnumerator()
|
||||||
|
{
|
||||||
|
throw new NotImplementedException();
|
||||||
|
}
|
||||||
|
|
||||||
|
private void SourceCollectionChanged(in NotifyCollectionChangedEventArgs<T> e)
|
||||||
|
{
|
||||||
|
lock (SyncRoot)
|
||||||
|
{
|
||||||
|
switch (e.Action)
|
||||||
|
{
|
||||||
|
case NotifyCollectionChangedAction.Add:
|
||||||
|
if (e.IsSingleItem)
|
||||||
|
{
|
||||||
|
var value = e.NewItem;
|
||||||
|
var key = keySelector(value);
|
||||||
|
var view = viewSelector(value);
|
||||||
|
lookup.Add(key, (value, view));
|
||||||
|
filter.InvokeOnAdd(value, view);
|
||||||
|
}
|
||||||
|
else
|
||||||
|
{
|
||||||
|
foreach (var value in e.NewItems)
|
||||||
|
{
|
||||||
|
var key = keySelector(value);
|
||||||
|
var view = viewSelector(value);
|
||||||
|
lookup.Add(key, (value, view));
|
||||||
|
filter.InvokeOnAdd(value, view);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
break;
|
||||||
|
case NotifyCollectionChangedAction.Remove:
|
||||||
|
if (e.IsSingleItem)
|
||||||
|
{
|
||||||
|
var value = e.OldItem;
|
||||||
|
var key = keySelector(value);
|
||||||
|
|
||||||
|
lookup
|
||||||
|
|
||||||
|
//var removeItems = lookup[key];
|
||||||
|
//foreach (var v in removeItems)
|
||||||
|
//{
|
||||||
|
// filter.InvokeOnRemove(v);
|
||||||
|
//}
|
||||||
|
|
||||||
|
//lookup.Remove(key);
|
||||||
|
//filter.InvokeOnRemove(
|
||||||
|
//lookup
|
||||||
|
//dict.Remove((value, id), out var v);
|
||||||
|
//filter.InvokeOnRemove(v.Value, v.View);
|
||||||
|
}
|
||||||
|
else
|
||||||
|
{
|
||||||
|
//foreach (var value in e.OldItems)
|
||||||
|
//{
|
||||||
|
// var id = identitySelector(value);
|
||||||
|
// dict.Remove((value, id), out var v);
|
||||||
|
// filter.InvokeOnRemove(v.Value, v.View);
|
||||||
|
//}
|
||||||
|
}
|
||||||
|
|
||||||
|
break;
|
||||||
|
case NotifyCollectionChangedAction.Replace:
|
||||||
|
break;
|
||||||
|
case NotifyCollectionChangedAction.Move:
|
||||||
|
break;
|
||||||
|
case NotifyCollectionChangedAction.Reset:
|
||||||
|
break;
|
||||||
|
default:
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
@ -4,7 +4,7 @@ using System.Collections.Specialized;
|
|||||||
namespace ObservableCollections.Internal
|
namespace ObservableCollections.Internal
|
||||||
{
|
{
|
||||||
internal class SortedView<T, TKey, TView> : ISynchronizedView<T, TView>
|
internal class SortedView<T, TKey, TView> : ISynchronizedView<T, TView>
|
||||||
where TKey : notnull
|
where TKey : notnull
|
||||||
{
|
{
|
||||||
readonly IObservableCollection<T> source;
|
readonly IObservableCollection<T> source;
|
||||||
readonly Func<T, TView> transform;
|
readonly Func<T, TView> transform;
|
||||||
@ -18,16 +18,16 @@ namespace ObservableCollections.Internal
|
|||||||
|
|
||||||
public object SyncRoot { get; } = new object();
|
public object SyncRoot { get; } = new object();
|
||||||
|
|
||||||
public SortedView(IObservableCollection<T> source, object syncRoot, IEnumerable<T> sourceEnumerable, Func<T, TKey> identitySelector, Func<T, TView> transform, IComparer<T> comparer)
|
public SortedView(IObservableCollection<T> source, Func<T, TKey> identitySelector, Func<T, TView> transform, IComparer<T> comparer)
|
||||||
{
|
{
|
||||||
this.source = source;
|
this.source = source;
|
||||||
this.identitySelector = identitySelector;
|
this.identitySelector = identitySelector;
|
||||||
this.transform = transform;
|
this.transform = transform;
|
||||||
this.filter = SynchronizedViewFilter<T, TView>.Null;
|
this.filter = SynchronizedViewFilter<T, TView>.Null;
|
||||||
lock (syncRoot)
|
lock (source.SyncRoot)
|
||||||
{
|
{
|
||||||
var dict = new SortedDictionary<(T, TKey), (T, TView)>(new Comparer(comparer));
|
var dict = new SortedDictionary<(T, TKey), (T, TView)>(new Comparer(comparer));
|
||||||
foreach (var v in sourceEnumerable)
|
foreach (var v in source)
|
||||||
{
|
{
|
||||||
dict.Add((v, identitySelector(v)), (v, transform(v)));
|
dict.Add((v, identitySelector(v)), (v, transform(v)));
|
||||||
}
|
}
|
||||||
@ -145,6 +145,8 @@ namespace ObservableCollections.Internal
|
|||||||
}
|
}
|
||||||
break;
|
break;
|
||||||
case NotifyCollectionChangedAction.Replace:
|
case NotifyCollectionChangedAction.Replace:
|
||||||
|
// TODO:Range support
|
||||||
|
|
||||||
// ReplaceRange is not supported in all ObservableCollections collections
|
// ReplaceRange is not supported in all ObservableCollections collections
|
||||||
// Replace is remove old item and insert new item.
|
// Replace is remove old item and insert new item.
|
||||||
{
|
{
|
||||||
|
@ -19,17 +19,17 @@ namespace ObservableCollections.Internal
|
|||||||
|
|
||||||
public object SyncRoot { get; } = new object();
|
public object SyncRoot { get; } = new object();
|
||||||
|
|
||||||
public SortedViewViewComparer(IObservableCollection<T> source, object syncRoot, IEnumerable<T> sourceEnumerable, Func<T, TKey> identitySelector, Func<T, TView> transform, IComparer<TView> comparer)
|
public SortedViewViewComparer(IObservableCollection<T> source, Func<T, TKey> identitySelector, Func<T, TView> transform, IComparer<TView> comparer)
|
||||||
{
|
{
|
||||||
this.source = source;
|
this.source = source;
|
||||||
this.identitySelector = identitySelector;
|
this.identitySelector = identitySelector;
|
||||||
this.transform = transform;
|
this.transform = transform;
|
||||||
this.filter = SynchronizedViewFilter<T, TView>.Null;
|
this.filter = SynchronizedViewFilter<T, TView>.Null;
|
||||||
lock (syncRoot)
|
lock (source.SyncRoot)
|
||||||
{
|
{
|
||||||
var dict = new SortedDictionary<(TView, TKey), (T, TView)>(new Comparer(comparer));
|
var dict = new SortedDictionary<(TView, TKey), (T, TView)>(new Comparer(comparer));
|
||||||
this.viewMap = new Dictionary<TKey, TView>();
|
this.viewMap = new Dictionary<TKey, TView>();
|
||||||
foreach (var value in sourceEnumerable)
|
foreach (var value in source)
|
||||||
{
|
{
|
||||||
var view = transform(value);
|
var view = transform(value);
|
||||||
var id = identitySelector(value);
|
var id = identitySelector(value);
|
||||||
|
@ -12,25 +12,15 @@ namespace ObservableCollections
|
|||||||
return new View<TView>(this, transform);
|
return new View<TView>(this, transform);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// using key implicitly
|
||||||
public ISynchronizedView<KeyValuePair<TKey, TValue>, TView> CreateSortedView<TView>(Func<KeyValuePair<TKey, TValue>, TView> transform, IComparer<KeyValuePair<TKey, TValue>> comparer)
|
public ISynchronizedView<KeyValuePair<TKey, TValue>, TView> CreateSortedView<TView>(Func<KeyValuePair<TKey, TValue>, TView> transform, IComparer<KeyValuePair<TKey, TValue>> comparer)
|
||||||
{
|
{
|
||||||
return new SortedView<KeyValuePair<TKey, TValue>, TKey, TView>(this, this.SyncRoot, dictionary, x => x.Key, transform, comparer);
|
return this.CreateSortedView(x => x.Key, transform, comparer);
|
||||||
}
|
}
|
||||||
|
|
||||||
public ISynchronizedView<KeyValuePair<TKey, TValue>, TView> CreateSortedView<TView>(Func<KeyValuePair<TKey, TValue>, TView> transform, IComparer<TView> viewComparer)
|
public ISynchronizedView<KeyValuePair<TKey, TValue>, TView> CreateSortedView<TView>(Func<KeyValuePair<TKey, TValue>, TView> transform, IComparer<TView> viewComparer)
|
||||||
{
|
{
|
||||||
return new SortedViewViewComparer<KeyValuePair<TKey, TValue>, TKey, TView>(this, this.SyncRoot, dictionary, x => x.Key, transform, viewComparer);
|
return this.CreateSortedView(x => x.Key, transform, viewComparer);
|
||||||
}
|
|
||||||
|
|
||||||
// identity selector is ignored
|
|
||||||
ISynchronizedView<KeyValuePair<TKey, TValue>, TView> IObservableCollection<KeyValuePair<TKey, TValue>>.CreateSortedView<TKey1, TView>(Func<KeyValuePair<TKey, TValue>, TKey1> identitySelector, Func<KeyValuePair<TKey, TValue>, TView> transform, IComparer<KeyValuePair<TKey, TValue>> comparer)
|
|
||||||
{
|
|
||||||
return new SortedView<KeyValuePair<TKey, TValue>, TKey, TView>(this, this.SyncRoot, dictionary, x => x.Key, transform, comparer);
|
|
||||||
}
|
|
||||||
|
|
||||||
ISynchronizedView<KeyValuePair<TKey, TValue>, TView> IObservableCollection<KeyValuePair<TKey, TValue>>.CreateSortedView<TKey1, TView>(Func<KeyValuePair<TKey, TValue>, TKey1> identitySelector, Func<KeyValuePair<TKey, TValue>, TView> transform, IComparer<TView> viewComparer)
|
|
||||||
{
|
|
||||||
return new SortedViewViewComparer<KeyValuePair<TKey, TValue>, TKey, TView>(this, this.SyncRoot, dictionary, x => x.Key, transform, viewComparer);
|
|
||||||
}
|
}
|
||||||
|
|
||||||
class View<TView> : ISynchronizedView<KeyValuePair<TKey, TValue>, TView>
|
class View<TView> : ISynchronizedView<KeyValuePair<TKey, TValue>, TView>
|
||||||
|
@ -11,7 +11,7 @@ namespace ObservableCollections
|
|||||||
where TKey : notnull
|
where TKey : notnull
|
||||||
{
|
{
|
||||||
readonly Dictionary<TKey, TValue> dictionary;
|
readonly Dictionary<TKey, TValue> dictionary;
|
||||||
public readonly object SyncRoot = new object();
|
public object SyncRoot { get; } = new object();
|
||||||
|
|
||||||
public ObservableDictionary()
|
public ObservableDictionary()
|
||||||
{
|
{
|
||||||
|
@ -5,15 +5,6 @@ namespace ObservableCollections
|
|||||||
public sealed partial class ObservableHashSet<T> : IReadOnlyCollection<T>, IObservableCollection<T>
|
public sealed partial class ObservableHashSet<T> : IReadOnlyCollection<T>, IObservableCollection<T>
|
||||||
{
|
{
|
||||||
// TODO:
|
// TODO:
|
||||||
public ISynchronizedView<T, TView> CreateSortedView<TKey, TView>(Func<T, TKey> identitySelector, Func<T, TView> transform, IComparer<T> comparer) where TKey : notnull
|
|
||||||
{
|
|
||||||
throw new NotImplementedException();
|
|
||||||
}
|
|
||||||
|
|
||||||
public ISynchronizedView<T, TView> CreateSortedView<TKey, TView>(Func<T, TKey> identitySelector, Func<T, TView> transform, IComparer<TView> viewComparer) where TKey : notnull
|
|
||||||
{
|
|
||||||
throw new NotImplementedException();
|
|
||||||
}
|
|
||||||
|
|
||||||
public ISynchronizedView<T, TView> CreateView<TView>(Func<T, TView> transform, bool reverse = false)
|
public ISynchronizedView<T, TView> CreateView<TView>(Func<T, TView> transform, bool reverse = false)
|
||||||
{
|
{
|
||||||
|
@ -8,7 +8,7 @@ namespace ObservableCollections
|
|||||||
public sealed partial class ObservableHashSet<T> : IReadOnlySet<T>, IReadOnlyCollection<T>, IObservableCollection<T>
|
public sealed partial class ObservableHashSet<T> : IReadOnlySet<T>, IReadOnlyCollection<T>, IObservableCollection<T>
|
||||||
{
|
{
|
||||||
readonly HashSet<T> set;
|
readonly HashSet<T> set;
|
||||||
public readonly object SyncRoot = new object();
|
public object SyncRoot { get; } = new object();
|
||||||
|
|
||||||
public ObservableHashSet()
|
public ObservableHashSet()
|
||||||
{
|
{
|
||||||
|
@ -4,23 +4,13 @@ using System.Collections.Specialized;
|
|||||||
|
|
||||||
namespace ObservableCollections
|
namespace ObservableCollections
|
||||||
{
|
{
|
||||||
public sealed partial class ObservableLinkedList<T> : IReadOnlyCollection<T>, IObservableCollection<LinkedListNode<T>>
|
public sealed partial class ObservableLinkedList<T>
|
||||||
{
|
{
|
||||||
public ISynchronizedView<LinkedListNode<T>, TView> CreateView<TView>(Func<LinkedListNode<T>, TView> transform, bool reverse = false)
|
public ISynchronizedView<LinkedListNode<T>, TView> CreateView<TView>(Func<LinkedListNode<T>, TView> transform, bool reverse = false)
|
||||||
{
|
{
|
||||||
throw new NotImplementedException();
|
throw new NotImplementedException();
|
||||||
}
|
}
|
||||||
|
|
||||||
public ISynchronizedView<LinkedListNode<T>, TView> CreateSortedView<TKey, TView>(Func<LinkedListNode<T>, TKey> identitySelector, Func<LinkedListNode<T>, TView> transform, IComparer<LinkedListNode<T>> comparer) where TKey : notnull
|
|
||||||
{
|
|
||||||
throw new NotImplementedException();
|
|
||||||
}
|
|
||||||
|
|
||||||
public ISynchronizedView<LinkedListNode<T>, TView> CreateSortedView<TKey, TView>(Func<LinkedListNode<T>, TKey> identitySelector, Func<LinkedListNode<T>, TView> transform, IComparer<TView> viewComparer) where TKey : notnull
|
|
||||||
{
|
|
||||||
throw new NotImplementedException();
|
|
||||||
}
|
|
||||||
|
|
||||||
sealed class View<TView> : ISynchronizedView<LinkedListNode<T>, TView>
|
sealed class View<TView> : ISynchronizedView<LinkedListNode<T>, TView>
|
||||||
{
|
{
|
||||||
readonly ObservableLinkedList<T> source;
|
readonly ObservableLinkedList<T> source;
|
||||||
|
@ -8,7 +8,7 @@ namespace ObservableCollections
|
|||||||
public sealed partial class ObservableLinkedList<T> : IReadOnlyCollection<T>, IObservableCollection<LinkedListNode<T>>
|
public sealed partial class ObservableLinkedList<T> : IReadOnlyCollection<T>, IObservableCollection<LinkedListNode<T>>
|
||||||
{
|
{
|
||||||
readonly LinkedList<T> list;
|
readonly LinkedList<T> list;
|
||||||
public readonly object SyncRoot = new object();
|
public object SyncRoot { get; } = new object();
|
||||||
|
|
||||||
public event NotifyCollectionChangedEventHandler<LinkedListNode<T>>? CollectionChanged;
|
public event NotifyCollectionChangedEventHandler<LinkedListNode<T>>? CollectionChanged;
|
||||||
|
|
||||||
@ -126,11 +126,7 @@ namespace ObservableCollections
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
public IEnumerator<LinkedListNode<T>> GetEnumerator()
|
||||||
|
|
||||||
// TODO: GetEnumerator
|
|
||||||
|
|
||||||
public IEnumerator<T> GetEnumerator()
|
|
||||||
{
|
{
|
||||||
throw new NotImplementedException();
|
throw new NotImplementedException();
|
||||||
}
|
}
|
||||||
@ -139,5 +135,15 @@ namespace ObservableCollections
|
|||||||
{
|
{
|
||||||
throw new NotImplementedException();
|
throw new NotImplementedException();
|
||||||
}
|
}
|
||||||
|
|
||||||
|
IEnumerator<T> IEnumerable<T>.GetEnumerator()
|
||||||
|
{
|
||||||
|
throw new NotImplementedException();
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
// TODO: GetEnumerator
|
||||||
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -11,18 +11,6 @@ namespace ObservableCollections
|
|||||||
return new View<TView>(this, transform, reverse);
|
return new View<TView>(this, transform, reverse);
|
||||||
}
|
}
|
||||||
|
|
||||||
public ISynchronizedView<T, TView> CreateSortedView<TKey, TView>(Func<T, TKey> identitySelector, Func<T, TView> transform, IComparer<T> comparer)
|
|
||||||
where TKey : notnull
|
|
||||||
{
|
|
||||||
return new SortedView<T, TKey, TView>(this, SyncRoot, list, identitySelector, transform, comparer);
|
|
||||||
}
|
|
||||||
|
|
||||||
public ISynchronizedView<T, TView> CreateSortedView<TKey, TView>(Func<T, TKey> identitySelector, Func<T, TView> transform, IComparer<TView> viewComparer)
|
|
||||||
where TKey : notnull
|
|
||||||
{
|
|
||||||
return new SortedViewViewComparer<T, TKey, TView>(this, SyncRoot, list, identitySelector, transform, viewComparer);
|
|
||||||
}
|
|
||||||
|
|
||||||
class View<TView> : ISynchronizedView<T, TView>
|
class View<TView> : ISynchronizedView<T, TView>
|
||||||
{
|
{
|
||||||
readonly ObservableList<T> source;
|
readonly ObservableList<T> source;
|
||||||
|
@ -10,7 +10,7 @@ namespace ObservableCollections
|
|||||||
public sealed partial class ObservableList<T> : IList<T>, IReadOnlyList<T>, IObservableCollection<T>
|
public sealed partial class ObservableList<T> : IList<T>, IReadOnlyList<T>, IObservableCollection<T>
|
||||||
{
|
{
|
||||||
readonly List<T> list;
|
readonly List<T> list;
|
||||||
public readonly object SyncRoot = new object();
|
public object SyncRoot { get; } = new object();
|
||||||
|
|
||||||
public ObservableList()
|
public ObservableList()
|
||||||
{
|
{
|
||||||
|
@ -11,16 +11,6 @@ namespace ObservableCollections
|
|||||||
return new View<TView>(this, transform, reverse);
|
return new View<TView>(this, transform, reverse);
|
||||||
}
|
}
|
||||||
|
|
||||||
public ISynchronizedView<T, TView> CreateSortedView<TKey, TView>(Func<T, TKey> identitySelector, Func<T, TView> transform, IComparer<T> comparer) where TKey : notnull
|
|
||||||
{
|
|
||||||
return new SortedView<T, TKey, TView>(this, SyncRoot, queue, identitySelector, transform, comparer);
|
|
||||||
}
|
|
||||||
|
|
||||||
public ISynchronizedView<T, TView> CreateSortedView<TKey, TView>(Func<T, TKey> identitySelector, Func<T, TView> transform, IComparer<TView> viewComparer) where TKey : notnull
|
|
||||||
{
|
|
||||||
return new SortedViewViewComparer<T, TKey, TView>(this, SyncRoot, queue, identitySelector, transform, viewComparer);
|
|
||||||
}
|
|
||||||
|
|
||||||
class View<TView> : ISynchronizedView<T, TView>
|
class View<TView> : ISynchronizedView<T, TView>
|
||||||
{
|
{
|
||||||
readonly ObservableQueue<T> source;
|
readonly ObservableQueue<T> source;
|
||||||
|
@ -8,7 +8,7 @@ namespace ObservableCollections
|
|||||||
public sealed partial class ObservableQueue<T> : IReadOnlyCollection<T>, IObservableCollection<T>
|
public sealed partial class ObservableQueue<T> : IReadOnlyCollection<T>, IObservableCollection<T>
|
||||||
{
|
{
|
||||||
readonly Queue<T> queue;
|
readonly Queue<T> queue;
|
||||||
public readonly object SyncRoot = new object();
|
public object SyncRoot { get; } = new object();
|
||||||
|
|
||||||
public ObservableQueue()
|
public ObservableQueue()
|
||||||
{
|
{
|
||||||
|
@ -11,16 +11,6 @@ namespace ObservableCollections
|
|||||||
return new View<TView>(this, transform, reverse);
|
return new View<TView>(this, transform, reverse);
|
||||||
}
|
}
|
||||||
|
|
||||||
public ISynchronizedView<T, TView> CreateSortedView<TKey, TView>(Func<T, TKey> identitySelector, Func<T, TView> transform, IComparer<T> comparer) where TKey : notnull
|
|
||||||
{
|
|
||||||
return new SortedView<T, TKey, TView>(this, SyncRoot, stack, identitySelector, transform, comparer);
|
|
||||||
}
|
|
||||||
|
|
||||||
public ISynchronizedView<T, TView> CreateSortedView<TKey, TView>(Func<T, TKey> identitySelector, Func<T, TView> transform, IComparer<TView> viewComparer) where TKey : notnull
|
|
||||||
{
|
|
||||||
return new SortedViewViewComparer<T, TKey, TView>(this, SyncRoot, stack, identitySelector, transform, viewComparer);
|
|
||||||
}
|
|
||||||
|
|
||||||
class View<TView> : ISynchronizedView<T, TView>
|
class View<TView> : ISynchronizedView<T, TView>
|
||||||
{
|
{
|
||||||
readonly ObservableStack<T> source;
|
readonly ObservableStack<T> source;
|
||||||
|
@ -8,7 +8,7 @@ namespace ObservableCollections
|
|||||||
public sealed partial class ObservableStack<T> : IReadOnlyCollection<T>, IObservableCollection<T>
|
public sealed partial class ObservableStack<T> : IReadOnlyCollection<T>, IObservableCollection<T>
|
||||||
{
|
{
|
||||||
readonly Stack<T> stack;
|
readonly Stack<T> stack;
|
||||||
public readonly object SyncRoot = new object();
|
public object SyncRoot { get; } = new object();
|
||||||
|
|
||||||
public ObservableStack()
|
public ObservableStack()
|
||||||
{
|
{
|
||||||
|
Loading…
x
Reference in New Issue
Block a user