#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 : ILookup { private readonly IDictionary> _cache; private readonly IEqualityComparer _itemComparer; private readonly IEqualityComparer _keyComparer; private readonly ProgressiveSet _keysReadonly; private readonly Progressor> _progressor; public ProgressiveLookup(IEnumerable> wrapped) : this(wrapped, new NullAwareDictionary>(), null, null) { // Empty } public ProgressiveLookup(IEnumerable> wrapped, IEqualityComparer keyComparer) : this(wrapped, new NullAwareDictionary>(keyComparer), keyComparer, null) { // Empty } protected ProgressiveLookup(IEnumerable> wrapped, IDictionary> cache, IEqualityComparer keyComparer, IEqualityComparer itemComparer) { if (cache == null) { throw new ArgumentNullException("cache"); } _cache = cache; _progressor = new Progressor>(wrapped); _progressor.SubscribeAction(obj => _cache.Add(new KeyValuePair>(obj.Key, obj))); _keyComparer = keyComparer ?? EqualityComparer.Default; _itemComparer = itemComparer ?? EqualityComparer.Default; _keysReadonly = new ProgressiveSet(Progressor.CreateConverted(Progressor, input => input.Key), keyComparer); } protected ProgressiveLookup(Progressor> wrapped, IDictionary> cache, IEqualityComparer keyComparer, IEqualityComparer itemComparer) { if (cache == null) { throw new ArgumentNullException("cache"); } _cache = cache; _progressor = new Progressor>(wrapped); _progressor.SubscribeAction(obj => _cache.Add(new KeyValuePair>(obj.Key, obj))); _keyComparer = keyComparer ?? EqualityComparer.Default; _itemComparer = itemComparer ?? EqualityComparer.Default; _keysReadonly = new ProgressiveSet(Progressor.CreateConverted(Progressor, input => input.Key), keyComparer); } protected ProgressiveLookup(TryTake> tryTake, IDictionary> cache, IEqualityComparer keyComparer, IEqualityComparer itemComparer) { if (cache == null) { throw new ArgumentNullException("cache"); } _cache = cache; _progressor = new Progressor>(tryTake, false); // false because the underlaying structure may change _progressor.SubscribeAction(obj => _cache.Add(new KeyValuePair>(obj.Key, obj))); _keyComparer = keyComparer ?? EqualityComparer.Default; _itemComparer = itemComparer ?? EqualityComparer.Default; _keysReadonly = new ProgressiveSet(Progressor.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 Keys { get { return _keysReadonly; } } protected IEqualityComparer ItemComparer { get { return _itemComparer; } } protected IEqualityComparer KeyComparer { get { return _keyComparer; } } protected Progressor> Progressor { get { return _progressor; } } public IEnumerable this[TKey key] { get { IGrouping grouping; if (TryGetValue(key, out grouping)) { return grouping; } else { return ArrayReservoir.EmptyArray; } } } public static ProgressiveLookup Create(IEnumerable source, Func keySelector) { return new ProgressiveLookup(source.GroupProgressiveBy(keySelector)); } public static ProgressiveLookup Create(IEnumerable source, Func keySelector, IEqualityComparer keyComparer) { return new ProgressiveLookup(source.GroupProgressiveBy(keySelector, keyComparer), keyComparer); } public static ProgressiveLookup Create(IEnumerable source, Func keySelector, Func elementSelector, IEqualityComparer keyComparer) { return new ProgressiveLookup(source.GroupProgressiveBy(keySelector, elementSelector, keyComparer), keyComparer); } public static ProgressiveLookup Create(IEnumerable> source) { return new ProgressiveLookup(source.GroupProgressiveBy(item => item.Key, item => item.Value)); } public static ProgressiveLookup Create(IEnumerable> source, IEqualityComparer keyComparer) { return new ProgressiveLookup(source.GroupProgressiveBy(item => item.Key, item => item.Value, keyComparer), keyComparer); } public bool Contains(TKey key) { if (_cache.ContainsKey(key)) { return true; } else { IGrouping item; while (_progressor.TryTake(out item)) { if (_keyComparer.Equals(key, item.Key)) { return true; } } return false; } } public void CopyTo(KeyValuePair>[] array) { _progressor.AsEnumerable().Consume(); _cache.CopyTo(array, 0); } public void CopyTo(KeyValuePair>[] array, int arrayIndex) { _progressor.AsEnumerable().Consume(); _cache.CopyTo(array, arrayIndex); } public void CopyTo(KeyValuePair>[] 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[] array, int arrayIndex) { _progressor.AsEnumerable().Consume(); _cache.Values.CopyTo(array, arrayIndex); } public void CopyTo(IGrouping[] array) { _progressor.AsEnumerable().Consume(); _cache.Values.CopyTo(array, 0); } public void CopyTo(IGrouping[] array, int arrayIndex, int countLimit) { Extensions.CanCopyTo(array, arrayIndex, countLimit); _progressor.While(() => _cache.Count < countLimit).Consume(); _cache.Values.CopyTo(array, arrayIndex, countLimit); } public IEnumerator> GetEnumerator() { foreach (var item in _cache) { yield return item.Value; } { IGrouping 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 value) { if (_cache.TryGetValue(key, out value)) { return true; } IGrouping item; while (_progressor.TryTake(out item)) { if (_keyComparer.Equals(key, item.Key)) { value = item; return true; } } return false; } } } #endif