You can not select more than 25 topics
Topics must start with a letter or number, can include dashes ('-') and can be up to 35 characters long.
249 lines
9.0 KiB
249 lines
9.0 KiB
5 years ago
|
#if FAT
|
||
|
|
||
|
using System;
|
||
|
using System.Collections.Generic;
|
||
|
using System.Linq;
|
||
|
using LinqInternal.Collections.Specialized;
|
||
|
using LinqInternal.Collections.ThreadSafe;
|
||
|
using LinqInternal.Core;
|
||
|
|
||
|
namespace LinqInternal.Collections
|
||
|
{
|
||
|
[Serializable]
|
||
|
[System.Diagnostics.DebuggerNonUserCode]
|
||
|
internal class ProgressiveLookup<TKey, T> : ILookup<TKey, T>
|
||
|
{
|
||
|
private readonly IDictionary<TKey, IGrouping<TKey, T>> _cache;
|
||
|
private readonly IEqualityComparer<T> _itemComparer;
|
||
|
private readonly IEqualityComparer<TKey> _keyComparer;
|
||
|
private readonly ProgressiveSet<TKey> _keysReadonly;
|
||
|
private readonly Progressor<IGrouping<TKey, T>> _progressor;
|
||
|
|
||
|
public ProgressiveLookup(IEnumerable<IGrouping<TKey, T>> wrapped)
|
||
|
: this(wrapped, new NullAwareDictionary<TKey, IGrouping<TKey, T>>(), null, null)
|
||
|
{
|
||
|
// Empty
|
||
|
}
|
||
|
|
||
|
public ProgressiveLookup(IEnumerable<IGrouping<TKey, T>> wrapped, IEqualityComparer<TKey> keyComparer)
|
||
|
: this(wrapped, new NullAwareDictionary<TKey, IGrouping<TKey, T>>(keyComparer), keyComparer, null)
|
||
|
{
|
||
|
// Empty
|
||
|
}
|
||
|
|
||
|
protected ProgressiveLookup(IEnumerable<IGrouping<TKey, T>> wrapped, IDictionary<TKey, IGrouping<TKey, T>> cache, IEqualityComparer<TKey> keyComparer, IEqualityComparer<T> itemComparer)
|
||
|
{
|
||
|
if (cache == null)
|
||
|
{
|
||
|
throw new ArgumentNullException("cache");
|
||
|
}
|
||
|
_cache = cache;
|
||
|
_progressor = new Progressor<IGrouping<TKey, T>>(wrapped);
|
||
|
_progressor.SubscribeAction(obj => _cache.Add(new KeyValuePair<TKey, IGrouping<TKey, T>>(obj.Key, obj)));
|
||
|
_keyComparer = keyComparer ?? EqualityComparer<TKey>.Default;
|
||
|
_itemComparer = itemComparer ?? EqualityComparer<T>.Default;
|
||
|
_keysReadonly = new ProgressiveSet<TKey>(Progressor<TKey>.CreateConverted(Progressor, input => input.Key), keyComparer);
|
||
|
}
|
||
|
|
||
|
protected ProgressiveLookup(Progressor<IGrouping<TKey, T>> wrapped, IDictionary<TKey, IGrouping<TKey, T>> cache, IEqualityComparer<TKey> keyComparer, IEqualityComparer<T> itemComparer)
|
||
|
{
|
||
|
if (cache == null)
|
||
|
{
|
||
|
throw new ArgumentNullException("cache");
|
||
|
}
|
||
|
_cache = cache;
|
||
|
_progressor = new Progressor<IGrouping<TKey, T>>(wrapped);
|
||
|
_progressor.SubscribeAction(obj => _cache.Add(new KeyValuePair<TKey, IGrouping<TKey, T>>(obj.Key, obj)));
|
||
|
_keyComparer = keyComparer ?? EqualityComparer<TKey>.Default;
|
||
|
_itemComparer = itemComparer ?? EqualityComparer<T>.Default;
|
||
|
_keysReadonly = new ProgressiveSet<TKey>(Progressor<TKey>.CreateConverted(Progressor, input => input.Key), keyComparer);
|
||
|
}
|
||
|
|
||
|
protected ProgressiveLookup(TryTake<IGrouping<TKey, T>> tryTake, IDictionary<TKey, IGrouping<TKey, T>> cache, IEqualityComparer<TKey> keyComparer, IEqualityComparer<T> itemComparer)
|
||
|
{
|
||
|
if (cache == null)
|
||
|
{
|
||
|
throw new ArgumentNullException("cache");
|
||
|
}
|
||
|
_cache = cache;
|
||
|
_progressor = new Progressor<IGrouping<TKey, T>>(tryTake, false); // false because the underlaying structure may change
|
||
|
_progressor.SubscribeAction(obj => _cache.Add(new KeyValuePair<TKey, IGrouping<TKey, T>>(obj.Key, obj)));
|
||
|
_keyComparer = keyComparer ?? EqualityComparer<TKey>.Default;
|
||
|
_itemComparer = itemComparer ?? EqualityComparer<T>.Default;
|
||
|
_keysReadonly = new ProgressiveSet<TKey>(Progressor<TKey>.CreateConverted(Progressor, input => input.Key), keyComparer);
|
||
|
}
|
||
|
|
||
|
public int Count
|
||
|
{
|
||
|
get
|
||
|
{
|
||
|
_progressor.AsEnumerable().Consume();
|
||
|
return _cache.Count;
|
||
|
}
|
||
|
}
|
||
|
|
||
|
public bool EndOfEnumeration
|
||
|
{
|
||
|
get { return _progressor.IsClosed; }
|
||
|
}
|
||
|
|
||
|
public IReadOnlyCollection<TKey> Keys
|
||
|
{
|
||
|
get { return _keysReadonly; }
|
||
|
}
|
||
|
|
||
|
protected IEqualityComparer<T> ItemComparer
|
||
|
{
|
||
|
get { return _itemComparer; }
|
||
|
}
|
||
|
|
||
|
protected IEqualityComparer<TKey> KeyComparer
|
||
|
{
|
||
|
get { return _keyComparer; }
|
||
|
}
|
||
|
|
||
|
protected Progressor<IGrouping<TKey, T>> Progressor
|
||
|
{
|
||
|
get { return _progressor; }
|
||
|
}
|
||
|
|
||
|
public IEnumerable<T> this[TKey key]
|
||
|
{
|
||
|
get
|
||
|
{
|
||
|
IGrouping<TKey, T> grouping;
|
||
|
if (TryGetValue(key, out grouping))
|
||
|
{
|
||
|
return grouping;
|
||
|
}
|
||
|
else
|
||
|
{
|
||
|
return ArrayReservoir<T>.EmptyArray;
|
||
|
}
|
||
|
}
|
||
|
}
|
||
|
|
||
|
public static ProgressiveLookup<TKey, T> Create(IEnumerable<T> source, Func<T, TKey> keySelector)
|
||
|
{
|
||
|
return new ProgressiveLookup<TKey, T>(source.GroupProgressiveBy(keySelector));
|
||
|
}
|
||
|
|
||
|
public static ProgressiveLookup<TKey, T> Create(IEnumerable<T> source, Func<T, TKey> keySelector, IEqualityComparer<TKey> keyComparer)
|
||
|
{
|
||
|
return new ProgressiveLookup<TKey, T>(source.GroupProgressiveBy(keySelector, keyComparer), keyComparer);
|
||
|
}
|
||
|
|
||
|
public static ProgressiveLookup<TKey, T> Create<TSource>(IEnumerable<TSource> source, Func<TSource, TKey> keySelector, Func<TSource, T> elementSelector, IEqualityComparer<TKey> keyComparer)
|
||
|
{
|
||
|
return new ProgressiveLookup<TKey, T>(source.GroupProgressiveBy(keySelector, elementSelector, keyComparer), keyComparer);
|
||
|
}
|
||
|
|
||
|
public static ProgressiveLookup<TKey, T> Create(IEnumerable<KeyValuePair<TKey, T>> source)
|
||
|
{
|
||
|
return new ProgressiveLookup<TKey, T>(source.GroupProgressiveBy(item => item.Key, item => item.Value));
|
||
|
}
|
||
|
|
||
|
public static ProgressiveLookup<TKey, T> Create(IEnumerable<KeyValuePair<TKey, T>> source, IEqualityComparer<TKey> keyComparer)
|
||
|
{
|
||
|
return new ProgressiveLookup<TKey, T>(source.GroupProgressiveBy(item => item.Key, item => item.Value, keyComparer), keyComparer);
|
||
|
}
|
||
|
|
||
|
public bool Contains(TKey key)
|
||
|
{
|
||
|
if (_cache.ContainsKey(key))
|
||
|
{
|
||
|
return true;
|
||
|
}
|
||
|
else
|
||
|
{
|
||
|
IGrouping<TKey, T> item;
|
||
|
while (_progressor.TryTake(out item))
|
||
|
{
|
||
|
if (_keyComparer.Equals(key, item.Key))
|
||
|
{
|
||
|
return true;
|
||
|
}
|
||
|
}
|
||
|
return false;
|
||
|
}
|
||
|
}
|
||
|
|
||
|
public void CopyTo(KeyValuePair<TKey, IGrouping<TKey, T>>[] array)
|
||
|
{
|
||
|
_progressor.AsEnumerable().Consume();
|
||
|
_cache.CopyTo(array, 0);
|
||
|
}
|
||
|
|
||
|
public void CopyTo(KeyValuePair<TKey, IGrouping<TKey, T>>[] array, int arrayIndex)
|
||
|
{
|
||
|
_progressor.AsEnumerable().Consume();
|
||
|
_cache.CopyTo(array, arrayIndex);
|
||
|
}
|
||
|
|
||
|
public void CopyTo(KeyValuePair<TKey, IGrouping<TKey, T>>[] array, int arrayIndex, int countLimit)
|
||
|
{
|
||
|
Extensions.CanCopyTo(array, arrayIndex, countLimit);
|
||
|
_progressor.While(() => _cache.Count < countLimit).Consume();
|
||
|
_cache.CopyTo(array, arrayIndex, countLimit);
|
||
|
}
|
||
|
|
||
|
public void CopyTo(IGrouping<TKey, T>[] array, int arrayIndex)
|
||
|
{
|
||
|
_progressor.AsEnumerable().Consume();
|
||
|
_cache.Values.CopyTo(array, arrayIndex);
|
||
|
}
|
||
|
|
||
|
public void CopyTo(IGrouping<TKey, T>[] array)
|
||
|
{
|
||
|
_progressor.AsEnumerable().Consume();
|
||
|
_cache.Values.CopyTo(array, 0);
|
||
|
}
|
||
|
|
||
|
public void CopyTo(IGrouping<TKey, T>[] array, int arrayIndex, int countLimit)
|
||
|
{
|
||
|
Extensions.CanCopyTo(array, arrayIndex, countLimit);
|
||
|
_progressor.While(() => _cache.Count < countLimit).Consume();
|
||
|
_cache.Values.CopyTo(array, arrayIndex, countLimit);
|
||
|
}
|
||
|
|
||
|
public IEnumerator<IGrouping<TKey, T>> GetEnumerator()
|
||
|
{
|
||
|
foreach (var item in _cache)
|
||
|
{
|
||
|
yield return item.Value;
|
||
|
}
|
||
|
{
|
||
|
IGrouping<TKey, T> item;
|
||
|
while (_progressor.TryTake(out item))
|
||
|
{
|
||
|
yield return item;
|
||
|
}
|
||
|
}
|
||
|
}
|
||
|
|
||
|
System.Collections.IEnumerator System.Collections.IEnumerable.GetEnumerator()
|
||
|
{
|
||
|
return GetEnumerator();
|
||
|
}
|
||
|
|
||
|
public bool TryGetValue(TKey key, out IGrouping<TKey, T> value)
|
||
|
{
|
||
|
if (_cache.TryGetValue(key, out value))
|
||
|
{
|
||
|
return true;
|
||
|
}
|
||
|
IGrouping<TKey, T> item;
|
||
|
while (_progressor.TryTake(out item))
|
||
|
{
|
||
|
if (_keyComparer.Equals(key, item.Key))
|
||
|
{
|
||
|
value = item;
|
||
|
return true;
|
||
|
}
|
||
|
}
|
||
|
return false;
|
||
|
}
|
||
|
}
|
||
|
}
|
||
|
|
||
|
#endif
|