using System; using System.Collections.Concurrent; using System.Collections.Generic; using System.Collections.ObjectModel; using System.Diagnostics; using System.Diagnostics.CodeAnalysis; using System.Diagnostics.Tracing; using System.Globalization; using System.Reflection; using System.Resources; using System.Runtime.CompilerServices; using System.Runtime.InteropServices; using System.Runtime.Versioning; using System.Threading; using FxResources.System.Collections.Concurrent; using Microsoft.CodeAnalysis; [assembly: CompilationRelaxations(8)] [assembly: RuntimeCompatibility(WrapNonExceptionThrows = true)] [assembly: Debuggable(DebuggableAttribute.DebuggingModes.IgnoreSymbolStoreSequencePoints)] [assembly: TargetFramework(".NETCoreApp,Version=v6.0", FrameworkDisplayName = "")] [assembly: CLSCompliant(true)] [assembly: DefaultDllImportSearchPaths(DllImportSearchPath.System32 | DllImportSearchPath.AssemblyDirectory)] [assembly: AssemblyDefaultAlias("System.Collections.Concurrent")] [assembly: NeutralResourcesLanguage("en-US")] [assembly: AssemblyMetadata(".NETFrameworkAssembly", "")] [assembly: AssemblyMetadata("Serviceable", "True")] [assembly: AssemblyMetadata("PreferInbox", "True")] [assembly: AssemblyMetadata("IsTrimmable", "True")] [assembly: AssemblyCompany("Microsoft Corporation")] [assembly: AssemblyCopyright("© Microsoft Corporation. All rights reserved.")] [assembly: AssemblyDescription("System.Collections.Concurrent")] [assembly: AssemblyFileVersion("6.0.722.32202")] [assembly: AssemblyInformationalVersion("6.0.7+0ec02c8c96e2eda06dc5b5edfdbdba0f36415082")] [assembly: AssemblyProduct("Microsoft® .NET")] [assembly: AssemblyTitle("System.Collections.Concurrent")] [assembly: AssemblyMetadata("RepositoryUrl", "https://github.com/dotnet/runtime")] [assembly: AssemblyVersion("6.0.0.0")] [assembly: TypeForwardedTo(typeof(ConcurrentQueue<>))] [assembly: TypeForwardedTo(typeof(IProducerConsumerCollection<>))] [module: System.Runtime.CompilerServices.NullablePublicOnly(false)] [module: SkipLocalsInit] namespace Microsoft.CodeAnalysis { [CompilerGenerated] [Microsoft.CodeAnalysis.Embedded] internal sealed class EmbeddedAttribute : Attribute { } } namespace System.Runtime.CompilerServices { [CompilerGenerated] [Microsoft.CodeAnalysis.Embedded] [AttributeUsage(AttributeTargets.Class | AttributeTargets.Property | AttributeTargets.Field | AttributeTargets.Event | AttributeTargets.Parameter | AttributeTargets.ReturnValue | AttributeTargets.GenericParameter, AllowMultiple = false, Inherited = false)] internal sealed class NullableAttribute : Attribute { public readonly byte[] NullableFlags; public NullableAttribute(byte P_0) { NullableFlags = new byte[1] { P_0 }; } public NullableAttribute(byte[] P_0) { NullableFlags = P_0; } } [CompilerGenerated] [Microsoft.CodeAnalysis.Embedded] [AttributeUsage(AttributeTargets.Class | AttributeTargets.Struct | AttributeTargets.Method | AttributeTargets.Interface | AttributeTargets.Delegate, AllowMultiple = false, Inherited = false)] internal sealed class NullableContextAttribute : Attribute { public readonly byte Flag; public NullableContextAttribute(byte P_0) { Flag = P_0; } } [CompilerGenerated] [Microsoft.CodeAnalysis.Embedded] [AttributeUsage(AttributeTargets.Module, AllowMultiple = false, Inherited = false)] internal sealed class NullablePublicOnlyAttribute : Attribute { public readonly bool IncludesInternals; public NullablePublicOnlyAttribute(bool P_0) { IncludesInternals = P_0; } } } namespace FxResources.System.Collections.Concurrent { internal static class SR { } } namespace System { internal static class ThrowHelper { [DoesNotReturn] internal static void ThrowKeyNullException() { ThrowArgumentNullException("key"); } [DoesNotReturn] internal static void ThrowArgumentNullException(string name) { throw new ArgumentNullException(name); } [DoesNotReturn] internal static void ThrowArgumentNullException(string name, string message) { throw new ArgumentNullException(name, message); } [DoesNotReturn] internal static void ThrowValueNullException() { throw new ArgumentException(System.SR.ConcurrentDictionary_TypeOfValueIncorrect); } [DoesNotReturn] internal static void ThrowOutOfMemoryException() { throw new OutOfMemoryException(); } } internal static class SR { private static readonly bool s_usingResourceKeys = AppContext.TryGetSwitch("System.Resources.UseSystemResourceKeys", out var isEnabled) && isEnabled; private static ResourceManager s_resourceManager; internal static ResourceManager ResourceManager => s_resourceManager ?? (s_resourceManager = new ResourceManager(typeof(SR))); internal static string BlockingCollection_Add_ConcurrentCompleteAdd => GetResourceString("BlockingCollection_Add_ConcurrentCompleteAdd"); internal static string BlockingCollection_Add_Failed => GetResourceString("BlockingCollection_Add_Failed"); internal static string BlockingCollection_CantAddAnyWhenCompleted => GetResourceString("BlockingCollection_CantAddAnyWhenCompleted"); internal static string BlockingCollection_CantTakeAnyWhenAllDone => GetResourceString("BlockingCollection_CantTakeAnyWhenAllDone"); internal static string BlockingCollection_CantTakeWhenDone => GetResourceString("BlockingCollection_CantTakeWhenDone"); internal static string BlockingCollection_Completed => GetResourceString("BlockingCollection_Completed"); internal static string BlockingCollection_CopyTo_IncorrectType => GetResourceString("BlockingCollection_CopyTo_IncorrectType"); internal static string BlockingCollection_CopyTo_MultiDim => GetResourceString("BlockingCollection_CopyTo_MultiDim"); internal static string BlockingCollection_CopyTo_NonNegative => GetResourceString("BlockingCollection_CopyTo_NonNegative"); internal static string Collection_CopyTo_TooManyElems => GetResourceString("Collection_CopyTo_TooManyElems"); internal static string BlockingCollection_ctor_BoundedCapacityRange => GetResourceString("BlockingCollection_ctor_BoundedCapacityRange"); internal static string BlockingCollection_ctor_CountMoreThanCapacity => GetResourceString("BlockingCollection_ctor_CountMoreThanCapacity"); internal static string BlockingCollection_Disposed => GetResourceString("BlockingCollection_Disposed"); internal static string BlockingCollection_Take_CollectionModified => GetResourceString("BlockingCollection_Take_CollectionModified"); internal static string BlockingCollection_TimeoutInvalid => GetResourceString("BlockingCollection_TimeoutInvalid"); internal static string BlockingCollection_ValidateCollectionsArray_DispElems => GetResourceString("BlockingCollection_ValidateCollectionsArray_DispElems"); internal static string BlockingCollection_ValidateCollectionsArray_LargeSize => GetResourceString("BlockingCollection_ValidateCollectionsArray_LargeSize"); internal static string BlockingCollection_ValidateCollectionsArray_NullElems => GetResourceString("BlockingCollection_ValidateCollectionsArray_NullElems"); internal static string BlockingCollection_ValidateCollectionsArray_ZeroSize => GetResourceString("BlockingCollection_ValidateCollectionsArray_ZeroSize"); internal static string ConcurrentBag_Ctor_ArgumentNullException => GetResourceString("ConcurrentBag_Ctor_ArgumentNullException"); internal static string ConcurrentBag_CopyTo_ArgumentNullException => GetResourceString("ConcurrentBag_CopyTo_ArgumentNullException"); internal static string Collection_CopyTo_ArgumentOutOfRangeException => GetResourceString("Collection_CopyTo_ArgumentOutOfRangeException"); internal static string ConcurrentCollection_SyncRoot_NotSupported => GetResourceString("ConcurrentCollection_SyncRoot_NotSupported"); internal static string ConcurrentDictionary_ArrayIncorrectType => GetResourceString("ConcurrentDictionary_ArrayIncorrectType"); internal static string ConcurrentDictionary_SourceContainsDuplicateKeys => GetResourceString("ConcurrentDictionary_SourceContainsDuplicateKeys"); internal static string ConcurrentDictionary_ConcurrencyLevelMustBePositive => GetResourceString("ConcurrentDictionary_ConcurrencyLevelMustBePositive"); internal static string ConcurrentDictionary_CapacityMustNotBeNegative => GetResourceString("ConcurrentDictionary_CapacityMustNotBeNegative"); internal static string ConcurrentDictionary_IndexIsNegative => GetResourceString("ConcurrentDictionary_IndexIsNegative"); internal static string ConcurrentDictionary_ArrayNotLargeEnough => GetResourceString("ConcurrentDictionary_ArrayNotLargeEnough"); internal static string ConcurrentDictionary_KeyAlreadyExisted => GetResourceString("ConcurrentDictionary_KeyAlreadyExisted"); internal static string ConcurrentDictionary_ItemKeyIsNull => GetResourceString("ConcurrentDictionary_ItemKeyIsNull"); internal static string ConcurrentDictionary_TypeOfKeyIncorrect => GetResourceString("ConcurrentDictionary_TypeOfKeyIncorrect"); internal static string ConcurrentDictionary_TypeOfValueIncorrect => GetResourceString("ConcurrentDictionary_TypeOfValueIncorrect"); internal static string ConcurrentStack_PushPopRange_CountOutOfRange => GetResourceString("ConcurrentStack_PushPopRange_CountOutOfRange"); internal static string ConcurrentStack_PushPopRange_InvalidCount => GetResourceString("ConcurrentStack_PushPopRange_InvalidCount"); internal static string ConcurrentStack_PushPopRange_StartOutOfRange => GetResourceString("ConcurrentStack_PushPopRange_StartOutOfRange"); internal static string Partitioner_DynamicPartitionsNotSupported => GetResourceString("Partitioner_DynamicPartitionsNotSupported"); internal static string PartitionerStatic_CanNotCallGetEnumeratorAfterSourceHasBeenDisposed => GetResourceString("PartitionerStatic_CanNotCallGetEnumeratorAfterSourceHasBeenDisposed"); internal static string PartitionerStatic_CurrentCalledBeforeMoveNext => GetResourceString("PartitionerStatic_CurrentCalledBeforeMoveNext"); internal static string ConcurrentBag_Enumerator_EnumerationNotStartedOrAlreadyFinished => GetResourceString("ConcurrentBag_Enumerator_EnumerationNotStartedOrAlreadyFinished"); internal static string Arg_KeyNotFoundWithKey => GetResourceString("Arg_KeyNotFoundWithKey"); private static bool UsingResourceKeys() { return s_usingResourceKeys; } internal static string GetResourceString(string resourceKey) { if (UsingResourceKeys()) { return resourceKey; } string result = null; try { result = ResourceManager.GetString(resourceKey); } catch (MissingManifestResourceException) { } return result; } internal static string Format(string resourceFormat, object p1) { if (UsingResourceKeys()) { return string.Join(", ", resourceFormat, p1); } return string.Format(resourceFormat, p1); } internal static string Format(IFormatProvider provider, string resourceFormat, object p1) { if (UsingResourceKeys()) { return string.Join(", ", resourceFormat, p1); } return string.Format(provider, resourceFormat, p1); } } } namespace System.Collections { internal static class HashHelpers { [MethodImpl(MethodImplOptions.AggressiveInlining)] public static uint FastMod(uint value, uint divisor, ulong multiplier) { return (uint)(((multiplier * value >> 32) + 1) * divisor >> 32); } } } namespace System.Collections.Concurrent { [UnsupportedOSPlatform("browser")] [DebuggerTypeProxy(typeof(BlockingCollectionDebugView<>))] [DebuggerDisplay("Count = {Count}, Type = {_collection}")] public class BlockingCollection : IEnumerable, IEnumerable, ICollection, IDisposable, IReadOnlyCollection { private IProducerConsumerCollection _collection; private int _boundedCapacity; private SemaphoreSlim _freeNodes; private SemaphoreSlim _occupiedNodes; private bool _isDisposed; private CancellationTokenSource _consumersCancellationTokenSource; private CancellationTokenSource _producersCancellationTokenSource; private volatile int _currentAdders; public int BoundedCapacity { get { CheckDisposed(); return _boundedCapacity; } } public bool IsAddingCompleted { get { CheckDisposed(); return _currentAdders == int.MinValue; } } public bool IsCompleted { get { CheckDisposed(); if (IsAddingCompleted) { return _occupiedNodes.CurrentCount == 0; } return false; } } public int Count { get { CheckDisposed(); return _occupiedNodes.CurrentCount; } } bool ICollection.IsSynchronized { get { CheckDisposed(); return false; } } object ICollection.SyncRoot { get { throw new NotSupportedException(System.SR.ConcurrentCollection_SyncRoot_NotSupported); } } public BlockingCollection() : this((IProducerConsumerCollection)new ConcurrentQueue()) { } public BlockingCollection(int boundedCapacity) : this((IProducerConsumerCollection)new ConcurrentQueue(), boundedCapacity) { } public BlockingCollection(IProducerConsumerCollection collection, int boundedCapacity) { if (boundedCapacity < 1) { throw new ArgumentOutOfRangeException("boundedCapacity", boundedCapacity, System.SR.BlockingCollection_ctor_BoundedCapacityRange); } if (collection == null) { throw new ArgumentNullException("collection"); } int count = collection.Count; if (count > boundedCapacity) { throw new ArgumentException(System.SR.BlockingCollection_ctor_CountMoreThanCapacity); } Initialize(collection, boundedCapacity, count); } public BlockingCollection(IProducerConsumerCollection collection) { if (collection == null) { throw new ArgumentNullException("collection"); } Initialize(collection, -1, collection.Count); } [MemberNotNull("_collection")] [MemberNotNull("_consumersCancellationTokenSource")] [MemberNotNull("_producersCancellationTokenSource")] [MemberNotNull("_occupiedNodes")] private void Initialize(IProducerConsumerCollection collection, int boundedCapacity, int collectionCount) { _collection = collection; _boundedCapacity = boundedCapacity; _isDisposed = false; _consumersCancellationTokenSource = new CancellationTokenSource(); _producersCancellationTokenSource = new CancellationTokenSource(); if (boundedCapacity == -1) { _freeNodes = null; } else { _freeNodes = new SemaphoreSlim(boundedCapacity - collectionCount); } _occupiedNodes = new SemaphoreSlim(collectionCount); } public void Add(T item) { TryAddWithNoTimeValidation(item, -1, CancellationToken.None); } public void Add(T item, CancellationToken cancellationToken) { TryAddWithNoTimeValidation(item, -1, cancellationToken); } public bool TryAdd(T item) { return TryAddWithNoTimeValidation(item, 0, CancellationToken.None); } public bool TryAdd(T item, TimeSpan timeout) { ValidateTimeout(timeout); return TryAddWithNoTimeValidation(item, (int)timeout.TotalMilliseconds, CancellationToken.None); } public bool TryAdd(T item, int millisecondsTimeout) { ValidateMillisecondsTimeout(millisecondsTimeout); return TryAddWithNoTimeValidation(item, millisecondsTimeout, CancellationToken.None); } public bool TryAdd(T item, int millisecondsTimeout, CancellationToken cancellationToken) { ValidateMillisecondsTimeout(millisecondsTimeout); return TryAddWithNoTimeValidation(item, millisecondsTimeout, cancellationToken); } private bool TryAddWithNoTimeValidation(T item, int millisecondsTimeout, CancellationToken cancellationToken) { CheckDisposed(); cancellationToken.ThrowIfCancellationRequested(); if (IsAddingCompleted) { throw new InvalidOperationException(System.SR.BlockingCollection_Completed); } bool flag = true; if (_freeNodes != null) { CancellationTokenSource cancellationTokenSource = null; try { flag = _freeNodes.Wait(0, default(CancellationToken)); if (!flag && millisecondsTimeout != 0) { cancellationTokenSource = CancellationTokenSource.CreateLinkedTokenSource(cancellationToken, _producersCancellationTokenSource.Token); flag = _freeNodes.Wait(millisecondsTimeout, cancellationTokenSource.Token); } } catch (OperationCanceledException) { cancellationToken.ThrowIfCancellationRequested(); throw new InvalidOperationException(System.SR.BlockingCollection_Add_ConcurrentCompleteAdd); } finally { cancellationTokenSource?.Dispose(); } } if (flag) { SpinWait spinWait = default(SpinWait); while (true) { int currentAdders = _currentAdders; if (((uint)currentAdders & 0x80000000u) != 0) { spinWait.Reset(); while (_currentAdders != int.MinValue) { spinWait.SpinOnce(); } throw new InvalidOperationException(System.SR.BlockingCollection_Completed); } if (Interlocked.CompareExchange(ref _currentAdders, currentAdders + 1, currentAdders) == currentAdders) { break; } spinWait.SpinOnce(-1); } try { bool flag2 = false; try { cancellationToken.ThrowIfCancellationRequested(); flag2 = _collection.TryAdd(item); } catch { if (_freeNodes != null) { _freeNodes.Release(); } throw; } if (!flag2) { throw new InvalidOperationException(System.SR.BlockingCollection_Add_Failed); } _occupiedNodes.Release(); } finally { Interlocked.Decrement(ref _currentAdders); } } return flag; } public T Take() { if (!TryTake(out var item, -1, CancellationToken.None)) { throw new InvalidOperationException(System.SR.BlockingCollection_CantTakeWhenDone); } return item; } public T Take(CancellationToken cancellationToken) { if (!TryTake(out var item, -1, cancellationToken)) { throw new InvalidOperationException(System.SR.BlockingCollection_CantTakeWhenDone); } return item; } public bool TryTake([MaybeNullWhen(false)] out T item) { return TryTake(out item, 0, CancellationToken.None); } public bool TryTake([MaybeNullWhen(false)] out T item, TimeSpan timeout) { ValidateTimeout(timeout); return TryTakeWithNoTimeValidation(out item, (int)timeout.TotalMilliseconds, CancellationToken.None, null); } public bool TryTake([MaybeNullWhen(false)] out T item, int millisecondsTimeout) { ValidateMillisecondsTimeout(millisecondsTimeout); return TryTakeWithNoTimeValidation(out item, millisecondsTimeout, CancellationToken.None, null); } public bool TryTake([MaybeNullWhen(false)] out T item, int millisecondsTimeout, CancellationToken cancellationToken) { ValidateMillisecondsTimeout(millisecondsTimeout); return TryTakeWithNoTimeValidation(out item, millisecondsTimeout, cancellationToken, null); } private bool TryTakeWithNoTimeValidation([MaybeNullWhen(false)] out T item, int millisecondsTimeout, CancellationToken cancellationToken, CancellationTokenSource combinedTokenSource) { CheckDisposed(); item = default(T); cancellationToken.ThrowIfCancellationRequested(); if (IsCompleted) { return false; } bool flag = false; CancellationTokenSource cancellationTokenSource = combinedTokenSource; try { flag = _occupiedNodes.Wait(0); if (!flag && millisecondsTimeout != 0) { if (cancellationTokenSource == null) { cancellationTokenSource = CancellationTokenSource.CreateLinkedTokenSource(cancellationToken, _consumersCancellationTokenSource.Token); } flag = _occupiedNodes.Wait(millisecondsTimeout, cancellationTokenSource.Token); } } catch (OperationCanceledException) { cancellationToken.ThrowIfCancellationRequested(); return false; } finally { if (cancellationTokenSource != null && combinedTokenSource == null) { cancellationTokenSource.Dispose(); } } if (flag) { bool flag2 = false; bool flag3 = true; try { cancellationToken.ThrowIfCancellationRequested(); flag2 = _collection.TryTake(out item); flag3 = false; if (!flag2) { throw new InvalidOperationException(System.SR.BlockingCollection_Take_CollectionModified); } } finally { if (flag2) { if (_freeNodes != null) { _freeNodes.Release(); } } else if (flag3) { _occupiedNodes.Release(); } if (IsCompleted) { CancelWaitingConsumers(); } } } return flag; } public static int AddToAny(BlockingCollection[] collections, T item) { return TryAddToAny(collections, item, -1, CancellationToken.None); } public static int AddToAny(BlockingCollection[] collections, T item, CancellationToken cancellationToken) { return TryAddToAny(collections, item, -1, cancellationToken); } public static int TryAddToAny(BlockingCollection[] collections, T item) { return TryAddToAny(collections, item, 0, CancellationToken.None); } public static int TryAddToAny(BlockingCollection[] collections, T item, TimeSpan timeout) { ValidateTimeout(timeout); return TryAddToAnyCore(collections, item, (int)timeout.TotalMilliseconds, CancellationToken.None); } public static int TryAddToAny(BlockingCollection[] collections, T item, int millisecondsTimeout) { ValidateMillisecondsTimeout(millisecondsTimeout); return TryAddToAnyCore(collections, item, millisecondsTimeout, CancellationToken.None); } public static int TryAddToAny(BlockingCollection[] collections, T item, int millisecondsTimeout, CancellationToken cancellationToken) { ValidateMillisecondsTimeout(millisecondsTimeout); return TryAddToAnyCore(collections, item, millisecondsTimeout, cancellationToken); } private static int TryAddToAnyCore(BlockingCollection[] collections, T item, int millisecondsTimeout, CancellationToken externalCancellationToken) { ValidateCollectionsArray(collections, isAddOperation: true); int num = millisecondsTimeout; uint startTime = 0u; if (millisecondsTimeout != -1) { startTime = (uint)Environment.TickCount; } int num2 = TryAddToAnyFast(collections, item); if (num2 > -1) { return num2; } CancellationToken[] cancellationTokens; List handles = GetHandles(collections, externalCancellationToken, isAddOperation: true, out cancellationTokens); while (millisecondsTimeout == -1 || num >= 0) { num2 = -1; using (CancellationTokenSource cancellationTokenSource = CancellationTokenSource.CreateLinkedTokenSource(cancellationTokens)) { handles.Add(cancellationTokenSource.Token.WaitHandle); num2 = WaitHandle.WaitAny(handles.ToArray(), num); handles.RemoveAt(handles.Count - 1); if (cancellationTokenSource.IsCancellationRequested) { externalCancellationToken.ThrowIfCancellationRequested(); throw new ArgumentException(System.SR.BlockingCollection_CantAddAnyWhenCompleted, "collections"); } } if (num2 == 258) { return -1; } if (collections[num2].TryAdd(item)) { return num2; } if (millisecondsTimeout != -1) { num = UpdateTimeOut(startTime, millisecondsTimeout); } } return -1; } private static int TryAddToAnyFast(BlockingCollection[] collections, T item) { for (int i = 0; i < collections.Length; i++) { if (collections[i]._freeNodes == null) { collections[i].TryAdd(item); return i; } } return -1; } private static List GetHandles(BlockingCollection[] collections, CancellationToken externalCancellationToken, bool isAddOperation, out CancellationToken[] cancellationTokens) { List list = new List(collections.Length + 1); List list2 = new List(collections.Length + 1); list2.Add(externalCancellationToken); if (isAddOperation) { foreach (BlockingCollection blockingCollection in collections) { if (blockingCollection._freeNodes != null) { list.Add(blockingCollection._freeNodes.AvailableWaitHandle); list2.Add(blockingCollection._producersCancellationTokenSource.Token); } } } else { for (int j = 0; j < collections.Length; j++) { if (!collections[j].IsCompleted) { list.Add(collections[j]._occupiedNodes.AvailableWaitHandle); list2.Add(collections[j]._consumersCancellationTokenSource.Token); } } } cancellationTokens = list2.ToArray(); return list; } private static int UpdateTimeOut(uint startTime, int originalWaitMillisecondsTimeout) { if (originalWaitMillisecondsTimeout == 0) { return 0; } uint num = (uint)Environment.TickCount - startTime; if (num > int.MaxValue) { return 0; } int num2 = originalWaitMillisecondsTimeout - (int)num; if (num2 <= 0) { return 0; } return num2; } public static int TakeFromAny(BlockingCollection[] collections, out T? item) { return TakeFromAny(collections, out item, CancellationToken.None); } public static int TakeFromAny(BlockingCollection[] collections, out T? item, CancellationToken cancellationToken) { return TryTakeFromAnyCore(collections, out item, -1, isTakeOperation: true, cancellationToken); } public static int TryTakeFromAny(BlockingCollection[] collections, out T? item) { return TryTakeFromAny(collections, out item, 0); } public static int TryTakeFromAny(BlockingCollection[] collections, out T? item, TimeSpan timeout) { ValidateTimeout(timeout); return TryTakeFromAnyCore(collections, out item, (int)timeout.TotalMilliseconds, isTakeOperation: false, CancellationToken.None); } public static int TryTakeFromAny(BlockingCollection[] collections, out T? item, int millisecondsTimeout) { ValidateMillisecondsTimeout(millisecondsTimeout); return TryTakeFromAnyCore(collections, out item, millisecondsTimeout, isTakeOperation: false, CancellationToken.None); } public static int TryTakeFromAny(BlockingCollection[] collections, out T? item, int millisecondsTimeout, CancellationToken cancellationToken) { ValidateMillisecondsTimeout(millisecondsTimeout); return TryTakeFromAnyCore(collections, out item, millisecondsTimeout, isTakeOperation: false, cancellationToken); } private static int TryTakeFromAnyCore(BlockingCollection[] collections, out T item, int millisecondsTimeout, bool isTakeOperation, CancellationToken externalCancellationToken) { ValidateCollectionsArray(collections, isAddOperation: false); for (int i = 0; i < collections.Length; i++) { if (!collections[i].IsCompleted && collections[i]._occupiedNodes.CurrentCount > 0 && collections[i].TryTake(out item)) { return i; } } return TryTakeFromAnyCoreSlow(collections, out item, millisecondsTimeout, isTakeOperation, externalCancellationToken); } private static int TryTakeFromAnyCoreSlow(BlockingCollection[] collections, out T item, int millisecondsTimeout, bool isTakeOperation, CancellationToken externalCancellationToken) { int num = millisecondsTimeout; uint startTime = 0u; if (millisecondsTimeout != -1) { startTime = (uint)Environment.TickCount; } while (millisecondsTimeout == -1 || num >= 0) { CancellationToken[] cancellationTokens; List handles = GetHandles(collections, externalCancellationToken, isAddOperation: false, out cancellationTokens); if (handles.Count == 0 && isTakeOperation) { throw new ArgumentException(System.SR.BlockingCollection_CantTakeAnyWhenAllDone, "collections"); } if (handles.Count == 0) { break; } using (CancellationTokenSource cancellationTokenSource = CancellationTokenSource.CreateLinkedTokenSource(cancellationTokens)) { handles.Add(cancellationTokenSource.Token.WaitHandle); int num2 = WaitHandle.WaitAny(handles.ToArray(), num); if (cancellationTokenSource.IsCancellationRequested) { externalCancellationToken.ThrowIfCancellationRequested(); } if (!cancellationTokenSource.IsCancellationRequested) { if (num2 == 258) { break; } if (collections.Length != handles.Count - 1) { for (int i = 0; i < collections.Length; i++) { if (collections[i]._occupiedNodes.AvailableWaitHandle == handles[num2]) { num2 = i; break; } } } if (collections[num2].TryTake(out item)) { return num2; } } } if (millisecondsTimeout != -1) { num = UpdateTimeOut(startTime, millisecondsTimeout); } } item = default(T); return -1; } public void CompleteAdding() { CheckDisposed(); if (IsAddingCompleted) { return; } SpinWait spinWait = default(SpinWait); while (true) { int currentAdders = _currentAdders; if (((uint)currentAdders & 0x80000000u) != 0) { spinWait.Reset(); while (_currentAdders != int.MinValue) { spinWait.SpinOnce(); } return; } if (Interlocked.CompareExchange(ref _currentAdders, currentAdders | int.MinValue, currentAdders) == currentAdders) { break; } spinWait.SpinOnce(-1); } spinWait.Reset(); while (_currentAdders != int.MinValue) { spinWait.SpinOnce(); } if (Count == 0) { CancelWaitingConsumers(); } CancelWaitingProducers(); } private void CancelWaitingConsumers() { _consumersCancellationTokenSource.Cancel(); } private void CancelWaitingProducers() { _producersCancellationTokenSource.Cancel(); } public void Dispose() { Dispose(disposing: true); GC.SuppressFinalize(this); } protected virtual void Dispose(bool disposing) { if (!_isDisposed) { if (_freeNodes != null) { _freeNodes.Dispose(); } _occupiedNodes.Dispose(); _isDisposed = true; } } public T[] ToArray() { CheckDisposed(); return _collection.ToArray(); } public void CopyTo(T[] array, int index) { ((ICollection)this).CopyTo((Array)array, index); } void ICollection.CopyTo(Array array, int index) { CheckDisposed(); T[] array2 = _collection.ToArray(); try { Array.Copy(array2, 0, array, index, array2.Length); } catch (ArgumentNullException) { throw new ArgumentNullException("array"); } catch (ArgumentOutOfRangeException) { throw new ArgumentOutOfRangeException("index", index, System.SR.BlockingCollection_CopyTo_NonNegative); } catch (ArgumentException) { throw new ArgumentException(System.SR.Collection_CopyTo_TooManyElems, "index"); } catch (RankException) { throw new ArgumentException(System.SR.BlockingCollection_CopyTo_MultiDim, "array"); } catch (InvalidCastException) { throw new ArgumentException(System.SR.BlockingCollection_CopyTo_IncorrectType, "array"); } catch (ArrayTypeMismatchException) { throw new ArgumentException(System.SR.BlockingCollection_CopyTo_IncorrectType, "array"); } } public IEnumerable GetConsumingEnumerable() { return GetConsumingEnumerable(CancellationToken.None); } public IEnumerable GetConsumingEnumerable(CancellationToken cancellationToken) { CancellationTokenSource linkedTokenSource = null; try { linkedTokenSource = CancellationTokenSource.CreateLinkedTokenSource(cancellationToken, _consumersCancellationTokenSource.Token); while (!IsCompleted) { if (TryTakeWithNoTimeValidation(out var item, -1, cancellationToken, linkedTokenSource)) { yield return item; } } } finally { linkedTokenSource?.Dispose(); } } IEnumerator IEnumerable.GetEnumerator() { CheckDisposed(); return _collection.GetEnumerator(); } IEnumerator IEnumerable.GetEnumerator() { return ((IEnumerable)this).GetEnumerator(); } private static void ValidateCollectionsArray(BlockingCollection[] collections, bool isAddOperation) { if (collections == null) { throw new ArgumentNullException("collections"); } if (collections.Length < 1) { throw new ArgumentException(System.SR.BlockingCollection_ValidateCollectionsArray_ZeroSize, "collections"); } if (collections.Length > 63 || (collections.Length == 63 && Thread.CurrentThread.GetApartmentState() == ApartmentState.STA)) { throw new ArgumentOutOfRangeException("collections", System.SR.BlockingCollection_ValidateCollectionsArray_LargeSize); } for (int i = 0; i < collections.Length; i++) { if (collections[i] == null) { throw new ArgumentException(System.SR.BlockingCollection_ValidateCollectionsArray_NullElems, "collections"); } if (collections[i]._isDisposed) { throw new ObjectDisposedException("collections", System.SR.BlockingCollection_ValidateCollectionsArray_DispElems); } if (isAddOperation && collections[i].IsAddingCompleted) { throw new ArgumentException(System.SR.BlockingCollection_CantAddAnyWhenCompleted, "collections"); } } } private static void ValidateTimeout(TimeSpan timeout) { long num = (long)timeout.TotalMilliseconds; if ((num < 0 || num > int.MaxValue) && num != -1) { throw new ArgumentOutOfRangeException("timeout", timeout, System.SR.Format(CultureInfo.InvariantCulture, System.SR.BlockingCollection_TimeoutInvalid, int.MaxValue)); } } private static void ValidateMillisecondsTimeout(int millisecondsTimeout) { if (millisecondsTimeout < 0 && millisecondsTimeout != -1) { throw new ArgumentOutOfRangeException("millisecondsTimeout", millisecondsTimeout, System.SR.Format(CultureInfo.InvariantCulture, System.SR.BlockingCollection_TimeoutInvalid, int.MaxValue)); } } private void CheckDisposed() { if (_isDisposed) { throw new ObjectDisposedException("BlockingCollection", System.SR.BlockingCollection_Disposed); } } } internal sealed class BlockingCollectionDebugView { private readonly BlockingCollection _blockingCollection; [UnsupportedOSPlatform("browser")] [DebuggerBrowsable(DebuggerBrowsableState.RootHidden)] public T[] Items => _blockingCollection.ToArray(); public BlockingCollectionDebugView(BlockingCollection collection) { if (collection == null) { throw new ArgumentNullException("collection"); } _blockingCollection = collection; } } [EventSource(Name = "System.Collections.Concurrent.ConcurrentCollectionsEventSource", Guid = "35167F8E-49B2-4b96-AB86-435B59336B5E")] internal sealed class CDSCollectionETWBCLProvider : EventSource { public static CDSCollectionETWBCLProvider Log = new CDSCollectionETWBCLProvider(); private CDSCollectionETWBCLProvider() { } [Event(1, Level = EventLevel.Warning)] public void ConcurrentStack_FastPushFailed(int spinCount) { if (IsEnabled(EventLevel.Warning, EventKeywords.All)) { WriteEvent(1, spinCount); } } [Event(2, Level = EventLevel.Warning)] public void ConcurrentStack_FastPopFailed(int spinCount) { if (IsEnabled(EventLevel.Warning, EventKeywords.All)) { WriteEvent(2, spinCount); } } [Event(3, Level = EventLevel.Warning)] public void ConcurrentDictionary_AcquiringAllLocks(int numOfBuckets) { if (IsEnabled(EventLevel.Warning, EventKeywords.All)) { WriteEvent(3, numOfBuckets); } } [Event(4, Level = EventLevel.Verbose)] public void ConcurrentBag_TryTakeSteals() { if (IsEnabled(EventLevel.Verbose, EventKeywords.All)) { WriteEvent(4); } } [Event(5, Level = EventLevel.Verbose)] public void ConcurrentBag_TryPeekSteals() { if (IsEnabled(EventLevel.Verbose, EventKeywords.All)) { WriteEvent(5); } } } [DebuggerTypeProxy(typeof(System.Collections.Concurrent.IProducerConsumerCollectionDebugView<>))] [DebuggerDisplay("Count = {Count}")] public class ConcurrentBag : IProducerConsumerCollection, IEnumerable, IEnumerable, ICollection, IReadOnlyCollection { private sealed class WorkStealingQueue { private volatile int _headIndex; private volatile int _tailIndex; private volatile T[] _array = new T[32]; private volatile int _mask = 31; private int _addTakeCount; private int _stealCount; internal volatile int _currentOp; internal bool _frozen; internal readonly WorkStealingQueue _nextQueue; internal readonly int _ownerThreadId; internal bool IsEmpty => _headIndex - _tailIndex >= 0; internal int DangerousCount { get { int stealCount = _stealCount; int addTakeCount = _addTakeCount; return addTakeCount - stealCount; } } internal WorkStealingQueue(WorkStealingQueue nextQueue) { _ownerThreadId = Environment.CurrentManagedThreadId; _nextQueue = nextQueue; } internal void LocalPush(T item, ref long emptyToNonEmptyListTransitionCount) { bool lockTaken = false; try { Interlocked.Exchange(ref _currentOp, 1); int num = _tailIndex; if (num == int.MaxValue) { _currentOp = 0; lock (this) { _headIndex &= _mask; num = (_tailIndex = num & _mask); Interlocked.Exchange(ref _currentOp, 1); } } int headIndex = _headIndex; if (!_frozen && headIndex - (num - 1) < 0 && num - (headIndex + _mask) < 0) { _array[num & _mask] = item; _tailIndex = num + 1; } else { _currentOp = 0; Monitor.Enter(this, ref lockTaken); headIndex = _headIndex; int num2 = num - headIndex; if (num2 >= _mask) { T[] array = new T[_array.Length << 1]; int num3 = headIndex & _mask; if (num3 == 0) { Array.Copy(_array, array, _array.Length); } else { Array.Copy(_array, num3, array, 0, _array.Length - num3); Array.Copy(_array, 0, array, _array.Length - num3, num3); } _array = array; _headIndex = 0; num = (_tailIndex = num2); _mask = (_mask << 1) | 1; } _array[num & _mask] = item; _tailIndex = num + 1; if (num2 == 0) { Interlocked.Increment(ref emptyToNonEmptyListTransitionCount); } _addTakeCount -= _stealCount; _stealCount = 0; } checked { _addTakeCount++; } } finally { _currentOp = 0; if (lockTaken) { Monitor.Exit(this); } } } internal void LocalClear() { lock (this) { if (_headIndex - _tailIndex < 0) { _headIndex = (_tailIndex = 0); _addTakeCount = (_stealCount = 0); Array.Clear(_array); } } } internal bool TryLocalPop([MaybeNullWhen(false)] out T result) { int tailIndex = _tailIndex; if (_headIndex - tailIndex >= 0) { result = default(T); return false; } bool lockTaken = false; try { _currentOp = 2; Interlocked.Exchange(ref _tailIndex, --tailIndex); if (!_frozen && _headIndex - tailIndex < 0) { int num = tailIndex & _mask; result = _array[num]; if (RuntimeHelpers.IsReferenceOrContainsReferences()) { _array[num] = default(T); } _addTakeCount--; return true; } _currentOp = 0; Monitor.Enter(this, ref lockTaken); if (_headIndex - tailIndex <= 0) { int num2 = tailIndex & _mask; result = _array[num2]; if (RuntimeHelpers.IsReferenceOrContainsReferences()) { _array[num2] = default(T); } _addTakeCount--; return true; } _tailIndex = tailIndex + 1; result = default(T); return false; } finally { _currentOp = 0; if (lockTaken) { Monitor.Exit(this); } } } internal bool TryLocalPeek([MaybeNullWhen(false)] out T result) { int tailIndex = _tailIndex; if (_headIndex - tailIndex < 0) { lock (this) { if (_headIndex - tailIndex < 0) { result = _array[(tailIndex - 1) & _mask]; return true; } } } result = default(T); return false; } internal bool TrySteal([MaybeNullWhen(false)] out T result, bool take) { lock (this) { int headIndex = _headIndex; if (take) { if (headIndex - (_tailIndex - 2) >= 0 && _currentOp == 1) { SpinWait spinWait = default(SpinWait); do { spinWait.SpinOnce(); } while (_currentOp == 1); } Interlocked.Exchange(ref _headIndex, headIndex + 1); if (headIndex < _tailIndex) { int num = headIndex & _mask; result = _array[num]; if (RuntimeHelpers.IsReferenceOrContainsReferences()) { _array[num] = default(T); } _stealCount++; return true; } _headIndex = headIndex; } else if (headIndex < _tailIndex) { result = _array[headIndex & _mask]; return true; } } result = default(T); return false; } internal int DangerousCopyTo(T[] array, int arrayIndex) { int headIndex = _headIndex; int dangerousCount = DangerousCount; for (int num = arrayIndex + dangerousCount - 1; num >= arrayIndex; num--) { array[num] = _array[headIndex++ & _mask]; } return dangerousCount; } } private sealed class Enumerator : IEnumerator, IDisposable, IEnumerator { private readonly T[] _array; private T _current; private int _index; public T Current => _current; object IEnumerator.Current { get { if (_index == 0 || _index == _array.Length + 1) { throw new InvalidOperationException(System.SR.ConcurrentBag_Enumerator_EnumerationNotStartedOrAlreadyFinished); } return Current; } } public Enumerator(T[] array) { _array = array; } public bool MoveNext() { if (_index < _array.Length) { _current = _array[_index++]; return true; } _index = _array.Length + 1; return false; } public void Reset() { _index = 0; _current = default(T); } public void Dispose() { } } private readonly ThreadLocal _locals; private volatile WorkStealingQueue _workStealingQueues; private long _emptyToNonEmptyListTransitionCount; public int Count { get { if (_workStealingQueues == null) { return 0; } bool lockTaken = false; try { FreezeBag(ref lockTaken); return DangerousCount; } finally { UnfreezeBag(lockTaken); } } } private int DangerousCount { get { int num = 0; for (WorkStealingQueue workStealingQueue = _workStealingQueues; workStealingQueue != null; workStealingQueue = workStealingQueue._nextQueue) { num = checked(num + workStealingQueue.DangerousCount); } return num; } } public bool IsEmpty { get { WorkStealingQueue currentThreadWorkStealingQueue = GetCurrentThreadWorkStealingQueue(forceCreate: false); if (currentThreadWorkStealingQueue != null) { if (!currentThreadWorkStealingQueue.IsEmpty) { return false; } if (currentThreadWorkStealingQueue._nextQueue == null && currentThreadWorkStealingQueue == _workStealingQueues) { return true; } } bool lockTaken = false; try { FreezeBag(ref lockTaken); for (WorkStealingQueue workStealingQueue = _workStealingQueues; workStealingQueue != null; workStealingQueue = workStealingQueue._nextQueue) { if (!workStealingQueue.IsEmpty) { return false; } } } finally { UnfreezeBag(lockTaken); } return true; } } bool ICollection.IsSynchronized => false; object ICollection.SyncRoot { get { throw new NotSupportedException(System.SR.ConcurrentCollection_SyncRoot_NotSupported); } } private object GlobalQueuesLock => _locals; public ConcurrentBag() { _locals = new ThreadLocal(); } public ConcurrentBag(IEnumerable collection) { if (collection == null) { throw new ArgumentNullException("collection", System.SR.ConcurrentBag_Ctor_ArgumentNullException); } _locals = new ThreadLocal(); WorkStealingQueue currentThreadWorkStealingQueue = GetCurrentThreadWorkStealingQueue(forceCreate: true); foreach (T item in collection) { currentThreadWorkStealingQueue.LocalPush(item, ref _emptyToNonEmptyListTransitionCount); } } public void Add(T item) { GetCurrentThreadWorkStealingQueue(forceCreate: true).LocalPush(item, ref _emptyToNonEmptyListTransitionCount); } bool IProducerConsumerCollection.TryAdd(T item) { Add(item); return true; } public bool TryTake([MaybeNullWhen(false)] out T result) { WorkStealingQueue currentThreadWorkStealingQueue = GetCurrentThreadWorkStealingQueue(forceCreate: false); if (currentThreadWorkStealingQueue == null || !currentThreadWorkStealingQueue.TryLocalPop(out result)) { return TrySteal(out result, take: true); } return true; } public bool TryPeek([MaybeNullWhen(false)] out T result) { WorkStealingQueue currentThreadWorkStealingQueue = GetCurrentThreadWorkStealingQueue(forceCreate: false); if (currentThreadWorkStealingQueue == null || !currentThreadWorkStealingQueue.TryLocalPeek(out result)) { return TrySteal(out result, take: false); } return true; } private WorkStealingQueue GetCurrentThreadWorkStealingQueue(bool forceCreate) { WorkStealingQueue workStealingQueue = _locals.Value; if (workStealingQueue == null) { if (!forceCreate) { return null; } workStealingQueue = CreateWorkStealingQueueForCurrentThread(); } return workStealingQueue; } private WorkStealingQueue CreateWorkStealingQueueForCurrentThread() { lock (GlobalQueuesLock) { WorkStealingQueue workStealingQueues = _workStealingQueues; WorkStealingQueue workStealingQueue = ((workStealingQueues != null) ? GetUnownedWorkStealingQueue() : null); if (workStealingQueue == null) { workStealingQueue = (_workStealingQueues = new WorkStealingQueue(workStealingQueues)); } _locals.Value = workStealingQueue; return workStealingQueue; } } private WorkStealingQueue GetUnownedWorkStealingQueue() { int currentManagedThreadId = Environment.CurrentManagedThreadId; for (WorkStealingQueue workStealingQueue = _workStealingQueues; workStealingQueue != null; workStealingQueue = workStealingQueue._nextQueue) { if (workStealingQueue._ownerThreadId == currentManagedThreadId) { return workStealingQueue; } } return null; } private bool TrySteal([MaybeNullWhen(false)] out T result, bool take) { if (CDSCollectionETWBCLProvider.Log.IsEnabled()) { if (take) { CDSCollectionETWBCLProvider.Log.ConcurrentBag_TryTakeSteals(); } else { CDSCollectionETWBCLProvider.Log.ConcurrentBag_TryPeekSteals(); } } while (true) { long num = Interlocked.Read(ref _emptyToNonEmptyListTransitionCount); WorkStealingQueue currentThreadWorkStealingQueue = GetCurrentThreadWorkStealingQueue(forceCreate: false); bool num2; if (currentThreadWorkStealingQueue != null) { if (TryStealFromTo(currentThreadWorkStealingQueue._nextQueue, null, out result, take)) { goto IL_0078; } num2 = TryStealFromTo(_workStealingQueues, currentThreadWorkStealingQueue, out result, take); } else { num2 = TryStealFromTo(_workStealingQueues, null, out result, take); } if (!num2) { if (Interlocked.Read(ref _emptyToNonEmptyListTransitionCount) == num) { break; } continue; } goto IL_0078; IL_0078: return true; } return false; } private bool TryStealFromTo(WorkStealingQueue startInclusive, WorkStealingQueue endExclusive, [MaybeNullWhen(false)] out T result, bool take) { for (WorkStealingQueue workStealingQueue = startInclusive; workStealingQueue != endExclusive; workStealingQueue = workStealingQueue._nextQueue) { if (workStealingQueue.TrySteal(out result, take)) { return true; } } result = default(T); return false; } public void CopyTo(T[] array, int index) { if (array == null) { throw new ArgumentNullException("array", System.SR.ConcurrentBag_CopyTo_ArgumentNullException); } if (index < 0) { throw new ArgumentOutOfRangeException("index", System.SR.Collection_CopyTo_ArgumentOutOfRangeException); } if (_workStealingQueues == null) { return; } bool lockTaken = false; try { FreezeBag(ref lockTaken); int dangerousCount = DangerousCount; if (index > array.Length - dangerousCount) { throw new ArgumentException(System.SR.Collection_CopyTo_TooManyElems, "index"); } try { int num = CopyFromEachQueueToArray(array, index); } catch (ArrayTypeMismatchException ex) { throw new InvalidCastException(ex.Message, ex); } } finally { UnfreezeBag(lockTaken); } } private int CopyFromEachQueueToArray(T[] array, int index) { int num = index; for (WorkStealingQueue workStealingQueue = _workStealingQueues; workStealingQueue != null; workStealingQueue = workStealingQueue._nextQueue) { num += workStealingQueue.DangerousCopyTo(array, num); } return num - index; } void ICollection.CopyTo(Array array, int index) { if (array is T[] array2) { CopyTo(array2, index); return; } if (array == null) { throw new ArgumentNullException("array", System.SR.ConcurrentBag_CopyTo_ArgumentNullException); } ToArray().CopyTo(array, index); } public T[] ToArray() { if (_workStealingQueues != null) { bool lockTaken = false; try { FreezeBag(ref lockTaken); int dangerousCount = DangerousCount; if (dangerousCount > 0) { T[] array = new T[dangerousCount]; int num = CopyFromEachQueueToArray(array, 0); return array; } } finally { UnfreezeBag(lockTaken); } } return Array.Empty(); } public void Clear() { if (_workStealingQueues == null) { return; } WorkStealingQueue currentThreadWorkStealingQueue = GetCurrentThreadWorkStealingQueue(forceCreate: false); if (currentThreadWorkStealingQueue != null) { currentThreadWorkStealingQueue.LocalClear(); if (currentThreadWorkStealingQueue._nextQueue == null && currentThreadWorkStealingQueue == _workStealingQueues) { return; } } bool lockTaken = false; try { FreezeBag(ref lockTaken); for (WorkStealingQueue workStealingQueue = _workStealingQueues; workStealingQueue != null; workStealingQueue = workStealingQueue._nextQueue) { T result; while (workStealingQueue.TrySteal(out result, take: true)) { } } } finally { UnfreezeBag(lockTaken); } } public IEnumerator GetEnumerator() { return new Enumerator(ToArray()); } IEnumerator IEnumerable.GetEnumerator() { return GetEnumerator(); } private void FreezeBag(ref bool lockTaken) { Monitor.Enter(GlobalQueuesLock, ref lockTaken); WorkStealingQueue workStealingQueues = _workStealingQueues; for (WorkStealingQueue workStealingQueue = workStealingQueues; workStealingQueue != null; workStealingQueue = workStealingQueue._nextQueue) { Monitor.Enter(workStealingQueue, ref workStealingQueue._frozen); } Interlocked.MemoryBarrier(); for (WorkStealingQueue workStealingQueue2 = workStealingQueues; workStealingQueue2 != null; workStealingQueue2 = workStealingQueue2._nextQueue) { if (workStealingQueue2._currentOp != 0) { SpinWait spinWait = default(SpinWait); do { spinWait.SpinOnce(); } while (workStealingQueue2._currentOp != 0); } } } private void UnfreezeBag(bool lockTaken) { if (!lockTaken) { return; } for (WorkStealingQueue workStealingQueue = _workStealingQueues; workStealingQueue != null; workStealingQueue = workStealingQueue._nextQueue) { if (workStealingQueue._frozen) { workStealingQueue._frozen = false; Monitor.Exit(workStealingQueue); } } Monitor.Exit(GlobalQueuesLock); } } [DebuggerTypeProxy(typeof(IDictionaryDebugView<, >))] [DebuggerDisplay("Count = {Count}")] public class ConcurrentDictionary : IDictionary, ICollection>, IEnumerable>, IEnumerable, IDictionary, ICollection, IReadOnlyDictionary, IReadOnlyCollection> where TKey : notnull { private sealed class Enumerator : IEnumerator>, IDisposable, IEnumerator { private readonly ConcurrentDictionary _dictionary; private Node[] _buckets; private Node _node; private int _i; private int _state; public KeyValuePair Current { get; private set; } object IEnumerator.Current => Current; public Enumerator(ConcurrentDictionary dictionary) { _dictionary = dictionary; _i = -1; } public void Reset() { _buckets = null; _node = null; Current = default(KeyValuePair); _i = -1; _state = 0; } public void Dispose() { } public bool MoveNext() { switch (_state) { case 0: _buckets = _dictionary._tables._buckets; _i = -1; goto case 1; case 1: { Node[] buckets = _buckets; int num = ++_i; if ((uint)num >= (uint)buckets.Length) { break; } _node = Volatile.Read(ref buckets[num]); _state = 2; goto case 2; } case 2: { Node node = _node; if (node != null) { Current = new KeyValuePair(node._key, node._value); _node = node._next; return true; } goto case 1; } } _state = 3; return false; } } private sealed class Node { internal readonly TKey _key; internal TValue _value; internal volatile Node _next; internal readonly int _hashcode; internal Node(TKey key, TValue value, int hashcode, Node next) { _key = key; _value = value; _next = next; _hashcode = hashcode; } } private sealed class Tables { internal readonly Node[] _buckets; internal readonly object[] _locks; internal readonly int[] _countPerLock; internal readonly ulong _fastModBucketsMultiplier; internal Tables(Node[] buckets, object[] locks, int[] countPerLock) { _buckets = buckets; _locks = locks; _countPerLock = countPerLock; if (IntPtr.Size != 8) { } } [MethodImpl(MethodImplOptions.AggressiveInlining)] internal ref Node GetBucket(int hashcode) { Node[] buckets = _buckets; if (IntPtr.Size == 8) { return ref buckets[System.Collections.HashHelpers.FastMod((uint)hashcode, (uint)buckets.Length, _fastModBucketsMultiplier)]; } return ref buckets[(uint)hashcode % (uint)buckets.Length]; } [MethodImpl(MethodImplOptions.AggressiveInlining)] internal ref Node GetBucketAndLock(int hashcode, out uint lockNo) { Node[] buckets = _buckets; uint num = ((IntPtr.Size != 8) ? ((uint)hashcode % (uint)buckets.Length) : System.Collections.HashHelpers.FastMod((uint)hashcode, (uint)buckets.Length, _fastModBucketsMultiplier)); lockNo = num % (uint)_locks.Length; return ref buckets[num]; } } private sealed class DictionaryEnumerator : IDictionaryEnumerator, IEnumerator { private readonly IEnumerator> _enumerator; public DictionaryEntry Entry => new DictionaryEntry(_enumerator.Current.Key, _enumerator.Current.Value); public object Key => _enumerator.Current.Key; public object Value => _enumerator.Current.Value; public object Current => Entry; internal DictionaryEnumerator(ConcurrentDictionary dictionary) { _enumerator = dictionary.GetEnumerator(); } public bool MoveNext() { return _enumerator.MoveNext(); } public void Reset() { _enumerator.Reset(); } } private volatile Tables _tables; private readonly IEqualityComparer _comparer; private readonly EqualityComparer _defaultComparer; private readonly bool _growLockArray; private int _budget; private static readonly bool s_isValueWriteAtomic = IsValueWriteAtomic(); public TValue this[TKey key] { get { if (!TryGetValue(key, out var value)) { ThrowKeyNotFoundException(key); } return value; } set { if (key == null) { System.ThrowHelper.ThrowKeyNullException(); } TryAddInternal(key, null, value, updateIfExists: true, acquireLock: true, out var _); } } public IEqualityComparer Comparer => _comparer ?? _defaultComparer; public int Count { get { int locksAcquired = 0; try { AcquireAllLocks(ref locksAcquired); return GetCountInternal(); } finally { ReleaseLocks(0, locksAcquired); } } } public bool IsEmpty { get { if (!AreAllBucketsEmpty()) { return false; } int locksAcquired = 0; try { AcquireAllLocks(ref locksAcquired); return AreAllBucketsEmpty(); } finally { ReleaseLocks(0, locksAcquired); } } } public ICollection Keys => GetKeys(); IEnumerable IReadOnlyDictionary.Keys => GetKeys(); public ICollection Values => GetValues(); IEnumerable IReadOnlyDictionary.Values => GetValues(); bool ICollection>.IsReadOnly => false; bool IDictionary.IsFixedSize => false; bool IDictionary.IsReadOnly => false; ICollection IDictionary.Keys => GetKeys(); ICollection IDictionary.Values => GetValues(); object? IDictionary.this[object key] { get { if (key == null) { System.ThrowHelper.ThrowKeyNullException(); } if (key is TKey key2 && TryGetValue(key2, out var value)) { return value; } return null; } set { if (key == null) { System.ThrowHelper.ThrowKeyNullException(); } if (!(key is TKey)) { throw new ArgumentException(System.SR.ConcurrentDictionary_TypeOfKeyIncorrect); } ThrowIfInvalidObjectValue(value); this[(TKey)key] = (TValue)value; } } bool ICollection.IsSynchronized => false; object ICollection.SyncRoot { get { throw new NotSupportedException(System.SR.ConcurrentCollection_SyncRoot_NotSupported); } } private static int DefaultConcurrencyLevel => Environment.ProcessorCount; private static bool IsValueWriteAtomic() { if (!typeof(TValue).IsValueType || typeof(TValue) == typeof(IntPtr) || typeof(TValue) == typeof(UIntPtr)) { return true; } switch (Type.GetTypeCode(typeof(TValue))) { case TypeCode.Boolean: case TypeCode.Char: case TypeCode.SByte: case TypeCode.Byte: case TypeCode.Int16: case TypeCode.UInt16: case TypeCode.Int32: case TypeCode.UInt32: case TypeCode.Single: return true; case TypeCode.Int64: case TypeCode.UInt64: case TypeCode.Double: return IntPtr.Size == 8; default: return false; } } public ConcurrentDictionary() : this(DefaultConcurrencyLevel, 31, growLockArray: true, (IEqualityComparer)null) { } public ConcurrentDictionary(int concurrencyLevel, int capacity) : this(concurrencyLevel, capacity, growLockArray: false, (IEqualityComparer)null) { } public ConcurrentDictionary(IEnumerable> collection) : this(collection, (IEqualityComparer?)null) { } public ConcurrentDictionary(IEqualityComparer? comparer) : this(DefaultConcurrencyLevel, 31, growLockArray: true, comparer) { } public ConcurrentDictionary(IEnumerable> collection, IEqualityComparer? comparer) : this(comparer) { if (collection == null) { System.ThrowHelper.ThrowArgumentNullException("collection"); } InitializeFromCollection(collection); } public ConcurrentDictionary(int concurrencyLevel, IEnumerable> collection, IEqualityComparer? comparer) : this(concurrencyLevel, 31, growLockArray: false, comparer) { if (collection == null) { System.ThrowHelper.ThrowArgumentNullException("collection"); } InitializeFromCollection(collection); } private void InitializeFromCollection(IEnumerable> collection) { foreach (KeyValuePair item in collection) { if (item.Key == null) { System.ThrowHelper.ThrowKeyNullException(); } if (!TryAddInternal(item.Key, null, item.Value, updateIfExists: false, acquireLock: false, out var _)) { throw new ArgumentException(System.SR.ConcurrentDictionary_SourceContainsDuplicateKeys); } } if (_budget == 0) { Tables tables = _tables; _budget = tables._buckets.Length / tables._locks.Length; } } public ConcurrentDictionary(int concurrencyLevel, int capacity, IEqualityComparer? comparer) : this(concurrencyLevel, capacity, growLockArray: false, comparer) { } internal ConcurrentDictionary(int concurrencyLevel, int capacity, bool growLockArray, IEqualityComparer comparer) { if (concurrencyLevel < 1) { throw new ArgumentOutOfRangeException("concurrencyLevel", System.SR.ConcurrentDictionary_ConcurrencyLevelMustBePositive); } if (capacity < 0) { throw new ArgumentOutOfRangeException("capacity", System.SR.ConcurrentDictionary_CapacityMustNotBeNegative); } if (capacity < concurrencyLevel) { capacity = concurrencyLevel; } object[] array = new object[concurrencyLevel]; array[0] = array; for (int i = 1; i < array.Length; i++) { array[i] = new object(); } int[] countPerLock = new int[array.Length]; Node[] array2 = new Node[capacity]; _tables = new Tables(array2, array, countPerLock); _defaultComparer = EqualityComparer.Default; if (comparer != null && comparer != _defaultComparer && comparer != StringComparer.Ordinal) { _comparer = comparer; } _growLockArray = growLockArray; _budget = array2.Length / array.Length; } public bool TryAdd(TKey key, TValue value) { if (key == null) { System.ThrowHelper.ThrowKeyNullException(); } TValue resultingValue; return TryAddInternal(key, null, value, updateIfExists: false, acquireLock: true, out resultingValue); } public bool ContainsKey(TKey key) { if (key == null) { System.ThrowHelper.ThrowKeyNullException(); } TValue value; return TryGetValue(key, out value); } public bool TryRemove(TKey key, [MaybeNullWhen(false)] out TValue value) { if (key == null) { System.ThrowHelper.ThrowKeyNullException(); } return TryRemoveInternal(key, out value, matchValue: false, default(TValue)); } public bool TryRemove(KeyValuePair item) { if (item.Key == null) { System.ThrowHelper.ThrowArgumentNullException("item", System.SR.ConcurrentDictionary_ItemKeyIsNull); } TValue value; return TryRemoveInternal(item.Key, out value, matchValue: true, item.Value); } private bool TryRemoveInternal(TKey key, [MaybeNullWhen(false)] out TValue value, bool matchValue, TValue oldValue) { IEqualityComparer comparer = _comparer; int num = comparer?.GetHashCode(key) ?? key.GetHashCode(); while (true) { Tables tables = _tables; object[] locks = tables._locks; uint lockNo; ref Node bucketAndLock = ref tables.GetBucketAndLock(num, out lockNo); lock (locks[lockNo]) { if (tables != _tables) { continue; } Node node = null; for (Node node2 = bucketAndLock; node2 != null; node2 = node2._next) { if (num == node2._hashcode && (comparer?.Equals(node2._key, key) ?? _defaultComparer.Equals(node2._key, key))) { if (matchValue && !EqualityComparer.Default.Equals(oldValue, node2._value)) { value = default(TValue); return false; } if (node == null) { Volatile.Write(ref bucketAndLock, node2._next); } else { node._next = node2._next; } value = node2._value; tables._countPerLock[lockNo]--; return true; } node = node2; } break; } } value = default(TValue); return false; } public bool TryGetValue(TKey key, [MaybeNullWhen(false)] out TValue value) { if (key == null) { System.ThrowHelper.ThrowKeyNullException(); } Tables tables = _tables; IEqualityComparer comparer = _comparer; if (comparer == null) { int hashCode = key.GetHashCode(); if (typeof(TKey).IsValueType) { for (Node node = Volatile.Read(ref tables.GetBucket(hashCode)); node != null; node = node._next) { if (hashCode == node._hashcode && EqualityComparer.Default.Equals(node._key, key)) { value = node._value; return true; } } } else { for (Node node2 = Volatile.Read(ref tables.GetBucket(hashCode)); node2 != null; node2 = node2._next) { if (hashCode == node2._hashcode && _defaultComparer.Equals(node2._key, key)) { value = node2._value; return true; } } } } else { int hashCode2 = comparer.GetHashCode(key); for (Node node3 = Volatile.Read(ref tables.GetBucket(hashCode2)); node3 != null; node3 = node3._next) { if (hashCode2 == node3._hashcode && comparer.Equals(node3._key, key)) { value = node3._value; return true; } } } value = default(TValue); return false; } private bool TryGetValueInternal(TKey key, int hashcode, [MaybeNullWhen(false)] out TValue value) { Tables tables = _tables; IEqualityComparer comparer = _comparer; if (comparer == null) { if (typeof(TKey).IsValueType) { for (Node node = Volatile.Read(ref tables.GetBucket(hashcode)); node != null; node = node._next) { if (hashcode == node._hashcode && EqualityComparer.Default.Equals(node._key, key)) { value = node._value; return true; } } } else { for (Node node2 = Volatile.Read(ref tables.GetBucket(hashcode)); node2 != null; node2 = node2._next) { if (hashcode == node2._hashcode && _defaultComparer.Equals(node2._key, key)) { value = node2._value; return true; } } } } else { for (Node node3 = Volatile.Read(ref tables.GetBucket(hashcode)); node3 != null; node3 = node3._next) { if (hashcode == node3._hashcode && comparer.Equals(node3._key, key)) { value = node3._value; return true; } } } value = default(TValue); return false; } public bool TryUpdate(TKey key, TValue newValue, TValue comparisonValue) { if (key == null) { System.ThrowHelper.ThrowKeyNullException(); } return TryUpdateInternal(key, null, newValue, comparisonValue); } private bool TryUpdateInternal(TKey key, int? nullableHashcode, TValue newValue, TValue comparisonValue) { IEqualityComparer comparer = _comparer; int num = nullableHashcode ?? comparer?.GetHashCode(key) ?? key.GetHashCode(); EqualityComparer @default = EqualityComparer.Default; while (true) { Tables tables = _tables; object[] locks = tables._locks; uint lockNo; ref Node bucketAndLock = ref tables.GetBucketAndLock(num, out lockNo); lock (locks[lockNo]) { if (tables != _tables) { continue; } Node node = null; for (Node node2 = bucketAndLock; node2 != null; node2 = node2._next) { if (num == node2._hashcode && (comparer?.Equals(node2._key, key) ?? _defaultComparer.Equals(node2._key, key))) { if (@default.Equals(node2._value, comparisonValue)) { if (s_isValueWriteAtomic) { node2._value = newValue; } else { Node node3 = new Node(node2._key, newValue, num, node2._next); if (node == null) { Volatile.Write(ref bucketAndLock, node3); } else { node._next = node3; } } return true; } return false; } node = node2; } return false; } } } public void Clear() { int locksAcquired = 0; try { AcquireAllLocks(ref locksAcquired); if (!AreAllBucketsEmpty()) { Tables tables = _tables; Tables tables2 = (_tables = new Tables(new Node[31], tables._locks, new int[tables._countPerLock.Length])); _budget = Math.Max(1, tables2._buckets.Length / tables2._locks.Length); } } finally { ReleaseLocks(0, locksAcquired); } } void ICollection>.CopyTo(KeyValuePair[] array, int index) { if (array == null) { System.ThrowHelper.ThrowArgumentNullException("array"); } if (index < 0) { throw new ArgumentOutOfRangeException("index", System.SR.ConcurrentDictionary_IndexIsNegative); } int locksAcquired = 0; try { AcquireAllLocks(ref locksAcquired); int num = 0; int[] countPerLock = _tables._countPerLock; for (int i = 0; i < countPerLock.Length; i++) { if (num < 0) { break; } num += countPerLock[i]; } if (array.Length - num < index || num < 0) { throw new ArgumentException(System.SR.ConcurrentDictionary_ArrayNotLargeEnough); } CopyToPairs(array, index); } finally { ReleaseLocks(0, locksAcquired); } } public KeyValuePair[] ToArray() { int locksAcquired = 0; try { AcquireAllLocks(ref locksAcquired); int num = 0; int[] countPerLock = _tables._countPerLock; for (int i = 0; i < countPerLock.Length; i++) { num = checked(num + countPerLock[i]); } if (num == 0) { return Array.Empty>(); } KeyValuePair[] array = new KeyValuePair[num]; CopyToPairs(array, 0); return array; } finally { ReleaseLocks(0, locksAcquired); } } private void CopyToPairs(KeyValuePair[] array, int index) { Node[] buckets = _tables._buckets; for (int i = 0; i < buckets.Length; i++) { for (Node node = buckets[i]; node != null; node = node._next) { array[index] = new KeyValuePair(node._key, node._value); index++; } } } private void CopyToEntries(DictionaryEntry[] array, int index) { Node[] buckets = _tables._buckets; for (int i = 0; i < buckets.Length; i++) { for (Node node = buckets[i]; node != null; node = node._next) { array[index] = new DictionaryEntry(node._key, node._value); index++; } } } private void CopyToObjects(object[] array, int index) { Node[] buckets = _tables._buckets; for (int i = 0; i < buckets.Length; i++) { for (Node node = buckets[i]; node != null; node = node._next) { array[index] = new KeyValuePair(node._key, node._value); index++; } } } public IEnumerator> GetEnumerator() { return new Enumerator(this); } private bool TryAddInternal(TKey key, int? nullableHashcode, TValue value, bool updateIfExists, bool acquireLock, out TValue resultingValue) { IEqualityComparer comparer = _comparer; int num = nullableHashcode ?? comparer?.GetHashCode(key) ?? key.GetHashCode(); checked { Tables tables; bool flag; while (true) { tables = _tables; object[] locks = tables._locks; uint lockNo; ref Node bucketAndLock = ref tables.GetBucketAndLock(num, out lockNo); flag = false; bool lockTaken = false; try { if (acquireLock) { Monitor.Enter(locks[lockNo], ref lockTaken); } if (tables != _tables) { continue; } Node node = null; for (Node node2 = bucketAndLock; node2 != null; node2 = node2._next) { if (num == node2._hashcode && (comparer?.Equals(node2._key, key) ?? _defaultComparer.Equals(node2._key, key))) { if (updateIfExists) { if (s_isValueWriteAtomic) { node2._value = value; } else { Node node3 = new Node(node2._key, value, num, node2._next); if (node == null) { Volatile.Write(ref bucketAndLock, node3); } else { node._next = node3; } } resultingValue = value; } else { resultingValue = node2._value; } return false; } node = node2; } Node value2 = new Node(key, value, num, bucketAndLock); Volatile.Write(ref bucketAndLock, value2); tables._countPerLock[lockNo]++; if (tables._countPerLock[lockNo] > _budget) { flag = true; } break; } finally { if (lockTaken) { Monitor.Exit(locks[lockNo]); } } } if (flag) { GrowTable(tables); } resultingValue = value; return true; } } [DoesNotReturn] private static void ThrowKeyNotFoundException(TKey key) { throw new KeyNotFoundException(System.SR.Format(System.SR.Arg_KeyNotFoundWithKey, key.ToString())); } private int GetCountInternal() { int num = 0; int[] countPerLock = _tables._countPerLock; for (int i = 0; i < countPerLock.Length; i++) { num += countPerLock[i]; } return num; } public TValue GetOrAdd(TKey key, Func valueFactory) { if (key == null) { System.ThrowHelper.ThrowKeyNullException(); } if (valueFactory == null) { System.ThrowHelper.ThrowArgumentNullException("valueFactory"); } int num = _comparer?.GetHashCode(key) ?? key.GetHashCode(); if (!TryGetValueInternal(key, num, out var value)) { TryAddInternal(key, num, valueFactory(key), updateIfExists: false, acquireLock: true, out value); } return value; } public TValue GetOrAdd(TKey key, Func valueFactory, TArg factoryArgument) { if (key == null) { System.ThrowHelper.ThrowKeyNullException(); } if (valueFactory == null) { System.ThrowHelper.ThrowArgumentNullException("valueFactory"); } int num = _comparer?.GetHashCode(key) ?? key.GetHashCode(); if (!TryGetValueInternal(key, num, out var value)) { TryAddInternal(key, num, valueFactory(key, factoryArgument), updateIfExists: false, acquireLock: true, out value); } return value; } public TValue GetOrAdd(TKey key, TValue value) { if (key == null) { System.ThrowHelper.ThrowKeyNullException(); } int num = _comparer?.GetHashCode(key) ?? key.GetHashCode(); if (!TryGetValueInternal(key, num, out var value2)) { TryAddInternal(key, num, value, updateIfExists: false, acquireLock: true, out value2); } return value2; } public TValue AddOrUpdate(TKey key, Func addValueFactory, Func updateValueFactory, TArg factoryArgument) { if (key == null) { System.ThrowHelper.ThrowKeyNullException(); } if (addValueFactory == null) { System.ThrowHelper.ThrowArgumentNullException("addValueFactory"); } if (updateValueFactory == null) { System.ThrowHelper.ThrowArgumentNullException("updateValueFactory"); } int num = _comparer?.GetHashCode(key) ?? key.GetHashCode(); TValue resultingValue; while (true) { if (TryGetValueInternal(key, num, out var value)) { TValue val = updateValueFactory(key, value, factoryArgument); if (TryUpdateInternal(key, num, val, value)) { return val; } } else if (TryAddInternal(key, num, addValueFactory(key, factoryArgument), updateIfExists: false, acquireLock: true, out resultingValue)) { break; } } return resultingValue; } public TValue AddOrUpdate(TKey key, Func addValueFactory, Func updateValueFactory) { if (key == null) { System.ThrowHelper.ThrowKeyNullException(); } if (addValueFactory == null) { System.ThrowHelper.ThrowArgumentNullException("addValueFactory"); } if (updateValueFactory == null) { System.ThrowHelper.ThrowArgumentNullException("updateValueFactory"); } int num = _comparer?.GetHashCode(key) ?? key.GetHashCode(); TValue resultingValue; while (true) { if (TryGetValueInternal(key, num, out var value)) { TValue val = updateValueFactory(key, value); if (TryUpdateInternal(key, num, val, value)) { return val; } } else if (TryAddInternal(key, num, addValueFactory(key), updateIfExists: false, acquireLock: true, out resultingValue)) { break; } } return resultingValue; } public TValue AddOrUpdate(TKey key, TValue addValue, Func updateValueFactory) { if (key == null) { System.ThrowHelper.ThrowKeyNullException(); } if (updateValueFactory == null) { System.ThrowHelper.ThrowArgumentNullException("updateValueFactory"); } int num = _comparer?.GetHashCode(key) ?? key.GetHashCode(); TValue resultingValue; while (true) { if (TryGetValueInternal(key, num, out var value)) { TValue val = updateValueFactory(key, value); if (TryUpdateInternal(key, num, val, value)) { return val; } } else if (TryAddInternal(key, num, addValue, updateIfExists: false, acquireLock: true, out resultingValue)) { break; } } return resultingValue; } void IDictionary.Add(TKey key, TValue value) { if (!TryAdd(key, value)) { throw new ArgumentException(System.SR.ConcurrentDictionary_KeyAlreadyExisted); } } bool IDictionary.Remove(TKey key) { TValue value; return TryRemove(key, out value); } void ICollection>.Add(KeyValuePair keyValuePair) { ((IDictionary)this).Add(keyValuePair.Key, keyValuePair.Value); } bool ICollection>.Contains(KeyValuePair keyValuePair) { if (!TryGetValue(keyValuePair.Key, out var value)) { return false; } return EqualityComparer.Default.Equals(value, keyValuePair.Value); } bool ICollection>.Remove(KeyValuePair keyValuePair) { return TryRemove(keyValuePair); } IEnumerator IEnumerable.GetEnumerator() { return GetEnumerator(); } void IDictionary.Add(object key, object value) { if (key == null) { System.ThrowHelper.ThrowKeyNullException(); } if (!(key is TKey)) { throw new ArgumentException(System.SR.ConcurrentDictionary_TypeOfKeyIncorrect); } ThrowIfInvalidObjectValue(value); ((IDictionary)this).Add((TKey)key, (TValue)value); } bool IDictionary.Contains(object key) { if (key == null) { System.ThrowHelper.ThrowKeyNullException(); } if (key is TKey key2) { return ContainsKey(key2); } return false; } IDictionaryEnumerator IDictionary.GetEnumerator() { return new DictionaryEnumerator(this); } void IDictionary.Remove(object key) { if (key == null) { System.ThrowHelper.ThrowKeyNullException(); } if (key is TKey) { TKey key2 = (TKey)key; TryRemove(key2, out var _); } } [MethodImpl(MethodImplOptions.AggressiveInlining)] private static void ThrowIfInvalidObjectValue(object value) { if (value != null) { if (!(value is TValue)) { System.ThrowHelper.ThrowValueNullException(); } } else if (default(TValue) != null) { System.ThrowHelper.ThrowValueNullException(); } } void ICollection.CopyTo(Array array, int index) { if (array == null) { System.ThrowHelper.ThrowArgumentNullException("array"); } if (index < 0) { throw new ArgumentOutOfRangeException("index", System.SR.ConcurrentDictionary_IndexIsNegative); } int locksAcquired = 0; try { AcquireAllLocks(ref locksAcquired); Tables tables = _tables; int num = 0; int[] countPerLock = tables._countPerLock; for (int i = 0; i < countPerLock.Length; i++) { if (num < 0) { break; } num += countPerLock[i]; } if (array.Length - num < index || num < 0) { throw new ArgumentException(System.SR.ConcurrentDictionary_ArrayNotLargeEnough); } if (array is KeyValuePair[] array2) { CopyToPairs(array2, index); return; } if (array is DictionaryEntry[] array3) { CopyToEntries(array3, index); return; } if (array is object[] array4) { CopyToObjects(array4, index); return; } throw new ArgumentException(System.SR.ConcurrentDictionary_ArrayIncorrectType, "array"); } finally { ReleaseLocks(0, locksAcquired); } } private bool AreAllBucketsEmpty() { int[] countPerLock = _tables._countPerLock; for (int i = 0; i < countPerLock.Length; i++) { if (countPerLock[i] != 0) { return false; } } return true; } private void GrowTable(Tables tables) { int locksAcquired = 0; try { AcquireLocks(0, 1, ref locksAcquired); if (tables != _tables) { return; } long num = 0L; for (int i = 0; i < tables._countPerLock.Length; i++) { num += tables._countPerLock[i]; } if (num < tables._buckets.Length / 4) { _budget = 2 * _budget; if (_budget < 0) { _budget = int.MaxValue; } return; } int j = 0; bool flag = false; try { for (j = checked(tables._buckets.Length * 2 + 1); j % 3 == 0 || j % 5 == 0 || j % 7 == 0; j = checked(j + 2)) { } if (j > Array.MaxLength) { flag = true; } } catch (OverflowException) { flag = true; } if (flag) { j = Array.MaxLength; _budget = int.MaxValue; } AcquireLocks(1, tables._locks.Length, ref locksAcquired); object[] array = tables._locks; if (_growLockArray && tables._locks.Length < 1024) { array = new object[tables._locks.Length * 2]; Array.Copy(tables._locks, array, tables._locks.Length); for (int k = tables._locks.Length; k < array.Length; k++) { array[k] = new object(); } } Node[] array2 = new Node[j]; int[] array3 = new int[array.Length]; Tables tables2 = new Tables(array2, array, array3); Node[] buckets = tables._buckets; checked { foreach (Node node in buckets) { Node node2 = node; while (node2 != null) { Node next = node2._next; uint lockNo; ref Node bucketAndLock = ref tables2.GetBucketAndLock(node2._hashcode, out lockNo); bucketAndLock = new Node(node2._key, node2._value, node2._hashcode, bucketAndLock); array3[lockNo]++; node2 = next; } } } _budget = Math.Max(1, array2.Length / array.Length); _tables = tables2; } finally { ReleaseLocks(0, locksAcquired); } } private void AcquireAllLocks(ref int locksAcquired) { if (CDSCollectionETWBCLProvider.Log.IsEnabled()) { CDSCollectionETWBCLProvider.Log.ConcurrentDictionary_AcquiringAllLocks(_tables._buckets.Length); } AcquireLocks(0, 1, ref locksAcquired); AcquireLocks(1, _tables._locks.Length, ref locksAcquired); } private void AcquireLocks(int fromInclusive, int toExclusive, ref int locksAcquired) { object[] locks = _tables._locks; for (int i = fromInclusive; i < toExclusive; i++) { bool lockTaken = false; try { Monitor.Enter(locks[i], ref lockTaken); } finally { if (lockTaken) { locksAcquired++; } } } } private void ReleaseLocks(int fromInclusive, int toExclusive) { Tables tables = _tables; for (int i = fromInclusive; i < toExclusive; i++) { Monitor.Exit(tables._locks[i]); } } private ReadOnlyCollection GetKeys() { int locksAcquired = 0; try { AcquireAllLocks(ref locksAcquired); int countInternal = GetCountInternal(); if (countInternal < 0) { System.ThrowHelper.ThrowOutOfMemoryException(); } List list = new List(countInternal); Node[] buckets = _tables._buckets; for (int i = 0; i < buckets.Length; i++) { for (Node node = buckets[i]; node != null; node = node._next) { list.Add(node._key); } } return new ReadOnlyCollection(list); } finally { ReleaseLocks(0, locksAcquired); } } private ReadOnlyCollection GetValues() { int locksAcquired = 0; try { AcquireAllLocks(ref locksAcquired); int countInternal = GetCountInternal(); if (countInternal < 0) { System.ThrowHelper.ThrowOutOfMemoryException(); } List list = new List(countInternal); Node[] buckets = _tables._buckets; for (int i = 0; i < buckets.Length; i++) { for (Node node = buckets[i]; node != null; node = node._next) { list.Add(node._value); } } return new ReadOnlyCollection(list); } finally { ReleaseLocks(0, locksAcquired); } } } internal sealed class IDictionaryDebugView { private readonly IDictionary _dictionary; [DebuggerBrowsable(DebuggerBrowsableState.RootHidden)] public KeyValuePair[] Items { get { KeyValuePair[] array = new KeyValuePair[_dictionary.Count]; _dictionary.CopyTo(array, 0); return array; } } public IDictionaryDebugView(IDictionary dictionary) { if (dictionary == null) { System.ThrowHelper.ThrowArgumentNullException("dictionary"); } _dictionary = dictionary; } } [DebuggerDisplay("Count = {Count}")] [DebuggerTypeProxy(typeof(System.Collections.Concurrent.IProducerConsumerCollectionDebugView<>))] public class ConcurrentStack : IProducerConsumerCollection, IEnumerable, IEnumerable, ICollection, IReadOnlyCollection { private sealed class Node { internal readonly T _value; internal Node _next; internal Node(T value) { _value = value; _next = null; } } private volatile Node _head; public bool IsEmpty => _head == null; public int Count { get { int num = 0; for (Node node = _head; node != null; node = node._next) { num++; } return num; } } bool ICollection.IsSynchronized => false; object ICollection.SyncRoot { get { throw new NotSupportedException(System.SR.ConcurrentCollection_SyncRoot_NotSupported); } } public ConcurrentStack() { } public ConcurrentStack(IEnumerable collection) { if (collection == null) { throw new ArgumentNullException("collection"); } InitializeFromCollection(collection); } private void InitializeFromCollection(IEnumerable collection) { Node node = null; foreach (T item in collection) { Node node2 = new Node(item); node2._next = node; node = node2; } _head = node; } public void Clear() { _head = null; } void ICollection.CopyTo(Array array, int index) { if (array == null) { throw new ArgumentNullException("array"); } ((ICollection)ToList()).CopyTo(array, index); } public void CopyTo(T[] array, int index) { if (array == null) { throw new ArgumentNullException("array"); } ToList().CopyTo(array, index); } public void Push(T item) { Node node = new Node(item); node._next = _head; if (Interlocked.CompareExchange(ref _head, node, node._next) != node._next) { PushCore(node, node); } } public void PushRange(T[] items) { if (items == null) { throw new ArgumentNullException("items"); } PushRange(items, 0, items.Length); } public void PushRange(T[] items, int startIndex, int count) { ValidatePushPopRangeInput(items, startIndex, count); if (count != 0) { Node node; Node node2 = (node = new Node(items[startIndex])); for (int i = startIndex + 1; i < startIndex + count; i++) { Node node3 = new Node(items[i]); node3._next = node2; node2 = node3; } node._next = _head; if (Interlocked.CompareExchange(ref _head, node2, node._next) != node._next) { PushCore(node2, node); } } } private void PushCore(Node head, Node tail) { SpinWait spinWait = default(SpinWait); do { spinWait.SpinOnce(-1); tail._next = _head; } while (Interlocked.CompareExchange(ref _head, head, tail._next) != tail._next); if (CDSCollectionETWBCLProvider.Log.IsEnabled()) { CDSCollectionETWBCLProvider.Log.ConcurrentStack_FastPushFailed(spinWait.Count); } } private static void ValidatePushPopRangeInput(T[] items, int startIndex, int count) { if (items == null) { throw new ArgumentNullException("items"); } if (count < 0) { throw new ArgumentOutOfRangeException("count", System.SR.ConcurrentStack_PushPopRange_CountOutOfRange); } int num = items.Length; if (startIndex >= num || startIndex < 0) { throw new ArgumentOutOfRangeException("startIndex", System.SR.ConcurrentStack_PushPopRange_StartOutOfRange); } if (num - count < startIndex) { throw new ArgumentException(System.SR.ConcurrentStack_PushPopRange_InvalidCount); } } bool IProducerConsumerCollection.TryAdd(T item) { Push(item); return true; } public bool TryPeek([MaybeNullWhen(false)] out T result) { Node head = _head; if (head == null) { result = default(T); return false; } result = head._value; return true; } public bool TryPop([MaybeNullWhen(false)] out T result) { Node head = _head; if (head == null) { result = default(T); return false; } if (Interlocked.CompareExchange(ref _head, head._next, head) == head) { result = head._value; return true; } return TryPopCore(out result); } public int TryPopRange(T[] items) { if (items == null) { throw new ArgumentNullException("items"); } return TryPopRange(items, 0, items.Length); } public int TryPopRange(T[] items, int startIndex, int count) { ValidatePushPopRangeInput(items, startIndex, count); if (count == 0) { return 0; } Node poppedHead; int num = TryPopCore(count, out poppedHead); if (num > 0) { CopyRemovedItems(poppedHead, items, startIndex, num); } return num; } private bool TryPopCore([MaybeNullWhen(false)] out T result) { if (TryPopCore(1, out var poppedHead) == 1) { result = poppedHead._value; return true; } result = default(T); return false; } private int TryPopCore(int count, out Node poppedHead) { SpinWait spinWait = default(SpinWait); int num = 1; Node head; int i; while (true) { head = _head; if (head == null) { if (count == 1 && CDSCollectionETWBCLProvider.Log.IsEnabled()) { CDSCollectionETWBCLProvider.Log.ConcurrentStack_FastPopFailed(spinWait.Count); } poppedHead = null; return 0; } Node node = head; for (i = 1; i < count; i++) { if (node._next == null) { break; } node = node._next; } if (Interlocked.CompareExchange(ref _head, node._next, head) == head) { break; } for (int j = 0; j < num; j++) { spinWait.SpinOnce(-1); } num = ((!spinWait.NextSpinWillYield) ? (num * 2) : Random.Shared.Next(1, 8)); } if (count == 1 && CDSCollectionETWBCLProvider.Log.IsEnabled()) { CDSCollectionETWBCLProvider.Log.ConcurrentStack_FastPopFailed(spinWait.Count); } poppedHead = head; return i; } private static void CopyRemovedItems(Node head, T[] collection, int startIndex, int nodesCount) { Node node = head; for (int i = startIndex; i < startIndex + nodesCount; i++) { collection[i] = node._value; node = node._next; } } bool IProducerConsumerCollection.TryTake([MaybeNullWhen(false)] out T item) { return TryPop(out item); } public T[] ToArray() { Node head = _head; if (head != null) { return ToList(head).ToArray(); } return Array.Empty(); } private List ToList() { return ToList(_head); } private List ToList(Node curr) { List list = new List(); while (curr != null) { list.Add(curr._value); curr = curr._next; } return list; } public IEnumerator GetEnumerator() { return GetEnumerator(_head); } private IEnumerator GetEnumerator(Node head) { for (Node current = head; current != null; current = current._next) { yield return current._value; } } IEnumerator IEnumerable.GetEnumerator() { return ((IEnumerable)this).GetEnumerator(); } } public abstract class OrderablePartitioner : Partitioner { private sealed class EnumerableDropIndices : IEnumerable, IEnumerable, IDisposable { private readonly IEnumerable> _source; public EnumerableDropIndices(IEnumerable> source) { _source = source; } public IEnumerator GetEnumerator() { return new EnumeratorDropIndices(_source.GetEnumerator()); } IEnumerator IEnumerable.GetEnumerator() { return GetEnumerator(); } public void Dispose() { if (_source is IDisposable disposable) { disposable.Dispose(); } } } private sealed class EnumeratorDropIndices : IEnumerator, IDisposable, IEnumerator { private readonly IEnumerator> _source; public TSource Current => _source.Current.Value; object IEnumerator.Current => Current; public EnumeratorDropIndices(IEnumerator> source) { _source = source; } public bool MoveNext() { return _source.MoveNext(); } public void Dispose() { _source.Dispose(); } public void Reset() { _source.Reset(); } } public bool KeysOrderedInEachPartition { get; private set; } public bool KeysOrderedAcrossPartitions { get; private set; } public bool KeysNormalized { get; private set; } protected OrderablePartitioner(bool keysOrderedInEachPartition, bool keysOrderedAcrossPartitions, bool keysNormalized) { KeysOrderedInEachPartition = keysOrderedInEachPartition; KeysOrderedAcrossPartitions = keysOrderedAcrossPartitions; KeysNormalized = keysNormalized; } public abstract IList>> GetOrderablePartitions(int partitionCount); public virtual IEnumerable> GetOrderableDynamicPartitions() { throw new NotSupportedException(System.SR.Partitioner_DynamicPartitionsNotSupported); } public override IList> GetPartitions(int partitionCount) { IList>> orderablePartitions = GetOrderablePartitions(partitionCount); if (orderablePartitions.Count != partitionCount) { throw new InvalidOperationException("OrderablePartitioner_GetPartitions_WrongNumberOfPartitions"); } IEnumerator[] array = new IEnumerator[partitionCount]; for (int i = 0; i < partitionCount; i++) { array[i] = new EnumeratorDropIndices(orderablePartitions[i]); } return array; } public override IEnumerable GetDynamicPartitions() { IEnumerable> orderableDynamicPartitions = GetOrderableDynamicPartitions(); return new EnumerableDropIndices(orderableDynamicPartitions); } } public abstract class Partitioner { public virtual bool SupportsDynamicPartitions => false; public abstract IList> GetPartitions(int partitionCount); public virtual IEnumerable GetDynamicPartitions() { throw new NotSupportedException(System.SR.Partitioner_DynamicPartitionsNotSupported); } } [Flags] public enum EnumerablePartitionerOptions { None = 0, NoBuffering = 1 } public static class Partitioner { private abstract class DynamicPartitionEnumerator_Abstract : IEnumerator>, IDisposable, IEnumerator { protected readonly TSourceReader _sharedReader; protected static int s_defaultMaxChunkSize = GetDefaultChunkSize(); protected StrongBox _currentChunkSize; protected StrongBox _localOffset; private int _doublingCountdown; protected readonly int _maxChunkSize; protected readonly SharedLong _sharedIndex; protected abstract bool HasNoElementsLeft { get; } public abstract KeyValuePair Current { get; } object IEnumerator.Current => Current; protected DynamicPartitionEnumerator_Abstract(TSourceReader sharedReader, SharedLong sharedIndex) : this(sharedReader, sharedIndex, useSingleChunking: false) { } protected DynamicPartitionEnumerator_Abstract(TSourceReader sharedReader, SharedLong sharedIndex, bool useSingleChunking) { _sharedReader = sharedReader; _sharedIndex = sharedIndex; _maxChunkSize = (useSingleChunking ? 1 : s_defaultMaxChunkSize); } protected abstract bool GrabNextChunk(int requestedChunkSize); public abstract void Dispose(); public void Reset() { throw new NotSupportedException(); } public bool MoveNext() { if (_localOffset == null) { _localOffset = new StrongBox(-1); _currentChunkSize = new StrongBox(0); _doublingCountdown = 3; } if (_localOffset.Value < _currentChunkSize.Value - 1) { _localOffset.Value++; return true; } int requestedChunkSize; if (_currentChunkSize.Value == 0) { requestedChunkSize = 1; } else if (_doublingCountdown > 0) { requestedChunkSize = _currentChunkSize.Value; } else { requestedChunkSize = Math.Min(_currentChunkSize.Value * 2, _maxChunkSize); _doublingCountdown = 3; } _doublingCountdown--; if (GrabNextChunk(requestedChunkSize)) { _localOffset.Value = 0; return true; } return false; } } private sealed class DynamicPartitionerForIEnumerable : OrderablePartitioner { private sealed class InternalPartitionEnumerable : IEnumerable>, IEnumerable, IDisposable { private readonly IEnumerator _sharedReader; private readonly SharedLong _sharedIndex; private volatile KeyValuePair[] _fillBuffer; private volatile int _fillBufferSize; private volatile int _fillBufferCurrentPosition; private volatile int _activeCopiers; private readonly SharedBool _hasNoElementsLeft; private readonly SharedBool _sourceDepleted; private readonly object _sharedLock; private bool _disposed; private readonly SharedInt _activePartitionCount; private readonly bool _useSingleChunking; internal InternalPartitionEnumerable(IEnumerator sharedReader, bool useSingleChunking, bool isStaticPartitioning) { _sharedReader = sharedReader; _sharedIndex = new SharedLong(-1L); _hasNoElementsLeft = new SharedBool(value: false); _sourceDepleted = new SharedBool(value: false); _sharedLock = new object(); _useSingleChunking = useSingleChunking; if (!_useSingleChunking) { _fillBuffer = new KeyValuePair[((Environment.ProcessorCount <= 4) ? 1 : 4) * GetDefaultChunkSize()]; } if (isStaticPartitioning) { _activePartitionCount = new SharedInt(0); } else { _activePartitionCount = null; } } public IEnumerator> GetEnumerator() { if (_disposed) { throw new ObjectDisposedException(System.SR.PartitionerStatic_CanNotCallGetEnumeratorAfterSourceHasBeenDisposed); } return new InternalPartitionEnumerator(_sharedReader, _sharedIndex, _hasNoElementsLeft, _activePartitionCount, this, _useSingleChunking); } IEnumerator IEnumerable.GetEnumerator() { return GetEnumerator(); } private void TryCopyFromFillBuffer(KeyValuePair[] destArray, int requestedChunkSize, ref int actualNumElementsGrabbed) { actualNumElementsGrabbed = 0; KeyValuePair[] fillBuffer = _fillBuffer; if (fillBuffer != null && _fillBufferCurrentPosition < _fillBufferSize) { Interlocked.Increment(ref _activeCopiers); int num = Interlocked.Add(ref _fillBufferCurrentPosition, requestedChunkSize); int num2 = num - requestedChunkSize; if (num2 < _fillBufferSize) { actualNumElementsGrabbed = ((num < _fillBufferSize) ? num : (_fillBufferSize - num2)); Array.Copy(fillBuffer, num2, destArray, 0, actualNumElementsGrabbed); } Interlocked.Decrement(ref _activeCopiers); } } internal bool GrabChunk(KeyValuePair[] destArray, int requestedChunkSize, ref int actualNumElementsGrabbed) { actualNumElementsGrabbed = 0; if (_hasNoElementsLeft.Value) { return false; } if (_useSingleChunking) { return GrabChunk_Single(destArray, requestedChunkSize, ref actualNumElementsGrabbed); } return GrabChunk_Buffered(destArray, requestedChunkSize, ref actualNumElementsGrabbed); } internal bool GrabChunk_Single(KeyValuePair[] destArray, int requestedChunkSize, ref int actualNumElementsGrabbed) { lock (_sharedLock) { if (_hasNoElementsLeft.Value) { return false; } try { if (_sharedReader.MoveNext()) { _sharedIndex.Value = checked(_sharedIndex.Value + 1); destArray[0] = new KeyValuePair(_sharedIndex.Value, _sharedReader.Current); actualNumElementsGrabbed = 1; return true; } _sourceDepleted.Value = true; _hasNoElementsLeft.Value = true; return false; } catch { _sourceDepleted.Value = true; _hasNoElementsLeft.Value = true; throw; } } } internal bool GrabChunk_Buffered(KeyValuePair[] destArray, int requestedChunkSize, ref int actualNumElementsGrabbed) { TryCopyFromFillBuffer(destArray, requestedChunkSize, ref actualNumElementsGrabbed); if (actualNumElementsGrabbed == requestedChunkSize) { return true; } if (_sourceDepleted.Value) { _hasNoElementsLeft.Value = true; _fillBuffer = null; return actualNumElementsGrabbed > 0; } lock (_sharedLock) { if (_sourceDepleted.Value) { return actualNumElementsGrabbed > 0; } try { if (_activeCopiers > 0) { SpinWait spinWait = default(SpinWait); while (_activeCopiers > 0) { spinWait.SpinOnce(); } } while (actualNumElementsGrabbed < requestedChunkSize) { if (_sharedReader.MoveNext()) { _sharedIndex.Value = checked(_sharedIndex.Value + 1); destArray[actualNumElementsGrabbed] = new KeyValuePair(_sharedIndex.Value, _sharedReader.Current); actualNumElementsGrabbed++; continue; } _sourceDepleted.Value = true; break; } KeyValuePair[] fillBuffer = _fillBuffer; if (!_sourceDepleted.Value && fillBuffer != null && _fillBufferCurrentPosition >= fillBuffer.Length) { for (int i = 0; i < fillBuffer.Length; i++) { if (_sharedReader.MoveNext()) { _sharedIndex.Value = checked(_sharedIndex.Value + 1); fillBuffer[i] = new KeyValuePair(_sharedIndex.Value, _sharedReader.Current); continue; } _sourceDepleted.Value = true; _fillBufferSize = i; break; } _fillBufferCurrentPosition = 0; } } catch { _sourceDepleted.Value = true; _hasNoElementsLeft.Value = true; throw; } } return actualNumElementsGrabbed > 0; } public void Dispose() { if (!_disposed) { _disposed = true; _sharedReader.Dispose(); } } } private sealed class InternalPartitionEnumerator : DynamicPartitionEnumerator_Abstract> { private KeyValuePair[] _localList; private readonly SharedBool _hasNoElementsLeft; private readonly SharedInt _activePartitionCount; private readonly InternalPartitionEnumerable _enumerable; protected override bool HasNoElementsLeft => _hasNoElementsLeft.Value; public override KeyValuePair Current { get { if (_currentChunkSize == null) { throw new InvalidOperationException(System.SR.PartitionerStatic_CurrentCalledBeforeMoveNext); } return _localList[_localOffset.Value]; } } internal InternalPartitionEnumerator(IEnumerator sharedReader, SharedLong sharedIndex, SharedBool hasNoElementsLeft, SharedInt activePartitionCount, InternalPartitionEnumerable enumerable, bool useSingleChunking) : base(sharedReader, sharedIndex, useSingleChunking) { _hasNoElementsLeft = hasNoElementsLeft; _enumerable = enumerable; _activePartitionCount = activePartitionCount; if (_activePartitionCount != null) { Interlocked.Increment(ref _activePartitionCount.Value); } } protected override bool GrabNextChunk(int requestedChunkSize) { if (HasNoElementsLeft) { return false; } if (_localList == null) { _localList = new KeyValuePair[_maxChunkSize]; } return _enumerable.GrabChunk(_localList, requestedChunkSize, ref _currentChunkSize.Value); } public override void Dispose() { if (_activePartitionCount != null && Interlocked.Decrement(ref _activePartitionCount.Value) == 0) { _enumerable.Dispose(); } } } private readonly IEnumerable _source; private readonly bool _useSingleChunking; public override bool SupportsDynamicPartitions => true; internal DynamicPartitionerForIEnumerable(IEnumerable source, EnumerablePartitionerOptions partitionerOptions) : base(keysOrderedInEachPartition: true, keysOrderedAcrossPartitions: false, keysNormalized: true) { _source = source; _useSingleChunking = (partitionerOptions & EnumerablePartitionerOptions.NoBuffering) != 0; } public override IList>> GetOrderablePartitions(int partitionCount) { if (partitionCount <= 0) { throw new ArgumentOutOfRangeException("partitionCount"); } IEnumerator>[] array = new IEnumerator>[partitionCount]; IEnumerable> enumerable = new InternalPartitionEnumerable(_source.GetEnumerator(), _useSingleChunking, isStaticPartitioning: true); for (int i = 0; i < partitionCount; i++) { array[i] = enumerable.GetEnumerator(); } return array; } public override IEnumerable> GetOrderableDynamicPartitions() { return new InternalPartitionEnumerable(_source.GetEnumerator(), _useSingleChunking, isStaticPartitioning: false); } } private abstract class DynamicPartitionerForIndexRange_Abstract : OrderablePartitioner { private readonly TCollection _data; public override bool SupportsDynamicPartitions => true; protected DynamicPartitionerForIndexRange_Abstract(TCollection data) : base(keysOrderedInEachPartition: true, keysOrderedAcrossPartitions: false, keysNormalized: true) { _data = data; } protected abstract IEnumerable> GetOrderableDynamicPartitions_Factory(TCollection data); public override IList>> GetOrderablePartitions(int partitionCount) { if (partitionCount <= 0) { throw new ArgumentOutOfRangeException("partitionCount"); } IEnumerator>[] array = new IEnumerator>[partitionCount]; IEnumerable> orderableDynamicPartitions_Factory = GetOrderableDynamicPartitions_Factory(_data); for (int i = 0; i < partitionCount; i++) { array[i] = orderableDynamicPartitions_Factory.GetEnumerator(); } return array; } public override IEnumerable> GetOrderableDynamicPartitions() { return GetOrderableDynamicPartitions_Factory(_data); } } private abstract class DynamicPartitionEnumeratorForIndexRange_Abstract : DynamicPartitionEnumerator_Abstract { protected int _startIndex; protected abstract int SourceCount { get; } protected override bool HasNoElementsLeft => Volatile.Read(ref _sharedIndex.Value) >= SourceCount - 1; protected DynamicPartitionEnumeratorForIndexRange_Abstract(TSourceReader sharedReader, SharedLong sharedIndex) : base(sharedReader, sharedIndex) { } protected override bool GrabNextChunk(int requestedChunkSize) { while (!HasNoElementsLeft) { long num = Volatile.Read(ref _sharedIndex.Value); if (HasNoElementsLeft) { return false; } long num2 = Math.Min(SourceCount - 1, num + requestedChunkSize); if (Interlocked.CompareExchange(ref _sharedIndex.Value, num2, num) == num) { _currentChunkSize.Value = (int)(num2 - num); _localOffset.Value = -1; _startIndex = (int)(num + 1); return true; } } return false; } public override void Dispose() { } } private sealed class DynamicPartitionerForIList : DynamicPartitionerForIndexRange_Abstract> { private sealed class InternalPartitionEnumerable : IEnumerable>, IEnumerable { private readonly IList _sharedReader; private readonly SharedLong _sharedIndex; internal InternalPartitionEnumerable(IList sharedReader) { _sharedReader = sharedReader; _sharedIndex = new SharedLong(-1L); } public IEnumerator> GetEnumerator() { return new InternalPartitionEnumerator(_sharedReader, _sharedIndex); } IEnumerator IEnumerable.GetEnumerator() { return GetEnumerator(); } } private sealed class InternalPartitionEnumerator : DynamicPartitionEnumeratorForIndexRange_Abstract> { protected override int SourceCount => _sharedReader.Count; public override KeyValuePair Current { get { if (_currentChunkSize == null) { throw new InvalidOperationException(System.SR.PartitionerStatic_CurrentCalledBeforeMoveNext); } return new KeyValuePair(_startIndex + _localOffset.Value, _sharedReader[_startIndex + _localOffset.Value]); } } internal InternalPartitionEnumerator(IList sharedReader, SharedLong sharedIndex) : base(sharedReader, sharedIndex) { } } internal DynamicPartitionerForIList(IList source) : base(source) { } protected override IEnumerable> GetOrderableDynamicPartitions_Factory(IList _data) { return new InternalPartitionEnumerable(_data); } } private sealed class DynamicPartitionerForArray : DynamicPartitionerForIndexRange_Abstract { private sealed class InternalPartitionEnumerable : IEnumerable>, IEnumerable { private readonly TSource[] _sharedReader; private readonly SharedLong _sharedIndex; internal InternalPartitionEnumerable(TSource[] sharedReader) { _sharedReader = sharedReader; _sharedIndex = new SharedLong(-1L); } IEnumerator IEnumerable.GetEnumerator() { return GetEnumerator(); } public IEnumerator> GetEnumerator() { return new InternalPartitionEnumerator(_sharedReader, _sharedIndex); } } private sealed class InternalPartitionEnumerator : DynamicPartitionEnumeratorForIndexRange_Abstract { protected override int SourceCount => _sharedReader.Length; public override KeyValuePair Current { get { if (_currentChunkSize == null) { throw new InvalidOperationException(System.SR.PartitionerStatic_CurrentCalledBeforeMoveNext); } return new KeyValuePair(_startIndex + _localOffset.Value, _sharedReader[_startIndex + _localOffset.Value]); } } internal InternalPartitionEnumerator(TSource[] sharedReader, SharedLong sharedIndex) : base(sharedReader, sharedIndex) { } } internal DynamicPartitionerForArray(TSource[] source) : base(source) { } protected override IEnumerable> GetOrderableDynamicPartitions_Factory(TSource[] _data) { return new InternalPartitionEnumerable(_data); } } private abstract class StaticIndexRangePartitioner : OrderablePartitioner { protected abstract int SourceCount { get; } protected StaticIndexRangePartitioner() : base(keysOrderedInEachPartition: true, keysOrderedAcrossPartitions: true, keysNormalized: true) { } protected abstract IEnumerator> CreatePartition(int startIndex, int endIndex); public override IList>> GetOrderablePartitions(int partitionCount) { if (partitionCount <= 0) { throw new ArgumentOutOfRangeException("partitionCount"); } int num = SourceCount / partitionCount; int num2 = SourceCount % partitionCount; IEnumerator>[] array = new IEnumerator>[partitionCount]; int num3 = -1; for (int i = 0; i < partitionCount; i++) { int num4 = num3 + 1; num3 = ((i >= num2) ? (num4 + num - 1) : (num4 + num)); array[i] = CreatePartition(num4, num3); } return array; } } private abstract class StaticIndexRangePartition : IEnumerator>, IDisposable, IEnumerator { protected readonly int _startIndex; protected readonly int _endIndex; protected volatile int _offset; public abstract KeyValuePair Current { get; } object IEnumerator.Current => Current; protected StaticIndexRangePartition(int startIndex, int endIndex) { _startIndex = startIndex; _endIndex = endIndex; _offset = startIndex - 1; } public void Dispose() { } public void Reset() { throw new NotSupportedException(); } public bool MoveNext() { if (_offset < _endIndex) { _offset++; return true; } _offset = _endIndex + 1; return false; } } private sealed class StaticIndexRangePartitionerForIList : StaticIndexRangePartitioner> { private readonly IList _list; protected override int SourceCount => _list.Count; internal StaticIndexRangePartitionerForIList(IList list) { _list = list; } protected override IEnumerator> CreatePartition(int startIndex, int endIndex) { return new StaticIndexRangePartitionForIList(_list, startIndex, endIndex); } } private sealed class StaticIndexRangePartitionForIList : StaticIndexRangePartition { private readonly IList _list; public override KeyValuePair Current { get { if (_offset < _startIndex) { throw new InvalidOperationException(System.SR.PartitionerStatic_CurrentCalledBeforeMoveNext); } return new KeyValuePair(_offset, _list[_offset]); } } internal StaticIndexRangePartitionForIList(IList list, int startIndex, int endIndex) : base(startIndex, endIndex) { _list = list; } } private sealed class StaticIndexRangePartitionerForArray : StaticIndexRangePartitioner { private readonly TSource[] _array; protected override int SourceCount => _array.Length; internal StaticIndexRangePartitionerForArray(TSource[] array) { _array = array; } protected override IEnumerator> CreatePartition(int startIndex, int endIndex) { return new StaticIndexRangePartitionForArray(_array, startIndex, endIndex); } } private sealed class StaticIndexRangePartitionForArray : StaticIndexRangePartition { private readonly TSource[] _array; public override KeyValuePair Current { get { if (_offset < _startIndex) { throw new InvalidOperationException(System.SR.PartitionerStatic_CurrentCalledBeforeMoveNext); } return new KeyValuePair(_offset, _array[_offset]); } } internal StaticIndexRangePartitionForArray(TSource[] array, int startIndex, int endIndex) : base(startIndex, endIndex) { _array = array; } } private sealed class SharedInt { internal volatile int Value; internal SharedInt(int value) { Value = value; } } private sealed class SharedBool { internal volatile bool Value; internal SharedBool(bool value) { Value = value; } } private sealed class SharedLong { internal long Value; internal SharedLong(long value) { Value = value; } } public static OrderablePartitioner Create(IList list, bool loadBalance) { if (list == null) { throw new ArgumentNullException("list"); } if (loadBalance) { return new DynamicPartitionerForIList(list); } return new StaticIndexRangePartitionerForIList(list); } public static OrderablePartitioner Create(TSource[] array, bool loadBalance) { if (array == null) { throw new ArgumentNullException("array"); } if (loadBalance) { return new DynamicPartitionerForArray(array); } return new StaticIndexRangePartitionerForArray(array); } public static OrderablePartitioner Create(IEnumerable source) { return Create(source, EnumerablePartitionerOptions.None); } public static OrderablePartitioner Create(IEnumerable source, EnumerablePartitionerOptions partitionerOptions) { if (source == null) { throw new ArgumentNullException("source"); } if (((uint)partitionerOptions & 0xFFFFFFFEu) != 0) { throw new ArgumentOutOfRangeException("partitionerOptions"); } return new DynamicPartitionerForIEnumerable(source, partitionerOptions); } public static OrderablePartitioner> Create(long fromInclusive, long toExclusive) { if (toExclusive <= fromInclusive) { throw new ArgumentOutOfRangeException("toExclusive"); } decimal num = (decimal)toExclusive - (decimal)fromInclusive; long num2 = (long)(num / (decimal)(Environment.ProcessorCount * 3)); if (num2 == 0L) { num2 = 1L; } return Create(CreateRanges(fromInclusive, toExclusive, num2), EnumerablePartitionerOptions.NoBuffering); } public static OrderablePartitioner> Create(long fromInclusive, long toExclusive, long rangeSize) { if (toExclusive <= fromInclusive) { throw new ArgumentOutOfRangeException("toExclusive"); } if (rangeSize <= 0) { throw new ArgumentOutOfRangeException("rangeSize"); } return Create(CreateRanges(fromInclusive, toExclusive, rangeSize), EnumerablePartitionerOptions.NoBuffering); } private static IEnumerable> CreateRanges(long fromInclusive, long toExclusive, long rangeSize) { bool shouldQuit = false; for (long i = fromInclusive; i < toExclusive; i += rangeSize) { if (shouldQuit) { break; } long item = i; long num; try { num = checked(i + rangeSize); } catch (OverflowException) { num = toExclusive; shouldQuit = true; } if (num > toExclusive) { num = toExclusive; } yield return new Tuple(item, num); } } public static OrderablePartitioner> Create(int fromInclusive, int toExclusive) { if (toExclusive <= fromInclusive) { throw new ArgumentOutOfRangeException("toExclusive"); } long num = (long)toExclusive - (long)fromInclusive; int num2 = (int)(num / (Environment.ProcessorCount * 3)); if (num2 == 0) { num2 = 1; } return Create(CreateRanges(fromInclusive, toExclusive, num2), EnumerablePartitionerOptions.NoBuffering); } public static OrderablePartitioner> Create(int fromInclusive, int toExclusive, int rangeSize) { if (toExclusive <= fromInclusive) { throw new ArgumentOutOfRangeException("toExclusive"); } if (rangeSize <= 0) { throw new ArgumentOutOfRangeException("rangeSize"); } return Create(CreateRanges(fromInclusive, toExclusive, rangeSize), EnumerablePartitionerOptions.NoBuffering); } private static IEnumerable> CreateRanges(int fromInclusive, int toExclusive, int rangeSize) { bool shouldQuit = false; for (int i = fromInclusive; i < toExclusive; i += rangeSize) { if (shouldQuit) { break; } int item = i; int num; try { num = checked(i + rangeSize); } catch (OverflowException) { num = toExclusive; shouldQuit = true; } if (num > toExclusive) { num = toExclusive; } yield return new Tuple(item, num); } } private static int GetDefaultChunkSize() { if (typeof(TSource).IsValueType) { return 128; } return 512 / IntPtr.Size; } } internal sealed class IProducerConsumerCollectionDebugView { private readonly IProducerConsumerCollection _collection; [DebuggerBrowsable(DebuggerBrowsableState.RootHidden)] public T[] Items => _collection.ToArray(); public IProducerConsumerCollectionDebugView(IProducerConsumerCollection collection) { _collection = collection ?? throw new ArgumentNullException("collection"); } } }