Created
August 21, 2018 11:00
-
-
Save friuns2/1c54f0d0ba204da5b04a8a63f4f8684a to your computer and use it in GitHub Desktop.
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
using System; | |
using System.Collections.Generic; | |
using System.Linq; | |
using System.Text; | |
using System.Collections.Specialized; | |
namespace ContinuousLinq.Collections | |
{ | |
public class KeyEqualityComparer<T> : IEqualityComparer<T> | |
{ | |
private readonly Func<T, object> keyExtractor; | |
public KeyEqualityComparer(Func<T,object> keyExtractor) | |
{ | |
this.keyExtractor = keyExtractor; | |
} | |
public bool Equals(T x, T y) | |
{ | |
return this.keyExtractor(x).Equals(this.keyExtractor(y)); | |
} | |
public int GetHashCode(T obj) | |
{ | |
return this.keyExtractor(obj).GetHashCode(); | |
} | |
} | |
internal class DistinctReadOnlyContinuousCollection<TSource> : ReadOnlyAdapterContinuousCollection<TSource, TSource> | |
{ | |
public ReferenceCountTracker<TSource> ReferenceCountTracker { get; set; } | |
public List<TSource> Output { get; set; } | |
public DistinctReadOnlyContinuousCollection(IList<TSource> list, Func<TSource, object> keyExtractor= null) | |
: base(list) | |
{ | |
this.Output = new List<TSource>(); | |
this.ReferenceCountTracker = keyExtractor == null ? new ReferenceCountTracker<TSource>() : new ReferenceCountTracker<TSource>(new KeyEqualityComparer<TSource>(keyExtractor)); | |
this.NotifyCollectionChangedMonitor.Add += OnAdd; | |
this.NotifyCollectionChangedMonitor.Remove += OnRemove; | |
this.NotifyCollectionChangedMonitor.Reset += OnReset; | |
this.NotifyCollectionChangedMonitor.Replace += OnReplace; | |
int index = 0; | |
AddValues(this.Source, out index); | |
} | |
public override int Count | |
{ | |
get { return this.Output.Count; } | |
} | |
public override TSource this[int index] | |
{ | |
get { return this.Output[index]; } | |
set { throw new AccessViolationException(); } | |
} | |
private List<TSource> AddValues(IEnumerable<TSource> newItems, out int index) | |
{ | |
index = -1; | |
List<TSource> newlyAddedItems = null; | |
foreach (TSource item in newItems) | |
{ | |
if (this.ReferenceCountTracker.Add(item)) | |
{ | |
if (newlyAddedItems == null) | |
{ | |
newlyAddedItems = new List<TSource>(); | |
index = this.Output.Count; | |
} | |
this.Output.Add(item); | |
newlyAddedItems.Add(item); | |
} | |
} | |
return newlyAddedItems; | |
} | |
private List<TSource> RemoveValues(IEnumerable<TSource> oldItems, out int index) | |
{ | |
index = -1; | |
List<TSource> removedItems = null; | |
foreach (TSource item in oldItems) | |
{ | |
if (this.ReferenceCountTracker.Remove(item)) | |
{ | |
if (removedItems == null) | |
{ | |
removedItems = new List<TSource>(); | |
index = this.Output.IndexOf(item); | |
} | |
this.Output.Remove(item); | |
removedItems.Add(item); | |
} | |
} | |
return removedItems; | |
} | |
void OnAdd(object sender, int index, IEnumerable<TSource> newItems) | |
{ | |
AddItemsAndNotifyCollectionChanged(newItems); | |
} | |
private void AddItemsAndNotifyCollectionChanged(IEnumerable<TSource> newItems) | |
{ | |
int indexInOutput; | |
List<TSource> newlyAddedItems = AddValues(newItems, out indexInOutput); | |
if (newlyAddedItems != null) | |
{ | |
FireAdd(newlyAddedItems, indexInOutput); | |
} | |
} | |
void OnRemove(object sender, int index, IEnumerable<TSource> oldItems) | |
{ | |
RemoveItemsAndNotifyCollectionChanged(oldItems); | |
} | |
private void RemoveItemsAndNotifyCollectionChanged(IEnumerable<TSource> oldItems) | |
{ | |
int indexInOutput; | |
List<TSource> removedItems = RemoveValues(oldItems, out indexInOutput); | |
if (removedItems != null) | |
{ | |
FireRemove(removedItems, indexInOutput); | |
} | |
} | |
void OnReset(object sender) | |
{ | |
this.Output.Clear(); | |
this.ReferenceCountTracker.Clear(); | |
int indexInOutput; | |
AddValues(this.Source, out indexInOutput); | |
FireReset(); | |
} | |
void OnReplace(object sender, IEnumerable<TSource> oldItems, int newStartingIndex, IEnumerable<TSource> newItems) | |
{ | |
AddItemsAndNotifyCollectionChanged(newItems); | |
RemoveItemsAndNotifyCollectionChanged(oldItems); | |
} | |
} | |
} |
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment