using System; using System.Buffers; using System.Collections.Generic; using System.Collections.Immutable; using System.ComponentModel; using System.Diagnostics; using System.Diagnostics.CodeAnalysis; using System.Linq; using System.Numerics; using System.Reflection; using System.Resources; using System.Runtime.CompilerServices; using System.Runtime.InteropServices; using System.Runtime.Versioning; using System.Security; using System.Security.Permissions; using System.Threading; using FxResources.System.Collections.Immutable; using Microsoft.CodeAnalysis; [assembly: CompilationRelaxations(8)] [assembly: RuntimeCompatibility(WrapNonExceptionThrows = true)] [assembly: Debuggable(DebuggableAttribute.DebuggingModes.IgnoreSymbolStoreSequencePoints)] [assembly: InternalsVisibleTo("System.Collections.Immutable.Tests, PublicKey=00240000048000009400000006020000002400005253413100040000010001004b86c4cb78549b34bab61a3b1800e23bfeb5b3ec390074041536a7e3cbd97f5f04cf0f857155a8928eaa29ebfd11cfbbad3ba70efea7bda3226c6a8d370a4cd303f714486b6ebc225985a638471e6ef571cc92a4613c00b8fa65d61ccee0cbe5f36330c9a01f4183559f1bef24cc2917c6d913e3a541333a1d05d9bed22b38cb")] [assembly: TargetFramework(".NETStandard,Version=v2.0", FrameworkDisplayName = ".NET Standard 2.0")] [assembly: AssemblyMetadata("Serviceable", "True")] [assembly: AssemblyMetadata("PreferInbox", "True")] [assembly: AssemblyDefaultAlias("System.Collections.Immutable")] [assembly: NeutralResourcesLanguage("en-US")] [assembly: CLSCompliant(true)] [assembly: AssemblyMetadata("IsTrimmable", "True")] [assembly: DefaultDllImportSearchPaths(DllImportSearchPath.System32 | DllImportSearchPath.AssemblyDirectory)] [assembly: AssemblyCompany("Microsoft Corporation")] [assembly: AssemblyCopyright("© Microsoft Corporation. All rights reserved.")] [assembly: AssemblyDescription("This package provides collections that are thread safe and guaranteed to never change their contents, also known as immutable collections. Like strings, any methods that perform modifications will not change the existing instance but instead return a new instance. For efficiency reasons, the implementation uses a sharing mechanism to ensure that newly created instances share as much data as possible with the previous instance while ensuring that operations have a predictable time complexity.\r\n\r\nThe System.Collections.Immutable library is built-in as part of the shared framework in .NET Runtime. The package can be installed when you need to use it in other target frameworks.")] [assembly: AssemblyFileVersion("9.0.925.41916")] [assembly: AssemblyInformationalVersion("9.0.9+893c2ebbd49952ca49e93298148af2d95a61a0a4")] [assembly: AssemblyProduct("Microsoft® .NET")] [assembly: AssemblyTitle("System.Collections.Immutable")] [assembly: AssemblyMetadata("RepositoryUrl", "https://github.com/dotnet/runtime")] [assembly: SecurityPermission(SecurityAction.RequestMinimum, SkipVerification = true)] [assembly: AssemblyVersion("9.0.0.0")] [module: UnverifiableCode] [module: RefSafetyRules(11)] [module: System.Runtime.CompilerServices.NullablePublicOnly(true)] namespace Microsoft.CodeAnalysis { [CompilerGenerated] [Microsoft.CodeAnalysis.Embedded] internal sealed class EmbeddedAttribute : Attribute { } } namespace System.Runtime.CompilerServices { [CompilerGenerated] [Microsoft.CodeAnalysis.Embedded] internal sealed class IsReadOnlyAttribute : Attribute { } [CompilerGenerated] [Microsoft.CodeAnalysis.Embedded] internal sealed class ParamCollectionAttribute : Attribute { } [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; } } [CompilerGenerated] [Microsoft.CodeAnalysis.Embedded] [AttributeUsage(AttributeTargets.Parameter, AllowMultiple = false, Inherited = false)] internal sealed class ScopedRefAttribute : Attribute { } [CompilerGenerated] [Microsoft.CodeAnalysis.Embedded] [AttributeUsage(AttributeTargets.Module, AllowMultiple = false, Inherited = false)] internal sealed class RefSafetyRulesAttribute : Attribute { public readonly int Version; public RefSafetyRulesAttribute(int P_0) { Version = P_0; } } } namespace FxResources.System.Collections.Immutable { internal static class SR { } } namespace System { internal static class SR { private static readonly bool s_usingResourceKeys = GetUsingResourceKeysSwitchValue(); private static ResourceManager s_resourceManager; internal static ResourceManager ResourceManager => s_resourceManager ?? (s_resourceManager = new ResourceManager(typeof(SR))); internal static string Arg_KeyNotFoundWithKey => GetResourceString("Arg_KeyNotFoundWithKey"); internal static string ArrayInitializedStateNotEqual => GetResourceString("ArrayInitializedStateNotEqual"); internal static string ArrayLengthsNotEqual => GetResourceString("ArrayLengthsNotEqual"); internal static string CannotFindOldValue => GetResourceString("CannotFindOldValue"); internal static string CapacityMustBeGreaterThanOrEqualToCount => GetResourceString("CapacityMustBeGreaterThanOrEqualToCount"); internal static string CapacityMustEqualCountOnMove => GetResourceString("CapacityMustEqualCountOnMove"); internal static string CollectionModifiedDuringEnumeration => GetResourceString("CollectionModifiedDuringEnumeration"); internal static string DuplicateKey => GetResourceString("DuplicateKey"); internal static string InvalidEmptyOperation => GetResourceString("InvalidEmptyOperation"); internal static string InvalidOperationOnDefaultArray => GetResourceString("InvalidOperationOnDefaultArray"); internal static string Arg_HTCapacityOverflow => GetResourceString("Arg_HTCapacityOverflow"); internal static string Arg_RankMultiDimNotSupported => GetResourceString("Arg_RankMultiDimNotSupported"); internal static string Arg_NonZeroLowerBound => GetResourceString("Arg_NonZeroLowerBound"); internal static string Arg_ArrayPlusOffTooSmall => GetResourceString("Arg_ArrayPlusOffTooSmall"); internal static string Argument_IncompatibleArrayType => GetResourceString("Argument_IncompatibleArrayType"); internal static string ArgumentOutOfRange_NeedNonNegNum => GetResourceString("ArgumentOutOfRange_NeedNonNegNum"); internal static string InvalidOperation_IncompatibleComparer => GetResourceString("InvalidOperation_IncompatibleComparer"); private static bool GetUsingResourceKeysSwitchValue() { if (!AppContext.TryGetSwitch("System.Resources.UseSystemResourceKeys", out var isEnabled)) { return false; } return isEnabled; } internal static bool UsingResourceKeys() { return s_usingResourceKeys; } private static string GetResourceString(string resourceKey) { if (UsingResourceKeys()) { return resourceKey; } string result = null; try { result = ResourceManager.GetString(resourceKey); } catch (MissingManifestResourceException) { } return result; } private static string GetResourceString(string resourceKey, string defaultString) { string resourceString = GetResourceString(resourceKey); if (!(resourceKey == resourceString) && resourceString != null) { return resourceString; } return defaultString; } internal static string Format(string resourceFormat, object? p1) { if (UsingResourceKeys()) { return string.Join(", ", resourceFormat, p1); } return string.Format(resourceFormat, p1); } internal static string Format(string resourceFormat, object? p1, object? p2) { if (UsingResourceKeys()) { return string.Join(", ", resourceFormat, p1, p2); } return string.Format(resourceFormat, p1, p2); } internal static string Format(string resourceFormat, object? p1, object? p2, object? p3) { if (UsingResourceKeys()) { return string.Join(", ", resourceFormat, p1, p2, p3); } return string.Format(resourceFormat, p1, p2, p3); } internal static string Format(string resourceFormat, params object?[]? args) { if (args != null) { if (UsingResourceKeys()) { return resourceFormat + ", " + string.Join(", ", args); } return string.Format(resourceFormat, args); } return resourceFormat; } internal static string Format(IFormatProvider? provider, string resourceFormat, object? p1) { if (UsingResourceKeys()) { return string.Join(", ", resourceFormat, p1); } return string.Format(provider, resourceFormat, p1); } internal static string Format(IFormatProvider? provider, string resourceFormat, object? p1, object? p2) { if (UsingResourceKeys()) { return string.Join(", ", resourceFormat, p1, p2); } return string.Format(provider, resourceFormat, p1, p2); } internal static string Format(IFormatProvider? provider, string resourceFormat, object? p1, object? p2, object? p3) { if (UsingResourceKeys()) { return string.Join(", ", resourceFormat, p1, p2, p3); } return string.Format(provider, resourceFormat, p1, p2, p3); } internal static string Format(IFormatProvider? provider, string resourceFormat, params object?[]? args) { if (args != null) { if (UsingResourceKeys()) { return resourceFormat + ", " + string.Join(", ", args); } return string.Format(provider, resourceFormat, args); } return resourceFormat; } } } namespace System.Diagnostics.CodeAnalysis { [AttributeUsage(AttributeTargets.Property | AttributeTargets.Field | AttributeTargets.Parameter, Inherited = false)] internal sealed class AllowNullAttribute : Attribute { } [AttributeUsage(AttributeTargets.Property | AttributeTargets.Field | AttributeTargets.Parameter, Inherited = false)] internal sealed class DisallowNullAttribute : Attribute { } [AttributeUsage(AttributeTargets.Property | AttributeTargets.Field | AttributeTargets.Parameter | AttributeTargets.ReturnValue, Inherited = false)] internal sealed class MaybeNullAttribute : Attribute { } [AttributeUsage(AttributeTargets.Property | AttributeTargets.Field | AttributeTargets.Parameter | AttributeTargets.ReturnValue, Inherited = false)] internal sealed class NotNullAttribute : Attribute { } [AttributeUsage(AttributeTargets.Parameter, Inherited = false)] internal sealed class MaybeNullWhenAttribute : Attribute { public bool ReturnValue { get; } public MaybeNullWhenAttribute(bool returnValue) { ReturnValue = returnValue; } } [AttributeUsage(AttributeTargets.Parameter, Inherited = false)] internal sealed class NotNullWhenAttribute : Attribute { public bool ReturnValue { get; } public NotNullWhenAttribute(bool returnValue) { ReturnValue = returnValue; } } [AttributeUsage(AttributeTargets.Property | AttributeTargets.Parameter | AttributeTargets.ReturnValue, AllowMultiple = true, Inherited = false)] internal sealed class NotNullIfNotNullAttribute : Attribute { public string ParameterName { get; } public NotNullIfNotNullAttribute(string parameterName) { ParameterName = parameterName; } } [AttributeUsage(AttributeTargets.Method, Inherited = false)] internal sealed class DoesNotReturnAttribute : Attribute { } [AttributeUsage(AttributeTargets.Parameter, Inherited = false)] internal sealed class DoesNotReturnIfAttribute : Attribute { public bool ParameterValue { get; } public DoesNotReturnIfAttribute(bool parameterValue) { ParameterValue = parameterValue; } } [AttributeUsage(AttributeTargets.Method | AttributeTargets.Property, Inherited = false, AllowMultiple = true)] internal sealed class MemberNotNullAttribute : Attribute { public string[] Members { get; } public MemberNotNullAttribute(string member) { Members = new string[1] { member }; } public MemberNotNullAttribute(params string[] members) { Members = members; } } [AttributeUsage(AttributeTargets.Method | AttributeTargets.Property, Inherited = false, AllowMultiple = true)] internal sealed class MemberNotNullWhenAttribute : Attribute { public bool ReturnValue { get; } public string[] Members { get; } public MemberNotNullWhenAttribute(bool returnValue, string member) { ReturnValue = returnValue; Members = new string[1] { member }; } public MemberNotNullWhenAttribute(bool returnValue, params string[] members) { ReturnValue = returnValue; Members = members; } } } namespace System.Linq { public static class ImmutableArrayExtensions { public static IEnumerable Select(this ImmutableArray immutableArray, Func selector) { immutableArray.ThrowNullRefIfNotInitialized(); return immutableArray.array.Select(selector); } public static IEnumerable SelectMany(this ImmutableArray immutableArray, Func> collectionSelector, Func resultSelector) { immutableArray.ThrowNullRefIfNotInitialized(); if (collectionSelector == null || resultSelector == null) { return Enumerable.SelectMany(immutableArray, collectionSelector, resultSelector); } if (immutableArray.Length != 0) { return immutableArray.SelectManyIterator(collectionSelector, resultSelector); } return Enumerable.Empty(); } public static IEnumerable Where(this ImmutableArray immutableArray, Func predicate) { immutableArray.ThrowNullRefIfNotInitialized(); return immutableArray.array.Where(predicate); } public static bool Any(this ImmutableArray immutableArray) { return immutableArray.Length > 0; } public static bool Any(this ImmutableArray immutableArray, Func predicate) { immutableArray.ThrowNullRefIfNotInitialized(); Requires.NotNull(predicate, "predicate"); T[] array = immutableArray.array; foreach (T arg in array) { if (predicate(arg)) { return true; } } return false; } public static bool All(this ImmutableArray immutableArray, Func predicate) { immutableArray.ThrowNullRefIfNotInitialized(); Requires.NotNull(predicate, "predicate"); T[] array = immutableArray.array; foreach (T arg in array) { if (!predicate(arg)) { return false; } } return true; } public static bool SequenceEqual(this ImmutableArray immutableArray, ImmutableArray items, IEqualityComparer? comparer = null) where TDerived : TBase { immutableArray.ThrowNullRefIfNotInitialized(); items.ThrowNullRefIfNotInitialized(); if (immutableArray.array == items.array) { return true; } if (immutableArray.Length != items.Length) { return false; } if (comparer == null) { comparer = EqualityComparer.Default; } for (int i = 0; i < immutableArray.Length; i++) { if (!comparer.Equals(immutableArray.array[i], (TBase)(object)items.array[i])) { return false; } } return true; } public static bool SequenceEqual(this ImmutableArray immutableArray, IEnumerable items, IEqualityComparer? comparer = null) where TDerived : TBase { Requires.NotNull(items, "items"); if (comparer == null) { comparer = EqualityComparer.Default; } int num = 0; int length = immutableArray.Length; foreach (TDerived item in items) { if (num == length) { return false; } if (!comparer.Equals(immutableArray[num], (TBase)(object)item)) { return false; } num++; } return num == length; } public static bool SequenceEqual(this ImmutableArray immutableArray, ImmutableArray items, Func predicate) where TDerived : TBase { Requires.NotNull(predicate, "predicate"); immutableArray.ThrowNullRefIfNotInitialized(); items.ThrowNullRefIfNotInitialized(); if (immutableArray.array == items.array) { return true; } if (immutableArray.Length != items.Length) { return false; } int i = 0; for (int length = immutableArray.Length; i < length; i++) { if (!predicate(immutableArray[i], (TBase)(object)items[i])) { return false; } } return true; } public static T? Aggregate(this ImmutableArray immutableArray, Func func) { Requires.NotNull(func, "func"); if (immutableArray.Length == 0) { return default(T); } T val = immutableArray[0]; int i = 1; for (int length = immutableArray.Length; i < length; i++) { val = func(val, immutableArray[i]); } return val; } public static TAccumulate Aggregate(this ImmutableArray immutableArray, TAccumulate seed, Func func) { Requires.NotNull(func, "func"); TAccumulate val = seed; T[] array = immutableArray.array; foreach (T arg in array) { val = func(val, arg); } return val; } public static TResult Aggregate(this ImmutableArray immutableArray, TAccumulate seed, Func func, Func resultSelector) { Requires.NotNull(resultSelector, "resultSelector"); return resultSelector(immutableArray.Aggregate(seed, func)); } public static T ElementAt(this ImmutableArray immutableArray, int index) { return immutableArray[index]; } public static T? ElementAtOrDefault(this ImmutableArray immutableArray, int index) { if (index < 0 || index >= immutableArray.Length) { return default(T); } return immutableArray[index]; } public static T First(this ImmutableArray immutableArray, Func predicate) { Requires.NotNull(predicate, "predicate"); T[] array = immutableArray.array; foreach (T val in array) { if (predicate(val)) { return val; } } return Enumerable.Empty().First(); } public static T First(this ImmutableArray immutableArray) { if (immutableArray.Length <= 0) { return immutableArray.array.First(); } return immutableArray[0]; } public static T? FirstOrDefault(this ImmutableArray immutableArray) { if (immutableArray.array.Length == 0) { return default(T); } return immutableArray.array[0]; } public static T? FirstOrDefault(this ImmutableArray immutableArray, Func predicate) { Requires.NotNull(predicate, "predicate"); T[] array = immutableArray.array; foreach (T val in array) { if (predicate(val)) { return val; } } return default(T); } public static T Last(this ImmutableArray immutableArray) { if (immutableArray.Length <= 0) { return immutableArray.array.Last(); } return immutableArray[immutableArray.Length - 1]; } public static T Last(this ImmutableArray immutableArray, Func predicate) { Requires.NotNull(predicate, "predicate"); for (int num = immutableArray.Length - 1; num >= 0; num--) { if (predicate(immutableArray[num])) { return immutableArray[num]; } } return Enumerable.Empty().Last(); } public static T? LastOrDefault(this ImmutableArray immutableArray) { immutableArray.ThrowNullRefIfNotInitialized(); return immutableArray.array.LastOrDefault(); } public static T? LastOrDefault(this ImmutableArray immutableArray, Func predicate) { Requires.NotNull(predicate, "predicate"); for (int num = immutableArray.Length - 1; num >= 0; num--) { if (predicate(immutableArray[num])) { return immutableArray[num]; } } return default(T); } public static T Single(this ImmutableArray immutableArray) { immutableArray.ThrowNullRefIfNotInitialized(); return immutableArray.array.Single(); } public static T Single(this ImmutableArray immutableArray, Func predicate) { Requires.NotNull(predicate, "predicate"); bool flag = true; T result = default(T); T[] array = immutableArray.array; foreach (T val in array) { if (predicate(val)) { if (!flag) { ImmutableArray.TwoElementArray.Single(); } flag = false; result = val; } } if (flag) { Enumerable.Empty().Single(); } return result; } public static T? SingleOrDefault(this ImmutableArray immutableArray) { immutableArray.ThrowNullRefIfNotInitialized(); return immutableArray.array.SingleOrDefault(); } public static T? SingleOrDefault(this ImmutableArray immutableArray, Func predicate) { Requires.NotNull(predicate, "predicate"); bool flag = true; T result = default(T); T[] array = immutableArray.array; foreach (T val in array) { if (predicate(val)) { if (!flag) { ImmutableArray.TwoElementArray.Single(); } flag = false; result = val; } } return result; } public static Dictionary ToDictionary(this ImmutableArray immutableArray, Func keySelector) where TKey : notnull { return immutableArray.ToDictionary(keySelector, EqualityComparer.Default); } public static Dictionary ToDictionary(this ImmutableArray immutableArray, Func keySelector, Func elementSelector) where TKey : notnull { return immutableArray.ToDictionary(keySelector, elementSelector, EqualityComparer.Default); } public static Dictionary ToDictionary(this ImmutableArray immutableArray, Func keySelector, IEqualityComparer? comparer) where TKey : notnull { Requires.NotNull(keySelector, "keySelector"); Dictionary dictionary = new Dictionary(immutableArray.Length, comparer); ImmutableArray.Enumerator enumerator = immutableArray.GetEnumerator(); while (enumerator.MoveNext()) { T current = enumerator.Current; dictionary.Add(keySelector(current), current); } return dictionary; } public static Dictionary ToDictionary(this ImmutableArray immutableArray, Func keySelector, Func elementSelector, IEqualityComparer? comparer) where TKey : notnull { Requires.NotNull(keySelector, "keySelector"); Requires.NotNull(elementSelector, "elementSelector"); Dictionary dictionary = new Dictionary(immutableArray.Length, comparer); T[] array = immutableArray.array; foreach (T arg in array) { dictionary.Add(keySelector(arg), elementSelector(arg)); } return dictionary; } public static T[] ToArray(this ImmutableArray immutableArray) { immutableArray.ThrowNullRefIfNotInitialized(); if (immutableArray.array.Length == 0) { return ImmutableArray.Empty.array; } return (T[])immutableArray.array.Clone(); } public static T First(this ImmutableArray.Builder builder) { Requires.NotNull(builder, "builder"); if (!builder.Any()) { throw new InvalidOperationException(); } return builder[0]; } public static T? FirstOrDefault(this ImmutableArray.Builder builder) { Requires.NotNull(builder, "builder"); if (!builder.Any()) { return default(T); } return builder[0]; } public static T Last(this ImmutableArray.Builder builder) { Requires.NotNull(builder, "builder"); if (!builder.Any()) { throw new InvalidOperationException(); } return builder[builder.Count - 1]; } public static T? LastOrDefault(this ImmutableArray.Builder builder) { Requires.NotNull(builder, "builder"); if (!builder.Any()) { return default(T); } return builder[builder.Count - 1]; } public static bool Any(this ImmutableArray.Builder builder) { Requires.NotNull(builder, "builder"); return builder.Count > 0; } private static IEnumerable SelectManyIterator(this ImmutableArray immutableArray, Func> collectionSelector, Func resultSelector) { TSource[] array = immutableArray.array; foreach (TSource item in array) { foreach (TCollection item2 in collectionSelector(item)) { yield return resultSelector(item, item2); } } } } } namespace System.Runtime.Versioning { [AttributeUsage(AttributeTargets.Class | AttributeTargets.Struct | AttributeTargets.Constructor | AttributeTargets.Method, AllowMultiple = false, Inherited = false)] internal sealed class NonVersionableAttribute : Attribute { } } namespace System.Runtime.InteropServices { public static class ImmutableCollectionsMarshal { public static ImmutableArray AsImmutableArray(T[]? array) { return new ImmutableArray(array); } public static T[]? AsArray(ImmutableArray array) { return array.array; } } [AttributeUsage(AttributeTargets.Method, AllowMultiple = false, Inherited = false)] internal sealed class LibraryImportAttribute : Attribute { public string LibraryName { get; } public string? EntryPoint { get; set; } public StringMarshalling StringMarshalling { get; set; } public Type? StringMarshallingCustomType { get; set; } public bool SetLastError { get; set; } public LibraryImportAttribute(string libraryName) { LibraryName = libraryName; } } internal enum StringMarshalling { Custom, Utf8, Utf16 } } namespace System.Runtime.CompilerServices { [AttributeUsage(AttributeTargets.Parameter, AllowMultiple = false, Inherited = false)] internal sealed class CallerArgumentExpressionAttribute : Attribute { public string ParameterName { get; } public CallerArgumentExpressionAttribute(string parameterName) { ParameterName = parameterName; } } [AttributeUsage(AttributeTargets.Class | AttributeTargets.Struct | AttributeTargets.Interface, Inherited = false)] internal sealed class CollectionBuilderAttribute : Attribute { public Type BuilderType { get; } public string MethodName { get; } public CollectionBuilderAttribute(Type builderType, string methodName) { BuilderType = builderType; MethodName = methodName; } } } namespace System.Numerics { internal static class BitOperations { [MethodImpl(MethodImplOptions.AggressiveInlining)] public static uint RotateLeft(uint value, int offset) { return (value << offset) | (value >> 32 - offset); } } } namespace System.Collections { internal static class ThrowHelper { public static void ThrowIfNull(object arg, [CallerArgumentExpression("arg")] string? paramName = null) { if (arg == null) { ThrowArgumentNullException(paramName); } } [DoesNotReturn] public static void ThrowIfDestinationTooSmall() { throw new ArgumentException(System.SR.CapacityMustBeGreaterThanOrEqualToCount, "destination"); } [DoesNotReturn] public static void ThrowArgumentNullException(string? paramName) { throw new ArgumentNullException(paramName); } [DoesNotReturn] public static void ThrowKeyNotFoundException() { throw new KeyNotFoundException(); } [DoesNotReturn] public static void ThrowKeyNotFoundException(TKey key) { throw new KeyNotFoundException(System.SR.Format(System.SR.Arg_KeyNotFoundWithKey, key)); } [DoesNotReturn] public static void ThrowInvalidOperationException() { throw new InvalidOperationException(); } [DoesNotReturn] internal static void ThrowIncompatibleComparer() { throw new InvalidOperationException(System.SR.InvalidOperation_IncompatibleComparer); } } internal static class HashHelpers { public const uint HashCollisionThreshold = 100u; public const int MaxPrimeArrayLength = 2147483587; public const int HashPrime = 101; internal static ReadOnlySpan Primes { get { object obj = global::.74BCD6ED20AF2231F2BB1CDE814C5F4FF48E54BAC46029EEF90DDF4A208E2B20_A6; if (obj == null) { obj = new int[72] { 3, 7, 11, 17, 23, 29, 37, 47, 59, 71, 89, 107, 131, 163, 197, 239, 293, 353, 431, 521, 631, 761, 919, 1103, 1327, 1597, 1931, 2333, 2801, 3371, 4049, 4861, 5839, 7013, 8419, 10103, 12143, 14591, 17519, 21023, 25229, 30293, 36353, 43627, 52361, 62851, 75431, 90523, 108631, 130363, 156437, 187751, 225307, 270371, 324449, 389357, 467237, 560689, 672827, 807403, 968897, 1162687, 1395263, 1674319, 2009191, 2411033, 2893249, 3471899, 4166287, 4999559, 5999471, 7199369 }; global::.74BCD6ED20AF2231F2BB1CDE814C5F4FF48E54BAC46029EEF90DDF4A208E2B20_A6 = (int[])obj; } return new ReadOnlySpan((int[]?)obj); } } public static bool IsPrime(int candidate) { if (((uint)candidate & (true ? 1u : 0u)) != 0) { int num = (int)Math.Sqrt(candidate); for (int i = 3; i <= num; i += 2) { if (candidate % i == 0) { return false; } } return true; } return candidate == 2; } public static int GetPrime(int min) { if (min < 0) { throw new ArgumentException(System.SR.Arg_HTCapacityOverflow); } ReadOnlySpan primes = Primes; for (int i = 0; i < primes.Length; i++) { int num = primes[i]; if (num >= min) { return num; } } for (int j = min | 1; j < int.MaxValue; j += 2) { if (IsPrime(j) && (j - 1) % 101 != 0) { return j; } } return min; } public static int ExpandPrime(int oldSize) { int num = 2 * oldSize; if ((uint)num > 2147483587u && 2147483587 > oldSize) { return 2147483587; } return GetPrime(num); } public static ulong GetFastModMultiplier(uint divisor) { return ulong.MaxValue / (ulong)divisor + 1; } [MethodImpl(MethodImplOptions.AggressiveInlining)] public static uint FastMod(uint value, uint divisor, ulong multiplier) { return (uint)(((multiplier * value >> 32) + 1) * divisor >> 32); } } } namespace System.Collections.Immutable { internal static class AllocFreeConcurrentStack { private const int MaxSize = 35; private static readonly Type s_typeOfT = typeof(T); private static Stack> ThreadLocalStack { get { Dictionary dictionary = AllocFreeConcurrentStack.t_stacks ?? (AllocFreeConcurrentStack.t_stacks = new Dictionary()); if (!dictionary.TryGetValue(s_typeOfT, out var value)) { value = new Stack>(35); dictionary.Add(s_typeOfT, value); } return (Stack>)value; } } public static void TryAdd(T item) { Stack> threadLocalStack = ThreadLocalStack; if (threadLocalStack.Count < 35) { threadLocalStack.Push(new RefAsValueType(item)); } } public static bool TryTake([MaybeNullWhen(false)] out T item) { Stack> threadLocalStack = ThreadLocalStack; if (threadLocalStack != null && threadLocalStack.Count > 0) { item = threadLocalStack.Pop().Value; return true; } item = default(T); return false; } } internal static class AllocFreeConcurrentStack { [ThreadStatic] internal static Dictionary? t_stacks; } internal sealed class DictionaryEnumerator : IDictionaryEnumerator, IEnumerator where TKey : notnull { private readonly IEnumerator> _inner; public DictionaryEntry Entry => new DictionaryEntry(_inner.Current.Key, _inner.Current.Value); public object Key => _inner.Current.Key; public object? Value => _inner.Current.Value; public object Current => Entry; internal DictionaryEnumerator(IEnumerator> inner) { Requires.NotNull(inner, "inner"); _inner = inner; } public bool MoveNext() { return _inner.MoveNext(); } public void Reset() { _inner.Reset(); } } internal struct DisposableEnumeratorAdapter : IDisposable where TEnumerator : struct, IEnumerator { private readonly IEnumerator _enumeratorObject; private TEnumerator _enumeratorStruct; public T Current { get { if (_enumeratorObject == null) { return _enumeratorStruct.Current; } return _enumeratorObject.Current; } } internal DisposableEnumeratorAdapter(TEnumerator enumerator) { _enumeratorStruct = enumerator; _enumeratorObject = null; } internal DisposableEnumeratorAdapter(IEnumerator enumerator) { _enumeratorStruct = default(TEnumerator); _enumeratorObject = enumerator; } public bool MoveNext() { if (_enumeratorObject == null) { return _enumeratorStruct.MoveNext(); } return _enumeratorObject.MoveNext(); } public void Dispose() { if (_enumeratorObject != null) { _enumeratorObject.Dispose(); } else { _enumeratorStruct.Dispose(); } } public DisposableEnumeratorAdapter GetEnumerator() { return this; } } internal interface IBinaryTree { int Height { get; } bool IsEmpty { get; } int Count { get; } IBinaryTree? Left { get; } IBinaryTree? Right { get; } } internal interface IBinaryTree : IBinaryTree { T Value { get; } new IBinaryTree? Left { get; } new IBinaryTree? Right { get; } } internal interface IImmutableArray { Array? Array { get; } } public interface IImmutableDictionary : IReadOnlyDictionary, IEnumerable>, IEnumerable, IReadOnlyCollection> { IImmutableDictionary Clear(); IImmutableDictionary Add(TKey key, TValue value); IImmutableDictionary AddRange(IEnumerable> pairs); IImmutableDictionary SetItem(TKey key, TValue value); IImmutableDictionary SetItems(IEnumerable> items); IImmutableDictionary RemoveRange(IEnumerable keys); IImmutableDictionary Remove(TKey key); bool Contains(KeyValuePair pair); bool TryGetKey(TKey equalKey, out TKey actualKey); } internal interface IImmutableDictionaryInternal { bool ContainsValue(TValue value); } [CollectionBuilder(typeof(ImmutableList), "Create")] public interface IImmutableList : IReadOnlyList, IEnumerable, IEnumerable, IReadOnlyCollection { IImmutableList Clear(); int IndexOf(T item, int index, int count, IEqualityComparer? equalityComparer); int LastIndexOf(T item, int index, int count, IEqualityComparer? equalityComparer); IImmutableList Add(T value); IImmutableList AddRange(IEnumerable items); IImmutableList Insert(int index, T element); IImmutableList InsertRange(int index, IEnumerable items); IImmutableList Remove(T value, IEqualityComparer? equalityComparer); IImmutableList RemoveAll(Predicate match); IImmutableList RemoveRange(IEnumerable items, IEqualityComparer? equalityComparer); IImmutableList RemoveRange(int index, int count); IImmutableList RemoveAt(int index); IImmutableList SetItem(int index, T value); IImmutableList Replace(T oldValue, T newValue, IEqualityComparer? equalityComparer); } internal interface IImmutableListQueries : IReadOnlyList, IEnumerable, IEnumerable, IReadOnlyCollection { ImmutableList ConvertAll(Func converter); void ForEach(Action action); ImmutableList GetRange(int index, int count); void CopyTo(T[] array); void CopyTo(T[] array, int arrayIndex); void CopyTo(int index, T[] array, int arrayIndex, int count); bool Exists(Predicate match); T? Find(Predicate match); ImmutableList FindAll(Predicate match); int FindIndex(Predicate match); int FindIndex(int startIndex, Predicate match); int FindIndex(int startIndex, int count, Predicate match); T? FindLast(Predicate match); int FindLastIndex(Predicate match); int FindLastIndex(int startIndex, Predicate match); int FindLastIndex(int startIndex, int count, Predicate match); bool TrueForAll(Predicate match); int BinarySearch(T item); int BinarySearch(T item, IComparer? comparer); int BinarySearch(int index, int count, T item, IComparer? comparer); } [CollectionBuilder(typeof(ImmutableQueue), "Create")] public interface IImmutableQueue : IEnumerable, IEnumerable { bool IsEmpty { get; } IImmutableQueue Clear(); T Peek(); IImmutableQueue Enqueue(T value); IImmutableQueue Dequeue(); } [CollectionBuilder(typeof(ImmutableHashSet), "Create")] public interface IImmutableSet : IReadOnlyCollection, IEnumerable, IEnumerable { IImmutableSet Clear(); bool Contains(T value); IImmutableSet Add(T value); IImmutableSet Remove(T value); bool TryGetValue(T equalValue, out T actualValue); IImmutableSet Intersect(IEnumerable other); IImmutableSet Except(IEnumerable other); IImmutableSet SymmetricExcept(IEnumerable other); IImmutableSet Union(IEnumerable other); bool SetEquals(IEnumerable other); bool IsProperSubsetOf(IEnumerable other); bool IsProperSupersetOf(IEnumerable other); bool IsSubsetOf(IEnumerable other); bool IsSupersetOf(IEnumerable other); bool Overlaps(IEnumerable other); } [CollectionBuilder(typeof(ImmutableStack), "Create")] public interface IImmutableStack : IEnumerable, IEnumerable { bool IsEmpty { get; } IImmutableStack Clear(); IImmutableStack Push(T value); IImmutableStack Pop(); T Peek(); } [CollectionBuilder(typeof(ImmutableHashSet), "Create")] [DebuggerDisplay("Count = {Count}")] [DebuggerTypeProxy(typeof(ImmutableEnumerableDebuggerProxy<>))] public sealed class ImmutableHashSet : IImmutableSet, IReadOnlyCollection, IEnumerable, IEnumerable, IHashKeyCollection, ICollection, ISet, ICollection, IStrongEnumerable.Enumerator> { private sealed class HashBucketByValueEqualityComparer : IEqualityComparer { private static readonly IEqualityComparer s_defaultInstance = new HashBucketByValueEqualityComparer(EqualityComparer.Default); private readonly IEqualityComparer _valueComparer; internal static IEqualityComparer DefaultInstance => s_defaultInstance; internal HashBucketByValueEqualityComparer(IEqualityComparer valueComparer) { Requires.NotNull(valueComparer, "valueComparer"); _valueComparer = valueComparer; } public bool Equals(HashBucket x, HashBucket y) { return x.EqualsByValue(y, _valueComparer); } public int GetHashCode(HashBucket obj) { throw new NotSupportedException(); } } private sealed class HashBucketByRefEqualityComparer : IEqualityComparer { private static readonly IEqualityComparer s_defaultInstance = new HashBucketByRefEqualityComparer(); internal static IEqualityComparer DefaultInstance => s_defaultInstance; private HashBucketByRefEqualityComparer() { } public bool Equals(HashBucket x, HashBucket y) { return x.EqualsByRef(y); } public int GetHashCode(HashBucket obj) { throw new NotSupportedException(); } } [DebuggerDisplay("Count = {Count}")] public sealed class Builder : IReadOnlyCollection, IEnumerable, IEnumerable, ISet, ICollection { private SortedInt32KeyNode _root = SortedInt32KeyNode.EmptyNode; private IEqualityComparer _equalityComparer; private readonly IEqualityComparer _hashBucketEqualityComparer; private int _count; private ImmutableHashSet _immutable; private int _version; public int Count => _count; bool ICollection.IsReadOnly => false; public IEqualityComparer KeyComparer { get { return _equalityComparer; } set { Requires.NotNull(value, "value"); if (value != _equalityComparer) { MutationResult mutationResult = ImmutableHashSet.Union((IEnumerable)this, new MutationInput(SortedInt32KeyNode.EmptyNode, value, _hashBucketEqualityComparer, 0)); _immutable = null; _equalityComparer = value; Root = mutationResult.Root; _count = mutationResult.Count; } } } internal int Version => _version; private MutationInput Origin => new MutationInput(Root, _equalityComparer, _hashBucketEqualityComparer, _count); private SortedInt32KeyNode Root { get { return _root; } set { _version++; if (_root != value) { _root = value; _immutable = null; } } } internal Builder(ImmutableHashSet set) { Requires.NotNull(set, "set"); _root = set._root; _count = set._count; _equalityComparer = set._equalityComparer; _hashBucketEqualityComparer = set._hashBucketEqualityComparer; _immutable = set; } public Enumerator GetEnumerator() { return new Enumerator(_root, this); } public ImmutableHashSet ToImmutable() { return _immutable ?? (_immutable = ImmutableHashSet.Wrap(_root, _equalityComparer, _count)); } public bool TryGetValue(T equalValue, out T actualValue) { int key = ((equalValue != null) ? _equalityComparer.GetHashCode(equalValue) : 0); if (_root.TryGetValue(key, out var value)) { return value.TryExchange(equalValue, _equalityComparer, out actualValue); } actualValue = equalValue; return false; } public bool Add(T item) { MutationResult result = ImmutableHashSet.Add(item, Origin); Apply(result); return result.Count != 0; } public bool Remove(T item) { MutationResult result = ImmutableHashSet.Remove(item, Origin); Apply(result); return result.Count != 0; } public bool Contains(T item) { return ImmutableHashSet.Contains(item, Origin); } public void Clear() { _count = 0; Root = SortedInt32KeyNode.EmptyNode; } public void ExceptWith(IEnumerable other) { MutationResult result = ImmutableHashSet.Except(other, _equalityComparer, _hashBucketEqualityComparer, _root); Apply(result); } public void IntersectWith(IEnumerable other) { MutationResult result = ImmutableHashSet.Intersect(other, Origin); Apply(result); } public bool IsProperSubsetOf(IEnumerable other) { return ImmutableHashSet.IsProperSubsetOf(other, Origin); } public bool IsProperSupersetOf(IEnumerable other) { return ImmutableHashSet.IsProperSupersetOf(other, Origin); } public bool IsSubsetOf(IEnumerable other) { return ImmutableHashSet.IsSubsetOf(other, Origin); } public bool IsSupersetOf(IEnumerable other) { return ImmutableHashSet.IsSupersetOf(other, Origin); } public bool Overlaps(IEnumerable other) { return ImmutableHashSet.Overlaps(other, Origin); } public bool SetEquals(IEnumerable other) { if (this == other) { return true; } return ImmutableHashSet.SetEquals(other, Origin); } public void SymmetricExceptWith(IEnumerable other) { MutationResult result = ImmutableHashSet.SymmetricExcept(other, Origin); Apply(result); } public void UnionWith(IEnumerable other) { MutationResult result = ImmutableHashSet.Union(other, Origin); Apply(result); } void ICollection.Add(T item) { Add(item); } void ICollection.CopyTo(T[] array, int arrayIndex) { Requires.NotNull(array, "array"); Requires.Range(arrayIndex >= 0, "arrayIndex"); Requires.Range(array.Length >= arrayIndex + Count, "arrayIndex"); using Enumerator enumerator = GetEnumerator(); while (enumerator.MoveNext()) { T current = enumerator.Current; array[arrayIndex++] = current; } } IEnumerator IEnumerable.GetEnumerator() { return GetEnumerator(); } IEnumerator IEnumerable.GetEnumerator() { return GetEnumerator(); } private void Apply(MutationResult result) { Root = result.Root; if (result.CountType == CountType.Adjustment) { _count += result.Count; } else { _count = result.Count; } } } public struct Enumerator : IEnumerator, IEnumerator, IDisposable, IStrongEnumerator { private readonly Builder _builder; private SortedInt32KeyNode.Enumerator _mapEnumerator; private HashBucket.Enumerator _bucketEnumerator; private int _enumeratingBuilderVersion; public T Current { get { _mapEnumerator.ThrowIfDisposed(); return _bucketEnumerator.Current; } } object? IEnumerator.Current => Current; internal Enumerator(SortedInt32KeyNode root, Builder? builder = null) { _builder = builder; _mapEnumerator = new SortedInt32KeyNode.Enumerator(root); _bucketEnumerator = default(HashBucket.Enumerator); _enumeratingBuilderVersion = builder?.Version ?? (-1); } public bool MoveNext() { ThrowIfChanged(); if (_bucketEnumerator.MoveNext()) { return true; } if (_mapEnumerator.MoveNext()) { _bucketEnumerator = new HashBucket.Enumerator(_mapEnumerator.Current.Value); return _bucketEnumerator.MoveNext(); } return false; } public void Reset() { _enumeratingBuilderVersion = ((_builder != null) ? _builder.Version : (-1)); _mapEnumerator.Reset(); _bucketEnumerator.Dispose(); _bucketEnumerator = default(HashBucket.Enumerator); } public void Dispose() { _mapEnumerator.Dispose(); _bucketEnumerator.Dispose(); } private void ThrowIfChanged() { if (_builder != null && _builder.Version != _enumeratingBuilderVersion) { throw new InvalidOperationException(System.SR.CollectionModifiedDuringEnumeration); } } } internal enum OperationResult { SizeChanged, NoChangeRequired } internal readonly struct HashBucket { internal struct Enumerator : IEnumerator, IEnumerator, IDisposable { private enum Position { BeforeFirst, First, Additional, End } private readonly HashBucket _bucket; private bool _disposed; private Position _currentPosition; private ImmutableList.Enumerator _additionalEnumerator; object? IEnumerator.Current => Current; public T Current { get { ThrowIfDisposed(); return _currentPosition switch { Position.First => _bucket._firstValue, Position.Additional => _additionalEnumerator.Current, _ => throw new InvalidOperationException(), }; } } internal Enumerator(HashBucket bucket) { _disposed = false; _bucket = bucket; _currentPosition = Position.BeforeFirst; _additionalEnumerator = default(ImmutableList.Enumerator); } public bool MoveNext() { ThrowIfDisposed(); if (_bucket.IsEmpty) { _currentPosition = Position.End; return false; } switch (_currentPosition) { case Position.BeforeFirst: _currentPosition = Position.First; return true; case Position.First: if (_bucket._additionalElements.IsEmpty) { _currentPosition = Position.End; return false; } _currentPosition = Position.Additional; _additionalEnumerator = new ImmutableList.Enumerator(_bucket._additionalElements); return _additionalEnumerator.MoveNext(); case Position.Additional: return _additionalEnumerator.MoveNext(); case Position.End: return false; default: throw new InvalidOperationException(); } } public void Reset() { ThrowIfDisposed(); _additionalEnumerator.Dispose(); _currentPosition = Position.BeforeFirst; } public void Dispose() { _disposed = true; _additionalEnumerator.Dispose(); } private void ThrowIfDisposed() { if (_disposed) { Requires.FailObjectDisposed(this); } } } private readonly T _firstValue; private readonly ImmutableList.Node _additionalElements; internal bool IsEmpty => _additionalElements == null; private HashBucket(T firstElement, ImmutableList.Node additionalElements = null) { _firstValue = firstElement; _additionalElements = additionalElements ?? ImmutableList.Node.EmptyNode; } public Enumerator GetEnumerator() { return new Enumerator(this); } public override bool Equals(object? obj) { throw new NotSupportedException(); } public override int GetHashCode() { throw new NotSupportedException(); } internal bool EqualsByRef(HashBucket other) { if ((object)_firstValue == (object)other._firstValue) { return _additionalElements == other._additionalElements; } return false; } internal bool EqualsByValue(HashBucket other, IEqualityComparer valueComparer) { if (valueComparer.Equals(_firstValue, other._firstValue)) { return _additionalElements == other._additionalElements; } return false; } internal HashBucket Add(T value, IEqualityComparer valueComparer, out OperationResult result) { if (IsEmpty) { result = OperationResult.SizeChanged; return new HashBucket(value); } if (valueComparer.Equals(value, _firstValue) || _additionalElements.IndexOf(value, valueComparer) >= 0) { result = OperationResult.NoChangeRequired; return this; } result = OperationResult.SizeChanged; return new HashBucket(_firstValue, _additionalElements.Add(value)); } internal bool Contains(T value, IEqualityComparer valueComparer) { if (IsEmpty) { return false; } if (!valueComparer.Equals(value, _firstValue)) { return _additionalElements.IndexOf(value, valueComparer) >= 0; } return true; } internal bool TryExchange(T value, IEqualityComparer valueComparer, out T existingValue) { if (!IsEmpty) { if (valueComparer.Equals(value, _firstValue)) { existingValue = _firstValue; return true; } int num = _additionalElements.IndexOf(value, valueComparer); if (num >= 0) { existingValue = _additionalElements.ItemRef(num); return true; } } existingValue = value; return false; } internal HashBucket Remove(T value, IEqualityComparer equalityComparer, out OperationResult result) { if (IsEmpty) { result = OperationResult.NoChangeRequired; return this; } if (equalityComparer.Equals(_firstValue, value)) { if (_additionalElements.IsEmpty) { result = OperationResult.SizeChanged; return default(HashBucket); } int count = _additionalElements.Left.Count; result = OperationResult.SizeChanged; return new HashBucket(_additionalElements.Key, _additionalElements.RemoveAt(count)); } int num = _additionalElements.IndexOf(value, equalityComparer); if (num < 0) { result = OperationResult.NoChangeRequired; return this; } result = OperationResult.SizeChanged; return new HashBucket(_firstValue, _additionalElements.RemoveAt(num)); } internal void Freeze() { _additionalElements?.Freeze(); } } private readonly struct MutationInput { private readonly SortedInt32KeyNode _root; private readonly IEqualityComparer _equalityComparer; private readonly int _count; private readonly IEqualityComparer _hashBucketEqualityComparer; internal SortedInt32KeyNode Root => _root; internal IEqualityComparer EqualityComparer => _equalityComparer; internal int Count => _count; internal IEqualityComparer HashBucketEqualityComparer => _hashBucketEqualityComparer; internal MutationInput(ImmutableHashSet set) { Requires.NotNull(set, "set"); _root = set._root; _equalityComparer = set._equalityComparer; _count = set._count; _hashBucketEqualityComparer = set._hashBucketEqualityComparer; } internal MutationInput(SortedInt32KeyNode root, IEqualityComparer equalityComparer, IEqualityComparer hashBucketEqualityComparer, int count) { Requires.NotNull(root, "root"); Requires.NotNull(equalityComparer, "equalityComparer"); Requires.Range(count >= 0, "count"); Requires.NotNull(hashBucketEqualityComparer, "hashBucketEqualityComparer"); _root = root; _equalityComparer = equalityComparer; _count = count; _hashBucketEqualityComparer = hashBucketEqualityComparer; } } private enum CountType { Adjustment, FinalValue } private readonly struct MutationResult { private readonly SortedInt32KeyNode _root; private readonly int _count; private readonly CountType _countType; internal SortedInt32KeyNode Root => _root; internal int Count => _count; internal CountType CountType => _countType; internal MutationResult(SortedInt32KeyNode root, int count, CountType countType = CountType.Adjustment) { Requires.NotNull(root, "root"); _root = root; _count = count; _countType = countType; } internal ImmutableHashSet Finalize(ImmutableHashSet priorSet) { Requires.NotNull(priorSet, "priorSet"); int num = Count; if (CountType == CountType.Adjustment) { num += priorSet._count; } return priorSet.Wrap(Root, num); } } private readonly struct NodeEnumerable : IEnumerable, IEnumerable { private readonly SortedInt32KeyNode _root; internal NodeEnumerable(SortedInt32KeyNode root) { Requires.NotNull(root, "root"); _root = root; } public Enumerator GetEnumerator() { return new Enumerator(_root); } [ExcludeFromCodeCoverage] IEnumerator IEnumerable.GetEnumerator() { return GetEnumerator(); } [ExcludeFromCodeCoverage] IEnumerator IEnumerable.GetEnumerator() { return GetEnumerator(); } } public static readonly ImmutableHashSet Empty = new ImmutableHashSet(SortedInt32KeyNode.EmptyNode, EqualityComparer.Default, 0); private static readonly Action> s_FreezeBucketAction = delegate(KeyValuePair kv) { kv.Value.Freeze(); }; private readonly IEqualityComparer _equalityComparer; private readonly int _count; private readonly SortedInt32KeyNode _root; private readonly IEqualityComparer _hashBucketEqualityComparer; public int Count => _count; public bool IsEmpty => Count == 0; public IEqualityComparer KeyComparer => _equalityComparer; [DebuggerBrowsable(DebuggerBrowsableState.Never)] object ICollection.SyncRoot => this; [DebuggerBrowsable(DebuggerBrowsableState.Never)] bool ICollection.IsSynchronized => true; internal IBinaryTree Root => _root; private MutationInput Origin => new MutationInput(this); bool ICollection.IsReadOnly => true; internal ImmutableHashSet(IEqualityComparer equalityComparer) : this(SortedInt32KeyNode.EmptyNode, equalityComparer, 0) { } private ImmutableHashSet(SortedInt32KeyNode root, IEqualityComparer equalityComparer, int count) { Requires.NotNull(root, "root"); Requires.NotNull(equalityComparer, "equalityComparer"); root.Freeze(s_FreezeBucketAction); _root = root; _count = count; _equalityComparer = equalityComparer; _hashBucketEqualityComparer = GetHashBucketEqualityComparer(equalityComparer); } public ImmutableHashSet Clear() { if (!IsEmpty) { return Empty.WithComparer(_equalityComparer); } return this; } IImmutableSet IImmutableSet.Clear() { return Clear(); } public Builder ToBuilder() { return new Builder(this); } public ImmutableHashSet Add(T item) { return Add(item, Origin).Finalize(this); } public ImmutableHashSet Remove(T item) { return Remove(item, Origin).Finalize(this); } public bool TryGetValue(T equalValue, out T actualValue) { int key = ((equalValue != null) ? _equalityComparer.GetHashCode(equalValue) : 0); if (_root.TryGetValue(key, out var value)) { return value.TryExchange(equalValue, _equalityComparer, out actualValue); } actualValue = equalValue; return false; } public ImmutableHashSet Union(IEnumerable other) { Requires.NotNull(other, "other"); return Union(other, avoidWithComparer: false); } internal ImmutableHashSet Union(ReadOnlySpan other) { return Union(other, Origin).Finalize(this); } public ImmutableHashSet Intersect(IEnumerable other) { Requires.NotNull(other, "other"); return Intersect(other, Origin).Finalize(this); } public ImmutableHashSet Except(IEnumerable other) { Requires.NotNull(other, "other"); return Except(other, _equalityComparer, _hashBucketEqualityComparer, _root).Finalize(this); } public ImmutableHashSet SymmetricExcept(IEnumerable other) { Requires.NotNull(other, "other"); return SymmetricExcept(other, Origin).Finalize(this); } public bool SetEquals(IEnumerable other) { Requires.NotNull(other, "other"); if (this == other) { return true; } return SetEquals(other, Origin); } public bool IsProperSubsetOf(IEnumerable other) { Requires.NotNull(other, "other"); return IsProperSubsetOf(other, Origin); } public bool IsProperSupersetOf(IEnumerable other) { Requires.NotNull(other, "other"); return IsProperSupersetOf(other, Origin); } public bool IsSubsetOf(IEnumerable other) { Requires.NotNull(other, "other"); return IsSubsetOf(other, Origin); } public bool IsSupersetOf(IEnumerable other) { Requires.NotNull(other, "other"); return IsSupersetOf(other, Origin); } public bool Overlaps(IEnumerable other) { Requires.NotNull(other, "other"); return Overlaps(other, Origin); } IImmutableSet IImmutableSet.Add(T item) { return Add(item); } IImmutableSet IImmutableSet.Remove(T item) { return Remove(item); } IImmutableSet IImmutableSet.Union(IEnumerable other) { return Union(other); } IImmutableSet IImmutableSet.Intersect(IEnumerable other) { return Intersect(other); } IImmutableSet IImmutableSet.Except(IEnumerable other) { return Except(other); } IImmutableSet IImmutableSet.SymmetricExcept(IEnumerable other) { return SymmetricExcept(other); } public bool Contains(T item) { return Contains(item, Origin); } public ImmutableHashSet WithComparer(IEqualityComparer? equalityComparer) { if (equalityComparer == null) { equalityComparer = EqualityComparer.Default; } if (equalityComparer == _equalityComparer) { return this; } return new ImmutableHashSet(equalityComparer).Union(this, avoidWithComparer: true); } bool ISet.Add(T item) { throw new NotSupportedException(); } void ISet.ExceptWith(IEnumerable other) { throw new NotSupportedException(); } void ISet.IntersectWith(IEnumerable other) { throw new NotSupportedException(); } void ISet.SymmetricExceptWith(IEnumerable other) { throw new NotSupportedException(); } void ISet.UnionWith(IEnumerable other) { throw new NotSupportedException(); } void ICollection.CopyTo(T[] array, int arrayIndex) { Requires.NotNull(array, "array"); Requires.Range(arrayIndex >= 0, "arrayIndex"); Requires.Range(array.Length >= arrayIndex + Count, "arrayIndex"); using Enumerator enumerator = GetEnumerator(); while (enumerator.MoveNext()) { T current = enumerator.Current; array[arrayIndex++] = current; } } void ICollection.Add(T item) { throw new NotSupportedException(); } void ICollection.Clear() { throw new NotSupportedException(); } bool ICollection.Remove(T item) { throw new NotSupportedException(); } void ICollection.CopyTo(Array array, int arrayIndex) { Requires.NotNull(array, "array"); Requires.Range(arrayIndex >= 0, "arrayIndex"); Requires.Range(array.Length >= arrayIndex + Count, "arrayIndex"); using Enumerator enumerator = GetEnumerator(); while (enumerator.MoveNext()) { T current = enumerator.Current; array.SetValue(current, arrayIndex++); } } public Enumerator GetEnumerator() { return new Enumerator(_root); } IEnumerator IEnumerable.GetEnumerator() { if (!IsEmpty) { return GetEnumerator(); } return Enumerable.Empty().GetEnumerator(); } IEnumerator IEnumerable.GetEnumerator() { return GetEnumerator(); } private static bool IsSupersetOf(IEnumerable other, MutationInput origin) { Requires.NotNull(other, "other"); foreach (T item in other.GetEnumerableDisposable()) { if (!Contains(item, origin)) { return false; } } return true; } private static MutationResult Add(T item, MutationInput origin) { int num = ((item != null) ? origin.EqualityComparer.GetHashCode(item) : 0); OperationResult result; HashBucket newBucket = origin.Root.GetValueOrDefault(num).Add(item, origin.EqualityComparer, out result); if (result == OperationResult.NoChangeRequired) { return new MutationResult(origin.Root, 0); } return new MutationResult(UpdateRoot(origin.Root, num, origin.HashBucketEqualityComparer, newBucket), 1); } private static MutationResult Remove(T item, MutationInput origin) { OperationResult result = OperationResult.NoChangeRequired; int num = ((item != null) ? origin.EqualityComparer.GetHashCode(item) : 0); SortedInt32KeyNode root = origin.Root; if (origin.Root.TryGetValue(num, out var value)) { HashBucket newBucket = value.Remove(item, origin.EqualityComparer, out result); if (result == OperationResult.NoChangeRequired) { return new MutationResult(origin.Root, 0); } root = UpdateRoot(origin.Root, num, origin.HashBucketEqualityComparer, newBucket); } return new MutationResult(root, (result == OperationResult.SizeChanged) ? (-1) : 0); } private static bool Contains(T item, MutationInput origin) { int key = ((item != null) ? origin.EqualityComparer.GetHashCode(item) : 0); if (origin.Root.TryGetValue(key, out var value)) { return value.Contains(item, origin.EqualityComparer); } return false; } private static MutationResult Union(IEnumerable other, MutationInput origin) { Requires.NotNull(other, "other"); int num = 0; SortedInt32KeyNode sortedInt32KeyNode = origin.Root; foreach (T item in other.GetEnumerableDisposable()) { int num2 = ((item != null) ? origin.EqualityComparer.GetHashCode(item) : 0); OperationResult result; HashBucket newBucket = sortedInt32KeyNode.GetValueOrDefault(num2).Add(item, origin.EqualityComparer, out result); if (result == OperationResult.SizeChanged) { sortedInt32KeyNode = UpdateRoot(sortedInt32KeyNode, num2, origin.HashBucketEqualityComparer, newBucket); num++; } } return new MutationResult(sortedInt32KeyNode, num); } private static MutationResult Union(ReadOnlySpan other, MutationInput origin) { int num = 0; SortedInt32KeyNode sortedInt32KeyNode = origin.Root; ReadOnlySpan readOnlySpan = other; for (int i = 0; i < readOnlySpan.Length; i++) { T val = readOnlySpan[i]; int num2 = ((val != null) ? origin.EqualityComparer.GetHashCode(val) : 0); OperationResult result; HashBucket newBucket = sortedInt32KeyNode.GetValueOrDefault(num2).Add(val, origin.EqualityComparer, out result); if (result == OperationResult.SizeChanged) { sortedInt32KeyNode = UpdateRoot(sortedInt32KeyNode, num2, origin.HashBucketEqualityComparer, newBucket); num++; } } return new MutationResult(sortedInt32KeyNode, num); } private static bool Overlaps(IEnumerable other, MutationInput origin) { Requires.NotNull(other, "other"); if (origin.Root.IsEmpty) { return false; } foreach (T item in other.GetEnumerableDisposable()) { if (Contains(item, origin)) { return true; } } return false; } private static bool SetEquals(IEnumerable other, MutationInput origin) { Requires.NotNull(other, "other"); HashSet hashSet = new HashSet(other, origin.EqualityComparer); if (origin.Count != hashSet.Count) { return false; } foreach (T item in hashSet) { if (!Contains(item, origin)) { return false; } } return true; } private static SortedInt32KeyNode UpdateRoot(SortedInt32KeyNode root, int hashCode, IEqualityComparer hashBucketEqualityComparer, HashBucket newBucket) { bool mutated; if (newBucket.IsEmpty) { return root.Remove(hashCode, out mutated); } bool mutated2; return root.SetItem(hashCode, newBucket, hashBucketEqualityComparer, out mutated, out mutated2); } private static MutationResult Intersect(IEnumerable other, MutationInput origin) { Requires.NotNull(other, "other"); SortedInt32KeyNode root = SortedInt32KeyNode.EmptyNode; int num = 0; foreach (T item in other.GetEnumerableDisposable()) { if (Contains(item, origin)) { MutationResult mutationResult = Add(item, new MutationInput(root, origin.EqualityComparer, origin.HashBucketEqualityComparer, num)); root = mutationResult.Root; num += mutationResult.Count; } } return new MutationResult(root, num, CountType.FinalValue); } private static MutationResult Except(IEnumerable other, IEqualityComparer equalityComparer, IEqualityComparer hashBucketEqualityComparer, SortedInt32KeyNode root) { Requires.NotNull(other, "other"); Requires.NotNull(equalityComparer, "equalityComparer"); Requires.NotNull(root, "root"); int num = 0; SortedInt32KeyNode sortedInt32KeyNode = root; foreach (T item in other.GetEnumerableDisposable()) { int num2 = ((item != null) ? equalityComparer.GetHashCode(item) : 0); if (sortedInt32KeyNode.TryGetValue(num2, out var value)) { OperationResult result; HashBucket newBucket = value.Remove(item, equalityComparer, out result); if (result == OperationResult.SizeChanged) { num--; sortedInt32KeyNode = UpdateRoot(sortedInt32KeyNode, num2, hashBucketEqualityComparer, newBucket); } } } return new MutationResult(sortedInt32KeyNode, num); } private static MutationResult SymmetricExcept(IEnumerable other, MutationInput origin) { Requires.NotNull(other, "other"); ImmutableHashSet immutableHashSet = ImmutableHashSet.CreateRange(origin.EqualityComparer, other); int num = 0; SortedInt32KeyNode root = SortedInt32KeyNode.EmptyNode; foreach (T item in new NodeEnumerable(origin.Root)) { if (!immutableHashSet.Contains(item)) { MutationResult mutationResult = Add(item, new MutationInput(root, origin.EqualityComparer, origin.HashBucketEqualityComparer, num)); root = mutationResult.Root; num += mutationResult.Count; } } foreach (T item2 in immutableHashSet) { if (!Contains(item2, origin)) { MutationResult mutationResult2 = Add(item2, new MutationInput(root, origin.EqualityComparer, origin.HashBucketEqualityComparer, num)); root = mutationResult2.Root; num += mutationResult2.Count; } } return new MutationResult(root, num, CountType.FinalValue); } private static bool IsProperSubsetOf(IEnumerable other, MutationInput origin) { Requires.NotNull(other, "other"); if (origin.Root.IsEmpty) { return other.Any(); } HashSet hashSet = new HashSet(other, origin.EqualityComparer); if (origin.Count >= hashSet.Count) { return false; } int num = 0; bool flag = false; foreach (T item in hashSet) { if (Contains(item, origin)) { num++; } else { flag = true; } if (num == origin.Count && flag) { return true; } } return false; } private static bool IsProperSupersetOf(IEnumerable other, MutationInput origin) { Requires.NotNull(other, "other"); if (origin.Root.IsEmpty) { return false; } int num = 0; foreach (T item in other.GetEnumerableDisposable()) { num++; if (!Contains(item, origin)) { return false; } } return origin.Count > num; } private static bool IsSubsetOf(IEnumerable other, MutationInput origin) { Requires.NotNull(other, "other"); if (origin.Root.IsEmpty) { return true; } HashSet hashSet = new HashSet(other, origin.EqualityComparer); int num = 0; foreach (T item in hashSet) { if (Contains(item, origin)) { num++; } } return num == origin.Count; } private static ImmutableHashSet Wrap(SortedInt32KeyNode root, IEqualityComparer equalityComparer, int count) { Requires.NotNull(root, "root"); Requires.NotNull(equalityComparer, "equalityComparer"); Requires.Range(count >= 0, "count"); return new ImmutableHashSet(root, equalityComparer, count); } private static IEqualityComparer GetHashBucketEqualityComparer(IEqualityComparer valueComparer) { if (!ImmutableExtensions.IsValueType()) { return HashBucketByRefEqualityComparer.DefaultInstance; } if (valueComparer == EqualityComparer.Default) { return HashBucketByValueEqualityComparer.DefaultInstance; } return new HashBucketByValueEqualityComparer(valueComparer); } private ImmutableHashSet Wrap(SortedInt32KeyNode root, int adjustedCountIfDifferentRoot) { if (root == _root) { return this; } return new ImmutableHashSet(root, _equalityComparer, adjustedCountIfDifferentRoot); } private ImmutableHashSet Union(IEnumerable items, bool avoidWithComparer) { Requires.NotNull(items, "items"); if (IsEmpty && !avoidWithComparer && items is ImmutableHashSet immutableHashSet) { return immutableHashSet.WithComparer(KeyComparer); } return Union(items, Origin).Finalize(this); } } internal interface IStrongEnumerable where TEnumerator : struct, IStrongEnumerator { TEnumerator GetEnumerator(); } internal interface IStrongEnumerator { T Current { get; } bool MoveNext(); } internal interface IOrderedCollection : IEnumerable, IEnumerable { int Count { get; } T this[int index] { get; } } public static class ImmutableArray { internal static readonly byte[] TwoElementArray = new byte[2]; public static ImmutableArray Create() { return ImmutableArray.Empty; } public static ImmutableArray Create(T item) { return new ImmutableArray(new T[1] { item }); } public static ImmutableArray Create(T item1, T item2) { return new ImmutableArray(new T[2] { item1, item2 }); } public static ImmutableArray Create(T item1, T item2, T item3) { return new ImmutableArray(new T[3] { item1, item2, item3 }); } public static ImmutableArray Create(T item1, T item2, T item3, T item4) { return new ImmutableArray(new T[4] { item1, item2, item3, item4 }); } public static ImmutableArray Create([ParamCollection] scoped ReadOnlySpan items) { if (items.IsEmpty) { return ImmutableArray.Empty; } return new ImmutableArray(items.ToArray()); } public static ImmutableArray Create(Span items) { return Create((ReadOnlySpan)items); } public static ImmutableArray ToImmutableArray(this ReadOnlySpan items) { return Create(items); } public static ImmutableArray ToImmutableArray(this Span items) { return Create((ReadOnlySpan)items); } public static ImmutableArray CreateRange(IEnumerable items) { Requires.NotNull(items, "items"); if (items is IImmutableArray immutableArray) { return new ImmutableArray((T[])(immutableArray.Array ?? throw new InvalidOperationException(System.SR.InvalidOperationOnDefaultArray))); } if (items.TryGetCount(out var count)) { return new ImmutableArray(items.ToArray(count)); } return new ImmutableArray(items.ToArray()); } public static ImmutableArray Create(params T[]? items) { if (items == null || items.Length == 0) { return ImmutableArray.Empty; } T[] array = new T[items.Length]; Array.Copy(items, array, items.Length); return new ImmutableArray(array); } public static ImmutableArray Create(T[] items, int start, int length) { Requires.NotNull(items, "items"); Requires.Range(start >= 0 && start <= items.Length, "start"); Requires.Range(length >= 0 && start + length <= items.Length, "length"); if (length == 0) { return Create(); } T[] array = new T[length]; for (int i = 0; i < array.Length; i++) { array[i] = items[start + i]; } return new ImmutableArray(array); } public static ImmutableArray Create(ImmutableArray items, int start, int length) { Requires.Range(start >= 0 && start <= items.Length, "start"); Requires.Range(length >= 0 && start + length <= items.Length, "length"); if (length == 0) { return Create(); } if (start == 0 && length == items.Length) { return items; } T[] array = new T[length]; Array.Copy(items.array, start, array, 0, length); return new ImmutableArray(array); } public static ImmutableArray CreateRange(ImmutableArray items, Func selector) { Requires.NotNull(selector, "selector"); int length = items.Length; if (length == 0) { return Create(); } TResult[] array = new TResult[length]; for (int i = 0; i < array.Length; i++) { array[i] = selector(items[i]); } return new ImmutableArray(array); } public static ImmutableArray CreateRange(ImmutableArray items, int start, int length, Func selector) { int length2 = items.Length; Requires.Range(start >= 0 && start <= length2, "start"); Requires.Range(length >= 0 && start + length <= length2, "length"); Requires.NotNull(selector, "selector"); if (length == 0) { return Create(); } TResult[] array = new TResult[length]; for (int i = 0; i < array.Length; i++) { array[i] = selector(items[i + start]); } return new ImmutableArray(array); } public static ImmutableArray CreateRange(ImmutableArray items, Func selector, TArg arg) { Requires.NotNull(selector, "selector"); int length = items.Length; if (length == 0) { return Create(); } TResult[] array = new TResult[length]; for (int i = 0; i < array.Length; i++) { array[i] = selector(items[i], arg); } return new ImmutableArray(array); } public static ImmutableArray CreateRange(ImmutableArray items, int start, int length, Func selector, TArg arg) { int length2 = items.Length; Requires.Range(start >= 0 && start <= length2, "start"); Requires.Range(length >= 0 && start + length <= length2, "length"); Requires.NotNull(selector, "selector"); if (length == 0) { return Create(); } TResult[] array = new TResult[length]; for (int i = 0; i < array.Length; i++) { array[i] = selector(items[i + start], arg); } return new ImmutableArray(array); } public static ImmutableArray.Builder CreateBuilder() { return Create().ToBuilder(); } public static ImmutableArray.Builder CreateBuilder(int initialCapacity) { return new ImmutableArray.Builder(initialCapacity); } public static ImmutableArray ToImmutableArray(this IEnumerable items) { if (items is ImmutableArray) { return (ImmutableArray)(object)items; } return CreateRange(items); } public static ImmutableArray ToImmutableArray(this ImmutableArray.Builder builder) { Requires.NotNull(builder, "builder"); return builder.ToImmutable(); } public static int BinarySearch(this ImmutableArray array, T value) { return Array.BinarySearch(array.array, value); } public static int BinarySearch(this ImmutableArray array, T value, IComparer? comparer) { return Array.BinarySearch(array.array, value, comparer); } public static int BinarySearch(this ImmutableArray array, int index, int length, T value) { return Array.BinarySearch(array.array, index, length, value); } public static int BinarySearch(this ImmutableArray array, int index, int length, T value, IComparer? comparer) { return Array.BinarySearch(array.array, index, length, value, comparer); } } [CollectionBuilder(typeof(ImmutableArray), "Create")] [DebuggerDisplay("{DebuggerDisplay,nq}")] [System.Runtime.Versioning.NonVersionable] public readonly struct ImmutableArray : IReadOnlyList, IEnumerable, IEnumerable, IReadOnlyCollection, IList, ICollection, IEquatable>, IList, ICollection, IImmutableArray, IStructuralComparable, IStructuralEquatable, IImmutableList { [DebuggerDisplay("Count = {Count}")] [DebuggerTypeProxy(typeof(ImmutableArrayBuilderDebuggerProxy<>))] public sealed class Builder : IList, ICollection, IEnumerable, IEnumerable, IReadOnlyList, IReadOnlyCollection { private T[] _elements; private int _count; public int Capacity { get { return _elements.Length; } set { if (value < _count) { throw new ArgumentException(System.SR.CapacityMustBeGreaterThanOrEqualToCount, "value"); } if (value == _elements.Length) { return; } if (value > 0) { T[] array = new T[value]; if (_count > 0) { Array.Copy(_elements, array, _count); } _elements = array; } else { _elements = ImmutableArray.Empty.array; } } } public int Count { get { return _count; } set { Requires.Range(value >= 0, "value"); if (value < _count) { if (_count - value > 64) { Array.Clear(_elements, value, _count - value); } else { for (int i = value; i < Count; i++) { _elements[i] = default(T); } } } else if (value > _count) { EnsureCapacity(value); } _count = value; } } public T this[int index] { get { if (index >= Count) { ThrowIndexOutOfRangeException(); } return _elements[index]; } set { if (index >= Count) { ThrowIndexOutOfRangeException(); } _elements[index] = value; } } bool ICollection.IsReadOnly => false; internal Builder(int capacity) { Requires.Range(capacity >= 0, "capacity"); _elements = new T[capacity]; _count = 0; } internal Builder() : this(8) { } private static void ThrowIndexOutOfRangeException() { throw new IndexOutOfRangeException(); } public ref readonly T ItemRef(int index) { if (index >= Count) { ThrowIndexOutOfRangeException(); } return ref _elements[index]; } public ImmutableArray ToImmutable() { return new ImmutableArray(ToArray()); } public ImmutableArray MoveToImmutable() { if (Capacity != Count) { throw new InvalidOperationException(System.SR.CapacityMustEqualCountOnMove); } T[] elements = _elements; _elements = ImmutableArray.Empty.array; _count = 0; return new ImmutableArray(elements); } public ImmutableArray DrainToImmutable() { T[] array = _elements; if (array.Length != _count) { array = ToArray(); } _elements = ImmutableArray.Empty.array; _count = 0; return new ImmutableArray(array); } public void Clear() { Count = 0; } public void Insert(int index, T item) { Requires.Range(index >= 0 && index <= Count, "index"); EnsureCapacity(Count + 1); if (index < Count) { Array.Copy(_elements, index, _elements, index + 1, Count - index); } _count++; _elements[index] = item; } public void InsertRange(int index, IEnumerable items) { Requires.Range(index >= 0 && index <= Count, "index"); Requires.NotNull(items, "items"); int count = ImmutableExtensions.GetCount(ref items); EnsureCapacity(Count + count); if (index != Count) { Array.Copy(_elements, index, _elements, index + count, _count - index); } if (!items.TryCopyTo(_elements, index)) { foreach (T item in items) { _elements[index++] = item; } } _count += count; } public void InsertRange(int index, ImmutableArray items) { Requires.Range(index >= 0 && index <= Count, "index"); if (!items.IsEmpty) { EnsureCapacity(Count + items.Length); if (index != Count) { Array.Copy(_elements, index, _elements, index + items.Length, _count - index); } Array.Copy(items.array, 0, _elements, index, items.Length); _count += items.Length; } } public void Add(T item) { int num = _count + 1; EnsureCapacity(num); _elements[_count] = item; _count = num; } public void AddRange(IEnumerable items) { Requires.NotNull(items, "items"); if (items.TryGetCount(out var count)) { EnsureCapacity(Count + count); if (items.TryCopyTo(_elements, _count)) { _count += count; return; } } foreach (T item in items) { Add(item); } } public void AddRange(params T[] items) { Requires.NotNull(items, "items"); int count = Count; Count += items.Length; Array.Copy(items, 0, _elements, count, items.Length); } public void AddRange(TDerived[] items) where TDerived : T { Requires.NotNull(items, "items"); int count = Count; Count += items.Length; Array.Copy(items, 0, _elements, count, items.Length); } public void AddRange(T[] items, int length) { Requires.NotNull(items, "items"); Requires.Range(length >= 0 && length <= items.Length, "length"); int count = Count; Count += length; Array.Copy(items, 0, _elements, count, length); } public void AddRange(ImmutableArray items) { AddRange(items, items.Length); } public void AddRange(ImmutableArray items, int length) { Requires.Range(length >= 0, "length"); if (items.array != null) { AddRange(items.array, length); } } public void AddRange([ParamCollection] scoped ReadOnlySpan items) { int count = Count; Count += items.Length; items.CopyTo(new Span(_elements, count, items.Length)); } public void AddRange([ParamCollection] scoped ReadOnlySpan items) where TDerived : T { int count = Count; Count += items.Length; Span span = new Span(_elements, count, items.Length); for (int i = 0; i < items.Length; i++) { span[i] = (T)(object)items[i]; } } public void AddRange(ImmutableArray items) where TDerived : T { if (items.array != null) { this.AddRange(items.array); } } public void AddRange(Builder items) { Requires.NotNull(items, "items"); AddRange(items._elements, items.Count); } public void AddRange(ImmutableArray.Builder items) where TDerived : T { Requires.NotNull(items, "items"); AddRange(items._elements, items.Count); } public bool Remove(T element) { int num = IndexOf(element); if (num >= 0) { RemoveAt(num); return true; } return false; } public bool Remove(T element, IEqualityComparer? equalityComparer) { int num = IndexOf(element, 0, _count, equalityComparer); if (num >= 0) { RemoveAt(num); return true; } return false; } public void RemoveAll(Predicate match) { List list = null; for (int i = 0; i < _count; i++) { if (match(_elements[i])) { if (list == null) { list = new List(); } list.Add(i); } } if (list != null) { RemoveAtRange(list); } } public void RemoveAt(int index) { Requires.Range(index >= 0 && index < Count, "index"); if (index < Count - 1) { Array.Copy(_elements, index + 1, _elements, index, Count - index - 1); } Count--; } public void RemoveRange(int index, int length) { Requires.Range(index >= 0 && index <= _count, "index"); Requires.Range(length >= 0 && index <= _count - length, "length"); if (length != 0) { if (index + length < _count) { Array.Copy(_elements, index + length, _elements, index, Count - index - length); } _count -= length; } } public void RemoveRange(IEnumerable items) { RemoveRange(items, EqualityComparer.Default); } public void RemoveRange(IEnumerable items, IEqualityComparer? equalityComparer) { Requires.NotNull(items, "items"); SortedSet sortedSet = new SortedSet(); foreach (T item in items) { int num = IndexOf(item, 0, _count, equalityComparer); while (num >= 0 && !sortedSet.Add(num) && num + 1 < _count) { num = IndexOf(item, num + 1, equalityComparer); } } RemoveAtRange(sortedSet); } public void Replace(T oldValue, T newValue) { Replace(oldValue, newValue, EqualityComparer.Default); } public void Replace(T oldValue, T newValue, IEqualityComparer? equalityComparer) { int num = IndexOf(oldValue, 0, _count, equalityComparer); if (num >= 0) { _elements[num] = newValue; } } public bool Contains(T item) { return IndexOf(item) >= 0; } public T[] ToArray() { if (Count == 0) { return ImmutableArray.Empty.array; } T[] array = new T[Count]; Array.Copy(_elements, array, Count); return array; } public void CopyTo(T[] array, int index) { Requires.NotNull(array, "array"); Requires.Range(index >= 0 && index + Count <= array.Length, "index"); Array.Copy(_elements, 0, array, index, Count); } public void CopyTo(T[] destination) { Requires.NotNull(destination, "destination"); Array.Copy(_elements, 0, destination, 0, Count); } public void CopyTo(int sourceIndex, T[] destination, int destinationIndex, int length) { Requires.NotNull(destination, "destination"); Requires.Range(length >= 0, "length"); Requires.Range(sourceIndex >= 0 && sourceIndex + length <= Count, "sourceIndex"); Requires.Range(destinationIndex >= 0 && destinationIndex + length <= destination.Length, "destinationIndex"); Array.Copy(_elements, sourceIndex, destination, destinationIndex, length); } private void EnsureCapacity(int capacity) { if (_elements.Length < capacity) { int newSize = Math.Max(_elements.Length * 2, capacity); Array.Resize(ref _elements, newSize); } } public int IndexOf(T item) { return IndexOf(item, 0, _count, EqualityComparer.Default); } public int IndexOf(T item, int startIndex) { return IndexOf(item, startIndex, Count - startIndex, EqualityComparer.Default); } public int IndexOf(T item, int startIndex, int count) { return IndexOf(item, startIndex, count, EqualityComparer.Default); } public int IndexOf(T item, int startIndex, int count, IEqualityComparer? equalityComparer) { if (count == 0 && startIndex == 0) { return -1; } Requires.Range(startIndex >= 0 && startIndex < Count, "startIndex"); Requires.Range(count >= 0 && startIndex + count <= Count, "count"); if (equalityComparer == null) { equalityComparer = EqualityComparer.Default; } if (equalityComparer == EqualityComparer.Default) { return Array.IndexOf(_elements, item, startIndex, count); } for (int i = startIndex; i < startIndex + count; i++) { if (equalityComparer.Equals(_elements[i], item)) { return i; } } return -1; } public int IndexOf(T item, int startIndex, IEqualityComparer? equalityComparer) { return IndexOf(item, startIndex, Count - startIndex, equalityComparer); } public int LastIndexOf(T item) { if (Count == 0) { return -1; } return LastIndexOf(item, Count - 1, Count, EqualityComparer.Default); } public int LastIndexOf(T item, int startIndex) { if (Count == 0 && startIndex == 0) { return -1; } Requires.Range(startIndex >= 0 && startIndex < Count, "startIndex"); return LastIndexOf(item, startIndex, startIndex + 1, EqualityComparer.Default); } public int LastIndexOf(T item, int startIndex, int count) { return LastIndexOf(item, startIndex, count, EqualityComparer.Default); } public int LastIndexOf(T item, int startIndex, int count, IEqualityComparer? equalityComparer) { if (count == 0 && startIndex == 0) { return -1; } Requires.Range(startIndex >= 0 && startIndex < Count, "startIndex"); Requires.Range(count >= 0 && startIndex - count + 1 >= 0, "count"); if (equalityComparer == null) { equalityComparer = EqualityComparer.Default; } if (equalityComparer == EqualityComparer.Default) { return Array.LastIndexOf(_elements, item, startIndex, count); } for (int num = startIndex; num >= startIndex - count + 1; num--) { if (equalityComparer.Equals(item, _elements[num])) { return num; } } return -1; } public void Reverse() { int num = 0; int num2 = _count - 1; T[] elements = _elements; while (num < num2) { T val = elements[num]; elements[num] = elements[num2]; elements[num2] = val; num++; num2--; } } public void Sort() { if (Count > 1) { Array.Sort(_elements, 0, Count, Comparer.Default); } } public void Sort(Comparison comparison) { Requires.NotNull(comparison, "comparison"); if (Count > 1) { Array.Sort(_elements, 0, _count, Comparer.Create(comparison)); } } public void Sort(IComparer? comparer) { if (Count > 1) { Array.Sort(_elements, 0, _count, comparer); } } public void Sort(int index, int count, IComparer? comparer) { Requires.Range(index >= 0, "index"); Requires.Range(count >= 0 && index + count <= Count, "count"); if (count > 1) { Array.Sort(_elements, index, count, comparer); } } public void CopyTo(Span destination) { Requires.Range(Count <= destination.Length, "destination"); new ReadOnlySpan(_elements, 0, Count).CopyTo(destination); } public IEnumerator GetEnumerator() { for (int i = 0; i < Count; i++) { yield return this[i]; } } IEnumerator IEnumerable.GetEnumerator() { return GetEnumerator(); } IEnumerator IEnumerable.GetEnumerator() { return GetEnumerator(); } private void AddRange(TDerived[] items, int length) where TDerived : T { EnsureCapacity(Count + length); int count = Count; Count += length; T[] elements = _elements; for (int i = 0; i < length; i++) { elements[count + i] = (T)(object)items[i]; } } private void RemoveAtRange(ICollection indicesToRemove) { Requires.NotNull(indicesToRemove, "indicesToRemove"); if (indicesToRemove.Count == 0) { return; } int num = 0; int num2 = 0; int num3 = -1; foreach (int item in indicesToRemove) { int num4 = ((num3 == -1) ? item : (item - num3 - 1)); Array.Copy(_elements, num + num2, _elements, num, num4); num2++; num += num4; num3 = item; } Array.Copy(_elements, num + num2, _elements, num, _elements.Length - (num + num2)); _count -= indicesToRemove.Count; } } public struct Enumerator { private readonly T[] _array; private int _index; public T Current => _array[_index]; internal Enumerator(T[] array) { _array = array; _index = -1; } public bool MoveNext() { return ++_index < _array.Length; } } private sealed class EnumeratorObject : IEnumerator, IEnumerator, IDisposable { private static readonly IEnumerator s_EmptyEnumerator = new EnumeratorObject(ImmutableArray.Empty.array); private readonly T[] _array; private int _index; public T Current { get { if ((uint)_index < (uint)_array.Length) { return _array[_index]; } throw new InvalidOperationException(); } } object IEnumerator.Current => Current; private EnumeratorObject(T[] array) { _index = -1; _array = array; } public bool MoveNext() { int num = _index + 1; int num2 = _array.Length; if ((uint)num <= (uint)num2) { _index = num; return (uint)num < (uint)num2; } return false; } void IEnumerator.Reset() { _index = -1; } public void Dispose() { } internal static IEnumerator Create(T[] array) { if (array.Length != 0) { return new EnumeratorObject(array); } return s_EmptyEnumerator; } } public static readonly ImmutableArray Empty = new ImmutableArray(new T[0]); [DebuggerBrowsable(DebuggerBrowsableState.RootHidden)] internal readonly T[]? array; T IList.this[int index] { get { ImmutableArray immutableArray = this; immutableArray.ThrowInvalidOperationIfNotInitialized(); return immutableArray[index]; } set { throw new NotSupportedException(); } } [DebuggerBrowsable(DebuggerBrowsableState.Never)] bool ICollection.IsReadOnly => true; [DebuggerBrowsable(DebuggerBrowsableState.Never)] int ICollection.Count { get { ImmutableArray immutableArray = this; immutableArray.ThrowInvalidOperationIfNotInitialized(); return immutableArray.Length; } } [DebuggerBrowsable(DebuggerBrowsableState.Never)] int IReadOnlyCollection.Count { get { ImmutableArray immutableArray = this; immutableArray.ThrowInvalidOperationIfNotInitialized(); return immutableArray.Length; } } T IReadOnlyList.this[int index] { get { ImmutableArray immutableArray = this; immutableArray.ThrowInvalidOperationIfNotInitialized(); return immutableArray[index]; } } [DebuggerBrowsable(DebuggerBrowsableState.Never)] bool IList.IsFixedSize => true; [DebuggerBrowsable(DebuggerBrowsableState.Never)] bool IList.IsReadOnly => true; [DebuggerBrowsable(DebuggerBrowsableState.Never)] int ICollection.Count { get { ImmutableArray immutableArray = this; immutableArray.ThrowInvalidOperationIfNotInitialized(); return immutableArray.Length; } } [DebuggerBrowsable(DebuggerBrowsableState.Never)] bool ICollection.IsSynchronized => true; [DebuggerBrowsable(DebuggerBrowsableState.Never)] object ICollection.SyncRoot { get { throw new NotSupportedException(); } } object? IList.this[int index] { get { ImmutableArray immutableArray = this; immutableArray.ThrowInvalidOperationIfNotInitialized(); return immutableArray[index]; } set { throw new NotSupportedException(); } } public T this[int index] { [System.Runtime.Versioning.NonVersionable] get { return array[index]; } } [DebuggerBrowsable(DebuggerBrowsableState.Never)] public bool IsEmpty { [System.Runtime.Versioning.NonVersionable] get { return array.Length == 0; } } [DebuggerBrowsable(DebuggerBrowsableState.Never)] public int Length { [System.Runtime.Versioning.NonVersionable] get { return array.Length; } } [DebuggerBrowsable(DebuggerBrowsableState.Never)] public bool IsDefault => array == null; [DebuggerBrowsable(DebuggerBrowsableState.Never)] public bool IsDefaultOrEmpty { get { ImmutableArray immutableArray = this; if (immutableArray.array != null) { return immutableArray.array.Length == 0; } return true; } } [DebuggerBrowsable(DebuggerBrowsableState.Never)] Array? IImmutableArray.Array => array; [DebuggerBrowsable(DebuggerBrowsableState.Never)] private string DebuggerDisplay { get { ImmutableArray immutableArray = this; if (!immutableArray.IsDefault) { return $"Length = {immutableArray.Length}"; } return "Uninitialized"; } } public ReadOnlySpan AsSpan() { return new ReadOnlySpan(array); } public ReadOnlyMemory AsMemory() { return new ReadOnlyMemory(array); } public int IndexOf(T item) { ImmutableArray immutableArray = this; return immutableArray.IndexOf(item, 0, immutableArray.Length, EqualityComparer.Default); } public int IndexOf(T item, int startIndex, IEqualityComparer? equalityComparer) { ImmutableArray immutableArray = this; return immutableArray.IndexOf(item, startIndex, immutableArray.Length - startIndex, equalityComparer); } public int IndexOf(T item, int startIndex) { ImmutableArray immutableArray = this; return immutableArray.IndexOf(item, startIndex, immutableArray.Length - startIndex, EqualityComparer.Default); } public int IndexOf(T item, int startIndex, int count) { return IndexOf(item, startIndex, count, EqualityComparer.Default); } public int IndexOf(T item, int startIndex, int count, IEqualityComparer? equalityComparer) { ImmutableArray immutableArray = this; immutableArray.ThrowNullRefIfNotInitialized(); if (count == 0 && startIndex == 0) { return -1; } Requires.Range(startIndex >= 0 && startIndex < immutableArray.Length, "startIndex"); Requires.Range(count >= 0 && startIndex + count <= immutableArray.Length, "count"); if (equalityComparer == null) { equalityComparer = EqualityComparer.Default; } if (equalityComparer == EqualityComparer.Default) { return Array.IndexOf(immutableArray.array, item, startIndex, count); } for (int i = startIndex; i < startIndex + count; i++) { if (equalityComparer.Equals(immutableArray.array[i], item)) { return i; } } return -1; } public int LastIndexOf(T item) { ImmutableArray immutableArray = this; if (immutableArray.IsEmpty) { return -1; } return immutableArray.LastIndexOf(item, immutableArray.Length - 1, immutableArray.Length, EqualityComparer.Default); } public int LastIndexOf(T item, int startIndex) { ImmutableArray immutableArray = this; if (immutableArray.IsEmpty && startIndex == 0) { return -1; } return immutableArray.LastIndexOf(item, startIndex, startIndex + 1, EqualityComparer.Default); } public int LastIndexOf(T item, int startIndex, int count) { return LastIndexOf(item, startIndex, count, EqualityComparer.Default); } public int LastIndexOf(T item, int startIndex, int count, IEqualityComparer? equalityComparer) { ImmutableArray immutableArray = this; immutableArray.ThrowNullRefIfNotInitialized(); if (startIndex == 0 && count == 0) { return -1; } Requires.Range(startIndex >= 0 && startIndex < immutableArray.Length, "startIndex"); Requires.Range(count >= 0 && startIndex - count + 1 >= 0, "count"); if (equalityComparer == null) { equalityComparer = EqualityComparer.Default; } if (equalityComparer == EqualityComparer.Default) { return Array.LastIndexOf(immutableArray.array, item, startIndex, count); } for (int num = startIndex; num >= startIndex - count + 1; num--) { if (equalityComparer.Equals(item, immutableArray.array[num])) { return num; } } return -1; } public bool Contains(T item) { return IndexOf(item) >= 0; } public bool Contains(T item, IEqualityComparer? equalityComparer) { return this.IndexOf(item, equalityComparer) >= 0; } public ImmutableArray Insert(int index, T item) { ImmutableArray immutableArray = this; immutableArray.ThrowNullRefIfNotInitialized(); Requires.Range(index >= 0 && index <= immutableArray.Length, "index"); if (immutableArray.IsEmpty) { return ImmutableArray.Create(item); } T[] array = new T[immutableArray.Length + 1]; array[index] = item; if (index != 0) { Array.Copy(immutableArray.array, array, index); } if (index != immutableArray.Length) { Array.Copy(immutableArray.array, index, array, index + 1, immutableArray.Length - index); } return new ImmutableArray(array); } public ImmutableArray InsertRange(int index, IEnumerable items) { ImmutableArray result = this; result.ThrowNullRefIfNotInitialized(); Requires.Range(index >= 0 && index <= result.Length, "index"); Requires.NotNull(items, "items"); if (result.IsEmpty) { return ImmutableArray.CreateRange(items); } int count = ImmutableExtensions.GetCount(ref items); if (count == 0) { return result; } T[] array = new T[result.Length + count]; if (index != 0) { Array.Copy(result.array, array, index); } if (index != result.Length) { Array.Copy(result.array, index, array, index + count, result.Length - index); } if (!items.TryCopyTo(array, index)) { int num = index; foreach (T item in items) { array[num++] = item; } } return new ImmutableArray(array); } public ImmutableArray InsertRange(int index, ImmutableArray items) { ImmutableArray result = this; result.ThrowNullRefIfNotInitialized(); items.ThrowNullRefIfNotInitialized(); Requires.Range(index >= 0 && index <= result.Length, "index"); if (result.IsEmpty) { return items; } if (items.IsEmpty) { return result; } return result.InsertSpanRangeInternal(index, items.AsSpan()); } public ImmutableArray Add(T item) { ImmutableArray immutableArray = this; if (immutableArray.IsEmpty) { return ImmutableArray.Create(item); } return immutableArray.Insert(immutableArray.Length, item); } public ImmutableArray AddRange(IEnumerable items) { ImmutableArray immutableArray = this; return immutableArray.InsertRange(immutableArray.Length, items); } public ImmutableArray AddRange(T[] items, int length) { ImmutableArray result = this; result.ThrowNullRefIfNotInitialized(); Requires.NotNull(items, "items"); Requires.Range(length >= 0 && length <= items.Length, "length"); if (items.Length == 0 || length == 0) { return result; } if (result.IsEmpty) { return ImmutableArray.Create(items, 0, length); } T[] array = new T[result.Length + length]; Array.Copy(result.array, array, result.Length); Array.Copy(items, 0, array, result.Length, length); return new ImmutableArray(array); } public ImmutableArray AddRange(TDerived[] items) where TDerived : T { ImmutableArray result = this; result.ThrowNullRefIfNotInitialized(); Requires.NotNull(items, "items"); if (items.Length == 0) { return result; } T[] array = new T[result.Length + items.Length]; Array.Copy(result.array, array, result.Length); Array.Copy(items, 0, array, result.Length, items.Length); return new ImmutableArray(array); } public ImmutableArray AddRange(ImmutableArray items, int length) { ImmutableArray result = this; Requires.Range(length >= 0, "length"); if (items.array != null) { return result.AddRange(items.array, length); } return result; } public ImmutableArray AddRange(ImmutableArray items) where TDerived : T { ImmutableArray result = this; if (items.array != null) { return result.AddRange(items.array); } return result; } public ImmutableArray AddRange(ImmutableArray items) { ImmutableArray immutableArray = this; return immutableArray.InsertRange(immutableArray.Length, items); } public ImmutableArray SetItem(int index, T item) { ImmutableArray immutableArray = this; immutableArray.ThrowNullRefIfNotInitialized(); Requires.Range(index >= 0 && index < immutableArray.Length, "index"); T[] array = new T[immutableArray.Length]; Array.Copy(immutableArray.array, array, immutableArray.Length); array[index] = item; return new ImmutableArray(array); } public ImmutableArray Replace(T oldValue, T newValue) { return Replace(oldValue, newValue, EqualityComparer.Default); } public ImmutableArray Replace(T oldValue, T newValue, IEqualityComparer? equalityComparer) { ImmutableArray immutableArray = this; int num = immutableArray.IndexOf(oldValue, 0, immutableArray.Length, equalityComparer); if (num < 0) { throw new ArgumentException(System.SR.CannotFindOldValue, "oldValue"); } return immutableArray.SetItem(num, newValue); } public ImmutableArray Remove(T item) { return Remove(item, EqualityComparer.Default); } public ImmutableArray Remove(T item, IEqualityComparer? equalityComparer) { ImmutableArray result = this; result.ThrowNullRefIfNotInitialized(); int num = result.IndexOf(item, 0, result.Length, equalityComparer); if (num >= 0) { return result.RemoveAt(num); } return result; } public ImmutableArray RemoveAt(int index) { return RemoveRange(index, 1); } public ImmutableArray RemoveRange(int index, int length) { ImmutableArray result = this; result.ThrowNullRefIfNotInitialized(); Requires.Range(index >= 0 && index <= result.Length, "index"); Requires.Range(length >= 0 && index <= result.Length - length, "length"); if (length == 0) { return result; } T[] array = new T[result.Length - length]; Array.Copy(result.array, array, index); Array.Copy(result.array, index + length, array, index, result.Length - index - length); return new ImmutableArray(array); } public ImmutableArray RemoveRange(IEnumerable items) { return RemoveRange(items, EqualityComparer.Default); } public ImmutableArray RemoveRange(IEnumerable items, IEqualityComparer? equalityComparer) { ImmutableArray immutableArray = this; immutableArray.ThrowNullRefIfNotInitialized(); Requires.NotNull(items, "items"); SortedSet sortedSet = new SortedSet(); foreach (T item in items) { int num = -1; do { num = immutableArray.IndexOf(item, num + 1, equalityComparer); } while (num >= 0 && !sortedSet.Add(num) && num < immutableArray.Length - 1); } return immutableArray.RemoveAtRange(sortedSet); } public ImmutableArray RemoveRange(ImmutableArray items) { return RemoveRange(items, EqualityComparer.Default); } public ImmutableArray RemoveRange(ImmutableArray items, IEqualityComparer? equalityComparer) { Requires.NotNull(items.array, "items"); return RemoveRange(items.AsSpan(), equalityComparer); } public ImmutableArray RemoveAll(Predicate match) { ImmutableArray result = this; result.ThrowNullRefIfNotInitialized(); Requires.NotNull(match, "match"); if (result.IsEmpty) { return result; } List list = null; for (int i = 0; i < result.array.Length; i++) { if (match(result.array[i])) { if (list == null) { list = new List(); } list.Add(i); } } if (list == null) { return result; } return result.RemoveAtRange(list); } public ImmutableArray Clear() { return Empty; } public ImmutableArray Sort() { ImmutableArray immutableArray = this; return immutableArray.Sort(0, immutableArray.Length, Comparer.Default); } public ImmutableArray Sort(Comparison comparison) { Requires.NotNull(comparison, "comparison"); ImmutableArray immutableArray = this; return immutableArray.Sort(Comparer.Create(comparison)); } public ImmutableArray Sort(IComparer? comparer) { ImmutableArray immutableArray = this; return immutableArray.Sort(0, immutableArray.Length, comparer); } public ImmutableArray Sort(int index, int count, IComparer? comparer) { ImmutableArray result = this; result.ThrowNullRefIfNotInitialized(); Requires.Range(index >= 0, "index"); Requires.Range(count >= 0 && index + count <= result.Length, "count"); if (count > 1) { if (comparer == null) { comparer = Comparer.Default; } bool flag = false; for (int i = index + 1; i < index + count; i++) { if (comparer.Compare(result.array[i - 1], result.array[i]) > 0) { flag = true; break; } } if (flag) { T[] array = new T[result.Length]; Array.Copy(result.array, array, result.Length); Array.Sort(array, index, count, comparer); return new ImmutableArray(array); } } return result; } public IEnumerable OfType() { ImmutableArray immutableArray = this; if (immutableArray.array == null || immutableArray.array.Length == 0) { return Enumerable.Empty(); } return immutableArray.array.OfType(); } public ImmutableArray AddRange([ParamCollection] scoped ReadOnlySpan items) { ImmutableArray immutableArray = this; return immutableArray.InsertRange(immutableArray.Length, items); } public ImmutableArray AddRange(params T[] items) { ImmutableArray immutableArray = this; return immutableArray.InsertRange(immutableArray.Length, items); } public ReadOnlySpan AsSpan(int start, int length) { return new ReadOnlySpan(array, start, length); } public void CopyTo(Span destination) { ImmutableArray immutableArray = this; immutableArray.ThrowNullRefIfNotInitialized(); Requires.Range(immutableArray.Length <= destination.Length, "destination"); immutableArray.AsSpan().CopyTo(destination); } public ImmutableArray InsertRange(int index, T[] items) { ImmutableArray result = this; result.ThrowNullRefIfNotInitialized(); Requires.Range(index >= 0 && index <= result.Length, "index"); Requires.NotNull(items, "items"); if (items.Length == 0) { return result; } if (result.IsEmpty) { return new ImmutableArray(items); } return result.InsertSpanRangeInternal(index, items); } public ImmutableArray InsertRange(int index, [ParamCollection] scoped ReadOnlySpan items) { ImmutableArray result = this; result.ThrowNullRefIfNotInitialized(); Requires.Range(index >= 0 && index <= result.Length, "index"); if (items.IsEmpty) { return result; } if (result.IsEmpty) { return items.ToImmutableArray(); } return result.InsertSpanRangeInternal(index, items); } public ImmutableArray RemoveRange(ReadOnlySpan items, IEqualityComparer? equalityComparer = null) { ImmutableArray result = this; result.ThrowNullRefIfNotInitialized(); if (items.IsEmpty || result.IsEmpty) { return result; } if (items.Length == 1) { return result.Remove(items[0], equalityComparer); } SortedSet sortedSet = new SortedSet(); ReadOnlySpan readOnlySpan = items; for (int i = 0; i < readOnlySpan.Length; i++) { T item = readOnlySpan[i]; int num = -1; do { num = result.IndexOf(item, num + 1, equalityComparer); } while (num >= 0 && !sortedSet.Add(num) && num < result.Length - 1); } return result.RemoveAtRange(sortedSet); } public ImmutableArray RemoveRange(T[] items, IEqualityComparer? equalityComparer = null) { ImmutableArray immutableArray = this; immutableArray.ThrowNullRefIfNotInitialized(); Requires.NotNull(items, "items"); return immutableArray.RemoveRange(new ReadOnlySpan(items), equalityComparer); } public ImmutableArray Slice(int start, int length) { ImmutableArray items = this; items.ThrowNullRefIfNotInitialized(); return ImmutableArray.Create(items, start, length); } void IList.Insert(int index, T item) { throw new NotSupportedException(); } void IList.RemoveAt(int index) { throw new NotSupportedException(); } void ICollection.Add(T item) { throw new NotSupportedException(); } void ICollection.Clear() { throw new NotSupportedException(); } bool ICollection.Remove(T item) { throw new NotSupportedException(); } IImmutableList IImmutableList.Clear() { ImmutableArray immutableArray = this; immutableArray.ThrowInvalidOperationIfNotInitialized(); return immutableArray.Clear(); } IImmutableList IImmutableList.Add(T value) { ImmutableArray immutableArray = this; immutableArray.ThrowInvalidOperationIfNotInitialized(); return immutableArray.Add(value); } IImmutableList IImmutableList.AddRange(IEnumerable items) { ImmutableArray immutableArray = this; immutableArray.ThrowInvalidOperationIfNotInitialized(); return immutableArray.AddRange(items); } IImmutableList IImmutableList.Insert(int index, T element) { ImmutableArray immutableArray = this; immutableArray.ThrowInvalidOperationIfNotInitialized(); return immutableArray.Insert(index, element); } IImmutableList IImmutableList.InsertRange(int index, IEnumerable items) { ImmutableArray immutableArray = this; immutableArray.ThrowInvalidOperationIfNotInitialized(); return immutableArray.InsertRange(index, items); } IImmutableList IImmutableList.Remove(T value, IEqualityComparer equalityComparer) { ImmutableArray immutableArray = this; immutableArray.ThrowInvalidOperationIfNotInitialized(); return immutableArray.Remove(value, equalityComparer); } IImmutableList IImmutableList.RemoveAll(Predicate match) { ImmutableArray immutableArray = this; immutableArray.ThrowInvalidOperationIfNotInitialized(); return immutableArray.RemoveAll(match); } IImmutableList IImmutableList.RemoveRange(IEnumerable items, IEqualityComparer equalityComparer) { ImmutableArray immutableArray = this; immutableArray.ThrowInvalidOperationIfNotInitialized(); return immutableArray.RemoveRange(items, equalityComparer); } IImmutableList IImmutableList.RemoveRange(int index, int count) { ImmutableArray immutableArray = this; immutableArray.ThrowInvalidOperationIfNotInitialized(); return immutableArray.RemoveRange(index, count); } IImmutableList IImmutableList.RemoveAt(int index) { ImmutableArray immutableArray = this; immutableArray.ThrowInvalidOperationIfNotInitialized(); return immutableArray.RemoveAt(index); } IImmutableList IImmutableList.SetItem(int index, T value) { ImmutableArray immutableArray = this; immutableArray.ThrowInvalidOperationIfNotInitialized(); return immutableArray.SetItem(index, value); } IImmutableList IImmutableList.Replace(T oldValue, T newValue, IEqualityComparer equalityComparer) { ImmutableArray immutableArray = this; immutableArray.ThrowInvalidOperationIfNotInitialized(); return immutableArray.Replace(oldValue, newValue, equalityComparer); } int IList.Add(object value) { throw new NotSupportedException(); } void IList.Clear() { throw new NotSupportedException(); } private static bool IsCompatibleObject(object value) { if (!(value is T)) { if (default(T) == null) { return value == null; } return false; } return true; } bool IList.Contains(object value) { if (IsCompatibleObject(value)) { ImmutableArray immutableArray = this; immutableArray.ThrowInvalidOperationIfNotInitialized(); return immutableArray.Contains((T)value); } return false; } int IList.IndexOf(object value) { if (IsCompatibleObject(value)) { ImmutableArray immutableArray = this; immutableArray.ThrowInvalidOperationIfNotInitialized(); return immutableArray.IndexOf((T)value); } return -1; } void IList.Insert(int index, object value) { throw new NotSupportedException(); } void IList.Remove(object value) { throw new NotSupportedException(); } void IList.RemoveAt(int index) { throw new NotSupportedException(); } void ICollection.CopyTo(Array array, int index) { ImmutableArray immutableArray = this; immutableArray.ThrowInvalidOperationIfNotInitialized(); Array.Copy(immutableArray.array, 0, array, index, immutableArray.Length); } bool IStructuralEquatable.Equals(object other, IEqualityComparer comparer) { ImmutableArray immutableArray = this; Array array = other as Array; if (array == null && other is IImmutableArray immutableArray2) { array = immutableArray2.Array; if (immutableArray.array == null && array == null) { return true; } if (immutableArray.array == null) { return false; } } return ((IStructuralEquatable)immutableArray.array).Equals((object?)array, comparer); } int IStructuralEquatable.GetHashCode(IEqualityComparer comparer) { ImmutableArray immutableArray = this; return ((IStructuralEquatable)immutableArray.array)?.GetHashCode(comparer) ?? immutableArray.GetHashCode(); } int IStructuralComparable.CompareTo(object other, IComparer comparer) { ImmutableArray immutableArray = this; Array array = other as Array; if (array == null && other is IImmutableArray immutableArray2) { array = immutableArray2.Array; if (immutableArray.array == null && array == null) { return 0; } if ((immutableArray.array == null) ^ (array == null)) { throw new ArgumentException(System.SR.ArrayInitializedStateNotEqual, "other"); } } if (array != null) { return ((IStructuralComparable)(immutableArray.array ?? throw new ArgumentException(System.SR.ArrayInitializedStateNotEqual, "other"))).CompareTo((object?)array, comparer); } throw new ArgumentException(System.SR.ArrayLengthsNotEqual, "other"); } private ImmutableArray RemoveAtRange(ICollection indicesToRemove) { ImmutableArray result = this; result.ThrowNullRefIfNotInitialized(); Requires.NotNull(indicesToRemove, "indicesToRemove"); if (indicesToRemove.Count == 0) { return result; } T[] array = new T[result.Length - indicesToRemove.Count]; int num = 0; int num2 = 0; int num3 = -1; foreach (int item in indicesToRemove) { int num4 = ((num3 == -1) ? item : (item - num3 - 1)); Array.Copy(result.array, num + num2, array, num, num4); num2++; num += num4; num3 = item; } Array.Copy(result.array, num + num2, array, num, result.Length - (num + num2)); return new ImmutableArray(array); } private ImmutableArray InsertSpanRangeInternal(int index, ReadOnlySpan items) { T[] array = new T[Length + items.Length]; if (index != 0) { Array.Copy(this.array, array, index); } items.CopyTo(new Span(array, index, items.Length)); if (index != Length) { Array.Copy(this.array, index, array, index + items.Length, Length - index); } return new ImmutableArray(array); } internal ImmutableArray(T[]? items) { array = items; } [System.Runtime.Versioning.NonVersionable] public static bool operator ==(ImmutableArray left, ImmutableArray right) { return left.Equals(right); } [System.Runtime.Versioning.NonVersionable] public static bool operator !=(ImmutableArray left, ImmutableArray right) { return !left.Equals(right); } public static bool operator ==(ImmutableArray? left, ImmutableArray? right) { return left.GetValueOrDefault().Equals(right.GetValueOrDefault()); } public static bool operator !=(ImmutableArray? left, ImmutableArray? right) { return !left.GetValueOrDefault().Equals(right.GetValueOrDefault()); } public ref readonly T ItemRef(int index) { return ref array[index]; } public void CopyTo(T[] destination) { ImmutableArray immutableArray = this; immutableArray.ThrowNullRefIfNotInitialized(); Array.Copy(immutableArray.array, destination, immutableArray.Length); } public void CopyTo(T[] destination, int destinationIndex) { ImmutableArray immutableArray = this; immutableArray.ThrowNullRefIfNotInitialized(); Array.Copy(immutableArray.array, 0, destination, destinationIndex, immutableArray.Length); } public void CopyTo(int sourceIndex, T[] destination, int destinationIndex, int length) { ImmutableArray immutableArray = this; immutableArray.ThrowNullRefIfNotInitialized(); Array.Copy(immutableArray.array, sourceIndex, destination, destinationIndex, length); } public ImmutableArray.Builder ToBuilder() { ImmutableArray items = this; if (items.Length == 0) { return new Builder(); } Builder builder = new Builder(items.Length); builder.AddRange(items); return builder; } [MethodImpl(MethodImplOptions.AggressiveInlining)] public Enumerator GetEnumerator() { ImmutableArray immutableArray = this; immutableArray.ThrowNullRefIfNotInitialized(); return new Enumerator(immutableArray.array); } public override int GetHashCode() { ImmutableArray immutableArray = this; if (immutableArray.array != null) { return immutableArray.array.GetHashCode(); } return 0; } public override bool Equals([NotNullWhen(true)] object? obj) { if (obj is IImmutableArray immutableArray) { return array == immutableArray.Array; } return false; } [System.Runtime.Versioning.NonVersionable] public bool Equals(ImmutableArray other) { return array == other.array; } public static ImmutableArray CastUp(ImmutableArray items) where TDerived : class?, T { T[] items2 = (T[])(object)items.array; return new ImmutableArray(items2); } public ImmutableArray CastArray() where TOther : class? { return new ImmutableArray((TOther[])(object)array); } public ImmutableArray As() where TOther : class? { return new ImmutableArray(array as TOther[]); } IEnumerator IEnumerable.GetEnumerator() { ImmutableArray immutableArray = this; immutableArray.ThrowInvalidOperationIfNotInitialized(); return EnumeratorObject.Create(immutableArray.array); } IEnumerator IEnumerable.GetEnumerator() { ImmutableArray immutableArray = this; immutableArray.ThrowInvalidOperationIfNotInitialized(); return EnumeratorObject.Create(immutableArray.array); } internal void ThrowNullRefIfNotInitialized() { _ = array.Length; } private void ThrowInvalidOperationIfNotInitialized() { if (IsDefault) { throw new InvalidOperationException(System.SR.InvalidOperationOnDefaultArray); } } } internal sealed class ImmutableArrayBuilderDebuggerProxy { private readonly ImmutableArray.Builder _builder; [DebuggerBrowsable(DebuggerBrowsableState.RootHidden)] public T[] A => _builder.ToArray(); public ImmutableArrayBuilderDebuggerProxy(ImmutableArray.Builder builder) { Requires.NotNull(builder, "builder"); _builder = builder; } } public static class ImmutableDictionary { public static ImmutableDictionary Create() where TKey : notnull { return ImmutableDictionary.Empty; } public static ImmutableDictionary Create(IEqualityComparer? keyComparer) where TKey : notnull { return ImmutableDictionary.Empty.WithComparers(keyComparer); } public static ImmutableDictionary Create(IEqualityComparer? keyComparer, IEqualityComparer? valueComparer) where TKey : notnull { return ImmutableDictionary.Empty.WithComparers(keyComparer, valueComparer); } public static ImmutableDictionary CreateRange(IEnumerable> items) where TKey : notnull { return ImmutableDictionary.Empty.AddRange(items); } public static ImmutableDictionary CreateRange(IEqualityComparer? keyComparer, IEnumerable> items) where TKey : notnull { return ImmutableDictionary.Empty.WithComparers(keyComparer).AddRange(items); } public static ImmutableDictionary CreateRange(IEqualityComparer? keyComparer, IEqualityComparer? valueComparer, IEnumerable> items) where TKey : notnull { return ImmutableDictionary.Empty.WithComparers(keyComparer, valueComparer).AddRange(items); } public static ImmutableDictionary.Builder CreateBuilder() where TKey : notnull { return Create().ToBuilder(); } public static ImmutableDictionary.Builder CreateBuilder(IEqualityComparer? keyComparer) where TKey : notnull { return Create(keyComparer).ToBuilder(); } public static ImmutableDictionary.Builder CreateBuilder(IEqualityComparer? keyComparer, IEqualityComparer? valueComparer) where TKey : notnull { return Create(keyComparer, valueComparer).ToBuilder(); } public static ImmutableDictionary ToImmutableDictionary(this IEnumerable source, Func keySelector, Func elementSelector, IEqualityComparer? keyComparer, IEqualityComparer? valueComparer) where TKey : notnull { Func keySelector2 = keySelector; Func elementSelector2 = elementSelector; Requires.NotNull(source, "source"); Requires.NotNull(keySelector2, "keySelector"); Requires.NotNull(elementSelector2, "elementSelector"); return ImmutableDictionary.Empty.WithComparers(keyComparer, valueComparer).AddRange(source.Select((TSource element) => new KeyValuePair(keySelector2(element), elementSelector2(element)))); } public static ImmutableDictionary ToImmutableDictionary(this ImmutableDictionary.Builder builder) where TKey : notnull { Requires.NotNull(builder, "builder"); return builder.ToImmutable(); } public static ImmutableDictionary ToImmutableDictionary(this IEnumerable source, Func keySelector, Func elementSelector, IEqualityComparer? keyComparer) where TKey : notnull { return source.ToImmutableDictionary(keySelector, elementSelector, keyComparer, null); } public static ImmutableDictionary ToImmutableDictionary(this IEnumerable source, Func keySelector) where TKey : notnull { return source.ToImmutableDictionary(keySelector, (TSource v) => v, null, null); } public static ImmutableDictionary ToImmutableDictionary(this IEnumerable source, Func keySelector, IEqualityComparer? keyComparer) where TKey : notnull { return source.ToImmutableDictionary(keySelector, (TSource v) => v, keyComparer, null); } public static ImmutableDictionary ToImmutableDictionary(this IEnumerable source, Func keySelector, Func elementSelector) where TKey : notnull { return source.ToImmutableDictionary(keySelector, elementSelector, null, null); } public static ImmutableDictionary ToImmutableDictionary(this IEnumerable> source, IEqualityComparer? keyComparer, IEqualityComparer? valueComparer) where TKey : notnull { Requires.NotNull(source, "source"); if (source is ImmutableDictionary immutableDictionary) { return immutableDictionary.WithComparers(keyComparer, valueComparer); } return ImmutableDictionary.Empty.WithComparers(keyComparer, valueComparer).AddRange(source); } public static ImmutableDictionary ToImmutableDictionary(this IEnumerable> source, IEqualityComparer? keyComparer) where TKey : notnull { return source.ToImmutableDictionary(keyComparer, null); } public static ImmutableDictionary ToImmutableDictionary(this IEnumerable> source) where TKey : notnull { return source.ToImmutableDictionary(null, null); } public static bool Contains(this IImmutableDictionary map, TKey key, TValue value) where TKey : notnull { Requires.NotNull(map, "map"); Requires.NotNullAllowStructs(key, "key"); return map.Contains(new KeyValuePair(key, value)); } public static TValue? GetValueOrDefault(this IImmutableDictionary dictionary, TKey key) where TKey : notnull { return dictionary.GetValueOrDefault(key, default(TValue)); } public static TValue GetValueOrDefault(this IImmutableDictionary dictionary, TKey key, TValue defaultValue) where TKey : notnull { Requires.NotNull(dictionary, "dictionary"); Requires.NotNullAllowStructs(key, "key"); if (dictionary.TryGetValue(key, out TValue value)) { return value; } return defaultValue; } } [DebuggerDisplay("Count = {Count}")] [DebuggerTypeProxy(typeof(ImmutableDictionaryDebuggerProxy<, >))] public sealed class ImmutableDictionary : IImmutableDictionary, IReadOnlyDictionary, IEnumerable>, IEnumerable, IReadOnlyCollection>, IImmutableDictionaryInternal, IHashKeyCollection, IDictionary, ICollection>, IDictionary, ICollection where TKey : notnull { [DebuggerDisplay("Count = {Count}")] [DebuggerTypeProxy(typeof(System.Collections.Generic.IDictionaryDebugView<, >))] public sealed class Builder : IDictionary, ICollection>, IEnumerable>, IEnumerable, IReadOnlyDictionary, IReadOnlyCollection>, IDictionary, ICollection { private SortedInt32KeyNode _root = SortedInt32KeyNode.EmptyNode; private Comparers _comparers; private int _count; private ImmutableDictionary _immutable; private int _version; private object _syncRoot; public IEqualityComparer KeyComparer { get { return _comparers.KeyComparer; } set { Requires.NotNull(value, "value"); if (value != KeyComparer) { Comparers comparers = Comparers.Get(value, ValueComparer); MutationInput origin = new MutationInput(SortedInt32KeyNode.EmptyNode, comparers); MutationResult mutationResult = ImmutableDictionary.AddRange((IEnumerable>)this, origin, KeyCollisionBehavior.ThrowIfValueDifferent); _immutable = null; _comparers = comparers; _count = mutationResult.CountAdjustment; Root = mutationResult.Root; } } } public IEqualityComparer ValueComparer { get { return _comparers.ValueComparer; } set { Requires.NotNull(value, "value"); if (value != ValueComparer) { _comparers = _comparers.WithValueComparer(value); _immutable = null; } } } public int Count => _count; bool ICollection>.IsReadOnly => false; public IEnumerable Keys { get { using Enumerator enumerator = GetEnumerator(); while (enumerator.MoveNext()) { yield return enumerator.Current.Key; } } } ICollection IDictionary.Keys => Keys.ToArray(Count); public IEnumerable Values { get { using Enumerator enumerator = GetEnumerator(); while (enumerator.MoveNext()) { yield return enumerator.Current.Value; } } } ICollection IDictionary.Values => Values.ToArray(Count); bool IDictionary.IsFixedSize => false; bool IDictionary.IsReadOnly => false; ICollection IDictionary.Keys => Keys.ToArray(Count); ICollection IDictionary.Values => Values.ToArray(Count); [DebuggerBrowsable(DebuggerBrowsableState.Never)] object ICollection.SyncRoot { get { if (_syncRoot == null) { Interlocked.CompareExchange(ref _syncRoot, new object(), (object)null); } return _syncRoot; } } [DebuggerBrowsable(DebuggerBrowsableState.Never)] bool ICollection.IsSynchronized => false; object? IDictionary.this[object key] { get { return this[(TKey)key]; } set { this[(TKey)key] = (TValue)value; } } internal int Version => _version; private MutationInput Origin => new MutationInput(Root, _comparers); private SortedInt32KeyNode Root { get { return _root; } set { _version++; if (_root != value) { _root = value; _immutable = null; } } } public TValue this[TKey key] { get { if (!TryGetValue(key, out var value)) { ThrowHelper.ThrowKeyNotFoundException(key); } return value; } set { MutationResult result = ImmutableDictionary.Add(key, value, KeyCollisionBehavior.SetValue, Origin); Apply(result); } } internal Builder(ImmutableDictionary map) { Requires.NotNull(map, "map"); _root = map._root; _count = map._count; _comparers = map._comparers; _immutable = map; } void IDictionary.Add(object key, object value) { Add((TKey)key, (TValue)value); } bool IDictionary.Contains(object key) { return ContainsKey((TKey)key); } IDictionaryEnumerator IDictionary.GetEnumerator() { return new DictionaryEnumerator(GetEnumerator()); } void IDictionary.Remove(object key) { Remove((TKey)key); } void ICollection.CopyTo(Array array, int arrayIndex) { Requires.NotNull(array, "array"); Requires.Range(arrayIndex >= 0, "arrayIndex"); Requires.Range(array.Length >= arrayIndex + Count, "arrayIndex"); using Enumerator enumerator = GetEnumerator(); while (enumerator.MoveNext()) { KeyValuePair current = enumerator.Current; array.SetValue(new DictionaryEntry(current.Key, current.Value), arrayIndex++); } } public void AddRange(IEnumerable> items) { MutationResult result = ImmutableDictionary.AddRange(items, Origin, KeyCollisionBehavior.ThrowIfValueDifferent); Apply(result); } public void RemoveRange(IEnumerable keys) { Requires.NotNull(keys, "keys"); foreach (TKey key in keys) { Remove(key); } } public Enumerator GetEnumerator() { return new Enumerator(_root, this); } public TValue? GetValueOrDefault(TKey key) { return GetValueOrDefault(key, default(TValue)); } public TValue GetValueOrDefault(TKey key, TValue defaultValue) { Requires.NotNullAllowStructs(key, "key"); if (TryGetValue(key, out var value)) { return value; } return defaultValue; } public ImmutableDictionary ToImmutable() { return _immutable ?? (_immutable = ImmutableDictionary.Wrap(_root, _comparers, _count)); } public void Add(TKey key, TValue value) { MutationResult result = ImmutableDictionary.Add(key, value, KeyCollisionBehavior.ThrowIfValueDifferent, Origin); Apply(result); } public bool ContainsKey(TKey key) { return ImmutableDictionary.ContainsKey(key, Origin); } public bool ContainsValue(TValue value) { using (Enumerator enumerator = GetEnumerator()) { while (enumerator.MoveNext()) { KeyValuePair current = enumerator.Current; if (ValueComparer.Equals(value, current.Value)) { return true; } } } return false; } public bool Remove(TKey key) { MutationResult result = ImmutableDictionary.Remove(key, Origin); return Apply(result); } public bool TryGetValue(TKey key, [MaybeNullWhen(false)] out TValue value) { return ImmutableDictionary.TryGetValue(key, Origin, out value); } public bool TryGetKey(TKey equalKey, out TKey actualKey) { return ImmutableDictionary.TryGetKey(equalKey, Origin, out actualKey); } public void Add(KeyValuePair item) { Add(item.Key, item.Value); } public void Clear() { Root = SortedInt32KeyNode.EmptyNode; _count = 0; } public bool Contains(KeyValuePair item) { return ImmutableDictionary.Contains(item, Origin); } void ICollection>.CopyTo(KeyValuePair[] array, int arrayIndex) { Requires.NotNull(array, "array"); using Enumerator enumerator = GetEnumerator(); while (enumerator.MoveNext()) { KeyValuePair current = enumerator.Current; array[arrayIndex++] = current; } } public bool Remove(KeyValuePair item) { if (Contains(item)) { return Remove(item.Key); } return false; } IEnumerator> IEnumerable>.GetEnumerator() { return GetEnumerator(); } IEnumerator IEnumerable.GetEnumerator() { return GetEnumerator(); } private bool Apply(MutationResult result) { Root = result.Root; _count += result.CountAdjustment; return result.CountAdjustment != 0; } } internal sealed class Comparers : IEqualityComparer, IEqualityComparer> { internal static readonly Comparers Default = new Comparers(EqualityComparer.Default, EqualityComparer.Default); private readonly IEqualityComparer _keyComparer; private readonly IEqualityComparer _valueComparer; internal IEqualityComparer KeyComparer => _keyComparer; internal IEqualityComparer> KeyOnlyComparer => this; internal IEqualityComparer ValueComparer => _valueComparer; internal IEqualityComparer HashBucketEqualityComparer => this; internal Comparers(IEqualityComparer keyComparer, IEqualityComparer valueComparer) { Requires.NotNull(keyComparer, "keyComparer"); Requires.NotNull(valueComparer, "valueComparer"); _keyComparer = keyComparer; _valueComparer = valueComparer; } public bool Equals(HashBucket x, HashBucket y) { if (x.AdditionalElements == y.AdditionalElements && KeyComparer.Equals(x.FirstValue.Key, y.FirstValue.Key)) { return ValueComparer.Equals(x.FirstValue.Value, y.FirstValue.Value); } return false; } public int GetHashCode(HashBucket obj) { return KeyComparer.GetHashCode(obj.FirstValue.Key); } bool IEqualityComparer>.Equals(KeyValuePair x, KeyValuePair y) { return _keyComparer.Equals(x.Key, y.Key); } int IEqualityComparer>.GetHashCode(KeyValuePair obj) { return _keyComparer.GetHashCode(obj.Key); } internal static Comparers Get(IEqualityComparer keyComparer, IEqualityComparer valueComparer) { Requires.NotNull(keyComparer, "keyComparer"); Requires.NotNull(valueComparer, "valueComparer"); if (keyComparer != Default.KeyComparer || valueComparer != Default.ValueComparer) { return new Comparers(keyComparer, valueComparer); } return Default; } internal Comparers WithValueComparer(IEqualityComparer valueComparer) { Requires.NotNull(valueComparer, "valueComparer"); if (_valueComparer != valueComparer) { return Get(KeyComparer, valueComparer); } return this; } } public struct Enumerator : IEnumerator>, IEnumerator, IDisposable { private readonly Builder _builder; private SortedInt32KeyNode.Enumerator _mapEnumerator; private HashBucket.Enumerator _bucketEnumerator; private int _enumeratingBuilderVersion; public KeyValuePair Current { get { _mapEnumerator.ThrowIfDisposed(); return _bucketEnumerator.Current; } } object IEnumerator.Current => Current; internal Enumerator(SortedInt32KeyNode root, Builder? builder = null) { _builder = builder; _mapEnumerator = new SortedInt32KeyNode.Enumerator(root); _bucketEnumerator = default(HashBucket.Enumerator); _enumeratingBuilderVersion = builder?.Version ?? (-1); } public bool MoveNext() { ThrowIfChanged(); if (_bucketEnumerator.MoveNext()) { return true; } if (_mapEnumerator.MoveNext()) { _bucketEnumerator = new HashBucket.Enumerator(_mapEnumerator.Current.Value); return _bucketEnumerator.MoveNext(); } return false; } public void Reset() { _enumeratingBuilderVersion = ((_builder != null) ? _builder.Version : (-1)); _mapEnumerator.Reset(); _bucketEnumerator.Dispose(); _bucketEnumerator = default(HashBucket.Enumerator); } public void Dispose() { _mapEnumerator.Dispose(); _bucketEnumerator.Dispose(); } private void ThrowIfChanged() { if (_builder != null && _builder.Version != _enumeratingBuilderVersion) { throw new InvalidOperationException(System.SR.CollectionModifiedDuringEnumeration); } } } internal readonly struct HashBucket : IEnumerable>, IEnumerable { internal struct Enumerator : IEnumerator>, IEnumerator, IDisposable { private enum Position { BeforeFirst, First, Additional, End } private readonly HashBucket _bucket; private Position _currentPosition; private ImmutableList>.Enumerator _additionalEnumerator; object IEnumerator.Current => Current; public KeyValuePair Current => _currentPosition switch { Position.First => _bucket._firstValue, Position.Additional => _additionalEnumerator.Current, _ => throw new InvalidOperationException(), }; internal Enumerator(HashBucket bucket) { _bucket = bucket; _currentPosition = Position.BeforeFirst; _additionalEnumerator = default(ImmutableList>.Enumerator); } public bool MoveNext() { if (_bucket.IsEmpty) { _currentPosition = Position.End; return false; } switch (_currentPosition) { case Position.BeforeFirst: _currentPosition = Position.First; return true; case Position.First: if (_bucket._additionalElements.IsEmpty) { _currentPosition = Position.End; return false; } _currentPosition = Position.Additional; _additionalEnumerator = new ImmutableList>.Enumerator(_bucket._additionalElements); return _additionalEnumerator.MoveNext(); case Position.Additional: return _additionalEnumerator.MoveNext(); case Position.End: return false; default: throw new InvalidOperationException(); } } public void Reset() { _additionalEnumerator.Dispose(); _currentPosition = Position.BeforeFirst; } public void Dispose() { _additionalEnumerator.Dispose(); } } private readonly KeyValuePair _firstValue; private readonly ImmutableList>.Node _additionalElements; internal bool IsEmpty => _additionalElements == null; internal KeyValuePair FirstValue { get { if (IsEmpty) { throw new InvalidOperationException(); } return _firstValue; } } internal ImmutableList>.Node AdditionalElements => _additionalElements; private HashBucket(KeyValuePair firstElement, ImmutableList>.Node additionalElements = null) { _firstValue = firstElement; _additionalElements = additionalElements ?? ImmutableList>.Node.EmptyNode; } public Enumerator GetEnumerator() { return new Enumerator(this); } IEnumerator> IEnumerable>.GetEnumerator() { return GetEnumerator(); } IEnumerator IEnumerable.GetEnumerator() { return GetEnumerator(); } public override bool Equals(object? obj) { throw new NotSupportedException(); } public override int GetHashCode() { throw new NotSupportedException(); } internal HashBucket Add(TKey key, TValue value, IEqualityComparer> keyOnlyComparer, IEqualityComparer valueComparer, KeyCollisionBehavior behavior, out OperationResult result) { KeyValuePair keyValuePair = new KeyValuePair(key, value); if (IsEmpty) { result = OperationResult.SizeChanged; return new HashBucket(keyValuePair); } if (keyOnlyComparer.Equals(keyValuePair, _firstValue)) { switch (behavior) { case KeyCollisionBehavior.SetValue: result = OperationResult.AppliedWithoutSizeChange; return new HashBucket(keyValuePair, _additionalElements); case KeyCollisionBehavior.Skip: result = OperationResult.NoChangeRequired; return this; case KeyCollisionBehavior.ThrowIfValueDifferent: { KeyValuePair firstValue = _firstValue; if (!valueComparer.Equals(firstValue.Value, value)) { throw new ArgumentException(System.SR.Format(System.SR.DuplicateKey, key)); } result = OperationResult.NoChangeRequired; return this; } case KeyCollisionBehavior.ThrowAlways: throw new ArgumentException(System.SR.Format(System.SR.DuplicateKey, key)); default: throw new InvalidOperationException(); } } int num = _additionalElements.IndexOf(keyValuePair, keyOnlyComparer); if (num < 0) { result = OperationResult.SizeChanged; return new HashBucket(_firstValue, _additionalElements.Add(keyValuePair)); } switch (behavior) { case KeyCollisionBehavior.SetValue: result = OperationResult.AppliedWithoutSizeChange; return new HashBucket(_firstValue, _additionalElements.ReplaceAt(num, keyValuePair)); case KeyCollisionBehavior.Skip: result = OperationResult.NoChangeRequired; return this; case KeyCollisionBehavior.ThrowIfValueDifferent: { KeyValuePair firstValue = _additionalElements.ItemRef(num); if (!valueComparer.Equals(firstValue.Value, value)) { throw new ArgumentException(System.SR.Format(System.SR.DuplicateKey, key)); } result = OperationResult.NoChangeRequired; return this; } case KeyCollisionBehavior.ThrowAlways: throw new ArgumentException(System.SR.Format(System.SR.DuplicateKey, key)); default: throw new InvalidOperationException(); } } internal HashBucket Remove(TKey key, IEqualityComparer> keyOnlyComparer, out OperationResult result) { if (IsEmpty) { result = OperationResult.NoChangeRequired; return this; } KeyValuePair keyValuePair = new KeyValuePair(key, default(TValue)); if (keyOnlyComparer.Equals(_firstValue, keyValuePair)) { if (_additionalElements.IsEmpty) { result = OperationResult.SizeChanged; return default(HashBucket); } int count = _additionalElements.Left.Count; result = OperationResult.SizeChanged; return new HashBucket(_additionalElements.Key, _additionalElements.RemoveAt(count)); } int num = _additionalElements.IndexOf(keyValuePair, keyOnlyComparer); if (num < 0) { result = OperationResult.NoChangeRequired; return this; } result = OperationResult.SizeChanged; return new HashBucket(_firstValue, _additionalElements.RemoveAt(num)); } internal bool TryGetValue(TKey key, Comparers comparers, [MaybeNullWhen(false)] out TValue value) { if (IsEmpty) { value = default(TValue); return false; } IEqualityComparer keyComparer = comparers.KeyComparer; KeyValuePair firstValue = _firstValue; if (keyComparer.Equals(firstValue.Key, key)) { firstValue = _firstValue; value = firstValue.Value; return true; } KeyValuePair item = new KeyValuePair(key, default(TValue)); int num = _additionalElements.IndexOf(item, comparers.KeyOnlyComparer); if (num < 0) { value = default(TValue); return false; } firstValue = _additionalElements.ItemRef(num); value = firstValue.Value; return true; } internal bool TryGetKey(TKey equalKey, Comparers comparers, out TKey actualKey) { if (IsEmpty) { actualKey = equalKey; return false; } IEqualityComparer keyComparer = comparers.KeyComparer; KeyValuePair firstValue = _firstValue; if (keyComparer.Equals(firstValue.Key, equalKey)) { firstValue = _firstValue; actualKey = firstValue.Key; return true; } KeyValuePair item = new KeyValuePair(equalKey, default(TValue)); int num = _additionalElements.IndexOf(item, comparers.KeyOnlyComparer); if (num < 0) { actualKey = equalKey; return false; } firstValue = _additionalElements.ItemRef(num); actualKey = firstValue.Key; return true; } internal void Freeze() { _additionalElements?.Freeze(); } } private readonly struct MutationInput { private readonly SortedInt32KeyNode _root; private readonly Comparers _comparers; internal SortedInt32KeyNode Root => _root; internal Comparers Comparers => _comparers; internal IEqualityComparer KeyComparer => _comparers.KeyComparer; internal IEqualityComparer> KeyOnlyComparer => _comparers.KeyOnlyComparer; internal IEqualityComparer ValueComparer => _comparers.ValueComparer; internal IEqualityComparer HashBucketComparer => _comparers.HashBucketEqualityComparer; internal MutationInput(SortedInt32KeyNode root, Comparers comparers) { _root = root; _comparers = comparers; } internal MutationInput(ImmutableDictionary map) { _root = map._root; _comparers = map._comparers; } } private readonly struct MutationResult { private readonly SortedInt32KeyNode _root; private readonly int _countAdjustment; internal SortedInt32KeyNode Root => _root; internal int CountAdjustment => _countAdjustment; internal MutationResult(MutationInput unchangedInput) { _root = unchangedInput.Root; _countAdjustment = 0; } internal MutationResult(SortedInt32KeyNode root, int countAdjustment) { Requires.NotNull(root, "root"); _root = root; _countAdjustment = countAdjustment; } internal ImmutableDictionary Finalize(ImmutableDictionary priorMap) { Requires.NotNull(priorMap, "priorMap"); return priorMap.Wrap(Root, priorMap._count + CountAdjustment); } } internal enum KeyCollisionBehavior { SetValue, Skip, ThrowIfValueDifferent, ThrowAlways } internal enum OperationResult { AppliedWithoutSizeChange, SizeChanged, NoChangeRequired } public static readonly ImmutableDictionary Empty = new ImmutableDictionary(); private static readonly Action> s_FreezeBucketAction = delegate(KeyValuePair kv) { kv.Value.Freeze(); }; private readonly int _count; private readonly SortedInt32KeyNode _root; private readonly Comparers _comparers; public int Count => _count; public bool IsEmpty => Count == 0; public IEqualityComparer KeyComparer => _comparers.KeyComparer; public IEqualityComparer ValueComparer => _comparers.ValueComparer; public IEnumerable Keys { get { foreach (KeyValuePair item in _root) { foreach (KeyValuePair item2 in item.Value) { yield return item2.Key; } } } } public IEnumerable Values { get { foreach (KeyValuePair item in _root) { foreach (KeyValuePair item2 in item.Value) { yield return item2.Value; } } } } ICollection IDictionary.Keys => new KeysCollectionAccessor(this); ICollection IDictionary.Values => new ValuesCollectionAccessor(this); private MutationInput Origin => new MutationInput(this); public TValue this[TKey key] { get { Requires.NotNullAllowStructs(key, "key"); if (!TryGetValue(key, out var value)) { ThrowHelper.ThrowKeyNotFoundException(key); } return value; } } TValue IDictionary.this[TKey key] { get { return this[key]; } set { throw new NotSupportedException(); } } bool ICollection>.IsReadOnly => true; bool IDictionary.IsFixedSize => true; bool IDictionary.IsReadOnly => true; ICollection IDictionary.Keys => new KeysCollectionAccessor(this); ICollection IDictionary.Values => new ValuesCollectionAccessor(this); internal SortedInt32KeyNode Root => _root; object? IDictionary.this[object key] { get { return this[(TKey)key]; } set { throw new NotSupportedException(); } } [DebuggerBrowsable(DebuggerBrowsableState.Never)] object ICollection.SyncRoot => this; [DebuggerBrowsable(DebuggerBrowsableState.Never)] bool ICollection.IsSynchronized => true; private ImmutableDictionary(SortedInt32KeyNode root, Comparers comparers, int count) : this(Requires.NotNullPassthrough(comparers, "comparers")) { Requires.NotNull(root, "root"); root.Freeze(s_FreezeBucketAction); _root = root; _count = count; } private ImmutableDictionary(Comparers comparers = null) { _comparers = comparers ?? Comparers.Get(EqualityComparer.Default, EqualityComparer.Default); _root = SortedInt32KeyNode.EmptyNode; } public ImmutableDictionary Clear() { if (!IsEmpty) { return EmptyWithComparers(_comparers); } return this; } IImmutableDictionary IImmutableDictionary.Clear() { return Clear(); } public Builder ToBuilder() { return new Builder(this); } public ImmutableDictionary Add(TKey key, TValue value) { Requires.NotNullAllowStructs(key, "key"); return Add(key, value, KeyCollisionBehavior.ThrowIfValueDifferent, Origin).Finalize(this); } public ImmutableDictionary AddRange(IEnumerable> pairs) { Requires.NotNull(pairs, "pairs"); return AddRange(pairs, avoidToHashMap: false); } public ImmutableDictionary SetItem(TKey key, TValue value) { Requires.NotNullAllowStructs(key, "key"); return Add(key, value, KeyCollisionBehavior.SetValue, Origin).Finalize(this); } public ImmutableDictionary SetItems(IEnumerable> items) { Requires.NotNull(items, "items"); return AddRange(items, Origin, KeyCollisionBehavior.SetValue).Finalize(this); } public ImmutableDictionary Remove(TKey key) { Requires.NotNullAllowStructs(key, "key"); return Remove(key, Origin).Finalize(this); } public ImmutableDictionary RemoveRange(IEnumerable keys) { Requires.NotNull(keys, "keys"); int num = _count; SortedInt32KeyNode sortedInt32KeyNode = _root; foreach (TKey key in keys) { int hashCode = KeyComparer.GetHashCode(key); if (sortedInt32KeyNode.TryGetValue(hashCode, out var value)) { OperationResult result; HashBucket newBucket = value.Remove(key, _comparers.KeyOnlyComparer, out result); sortedInt32KeyNode = UpdateRoot(sortedInt32KeyNode, hashCode, newBucket, _comparers.HashBucketEqualityComparer); if (result == OperationResult.SizeChanged) { num--; } } } return Wrap(sortedInt32KeyNode, num); } public bool ContainsKey(TKey key) { Requires.NotNullAllowStructs(key, "key"); return ContainsKey(key, Origin); } public bool Contains(KeyValuePair pair) { return Contains(pair, Origin); } public bool TryGetValue(TKey key, [MaybeNullWhen(false)] out TValue value) { Requires.NotNullAllowStructs(key, "key"); return TryGetValue(key, Origin, out value); } public bool TryGetKey(TKey equalKey, out TKey actualKey) { Requires.NotNullAllowStructs(equalKey, "equalKey"); return TryGetKey(equalKey, Origin, out actualKey); } public ImmutableDictionary WithComparers(IEqualityComparer? keyComparer, IEqualityComparer? valueComparer) { if (keyComparer == null) { keyComparer = EqualityComparer.Default; } if (valueComparer == null) { valueComparer = EqualityComparer.Default; } if (KeyComparer == keyComparer) { if (ValueComparer == valueComparer) { return this; } Comparers comparers = _comparers.WithValueComparer(valueComparer); return new ImmutableDictionary(_root, comparers, _count); } return new ImmutableDictionary(Comparers.Get(keyComparer, valueComparer)).AddRange(this, avoidToHashMap: true); } public ImmutableDictionary WithComparers(IEqualityComparer? keyComparer) { return WithComparers(keyComparer, _comparers.ValueComparer); } public bool ContainsValue(TValue value) { using (Enumerator enumerator = GetEnumerator()) { while (enumerator.MoveNext()) { KeyValuePair current = enumerator.Current; if (ValueComparer.Equals(value, current.Value)) { return true; } } } return false; } public Enumerator GetEnumerator() { return new Enumerator(_root); } IImmutableDictionary IImmutableDictionary.Add(TKey key, TValue value) { return Add(key, value); } IImmutableDictionary IImmutableDictionary.SetItem(TKey key, TValue value) { return SetItem(key, value); } IImmutableDictionary IImmutableDictionary.SetItems(IEnumerable> items) { return SetItems(items); } IImmutableDictionary IImmutableDictionary.AddRange(IEnumerable> pairs) { return AddRange(pairs); } IImmutableDictionary IImmutableDictionary.RemoveRange(IEnumerable keys) { return RemoveRange(keys); } IImmutableDictionary IImmutableDictionary.Remove(TKey key) { return Remove(key); } void IDictionary.Add(TKey key, TValue value) { throw new NotSupportedException(); } bool IDictionary.Remove(TKey key) { throw new NotSupportedException(); } void ICollection>.Add(KeyValuePair item) { throw new NotSupportedException(); } void ICollection>.Clear() { throw new NotSupportedException(); } bool ICollection>.Remove(KeyValuePair item) { throw new NotSupportedException(); } void ICollection>.CopyTo(KeyValuePair[] array, int arrayIndex) { Requires.NotNull(array, "array"); Requires.Range(arrayIndex >= 0, "arrayIndex"); Requires.Range(array.Length >= arrayIndex + Count, "arrayIndex"); using Enumerator enumerator = GetEnumerator(); while (enumerator.MoveNext()) { KeyValuePair current = enumerator.Current; array[arrayIndex++] = current; } } void IDictionary.Add(object key, object value) { throw new NotSupportedException(); } bool IDictionary.Contains(object key) { return ContainsKey((TKey)key); } IDictionaryEnumerator IDictionary.GetEnumerator() { return new DictionaryEnumerator(GetEnumerator()); } void IDictionary.Remove(object key) { throw new NotSupportedException(); } void IDictionary.Clear() { throw new NotSupportedException(); } void ICollection.CopyTo(Array array, int arrayIndex) { Requires.NotNull(array, "array"); Requires.Range(arrayIndex >= 0, "arrayIndex"); Requires.Range(array.Length >= arrayIndex + Count, "arrayIndex"); using Enumerator enumerator = GetEnumerator(); while (enumerator.MoveNext()) { KeyValuePair current = enumerator.Current; array.SetValue(new DictionaryEntry(current.Key, current.Value), arrayIndex++); } } IEnumerator> IEnumerable>.GetEnumerator() { if (!IsEmpty) { return GetEnumerator(); } return Enumerable.Empty>().GetEnumerator(); } IEnumerator IEnumerable.GetEnumerator() { return GetEnumerator(); } private static ImmutableDictionary EmptyWithComparers(Comparers comparers) { Requires.NotNull(comparers, "comparers"); if (Empty._comparers != comparers) { return new ImmutableDictionary(comparers); } return Empty; } private static bool TryCastToImmutableMap(IEnumerable> sequence, [NotNullWhen(true)] out ImmutableDictionary other) { other = sequence as ImmutableDictionary; if (other != null) { return true; } if (sequence is Builder builder) { other = builder.ToImmutable(); return true; } return false; } private static bool ContainsKey(TKey key, MutationInput origin) { int hashCode = origin.KeyComparer.GetHashCode(key); TValue value2; if (origin.Root.TryGetValue(hashCode, out var value)) { return value.TryGetValue(key, origin.Comparers, out value2); } return false; } private static bool Contains(KeyValuePair keyValuePair, MutationInput origin) { int hashCode = origin.KeyComparer.GetHashCode(keyValuePair.Key); if (origin.Root.TryGetValue(hashCode, out var value)) { if (value.TryGetValue(keyValuePair.Key, origin.Comparers, out var value2)) { return origin.ValueComparer.Equals(value2, keyValuePair.Value); } return false; } return false; } private static bool TryGetValue(TKey key, MutationInput origin, [MaybeNullWhen(false)] out TValue value) { int hashCode = origin.KeyComparer.GetHashCode(key); if (origin.Root.TryGetValue(hashCode, out var value2)) { return value2.TryGetValue(key, origin.Comparers, out value); } value = default(TValue); return false; } private static bool TryGetKey(TKey equalKey, MutationInput origin, out TKey actualKey) { int hashCode = origin.KeyComparer.GetHashCode(equalKey); if (origin.Root.TryGetValue(hashCode, out var value)) { return value.TryGetKey(equalKey, origin.Comparers, out actualKey); } actualKey = equalKey; return false; } private static MutationResult Add(TKey key, TValue value, KeyCollisionBehavior behavior, MutationInput origin) { Requires.NotNullAllowStructs(key, "key"); int hashCode = origin.KeyComparer.GetHashCode(key); OperationResult result; HashBucket newBucket = origin.Root.GetValueOrDefault(hashCode).Add(key, value, origin.KeyOnlyComparer, origin.ValueComparer, behavior, out result); if (result == OperationResult.NoChangeRequired) { return new MutationResult(origin); } return new MutationResult(UpdateRoot(origin.Root, hashCode, newBucket, origin.HashBucketComparer), (result == OperationResult.SizeChanged) ? 1 : 0); } private static MutationResult AddRange(IEnumerable> items, MutationInput origin, KeyCollisionBehavior collisionBehavior = KeyCollisionBehavior.ThrowIfValueDifferent) { Requires.NotNull(items, "items"); int num = 0; SortedInt32KeyNode sortedInt32KeyNode = origin.Root; foreach (KeyValuePair item in items) { Requires.NotNullAllowStructs(item.Key, "Key"); int hashCode = origin.KeyComparer.GetHashCode(item.Key); OperationResult result; HashBucket newBucket = sortedInt32KeyNode.GetValueOrDefault(hashCode).Add(item.Key, item.Value, origin.KeyOnlyComparer, origin.ValueComparer, collisionBehavior, out result); sortedInt32KeyNode = UpdateRoot(sortedInt32KeyNode, hashCode, newBucket, origin.HashBucketComparer); if (result == OperationResult.SizeChanged) { num++; } } return new MutationResult(sortedInt32KeyNode, num); } private static MutationResult Remove(TKey key, MutationInput origin) { int hashCode = origin.KeyComparer.GetHashCode(key); OperationResult result; if (origin.Root.TryGetValue(hashCode, out var value)) { return new MutationResult(UpdateRoot(origin.Root, hashCode, value.Remove(key, origin.KeyOnlyComparer, out result), origin.HashBucketComparer), (result == OperationResult.SizeChanged) ? (-1) : 0); } return new MutationResult(origin); } private static SortedInt32KeyNode UpdateRoot(SortedInt32KeyNode root, int hashCode, HashBucket newBucket, IEqualityComparer hashBucketComparer) { bool mutated; if (newBucket.IsEmpty) { return root.Remove(hashCode, out mutated); } bool mutated2; return root.SetItem(hashCode, newBucket, hashBucketComparer, out mutated, out mutated2); } private static ImmutableDictionary Wrap(SortedInt32KeyNode root, Comparers comparers, int count) { Requires.NotNull(root, "root"); Requires.NotNull(comparers, "comparers"); Requires.Range(count >= 0, "count"); return new ImmutableDictionary(root, comparers, count); } private ImmutableDictionary Wrap(SortedInt32KeyNode root, int adjustedCountIfDifferentRoot) { if (root == null) { return Clear(); } if (_root != root) { if (!root.IsEmpty) { return new ImmutableDictionary(root, _comparers, adjustedCountIfDifferentRoot); } return Clear(); } return this; } private ImmutableDictionary AddRange(IEnumerable> pairs, bool avoidToHashMap) { Requires.NotNull(pairs, "pairs"); if (IsEmpty && !avoidToHashMap && TryCastToImmutableMap(pairs, out var other)) { return other.WithComparers(KeyComparer, ValueComparer); } return AddRange(pairs, Origin).Finalize(this); } } internal sealed class ImmutableDictionaryDebuggerProxy where TKey : notnull { private readonly IReadOnlyDictionary _dictionary; private DebugViewDictionaryItem[] _cachedContents; [DebuggerBrowsable(DebuggerBrowsableState.RootHidden)] public DebugViewDictionaryItem[] Contents => _cachedContents ?? (_cachedContents = _dictionary.Select((KeyValuePair kv) => new DebugViewDictionaryItem(kv)).ToArray(_dictionary.Count)); public ImmutableDictionaryDebuggerProxy(IReadOnlyDictionary dictionary) { Requires.NotNull(dictionary, "dictionary"); _dictionary = dictionary; } } internal class ImmutableEnumerableDebuggerProxy { private readonly IEnumerable _enumerable; private T[] _cachedContents; [DebuggerBrowsable(DebuggerBrowsableState.RootHidden)] public T[] Contents => _cachedContents ?? (_cachedContents = _enumerable.ToArray()); public ImmutableEnumerableDebuggerProxy(IEnumerable enumerable) { Requires.NotNull(enumerable, "enumerable"); _enumerable = enumerable; } } internal static class ImmutableExtensions { private sealed class ListOfTWrapper : IOrderedCollection, IEnumerable, IEnumerable { private readonly IList _collection; public int Count => _collection.Count; public T this[int index] => _collection[index]; internal ListOfTWrapper(IList collection) { Requires.NotNull(collection, "collection"); _collection = collection; } public IEnumerator GetEnumerator() { return _collection.GetEnumerator(); } IEnumerator IEnumerable.GetEnumerator() { return GetEnumerator(); } } private sealed class FallbackWrapper : IOrderedCollection, IEnumerable, IEnumerable { private readonly IEnumerable _sequence; private IList _collection; public int Count { get { if (_collection == null) { if (_sequence.TryGetCount(out var count)) { return count; } _collection = _sequence.ToArray(); } return _collection.Count; } } public T this[int index] { get { if (_collection == null) { _collection = _sequence.ToArray(); } return _collection[index]; } } internal FallbackWrapper(IEnumerable sequence) { Requires.NotNull(sequence, "sequence"); _sequence = sequence; } public IEnumerator GetEnumerator() { return _sequence.GetEnumerator(); } IEnumerator IEnumerable.GetEnumerator() { return GetEnumerator(); } } internal static bool IsValueType() { if (default(T) != null) { return true; } Type typeFromHandle = typeof(T); if (typeFromHandle.IsConstructedGenericType && typeFromHandle.GetGenericTypeDefinition() == typeof(Nullable<>)) { return true; } return false; } internal static IOrderedCollection AsOrderedCollection(this IEnumerable sequence) { Requires.NotNull(sequence, "sequence"); if (sequence is IOrderedCollection result) { return result; } if (sequence is IList collection) { return new ListOfTWrapper(collection); } return new FallbackWrapper(sequence); } internal static void ClearFastWhenEmpty(this Stack stack) { if (stack.Count > 0) { stack.Clear(); } } internal static DisposableEnumeratorAdapter GetEnumerableDisposable(this IEnumerable enumerable) where TEnumerator : struct, IStrongEnumerator, IEnumerator { Requires.NotNull(enumerable, "enumerable"); if (enumerable is IStrongEnumerable strongEnumerable) { return new DisposableEnumeratorAdapter(strongEnumerable.GetEnumerator()); } return new DisposableEnumeratorAdapter(enumerable.GetEnumerator()); } internal static bool TryGetCount(this IEnumerable sequence, out int count) { return ((IEnumerable)sequence).TryGetCount(out count); } internal static bool TryGetCount(this IEnumerable sequence, out int count) { if (sequence is ICollection collection) { count = collection.Count; return true; } if (sequence is ICollection collection2) { count = collection2.Count; return true; } if (sequence is IReadOnlyCollection readOnlyCollection) { count = readOnlyCollection.Count; return true; } count = 0; return false; } internal static int GetCount(ref IEnumerable sequence) { if (!sequence.TryGetCount(out var count)) { List list = sequence.ToList(); count = list.Count; sequence = list; } return count; } internal static bool TryCopyTo(this IEnumerable sequence, T[] array, int arrayIndex) { if (sequence is IList) { if (sequence is List list) { list.CopyTo(array, arrayIndex); return true; } if (sequence.GetType() == typeof(T[])) { T[] array2 = (T[])sequence; Array.Copy(array2, 0, array, arrayIndex, array2.Length); return true; } if (sequence is ImmutableArray immutableArray) { Array.Copy(immutableArray.array, 0, array, arrayIndex, immutableArray.Length); return true; } } return false; } internal static T[] ToArray(this IEnumerable sequence, int count) { Requires.NotNull(sequence, "sequence"); Requires.Range(count >= 0, "count"); if (count == 0) { return ImmutableArray.Empty.array; } T[] array = new T[count]; if (!sequence.TryCopyTo(array, 0)) { int num = 0; foreach (T item in sequence) { Requires.Argument(num < count); array[num++] = item; } Requires.Argument(num == count); } return array; } } public static class ImmutableHashSet { public static ImmutableHashSet Create() { return ImmutableHashSet.Empty; } public static ImmutableHashSet Create(IEqualityComparer? equalityComparer) { return ImmutableHashSet.Empty.WithComparer(equalityComparer); } public static ImmutableHashSet Create(T item) { return ImmutableHashSet.Empty.Add(item); } public static ImmutableHashSet Create(IEqualityComparer? equalityComparer, T item) { return ImmutableHashSet.Empty.WithComparer(equalityComparer).Add(item); } public static ImmutableHashSet CreateRange(IEnumerable items) { return ImmutableHashSet.Empty.Union(items); } public static ImmutableHashSet CreateRange(IEqualityComparer? equalityComparer, IEnumerable items) { return ImmutableHashSet.Empty.WithComparer(equalityComparer).Union(items); } public static ImmutableHashSet Create(params T[] items) { Requires.NotNull(items, "items"); return Create((ReadOnlySpan)items); } public static ImmutableHashSet Create([ParamCollection] scoped ReadOnlySpan items) { return ImmutableHashSet.Empty.Union(items); } public static ImmutableHashSet Create(IEqualityComparer? equalityComparer, params T[] items) { Requires.NotNull(items, "items"); return Create(equalityComparer, (ReadOnlySpan)items); } public static ImmutableHashSet Create(IEqualityComparer? equalityComparer, [ParamCollection] scoped ReadOnlySpan items) { return ImmutableHashSet.Empty.WithComparer(equalityComparer).Union(items); } public static ImmutableHashSet.Builder CreateBuilder() { return Create().ToBuilder(); } public static ImmutableHashSet.Builder CreateBuilder(IEqualityComparer? equalityComparer) { return Create(equalityComparer).ToBuilder(); } public static ImmutableHashSet ToImmutableHashSet(this IEnumerable source, IEqualityComparer? equalityComparer) { if (source is ImmutableHashSet immutableHashSet) { return immutableHashSet.WithComparer(equalityComparer); } return ImmutableHashSet.Empty.WithComparer(equalityComparer).Union(source); } public static ImmutableHashSet ToImmutableHashSet(this ImmutableHashSet.Builder builder) { Requires.NotNull(builder, "builder"); return builder.ToImmutable(); } public static ImmutableHashSet ToImmutableHashSet(this IEnumerable source) { return source.ToImmutableHashSet(null); } } public static class ImmutableInterlocked { public static bool Update(ref T location, Func transformer) where T : class? { Requires.NotNull(transformer, "transformer"); T val = Volatile.Read(ref location); bool flag; do { T val2 = transformer(val); if (val == val2) { return false; } T val3 = Interlocked.CompareExchange(ref location, val2, val); flag = val == val3; val = val3; } while (!flag); return true; } public static bool Update(ref T location, Func transformer, TArg transformerArgument) where T : class? { Requires.NotNull(transformer, "transformer"); T val = Volatile.Read(ref location); bool flag; do { T val2 = transformer(val, transformerArgument); if (val == val2) { return false; } T val3 = Interlocked.CompareExchange(ref location, val2, val); flag = val == val3; val = val3; } while (!flag); return true; } public static bool Update(ref ImmutableArray location, Func, ImmutableArray> transformer) { Requires.NotNull(transformer, "transformer"); T[] array = Volatile.Read(ref Unsafe.AsRef(in location.array)); bool flag; do { ImmutableArray immutableArray = transformer(new ImmutableArray(array)); if (array == immutableArray.array) { return false; } T[] array2 = Interlocked.CompareExchange(ref Unsafe.AsRef(in location.array), immutableArray.array, array); flag = array == array2; array = array2; } while (!flag); return true; } public static bool Update(ref ImmutableArray location, Func, TArg, ImmutableArray> transformer, TArg transformerArgument) { Requires.NotNull(transformer, "transformer"); T[] array = Volatile.Read(ref Unsafe.AsRef(in location.array)); bool flag; do { ImmutableArray immutableArray = transformer(new ImmutableArray(array), transformerArgument); if (array == immutableArray.array) { return false; } T[] array2 = Interlocked.CompareExchange(ref Unsafe.AsRef(in location.array), immutableArray.array, array); flag = array == array2; array = array2; } while (!flag); return true; } public static ImmutableArray InterlockedExchange(ref ImmutableArray location, ImmutableArray value) { return new ImmutableArray(Interlocked.Exchange(ref Unsafe.AsRef(in location.array), value.array)); } public static ImmutableArray InterlockedCompareExchange(ref ImmutableArray location, ImmutableArray value, ImmutableArray comparand) { return new ImmutableArray(Interlocked.CompareExchange(ref Unsafe.AsRef(in location.array), value.array, comparand.array)); } public static bool InterlockedInitialize(ref ImmutableArray location, ImmutableArray value) { return InterlockedCompareExchange(ref location, value, default(ImmutableArray)).IsDefault; } public static TValue GetOrAdd(ref ImmutableDictionary location, TKey key, Func valueFactory, TArg factoryArgument) where TKey : notnull { Requires.NotNull(valueFactory, "valueFactory"); ImmutableDictionary immutableDictionary = Volatile.Read(ref location); Requires.NotNull(immutableDictionary, "location"); if (immutableDictionary.TryGetValue(key, out TValue value)) { return value; } value = valueFactory(key, factoryArgument); return GetOrAdd(ref location, key, value); } public static TValue GetOrAdd(ref ImmutableDictionary location, TKey key, Func valueFactory) where TKey : notnull { Requires.NotNull(valueFactory, "valueFactory"); ImmutableDictionary immutableDictionary = Volatile.Read(ref location); Requires.NotNull(immutableDictionary, "location"); if (immutableDictionary.TryGetValue(key, out TValue value)) { return value; } value = valueFactory(key); return GetOrAdd(ref location, key, value); } public static TValue GetOrAdd(ref ImmutableDictionary location, TKey key, TValue value) where TKey : notnull { ImmutableDictionary immutableDictionary = Volatile.Read(ref location); bool flag; do { Requires.NotNull(immutableDictionary, "location"); if (immutableDictionary.TryGetValue(key, out var value2)) { return value2; } ImmutableDictionary value3 = immutableDictionary.Add(key, value); ImmutableDictionary immutableDictionary2 = Interlocked.CompareExchange(ref location, value3, immutableDictionary); flag = immutableDictionary == immutableDictionary2; immutableDictionary = immutableDictionary2; } while (!flag); return value; } public static TValue AddOrUpdate(ref ImmutableDictionary location, TKey key, Func addValueFactory, Func updateValueFactory) where TKey : notnull { Requires.NotNull(addValueFactory, "addValueFactory"); Requires.NotNull(updateValueFactory, "updateValueFactory"); ImmutableDictionary immutableDictionary = Volatile.Read(ref location); TValue val; bool flag; do { Requires.NotNull(immutableDictionary, "location"); val = ((!immutableDictionary.TryGetValue(key, out var value)) ? addValueFactory(key) : updateValueFactory(key, value)); ImmutableDictionary immutableDictionary2 = immutableDictionary.SetItem(key, val); if (immutableDictionary == immutableDictionary2) { return value; } ImmutableDictionary immutableDictionary3 = Interlocked.CompareExchange(ref location, immutableDictionary2, immutableDictionary); flag = immutableDictionary == immutableDictionary3; immutableDictionary = immutableDictionary3; } while (!flag); return val; } public static TValue AddOrUpdate(ref ImmutableDictionary location, TKey key, TValue addValue, Func updateValueFactory) where TKey : notnull { Requires.NotNull(updateValueFactory, "updateValueFactory"); ImmutableDictionary immutableDictionary = Volatile.Read(ref location); TValue val; bool flag; do { Requires.NotNull(immutableDictionary, "location"); val = (TValue)((!immutableDictionary.TryGetValue(key, out var value)) ? ((object)addValue) : ((object)updateValueFactory(key, value))); ImmutableDictionary immutableDictionary2 = immutableDictionary.SetItem(key, val); if (immutableDictionary == immutableDictionary2) { return value; } ImmutableDictionary immutableDictionary3 = Interlocked.CompareExchange(ref location, immutableDictionary2, immutableDictionary); flag = immutableDictionary == immutableDictionary3; immutableDictionary = immutableDictionary3; } while (!flag); return val; } public static bool TryAdd(ref ImmutableDictionary location, TKey key, TValue value) where TKey : notnull { ImmutableDictionary immutableDictionary = Volatile.Read(ref location); bool flag; do { Requires.NotNull(immutableDictionary, "location"); if (immutableDictionary.ContainsKey(key)) { return false; } ImmutableDictionary value2 = immutableDictionary.Add(key, value); ImmutableDictionary immutableDictionary2 = Interlocked.CompareExchange(ref location, value2, immutableDictionary); flag = immutableDictionary == immutableDictionary2; immutableDictionary = immutableDictionary2; } while (!flag); return true; } public static bool TryUpdate(ref ImmutableDictionary location, TKey key, TValue newValue, TValue comparisonValue) where TKey : notnull { EqualityComparer @default = EqualityComparer.Default; ImmutableDictionary immutableDictionary = Volatile.Read(ref location); bool flag; do { Requires.NotNull(immutableDictionary, "location"); if (!immutableDictionary.TryGetValue(key, out var value) || !@default.Equals(value, comparisonValue)) { return false; } ImmutableDictionary value2 = immutableDictionary.SetItem(key, newValue); ImmutableDictionary immutableDictionary2 = Interlocked.CompareExchange(ref location, value2, immutableDictionary); flag = immutableDictionary == immutableDictionary2; immutableDictionary = immutableDictionary2; } while (!flag); return true; } public static bool TryRemove(ref ImmutableDictionary location, TKey key, [MaybeNullWhen(false)] out TValue value) where TKey : notnull { ImmutableDictionary immutableDictionary = Volatile.Read(ref location); bool flag; do { Requires.NotNull(immutableDictionary, "location"); if (!immutableDictionary.TryGetValue(key, out value)) { return false; } ImmutableDictionary value2 = immutableDictionary.Remove(key); ImmutableDictionary immutableDictionary2 = Interlocked.CompareExchange(ref location, value2, immutableDictionary); flag = immutableDictionary == immutableDictionary2; immutableDictionary = immutableDictionary2; } while (!flag); return true; } public static bool TryPop(ref ImmutableStack location, [MaybeNullWhen(false)] out T value) { ImmutableStack immutableStack = Volatile.Read(ref location); bool flag; do { Requires.NotNull(immutableStack, "location"); if (immutableStack.IsEmpty) { value = default(T); return false; } ImmutableStack value2 = immutableStack.Pop(out value); ImmutableStack immutableStack2 = Interlocked.CompareExchange(ref location, value2, immutableStack); flag = immutableStack == immutableStack2; immutableStack = immutableStack2; } while (!flag); return true; } public static void Push(ref ImmutableStack location, T value) { ImmutableStack immutableStack = Volatile.Read(ref location); bool flag; do { Requires.NotNull(immutableStack, "location"); ImmutableStack value2 = immutableStack.Push(value); ImmutableStack immutableStack2 = Interlocked.CompareExchange(ref location, value2, immutableStack); flag = immutableStack == immutableStack2; immutableStack = immutableStack2; } while (!flag); } public static bool TryDequeue(ref ImmutableQueue location, [MaybeNullWhen(false)] out T value) { ImmutableQueue immutableQueue = Volatile.Read(ref location); bool flag; do { Requires.NotNull(immutableQueue, "location"); if (immutableQueue.IsEmpty) { value = default(T); return false; } ImmutableQueue value2 = immutableQueue.Dequeue(out value); ImmutableQueue immutableQueue2 = Interlocked.CompareExchange(ref location, value2, immutableQueue); flag = immutableQueue == immutableQueue2; immutableQueue = immutableQueue2; } while (!flag); return true; } public static void Enqueue(ref ImmutableQueue location, T value) { ImmutableQueue immutableQueue = Volatile.Read(ref location); bool flag; do { Requires.NotNull(immutableQueue, "location"); ImmutableQueue value2 = immutableQueue.Enqueue(value); ImmutableQueue immutableQueue2 = Interlocked.CompareExchange(ref location, value2, immutableQueue); flag = immutableQueue == immutableQueue2; immutableQueue = immutableQueue2; } while (!flag); } } public static class ImmutableList { public static ImmutableList Create() { return ImmutableList.Empty; } public static ImmutableList Create(T item) { return ImmutableList.Empty.Add(item); } public static ImmutableList CreateRange(IEnumerable items) { return ImmutableList.Empty.AddRange(items); } public static ImmutableList Create(params T[] items) { Requires.NotNull(items, "items"); return Create((ReadOnlySpan)items); } public static ImmutableList Create([ParamCollection] scoped ReadOnlySpan items) { return ImmutableList.Empty.AddRange(items); } public static ImmutableList.Builder CreateBuilder() { return Create().ToBuilder(); } public static ImmutableList ToImmutableList(this IEnumerable source) { if (source is ImmutableList result) { return result; } return ImmutableList.Empty.AddRange(source); } public static ImmutableList ToImmutableList(this ImmutableList.Builder builder) { Requires.NotNull(builder, "builder"); return builder.ToImmutable(); } public static IImmutableList Replace(this IImmutableList list, T oldValue, T newValue) { Requires.NotNull(list, "list"); return list.Replace(oldValue, newValue, EqualityComparer.Default); } public static IImmutableList Remove(this IImmutableList list, T value) { Requires.NotNull(list, "list"); return list.Remove(value, EqualityComparer.Default); } public static IImmutableList RemoveRange(this IImmutableList list, IEnumerable items) { Requires.NotNull(list, "list"); return list.RemoveRange(items, EqualityComparer.Default); } public static int IndexOf(this IImmutableList list, T item) { Requires.NotNull(list, "list"); return list.IndexOf(item, 0, list.Count, EqualityComparer.Default); } public static int IndexOf(this IImmutableList list, T item, IEqualityComparer? equalityComparer) { Requires.NotNull(list, "list"); return list.IndexOf(item, 0, list.Count, equalityComparer); } public static int IndexOf(this IImmutableList list, T item, int startIndex) { Requires.NotNull(list, "list"); return list.IndexOf(item, startIndex, list.Count - startIndex, EqualityComparer.Default); } public static int IndexOf(this IImmutableList list, T item, int startIndex, int count) { Requires.NotNull(list, "list"); return list.IndexOf(item, startIndex, count, EqualityComparer.Default); } public static int LastIndexOf(this IImmutableList list, T item) { Requires.NotNull(list, "list"); if (list.Count == 0) { return -1; } return list.LastIndexOf(item, list.Count - 1, list.Count, EqualityComparer.Default); } public static int LastIndexOf(this IImmutableList list, T item, IEqualityComparer? equalityComparer) { Requires.NotNull(list, "list"); if (list.Count == 0) { return -1; } return list.LastIndexOf(item, list.Count - 1, list.Count, equalityComparer); } public static int LastIndexOf(this IImmutableList list, T item, int startIndex) { Requires.NotNull(list, "list"); if (list.Count == 0 && startIndex == 0) { return -1; } return list.LastIndexOf(item, startIndex, startIndex + 1, EqualityComparer.Default); } public static int LastIndexOf(this IImmutableList list, T item, int startIndex, int count) { Requires.NotNull(list, "list"); return list.LastIndexOf(item, startIndex, count, EqualityComparer.Default); } } [CollectionBuilder(typeof(ImmutableList), "Create")] [DebuggerDisplay("Count = {Count}")] [DebuggerTypeProxy(typeof(ImmutableEnumerableDebuggerProxy<>))] public sealed class ImmutableList : IImmutableList, IReadOnlyList, IEnumerable, IEnumerable, IReadOnlyCollection, IList, ICollection, IList, ICollection, IOrderedCollection, IImmutableListQueries, IStrongEnumerable.Enumerator> { [DebuggerDisplay("Count = {Count}")] [DebuggerTypeProxy(typeof(ImmutableListBuilderDebuggerProxy<>))] public sealed class Builder : IList, ICollection, IEnumerable, IEnumerable, IList, ICollection, IOrderedCollection, IImmutableListQueries, IReadOnlyList, IReadOnlyCollection { private Node _root = Node.EmptyNode; private ImmutableList _immutable; private int _version; private object _syncRoot; public int Count => Root.Count; bool ICollection.IsReadOnly => false; internal int Version => _version; internal Node Root { get { return _root; } private set { _version++; if (_root != value) { _root = value; _immutable = null; } } } public T this[int index] { get { return Root.ItemRef(index); } set { Root = Root.ReplaceAt(index, value); } } T IOrderedCollection.this[int index] => this[index]; bool IList.IsFixedSize => false; bool IList.IsReadOnly => false; object? IList.this[int index] { get { return this[index]; } set { this[index] = (T)value; } } [DebuggerBrowsable(DebuggerBrowsableState.Never)] bool ICollection.IsSynchronized => false; [DebuggerBrowsable(DebuggerBrowsableState.Never)] object ICollection.SyncRoot { get { if (_syncRoot == null) { Interlocked.CompareExchange(ref _syncRoot, new object(), (object)null); } return _syncRoot; } } internal Builder(ImmutableList list) { Requires.NotNull(list, "list"); _root = list._root; _immutable = list; } public ref readonly T ItemRef(int index) { return ref Root.ItemRef(index); } public int IndexOf(T item) { return Root.IndexOf(item, EqualityComparer.Default); } public void Insert(int index, T item) { Root = Root.Insert(index, item); } public void RemoveAt(int index) { Root = Root.RemoveAt(index); } public void Add(T item) { Root = Root.Add(item); } public void Clear() { Root = Node.EmptyNode; } public bool Contains(T item) { return IndexOf(item) >= 0; } public bool Remove(T item) { int num = IndexOf(item); if (num < 0) { return false; } Root = Root.RemoveAt(num); return true; } public ImmutableList.Enumerator GetEnumerator() { return Root.GetEnumerator(this); } IEnumerator IEnumerable.GetEnumerator() { return GetEnumerator(); } IEnumerator IEnumerable.GetEnumerator() { return GetEnumerator(); } public void ForEach(Action action) { Requires.NotNull(action, "action"); using Enumerator enumerator = GetEnumerator(); while (enumerator.MoveNext()) { T current = enumerator.Current; action(current); } } public void CopyTo(T[] array) { _root.CopyTo(array); } public void CopyTo(T[] array, int arrayIndex) { _root.CopyTo(array, arrayIndex); } public void CopyTo(int index, T[] array, int arrayIndex, int count) { _root.CopyTo(index, array, arrayIndex, count); } public ImmutableList GetRange(int index, int count) { Requires.Range(index >= 0, "index"); Requires.Range(count >= 0, "count"); Requires.Range(index + count <= Count, "count"); return ImmutableList.WrapNode(Node.NodeTreeFromList(this, index, count)); } public ImmutableList ConvertAll(Func converter) { Requires.NotNull(converter, "converter"); return ImmutableList.WrapNode(_root.ConvertAll(converter)); } public bool Exists(Predicate match) { return _root.Exists(match); } public T? Find(Predicate match) { return _root.Find(match); } public ImmutableList FindAll(Predicate match) { return _root.FindAll(match); } public int FindIndex(Predicate match) { return _root.FindIndex(match); } public int FindIndex(int startIndex, Predicate match) { return _root.FindIndex(startIndex, match); } public int FindIndex(int startIndex, int count, Predicate match) { return _root.FindIndex(startIndex, count, match); } public T? FindLast(Predicate match) { return _root.FindLast(match); } public int FindLastIndex(Predicate match) { return _root.FindLastIndex(match); } public int FindLastIndex(int startIndex, Predicate match) { return _root.FindLastIndex(startIndex, match); } public int FindLastIndex(int startIndex, int count, Predicate match) { return _root.FindLastIndex(startIndex, count, match); } public int IndexOf(T item, int index) { return _root.IndexOf(item, index, Count - index, EqualityComparer.Default); } public int IndexOf(T item, int index, int count) { return _root.IndexOf(item, index, count, EqualityComparer.Default); } public int IndexOf(T item, int index, int count, IEqualityComparer? equalityComparer) { return _root.IndexOf(item, index, count, equalityComparer); } public int LastIndexOf(T item) { if (Count == 0) { return -1; } return _root.LastIndexOf(item, Count - 1, Count, EqualityComparer.Default); } public int LastIndexOf(T item, int startIndex) { if (Count == 0 && startIndex == 0) { return -1; } return _root.LastIndexOf(item, startIndex, startIndex + 1, EqualityComparer.Default); } public int LastIndexOf(T item, int startIndex, int count) { return _root.LastIndexOf(item, startIndex, count, EqualityComparer.Default); } public int LastIndexOf(T item, int startIndex, int count, IEqualityComparer? equalityComparer) { return _root.LastIndexOf(item, startIndex, count, equalityComparer); } public bool TrueForAll(Predicate match) { return _root.TrueForAll(match); } public void AddRange(IEnumerable items) { Requires.NotNull(items, "items"); Root = Root.AddRange(items); } public void InsertRange(int index, IEnumerable items) { Requires.Range(index >= 0 && index <= Count, "index"); Requires.NotNull(items, "items"); Root = Root.InsertRange(index, items); } public int RemoveAll(Predicate match) { Requires.NotNull(match, "match"); int count = Count; Root = Root.RemoveAll(match); return count - Count; } public bool Remove(T item, IEqualityComparer? equalityComparer) { int num = IndexOf(item, 0, Count, equalityComparer); if (num >= 0) { RemoveAt(num); return true; } return false; } public void RemoveRange(int index, int count) { Requires.Range(index >= 0 && index <= Count, "index"); Requires.Range(count >= 0 && index <= Count - count, "count"); int num = count; while (num-- > 0) { RemoveAt(index); } } public void RemoveRange(IEnumerable items, IEqualityComparer? equalityComparer) { Requires.NotNull(items, "items"); foreach (T item in items.GetEnumerableDisposable()) { int num = Root.IndexOf(item, equalityComparer); if (num >= 0) { RemoveAt(num); } } } public void RemoveRange(IEnumerable items) { RemoveRange(items, EqualityComparer.Default); } public void Replace(T oldValue, T newValue) { Replace(oldValue, newValue, EqualityComparer.Default); } public void Replace(T oldValue, T newValue, IEqualityComparer? equalityComparer) { int num = IndexOf(oldValue, 0, Count, equalityComparer); if (num < 0) { throw new ArgumentException(System.SR.CannotFindOldValue, "oldValue"); } Root = Root.ReplaceAt(num, newValue); } public void Reverse() { Reverse(0, Count); } public void Reverse(int index, int count) { Requires.Range(index >= 0, "index"); Requires.Range(count >= 0, "count"); Requires.Range(index + count <= Count, "count"); Root = Root.Reverse(index, count); } public void Sort() { Root = Root.Sort(); } public void Sort(Comparison comparison) { Requires.NotNull(comparison, "comparison"); Root = Root.Sort(comparison); } public void Sort(IComparer? comparer) { Root = Root.Sort(comparer); } public void Sort(int index, int count, IComparer? comparer) { Requires.Range(index >= 0, "index"); Requires.Range(count >= 0, "count"); Requires.Range(index + count <= Count, "count"); Root = Root.Sort(index, count, comparer); } public int BinarySearch(T item) { return BinarySearch(item, null); } public int BinarySearch(T item, IComparer? comparer) { return BinarySearch(0, Count, item, comparer); } public int BinarySearch(int index, int count, T item, IComparer? comparer) { return Root.BinarySearch(index, count, item, comparer); } public ImmutableList ToImmutable() { return _immutable ?? (_immutable = ImmutableList.WrapNode(Root)); } int IList.Add(object value) { Add((T)value); return Count - 1; } void IList.Clear() { Clear(); } bool IList.Contains(object value) { if (ImmutableList.IsCompatibleObject(value)) { return Contains((T)value); } return false; } int IList.IndexOf(object value) { if (ImmutableList.IsCompatibleObject(value)) { return IndexOf((T)value); } return -1; } void IList.Insert(int index, object value) { Insert(index, (T)value); } void IList.Remove(object value) { if (ImmutableList.IsCompatibleObject(value)) { Remove((T)value); } } void ICollection.CopyTo(Array array, int arrayIndex) { Root.CopyTo(array, arrayIndex); } } [EditorBrowsable(EditorBrowsableState.Advanced)] public struct Enumerator : IEnumerator, IEnumerator, IDisposable, ISecurePooledObjectUser, IStrongEnumerator { private readonly Builder _builder; private readonly int _poolUserId; private readonly int _startIndex; private readonly int _count; private int _remainingCount; private readonly bool _reversed; private Node _root; private SecurePooledObject>> _stack; private Node _current; private int _enumeratingBuilderVersion; int ISecurePooledObjectUser.PoolUserId => _poolUserId; public T Current { get { ThrowIfDisposed(); if (_current != null) { return _current.Value; } throw new InvalidOperationException(); } } object? IEnumerator.Current => Current; internal Enumerator(Node root, Builder? builder = null, int startIndex = -1, int count = -1, bool reversed = false) { Requires.NotNull(root, "root"); Requires.Range(startIndex >= -1, "startIndex"); Requires.Range(count >= -1, "count"); Requires.Argument(reversed || count == -1 || ((startIndex != -1) ? startIndex : 0) + count <= root.Count); Requires.Argument(!reversed || count == -1 || ((startIndex == -1) ? (root.Count - 1) : startIndex) - count + 1 >= 0); _root = root; _builder = builder; _current = null; _startIndex = ((startIndex >= 0) ? startIndex : (reversed ? (root.Count - 1) : 0)); _count = ((count == -1) ? root.Count : count); _remainingCount = _count; _reversed = reversed; _enumeratingBuilderVersion = builder?.Version ?? (-1); _poolUserId = SecureObjectPool.NewId(); _stack = null; if (_count > 0) { if (!SecureObjectPool>, Enumerator>.TryTake(this, out _stack)) { _stack = SecureObjectPool>, Enumerator>.PrepNew(this, new Stack>(root.Height)); } ResetStack(); } } public void Dispose() { _root = null; _current = null; if (_stack != null && _stack.TryUse(ref this, out var value)) { value.ClearFastWhenEmpty(); SecureObjectPool>, Enumerator>.TryAdd(this, _stack); } _stack = null; } public bool MoveNext() { ThrowIfDisposed(); ThrowIfChanged(); if (_stack != null) { Stack> stack = _stack.Use(ref this); if (_remainingCount > 0 && stack.Count > 0) { PushNext(NextBranch(_current = stack.Pop().Value)); _remainingCount--; return true; } } _current = null; return false; } public void Reset() { ThrowIfDisposed(); _enumeratingBuilderVersion = ((_builder != null) ? _builder.Version : (-1)); _remainingCount = _count; if (_stack != null) { ResetStack(); } } private void ResetStack() { Stack> stack = _stack.Use(ref this); stack.ClearFastWhenEmpty(); Node node = _root; int num = (_reversed ? (_root.Count - _startIndex - 1) : _startIndex); while (!node.IsEmpty && num != PreviousBranch(node).Count) { if (num < PreviousBranch(node).Count) { stack.Push(new RefAsValueType(node)); node = PreviousBranch(node); } else { num -= PreviousBranch(node).Count + 1; node = NextBranch(node); } } if (!node.IsEmpty) { stack.Push(new RefAsValueType(node)); } } private Node NextBranch(Node node) { if (!_reversed) { return node.Right; } return node.Left; } private Node PreviousBranch(Node node) { if (!_reversed) { return node.Left; } return node.Right; } private void ThrowIfDisposed() { if (_root == null || (_stack != null && !_stack.IsOwned(ref this))) { Requires.FailObjectDisposed(this); } } private void ThrowIfChanged() { if (_builder != null && _builder.Version != _enumeratingBuilderVersion) { throw new InvalidOperationException(System.SR.CollectionModifiedDuringEnumeration); } } private void PushNext(Node node) { Requires.NotNull(node, "node"); if (!node.IsEmpty) { Stack> stack = _stack.Use(ref this); while (!node.IsEmpty) { stack.Push(new RefAsValueType(node)); node = PreviousBranch(node); } } } } [DebuggerDisplay("{_key}")] internal sealed class Node : IBinaryTree, IBinaryTree, IEnumerable, IEnumerable { internal static readonly Node EmptyNode = new Node(); private T _key; private bool _frozen; private byte _height; private int _count; private Node _left; private Node _right; public bool IsEmpty => _left == null; public int Height => _height; public Node? Left => _left; IBinaryTree? IBinaryTree.Left => _left; public Node? Right => _right; IBinaryTree? IBinaryTree.Right => _right; IBinaryTree? IBinaryTree.Left => _left; IBinaryTree? IBinaryTree.Right => _right; public T Value => _key; public int Count => _count; internal T Key => _key; internal T this[int index] { get { Requires.Range(index >= 0 && index < Count, "index"); if (index < _left._count) { return _left[index]; } if (index > _left._count) { return _right[index - _left._count - 1]; } return _key; } } private int BalanceFactor => _right._height - _left._height; private bool IsRightHeavy => BalanceFactor >= 2; private bool IsLeftHeavy => BalanceFactor <= -2; private bool IsBalanced => (uint)(BalanceFactor + 1) <= 2u; private Node() { _frozen = true; } private Node(T key, Node left, Node right, bool frozen = false) { Requires.NotNull(left, "left"); Requires.NotNull(right, "right"); _key = key; _left = left; _right = right; _height = ParentHeight(left, right); _count = ParentCount(left, right); _frozen = frozen; } internal ref readonly T ItemRef(int index) { Requires.Range(index >= 0 && index < Count, "index"); return ref ItemRefUnchecked(index); } private ref readonly T ItemRefUnchecked(int index) { if (index < _left._count) { return ref _left.ItemRefUnchecked(index); } if (index > _left._count) { return ref _right.ItemRefUnchecked(index - _left._count - 1); } return ref _key; } public Enumerator GetEnumerator() { return new Enumerator(this); } [ExcludeFromCodeCoverage] IEnumerator IEnumerable.GetEnumerator() { return GetEnumerator(); } [ExcludeFromCodeCoverage] IEnumerator IEnumerable.GetEnumerator() { return GetEnumerator(); } internal Enumerator GetEnumerator(Builder builder) { return new Enumerator(this, builder); } internal static Node NodeTreeFromList(IOrderedCollection items, int start, int length) { Requires.NotNull(items, "items"); Requires.Range(start >= 0, "start"); Requires.Range(length >= 0, "length"); if (length == 0) { return EmptyNode; } int num = (length - 1) / 2; int num2 = length - 1 - num; Node left = NodeTreeFromList(items, start, num2); Node right = NodeTreeFromList(items, start + num2 + 1, num); return new Node(items[start + num2], left, right, frozen: true); } internal static Node NodeTreeFromList(ReadOnlySpan items) { if (items.IsEmpty) { return EmptyNode; } int num = (items.Length - 1) / 2; int num2 = items.Length - 1 - num; Node left = NodeTreeFromList(items.Slice(0, num2)); Node right = NodeTreeFromList(items.Slice(num2 + 1)); return new Node(items[num2], left, right, frozen: true); } internal Node Add(T key) { if (IsEmpty) { return CreateLeaf(key); } Node right = _right.Add(key); Node node = MutateRight(right); if (!node.IsBalanced) { return node.BalanceRight(); } return node; } internal Node Insert(int index, T key) { Requires.Range(index >= 0 && index <= Count, "index"); if (IsEmpty) { return CreateLeaf(key); } if (index <= _left._count) { Node left = _left.Insert(index, key); Node node = MutateLeft(left); if (!node.IsBalanced) { return node.BalanceLeft(); } return node; } Node right = _right.Insert(index - _left._count - 1, key); Node node2 = MutateRight(right); if (!node2.IsBalanced) { return node2.BalanceRight(); } return node2; } internal Node AddRange(IEnumerable keys) { Requires.NotNull(keys, "keys"); if (IsEmpty) { return CreateRange(keys); } Node right = _right.AddRange(keys); return MutateRight(right).BalanceMany(); } internal Node AddRange(ReadOnlySpan keys) { if (IsEmpty) { return NodeTreeFromList(keys); } Node right = _right.AddRange(keys); return MutateRight(right).BalanceMany(); } internal Node InsertRange(int index, IEnumerable keys) { Requires.Range(index >= 0 && index <= Count, "index"); Requires.NotNull(keys, "keys"); if (IsEmpty) { return CreateRange(keys); } Node node; if (index <= _left._count) { Node left = _left.InsertRange(index, keys); node = MutateLeft(left); } else { Node right = _right.InsertRange(index - _left._count - 1, keys); node = MutateRight(right); } return node.BalanceMany(); } internal Node RemoveAt(int index) { Requires.Range(index >= 0 && index < Count, "index"); Node node; if (index == _left._count) { if (_right.IsEmpty && _left.IsEmpty) { node = EmptyNode; } else if (_right.IsEmpty && !_left.IsEmpty) { node = _left; } else if (!_right.IsEmpty && _left.IsEmpty) { node = _right; } else { Node node2 = _right; while (!node2._left.IsEmpty) { node2 = node2._left; } Node right = _right.RemoveAt(0); node = node2.MutateBoth(_left, right); } } else if (index < _left._count) { Node left = _left.RemoveAt(index); node = MutateLeft(left); } else { Node right2 = _right.RemoveAt(index - _left._count - 1); node = MutateRight(right2); } if (!node.IsEmpty && !node.IsBalanced) { return node.Balance(); } return node; } internal Node RemoveAll(Predicate match) { Requires.NotNull(match, "match"); Node node = this; Enumerator enumerator = new Enumerator(node); try { int num = 0; while (enumerator.MoveNext()) { if (match(enumerator.Current)) { node = node.RemoveAt(num); enumerator.Dispose(); enumerator = new Enumerator(node, null, num); } else { num++; } } return node; } finally { enumerator.Dispose(); } } internal Node ReplaceAt(int index, T value) { Requires.Range(index >= 0 && index < Count, "index"); if (index == _left._count) { return MutateKey(value); } if (index < _left._count) { Node left = _left.ReplaceAt(index, value); return MutateLeft(left); } Node right = _right.ReplaceAt(index - _left._count - 1, value); return MutateRight(right); } internal Node Reverse() { return Reverse(0, Count); } internal Node Reverse(int index, int count) { Requires.Range(index >= 0, "index"); Requires.Range(count >= 0, "count"); Requires.Range(index + count <= Count, "index"); Node node = this; int num = index; int num2 = index + count - 1; while (num < num2) { T value = node.ItemRef(num); T value2 = node.ItemRef(num2); node = node.ReplaceAt(num2, value).ReplaceAt(num, value2); num++; num2--; } return node; } internal Node Sort() { return Sort(Comparer.Default); } internal Node Sort(Comparison comparison) { Requires.NotNull(comparison, "comparison"); T[] array = new T[Count]; CopyTo(array); Array.Sort(array, comparison); return NodeTreeFromList(array.AsOrderedCollection(), 0, Count); } internal Node Sort(IComparer? comparer) { return Sort(0, Count, comparer); } internal Node Sort(int index, int count, IComparer? comparer) { Requires.Range(index >= 0, "index"); Requires.Range(count >= 0, "count"); Requires.Argument(index + count <= Count); T[] array = new T[Count]; CopyTo(array); Array.Sort(array, index, count, comparer); return NodeTreeFromList(array.AsOrderedCollection(), 0, Count); } internal int BinarySearch(int index, int count, T item, IComparer? comparer) { Requires.Range(index >= 0, "index"); Requires.Range(count >= 0, "count"); if (comparer == null) { comparer = Comparer.Default; } if (IsEmpty || count <= 0) { return ~index; } int count2 = _left.Count; if (index + count <= count2) { return _left.BinarySearch(index, count, item, comparer); } if (index > count2) { int num = _right.BinarySearch(index - count2 - 1, count, item, comparer); int num2 = count2 + 1; if (num >= 0) { return num + num2; } return num - num2; } int num3 = comparer.Compare(item, _key); if (num3 == 0) { return count2; } if (num3 > 0) { int num4 = count - (count2 - index) - 1; int num5 = ((num4 < 0) ? (-1) : _right.BinarySearch(0, num4, item, comparer)); int num6 = count2 + 1; if (num5 >= 0) { return num5 + num6; } return num5 - num6; } if (index == count2) { return ~index; } return _left.BinarySearch(index, count, item, comparer); } internal int IndexOf(T item, IEqualityComparer? equalityComparer) { return IndexOf(item, 0, Count, equalityComparer); } internal bool Contains(T item, IEqualityComparer equalityComparer) { return Contains(this, item, equalityComparer); } internal int IndexOf(T item, int index, int count, IEqualityComparer? equalityComparer) { Requires.Range(index >= 0, "index"); Requires.Range(count >= 0, "count"); Requires.Range(count <= Count, "count"); Requires.Range(index + count <= Count, "count"); if (equalityComparer == null) { equalityComparer = EqualityComparer.Default; } using (Enumerator enumerator = new Enumerator(this, null, index, count)) { while (enumerator.MoveNext()) { if (equalityComparer.Equals(item, enumerator.Current)) { return index; } index++; } } return -1; } internal int LastIndexOf(T item, int index, int count, IEqualityComparer? equalityComparer) { Requires.Range(index >= 0, "index"); Requires.Range(count >= 0 && count <= Count, "count"); Requires.Argument(index - count + 1 >= 0); if (equalityComparer == null) { equalityComparer = EqualityComparer.Default; } using (Enumerator enumerator = new Enumerator(this, null, index, count, reversed: true)) { while (enumerator.MoveNext()) { if (equalityComparer.Equals(item, enumerator.Current)) { return index; } index--; } } return -1; } internal void CopyTo(T[] array) { Requires.NotNull(array, "array"); Requires.Range(array.Length >= Count, "array"); int num = 0; using Enumerator enumerator = GetEnumerator(); while (enumerator.MoveNext()) { T current = enumerator.Current; array[num++] = current; } } internal void CopyTo(T[] array, int arrayIndex) { Requires.NotNull(array, "array"); Requires.Range(arrayIndex >= 0, "arrayIndex"); Requires.Range(array.Length >= arrayIndex + Count, "arrayIndex"); using Enumerator enumerator = GetEnumerator(); while (enumerator.MoveNext()) { T current = enumerator.Current; array[arrayIndex++] = current; } } internal void CopyTo(int index, T[] array, int arrayIndex, int count) { Requires.NotNull(array, "array"); Requires.Range(index >= 0, "index"); Requires.Range(count >= 0, "count"); Requires.Range(index + count <= Count, "count"); Requires.Range(arrayIndex >= 0, "arrayIndex"); Requires.Range(arrayIndex + count <= array.Length, "arrayIndex"); using Enumerator enumerator = new Enumerator(this, null, index, count); while (enumerator.MoveNext()) { array[arrayIndex++] = enumerator.Current; } } internal void CopyTo(Array array, int arrayIndex) { Requires.NotNull(array, "array"); Requires.Range(arrayIndex >= 0, "arrayIndex"); Requires.Range(array.Length >= arrayIndex + Count, "arrayIndex"); using Enumerator enumerator = GetEnumerator(); while (enumerator.MoveNext()) { T current = enumerator.Current; array.SetValue(current, arrayIndex++); } } internal ImmutableList.Node ConvertAll(Func converter) { ImmutableList.Node emptyNode = ImmutableList.Node.EmptyNode; if (IsEmpty) { return emptyNode; } return emptyNode.AddRange(this.Select(converter)); } internal bool TrueForAll(Predicate match) { Requires.NotNull(match, "match"); using (Enumerator enumerator = GetEnumerator()) { while (enumerator.MoveNext()) { T current = enumerator.Current; if (!match(current)) { return false; } } } return true; } internal bool Exists(Predicate match) { Requires.NotNull(match, "match"); using (Enumerator enumerator = GetEnumerator()) { while (enumerator.MoveNext()) { T current = enumerator.Current; if (match(current)) { return true; } } } return false; } internal T? Find(Predicate match) { Requires.NotNull(match, "match"); using (Enumerator enumerator = GetEnumerator()) { while (enumerator.MoveNext()) { T current = enumerator.Current; if (match(current)) { return current; } } } return default(T); } internal ImmutableList FindAll(Predicate match) { Requires.NotNull(match, "match"); if (IsEmpty) { return ImmutableList.Empty; } List list = null; using (Enumerator enumerator = GetEnumerator()) { while (enumerator.MoveNext()) { T current = enumerator.Current; if (match(current)) { if (list == null) { list = new List(); } list.Add(current); } } } if (list == null) { return ImmutableList.Empty; } return ImmutableList.CreateRange(list); } internal int FindIndex(Predicate match) { Requires.NotNull(match, "match"); return FindIndex(0, _count, match); } internal int FindIndex(int startIndex, Predicate match) { Requires.NotNull(match, "match"); Requires.Range(startIndex >= 0 && startIndex <= Count, "startIndex"); return FindIndex(startIndex, Count - startIndex, match); } internal int FindIndex(int startIndex, int count, Predicate match) { Requires.NotNull(match, "match"); Requires.Range(startIndex >= 0, "startIndex"); Requires.Range(count >= 0, "count"); Requires.Range(startIndex <= Count - count, "count"); using (Enumerator enumerator = new Enumerator(this, null, startIndex, count)) { int num = startIndex; while (enumerator.MoveNext()) { if (match(enumerator.Current)) { return num; } num++; } } return -1; } internal T? FindLast(Predicate match) { Requires.NotNull(match, "match"); using (Enumerator enumerator = new Enumerator(this, null, -1, -1, reversed: true)) { while (enumerator.MoveNext()) { if (match(enumerator.Current)) { return enumerator.Current; } } } return default(T); } internal int FindLastIndex(Predicate match) { Requires.NotNull(match, "match"); if (!IsEmpty) { return FindLastIndex(Count - 1, Count, match); } return -1; } internal int FindLastIndex(int startIndex, Predicate match) { Requires.NotNull(match, "match"); Requires.Range(startIndex >= 0, "startIndex"); Requires.Range(startIndex == 0 || startIndex < Count, "startIndex"); if (!IsEmpty) { return FindLastIndex(startIndex, startIndex + 1, match); } return -1; } internal int FindLastIndex(int startIndex, int count, Predicate match) { Requires.NotNull(match, "match"); Requires.Range(startIndex >= 0, "startIndex"); Requires.Range(count <= Count, "count"); Requires.Range(startIndex - count + 1 >= 0, "startIndex"); using (Enumerator enumerator = new Enumerator(this, null, startIndex, count, reversed: true)) { int num = startIndex; while (enumerator.MoveNext()) { if (match(enumerator.Current)) { return num; } num--; } } return -1; } internal void Freeze() { if (!_frozen) { _left.Freeze(); _right.Freeze(); _frozen = true; } } private Node RotateLeft() { return _right.MutateLeft(MutateRight(_right._left)); } private Node RotateRight() { return _left.MutateRight(MutateLeft(_left._right)); } private Node DoubleLeft() { Node right = _right; Node left = right._left; return left.MutateBoth(MutateRight(left._left), right.MutateLeft(left._right)); } private Node DoubleRight() { Node left = _left; Node right = left._right; return right.MutateBoth(left.MutateRight(right._left), MutateLeft(right._right)); } private Node Balance() { if (!IsLeftHeavy) { return BalanceRight(); } return BalanceLeft(); } private Node BalanceLeft() { if (_left.BalanceFactor <= 0) { return RotateRight(); } return DoubleRight(); } private Node BalanceRight() { if (_right.BalanceFactor >= 0) { return RotateLeft(); } return DoubleLeft(); } private Node BalanceMany() { Node node = this; while (!node.IsBalanced) { if (node.IsRightHeavy) { node = node.BalanceRight(); node.MutateLeft(node._left.BalanceMany()); } else { node = node.BalanceLeft(); node.MutateRight(node._right.BalanceMany()); } } return node; } private Node MutateBoth(Node left, Node right) { Requires.NotNull(left, "left"); Requires.NotNull(right, "right"); if (_frozen) { return new Node(_key, left, right); } _left = left; _right = right; _height = ParentHeight(left, right); _count = ParentCount(left, right); return this; } private Node MutateLeft(Node left) { Requires.NotNull(left, "left"); if (_frozen) { return new Node(_key, left, _right); } _left = left; _height = ParentHeight(left, _right); _count = ParentCount(left, _right); return this; } private Node MutateRight(Node right) { Requires.NotNull(right, "right"); if (_frozen) { return new Node(_key, _left, right); } _right = right; _height = ParentHeight(_left, right); _count = ParentCount(_left, right); return this; } [MethodImpl(MethodImplOptions.AggressiveInlining)] private static byte ParentHeight(Node left, Node right) { return checked((byte)(1 + Math.Max(left._height, right._height))); } private static int ParentCount(Node left, Node right) { return 1 + left._count + right._count; } private Node MutateKey(T key) { if (_frozen) { return new Node(key, _left, _right); } _key = key; return this; } private static Node CreateRange(IEnumerable keys) { if (ImmutableList.TryCastToImmutableList(keys, out ImmutableList other)) { return other._root; } IOrderedCollection orderedCollection = keys.AsOrderedCollection(); return NodeTreeFromList(orderedCollection, 0, orderedCollection.Count); } private static Node CreateLeaf(T key) { return new Node(key, EmptyNode, EmptyNode); } private static bool Contains(Node node, T value, IEqualityComparer equalityComparer) { if (!node.IsEmpty) { if (!equalityComparer.Equals(value, node._key) && !Contains(node._left, value, equalityComparer)) { return Contains(node._right, value, equalityComparer); } return true; } return false; } } public static readonly ImmutableList Empty = new ImmutableList(); private readonly Node _root; [DebuggerBrowsable(DebuggerBrowsableState.Never)] public bool IsEmpty => _root.IsEmpty; public int Count => _root.Count; [DebuggerBrowsable(DebuggerBrowsableState.Never)] object ICollection.SyncRoot => this; [DebuggerBrowsable(DebuggerBrowsableState.Never)] bool ICollection.IsSynchronized => true; public T this[int index] => _root.ItemRef(index); T IOrderedCollection.this[int index] => this[index]; T IList.this[int index] { get { return this[index]; } set { throw new NotSupportedException(); } } bool ICollection.IsReadOnly => true; bool IList.IsFixedSize => true; bool IList.IsReadOnly => true; object? IList.this[int index] { get { return this[index]; } set { throw new NotSupportedException(); } } internal Node Root => _root; internal ImmutableList() { _root = Node.EmptyNode; } private ImmutableList(Node root) { Requires.NotNull(root, "root"); root.Freeze(); _root = root; } public ImmutableList Clear() { return Empty; } public int BinarySearch(T item) { return BinarySearch(item, null); } public int BinarySearch(T item, IComparer? comparer) { return BinarySearch(0, Count, item, comparer); } public int BinarySearch(int index, int count, T item, IComparer? comparer) { return _root.BinarySearch(index, count, item, comparer); } IImmutableList IImmutableList.Clear() { return Clear(); } public ref readonly T ItemRef(int index) { return ref _root.ItemRef(index); } public Builder ToBuilder() { return new Builder(this); } public ImmutableList Add(T value) { Node root = _root.Add(value); return Wrap(root); } public ImmutableList AddRange(IEnumerable items) { Requires.NotNull(items, "items"); if (IsEmpty) { return CreateRange(items); } Node root = _root.AddRange(items); return Wrap(root); } internal ImmutableList AddRange(ReadOnlySpan items) { if (IsEmpty) { if (items.IsEmpty) { return Empty; } return new ImmutableList(Node.NodeTreeFromList(items)); } if (items.IsEmpty) { return this; } return Wrap(_root.AddRange(items)); } public ImmutableList Insert(int index, T item) { Requires.Range(index >= 0 && index <= Count, "index"); return Wrap(_root.Insert(index, item)); } public ImmutableList InsertRange(int index, IEnumerable items) { Requires.Range(index >= 0 && index <= Count, "index"); Requires.NotNull(items, "items"); Node root = _root.InsertRange(index, items); return Wrap(root); } public ImmutableList Remove(T value) { return Remove(value, EqualityComparer.Default); } public ImmutableList Remove(T value, IEqualityComparer? equalityComparer) { int num = this.IndexOf(value, equalityComparer); if (num >= 0) { return RemoveAt(num); } return this; } public ImmutableList RemoveRange(int index, int count) { Requires.Range(index >= 0 && index <= Count, "index"); Requires.Range(count >= 0 && index <= Count - count, "count"); Node node = _root; int num = count; while (num-- > 0) { node = node.RemoveAt(index); } return Wrap(node); } public ImmutableList RemoveRange(IEnumerable items) { return RemoveRange(items, EqualityComparer.Default); } public ImmutableList RemoveRange(IEnumerable items, IEqualityComparer? equalityComparer) { Requires.NotNull(items, "items"); if (IsEmpty) { return this; } Node node = _root; foreach (T item in items.GetEnumerableDisposable()) { int num = node.IndexOf(item, equalityComparer); if (num >= 0) { node = node.RemoveAt(num); } } return Wrap(node); } public ImmutableList RemoveAt(int index) { Requires.Range(index >= 0 && index < Count, "index"); Node root = _root.RemoveAt(index); return Wrap(root); } public ImmutableList RemoveAll(Predicate match) { Requires.NotNull(match, "match"); return Wrap(_root.RemoveAll(match)); } public ImmutableList SetItem(int index, T value) { return Wrap(_root.ReplaceAt(index, value)); } public ImmutableList Replace(T oldValue, T newValue) { return Replace(oldValue, newValue, EqualityComparer.Default); } public ImmutableList Replace(T oldValue, T newValue, IEqualityComparer? equalityComparer) { int num = this.IndexOf(oldValue, equalityComparer); if (num < 0) { throw new ArgumentException(System.SR.CannotFindOldValue, "oldValue"); } return SetItem(num, newValue); } public ImmutableList Reverse() { return Wrap(_root.Reverse()); } public ImmutableList Reverse(int index, int count) { return Wrap(_root.Reverse(index, count)); } public ImmutableList Sort() { return Wrap(_root.Sort()); } public ImmutableList Sort(Comparison comparison) { Requires.NotNull(comparison, "comparison"); return Wrap(_root.Sort(comparison)); } public ImmutableList Sort(IComparer? comparer) { return Wrap(_root.Sort(comparer)); } public ImmutableList Sort(int index, int count, IComparer? comparer) { Requires.Range(index >= 0, "index"); Requires.Range(count >= 0, "count"); Requires.Range(index + count <= Count, "count"); return Wrap(_root.Sort(index, count, comparer)); } public void ForEach(Action action) { Requires.NotNull(action, "action"); using Enumerator enumerator = GetEnumerator(); while (enumerator.MoveNext()) { T current = enumerator.Current; action(current); } } public void CopyTo(T[] array) { _root.CopyTo(array); } public void CopyTo(T[] array, int arrayIndex) { _root.CopyTo(array, arrayIndex); } public void CopyTo(int index, T[] array, int arrayIndex, int count) { _root.CopyTo(index, array, arrayIndex, count); } public ImmutableList GetRange(int index, int count) { Requires.Range(index >= 0, "index"); Requires.Range(count >= 0, "count"); Requires.Range(index + count <= Count, "count"); return Wrap(Node.NodeTreeFromList(this, index, count)); } public ImmutableList ConvertAll(Func converter) { Requires.NotNull(converter, "converter"); return ImmutableList.WrapNode(_root.ConvertAll(converter)); } public bool Exists(Predicate match) { return _root.Exists(match); } public T? Find(Predicate match) { return _root.Find(match); } public ImmutableList FindAll(Predicate match) { return _root.FindAll(match); } public int FindIndex(Predicate match) { return _root.FindIndex(match); } public int FindIndex(int startIndex, Predicate match) { return _root.FindIndex(startIndex, match); } public int FindIndex(int startIndex, int count, Predicate match) { return _root.FindIndex(startIndex, count, match); } public T? FindLast(Predicate match) { return _root.FindLast(match); } public int FindLastIndex(Predicate match) { return _root.FindLastIndex(match); } public int FindLastIndex(int startIndex, Predicate match) { return _root.FindLastIndex(startIndex, match); } public int FindLastIndex(int startIndex, int count, Predicate match) { return _root.FindLastIndex(startIndex, count, match); } public int IndexOf(T item, int index, int count, IEqualityComparer? equalityComparer) { return _root.IndexOf(item, index, count, equalityComparer); } public int LastIndexOf(T item, int index, int count, IEqualityComparer? equalityComparer) { return _root.LastIndexOf(item, index, count, equalityComparer); } public bool TrueForAll(Predicate match) { return _root.TrueForAll(match); } public bool Contains(T value) { return _root.Contains(value, EqualityComparer.Default); } public int IndexOf(T value) { return this.IndexOf(value, EqualityComparer.Default); } IImmutableList IImmutableList.Add(T value) { return Add(value); } IImmutableList IImmutableList.AddRange(IEnumerable items) { return AddRange(items); } IImmutableList IImmutableList.Insert(int index, T item) { return Insert(index, item); } IImmutableList IImmutableList.InsertRange(int index, IEnumerable items) { return InsertRange(index, items); } IImmutableList IImmutableList.Remove(T value, IEqualityComparer equalityComparer) { return Remove(value, equalityComparer); } IImmutableList IImmutableList.RemoveAll(Predicate match) { return RemoveAll(match); } IImmutableList IImmutableList.RemoveRange(IEnumerable items, IEqualityComparer equalityComparer) { return RemoveRange(items, equalityComparer); } IImmutableList IImmutableList.RemoveRange(int index, int count) { return RemoveRange(index, count); } IImmutableList IImmutableList.RemoveAt(int index) { return RemoveAt(index); } IImmutableList IImmutableList.SetItem(int index, T value) { return SetItem(index, value); } IImmutableList IImmutableList.Replace(T oldValue, T newValue, IEqualityComparer equalityComparer) { return Replace(oldValue, newValue, equalityComparer); } IEnumerator IEnumerable.GetEnumerator() { if (!IsEmpty) { return GetEnumerator(); } return Enumerable.Empty().GetEnumerator(); } IEnumerator IEnumerable.GetEnumerator() { return GetEnumerator(); } void IList.Insert(int index, T item) { throw new NotSupportedException(); } void IList.RemoveAt(int index) { throw new NotSupportedException(); } void ICollection.Add(T item) { throw new NotSupportedException(); } void ICollection.Clear() { throw new NotSupportedException(); } bool ICollection.Remove(T item) { throw new NotSupportedException(); } void ICollection.CopyTo(Array array, int arrayIndex) { _root.CopyTo(array, arrayIndex); } int IList.Add(object value) { throw new NotSupportedException(); } void IList.RemoveAt(int index) { throw new NotSupportedException(); } void IList.Clear() { throw new NotSupportedException(); } bool IList.Contains(object value) { if (IsCompatibleObject(value)) { return Contains((T)value); } return false; } int IList.IndexOf(object value) { if (!IsCompatibleObject(value)) { return -1; } return IndexOf((T)value); } void IList.Insert(int index, object value) { throw new NotSupportedException(); } void IList.Remove(object value) { throw new NotSupportedException(); } public Enumerator GetEnumerator() { return new Enumerator(_root); } private static ImmutableList WrapNode(Node root) { if (!root.IsEmpty) { return new ImmutableList(root); } return Empty; } private static bool TryCastToImmutableList(IEnumerable sequence, [NotNullWhen(true)] out ImmutableList other) { other = sequence as ImmutableList; if (other != null) { return true; } if (sequence is Builder builder) { other = builder.ToImmutable(); return true; } return false; } private static bool IsCompatibleObject(object value) { if (!(value is T)) { if (default(T) == null) { return value == null; } return false; } return true; } private ImmutableList Wrap(Node root) { if (root != _root) { if (!root.IsEmpty) { return new ImmutableList(root); } return Clear(); } return this; } private static ImmutableList CreateRange(IEnumerable items) { if (TryCastToImmutableList(items, out var other)) { return other; } IOrderedCollection orderedCollection = items.AsOrderedCollection(); if (orderedCollection.Count == 0) { return Empty; } return new ImmutableList(Node.NodeTreeFromList(orderedCollection, 0, orderedCollection.Count)); } } internal sealed class ImmutableListBuilderDebuggerProxy { private readonly ImmutableList.Builder _list; private T[] _cachedContents; [DebuggerBrowsable(DebuggerBrowsableState.RootHidden)] public T[] Contents => _cachedContents ?? (_cachedContents = _list.ToArray(_list.Count)); public ImmutableListBuilderDebuggerProxy(ImmutableList.Builder builder) { Requires.NotNull(builder, "builder"); _list = builder; } } public static class ImmutableQueue { public static ImmutableQueue Create() { return ImmutableQueue.Empty; } public static ImmutableQueue Create(T item) { return ImmutableQueue.Empty.Enqueue(item); } public static ImmutableQueue CreateRange(IEnumerable items) { Requires.NotNull(items, "items"); if (items is T[] items2) { return Create(items2); } using IEnumerator enumerator = items.GetEnumerator(); if (!enumerator.MoveNext()) { return ImmutableQueue.Empty; } ImmutableStack forwards = ImmutableStack.Create(enumerator.Current); ImmutableStack immutableStack = ImmutableStack.Empty; while (enumerator.MoveNext()) { immutableStack = immutableStack.Push(enumerator.Current); } return new ImmutableQueue(forwards, immutableStack); } public static ImmutableQueue Create(params T[] items) { Requires.NotNull(items, "items"); return Create((ReadOnlySpan)items); } public static ImmutableQueue Create([ParamCollection] scoped ReadOnlySpan items) { if (items.IsEmpty) { return ImmutableQueue.Empty; } ImmutableStack immutableStack = ImmutableStack.Empty; for (int num = items.Length - 1; num >= 0; num--) { immutableStack = immutableStack.Push(items[num]); } return new ImmutableQueue(immutableStack, ImmutableStack.Empty); } public static IImmutableQueue Dequeue(this IImmutableQueue queue, out T value) { Requires.NotNull(queue, "queue"); value = queue.Peek(); return queue.Dequeue(); } } [CollectionBuilder(typeof(ImmutableQueue), "Create")] [DebuggerDisplay("IsEmpty = {IsEmpty}")] [DebuggerTypeProxy(typeof(ImmutableEnumerableDebuggerProxy<>))] public sealed class ImmutableQueue : IImmutableQueue, IEnumerable, IEnumerable { [EditorBrowsable(EditorBrowsableState.Advanced)] public struct Enumerator { private readonly ImmutableQueue _originalQueue; private ImmutableStack _remainingForwardsStack; private ImmutableStack _remainingBackwardsStack; public T Current { get { if (_remainingForwardsStack == null) { throw new InvalidOperationException(); } if (!_remainingForwardsStack.IsEmpty) { return _remainingForwardsStack.Peek(); } if (!_remainingBackwardsStack.IsEmpty) { return _remainingBackwardsStack.Peek(); } throw new InvalidOperationException(); } } internal Enumerator(ImmutableQueue queue) { _originalQueue = queue; _remainingForwardsStack = null; _remainingBackwardsStack = null; } public bool MoveNext() { if (_remainingForwardsStack == null) { _remainingForwardsStack = _originalQueue._forwards; _remainingBackwardsStack = _originalQueue.BackwardsReversed; } else if (!_remainingForwardsStack.IsEmpty) { _remainingForwardsStack = _remainingForwardsStack.Pop(); } else if (!_remainingBackwardsStack.IsEmpty) { _remainingBackwardsStack = _remainingBackwardsStack.Pop(); } if (_remainingForwardsStack.IsEmpty) { return !_remainingBackwardsStack.IsEmpty; } return true; } } private sealed class EnumeratorObject : IEnumerator, IEnumerator, IDisposable { private readonly ImmutableQueue _originalQueue; private ImmutableStack _remainingForwardsStack; private ImmutableStack _remainingBackwardsStack; private bool _disposed; public T Current { get { ThrowIfDisposed(); if (_remainingForwardsStack == null) { throw new InvalidOperationException(); } if (!_remainingForwardsStack.IsEmpty) { return _remainingForwardsStack.Peek(); } if (!_remainingBackwardsStack.IsEmpty) { return _remainingBackwardsStack.Peek(); } throw new InvalidOperationException(); } } object IEnumerator.Current => Current; internal EnumeratorObject(ImmutableQueue queue) { _originalQueue = queue; } public bool MoveNext() { ThrowIfDisposed(); if (_remainingForwardsStack == null) { _remainingForwardsStack = _originalQueue._forwards; _remainingBackwardsStack = _originalQueue.BackwardsReversed; } else if (!_remainingForwardsStack.IsEmpty) { _remainingForwardsStack = _remainingForwardsStack.Pop(); } else if (!_remainingBackwardsStack.IsEmpty) { _remainingBackwardsStack = _remainingBackwardsStack.Pop(); } if (_remainingForwardsStack.IsEmpty) { return !_remainingBackwardsStack.IsEmpty; } return true; } public void Reset() { ThrowIfDisposed(); _remainingBackwardsStack = null; _remainingForwardsStack = null; } public void Dispose() { _disposed = true; } private void ThrowIfDisposed() { if (_disposed) { Requires.FailObjectDisposed(this); } } } private static readonly ImmutableQueue s_EmptyField = new ImmutableQueue(ImmutableStack.Empty, ImmutableStack.Empty); private readonly ImmutableStack _backwards; private readonly ImmutableStack _forwards; private ImmutableStack _backwardsReversed; public bool IsEmpty => _forwards.IsEmpty; public static ImmutableQueue Empty => s_EmptyField; private ImmutableStack BackwardsReversed { get { if (_backwardsReversed == null) { _backwardsReversed = _backwards.Reverse(); } return _backwardsReversed; } } internal ImmutableQueue(ImmutableStack forwards, ImmutableStack backwards) { _forwards = forwards; _backwards = backwards; } public ImmutableQueue Clear() { return Empty; } IImmutableQueue IImmutableQueue.Clear() { return Clear(); } public T Peek() { if (IsEmpty) { throw new InvalidOperationException(System.SR.InvalidEmptyOperation); } return _forwards.Peek(); } public ref readonly T PeekRef() { if (IsEmpty) { throw new InvalidOperationException(System.SR.InvalidEmptyOperation); } return ref _forwards.PeekRef(); } public ImmutableQueue Enqueue(T value) { if (IsEmpty) { return new ImmutableQueue(ImmutableStack.Create(value), ImmutableStack.Empty); } return new ImmutableQueue(_forwards, _backwards.Push(value)); } IImmutableQueue IImmutableQueue.Enqueue(T value) { return Enqueue(value); } public ImmutableQueue Dequeue() { if (IsEmpty) { throw new InvalidOperationException(System.SR.InvalidEmptyOperation); } ImmutableStack immutableStack = _forwards.Pop(); if (!immutableStack.IsEmpty) { return new ImmutableQueue(immutableStack, _backwards); } if (_backwards.IsEmpty) { return Empty; } return new ImmutableQueue(BackwardsReversed, ImmutableStack.Empty); } public ImmutableQueue Dequeue(out T value) { value = Peek(); return Dequeue(); } IImmutableQueue IImmutableQueue.Dequeue() { return Dequeue(); } public Enumerator GetEnumerator() { return new Enumerator(this); } IEnumerator IEnumerable.GetEnumerator() { if (!IsEmpty) { return new EnumeratorObject(this); } return Enumerable.Empty().GetEnumerator(); } IEnumerator IEnumerable.GetEnumerator() { return new EnumeratorObject(this); } } public static class ImmutableSortedDictionary { public static ImmutableSortedDictionary Create() where TKey : notnull { return ImmutableSortedDictionary.Empty; } public static ImmutableSortedDictionary Create(IComparer? keyComparer) where TKey : notnull { return ImmutableSortedDictionary.Empty.WithComparers(keyComparer); } public static ImmutableSortedDictionary Create(IComparer? keyComparer, IEqualityComparer? valueComparer) where TKey : notnull { return ImmutableSortedDictionary.Empty.WithComparers(keyComparer, valueComparer); } public static ImmutableSortedDictionary CreateRange(IEnumerable> items) where TKey : notnull { return ImmutableSortedDictionary.Empty.AddRange(items); } public static ImmutableSortedDictionary CreateRange(IComparer? keyComparer, IEnumerable> items) where TKey : notnull { return ImmutableSortedDictionary.Empty.WithComparers(keyComparer).AddRange(items); } public static ImmutableSortedDictionary CreateRange(IComparer? keyComparer, IEqualityComparer? valueComparer, IEnumerable> items) where TKey : notnull { return ImmutableSortedDictionary.Empty.WithComparers(keyComparer, valueComparer).AddRange(items); } public static ImmutableSortedDictionary.Builder CreateBuilder() where TKey : notnull { return Create().ToBuilder(); } public static ImmutableSortedDictionary.Builder CreateBuilder(IComparer? keyComparer) where TKey : notnull { return Create(keyComparer).ToBuilder(); } public static ImmutableSortedDictionary.Builder CreateBuilder(IComparer? keyComparer, IEqualityComparer? valueComparer) where TKey : notnull { return Create(keyComparer, valueComparer).ToBuilder(); } public static ImmutableSortedDictionary ToImmutableSortedDictionary(this IEnumerable source, Func keySelector, Func elementSelector, IComparer? keyComparer, IEqualityComparer? valueComparer) where TKey : notnull { Func keySelector2 = keySelector; Func elementSelector2 = elementSelector; Requires.NotNull(source, "source"); Requires.NotNull(keySelector2, "keySelector"); Requires.NotNull(elementSelector2, "elementSelector"); return ImmutableSortedDictionary.Empty.WithComparers(keyComparer, valueComparer).AddRange(source.Select((TSource element) => new KeyValuePair(keySelector2(element), elementSelector2(element)))); } public static ImmutableSortedDictionary ToImmutableSortedDictionary(this ImmutableSortedDictionary.Builder builder) where TKey : notnull { Requires.NotNull(builder, "builder"); return builder.ToImmutable(); } public static ImmutableSortedDictionary ToImmutableSortedDictionary(this IEnumerable source, Func keySelector, Func elementSelector, IComparer? keyComparer) where TKey : notnull { return source.ToImmutableSortedDictionary(keySelector, elementSelector, keyComparer, null); } public static ImmutableSortedDictionary ToImmutableSortedDictionary(this IEnumerable source, Func keySelector, Func elementSelector) where TKey : notnull { return source.ToImmutableSortedDictionary(keySelector, elementSelector, null, null); } public static ImmutableSortedDictionary ToImmutableSortedDictionary(this IEnumerable> source, IComparer? keyComparer, IEqualityComparer? valueComparer) where TKey : notnull { Requires.NotNull(source, "source"); if (source is ImmutableSortedDictionary immutableSortedDictionary) { return immutableSortedDictionary.WithComparers(keyComparer, valueComparer); } return ImmutableSortedDictionary.Empty.WithComparers(keyComparer, valueComparer).AddRange(source); } public static ImmutableSortedDictionary ToImmutableSortedDictionary(this IEnumerable> source, IComparer? keyComparer) where TKey : notnull { return source.ToImmutableSortedDictionary(keyComparer, null); } public static ImmutableSortedDictionary ToImmutableSortedDictionary(this IEnumerable> source) where TKey : notnull { return source.ToImmutableSortedDictionary(null, null); } } [DebuggerDisplay("Count = {Count}")] [DebuggerTypeProxy(typeof(ImmutableDictionaryDebuggerProxy<, >))] public sealed class ImmutableSortedDictionary : IImmutableDictionary, IReadOnlyDictionary, IEnumerable>, IEnumerable, IReadOnlyCollection>, ISortKeyCollection, IDictionary, ICollection>, IDictionary, ICollection where TKey : notnull { [DebuggerDisplay("Count = {Count}")] [DebuggerTypeProxy(typeof(System.Collections.Generic.IDictionaryDebugView<, >))] public sealed class Builder : IDictionary, ICollection>, IEnumerable>, IEnumerable, IReadOnlyDictionary, IReadOnlyCollection>, IDictionary, ICollection { private Node _root = Node.EmptyNode; private IComparer _keyComparer = Comparer.Default; private IEqualityComparer _valueComparer = EqualityComparer.Default; private int _count; private ImmutableSortedDictionary _immutable; private int _version; private object _syncRoot; ICollection IDictionary.Keys => Root.Keys.ToArray(Count); public IEnumerable Keys => Root.Keys; ICollection IDictionary.Values => Root.Values.ToArray(Count); public IEnumerable Values => Root.Values; public int Count => _count; bool ICollection>.IsReadOnly => false; internal int Version => _version; private Node Root { get { return _root; } set { _version++; if (_root != value) { _root = value; _immutable = null; } } } public TValue this[TKey key] { get { if (!TryGetValue(key, out var value)) { ThrowHelper.ThrowKeyNotFoundException(key); } return value; } set { Root = _root.SetItem(key, value, _keyComparer, _valueComparer, out var replacedExistingValue, out var mutated); if (mutated && !replacedExistingValue) { _count++; } } } bool IDictionary.IsFixedSize => false; bool IDictionary.IsReadOnly => false; ICollection IDictionary.Keys => Keys.ToArray(Count); ICollection IDictionary.Values => Values.ToArray(Count); [DebuggerBrowsable(DebuggerBrowsableState.Never)] object ICollection.SyncRoot { get { if (_syncRoot == null) { Interlocked.CompareExchange(ref _syncRoot, new object(), (object)null); } return _syncRoot; } } [DebuggerBrowsable(DebuggerBrowsableState.Never)] bool ICollection.IsSynchronized => false; public IComparer KeyComparer { get { return _keyComparer; } set { Requires.NotNull(value, "value"); if (value == _keyComparer) { return; } Node node = Node.EmptyNode; int num = 0; using (Enumerator enumerator = GetEnumerator()) { while (enumerator.MoveNext()) { KeyValuePair current = enumerator.Current; node = node.Add(current.Key, current.Value, value, _valueComparer, out var mutated); if (mutated) { num++; } } } _keyComparer = value; Root = node; _count = num; } } public IEqualityComparer ValueComparer { get { return _valueComparer; } set { Requires.NotNull(value, "value"); if (value != _valueComparer) { _valueComparer = value; _immutable = null; } } } object? IDictionary.this[object key] { get { return this[(TKey)key]; } set { this[(TKey)key] = (TValue)value; } } internal Builder(ImmutableSortedDictionary map) { Requires.NotNull(map, "map"); _root = map._root; _keyComparer = map.KeyComparer; _valueComparer = map.ValueComparer; _count = map.Count; _immutable = map; } public ref readonly TValue ValueRef(TKey key) { Requires.NotNullAllowStructs(key, "key"); return ref _root.ValueRef(key, _keyComparer); } void IDictionary.Add(object key, object value) { Add((TKey)key, (TValue)value); } bool IDictionary.Contains(object key) { return ContainsKey((TKey)key); } IDictionaryEnumerator IDictionary.GetEnumerator() { return new DictionaryEnumerator(GetEnumerator()); } void IDictionary.Remove(object key) { Remove((TKey)key); } void ICollection.CopyTo(Array array, int index) { Root.CopyTo(array, index, Count); } public void Add(TKey key, TValue value) { Root = Root.Add(key, value, _keyComparer, _valueComparer, out var mutated); if (mutated) { _count++; } } public bool ContainsKey(TKey key) { return Root.ContainsKey(key, _keyComparer); } public bool Remove(TKey key) { Root = Root.Remove(key, _keyComparer, out var mutated); if (mutated) { _count--; } return mutated; } public bool TryGetValue(TKey key, [MaybeNullWhen(false)] out TValue value) { return Root.TryGetValue(key, _keyComparer, out value); } public bool TryGetKey(TKey equalKey, out TKey actualKey) { Requires.NotNullAllowStructs(equalKey, "equalKey"); return Root.TryGetKey(equalKey, _keyComparer, out actualKey); } public void Add(KeyValuePair item) { Add(item.Key, item.Value); } public void Clear() { Root = Node.EmptyNode; _count = 0; } public bool Contains(KeyValuePair item) { return Root.Contains(item, _keyComparer, _valueComparer); } void ICollection>.CopyTo(KeyValuePair[] array, int arrayIndex) { Root.CopyTo(array, arrayIndex, Count); } public bool Remove(KeyValuePair item) { if (Contains(item)) { return Remove(item.Key); } return false; } public ImmutableSortedDictionary.Enumerator GetEnumerator() { return Root.GetEnumerator(this); } IEnumerator> IEnumerable>.GetEnumerator() { return GetEnumerator(); } IEnumerator IEnumerable.GetEnumerator() { return GetEnumerator(); } public bool ContainsValue(TValue value) { return _root.ContainsValue(value, _valueComparer); } public void AddRange(IEnumerable> items) { Requires.NotNull(items, "items"); foreach (KeyValuePair item in items) { Add(item); } } public void RemoveRange(IEnumerable keys) { Requires.NotNull(keys, "keys"); foreach (TKey key in keys) { Remove(key); } } public TValue? GetValueOrDefault(TKey key) { return GetValueOrDefault(key, default(TValue)); } public TValue GetValueOrDefault(TKey key, TValue defaultValue) { Requires.NotNullAllowStructs(key, "key"); if (TryGetValue(key, out var value)) { return value; } return defaultValue; } public ImmutableSortedDictionary ToImmutable() { return _immutable ?? (_immutable = ImmutableSortedDictionary.Wrap(Root, _count, _keyComparer, _valueComparer)); } } [EditorBrowsable(EditorBrowsableState.Advanced)] public struct Enumerator : IEnumerator>, IEnumerator, IDisposable, ISecurePooledObjectUser { private readonly Builder _builder; private readonly int _poolUserId; private Node _root; private SecurePooledObject>> _stack; private Node _current; private int _enumeratingBuilderVersion; public KeyValuePair Current { get { ThrowIfDisposed(); if (_current != null) { return _current.Value; } throw new InvalidOperationException(); } } int ISecurePooledObjectUser.PoolUserId => _poolUserId; object IEnumerator.Current => Current; internal Enumerator(Node root, Builder? builder = null) { Requires.NotNull(root, "root"); _root = root; _builder = builder; _current = null; _enumeratingBuilderVersion = builder?.Version ?? (-1); _poolUserId = SecureObjectPool.NewId(); _stack = null; if (!_root.IsEmpty) { if (!SecureObjectPool>, Enumerator>.TryTake(this, out _stack)) { _stack = SecureObjectPool>, Enumerator>.PrepNew(this, new Stack>(root.Height)); } PushLeft(_root); } } public void Dispose() { _root = null; _current = null; if (_stack != null && _stack.TryUse(ref this, out var value)) { value.ClearFastWhenEmpty(); SecureObjectPool>, Enumerator>.TryAdd(this, _stack); } _stack = null; } public bool MoveNext() { ThrowIfDisposed(); ThrowIfChanged(); if (_stack != null) { Stack> stack = _stack.Use(ref this); if (stack.Count > 0) { PushLeft((_current = stack.Pop().Value).Right); return true; } } _current = null; return false; } public void Reset() { ThrowIfDisposed(); _enumeratingBuilderVersion = ((_builder != null) ? _builder.Version : (-1)); _current = null; if (_stack != null) { _stack.Use(ref this).ClearFastWhenEmpty(); PushLeft(_root); } } internal void ThrowIfDisposed() { if (_root == null || (_stack != null && !_stack.IsOwned(ref this))) { Requires.FailObjectDisposed(this); } } private void ThrowIfChanged() { if (_builder != null && _builder.Version != _enumeratingBuilderVersion) { throw new InvalidOperationException(System.SR.CollectionModifiedDuringEnumeration); } } private void PushLeft(Node node) { Requires.NotNull(node, "node"); Stack> stack = _stack.Use(ref this); while (!node.IsEmpty) { stack.Push(new RefAsValueType(node)); node = node.Left; } } } [DebuggerDisplay("{_key} = {_value}")] internal sealed class Node : IBinaryTree>, IBinaryTree, IEnumerable>, IEnumerable { internal static readonly Node EmptyNode = new Node(); private readonly TKey _key; private readonly TValue _value; private bool _frozen; private byte _height; private Node _left; private Node _right; public bool IsEmpty => _left == null; IBinaryTree>? IBinaryTree>.Left => _left; IBinaryTree>? IBinaryTree>.Right => _right; public int Height => _height; public Node? Left => _left; IBinaryTree? IBinaryTree.Left => _left; public Node? Right => _right; IBinaryTree? IBinaryTree.Right => _right; public KeyValuePair Value => new KeyValuePair(_key, _value); int IBinaryTree.Count { get { throw new NotSupportedException(); } } internal IEnumerable Keys => this.Select((KeyValuePair p) => p.Key); internal IEnumerable Values => this.Select((KeyValuePair p) => p.Value); private Node() { _frozen = true; } private Node(TKey key, TValue value, Node left, Node right, bool frozen = false) { Requires.NotNullAllowStructs(key, "key"); Requires.NotNull(left, "left"); Requires.NotNull(right, "right"); _key = key; _value = value; _left = left; _right = right; _height = checked((byte)(1 + Math.Max(left._height, right._height))); _frozen = frozen; } public Enumerator GetEnumerator() { return new Enumerator(this); } IEnumerator> IEnumerable>.GetEnumerator() { return GetEnumerator(); } IEnumerator IEnumerable.GetEnumerator() { return GetEnumerator(); } internal Enumerator GetEnumerator(Builder builder) { return new Enumerator(this, builder); } internal void CopyTo(KeyValuePair[] array, int arrayIndex, int dictionarySize) { Requires.NotNull(array, "array"); Requires.Range(arrayIndex >= 0, "arrayIndex"); Requires.Range(array.Length >= arrayIndex + dictionarySize, "arrayIndex"); using Enumerator enumerator = GetEnumerator(); while (enumerator.MoveNext()) { KeyValuePair current = enumerator.Current; array[arrayIndex++] = current; } } internal void CopyTo(Array array, int arrayIndex, int dictionarySize) { Requires.NotNull(array, "array"); Requires.Range(arrayIndex >= 0, "arrayIndex"); Requires.Range(array.Length >= arrayIndex + dictionarySize, "arrayIndex"); using Enumerator enumerator = GetEnumerator(); while (enumerator.MoveNext()) { KeyValuePair current = enumerator.Current; array.SetValue(new DictionaryEntry(current.Key, current.Value), arrayIndex++); } } internal static Node NodeTreeFromSortedDictionary(SortedDictionary dictionary) { Requires.NotNull(dictionary, "dictionary"); IOrderedCollection> orderedCollection = dictionary.AsOrderedCollection(); return NodeTreeFromList(orderedCollection, 0, orderedCollection.Count); } internal Node Add(TKey key, TValue value, IComparer keyComparer, IEqualityComparer valueComparer, out bool mutated) { Requires.NotNullAllowStructs(key, "key"); Requires.NotNull(keyComparer, "keyComparer"); Requires.NotNull(valueComparer, "valueComparer"); bool replacedExistingValue; return SetOrAdd(key, value, keyComparer, valueComparer, overwriteExistingValue: false, out replacedExistingValue, out mutated); } internal Node SetItem(TKey key, TValue value, IComparer keyComparer, IEqualityComparer valueComparer, out bool replacedExistingValue, out bool mutated) { Requires.NotNullAllowStructs(key, "key"); Requires.NotNull(keyComparer, "keyComparer"); Requires.NotNull(valueComparer, "valueComparer"); return SetOrAdd(key, value, keyComparer, valueComparer, overwriteExistingValue: true, out replacedExistingValue, out mutated); } internal Node Remove(TKey key, IComparer keyComparer, out bool mutated) { Requires.NotNullAllowStructs(key, "key"); Requires.NotNull(keyComparer, "keyComparer"); return RemoveRecursive(key, keyComparer, out mutated); } internal ref readonly TValue ValueRef(TKey key, IComparer keyComparer) { Requires.NotNullAllowStructs(key, "key"); Requires.NotNull(keyComparer, "keyComparer"); Node node = Search(key, keyComparer); if (node.IsEmpty) { ThrowHelper.ThrowKeyNotFoundException(key); } return ref node._value; } internal bool TryGetValue(TKey key, IComparer keyComparer, [MaybeNullWhen(false)] out TValue value) { Requires.NotNullAllowStructs(key, "key"); Requires.NotNull(keyComparer, "keyComparer"); Node node = Search(key, keyComparer); if (node.IsEmpty) { value = default(TValue); return false; } value = node._value; return true; } internal bool TryGetKey(TKey equalKey, IComparer keyComparer, out TKey actualKey) { Requires.NotNullAllowStructs(equalKey, "equalKey"); Requires.NotNull(keyComparer, "keyComparer"); Node node = Search(equalKey, keyComparer); if (node.IsEmpty) { actualKey = equalKey; return false; } actualKey = node._key; return true; } internal bool ContainsKey(TKey key, IComparer keyComparer) { Requires.NotNullAllowStructs(key, "key"); Requires.NotNull(keyComparer, "keyComparer"); return !Search(key, keyComparer).IsEmpty; } internal bool ContainsValue(TValue value, IEqualityComparer valueComparer) { Requires.NotNull(valueComparer, "valueComparer"); using (Enumerator enumerator = GetEnumerator()) { while (enumerator.MoveNext()) { if (valueComparer.Equals(value, enumerator.Current.Value)) { return true; } } } return false; } internal bool Contains(KeyValuePair pair, IComparer keyComparer, IEqualityComparer valueComparer) { Requires.NotNullAllowStructs(pair.Key, "Key"); Requires.NotNull(keyComparer, "keyComparer"); Requires.NotNull(valueComparer, "valueComparer"); Node node = Search(pair.Key, keyComparer); if (node.IsEmpty) { return false; } return valueComparer.Equals(node._value, pair.Value); } internal void Freeze() { if (!_frozen) { _left.Freeze(); _right.Freeze(); _frozen = true; } } private static Node RotateLeft(Node tree) { Requires.NotNull(tree, "tree"); if (tree._right.IsEmpty) { return tree; } Node right = tree._right; return right.Mutate(tree.Mutate(null, right._left)); } private static Node RotateRight(Node tree) { Requires.NotNull(tree, "tree"); if (tree._left.IsEmpty) { return tree; } Node left = tree._left; return left.Mutate(null, tree.Mutate(left._right)); } private static Node DoubleLeft(Node tree) { Requires.NotNull(tree, "tree"); if (tree._right.IsEmpty) { return tree; } return RotateLeft(tree.Mutate(null, RotateRight(tree._right))); } private static Node DoubleRight(Node tree) { Requires.NotNull(tree, "tree"); if (tree._left.IsEmpty) { return tree; } return RotateRight(tree.Mutate(RotateLeft(tree._left))); } private static int Balance(Node tree) { Requires.NotNull(tree, "tree"); return tree._right._height - tree._left._height; } private static bool IsRightHeavy(Node tree) { Requires.NotNull(tree, "tree"); return Balance(tree) >= 2; } private static bool IsLeftHeavy(Node tree) { Requires.NotNull(tree, "tree"); return Balance(tree) <= -2; } private static Node MakeBalanced(Node tree) { Requires.NotNull(tree, "tree"); if (IsRightHeavy(tree)) { if (Balance(tree._right) >= 0) { return RotateLeft(tree); } return DoubleLeft(tree); } if (IsLeftHeavy(tree)) { if (Balance(tree._left) <= 0) { return RotateRight(tree); } return DoubleRight(tree); } return tree; } private static Node NodeTreeFromList(IOrderedCollection> items, int start, int length) { Requires.NotNull(items, "items"); Requires.Range(start >= 0, "start"); Requires.Range(length >= 0, "length"); if (length == 0) { return EmptyNode; } int num = (length - 1) / 2; int num2 = length - 1 - num; Node left = NodeTreeFromList(items, start, num2); Node right = NodeTreeFromList(items, start + num2 + 1, num); KeyValuePair keyValuePair = items[start + num2]; return new Node(keyValuePair.Key, keyValuePair.Value, left, right, frozen: true); } private Node SetOrAdd(TKey key, TValue value, IComparer keyComparer, IEqualityComparer valueComparer, bool overwriteExistingValue, out bool replacedExistingValue, out bool mutated) { replacedExistingValue = false; if (IsEmpty) { mutated = true; return new Node(key, value, this, this); } Node node = this; int num = keyComparer.Compare(key, _key); if (num > 0) { Node right = _right.SetOrAdd(key, value, keyComparer, valueComparer, overwriteExistingValue, out replacedExistingValue, out mutated); if (mutated) { node = Mutate(null, right); } } else if (num < 0) { Node left = _left.SetOrAdd(key, value, keyComparer, valueComparer, overwriteExistingValue, out replacedExistingValue, out mutated); if (mutated) { node = Mutate(left); } } else { if (valueComparer.Equals(_value, value)) { mutated = false; return this; } if (!overwriteExistingValue) { throw new ArgumentException(System.SR.Format(System.SR.DuplicateKey, key)); } mutated = true; replacedExistingValue = true; node = new Node(key, value, _left, _right); } if (!mutated) { return node; } return MakeBalanced(node); } private Node RemoveRecursive(TKey key, IComparer keyComparer, out bool mutated) { if (IsEmpty) { mutated = false; return this; } Node node = this; int num = keyComparer.Compare(key, _key); if (num == 0) { mutated = true; if (_right.IsEmpty && _left.IsEmpty) { node = EmptyNode; } else if (_right.IsEmpty && !_left.IsEmpty) { node = _left; } else if (!_right.IsEmpty && _left.IsEmpty) { node = _right; } else { Node node2 = _right; while (!node2._left.IsEmpty) { node2 = node2._left; } bool mutated2; Node right = _right.Remove(node2._key, keyComparer, out mutated2); node = node2.Mutate(_left, right); } } else if (num < 0) { Node left = _left.Remove(key, keyComparer, out mutated); if (mutated) { node = Mutate(left); } } else { Node right2 = _right.Remove(key, keyComparer, out mutated); if (mutated) { node = Mutate(null, right2); } } if (!node.IsEmpty) { return MakeBalanced(node); } return node; } private Node Mutate(Node left = null, Node right = null) { if (_frozen) { return new Node(_key, _value, left ?? _left, right ?? _right); } if (left != null) { _left = left; } if (right != null) { _right = right; } _height = checked((byte)(1 + Math.Max(_left._height, _right._height))); return this; } private Node Search(TKey key, IComparer keyComparer) { if (IsEmpty) { return this; } int num = keyComparer.Compare(key, _key); if (num == 0) { return this; } if (num > 0) { return _right.Search(key, keyComparer); } return _left.Search(key, keyComparer); } } public static readonly ImmutableSortedDictionary Empty = new ImmutableSortedDictionary(); private readonly Node _root; private readonly int _count; private readonly IComparer _keyComparer; private readonly IEqualityComparer _valueComparer; public IEqualityComparer ValueComparer => _valueComparer; public bool IsEmpty => _root.IsEmpty; public int Count => _count; public IEnumerable Keys => _root.Keys; public IEnumerable Values => _root.Values; ICollection IDictionary.Keys => new KeysCollectionAccessor(this); ICollection IDictionary.Values => new ValuesCollectionAccessor(this); bool ICollection>.IsReadOnly => true; public IComparer KeyComparer => _keyComparer; internal Node Root => _root; public TValue this[TKey key] { get { Requires.NotNullAllowStructs(key, "key"); if (!TryGetValue(key, out var value)) { ThrowHelper.ThrowKeyNotFoundException(key); } return value; } } TValue IDictionary.this[TKey key] { get { return this[key]; } set { throw new NotSupportedException(); } } bool IDictionary.IsFixedSize => true; bool IDictionary.IsReadOnly => true; ICollection IDictionary.Keys => new KeysCollectionAccessor(this); ICollection IDictionary.Values => new ValuesCollectionAccessor(this); object? IDictionary.this[object key] { get { return this[(TKey)key]; } set { throw new NotSupportedException(); } } [DebuggerBrowsable(DebuggerBrowsableState.Never)] object ICollection.SyncRoot => this; [DebuggerBrowsable(DebuggerBrowsableState.Never)] bool ICollection.IsSynchronized => true; internal ImmutableSortedDictionary(IComparer? keyComparer = null, IEqualityComparer? valueComparer = null) { _keyComparer = keyComparer ?? Comparer.Default; _valueComparer = valueComparer ?? EqualityComparer.Default; _root = Node.EmptyNode; } private ImmutableSortedDictionary(Node root, int count, IComparer keyComparer, IEqualityComparer valueComparer) { Requires.NotNull(root, "root"); Requires.Range(count >= 0, "count"); Requires.NotNull(keyComparer, "keyComparer"); Requires.NotNull(valueComparer, "valueComparer"); root.Freeze(); _root = root; _count = count; _keyComparer = keyComparer; _valueComparer = valueComparer; } public ImmutableSortedDictionary Clear() { if (!_root.IsEmpty) { return Empty.WithComparers(_keyComparer, _valueComparer); } return this; } IImmutableDictionary IImmutableDictionary.Clear() { return Clear(); } public ref readonly TValue ValueRef(TKey key) { Requires.NotNullAllowStructs(key, "key"); return ref _root.ValueRef(key, _keyComparer); } public Builder ToBuilder() { return new Builder(this); } public ImmutableSortedDictionary Add(TKey key, TValue value) { Requires.NotNullAllowStructs(key, "key"); bool mutated; Node root = _root.Add(key, value, _keyComparer, _valueComparer, out mutated); return Wrap(root, _count + 1); } public ImmutableSortedDictionary SetItem(TKey key, TValue value) { Requires.NotNullAllowStructs(key, "key"); bool replacedExistingValue; bool mutated; Node root = _root.SetItem(key, value, _keyComparer, _valueComparer, out replacedExistingValue, out mutated); return Wrap(root, replacedExistingValue ? _count : (_count + 1)); } public ImmutableSortedDictionary SetItems(IEnumerable> items) { Requires.NotNull(items, "items"); return AddRange(items, overwriteOnCollision: true, avoidToSortedMap: false); } public ImmutableSortedDictionary AddRange(IEnumerable> items) { Requires.NotNull(items, "items"); return AddRange(items, overwriteOnCollision: false, avoidToSortedMap: false); } public ImmutableSortedDictionary Remove(TKey value) { Requires.NotNullAllowStructs(value, "value"); bool mutated; Node root = _root.Remove(value, _keyComparer, out mutated); return Wrap(root, _count - 1); } public ImmutableSortedDictionary RemoveRange(IEnumerable keys) { Requires.NotNull(keys, "keys"); Node node = _root; int num = _count; foreach (TKey key in keys) { bool mutated; Node node2 = node.Remove(key, _keyComparer, out mutated); if (mutated) { node = node2; num--; } } return Wrap(node, num); } public ImmutableSortedDictionary WithComparers(IComparer? keyComparer, IEqualityComparer? valueComparer) { if (keyComparer == null) { keyComparer = Comparer.Default; } if (valueComparer == null) { valueComparer = EqualityComparer.Default; } if (keyComparer == _keyComparer) { if (valueComparer == _valueComparer) { return this; } return new ImmutableSortedDictionary(_root, _count, _keyComparer, valueComparer); } return new ImmutableSortedDictionary(Node.EmptyNode, 0, keyComparer, valueComparer).AddRange(this, overwriteOnCollision: false, avoidToSortedMap: true); } public ImmutableSortedDictionary WithComparers(IComparer? keyComparer) { return WithComparers(keyComparer, _valueComparer); } public bool ContainsValue(TValue value) { return _root.ContainsValue(value, _valueComparer); } IImmutableDictionary IImmutableDictionary.Add(TKey key, TValue value) { return Add(key, value); } IImmutableDictionary IImmutableDictionary.SetItem(TKey key, TValue value) { return SetItem(key, value); } IImmutableDictionary IImmutableDictionary.SetItems(IEnumerable> items) { return SetItems(items); } IImmutableDictionary IImmutableDictionary.AddRange(IEnumerable> pairs) { return AddRange(pairs); } IImmutableDictionary IImmutableDictionary.RemoveRange(IEnumerable keys) { return RemoveRange(keys); } IImmutableDictionary IImmutableDictionary.Remove(TKey key) { return Remove(key); } public bool ContainsKey(TKey key) { Requires.NotNullAllowStructs(key, "key"); return _root.ContainsKey(key, _keyComparer); } public bool Contains(KeyValuePair pair) { return _root.Contains(pair, _keyComparer, _valueComparer); } public bool TryGetValue(TKey key, [MaybeNullWhen(false)] out TValue value) { Requires.NotNullAllowStructs(key, "key"); return _root.TryGetValue(key, _keyComparer, out value); } public bool TryGetKey(TKey equalKey, out TKey actualKey) { Requires.NotNullAllowStructs(equalKey, "equalKey"); return _root.TryGetKey(equalKey, _keyComparer, out actualKey); } void IDictionary.Add(TKey key, TValue value) { throw new NotSupportedException(); } bool IDictionary.Remove(TKey key) { throw new NotSupportedException(); } void ICollection>.Add(KeyValuePair item) { throw new NotSupportedException(); } void ICollection>.Clear() { throw new NotSupportedException(); } bool ICollection>.Remove(KeyValuePair item) { throw new NotSupportedException(); } void ICollection>.CopyTo(KeyValuePair[] array, int arrayIndex) { Requires.NotNull(array, "array"); Requires.Range(arrayIndex >= 0, "arrayIndex"); Requires.Range(array.Length >= arrayIndex + Count, "arrayIndex"); using Enumerator enumerator = GetEnumerator(); while (enumerator.MoveNext()) { KeyValuePair current = enumerator.Current; array[arrayIndex++] = current; } } void IDictionary.Add(object key, object value) { throw new NotSupportedException(); } bool IDictionary.Contains(object key) { return ContainsKey((TKey)key); } IDictionaryEnumerator IDictionary.GetEnumerator() { return new DictionaryEnumerator(GetEnumerator()); } void IDictionary.Remove(object key) { throw new NotSupportedException(); } void IDictionary.Clear() { throw new NotSupportedException(); } void ICollection.CopyTo(Array array, int index) { _root.CopyTo(array, index, Count); } IEnumerator> IEnumerable>.GetEnumerator() { if (!IsEmpty) { return GetEnumerator(); } return Enumerable.Empty>().GetEnumerator(); } IEnumerator IEnumerable.GetEnumerator() { return GetEnumerator(); } public Enumerator GetEnumerator() { return _root.GetEnumerator(); } private static ImmutableSortedDictionary Wrap(Node root, int count, IComparer keyComparer, IEqualityComparer valueComparer) { if (!root.IsEmpty) { return new ImmutableSortedDictionary(root, count, keyComparer, valueComparer); } return Empty.WithComparers(keyComparer, valueComparer); } private static bool TryCastToImmutableMap(IEnumerable> sequence, [NotNullWhen(true)] out ImmutableSortedDictionary other) { other = sequence as ImmutableSortedDictionary; if (other != null) { return true; } if (sequence is Builder builder) { other = builder.ToImmutable(); return true; } return false; } private ImmutableSortedDictionary AddRange(IEnumerable> items, bool overwriteOnCollision, bool avoidToSortedMap) { Requires.NotNull(items, "items"); if (IsEmpty && !avoidToSortedMap) { return FillFromEmpty(items, overwriteOnCollision); } Node node = _root; int num = _count; foreach (KeyValuePair item in items) { bool replacedExistingValue = false; bool mutated; Node node2 = (overwriteOnCollision ? node.SetItem(item.Key, item.Value, _keyComparer, _valueComparer, out replacedExistingValue, out mutated) : node.Add(item.Key, item.Value, _keyComparer, _valueComparer, out mutated)); if (mutated) { node = node2; if (!replacedExistingValue) { num++; } } } return Wrap(node, num); } private ImmutableSortedDictionary Wrap(Node root, int adjustedCountIfDifferentRoot) { if (_root != root) { if (!root.IsEmpty) { return new ImmutableSortedDictionary(root, adjustedCountIfDifferentRoot, _keyComparer, _valueComparer); } return Clear(); } return this; } private ImmutableSortedDictionary FillFromEmpty(IEnumerable> items, bool overwriteOnCollision) { Requires.NotNull(items, "items"); if (TryCastToImmutableMap(items, out var other)) { return other.WithComparers(KeyComparer, ValueComparer); } SortedDictionary sortedDictionary; if (items is IDictionary dictionary) { sortedDictionary = new SortedDictionary(dictionary, KeyComparer); } else { sortedDictionary = new SortedDictionary(KeyComparer); foreach (KeyValuePair item in items) { TValue value; if (overwriteOnCollision) { sortedDictionary[item.Key] = item.Value; } else if (sortedDictionary.TryGetValue(item.Key, out value)) { if (!_valueComparer.Equals(value, item.Value)) { throw new ArgumentException(System.SR.Format(System.SR.DuplicateKey, item.Key)); } } else { sortedDictionary.Add(item.Key, item.Value); } } } if (sortedDictionary.Count == 0) { return this; } return new ImmutableSortedDictionary(Node.NodeTreeFromSortedDictionary(sortedDictionary), sortedDictionary.Count, KeyComparer, ValueComparer); } } public static class ImmutableSortedSet { public static ImmutableSortedSet Create() { return ImmutableSortedSet.Empty; } public static ImmutableSortedSet Create(IComparer? comparer) { return ImmutableSortedSet.Empty.WithComparer(comparer); } public static ImmutableSortedSet Create(T item) { return ImmutableSortedSet.Empty.Add(item); } public static ImmutableSortedSet Create(IComparer? comparer, T item) { return ImmutableSortedSet.Empty.WithComparer(comparer).Add(item); } public static ImmutableSortedSet CreateRange(IEnumerable items) { return ImmutableSortedSet.Empty.Union(items); } public static ImmutableSortedSet CreateRange(IComparer? comparer, IEnumerable items) { return ImmutableSortedSet.Empty.WithComparer(comparer).Union(items); } public static ImmutableSortedSet Create(params T[] items) { Requires.NotNull(items, "items"); return Create((ReadOnlySpan)items); } public static ImmutableSortedSet Create([ParamCollection] scoped ReadOnlySpan items) { return ImmutableSortedSet.Empty.Union(items); } public static ImmutableSortedSet Create(IComparer? comparer, params T[] items) { Requires.NotNull(items, "items"); return Create(comparer, (ReadOnlySpan)items); } public static ImmutableSortedSet Create(IComparer? comparer, [ParamCollection] scoped ReadOnlySpan items) { return ImmutableSortedSet.Empty.WithComparer(comparer).Union(items); } public static ImmutableSortedSet.Builder CreateBuilder() { return Create().ToBuilder(); } public static ImmutableSortedSet.Builder CreateBuilder(IComparer? comparer) { return Create(comparer).ToBuilder(); } public static ImmutableSortedSet ToImmutableSortedSet(this IEnumerable source, IComparer? comparer) { if (source is ImmutableSortedSet immutableSortedSet) { return immutableSortedSet.WithComparer(comparer); } return ImmutableSortedSet.Empty.WithComparer(comparer).Union(source); } public static ImmutableSortedSet ToImmutableSortedSet(this IEnumerable source) { return source.ToImmutableSortedSet(null); } public static ImmutableSortedSet ToImmutableSortedSet(this ImmutableSortedSet.Builder builder) { Requires.NotNull(builder, "builder"); return builder.ToImmutable(); } } [CollectionBuilder(typeof(ImmutableSortedSet), "Create")] [DebuggerDisplay("Count = {Count}")] [DebuggerTypeProxy(typeof(ImmutableEnumerableDebuggerProxy<>))] public sealed class ImmutableSortedSet : IImmutableSet, IReadOnlyCollection, IEnumerable, IEnumerable, ISortKeyCollection, IReadOnlyList, IList, ICollection, ISet, IList, ICollection, IStrongEnumerable.Enumerator> { [DebuggerDisplay("Count = {Count}")] [DebuggerTypeProxy(typeof(ImmutableSortedSetBuilderDebuggerProxy<>))] public sealed class Builder : ISortKeyCollection, IReadOnlyCollection, IEnumerable, IEnumerable, ISet, ICollection, ICollection { private Node _root = Node.EmptyNode; private IComparer _comparer = Comparer.Default; private ImmutableSortedSet _immutable; private int _version; private object _syncRoot; public int Count => Root.Count; bool ICollection.IsReadOnly => false; public T this[int index] => _root.ItemRef(index); public T? Max => _root.Max; public T? Min => _root.Min; public IComparer KeyComparer { get { return _comparer; } set { Requires.NotNull(value, "value"); if (value == _comparer) { return; } Node node = Node.EmptyNode; using (Enumerator enumerator = GetEnumerator()) { while (enumerator.MoveNext()) { T current = enumerator.Current; node = node.Add(current, value, out var _); } } _immutable = null; _comparer = value; Root = node; } } internal int Version => _version; private Node Root { get { return _root; } set { _version++; if (_root != value) { _root = value; _immutable = null; } } } [DebuggerBrowsable(DebuggerBrowsableState.Never)] bool ICollection.IsSynchronized => false; [DebuggerBrowsable(DebuggerBrowsableState.Never)] object ICollection.SyncRoot { get { if (_syncRoot == null) { Interlocked.CompareExchange(ref _syncRoot, new object(), (object)null); } return _syncRoot; } } internal Builder(ImmutableSortedSet set) { Requires.NotNull(set, "set"); _root = set._root; _comparer = set.KeyComparer; _immutable = set; } public ref readonly T ItemRef(int index) { return ref _root.ItemRef(index); } public bool Add(T item) { Root = Root.Add(item, _comparer, out var mutated); return mutated; } public void ExceptWith(IEnumerable other) { Requires.NotNull(other, "other"); foreach (T item in other) { Root = Root.Remove(item, _comparer, out var _); } } public void IntersectWith(IEnumerable other) { Requires.NotNull(other, "other"); Node node = Node.EmptyNode; foreach (T item in other) { if (Contains(item)) { node = node.Add(item, _comparer, out var _); } } Root = node; } public bool IsProperSubsetOf(IEnumerable other) { return ToImmutable().IsProperSubsetOf(other); } public bool IsProperSupersetOf(IEnumerable other) { return ToImmutable().IsProperSupersetOf(other); } public bool IsSubsetOf(IEnumerable other) { return ToImmutable().IsSubsetOf(other); } public bool IsSupersetOf(IEnumerable other) { return ToImmutable().IsSupersetOf(other); } public bool Overlaps(IEnumerable other) { return ToImmutable().Overlaps(other); } public bool SetEquals(IEnumerable other) { return ToImmutable().SetEquals(other); } public void SymmetricExceptWith(IEnumerable other) { Root = ToImmutable().SymmetricExcept(other)._root; } public void UnionWith(IEnumerable other) { Requires.NotNull(other, "other"); foreach (T item in other) { Root = Root.Add(item, _comparer, out var _); } } void ICollection.Add(T item) { Add(item); } public void Clear() { Root = Node.EmptyNode; } public bool Contains(T item) { return Root.Contains(item, _comparer); } void ICollection.CopyTo(T[] array, int arrayIndex) { _root.CopyTo(array, arrayIndex); } public bool Remove(T item) { Root = Root.Remove(item, _comparer, out var mutated); return mutated; } public ImmutableSortedSet.Enumerator GetEnumerator() { return Root.GetEnumerator(this); } IEnumerator IEnumerable.GetEnumerator() { return Root.GetEnumerator(); } IEnumerator IEnumerable.GetEnumerator() { return GetEnumerator(); } public int IndexOf(T item) { return Root.IndexOf(item, _comparer); } public IEnumerable Reverse() { return new ReverseEnumerable(_root); } public ImmutableSortedSet ToImmutable() { return _immutable ?? (_immutable = ImmutableSortedSet.Wrap(Root, _comparer)); } public bool TryGetValue(T equalValue, out T actualValue) { Node node = _root.Search(equalValue, _comparer); if (!node.IsEmpty) { actualValue = node.Key; return true; } actualValue = equalValue; return false; } void ICollection.CopyTo(Array array, int arrayIndex) { Root.CopyTo(array, arrayIndex); } } private sealed class ReverseEnumerable : IEnumerable, IEnumerable { private readonly Node _root; internal ReverseEnumerable(Node root) { Requires.NotNull(root, "root"); _root = root; } public IEnumerator GetEnumerator() { return _root.Reverse(); } IEnumerator IEnumerable.GetEnumerator() { return GetEnumerator(); } } [EditorBrowsable(EditorBrowsableState.Advanced)] public struct Enumerator : IEnumerator, IEnumerator, IDisposable, ISecurePooledObjectUser, IStrongEnumerator { private readonly Builder _builder; private readonly int _poolUserId; private readonly bool _reverse; private Node _root; private SecurePooledObject>> _stack; private Node _current; private int _enumeratingBuilderVersion; int ISecurePooledObjectUser.PoolUserId => _poolUserId; public T Current { get { ThrowIfDisposed(); if (_current != null) { return _current.Value; } throw new InvalidOperationException(); } } object? IEnumerator.Current => Current; internal Enumerator(Node root, Builder? builder = null, bool reverse = false) { Requires.NotNull(root, "root"); _root = root; _builder = builder; _current = null; _reverse = reverse; _enumeratingBuilderVersion = builder?.Version ?? (-1); _poolUserId = SecureObjectPool.NewId(); _stack = null; if (!SecureObjectPool>, Enumerator>.TryTake(this, out _stack)) { _stack = SecureObjectPool>, Enumerator>.PrepNew(this, new Stack>(root.Height)); } PushNext(_root); } public void Dispose() { _root = null; _current = null; if (_stack != null && _stack.TryUse(ref this, out var value)) { value.ClearFastWhenEmpty(); SecureObjectPool>, Enumerator>.TryAdd(this, _stack); _stack = null; } } public bool MoveNext() { ThrowIfDisposed(); ThrowIfChanged(); Stack> stack = _stack.Use(ref this); if (stack.Count > 0) { Node node = (_current = stack.Pop().Value); PushNext(_reverse ? node.Left : node.Right); return true; } _current = null; return false; } public void Reset() { ThrowIfDisposed(); _enumeratingBuilderVersion = ((_builder != null) ? _builder.Version : (-1)); _current = null; _stack.Use(ref this).ClearFastWhenEmpty(); PushNext(_root); } private void ThrowIfDisposed() { if (_root == null || (_stack != null && !_stack.IsOwned(ref this))) { Requires.FailObjectDisposed(this); } } private void ThrowIfChanged() { if (_builder != null && _builder.Version != _enumeratingBuilderVersion) { throw new InvalidOperationException(System.SR.CollectionModifiedDuringEnumeration); } } private void PushNext(Node node) { Requires.NotNull(node, "node"); Stack> stack = _stack.Use(ref this); while (!node.IsEmpty) { stack.Push(new RefAsValueType(node)); node = (_reverse ? node.Right : node.Left); } } } [DebuggerDisplay("{_key}")] internal sealed class Node : IBinaryTree, IBinaryTree, IEnumerable, IEnumerable { internal static readonly Node EmptyNode = new Node(); private readonly T _key; private bool _frozen; private byte _height; private int _count; private Node _left; private Node _right; public bool IsEmpty => _left == null; public int Height => _height; public Node? Left => _left; IBinaryTree? IBinaryTree.Left => _left; public Node? Right => _right; IBinaryTree? IBinaryTree.Right => _right; IBinaryTree? IBinaryTree.Left => _left; IBinaryTree? IBinaryTree.Right => _right; public T Value => _key; public int Count => _count; internal T Key => _key; internal T? Max { get { if (IsEmpty) { return default(T); } Node node = this; while (!node._right.IsEmpty) { node = node._right; } return node._key; } } internal T? Min { get { if (IsEmpty) { return default(T); } Node node = this; while (!node._left.IsEmpty) { node = node._left; } return node._key; } } internal T this[int index] { get { Requires.Range(index >= 0 && index < Count, "index"); if (index < _left._count) { return _left[index]; } if (index > _left._count) { return _right[index - _left._count - 1]; } return _key; } } private Node() { _frozen = true; } private Node(T key, Node left, Node right, bool frozen = false) { Requires.NotNull(left, "left"); Requires.NotNull(right, "right"); _key = key; _left = left; _right = right; _height = checked((byte)(1 + Math.Max(left._height, right._height))); _count = 1 + left._count + right._count; _frozen = frozen; } internal ref readonly T ItemRef(int index) { Requires.Range(index >= 0 && index < Count, "index"); return ref ItemRefUnchecked(index); } private ref readonly T ItemRefUnchecked(int index) { if (index < _left._count) { return ref _left.ItemRefUnchecked(index); } if (index > _left._count) { return ref _right.ItemRefUnchecked(index - _left._count - 1); } return ref _key; } public Enumerator GetEnumerator() { return new Enumerator(this); } [ExcludeFromCodeCoverage] IEnumerator IEnumerable.GetEnumerator() { return GetEnumerator(); } [ExcludeFromCodeCoverage] IEnumerator IEnumerable.GetEnumerator() { return GetEnumerator(); } internal Enumerator GetEnumerator(Builder builder) { return new Enumerator(this, builder); } internal void CopyTo(T[] array, int arrayIndex) { Requires.NotNull(array, "array"); Requires.Range(arrayIndex >= 0, "arrayIndex"); Requires.Range(array.Length >= arrayIndex + Count, "arrayIndex"); using Enumerator enumerator = GetEnumerator(); while (enumerator.MoveNext()) { T current = enumerator.Current; array[arrayIndex++] = current; } } internal void CopyTo(Array array, int arrayIndex) { Requires.NotNull(array, "array"); Requires.Range(arrayIndex >= 0, "arrayIndex"); Requires.Range(array.Length >= arrayIndex + Count, "arrayIndex"); using Enumerator enumerator = GetEnumerator(); while (enumerator.MoveNext()) { T current = enumerator.Current; array.SetValue(current, arrayIndex++); } } internal Node Add(T key, IComparer comparer, out bool mutated) { Requires.NotNull(comparer, "comparer"); if (IsEmpty) { mutated = true; return new Node(key, this, this); } Node node = this; int num = comparer.Compare(key, _key); if (num > 0) { Node right = _right.Add(key, comparer, out mutated); if (mutated) { node = Mutate(null, right); } } else { if (num >= 0) { mutated = false; return this; } Node left = _left.Add(key, comparer, out mutated); if (mutated) { node = Mutate(left); } } if (!mutated) { return node; } return MakeBalanced(node); } internal Node Remove(T key, IComparer comparer, out bool mutated) { Requires.NotNull(comparer, "comparer"); if (IsEmpty) { mutated = false; return this; } Node node = this; int num = comparer.Compare(key, _key); if (num == 0) { mutated = true; if (_right.IsEmpty && _left.IsEmpty) { node = EmptyNode; } else if (_right.IsEmpty && !_left.IsEmpty) { node = _left; } else if (!_right.IsEmpty && _left.IsEmpty) { node = _right; } else { Node node2 = _right; while (!node2._left.IsEmpty) { node2 = node2._left; } bool mutated2; Node right = _right.Remove(node2._key, comparer, out mutated2); node = node2.Mutate(_left, right); } } else if (num < 0) { Node left = _left.Remove(key, comparer, out mutated); if (mutated) { node = Mutate(left); } } else { Node right2 = _right.Remove(key, comparer, out mutated); if (mutated) { node = Mutate(null, right2); } } if (!node.IsEmpty) { return MakeBalanced(node); } return node; } internal bool Contains(T key, IComparer comparer) { Requires.NotNull(comparer, "comparer"); return !Search(key, comparer).IsEmpty; } internal void Freeze() { if (!_frozen) { _left.Freeze(); _right.Freeze(); _frozen = true; } } internal Node Search(T key, IComparer comparer) { Requires.NotNull(comparer, "comparer"); if (IsEmpty) { return this; } int num = comparer.Compare(key, _key); if (num == 0) { return this; } if (num > 0) { return _right.Search(key, comparer); } return _left.Search(key, comparer); } internal int IndexOf(T key, IComparer comparer) { Requires.NotNull(comparer, "comparer"); if (IsEmpty) { return -1; } int num = comparer.Compare(key, _key); if (num == 0) { return _left.Count; } if (num > 0) { int num2 = _right.IndexOf(key, comparer); bool num3 = num2 < 0; if (num3) { num2 = ~num2; } num2 = _left.Count + 1 + num2; if (num3) { num2 = ~num2; } return num2; } return _left.IndexOf(key, comparer); } internal IEnumerator Reverse() { return new Enumerator(this, null, reverse: true); } private static Node RotateLeft(Node tree) { Requires.NotNull(tree, "tree"); if (tree._right.IsEmpty) { return tree; } Node right = tree._right; return right.Mutate(tree.Mutate(null, right._left)); } private static Node RotateRight(Node tree) { Requires.NotNull(tree, "tree"); if (tree._left.IsEmpty) { return tree; } Node left = tree._left; return left.Mutate(null, tree.Mutate(left._right)); } private static Node DoubleLeft(Node tree) { Requires.NotNull(tree, "tree"); if (tree._right.IsEmpty) { return tree; } return RotateLeft(tree.Mutate(null, RotateRight(tree._right))); } private static Node DoubleRight(Node tree) { Requires.NotNull(tree, "tree"); if (tree._left.IsEmpty) { return tree; } return RotateRight(tree.Mutate(RotateLeft(tree._left))); } private static int Balance(Node tree) { Requires.NotNull(tree, "tree"); return tree._right._height - tree._left._height; } private static bool IsRightHeavy(Node tree) { Requires.NotNull(tree, "tree"); return Balance(tree) >= 2; } private static bool IsLeftHeavy(Node tree) { Requires.NotNull(tree, "tree"); return Balance(tree) <= -2; } private static Node MakeBalanced(Node tree) { Requires.NotNull(tree, "tree"); if (IsRightHeavy(tree)) { if (Balance(tree._right) >= 0) { return RotateLeft(tree); } return DoubleLeft(tree); } if (IsLeftHeavy(tree)) { if (Balance(tree._left) <= 0) { return RotateRight(tree); } return DoubleRight(tree); } return tree; } internal static Node NodeTreeFromList(IOrderedCollection items, int start, int length) { Requires.NotNull(items, "items"); if (length == 0) { return EmptyNode; } int num = (length - 1) / 2; int num2 = length - 1 - num; Node left = NodeTreeFromList(items, start, num2); Node right = NodeTreeFromList(items, start + num2 + 1, num); return new Node(items[start + num2], left, right, frozen: true); } private Node Mutate(Node left = null, Node right = null) { if (_frozen) { return new Node(_key, left ?? _left, right ?? _right); } if (left != null) { _left = left; } if (right != null) { _right = right; } _height = checked((byte)(1 + Math.Max(_left._height, _right._height))); _count = 1 + _left._count + _right._count; return this; } } private const float RefillOverIncrementalThreshold = 0.15f; public static readonly ImmutableSortedSet Empty = new ImmutableSortedSet(); private readonly Node _root; private readonly IComparer _comparer; public T? Max => _root.Max; public T? Min => _root.Min; public bool IsEmpty => _root.IsEmpty; public int Count => _root.Count; public IComparer KeyComparer => _comparer; internal IBinaryTree Root => _root; public T this[int index] => _root.ItemRef(index); bool ICollection.IsReadOnly => true; T IList.this[int index] { get { return this[index]; } set { throw new NotSupportedException(); } } bool IList.IsFixedSize => true; bool IList.IsReadOnly => true; [DebuggerBrowsable(DebuggerBrowsableState.Never)] object ICollection.SyncRoot => this; [DebuggerBrowsable(DebuggerBrowsableState.Never)] bool ICollection.IsSynchronized => true; object? IList.this[int index] { get { return this[index]; } set { throw new NotSupportedException(); } } internal ImmutableSortedSet(IComparer? comparer = null) { _root = Node.EmptyNode; _comparer = comparer ?? Comparer.Default; } private ImmutableSortedSet(Node root, IComparer comparer) { Requires.NotNull(root, "root"); Requires.NotNull(comparer, "comparer"); root.Freeze(); _root = root; _comparer = comparer; } public ImmutableSortedSet Clear() { if (!_root.IsEmpty) { return Empty.WithComparer(_comparer); } return this; } public ref readonly T ItemRef(int index) { return ref _root.ItemRef(index); } public Builder ToBuilder() { return new Builder(this); } public ImmutableSortedSet Add(T value) { bool mutated; return Wrap(_root.Add(value, _comparer, out mutated)); } public ImmutableSortedSet Remove(T value) { bool mutated; return Wrap(_root.Remove(value, _comparer, out mutated)); } public bool TryGetValue(T equalValue, out T actualValue) { Node node = _root.Search(equalValue, _comparer); if (node.IsEmpty) { actualValue = equalValue; return false; } actualValue = node.Key; return true; } public ImmutableSortedSet Intersect(IEnumerable other) { Requires.NotNull(other, "other"); ImmutableSortedSet immutableSortedSet = Clear(); foreach (T item in other.GetEnumerableDisposable()) { if (Contains(item)) { immutableSortedSet = immutableSortedSet.Add(item); } } return immutableSortedSet; } public ImmutableSortedSet Except(IEnumerable other) { Requires.NotNull(other, "other"); Node node = _root; foreach (T item in other.GetEnumerableDisposable()) { node = node.Remove(item, _comparer, out var _); } return Wrap(node); } public ImmutableSortedSet SymmetricExcept(IEnumerable other) { Requires.NotNull(other, "other"); ImmutableSortedSet immutableSortedSet = ImmutableSortedSet.CreateRange(_comparer, other); ImmutableSortedSet immutableSortedSet2 = Clear(); using (Enumerator enumerator = GetEnumerator()) { while (enumerator.MoveNext()) { T current = enumerator.Current; if (!immutableSortedSet.Contains(current)) { immutableSortedSet2 = immutableSortedSet2.Add(current); } } } foreach (T item in immutableSortedSet) { if (!Contains(item)) { immutableSortedSet2 = immutableSortedSet2.Add(item); } } return immutableSortedSet2; } public ImmutableSortedSet Union(IEnumerable other) { Requires.NotNull(other, "other"); if (TryCastToImmutableSortedSet(other, out var other2) && other2.KeyComparer == KeyComparer) { if (other2.IsEmpty) { return this; } if (IsEmpty) { return other2; } if (other2.Count > Count) { return other2.Union(this); } } if (IsEmpty || (other.TryGetCount(out var count) && (float)(Count + count) * 0.15f > (float)Count)) { return LeafToRootRefill(other); } return UnionIncremental(other); } internal ImmutableSortedSet Union(ReadOnlySpan other) { if (IsEmpty || (float)(Count + other.Length) * 0.15f > (float)Count) { return LeafToRootRefill(other); } return UnionIncremental(other); } public ImmutableSortedSet WithComparer(IComparer? comparer) { if (comparer == null) { comparer = Comparer.Default; } if (comparer == _comparer) { return this; } return new ImmutableSortedSet(Node.EmptyNode, comparer).Union(this); } public bool SetEquals(IEnumerable other) { Requires.NotNull(other, "other"); if (this == other) { return true; } SortedSet sortedSet = new SortedSet(other, KeyComparer); if (Count != sortedSet.Count) { return false; } int num = 0; foreach (T item in sortedSet) { if (!Contains(item)) { return false; } num++; } return num == Count; } public bool IsProperSubsetOf(IEnumerable other) { Requires.NotNull(other, "other"); if (IsEmpty) { return other.Any(); } SortedSet sortedSet = new SortedSet(other, KeyComparer); if (Count >= sortedSet.Count) { return false; } int num = 0; bool flag = false; foreach (T item in sortedSet) { if (Contains(item)) { num++; } else { flag = true; } if (num == Count && flag) { return true; } } return false; } public bool IsProperSupersetOf(IEnumerable other) { Requires.NotNull(other, "other"); if (IsEmpty) { return false; } int num = 0; foreach (T item in other.GetEnumerableDisposable()) { num++; if (!Contains(item)) { return false; } } return Count > num; } public bool IsSubsetOf(IEnumerable other) { Requires.NotNull(other, "other"); if (IsEmpty) { return true; } SortedSet sortedSet = new SortedSet(other, KeyComparer); int num = 0; foreach (T item in sortedSet) { if (Contains(item)) { num++; } } return num == Count; } public bool IsSupersetOf(IEnumerable other) { Requires.NotNull(other, "other"); foreach (T item in other.GetEnumerableDisposable()) { if (!Contains(item)) { return false; } } return true; } public bool Overlaps(IEnumerable other) { Requires.NotNull(other, "other"); if (IsEmpty) { return false; } foreach (T item in other.GetEnumerableDisposable()) { if (Contains(item)) { return true; } } return false; } public IEnumerable Reverse() { return new ReverseEnumerable(_root); } public int IndexOf(T item) { return _root.IndexOf(item, _comparer); } public bool Contains(T value) { return _root.Contains(value, _comparer); } IImmutableSet IImmutableSet.Clear() { return Clear(); } IImmutableSet IImmutableSet.Add(T value) { return Add(value); } IImmutableSet IImmutableSet.Remove(T value) { return Remove(value); } IImmutableSet IImmutableSet.Intersect(IEnumerable other) { return Intersect(other); } IImmutableSet IImmutableSet.Except(IEnumerable other) { return Except(other); } IImmutableSet IImmutableSet.SymmetricExcept(IEnumerable other) { return SymmetricExcept(other); } IImmutableSet IImmutableSet.Union(IEnumerable other) { return Union(other); } bool ISet.Add(T item) { throw new NotSupportedException(); } void ISet.ExceptWith(IEnumerable other) { throw new NotSupportedException(); } void ISet.IntersectWith(IEnumerable other) { throw new NotSupportedException(); } void ISet.SymmetricExceptWith(IEnumerable other) { throw new NotSupportedException(); } void ISet.UnionWith(IEnumerable other) { throw new NotSupportedException(); } void ICollection.CopyTo(T[] array, int arrayIndex) { _root.CopyTo(array, arrayIndex); } void ICollection.Add(T item) { throw new NotSupportedException(); } void ICollection.Clear() { throw new NotSupportedException(); } bool ICollection.Remove(T item) { throw new NotSupportedException(); } void IList.Insert(int index, T item) { throw new NotSupportedException(); } void IList.RemoveAt(int index) { throw new NotSupportedException(); } int IList.Add(object value) { throw new NotSupportedException(); } void IList.Clear() { throw new NotSupportedException(); } private static bool IsCompatibleObject(object value) { if (!(value is T)) { if (default(T) == null) { return value == null; } return false; } return true; } bool IList.Contains(object value) { if (IsCompatibleObject(value)) { return Contains((T)value); } return false; } int IList.IndexOf(object value) { if (IsCompatibleObject(value)) { return IndexOf((T)value); } return -1; } void IList.Insert(int index, object value) { throw new NotSupportedException(); } void IList.Remove(object value) { throw new NotSupportedException(); } void IList.RemoveAt(int index) { throw new NotSupportedException(); } void ICollection.CopyTo(Array array, int index) { _root.CopyTo(array, index); } IEnumerator IEnumerable.GetEnumerator() { if (!IsEmpty) { return GetEnumerator(); } return Enumerable.Empty().GetEnumerator(); } IEnumerator IEnumerable.GetEnumerator() { return GetEnumerator(); } public Enumerator GetEnumerator() { return _root.GetEnumerator(); } private static bool TryCastToImmutableSortedSet(IEnumerable sequence, [NotNullWhen(true)] out ImmutableSortedSet other) { other = sequence as ImmutableSortedSet; if (other != null) { return true; } if (sequence is Builder builder) { other = builder.ToImmutable(); return true; } return false; } private static ImmutableSortedSet Wrap(Node root, IComparer comparer) { if (!root.IsEmpty) { return new ImmutableSortedSet(root, comparer); } return Empty.WithComparer(comparer); } private ImmutableSortedSet UnionIncremental(IEnumerable items) { Requires.NotNull(items, "items"); Node node = _root; foreach (T item in items.GetEnumerableDisposable()) { node = node.Add(item, _comparer, out var _); } return Wrap(node); } private ImmutableSortedSet UnionIncremental(ReadOnlySpan items) { Node node = _root; ReadOnlySpan readOnlySpan = items; for (int i = 0; i < readOnlySpan.Length; i++) { T key = readOnlySpan[i]; node = node.Add(key, _comparer, out var _); } return Wrap(node); } private ImmutableSortedSet Wrap(Node root) { if (root != _root) { if (!root.IsEmpty) { return new ImmutableSortedSet(root, _comparer); } return Clear(); } return this; } private ImmutableSortedSet LeafToRootRefill(IEnumerable addedItems) { Requires.NotNull(addedItems, "addedItems"); List list; if (IsEmpty) { if (addedItems.TryGetCount(out var count) && count == 0) { return this; } list = new List(addedItems); if (list.Count == 0) { return this; } } else { list = new List(this); list.AddRange(addedItems); } IComparer keyComparer = KeyComparer; list.Sort(keyComparer); int num = 1; for (int i = 1; i < list.Count; i++) { if (keyComparer.Compare(list[i], list[i - 1]) != 0) { list[num++] = list[i]; } } list.RemoveRange(num, list.Count - num); Node root = Node.NodeTreeFromList(list.AsOrderedCollection(), 0, list.Count); return Wrap(root); } private ImmutableSortedSet LeafToRootRefill(ReadOnlySpan addedItems) { List list; if (IsEmpty && addedItems.IsEmpty) { if (addedItems.IsEmpty) { return this; } list = new List(addedItems.Length); } else { list = new List(Count + addedItems.Length); list.AddRange(this); } ReadOnlySpan readOnlySpan = addedItems; for (int i = 0; i < readOnlySpan.Length; i++) { T item = readOnlySpan[i]; list.Add(item); } IComparer keyComparer = KeyComparer; list.Sort(keyComparer); int num = 1; for (int j = 1; j < list.Count; j++) { if (keyComparer.Compare(list[j], list[j - 1]) != 0) { list[num++] = list[j]; } } list.RemoveRange(num, list.Count - num); Node root = Node.NodeTreeFromList(list.AsOrderedCollection(), 0, list.Count); return Wrap(root); } } internal sealed class ImmutableSortedSetBuilderDebuggerProxy { private readonly ImmutableSortedSet.Builder _set; [DebuggerBrowsable(DebuggerBrowsableState.RootHidden)] public T[] Contents => _set.ToArray(_set.Count); public ImmutableSortedSetBuilderDebuggerProxy(ImmutableSortedSet.Builder builder) { Requires.NotNull(builder, "builder"); _set = builder; } } public static class ImmutableStack { public static ImmutableStack Create() { return ImmutableStack.Empty; } public static ImmutableStack Create(T item) { return ImmutableStack.Empty.Push(item); } public static ImmutableStack CreateRange(IEnumerable items) { Requires.NotNull(items, "items"); ImmutableStack immutableStack = ImmutableStack.Empty; foreach (T item in items) { immutableStack = immutableStack.Push(item); } return immutableStack; } public static ImmutableStack Create(params T[] items) { Requires.NotNull(items, "items"); return Create((ReadOnlySpan)items); } public static ImmutableStack Create([ParamCollection] scoped ReadOnlySpan items) { ImmutableStack immutableStack = ImmutableStack.Empty; ReadOnlySpan readOnlySpan = items; for (int i = 0; i < readOnlySpan.Length; i++) { T value = readOnlySpan[i]; immutableStack = immutableStack.Push(value); } return immutableStack; } public static IImmutableStack Pop(this IImmutableStack stack, out T value) { Requires.NotNull(stack, "stack"); value = stack.Peek(); return stack.Pop(); } } [CollectionBuilder(typeof(ImmutableStack), "Create")] [DebuggerDisplay("IsEmpty = {IsEmpty}, Top = {_head}")] [DebuggerTypeProxy(typeof(ImmutableEnumerableDebuggerProxy<>))] public sealed class ImmutableStack : IImmutableStack, IEnumerable, IEnumerable { [EditorBrowsable(EditorBrowsableState.Advanced)] public struct Enumerator { private readonly ImmutableStack _originalStack; private ImmutableStack _remainingStack; public T Current { get { if (_remainingStack == null || _remainingStack.IsEmpty) { throw new InvalidOperationException(); } return _remainingStack.Peek(); } } internal Enumerator(ImmutableStack stack) { Requires.NotNull(stack, "stack"); _originalStack = stack; _remainingStack = null; } public bool MoveNext() { if (_remainingStack == null) { _remainingStack = _originalStack; } else if (!_remainingStack.IsEmpty) { _remainingStack = _remainingStack.Pop(); } return !_remainingStack.IsEmpty; } } private sealed class EnumeratorObject : IEnumerator, IEnumerator, IDisposable { private readonly ImmutableStack _originalStack; private ImmutableStack _remainingStack; private bool _disposed; public T Current { get { ThrowIfDisposed(); if (_remainingStack == null || _remainingStack.IsEmpty) { throw new InvalidOperationException(); } return _remainingStack.Peek(); } } object IEnumerator.Current => Current; internal EnumeratorObject(ImmutableStack stack) { Requires.NotNull(stack, "stack"); _originalStack = stack; } public bool MoveNext() { ThrowIfDisposed(); if (_remainingStack == null) { _remainingStack = _originalStack; } else if (!_remainingStack.IsEmpty) { _remainingStack = _remainingStack.Pop(); } return !_remainingStack.IsEmpty; } public void Reset() { ThrowIfDisposed(); _remainingStack = null; } public void Dispose() { _disposed = true; } private void ThrowIfDisposed() { if (_disposed) { Requires.FailObjectDisposed(this); } } } private static readonly ImmutableStack s_EmptyField = new ImmutableStack(); private readonly T _head; private readonly ImmutableStack _tail; public static ImmutableStack Empty => s_EmptyField; public bool IsEmpty => _tail == null; private ImmutableStack() { } private ImmutableStack(T head, ImmutableStack tail) { _head = head; _tail = tail; } public ImmutableStack Clear() { return Empty; } IImmutableStack IImmutableStack.Clear() { return Clear(); } public T Peek() { if (IsEmpty) { throw new InvalidOperationException(System.SR.InvalidEmptyOperation); } return _head; } public ref readonly T PeekRef() { if (IsEmpty) { throw new InvalidOperationException(System.SR.InvalidEmptyOperation); } return ref _head; } public ImmutableStack Push(T value) { return new ImmutableStack(value, this); } IImmutableStack IImmutableStack.Push(T value) { return Push(value); } public ImmutableStack Pop() { if (IsEmpty) { throw new InvalidOperationException(System.SR.InvalidEmptyOperation); } return _tail; } public ImmutableStack Pop(out T value) { value = Peek(); return Pop(); } IImmutableStack IImmutableStack.Pop() { return Pop(); } public Enumerator GetEnumerator() { return new Enumerator(this); } IEnumerator IEnumerable.GetEnumerator() { if (!IsEmpty) { return new EnumeratorObject(this); } return Enumerable.Empty().GetEnumerator(); } IEnumerator IEnumerable.GetEnumerator() { return new EnumeratorObject(this); } internal ImmutableStack Reverse() { ImmutableStack immutableStack = Clear(); ImmutableStack immutableStack2 = this; while (!immutableStack2.IsEmpty) { immutableStack = immutableStack.Push(immutableStack2.Peek()); immutableStack2 = immutableStack2.Pop(); } return immutableStack; } } internal abstract class KeysOrValuesCollectionAccessor : ICollection, IEnumerable, IEnumerable, ICollection where TKey : notnull { private readonly IImmutableDictionary _dictionary; private readonly IEnumerable _keysOrValues; public bool IsReadOnly => true; public int Count => _dictionary.Count; protected IImmutableDictionary Dictionary => _dictionary; [DebuggerBrowsable(DebuggerBrowsableState.Never)] bool ICollection.IsSynchronized => true; [DebuggerBrowsable(DebuggerBrowsableState.Never)] object ICollection.SyncRoot => this; protected KeysOrValuesCollectionAccessor(IImmutableDictionary dictionary, IEnumerable keysOrValues) { Requires.NotNull(dictionary, "dictionary"); Requires.NotNull(keysOrValues, "keysOrValues"); _dictionary = dictionary; _keysOrValues = keysOrValues; } public void Add(T item) { throw new NotSupportedException(); } public void Clear() { throw new NotSupportedException(); } public abstract bool Contains(T item); public void CopyTo(T[] array, int arrayIndex) { Requires.NotNull(array, "array"); Requires.Range(arrayIndex >= 0, "arrayIndex"); Requires.Range(array.Length >= arrayIndex + Count, "arrayIndex"); using IEnumerator enumerator = GetEnumerator(); while (enumerator.MoveNext()) { T current = enumerator.Current; array[arrayIndex++] = current; } } public bool Remove(T item) { throw new NotSupportedException(); } public IEnumerator GetEnumerator() { return _keysOrValues.GetEnumerator(); } IEnumerator IEnumerable.GetEnumerator() { return GetEnumerator(); } void ICollection.CopyTo(Array array, int arrayIndex) { Requires.NotNull(array, "array"); Requires.Range(arrayIndex >= 0, "arrayIndex"); Requires.Range(array.Length >= arrayIndex + Count, "arrayIndex"); using IEnumerator enumerator = GetEnumerator(); while (enumerator.MoveNext()) { T current = enumerator.Current; array.SetValue(current, arrayIndex++); } } } internal sealed class KeysCollectionAccessor : KeysOrValuesCollectionAccessor where TKey : notnull { internal KeysCollectionAccessor(IImmutableDictionary dictionary) : base(dictionary, dictionary.Keys) { } public override bool Contains(TKey item) { return base.Dictionary.ContainsKey(item); } } internal sealed class ValuesCollectionAccessor : KeysOrValuesCollectionAccessor where TKey : notnull { internal ValuesCollectionAccessor(IImmutableDictionary dictionary) : base(dictionary, dictionary.Values) { } public override bool Contains(TValue item) { if (base.Dictionary is ImmutableSortedDictionary immutableSortedDictionary) { return immutableSortedDictionary.ContainsValue(item); } if (base.Dictionary is IImmutableDictionaryInternal immutableDictionaryInternal) { return immutableDictionaryInternal.ContainsValue(item); } throw new NotSupportedException(); } } [DebuggerDisplay("{Value,nq}")] internal struct RefAsValueType { internal T Value; internal RefAsValueType(T value) { Value = value; } } internal static class SecureObjectPool { private static int s_poolUserIdCounter; internal const int UnassignedId = -1; internal static int NewId() { int num; do { num = Interlocked.Increment(ref s_poolUserIdCounter); } while (num == -1); return num; } } internal static class SecureObjectPool where TCaller : ISecurePooledObjectUser { public static void TryAdd(TCaller caller, SecurePooledObject item) { if (caller.PoolUserId == item.Owner) { item.Owner = -1; AllocFreeConcurrentStack>.TryAdd(item); } } public static bool TryTake(TCaller caller, out SecurePooledObject? item) { if (caller.PoolUserId != -1 && AllocFreeConcurrentStack>.TryTake(out item)) { item.Owner = caller.PoolUserId; return true; } item = null; return false; } public static SecurePooledObject PrepNew(TCaller caller, T newValue) { Requires.NotNullAllowStructs(newValue, "newValue"); return new SecurePooledObject(newValue) { Owner = caller.PoolUserId }; } } internal interface ISecurePooledObjectUser { int PoolUserId { get; } } internal sealed class SecurePooledObject { private readonly T _value; private int _owner; internal int Owner { get { return _owner; } set { _owner = value; } } internal SecurePooledObject(T newValue) { Requires.NotNullAllowStructs(newValue, "newValue"); _value = newValue; } internal T Use(ref TCaller caller) where TCaller : struct, ISecurePooledObjectUser { if (!IsOwned(ref caller)) { Requires.FailObjectDisposed(caller); } return _value; } internal bool TryUse(ref TCaller caller, [MaybeNullWhen(false)] out T value) where TCaller : struct, ISecurePooledObjectUser { if (IsOwned(ref caller)) { value = _value; return true; } value = default(T); return false; } [MethodImpl(MethodImplOptions.AggressiveInlining)] internal bool IsOwned(ref TCaller caller) where TCaller : struct, ISecurePooledObjectUser { return caller.PoolUserId == _owner; } } [DebuggerDisplay("{_key} = {_value}")] internal sealed class SortedInt32KeyNode : IBinaryTree { [EditorBrowsable(EditorBrowsableState.Advanced)] public struct Enumerator : IEnumerator>, IEnumerator, IDisposable, ISecurePooledObjectUser { private readonly int _poolUserId; private SortedInt32KeyNode _root; private SecurePooledObject>>> _stack; private SortedInt32KeyNode _current; public KeyValuePair Current { get { ThrowIfDisposed(); if (_current != null) { return _current.Value; } throw new InvalidOperationException(); } } int ISecurePooledObjectUser.PoolUserId => _poolUserId; object IEnumerator.Current => Current; internal Enumerator(SortedInt32KeyNode root) { Requires.NotNull(root, "root"); _root = root; _current = null; _poolUserId = SecureObjectPool.NewId(); _stack = null; if (!_root.IsEmpty) { if (!SecureObjectPool>>, Enumerator>.TryTake(this, out _stack)) { _stack = SecureObjectPool>>, Enumerator>.PrepNew(this, new Stack>>(root.Height)); } PushLeft(_root); } } public void Dispose() { _root = null; _current = null; if (_stack != null && _stack.TryUse(ref this, out var value)) { value.ClearFastWhenEmpty(); SecureObjectPool>>, Enumerator>.TryAdd(this, _stack); } _stack = null; } public bool MoveNext() { ThrowIfDisposed(); if (_stack != null) { Stack>> stack = _stack.Use(ref this); if (stack.Count > 0) { PushLeft((_current = stack.Pop().Value).Right); return true; } } _current = null; return false; } public void Reset() { ThrowIfDisposed(); _current = null; if (_stack != null) { _stack.Use(ref this).ClearFastWhenEmpty(); PushLeft(_root); } } internal void ThrowIfDisposed() { if (_root == null || (_stack != null && !_stack.IsOwned(ref this))) { Requires.FailObjectDisposed(this); } } private void PushLeft(SortedInt32KeyNode node) { Requires.NotNull(node, "node"); Stack>> stack = _stack.Use(ref this); while (!node.IsEmpty) { stack.Push(new RefAsValueType>(node)); node = node.Left; } } } internal static readonly SortedInt32KeyNode EmptyNode = new SortedInt32KeyNode(); private readonly int _key; private readonly TValue _value; private bool _frozen; private byte _height; private SortedInt32KeyNode _left; private SortedInt32KeyNode _right; public bool IsEmpty => _left == null; public int Height => _height; public SortedInt32KeyNode? Left => _left; public SortedInt32KeyNode? Right => _right; IBinaryTree? IBinaryTree.Left => _left; IBinaryTree? IBinaryTree.Right => _right; int IBinaryTree.Count { get { throw new NotSupportedException(); } } public KeyValuePair Value => new KeyValuePair(_key, _value); internal IEnumerable Values { get { using Enumerator enumerator = GetEnumerator(); while (enumerator.MoveNext()) { yield return enumerator.Current.Value; } } } private SortedInt32KeyNode() { _frozen = true; } private SortedInt32KeyNode(int key, TValue value, SortedInt32KeyNode left, SortedInt32KeyNode right, bool frozen = false) { Requires.NotNull(left, "left"); Requires.NotNull(right, "right"); _key = key; _value = value; _left = left; _right = right; _frozen = frozen; _height = checked((byte)(1 + Math.Max(left._height, right._height))); } public Enumerator GetEnumerator() { return new Enumerator(this); } internal SortedInt32KeyNode SetItem(int key, TValue value, IEqualityComparer valueComparer, out bool replacedExistingValue, out bool mutated) { Requires.NotNull(valueComparer, "valueComparer"); return SetOrAdd(key, value, valueComparer, overwriteExistingValue: true, out replacedExistingValue, out mutated); } internal SortedInt32KeyNode Remove(int key, out bool mutated) { return RemoveRecursive(key, out mutated); } internal TValue? GetValueOrDefault(int key) { SortedInt32KeyNode sortedInt32KeyNode = this; while (true) { if (sortedInt32KeyNode.IsEmpty) { return default(TValue); } if (key == sortedInt32KeyNode._key) { break; } sortedInt32KeyNode = ((key <= sortedInt32KeyNode._key) ? sortedInt32KeyNode._left : sortedInt32KeyNode._right); } return sortedInt32KeyNode._value; } internal bool TryGetValue(int key, [MaybeNullWhen(false)] out TValue value) { SortedInt32KeyNode sortedInt32KeyNode = this; while (true) { if (sortedInt32KeyNode.IsEmpty) { value = default(TValue); return false; } if (key == sortedInt32KeyNode._key) { break; } sortedInt32KeyNode = ((key <= sortedInt32KeyNode._key) ? sortedInt32KeyNode._left : sortedInt32KeyNode._right); } value = sortedInt32KeyNode._value; return true; } internal void Freeze(Action>? freezeAction = null) { if (!_frozen) { freezeAction?.Invoke(new KeyValuePair(_key, _value)); _left.Freeze(freezeAction); _right.Freeze(freezeAction); _frozen = true; } } private static SortedInt32KeyNode RotateLeft(SortedInt32KeyNode tree) { Requires.NotNull(tree, "tree"); if (tree._right.IsEmpty) { return tree; } SortedInt32KeyNode right = tree._right; return right.Mutate(tree.Mutate(null, right._left)); } private static SortedInt32KeyNode RotateRight(SortedInt32KeyNode tree) { Requires.NotNull(tree, "tree"); if (tree._left.IsEmpty) { return tree; } SortedInt32KeyNode left = tree._left; return left.Mutate(null, tree.Mutate(left._right)); } private static SortedInt32KeyNode DoubleLeft(SortedInt32KeyNode tree) { Requires.NotNull(tree, "tree"); if (tree._right.IsEmpty) { return tree; } return RotateLeft(tree.Mutate(null, RotateRight(tree._right))); } private static SortedInt32KeyNode DoubleRight(SortedInt32KeyNode tree) { Requires.NotNull(tree, "tree"); if (tree._left.IsEmpty) { return tree; } return RotateRight(tree.Mutate(RotateLeft(tree._left))); } private static int Balance(SortedInt32KeyNode tree) { Requires.NotNull(tree, "tree"); return tree._right._height - tree._left._height; } private static bool IsRightHeavy(SortedInt32KeyNode tree) { Requires.NotNull(tree, "tree"); return Balance(tree) >= 2; } private static bool IsLeftHeavy(SortedInt32KeyNode tree) { Requires.NotNull(tree, "tree"); return Balance(tree) <= -2; } private static SortedInt32KeyNode MakeBalanced(SortedInt32KeyNode tree) { Requires.NotNull(tree, "tree"); if (IsRightHeavy(tree)) { if (Balance(tree._right) >= 0) { return RotateLeft(tree); } return DoubleLeft(tree); } if (IsLeftHeavy(tree)) { if (Balance(tree._left) <= 0) { return RotateRight(tree); } return DoubleRight(tree); } return tree; } private SortedInt32KeyNode SetOrAdd(int key, TValue value, IEqualityComparer valueComparer, bool overwriteExistingValue, out bool replacedExistingValue, out bool mutated) { replacedExistingValue = false; if (IsEmpty) { mutated = true; return new SortedInt32KeyNode(key, value, this, this); } SortedInt32KeyNode sortedInt32KeyNode = this; if (key > _key) { SortedInt32KeyNode right = _right.SetOrAdd(key, value, valueComparer, overwriteExistingValue, out replacedExistingValue, out mutated); if (mutated) { sortedInt32KeyNode = Mutate(null, right); } } else if (key < _key) { SortedInt32KeyNode left = _left.SetOrAdd(key, value, valueComparer, overwriteExistingValue, out replacedExistingValue, out mutated); if (mutated) { sortedInt32KeyNode = Mutate(left); } } else { if (valueComparer.Equals(_value, value)) { mutated = false; return this; } if (!overwriteExistingValue) { throw new ArgumentException(System.SR.Format(System.SR.DuplicateKey, key)); } mutated = true; replacedExistingValue = true; sortedInt32KeyNode = new SortedInt32KeyNode(key, value, _left, _right); } if (!mutated) { return sortedInt32KeyNode; } return MakeBalanced(sortedInt32KeyNode); } private SortedInt32KeyNode RemoveRecursive(int key, out bool mutated) { if (IsEmpty) { mutated = false; return this; } SortedInt32KeyNode sortedInt32KeyNode = this; if (key == _key) { mutated = true; if (_right.IsEmpty && _left.IsEmpty) { sortedInt32KeyNode = EmptyNode; } else if (_right.IsEmpty && !_left.IsEmpty) { sortedInt32KeyNode = _left; } else if (!_right.IsEmpty && _left.IsEmpty) { sortedInt32KeyNode = _right; } else { SortedInt32KeyNode sortedInt32KeyNode2 = _right; while (!sortedInt32KeyNode2._left.IsEmpty) { sortedInt32KeyNode2 = sortedInt32KeyNode2._left; } bool mutated2; SortedInt32KeyNode right = _right.Remove(sortedInt32KeyNode2._key, out mutated2); sortedInt32KeyNode = sortedInt32KeyNode2.Mutate(_left, right); } } else if (key < _key) { SortedInt32KeyNode left = _left.Remove(key, out mutated); if (mutated) { sortedInt32KeyNode = Mutate(left); } } else { SortedInt32KeyNode right2 = _right.Remove(key, out mutated); if (mutated) { sortedInt32KeyNode = Mutate(null, right2); } } if (!sortedInt32KeyNode.IsEmpty) { return MakeBalanced(sortedInt32KeyNode); } return sortedInt32KeyNode; } private SortedInt32KeyNode Mutate(SortedInt32KeyNode left = null, SortedInt32KeyNode right = null) { if (_frozen) { return new SortedInt32KeyNode(_key, _value, left ?? _left, right ?? _right); } if (left != null) { _left = left; } if (right != null) { _right = right; } _height = checked((byte)(1 + Math.Max(_left._height, _right._height))); return this; } } internal static class Requires { [DebuggerStepThrough] public static void NotNull([NotNull] T value, string? parameterName) where T : class { if (value == null) { FailArgumentNullException(parameterName); } } [DebuggerStepThrough] public static T NotNullPassthrough([NotNull] T value, string? parameterName) where T : class { NotNull(value, parameterName); return value; } [DebuggerStepThrough] public static void NotNullAllowStructs([NotNull] T value, string? parameterName) { if (value == null) { FailArgumentNullException(parameterName); } } [DoesNotReturn] [DebuggerStepThrough] public static void FailArgumentNullException(string? parameterName) { throw new ArgumentNullException(parameterName); } [DebuggerStepThrough] public static void Range([DoesNotReturnIf(false)] bool condition, string? parameterName, string? message = null) { if (!condition) { FailRange(parameterName, message); } } [DoesNotReturn] [DebuggerStepThrough] public static void FailRange(string? parameterName, string? message = null) { if (string.IsNullOrEmpty(message)) { throw new ArgumentOutOfRangeException(parameterName); } throw new ArgumentOutOfRangeException(parameterName, message); } [DebuggerStepThrough] public static void Argument([DoesNotReturnIf(false)] bool condition, string? parameterName, string? message) { if (!condition) { throw new ArgumentException(message, parameterName); } } [DebuggerStepThrough] public static void Argument([DoesNotReturnIf(false)] bool condition) { if (!condition) { throw new ArgumentException(); } } [MethodImpl(MethodImplOptions.NoInlining)] [DoesNotReturn] [DebuggerStepThrough] public static void FailObjectDisposed(TDisposed disposed) { throw new ObjectDisposedException(disposed.GetType().FullName); } } } namespace System.Collections.Frozen { internal static class Constants { public const int MaxItemsInSmallFrozenCollection = 4; public const int MaxItemsInSmallValueTypeFrozenCollection = 10; public static bool IsKnownComparable() { if (!(typeof(T) == typeof(bool)) && !(typeof(T) == typeof(sbyte)) && !(typeof(T) == typeof(byte)) && !(typeof(T) == typeof(char)) && !(typeof(T) == typeof(short)) && !(typeof(T) == typeof(ushort)) && !(typeof(T) == typeof(int)) && !(typeof(T) == typeof(uint)) && !(typeof(T) == typeof(long)) && !(typeof(T) == typeof(ulong)) && !(typeof(T) == typeof(decimal)) && !(typeof(T) == typeof(float)) && !(typeof(T) == typeof(double)) && !(typeof(T) == typeof(decimal)) && !(typeof(T) == typeof(TimeSpan)) && !(typeof(T) == typeof(DateTime)) && !(typeof(T) == typeof(DateTimeOffset)) && !(typeof(T) == typeof(Guid))) { return typeof(T).IsEnum; } return true; } internal static bool KeysAreHashCodes() { if (!(typeof(T) == typeof(int)) && !(typeof(T) == typeof(uint)) && !(typeof(T) == typeof(short)) && !(typeof(T) == typeof(ushort)) && !(typeof(T) == typeof(byte)) && !(typeof(T) == typeof(sbyte))) { if (typeof(T) == typeof(IntPtr) || typeof(T) == typeof(UIntPtr)) { return IntPtr.Size == 4; } return false; } return true; } } internal sealed class DefaultFrozenDictionary : KeysAndValuesFrozenDictionary, IDictionary, ICollection>, IEnumerable>, IEnumerable where TKey : notnull { internal DefaultFrozenDictionary(Dictionary source) : base(source, keysAreHashCodes: false) { } private protected override ref readonly TValue GetValueRefOrNullRefCore(TKey key) { IEqualityComparer comparer = base.Comparer; int hashCode = comparer.GetHashCode(key); _hashTable.FindMatchingEntries(hashCode, out var i, out var endIndex); for (; i <= endIndex; i++) { if (hashCode == _hashTable.HashCodes[i] && comparer.Equals(key, _keys[i])) { return ref _values[i]; } } return ref Unsafe.NullRef(); } } internal sealed class DefaultFrozenSet : ItemsFrozenSet.GSW> { internal struct GSW : IGenericSpecializedWrapper { private DefaultFrozenSet _set; public int Count => _set.Count; public IEqualityComparer Comparer => _set.Comparer; public void Store(FrozenSet set) { _set = (DefaultFrozenSet)set; } public int FindItemIndex(T item) { return _set.FindItemIndex(item); } public Enumerator GetEnumerator() { return _set.GetEnumerator(); } } internal DefaultFrozenSet(HashSet source) : base(source, keysAreHashCodes: false) { } private protected override int FindItemIndex(T item) { IEqualityComparer comparer = base.Comparer; int num = ((item != null) ? comparer.GetHashCode(item) : 0); _hashTable.FindMatchingEntries(num, out var i, out var endIndex); for (; i <= endIndex; i++) { if (num == _hashTable.HashCodes[i] && comparer.Equals(item, _items[i])) { return i; } } return -1; } } internal sealed class EmptyFrozenDictionary : FrozenDictionary where TKey : notnull { private protected override TKey[] KeysCore => Array.Empty(); private protected override TValue[] ValuesCore => Array.Empty(); private protected override int CountCore => 0; internal EmptyFrozenDictionary(IEqualityComparer comparer) : base(comparer) { } private protected override Enumerator GetEnumeratorCore() { return new FrozenDictionary.Enumerator(Array.Empty(), Array.Empty()); } private protected override ref readonly TValue GetValueRefOrNullRefCore(TKey key) { return ref Unsafe.NullRef(); } } internal sealed class EmptyFrozenSet : FrozenSet { private protected override T[] ItemsCore => Array.Empty(); private protected override int CountCore => 0; internal EmptyFrozenSet(IEqualityComparer comparer) : base(comparer) { } private protected override int FindItemIndex(T item) { return -1; } private protected override Enumerator GetEnumeratorCore() { return new FrozenSet.Enumerator(Array.Empty()); } private protected override bool IsProperSubsetOfCore(IEnumerable other) { return !OtherIsEmpty(other); } private protected override bool IsProperSupersetOfCore(IEnumerable other) { return false; } private protected override bool IsSubsetOfCore(IEnumerable other) { return true; } private protected override bool IsSupersetOfCore(IEnumerable other) { return OtherIsEmpty(other); } private protected override bool OverlapsCore(IEnumerable other) { return false; } private protected override bool SetEqualsCore(IEnumerable other) { return OtherIsEmpty(other); } private static bool OtherIsEmpty(IEnumerable other) { if (!(other is IReadOnlyCollection readOnlyCollection)) { return !other.Any(); } return readOnlyCollection.Count == 0; } } public static class FrozenDictionary { public static FrozenDictionary ToFrozenDictionary(this IEnumerable> source, IEqualityComparer? comparer = null) where TKey : notnull { Dictionary newDictionary; return GetExistingFrozenOrNewDictionary(source, comparer, out newDictionary) ?? CreateFromDictionary(newDictionary); } public static FrozenDictionary ToFrozenDictionary(this IEnumerable source, Func keySelector, IEqualityComparer? comparer = null) where TKey : notnull { return source.ToDictionary(keySelector, comparer).ToFrozenDictionary(comparer); } public static FrozenDictionary ToFrozenDictionary(this IEnumerable source, Func keySelector, Func elementSelector, IEqualityComparer? comparer = null) where TKey : notnull { return source.ToDictionary(keySelector, elementSelector, comparer).ToFrozenDictionary(comparer); } private static FrozenDictionary GetExistingFrozenOrNewDictionary(IEnumerable> source, IEqualityComparer comparer, out Dictionary newDictionary) { ThrowHelper.ThrowIfNull(source, "source"); if (comparer == null) { comparer = EqualityComparer.Default; } if (source is FrozenDictionary frozenDictionary && frozenDictionary.Comparer.Equals(comparer)) { newDictionary = null; return frozenDictionary; } newDictionary = source as Dictionary; if (newDictionary == null || (newDictionary.Count != 0 && !newDictionary.Comparer.Equals(comparer))) { newDictionary = new Dictionary(comparer); foreach (KeyValuePair item in source) { newDictionary[item.Key] = item.Value; } } if (newDictionary.Count == 0) { if (comparer != FrozenDictionary.Empty.Comparer) { return new EmptyFrozenDictionary(comparer); } return FrozenDictionary.Empty; } return null; } private static FrozenDictionary CreateFromDictionary(Dictionary source) { IEqualityComparer comparer = source.Comparer; if (typeof(TKey).IsValueType && comparer == EqualityComparer.Default) { if (source.Count <= 10) { if (Constants.IsKnownComparable()) { return new SmallValueTypeComparableFrozenDictionary(source); } return new SmallValueTypeDefaultComparerFrozenDictionary(source); } if (typeof(TKey) == typeof(int)) { return (FrozenDictionary)(object)new Int32FrozenDictionary((Dictionary)(object)source); } return new ValueTypeDefaultComparerFrozenDictionary(source); } if (typeof(TKey) == typeof(string) && (comparer == EqualityComparer.Default || comparer == StringComparer.Ordinal || comparer == StringComparer.OrdinalIgnoreCase)) { IEqualityComparer equalityComparer = (IEqualityComparer)comparer; string[] array = (string[])(object)source.Keys.ToArray(); TValue[] values = source.Values.ToArray(); int num = int.MaxValue; int num2 = 0; ulong num3 = 0uL; string[] array2 = array; foreach (string text in array2) { if (text.Length < num) { num = text.Length; } if (text.Length > num2) { num2 = text.Length; } num3 |= (ulong)(1L << text.Length % 64); } FrozenDictionary frozenDictionary = LengthBucketsFrozenDictionary.CreateLengthBucketsFrozenDictionaryIfAppropriate(array, values, equalityComparer, num, num2); if (frozenDictionary != null) { return (FrozenDictionary)(object)frozenDictionary; } KeyAnalyzer.AnalysisResults analysisResults = KeyAnalyzer.Analyze(array, equalityComparer == StringComparer.OrdinalIgnoreCase, num, num2); frozenDictionary = (analysisResults.SubstringHashing ? (analysisResults.RightJustifiedSubstring ? ((!analysisResults.IgnoreCase) ? ((analysisResults.HashCount == 1) ? ((OrdinalStringFrozenDictionary)new OrdinalStringFrozenDictionary_RightJustifiedSingleChar(array, values, equalityComparer, analysisResults.MinimumLength, analysisResults.MaximumLengthDiff, analysisResults.HashIndex)) : ((OrdinalStringFrozenDictionary)new OrdinalStringFrozenDictionary_RightJustifiedSubstring(array, values, equalityComparer, analysisResults.MinimumLength, analysisResults.MaximumLengthDiff, analysisResults.HashIndex, analysisResults.HashCount))) : (analysisResults.AllAsciiIfIgnoreCase ? ((OrdinalStringFrozenDictionary)new OrdinalStringFrozenDictionary_RightJustifiedCaseInsensitiveAsciiSubstring(array, values, equalityComparer, analysisResults.MinimumLength, analysisResults.MaximumLengthDiff, analysisResults.HashIndex, analysisResults.HashCount)) : ((OrdinalStringFrozenDictionary)new OrdinalStringFrozenDictionary_RightJustifiedCaseInsensitiveSubstring(array, values, equalityComparer, analysisResults.MinimumLength, analysisResults.MaximumLengthDiff, analysisResults.HashIndex, analysisResults.HashCount)))) : ((!analysisResults.IgnoreCase) ? ((analysisResults.HashCount == 1) ? ((OrdinalStringFrozenDictionary)new OrdinalStringFrozenDictionary_LeftJustifiedSingleChar(array, values, equalityComparer, analysisResults.MinimumLength, analysisResults.MaximumLengthDiff, analysisResults.HashIndex)) : ((OrdinalStringFrozenDictionary)new OrdinalStringFrozenDictionary_LeftJustifiedSubstring(array, values, equalityComparer, analysisResults.MinimumLength, analysisResults.MaximumLengthDiff, analysisResults.HashIndex, analysisResults.HashCount))) : (analysisResults.AllAsciiIfIgnoreCase ? ((OrdinalStringFrozenDictionary)new OrdinalStringFrozenDictionary_LeftJustifiedCaseInsensitiveAsciiSubstring(array, values, equalityComparer, analysisResults.MinimumLength, analysisResults.MaximumLengthDiff, analysisResults.HashIndex, analysisResults.HashCount)) : ((OrdinalStringFrozenDictionary)new OrdinalStringFrozenDictionary_LeftJustifiedCaseInsensitiveSubstring(array, values, equalityComparer, analysisResults.MinimumLength, analysisResults.MaximumLengthDiff, analysisResults.HashIndex, analysisResults.HashCount))))) : ((!analysisResults.IgnoreCase) ? new OrdinalStringFrozenDictionary_Full(array, values, equalityComparer, analysisResults.MinimumLength, analysisResults.MaximumLengthDiff, num3) : (analysisResults.AllAsciiIfIgnoreCase ? ((OrdinalStringFrozenDictionary)new OrdinalStringFrozenDictionary_FullCaseInsensitiveAscii(array, values, equalityComparer, analysisResults.MinimumLength, analysisResults.MaximumLengthDiff, num3)) : ((OrdinalStringFrozenDictionary)new OrdinalStringFrozenDictionary_FullCaseInsensitive(array, values, equalityComparer, analysisResults.MinimumLength, analysisResults.MaximumLengthDiff, num3))))); return (FrozenDictionary)(object)frozenDictionary; } if (source.Count <= 4) { return new SmallFrozenDictionary(source); } return new DefaultFrozenDictionary(source); } } [DebuggerTypeProxy(typeof(ImmutableDictionaryDebuggerProxy<, >))] [DebuggerDisplay("Count = {Count}")] public abstract class FrozenDictionary : IDictionary, ICollection>, IEnumerable>, IEnumerable, IReadOnlyDictionary, IReadOnlyCollection>, IDictionary, ICollection where TKey : notnull { public struct Enumerator : IEnumerator>, IEnumerator, IDisposable { private readonly TKey[] _keys; private readonly TValue[] _values; private int _index; public readonly KeyValuePair Current { get { if ((uint)_index >= (uint)_keys.Length) { ThrowHelper.ThrowInvalidOperationException(); } return new KeyValuePair(_keys[_index], _values[_index]); } } object IEnumerator.Current => Current; internal Enumerator(TKey[] keys, TValue[] values) { _keys = keys; _values = values; _index = -1; } public bool MoveNext() { _index++; if ((uint)_index < (uint)_keys.Length) { return true; } _index = _keys.Length; return false; } void IEnumerator.Reset() { _index = -1; } void IDisposable.Dispose() { } } public static FrozenDictionary Empty { get; } = new EmptyFrozenDictionary(EqualityComparer.Default); public IEqualityComparer Comparer { get; } public ImmutableArray Keys => ImmutableCollectionsMarshal.AsImmutableArray(KeysCore); private protected abstract TKey[] KeysCore { get; } ICollection IDictionary.Keys { get { ImmutableArray keys = Keys; if (keys.Length <= 0) { return Array.Empty(); } return keys; } } IEnumerable IReadOnlyDictionary.Keys => ((IDictionary)this).Keys; ICollection IDictionary.Keys => Keys; public ImmutableArray Values => ImmutableCollectionsMarshal.AsImmutableArray(ValuesCore); private protected abstract TValue[] ValuesCore { get; } ICollection IDictionary.Values { get { ImmutableArray values = Values; if (values.Length <= 0) { return Array.Empty(); } return values; } } ICollection IDictionary.Values => Values; IEnumerable IReadOnlyDictionary.Values => ((IDictionary)this).Values; public int Count => CountCore; private protected abstract int CountCore { get; } bool ICollection>.IsReadOnly => true; bool IDictionary.IsReadOnly => true; bool IDictionary.IsFixedSize => true; bool ICollection.IsSynchronized => false; object ICollection.SyncRoot => this; object? IDictionary.this[object key] { get { ThrowHelper.ThrowIfNull(key, "key"); if (!(key is TKey key2) || !TryGetValue(key2, out var value)) { return null; } return value; } set { throw new NotSupportedException(); } } public ref readonly TValue this[TKey key] { get { ref readonly TValue valueRefOrNullRef = ref GetValueRefOrNullRef(key); if (Unsafe.IsNullRef(ref Unsafe.AsRef(in valueRefOrNullRef))) { ThrowHelper.ThrowKeyNotFoundException(key); } return ref valueRefOrNullRef; } } TValue IDictionary.this[TKey key] { get { return this[key]; } set { throw new NotSupportedException(); } } TValue IReadOnlyDictionary.this[TKey key] => this[key]; private protected FrozenDictionary(IEqualityComparer comparer) { Comparer = comparer; } public void CopyTo(KeyValuePair[] destination, int destinationIndex) { ThrowHelper.ThrowIfNull(destination, "destination"); CopyTo(destination.AsSpan(destinationIndex)); } public void CopyTo(Span> destination) { if (destination.Length < Count) { ThrowHelper.ThrowIfDestinationTooSmall(); } TKey[] keysCore = KeysCore; TValue[] valuesCore = ValuesCore; for (int i = 0; i < keysCore.Length; i++) { destination[i] = new KeyValuePair(keysCore[i], valuesCore[i]); } } void ICollection.CopyTo(Array array, int index) { ThrowHelper.ThrowIfNull(array, "array"); if (array.Rank != 1) { throw new ArgumentException(System.SR.Arg_RankMultiDimNotSupported, "array"); } if (array.GetLowerBound(0) != 0) { throw new ArgumentException(System.SR.Arg_NonZeroLowerBound, "array"); } if ((uint)index > (uint)array.Length) { throw new ArgumentOutOfRangeException("index", System.SR.ArgumentOutOfRange_NeedNonNegNum); } if (array.Length - index < Count) { throw new ArgumentException(System.SR.Arg_ArrayPlusOffTooSmall, "array"); } if (array is KeyValuePair[] array2) { using Enumerator enumerator = GetEnumerator(); while (enumerator.MoveNext()) { KeyValuePair current = enumerator.Current; array2[index++] = new KeyValuePair(current.Key, current.Value); } return; } if (array is DictionaryEntry[] array3) { using Enumerator enumerator = GetEnumerator(); while (enumerator.MoveNext()) { KeyValuePair current2 = enumerator.Current; array3[index++] = new DictionaryEntry(current2.Key, current2.Value); } return; } if (!(array is object[] array4)) { throw new ArgumentException(System.SR.Argument_IncompatibleArrayType, "array"); } try { using Enumerator enumerator = GetEnumerator(); while (enumerator.MoveNext()) { KeyValuePair current3 = enumerator.Current; array4[index++] = new KeyValuePair(current3.Key, current3.Value); } } catch (ArrayTypeMismatchException) { throw new ArgumentException(System.SR.Argument_IncompatibleArrayType, "array"); } } public ref readonly TValue GetValueRefOrNullRef(TKey key) { if (key == null) { ThrowHelper.ThrowArgumentNullException("key"); } return ref GetValueRefOrNullRefCore(key); } private protected abstract ref readonly TValue GetValueRefOrNullRefCore(TKey key); private protected virtual ref readonly TValue GetValueRefOrNullRefCore(TAlternateKey key) where TAlternateKey : notnull { return ref Unsafe.NullRef(); } public bool ContainsKey(TKey key) { return !Unsafe.IsNullRef(ref Unsafe.AsRef(in GetValueRefOrNullRef(key))); } bool IDictionary.Contains(object key) { ThrowHelper.ThrowIfNull(key, "key"); if (key is TKey key2) { return ContainsKey(key2); } return false; } bool ICollection>.Contains(KeyValuePair item) { if (TryGetValue(item.Key, out var value)) { return EqualityComparer.Default.Equals(value, item.Value); } return false; } public bool TryGetValue(TKey key, [MaybeNullWhen(false)] out TValue value) { ref readonly TValue valueRefOrNullRef = ref GetValueRefOrNullRef(key); if (!Unsafe.IsNullRef(ref Unsafe.AsRef(in valueRefOrNullRef))) { value = valueRefOrNullRef; return true; } value = default(TValue); return false; } public Enumerator GetEnumerator() { return GetEnumeratorCore(); } private protected abstract Enumerator GetEnumeratorCore(); IEnumerator> IEnumerable>.GetEnumerator() { if (Count != 0) { return GetEnumerator(); } return ((IEnumerable>)Array.Empty>()).GetEnumerator(); } IEnumerator IEnumerable.GetEnumerator() { if (Count != 0) { return GetEnumerator(); } return Array.Empty>().GetEnumerator(); } IDictionaryEnumerator IDictionary.GetEnumerator() { return new DictionaryEnumerator(GetEnumerator()); } void IDictionary.Add(TKey key, TValue value) { throw new NotSupportedException(); } void ICollection>.Add(KeyValuePair item) { throw new NotSupportedException(); } void IDictionary.Add(object key, object value) { throw new NotSupportedException(); } bool IDictionary.Remove(TKey key) { throw new NotSupportedException(); } bool ICollection>.Remove(KeyValuePair item) { throw new NotSupportedException(); } void IDictionary.Remove(object key) { throw new NotSupportedException(); } void ICollection>.Clear() { throw new NotSupportedException(); } void IDictionary.Clear() { throw new NotSupportedException(); } } internal readonly struct FrozenHashTable { private readonly struct Bucket { public readonly int StartIndex; public readonly int EndIndex; public Bucket(int startIndex, int count) { StartIndex = startIndex; EndIndex = startIndex + count - 1; } } private readonly Bucket[] _buckets; private readonly ulong _fastModMultiplier; public int Count => HashCodes.Length; internal int[] HashCodes { get; } private FrozenHashTable(int[] hashCodes, Bucket[] buckets, ulong fastModMultiplier) { HashCodes = hashCodes; _buckets = buckets; _fastModMultiplier = fastModMultiplier; } public static FrozenHashTable Create(Span hashCodes, bool hashCodesAreUnique = false) { int num = CalcNumBuckets(hashCodes, hashCodesAreUnique); ulong fastModMultiplier = System.Collections.HashHelpers.GetFastModMultiplier((uint)num); int[] array = ArrayPool.Shared.Rent(num + hashCodes.Length); Span span = array.AsSpan(0, num); Span span2 = array.AsSpan(num, hashCodes.Length); span.Fill(-1); for (int i = 0; i < hashCodes.Length; i++) { int index = (int)System.Collections.HashHelpers.FastMod((uint)hashCodes[i], (uint)span.Length, fastModMultiplier); ref int reference = ref span[index]; span2[i] = reference; reference = i; } int[] array2 = new int[hashCodes.Length]; Bucket[] array3 = new Bucket[span.Length]; int num2 = 0; for (int j = 0; j < array3.Length; j++) { int num3 = span[j]; if (num3 >= 0) { int num4 = 0; int num5 = num3; num3 = num2; while (num5 >= 0) { ref int reference2 = ref hashCodes[num5]; array2[num2] = reference2; reference2 = num2; num2++; num4++; num5 = span2[num5]; } array3[j] = new Bucket(num3, num4); } } ArrayPool.Shared.Return(array); return new FrozenHashTable(array2, array3, fastModMultiplier); } [MethodImpl(MethodImplOptions.AggressiveInlining)] public void FindMatchingEntries(int hashCode, out int startIndex, out int endIndex) { Bucket[] buckets = _buckets; ref Bucket reference = ref buckets[System.Collections.HashHelpers.FastMod((uint)hashCode, (uint)buckets.Length, _fastModMultiplier)]; startIndex = reference.StartIndex; endIndex = reference.EndIndex; } private static int CalcNumBuckets(ReadOnlySpan hashCodes, bool hashCodesAreUnique) { HashSet hashSet = null; int num = hashCodes.Length; if (!hashCodesAreUnique) { hashSet = new HashSet(); ReadOnlySpan readOnlySpan = hashCodes; for (int i = 0; i < readOnlySpan.Length; i++) { int item = readOnlySpan[i]; hashSet.Add(item); } num = hashSet.Count; } int num2 = num * 2; ReadOnlySpan primes = System.Collections.HashHelpers.Primes; int j; for (j = 0; (uint)j < (uint)primes.Length && num2 > primes[j]; j++) { } if (j >= primes.Length) { return System.Collections.HashHelpers.GetPrime(num); } int num3 = num * ((num >= 1000) ? 3 : 16); int k; for (k = j; (uint)k < (uint)primes.Length && num3 > primes[k]; k++) { } if (k < primes.Length) { num3 = primes[k - 1]; } int[] seenBuckets = ArrayPool.Shared.Rent(num3 / 32 + 1); int result = num3; int bestNumCollisions = num; int numBuckets = 0; int numCollisions = 0; for (int l = j; l < k; l++) { numBuckets = primes[l]; Array.Clear(seenBuckets, 0, Math.Min(numBuckets, seenBuckets.Length)); numCollisions = 0; if (hashSet != null && num != hashCodes.Length) { using HashSet.Enumerator enumerator = hashSet.GetEnumerator(); while (enumerator.MoveNext() && IsBucketFirstVisit(enumerator.Current)) { } } else { ReadOnlySpan readOnlySpan = hashCodes; for (int i = 0; i < readOnlySpan.Length && IsBucketFirstVisit(readOnlySpan[i]); i++) { } } if (numCollisions < bestNumCollisions) { result = numBuckets; if ((double)numCollisions / (double)num <= 0.05) { break; } bestNumCollisions = numCollisions; } } ArrayPool.Shared.Return(seenBuckets); return result; [MethodImpl(MethodImplOptions.AggressiveInlining)] bool IsBucketFirstVisit(int code) { uint num4 = (uint)code % (uint)numBuckets; if ((seenBuckets[num4 / 32] & (1 << (int)num4)) != 0) { numCollisions++; if (numCollisions >= bestNumCollisions) { return false; } } else { seenBuckets[num4 / 32] |= 1 << (int)num4; } return true; } } } public static class FrozenSet { public static FrozenSet Create([ParamCollection] scoped ReadOnlySpan source) { return Create(null, source); } public static FrozenSet Create(IEqualityComparer? equalityComparer, [ParamCollection] scoped ReadOnlySpan source) { if (source.Length == 0) { if (equalityComparer != null && equalityComparer != FrozenSet.Empty.Comparer) { return new EmptyFrozenSet(equalityComparer); } return FrozenSet.Empty; } HashSet hashSet = new HashSet(equalityComparer); ReadOnlySpan readOnlySpan = source; for (int i = 0; i < readOnlySpan.Length; i++) { T item = readOnlySpan[i]; hashSet.Add(item); } return hashSet.ToFrozenSet(equalityComparer); } public static FrozenSet ToFrozenSet(this IEnumerable source, IEqualityComparer? comparer = null) { HashSet newSet; return GetExistingFrozenOrNewSet(source, comparer, out newSet) ?? CreateFromSet(newSet); } private static FrozenSet GetExistingFrozenOrNewSet(IEnumerable source, IEqualityComparer comparer, out HashSet newSet) { ThrowHelper.ThrowIfNull(source, "source"); if (comparer == null) { comparer = EqualityComparer.Default; } if (source is FrozenSet frozenSet && frozenSet.Comparer.Equals(comparer)) { newSet = null; return frozenSet; } newSet = source as HashSet; if (newSet == null || (newSet.Count != 0 && !newSet.Comparer.Equals(comparer))) { newSet = new HashSet(source, comparer); } if (newSet.Count == 0) { if (comparer != FrozenSet.Empty.Comparer) { return new EmptyFrozenSet(comparer); } return FrozenSet.Empty; } return null; } private static FrozenSet CreateFromSet(HashSet source) { IEqualityComparer comparer = source.Comparer; if (typeof(T).IsValueType && comparer == EqualityComparer.Default) { if (source.Count <= 10) { if (Constants.IsKnownComparable()) { return new SmallValueTypeComparableFrozenSet(source); } return new SmallValueTypeDefaultComparerFrozenSet(source); } if (typeof(T) == typeof(int)) { return (FrozenSet)(object)new Int32FrozenSet((HashSet)(object)source); } return new ValueTypeDefaultComparerFrozenSet(source); } if (typeof(T) == typeof(string) && !source.Contains(default(T)) && (comparer == EqualityComparer.Default || comparer == StringComparer.Ordinal || comparer == StringComparer.OrdinalIgnoreCase)) { IEqualityComparer equalityComparer = (IEqualityComparer)comparer; HashSet obj = (HashSet)(object)source; string[] array = new string[obj.Count]; obj.CopyTo(array); int num = int.MaxValue; int num2 = 0; ulong num3 = 0uL; string[] array2 = array; foreach (string text in array2) { if (text.Length < num) { num = text.Length; } if (text.Length > num2) { num2 = text.Length; } num3 |= (ulong)(1L << text.Length % 64); } FrozenSet frozenSet = LengthBucketsFrozenSet.CreateLengthBucketsFrozenSetIfAppropriate(array, equalityComparer, num, num2); if (frozenSet != null) { return (FrozenSet)(object)frozenSet; } KeyAnalyzer.AnalysisResults analysisResults = KeyAnalyzer.Analyze(array, equalityComparer == StringComparer.OrdinalIgnoreCase, num, num2); frozenSet = (analysisResults.SubstringHashing ? (analysisResults.RightJustifiedSubstring ? ((!analysisResults.IgnoreCase) ? ((analysisResults.HashCount == 1) ? ((OrdinalStringFrozenSet)new OrdinalStringFrozenSet_RightJustifiedSingleChar(array, equalityComparer, analysisResults.MinimumLength, analysisResults.MaximumLengthDiff, analysisResults.HashIndex)) : ((OrdinalStringFrozenSet)new OrdinalStringFrozenSet_RightJustifiedSubstring(array, equalityComparer, analysisResults.MinimumLength, analysisResults.MaximumLengthDiff, analysisResults.HashIndex, analysisResults.HashCount))) : (analysisResults.AllAsciiIfIgnoreCase ? ((OrdinalStringFrozenSet)new OrdinalStringFrozenSet_RightJustifiedCaseInsensitiveAsciiSubstring(array, equalityComparer, analysisResults.MinimumLength, analysisResults.MaximumLengthDiff, analysisResults.HashIndex, analysisResults.HashCount)) : ((OrdinalStringFrozenSet)new OrdinalStringFrozenSet_RightJustifiedCaseInsensitiveSubstring(array, equalityComparer, analysisResults.MinimumLength, analysisResults.MaximumLengthDiff, analysisResults.HashIndex, analysisResults.HashCount)))) : ((!analysisResults.IgnoreCase) ? ((analysisResults.HashCount == 1) ? ((OrdinalStringFrozenSet)new OrdinalStringFrozenSet_LeftJustifiedSingleChar(array, equalityComparer, analysisResults.MinimumLength, analysisResults.MaximumLengthDiff, analysisResults.HashIndex)) : ((OrdinalStringFrozenSet)new OrdinalStringFrozenSet_LeftJustifiedSubstring(array, equalityComparer, analysisResults.MinimumLength, analysisResults.MaximumLengthDiff, analysisResults.HashIndex, analysisResults.HashCount))) : (analysisResults.AllAsciiIfIgnoreCase ? ((OrdinalStringFrozenSet)new OrdinalStringFrozenSet_LeftJustifiedCaseInsensitiveAsciiSubstring(array, equalityComparer, analysisResults.MinimumLength, analysisResults.MaximumLengthDiff, analysisResults.HashIndex, analysisResults.HashCount)) : ((OrdinalStringFrozenSet)new OrdinalStringFrozenSet_LeftJustifiedCaseInsensitiveSubstring(array, equalityComparer, analysisResults.MinimumLength, analysisResults.MaximumLengthDiff, analysisResults.HashIndex, analysisResults.HashCount))))) : ((!analysisResults.IgnoreCase) ? new OrdinalStringFrozenSet_Full(array, equalityComparer, analysisResults.MinimumLength, analysisResults.MaximumLengthDiff, num3) : (analysisResults.AllAsciiIfIgnoreCase ? ((OrdinalStringFrozenSet)new OrdinalStringFrozenSet_FullCaseInsensitiveAscii(array, equalityComparer, analysisResults.MinimumLength, analysisResults.MaximumLengthDiff, num3)) : ((OrdinalStringFrozenSet)new OrdinalStringFrozenSet_FullCaseInsensitive(array, equalityComparer, analysisResults.MinimumLength, analysisResults.MaximumLengthDiff, num3))))); return (FrozenSet)(object)frozenSet; } if (source.Count <= 4) { return new SmallFrozenSet(source); } return new DefaultFrozenSet(source); } } [CollectionBuilder(typeof(FrozenSet), "Create")] [DebuggerTypeProxy(typeof(ImmutableEnumerableDebuggerProxy<>))] [DebuggerDisplay("Count = {Count}")] public abstract class FrozenSet : ISet, ICollection, IEnumerable, IEnumerable, IReadOnlyCollection, ICollection { public struct Enumerator : IEnumerator, IEnumerator, IDisposable { private readonly T[] _entries; private int _index; public readonly T Current { get { if ((uint)_index >= (uint)_entries.Length) { ThrowHelper.ThrowInvalidOperationException(); } return _entries[_index]; } } object IEnumerator.Current => Current; internal Enumerator(T[] entries) { _entries = entries; _index = -1; } public bool MoveNext() { _index++; if ((uint)_index < (uint)_entries.Length) { return true; } _index = _entries.Length; return false; } void IEnumerator.Reset() { _index = -1; } void IDisposable.Dispose() { } } public static FrozenSet Empty { get; } = new EmptyFrozenSet(EqualityComparer.Default); public IEqualityComparer Comparer { get; } public ImmutableArray Items => ImmutableCollectionsMarshal.AsImmutableArray(ItemsCore); private protected abstract T[] ItemsCore { get; } public int Count => CountCore; private protected abstract int CountCore { get; } bool ICollection.IsReadOnly => true; bool ICollection.IsSynchronized => false; object ICollection.SyncRoot => this; private protected FrozenSet(IEqualityComparer comparer) { Comparer = comparer; } public void CopyTo(T[] destination, int destinationIndex) { ThrowHelper.ThrowIfNull(destination, "destination"); CopyTo(destination.AsSpan(destinationIndex)); } public void CopyTo(Span destination) { Items.AsSpan().CopyTo(destination); } void ICollection.CopyTo(Array array, int index) { if (array != null && array.Rank != 1) { throw new ArgumentException(System.SR.Arg_RankMultiDimNotSupported, "array"); } T[] itemsCore = ItemsCore; Array.Copy(itemsCore, 0, array, index, itemsCore.Length); } public bool Contains(T item) { return FindItemIndex(item) >= 0; } public bool TryGetValue(T equalValue, [MaybeNullWhen(false)] out T actualValue) { int num = FindItemIndex(equalValue); if (num >= 0) { actualValue = Items[num]; return true; } actualValue = default(T); return false; } private protected abstract int FindItemIndex(T item); private protected virtual int FindItemIndex(TAlternate item) { return -1; } public Enumerator GetEnumerator() { return GetEnumeratorCore(); } private protected abstract Enumerator GetEnumeratorCore(); IEnumerator IEnumerable.GetEnumerator() { if (Count != 0) { return GetEnumerator(); } return ((IEnumerable)Array.Empty()).GetEnumerator(); } IEnumerator IEnumerable.GetEnumerator() { if (Count != 0) { return GetEnumerator(); } return Array.Empty().GetEnumerator(); } bool ISet.Add(T item) { throw new NotSupportedException(); } void ISet.ExceptWith(IEnumerable other) { throw new NotSupportedException(); } void ISet.IntersectWith(IEnumerable other) { throw new NotSupportedException(); } void ISet.SymmetricExceptWith(IEnumerable other) { throw new NotSupportedException(); } void ISet.UnionWith(IEnumerable other) { throw new NotSupportedException(); } void ICollection.Add(T item) { throw new NotSupportedException(); } void ICollection.Clear() { throw new NotSupportedException(); } bool ICollection.Remove(T item) { throw new NotSupportedException(); } public bool IsProperSubsetOf(IEnumerable other) { ThrowHelper.ThrowIfNull(other, "other"); return IsProperSubsetOfCore(other); } private protected abstract bool IsProperSubsetOfCore(IEnumerable other); public bool IsProperSupersetOf(IEnumerable other) { ThrowHelper.ThrowIfNull(other, "other"); return IsProperSupersetOfCore(other); } private protected abstract bool IsProperSupersetOfCore(IEnumerable other); public bool IsSubsetOf(IEnumerable other) { ThrowHelper.ThrowIfNull(other, "other"); return IsSubsetOfCore(other); } private protected abstract bool IsSubsetOfCore(IEnumerable other); public bool IsSupersetOf(IEnumerable other) { ThrowHelper.ThrowIfNull(other, "other"); return IsSupersetOfCore(other); } private protected abstract bool IsSupersetOfCore(IEnumerable other); public bool Overlaps(IEnumerable other) { ThrowHelper.ThrowIfNull(other, "other"); return OverlapsCore(other); } private protected abstract bool OverlapsCore(IEnumerable other); public bool SetEquals(IEnumerable other) { ThrowHelper.ThrowIfNull(other, "other"); return SetEqualsCore(other); } private protected abstract bool SetEqualsCore(IEnumerable other); } internal abstract class FrozenSetInternalBase : FrozenSet where TThisWrapper : struct, FrozenSetInternalBase.IGenericSpecializedWrapper { internal interface IGenericSpecializedWrapper { int Count { get; } IEqualityComparer Comparer { get; } void Store(FrozenSet @this); int FindItemIndex(T item); Enumerator GetEnumerator(); } private readonly TThisWrapper _thisSet; protected FrozenSetInternalBase(IEqualityComparer comparer) : base(comparer) { _thisSet = default(TThisWrapper); _thisSet.Store(this); } private protected override bool IsProperSubsetOfCore(IEnumerable other) { if (other is ICollection collection) { int count = collection.Count; if (count == 0) { return false; } if (other is IReadOnlySet other2 && ComparersAreCompatible(other2)) { if (_thisSet.Count < count) { return IsSubsetOfSetWithCompatibleComparer(other2); } return false; } } var (num3, num4) = CheckUniqueAndUnfoundElements(other, returnIfUnfound: false); if (num3 == _thisSet.Count) { return num4 > 0; } return false; } private protected override bool IsProperSupersetOfCore(IEnumerable other) { if (other is ICollection collection) { int count = collection.Count; if (count == 0) { return true; } if (other is IReadOnlySet other2 && ComparersAreCompatible(other2)) { if (_thisSet.Count > count) { return ContainsAllElements(other2); } return false; } } var (num3, num4) = CheckUniqueAndUnfoundElements(other, returnIfUnfound: true); if (num3 < _thisSet.Count) { return num4 == 0; } return false; } private protected override bool IsSubsetOfCore(IEnumerable other) { if (other is IReadOnlySet readOnlySet && ComparersAreCompatible(readOnlySet)) { if (_thisSet.Count <= readOnlySet.Count) { return IsSubsetOfSetWithCompatibleComparer(readOnlySet); } return false; } var (num3, num4) = CheckUniqueAndUnfoundElements(other, returnIfUnfound: false); if (num3 == _thisSet.Count) { return num4 >= 0; } return false; } private protected override bool IsSupersetOfCore(IEnumerable other) { if (other is ICollection collection) { int count = collection.Count; if (count == 0) { return true; } if (other is IReadOnlySet other2 && count > _thisSet.Count && ComparersAreCompatible(other2)) { return false; } } return ContainsAllElements(other); } private protected override bool OverlapsCore(IEnumerable other) { foreach (T item in other) { if (_thisSet.FindItemIndex(item) >= 0) { return true; } } return false; } private protected override bool SetEqualsCore(IEnumerable other) { if (other is IReadOnlySet readOnlySet && ComparersAreCompatible(readOnlySet)) { if (_thisSet.Count == readOnlySet.Count) { return ContainsAllElements(readOnlySet); } return false; } var (num3, num4) = CheckUniqueAndUnfoundElements(other, returnIfUnfound: true); if (num3 == _thisSet.Count) { return num4 == 0; } return false; } private bool ComparersAreCompatible(IReadOnlySet other) { if (!(other is HashSet hashSet)) { if (!(other is SortedSet sortedSet)) { if (!(other is ImmutableHashSet immutableHashSet)) { if (!(other is ImmutableSortedSet immutableSortedSet)) { if (other is FrozenSet frozenSet) { return _thisSet.Comparer.Equals(frozenSet.Comparer); } return false; } return _thisSet.Comparer.Equals(immutableSortedSet.KeyComparer); } return _thisSet.Comparer.Equals(immutableHashSet.KeyComparer); } return _thisSet.Comparer.Equals(sortedSet.Comparer); } return _thisSet.Comparer.Equals(hashSet.Comparer); } private KeyValuePair CheckUniqueAndUnfoundElements(IEnumerable other, bool returnIfUnfound) { int num = _thisSet.Count / 32 + 1; int[] array = null; Span span = ((num > 128) ? ((Span)(array = ArrayPool.Shared.Rent(num))) : stackalloc int[128]); Span span2 = span; span2 = span2.Slice(0, num); span2.Clear(); int num2 = 0; int num3 = 0; foreach (T item in other) { int num4 = _thisSet.FindItemIndex(item); if (num4 >= 0) { if ((span2[num4 / 32] & (1 << num4)) == 0) { span2[num4 / 32] |= 1 << num4; num3++; } } else { num2++; if (returnIfUnfound) { break; } } } if (array != null) { ArrayPool.Shared.Return(array); } return new KeyValuePair(num3, num2); } private bool ContainsAllElements(IEnumerable other) { foreach (T item in other) { if (_thisSet.FindItemIndex(item) < 0) { return false; } } return true; } private bool IsSubsetOfSetWithCompatibleComparer(IReadOnlySet other) { foreach (T item in _thisSet) { if (!other.Contains(item)) { return false; } } return true; } } internal abstract class ItemsFrozenSet : FrozenSetInternalBase where TThisWrapper : struct, FrozenSetInternalBase.IGenericSpecializedWrapper { private protected readonly FrozenHashTable _hashTable; private protected readonly T[] _items; private protected sealed override T[] ItemsCore => _items; private protected sealed override int CountCore => _hashTable.Count; protected ItemsFrozenSet(HashSet source, bool keysAreHashCodes = false) : base(source.Comparer) { T[] array = new T[source.Count]; source.CopyTo(array); _items = new T[array.Length]; int[] array2 = ArrayPool.Shared.Rent(array.Length); Span hashCodes = array2.AsSpan(0, array.Length); for (int i = 0; i < array.Length; i++) { ref int reference = ref hashCodes[i]; T val = array[i]; reference = ((val != null) ? base.Comparer.GetHashCode(val) : 0); } _hashTable = FrozenHashTable.Create(hashCodes, keysAreHashCodes); for (int j = 0; j < hashCodes.Length; j++) { int num = hashCodes[j]; _items[num] = array[j]; } ArrayPool.Shared.Return(array2); } private protected sealed override Enumerator GetEnumeratorCore() { return new FrozenSet.Enumerator(_items); } } internal abstract class KeysAndValuesFrozenDictionary : FrozenDictionary, IDictionary, ICollection>, IEnumerable>, IEnumerable where TKey : notnull { private protected readonly FrozenHashTable _hashTable; private protected readonly TKey[] _keys; private protected readonly TValue[] _values; private protected sealed override TKey[] KeysCore => _keys; private protected sealed override TValue[] ValuesCore => _values; private protected sealed override int CountCore => _hashTable.Count; protected KeysAndValuesFrozenDictionary(Dictionary source, bool keysAreHashCodes = false) : base(source.Comparer) { KeyValuePair[] array = new KeyValuePair[source.Count]; ((ICollection>)source).CopyTo(array, 0); _keys = new TKey[array.Length]; _values = new TValue[array.Length]; int[] array2 = ArrayPool.Shared.Rent(array.Length); Span hashCodes = array2.AsSpan(0, array.Length); for (int i = 0; i < array.Length; i++) { hashCodes[i] = base.Comparer.GetHashCode(array[i].Key); } _hashTable = FrozenHashTable.Create(hashCodes, keysAreHashCodes); for (int j = 0; j < hashCodes.Length; j++) { int num = hashCodes[j]; _keys[num] = array[j].Key; _values[num] = array[j].Value; } ArrayPool.Shared.Return(array2); } private protected sealed override Enumerator GetEnumeratorCore() { return new FrozenDictionary.Enumerator(_keys, _values); } } internal sealed class SmallFrozenDictionary : FrozenDictionary where TKey : notnull { private readonly TKey[] _keys; private readonly TValue[] _values; private protected override TKey[] KeysCore => _keys; private protected override TValue[] ValuesCore => _values; private protected override int CountCore => _keys.Length; internal SmallFrozenDictionary(Dictionary source) : base(source.Comparer) { _keys = source.Keys.ToArray(); _values = source.Values.ToArray(); } private protected sealed override Enumerator GetEnumeratorCore() { return new FrozenDictionary.Enumerator(_keys, _values); } private protected override ref readonly TValue GetValueRefOrNullRefCore(TKey key) { IEqualityComparer comparer = base.Comparer; TKey[] keys = _keys; for (int i = 0; i < keys.Length; i++) { if (comparer.Equals(keys[i], key)) { return ref _values[i]; } } return ref Unsafe.NullRef(); } } internal sealed class SmallFrozenSet : FrozenSetInternalBase.GSW> { internal struct GSW : IGenericSpecializedWrapper { private SmallFrozenSet _set; public int Count => _set.Count; public IEqualityComparer Comparer => _set.Comparer; public void Store(FrozenSet set) { _set = (SmallFrozenSet)set; } public int FindItemIndex(T item) { return _set.FindItemIndex(item); } public Enumerator GetEnumerator() { return _set.GetEnumerator(); } } private readonly T[] _items; private protected override T[] ItemsCore => _items; private protected override int CountCore => _items.Length; internal SmallFrozenSet(HashSet source) : base(source.Comparer) { _items = source.ToArray(); } private protected override int FindItemIndex(T item) { T[] items = _items; for (int i = 0; i < items.Length; i++) { if (base.Comparer.Equals(item, items[i])) { return i; } } return -1; } private protected override Enumerator GetEnumeratorCore() { return new FrozenSet.Enumerator(_items); } } internal sealed class SmallValueTypeComparableFrozenDictionary : FrozenDictionary where TKey : notnull { private readonly TKey[] _keys; private readonly TValue[] _values; private readonly TKey _max; private protected override TKey[] KeysCore => _keys; private protected override TValue[] ValuesCore => _values; private protected override int CountCore => _keys.Length; internal SmallValueTypeComparableFrozenDictionary(Dictionary source) : base((IEqualityComparer)EqualityComparer.Default) { _keys = source.Keys.ToArray(); _values = source.Values.ToArray(); Array.Sort(_keys, _values); _max = _keys[_keys.Length - 1]; } private protected override Enumerator GetEnumeratorCore() { return new FrozenDictionary.Enumerator(_keys, _values); } [MethodImpl(MethodImplOptions.AggressiveInlining)] private protected override ref readonly TValue GetValueRefOrNullRefCore(TKey key) { if (Comparer.Default.Compare(key, _max) <= 0) { TKey[] keys = _keys; for (int i = 0; i < keys.Length; i++) { int num = Comparer.Default.Compare(key, keys[i]); if (num <= 0) { if (num != 0) { break; } return ref _values[i]; } } } return ref Unsafe.NullRef(); } } internal sealed class SmallValueTypeComparableFrozenSet : FrozenSetInternalBase.GSW> { internal struct GSW : IGenericSpecializedWrapper { private SmallValueTypeComparableFrozenSet _set; public int Count => _set.Count; public IEqualityComparer Comparer => _set.Comparer; public void Store(FrozenSet set) { _set = (SmallValueTypeComparableFrozenSet)set; } public int FindItemIndex(T item) { return _set.FindItemIndex(item); } public Enumerator GetEnumerator() { return _set.GetEnumerator(); } } private readonly T[] _items; private readonly T _max; private protected override T[] ItemsCore => _items; private protected override int CountCore => _items.Length; internal SmallValueTypeComparableFrozenSet(HashSet source) : base((IEqualityComparer)EqualityComparer.Default) { _items = source.ToArray(); Array.Sort(_items); _max = _items[_items.Length - 1]; } private protected override Enumerator GetEnumeratorCore() { return new FrozenSet.Enumerator(_items); } private protected override int FindItemIndex(T item) { if (Comparer.Default.Compare(item, _max) <= 0) { T[] items = _items; for (int i = 0; i < items.Length; i++) { int num = Comparer.Default.Compare(item, items[i]); if (num <= 0) { if (num != 0) { break; } return i; } } } return -1; } } internal sealed class SmallValueTypeDefaultComparerFrozenDictionary : FrozenDictionary where TKey : notnull { private readonly TKey[] _keys; private readonly TValue[] _values; private protected override TKey[] KeysCore => _keys; private protected override TValue[] ValuesCore => _values; private protected override int CountCore => _keys.Length; internal SmallValueTypeDefaultComparerFrozenDictionary(Dictionary source) : base((IEqualityComparer)EqualityComparer.Default) { _keys = source.Keys.ToArray(); _values = source.Values.ToArray(); } private protected override Enumerator GetEnumeratorCore() { return new FrozenDictionary.Enumerator(_keys, _values); } [MethodImpl(MethodImplOptions.AggressiveInlining)] private protected override ref readonly TValue GetValueRefOrNullRefCore(TKey key) { TKey[] keys = _keys; for (int i = 0; i < keys.Length; i++) { if (EqualityComparer.Default.Equals(keys[i], key)) { return ref _values[i]; } } return ref Unsafe.NullRef(); } } internal sealed class SmallValueTypeDefaultComparerFrozenSet : FrozenSetInternalBase.GSW> { internal struct GSW : IGenericSpecializedWrapper { private SmallValueTypeDefaultComparerFrozenSet _set; public int Count => _set.Count; public IEqualityComparer Comparer => _set.Comparer; public void Store(FrozenSet set) { _set = (SmallValueTypeDefaultComparerFrozenSet)set; } public int FindItemIndex(T item) { return _set.FindItemIndex(item); } public Enumerator GetEnumerator() { return _set.GetEnumerator(); } } private readonly T[] _items; private protected override T[] ItemsCore => _items; private protected override int CountCore => _items.Length; internal SmallValueTypeDefaultComparerFrozenSet(HashSet source) : base((IEqualityComparer)EqualityComparer.Default) { _items = source.ToArray(); } private protected override Enumerator GetEnumeratorCore() { return new FrozenSet.Enumerator(_items); } private protected override int FindItemIndex(T item) { T[] items = _items; for (int i = 0; i < items.Length; i++) { if (EqualityComparer.Default.Equals(item, items[i])) { return i; } } return -1; } } internal sealed class ValueTypeDefaultComparerFrozenDictionary : KeysAndValuesFrozenDictionary, IDictionary, ICollection>, IEnumerable>, IEnumerable where TKey : notnull { internal ValueTypeDefaultComparerFrozenDictionary(Dictionary source) : base(source, Constants.KeysAreHashCodes()) { } private protected override ref readonly TValue GetValueRefOrNullRefCore(TKey key) { int hashCode = EqualityComparer.Default.GetHashCode(key); _hashTable.FindMatchingEntries(hashCode, out var i, out var endIndex); for (; i <= endIndex; i++) { if (hashCode == _hashTable.HashCodes[i] && EqualityComparer.Default.Equals(key, _keys[i])) { return ref _values[i]; } } return ref Unsafe.NullRef(); } } internal sealed class ValueTypeDefaultComparerFrozenSet : ItemsFrozenSet.GSW> { internal struct GSW : IGenericSpecializedWrapper { private ValueTypeDefaultComparerFrozenSet _set; public int Count => _set.Count; public IEqualityComparer Comparer => _set.Comparer; public void Store(FrozenSet set) { _set = (ValueTypeDefaultComparerFrozenSet)set; } public int FindItemIndex(T item) { return _set.FindItemIndex(item); } public Enumerator GetEnumerator() { return _set.GetEnumerator(); } } internal ValueTypeDefaultComparerFrozenSet(HashSet source) : base(source, Constants.KeysAreHashCodes()) { } private protected override int FindItemIndex(T item) { int hashCode = EqualityComparer.Default.GetHashCode(item); _hashTable.FindMatchingEntries(hashCode, out var i, out var endIndex); for (; i <= endIndex; i++) { if (hashCode == _hashTable.HashCodes[i] && EqualityComparer.Default.Equals(item, _items[i])) { return i; } } return -1; } } internal sealed class Int32FrozenDictionary : FrozenDictionary { private readonly FrozenHashTable _hashTable; private readonly TValue[] _values; private protected override int[] KeysCore => _hashTable.HashCodes; private protected override TValue[] ValuesCore => _values; private protected override int CountCore => _hashTable.Count; internal Int32FrozenDictionary(Dictionary source) : base((IEqualityComparer)EqualityComparer.Default) { KeyValuePair[] array = new KeyValuePair[source.Count]; ((ICollection>)source).CopyTo(array, 0); _values = new TValue[array.Length]; int[] array2 = ArrayPool.Shared.Rent(array.Length); Span hashCodes = array2.AsSpan(0, array.Length); for (int i = 0; i < array.Length; i++) { hashCodes[i] = array[i].Key; } _hashTable = FrozenHashTable.Create(hashCodes, hashCodesAreUnique: true); for (int j = 0; j < hashCodes.Length; j++) { int num = hashCodes[j]; _values[num] = array[j].Value; } ArrayPool.Shared.Return(array2); } private protected override Enumerator GetEnumeratorCore() { return new FrozenDictionary.Enumerator(_hashTable.HashCodes, _values); } [MethodImpl(MethodImplOptions.AggressiveInlining)] private protected override ref readonly TValue GetValueRefOrNullRefCore(int key) { _hashTable.FindMatchingEntries(key, out var i, out var endIndex); int[] hashCodes = _hashTable.HashCodes; for (; i <= endIndex; i++) { if (key == hashCodes[i]) { return ref _values[i]; } } return ref Unsafe.NullRef(); } } internal sealed class Int32FrozenSet : FrozenSetInternalBase { internal struct GSW : IGenericSpecializedWrapper { private Int32FrozenSet _set; public int Count => _set.Count; public IEqualityComparer Comparer => _set.Comparer; public void Store(FrozenSet set) { _set = (Int32FrozenSet)set; } public int FindItemIndex(int item) { return _set.FindItemIndex(item); } public Enumerator GetEnumerator() { return _set.GetEnumerator(); } } private readonly FrozenHashTable _hashTable; private protected override int[] ItemsCore => _hashTable.HashCodes; private protected override int CountCore => _hashTable.Count; internal Int32FrozenSet(HashSet source) : base((IEqualityComparer)EqualityComparer.Default) { int count = source.Count; int[] array = ArrayPool.Shared.Rent(count); source.CopyTo(array); _hashTable = FrozenHashTable.Create(new Span(array, 0, count), hashCodesAreUnique: true); ArrayPool.Shared.Return(array); } private protected override Enumerator GetEnumeratorCore() { return new Enumerator(_hashTable.HashCodes); } private protected override int FindItemIndex(int item) { _hashTable.FindMatchingEntries(item, out var i, out var endIndex); int[] hashCodes = _hashTable.HashCodes; for (; i <= endIndex; i++) { if (item == hashCodes[i]) { return i; } } return -1; } } internal static class Hashing { private const uint Hash1Start = 352654597u; private const uint Factor = 1566083941u; public unsafe static int GetHashCodeOrdinal(ReadOnlySpan s) { int num = s.Length; fixed (char* ptr = &MemoryMarshal.GetReference(s)) { switch (num) { case 0: return 757602046; case 1: { uint num3 = (BitOperations.RotateLeft(352654597u, 5) + 352654597) ^ *ptr; return (int)(352654597 + num3 * 1566083941); } case 2: { uint num3 = (BitOperations.RotateLeft(352654597u, 5) + 352654597) ^ *ptr; num3 = (BitOperations.RotateLeft(num3, 5) + num3) ^ ptr[1]; return (int)(352654597 + num3 * 1566083941); } case 3: { uint num3 = (BitOperations.RotateLeft(352654597u, 5) + 352654597) ^ *ptr; num3 = (BitOperations.RotateLeft(num3, 5) + num3) ^ ptr[1]; num3 = (BitOperations.RotateLeft(num3, 5) + num3) ^ ptr[2]; return (int)(352654597 + num3 * 1566083941); } case 4: { uint num2 = (BitOperations.RotateLeft(352654597u, 5) + 352654597) ^ *(uint*)ptr; uint num3 = (BitOperations.RotateLeft(352654597u, 5) + 352654597) ^ *(uint*)(ptr + 2); return (int)(num2 + num3 * 1566083941); } default: { uint num2 = 352654597u; uint num3 = num2; uint* ptr2 = (uint*)ptr; while (num >= 4) { num2 = (BitOperations.RotateLeft(num2, 5) + num2) ^ *ptr2; num3 = (BitOperations.RotateLeft(num3, 5) + num3) ^ ptr2[1]; ptr2 += 2; num -= 4; } char* ptr3 = (char*)ptr2; while (num-- > 0) { num3 = (BitOperations.RotateLeft(num3, 5) + num3) ^ *(ptr3++); } return (int)(num2 + num3 * 1566083941); } } } } public unsafe static int GetHashCodeOrdinalIgnoreCaseAscii(ReadOnlySpan s) { int num = s.Length; fixed (char* ptr = &MemoryMarshal.GetReference(s)) { switch (num) { case 0: return 757602046; case 1: { uint num3 = (BitOperations.RotateLeft(352654597u, 5) + 352654597) ^ (*ptr | 0x20u); return (int)(352654597 + num3 * 1566083941); } case 2: { uint num3 = (BitOperations.RotateLeft(352654597u, 5) + 352654597) ^ (*ptr | 0x20u); num3 = (BitOperations.RotateLeft(num3, 5) + num3) ^ (ptr[1] | 0x20u); return (int)(352654597 + num3 * 1566083941); } case 3: { uint num3 = (BitOperations.RotateLeft(352654597u, 5) + 352654597) ^ (*ptr | 0x20u); num3 = (BitOperations.RotateLeft(num3, 5) + num3) ^ (ptr[1] | 0x20u); num3 = (BitOperations.RotateLeft(num3, 5) + num3) ^ (ptr[2] | 0x20u); return (int)(352654597 + num3 * 1566083941); } case 4: { uint num2 = (BitOperations.RotateLeft(352654597u, 5) + 352654597) ^ (*(uint*)ptr | 0x200020u); uint num3 = (BitOperations.RotateLeft(352654597u, 5) + 352654597) ^ (*(uint*)(ptr + 2) | 0x200020u); return (int)(num2 + num3 * 1566083941); } default: { uint num2 = 352654597u; uint num3 = num2; uint* ptr2 = (uint*)ptr; while (num >= 4) { num2 = (BitOperations.RotateLeft(num2, 5) + num2) ^ (*ptr2 | 0x200020u); num3 = (BitOperations.RotateLeft(num3, 5) + num3) ^ (ptr2[1] | 0x200020u); ptr2 += 2; num -= 4; } char* ptr3 = (char*)ptr2; while (num-- > 0) { num3 = (BitOperations.RotateLeft(num3, 5) + num3) ^ (*ptr3 | 0x200020u); ptr3++; } return (int)(num2 + num3 * 1566083941); } } } } public static int GetHashCodeOrdinalIgnoreCase(ReadOnlySpan s) { int length = s.Length; char[] array = null; Span span = ((length > 256) ? ((Span)(array = ArrayPool.Shared.Rent(length))) : stackalloc char[256]); Span destination = span; int hashCodeOrdinal = GetHashCodeOrdinal(destination[..s.ToUpperInvariant(destination)]); if (array != null) { ArrayPool.Shared.Return(array); } return hashCodeOrdinal; } } internal static class KeyAnalyzer { private delegate ReadOnlySpan GetSpan(string s, int index, int count); internal readonly struct AnalysisResults { public bool IgnoreCase { get; } public bool AllAsciiIfIgnoreCase { get; } public int HashIndex { get; } public int HashCount { get; } public int MinimumLength { get; } public int MaximumLengthDiff { get; } public bool SubstringHashing => HashCount != 0; public bool RightJustifiedSubstring => HashIndex < 0; public AnalysisResults(bool ignoreCase, bool allAsciiIfIgnoreCase, int hashIndex, int hashCount, int minLength, int maxLength) { IgnoreCase = ignoreCase; AllAsciiIfIgnoreCase = allAsciiIfIgnoreCase; HashIndex = hashIndex; HashCount = hashCount; MinimumLength = minLength; MaximumLengthDiff = maxLength - minLength; } } private abstract class SubstringComparer : IEqualityComparer { public int Index; public int Count; public bool IsLeft; public abstract bool Equals(string x, string y); public abstract int GetHashCode(string s); } private sealed class JustifiedSubstringComparer : SubstringComparer { public override bool Equals(string x, string y) { return x.AsSpan(IsLeft ? Index : (x.Length + Index), Count).SequenceEqual(y.AsSpan(IsLeft ? Index : (y.Length + Index), Count)); } public override int GetHashCode(string s) { return Hashing.GetHashCodeOrdinal(s.AsSpan(IsLeft ? Index : (s.Length + Index), Count)); } } private sealed class JustifiedCaseInsensitiveSubstringComparer : SubstringComparer { public override bool Equals(string x, string y) { return MemoryExtensions.Equals(x.AsSpan(IsLeft ? Index : (x.Length + Index), Count), y.AsSpan(IsLeft ? Index : (y.Length + Index), Count), StringComparison.OrdinalIgnoreCase); } public override int GetHashCode(string s) { return Hashing.GetHashCodeOrdinalIgnoreCase(s.AsSpan(IsLeft ? Index : (s.Length + Index), Count)); } } private sealed class JustifiedCaseInsensitiveAsciiSubstringComparer : SubstringComparer { public override bool Equals(string x, string y) { return MemoryExtensions.Equals(x.AsSpan(IsLeft ? Index : (x.Length + Index), Count), y.AsSpan(IsLeft ? Index : (y.Length + Index), Count), StringComparison.OrdinalIgnoreCase); } public override int GetHashCode(string s) { return Hashing.GetHashCodeOrdinalIgnoreCaseAscii(s.AsSpan(IsLeft ? Index : (s.Length + Index), Count)); } } public static AnalysisResults Analyze(ReadOnlySpan uniqueStrings, bool ignoreCase, int minLength, int maxLength) { bool allUniqueStringsAreConfirmedAscii = ignoreCase && AreAllAscii(uniqueStrings); if (minLength == 0 || !TryUseSubstring(uniqueStrings, allUniqueStringsAreConfirmedAscii, ignoreCase, minLength, maxLength, out var results)) { return CreateAnalysisResults(uniqueStrings, allUniqueStringsAreConfirmedAscii, ignoreCase, minLength, maxLength, 0, 0, (string s, int _, int _) => s.AsSpan()); } return results; } private static bool TryUseSubstring(ReadOnlySpan uniqueStrings, bool allUniqueStringsAreConfirmedAscii, bool ignoreCase, int minLength, int maxLength, out AnalysisResults results) { int acceptableNonUniqueCount = uniqueStrings.Length / 20; SubstringComparer substringComparer = ((!ignoreCase) ? new JustifiedSubstringComparer() : (allUniqueStringsAreConfirmedAscii ? ((SubstringComparer)new JustifiedCaseInsensitiveAsciiSubstringComparer()) : ((SubstringComparer)new JustifiedCaseInsensitiveSubstringComparer()))); HashSet set = new HashSet(substringComparer); int num = Math.Min(minLength, 8); for (int i = 1; i <= num; i++) { substringComparer.IsLeft = true; substringComparer.Count = i; for (int j = 0; j <= minLength - i; j++) { substringComparer.Index = j; if (HasSufficientUniquenessFactor(set, uniqueStrings, acceptableNonUniqueCount)) { results = CreateAnalysisResults(uniqueStrings, allUniqueStringsAreConfirmedAscii, ignoreCase, minLength, maxLength, j, i, (string s, int index, int count) => s.AsSpan(index, count)); return true; } } if (minLength == maxLength) { continue; } substringComparer.IsLeft = false; for (int k = 0; k <= minLength - i; k++) { substringComparer.Index = -k - i; if (HasSufficientUniquenessFactor(set, uniqueStrings, acceptableNonUniqueCount)) { results = CreateAnalysisResults(uniqueStrings, allUniqueStringsAreConfirmedAscii, ignoreCase, minLength, maxLength, substringComparer.Index, i, (string s, int index, int count) => s.AsSpan(s.Length + index, count)); return true; } } } results = default(AnalysisResults); return false; } private static AnalysisResults CreateAnalysisResults(ReadOnlySpan uniqueStrings, bool allUniqueStringsAreConfirmedAscii, bool ignoreCase, int minLength, int maxLength, int index, int count, GetSpan getHashString) { bool allAsciiIfIgnoreCase = true; if (ignoreCase) { bool flag = true; ReadOnlySpan readOnlySpan = uniqueStrings; for (int i = 0; i < readOnlySpan.Length; i++) { string text = readOnlySpan[i]; if (!allUniqueStringsAreConfirmedAscii && !IsAllAscii(getHashString(text, index, count))) { allAsciiIfIgnoreCase = false; flag = false; break; } if (flag && ((count > 0 && !allUniqueStringsAreConfirmedAscii && !IsAllAscii(text.AsSpan())) || ContainsAnyAsciiLetters(text.AsSpan()))) { flag = false; if (allUniqueStringsAreConfirmedAscii) { break; } } } if (flag) { ignoreCase = false; } } return new AnalysisResults(ignoreCase, allAsciiIfIgnoreCase, index, count, minLength, maxLength); } private static bool AreAllAscii(ReadOnlySpan strings) { ReadOnlySpan readOnlySpan = strings; for (int i = 0; i < readOnlySpan.Length; i++) { if (!IsAllAscii(readOnlySpan[i].AsSpan())) { return false; } } return true; } internal unsafe static bool IsAllAscii(ReadOnlySpan s) { fixed (char* ptr = s) { uint* ptr2 = (uint*)ptr; int num; for (num = s.Length; num >= 4; num -= 4) { if (!AllCharsInUInt32AreAscii(*ptr2 | ptr2[1])) { return false; } ptr2 += 2; } char* ptr3 = (char*)ptr2; while (num-- > 0) { if (*(ptr3++) >= '\u0080') { return false; } } } return true; [MethodImpl(MethodImplOptions.AggressiveInlining)] static bool AllCharsInUInt32AreAscii(uint value) { return (value & 0xFF80FF80u) == 0; } } internal static bool ContainsAnyAsciiLetters(ReadOnlySpan s) { ReadOnlySpan readOnlySpan = s; for (int i = 0; i < readOnlySpan.Length; i++) { if ((uint)((readOnlySpan[i] | 0x20) - 97) <= 25u) { return true; } } return false; } internal static bool HasSufficientUniquenessFactor(HashSet set, ReadOnlySpan uniqueStrings, int acceptableNonUniqueCount) { set.Clear(); ReadOnlySpan readOnlySpan = uniqueStrings; for (int i = 0; i < readOnlySpan.Length; i++) { string item = readOnlySpan[i]; if (!set.Add(item) && --acceptableNonUniqueCount < 0) { return false; } } return true; } } internal static class LengthBuckets { internal const int MaxPerLength = 5; private const double EmptyLengthsRatio = 0.2; internal static int[]? CreateLengthBucketsArrayIfAppropriate(string[] keys, IEqualityComparer comparer, int minLength, int maxLength) { int num = maxLength - minLength + 1; if (keys.Length / num > 5) { return null; } int num2 = num * 5; if (num2 > 2147483591) { return null; } int[] array = ArrayPool.Shared.Rent(num2); array.AsSpan(0, num2).Fill(-1); int num3 = 0; for (int i = 0; i < keys.Length; i++) { int num4 = (keys[i].Length - minLength) * 5; int num5 = num4 + 5; int j; for (j = num4; j < num5; j++) { ref int reference = ref array[j]; if (reference < 0) { if (j == num4) { num3++; } reference = i; break; } } if (j == num5) { ArrayPool.Shared.Return(array); return null; } } if ((double)num3 / (double)num < 0.2) { ArrayPool.Shared.Return(array); return null; } int[] result = array.AsSpan(0, num2).ToArray(); ArrayPool.Shared.Return(array); return result; } } internal sealed class LengthBucketsFrozenDictionary : FrozenDictionary { private readonly int[] _lengthBuckets; private readonly int _minLength; private readonly string[] _keys; private readonly TValue[] _values; private readonly bool _ignoreCase; private protected override string[] KeysCore => _keys; private protected override TValue[] ValuesCore => _values; private protected override int CountCore => _keys.Length; private LengthBucketsFrozenDictionary(string[] keys, TValue[] values, int[] lengthBuckets, int minLength, IEqualityComparer comparer) : base(comparer) { _keys = keys; _values = values; _lengthBuckets = lengthBuckets; _minLength = minLength; _ignoreCase = comparer == StringComparer.OrdinalIgnoreCase; } internal static LengthBucketsFrozenDictionary? CreateLengthBucketsFrozenDictionaryIfAppropriate(string[] keys, TValue[] values, IEqualityComparer comparer, int minLength, int maxLength) { int[] array = LengthBuckets.CreateLengthBucketsArrayIfAppropriate(keys, comparer, minLength, maxLength); if (array == null) { return null; } return new LengthBucketsFrozenDictionary(keys, values, array, minLength, comparer); } private protected override Enumerator GetEnumeratorCore() { return new FrozenDictionary.Enumerator(_keys, _values); } private protected override ref readonly TValue GetValueRefOrNullRefCore(string key) { int i = (key.Length - _minLength) * 5; int num = i + 5; int[] lengthBuckets = _lengthBuckets; if (i >= 0 && num <= lengthBuckets.Length) { string[] keys = _keys; TValue[] values = _values; if (!_ignoreCase) { for (; i < num; i++) { int num2 = lengthBuckets[i]; if ((uint)num2 >= (uint)keys.Length) { break; } if (key == keys[num2]) { return ref values[num2]; } } } else { for (; i < num; i++) { int num3 = lengthBuckets[i]; if ((uint)num3 >= (uint)keys.Length) { break; } if (StringComparer.OrdinalIgnoreCase.Equals(key, keys[num3])) { return ref values[num3]; } } } } return ref Unsafe.NullRef(); } } internal sealed class LengthBucketsFrozenSet : FrozenSetInternalBase { internal struct GSW : IGenericSpecializedWrapper { private LengthBucketsFrozenSet _set; public int Count => _set.Count; public IEqualityComparer Comparer => _set.Comparer; public void Store(FrozenSet set) { _set = (LengthBucketsFrozenSet)set; } public int FindItemIndex(string item) { return _set.FindItemIndex(item); } public Enumerator GetEnumerator() { return _set.GetEnumerator(); } } private readonly int[] _lengthBuckets; private readonly int _minLength; private readonly string[] _items; private readonly bool _ignoreCase; private protected override string[] ItemsCore => _items; private protected override int CountCore => _items.Length; private LengthBucketsFrozenSet(string[] items, int[] lengthBuckets, int minLength, IEqualityComparer comparer) : base(comparer) { _items = items; _lengthBuckets = lengthBuckets; _minLength = minLength; _ignoreCase = comparer == StringComparer.OrdinalIgnoreCase; } internal static LengthBucketsFrozenSet? CreateLengthBucketsFrozenSetIfAppropriate(string[] items, IEqualityComparer comparer, int minLength, int maxLength) { int[] array = LengthBuckets.CreateLengthBucketsArrayIfAppropriate(items, comparer, minLength, maxLength); if (array == null) { return null; } return new LengthBucketsFrozenSet(items, array, minLength, comparer); } private protected override Enumerator GetEnumeratorCore() { return new FrozenSet.Enumerator(_items); } private protected override int FindItemIndex(string? item) { if (item != null) { int i = (item.Length - _minLength) * 5; int num = i + 5; int[] lengthBuckets = _lengthBuckets; if (i >= 0 && num <= lengthBuckets.Length) { string[] items = _items; if (!_ignoreCase) { for (; i < num; i++) { int num2 = lengthBuckets[i]; if ((uint)num2 >= (uint)items.Length) { break; } if (item == items[num2]) { return num2; } } } else { for (; i < num; i++) { int num3 = lengthBuckets[i]; if ((uint)num3 >= (uint)items.Length) { break; } if (StringComparer.OrdinalIgnoreCase.Equals(item, items[num3])) { return num3; } } } } } return -1; } } internal abstract class OrdinalStringFrozenDictionary : FrozenDictionary { private readonly FrozenHashTable _hashTable; private readonly string[] _keys; private readonly TValue[] _values; private readonly int _minimumLength; private readonly int _maximumLengthDiff; private protected int HashIndex { get; } private protected int HashCount { get; } private protected override string[] KeysCore => _keys; private protected override TValue[] ValuesCore => _values; private protected override int CountCore => _hashTable.Count; internal OrdinalStringFrozenDictionary(string[] keys, TValue[] values, IEqualityComparer comparer, int minimumLength, int maximumLengthDiff, int hashIndex = -1, int hashCount = -1) : base(comparer) { _keys = new string[keys.Length]; _values = new TValue[values.Length]; _minimumLength = minimumLength; _maximumLengthDiff = maximumLengthDiff; HashIndex = hashIndex; HashCount = hashCount; int[] array = ArrayPool.Shared.Rent(keys.Length); Span hashCodes = array.AsSpan(0, keys.Length); for (int i = 0; i < keys.Length; i++) { hashCodes[i] = GetHashCode(keys[i]); } _hashTable = FrozenHashTable.Create(hashCodes); for (int j = 0; j < hashCodes.Length; j++) { int num = hashCodes[j]; _keys[num] = keys[j]; _values[num] = values[j]; } ArrayPool.Shared.Return(array); } private protected abstract bool Equals(string? x, string? y); private protected abstract bool Equals(ReadOnlySpan x, string? y); private protected abstract int GetHashCode(string s); private protected abstract int GetHashCode(ReadOnlySpan s); private protected virtual bool CheckLengthQuick(uint length) { return true; } private protected override Enumerator GetEnumeratorCore() { return new FrozenDictionary.Enumerator(_keys, _values); } [MethodImpl(MethodImplOptions.AggressiveInlining)] private protected override ref readonly TValue GetValueRefOrNullRefCore(string key) { if ((uint)(key.Length - _minimumLength) <= (uint)_maximumLengthDiff && CheckLengthQuick((uint)key.Length)) { int hashCode = GetHashCode(key); _hashTable.FindMatchingEntries(hashCode, out var i, out var endIndex); for (; i <= endIndex; i++) { if (hashCode == _hashTable.HashCodes[i] && Equals(key, _keys[i])) { return ref _values[i]; } } } return ref Unsafe.NullRef(); } } internal sealed class OrdinalStringFrozenDictionary_FullCaseInsensitiveAscii : OrdinalStringFrozenDictionary { private readonly ulong _lengthFilter; internal OrdinalStringFrozenDictionary_FullCaseInsensitiveAscii(string[] keys, TValue[] values, IEqualityComparer comparer, int minimumLength, int maximumLengthDiff, ulong lengthFilter) : base(keys, values, comparer, minimumLength, maximumLengthDiff, -1, -1) { _lengthFilter = lengthFilter; } private protected override ref readonly TValue GetValueRefOrNullRefCore(string key) { return ref base.GetValueRefOrNullRefCore(key); } private protected override ref readonly TValue GetValueRefOrNullRefCore(TAlternateKey key) { return ref base.GetValueRefOrNullRefCore(key); } private protected override bool Equals(string? x, string? y) { return StringComparer.OrdinalIgnoreCase.Equals(x, y); } private protected override bool Equals(ReadOnlySpan x, string? y) { return MemoryExtensions.Equals(x, y.AsSpan(), StringComparison.OrdinalIgnoreCase); } private protected override int GetHashCode(string s) { return Hashing.GetHashCodeOrdinalIgnoreCaseAscii(s.AsSpan()); } private protected override int GetHashCode(ReadOnlySpan s) { return Hashing.GetHashCodeOrdinalIgnoreCaseAscii(s); } private protected override bool CheckLengthQuick(uint length) { return (_lengthFilter & (ulong)(1L << (int)(length % 64))) != 0; } } internal sealed class OrdinalStringFrozenDictionary_FullCaseInsensitive : OrdinalStringFrozenDictionary { private readonly ulong _lengthFilter; internal OrdinalStringFrozenDictionary_FullCaseInsensitive(string[] keys, TValue[] values, IEqualityComparer comparer, int minimumLength, int maximumLengthDiff, ulong lengthFilter) : base(keys, values, comparer, minimumLength, maximumLengthDiff, -1, -1) { _lengthFilter = lengthFilter; } private protected override ref readonly TValue GetValueRefOrNullRefCore(string key) { return ref base.GetValueRefOrNullRefCore(key); } private protected override ref readonly TValue GetValueRefOrNullRefCore(TAlternateKey key) { return ref base.GetValueRefOrNullRefCore(key); } private protected override bool Equals(string? x, string? y) { return StringComparer.OrdinalIgnoreCase.Equals(x, y); } private protected override bool Equals(ReadOnlySpan x, string? y) { return MemoryExtensions.Equals(x, y.AsSpan(), StringComparison.OrdinalIgnoreCase); } private protected override int GetHashCode(string s) { return Hashing.GetHashCodeOrdinalIgnoreCase(s.AsSpan()); } private protected override int GetHashCode(ReadOnlySpan s) { return Hashing.GetHashCodeOrdinalIgnoreCase(s); } private protected override bool CheckLengthQuick(uint length) { return (_lengthFilter & (ulong)(1L << (int)(length % 64))) != 0; } } internal sealed class OrdinalStringFrozenDictionary_Full : OrdinalStringFrozenDictionary { private readonly ulong _lengthFilter; internal OrdinalStringFrozenDictionary_Full(string[] keys, TValue[] values, IEqualityComparer comparer, int minimumLength, int maximumLengthDiff, ulong lengthFilter) : base(keys, values, comparer, minimumLength, maximumLengthDiff, -1, -1) { _lengthFilter = lengthFilter; } private protected override ref readonly TValue GetValueRefOrNullRefCore(string key) { return ref base.GetValueRefOrNullRefCore(key); } private protected override ref readonly TValue GetValueRefOrNullRefCore(TAlternateKey key) { return ref base.GetValueRefOrNullRefCore(key); } private protected override bool Equals(string? x, string? y) { return string.Equals(x, y); } private protected override bool Equals(ReadOnlySpan x, string? y) { return x.SequenceEqual(y.AsSpan()); } private protected override int GetHashCode(string s) { return Hashing.GetHashCodeOrdinal(s.AsSpan()); } private protected override int GetHashCode(ReadOnlySpan s) { return Hashing.GetHashCodeOrdinal(s); } private protected override bool CheckLengthQuick(uint length) { return (_lengthFilter & (ulong)(1L << (int)(length % 64))) != 0; } } internal sealed class OrdinalStringFrozenDictionary_LeftJustifiedCaseInsensitiveAsciiSubstring : OrdinalStringFrozenDictionary { internal OrdinalStringFrozenDictionary_LeftJustifiedCaseInsensitiveAsciiSubstring(string[] keys, TValue[] values, IEqualityComparer comparer, int minimumLength, int maximumLengthDiff, int hashIndex, int hashCount) : base(keys, values, comparer, minimumLength, maximumLengthDiff, hashIndex, hashCount) { } private protected override ref readonly TValue GetValueRefOrNullRefCore(string key) { return ref base.GetValueRefOrNullRefCore(key); } private protected override ref readonly TValue GetValueRefOrNullRefCore(TAlternateKey key) { return ref base.GetValueRefOrNullRefCore(key); } private protected override bool Equals(string? x, string? y) { return StringComparer.OrdinalIgnoreCase.Equals(x, y); } private protected override bool Equals(ReadOnlySpan x, string? y) { return MemoryExtensions.Equals(x, y.AsSpan(), StringComparison.OrdinalIgnoreCase); } private protected override int GetHashCode(string s) { return Hashing.GetHashCodeOrdinalIgnoreCaseAscii(s.AsSpan(base.HashIndex, base.HashCount)); } private protected override int GetHashCode(ReadOnlySpan s) { return Hashing.GetHashCodeOrdinalIgnoreCaseAscii(s.Slice(base.HashIndex, base.HashCount)); } } internal sealed class OrdinalStringFrozenDictionary_LeftJustifiedCaseInsensitiveSubstring : OrdinalStringFrozenDictionary { internal OrdinalStringFrozenDictionary_LeftJustifiedCaseInsensitiveSubstring(string[] keys, TValue[] values, IEqualityComparer comparer, int minimumLength, int maximumLengthDiff, int hashIndex, int hashCount) : base(keys, values, comparer, minimumLength, maximumLengthDiff, hashIndex, hashCount) { } private protected override ref readonly TValue GetValueRefOrNullRefCore(string key) { return ref base.GetValueRefOrNullRefCore(key); } private protected override ref readonly TValue GetValueRefOrNullRefCore(TAlternateKey key) { return ref base.GetValueRefOrNullRefCore(key); } private protected override bool Equals(string? x, string? y) { return StringComparer.OrdinalIgnoreCase.Equals(x, y); } private protected override bool Equals(ReadOnlySpan x, string? y) { return MemoryExtensions.Equals(x, y.AsSpan(), StringComparison.OrdinalIgnoreCase); } private protected override int GetHashCode(string s) { return Hashing.GetHashCodeOrdinalIgnoreCase(s.AsSpan(base.HashIndex, base.HashCount)); } private protected override int GetHashCode(ReadOnlySpan s) { return Hashing.GetHashCodeOrdinalIgnoreCase(s.Slice(base.HashIndex, base.HashCount)); } } internal sealed class OrdinalStringFrozenDictionary_LeftJustifiedSingleChar : OrdinalStringFrozenDictionary { internal OrdinalStringFrozenDictionary_LeftJustifiedSingleChar(string[] keys, TValue[] values, IEqualityComparer comparer, int minimumLength, int maximumLengthDiff, int hashIndex) : base(keys, values, comparer, minimumLength, maximumLengthDiff, hashIndex, 1) { } private protected override ref readonly TValue GetValueRefOrNullRefCore(string key) { return ref base.GetValueRefOrNullRefCore(key); } private protected override ref readonly TValue GetValueRefOrNullRefCore(TAlternateKey key) { return ref base.GetValueRefOrNullRefCore(key); } private protected override bool Equals(string? x, string? y) { return string.Equals(x, y); } private protected override bool Equals(ReadOnlySpan x, string? y) { return x.SequenceEqual(y.AsSpan()); } private protected override int GetHashCode(string s) { return s[base.HashIndex]; } private protected override int GetHashCode(ReadOnlySpan s) { return s[base.HashIndex]; } } internal sealed class OrdinalStringFrozenDictionary_RightJustifiedCaseInsensitiveSubstring : OrdinalStringFrozenDictionary { internal OrdinalStringFrozenDictionary_RightJustifiedCaseInsensitiveSubstring(string[] keys, TValue[] values, IEqualityComparer comparer, int minimumLength, int maximumLengthDiff, int hashIndex, int hashCount) : base(keys, values, comparer, minimumLength, maximumLengthDiff, hashIndex, hashCount) { } private protected override ref readonly TValue GetValueRefOrNullRefCore(string key) { return ref base.GetValueRefOrNullRefCore(key); } private protected override ref readonly TValue GetValueRefOrNullRefCore(TAlternateKey key) { return ref base.GetValueRefOrNullRefCore(key); } private protected override bool Equals(string? x, string? y) { return StringComparer.OrdinalIgnoreCase.Equals(x, y); } private protected override bool Equals(ReadOnlySpan x, string? y) { return MemoryExtensions.Equals(x, y.AsSpan(), StringComparison.OrdinalIgnoreCase); } private protected override int GetHashCode(string s) { return Hashing.GetHashCodeOrdinalIgnoreCase(s.AsSpan(s.Length + base.HashIndex, base.HashCount)); } private protected override int GetHashCode(ReadOnlySpan s) { return Hashing.GetHashCodeOrdinalIgnoreCase(s.Slice(s.Length + base.HashIndex, base.HashCount)); } } internal sealed class OrdinalStringFrozenDictionary_RightJustifiedCaseInsensitiveAsciiSubstring : OrdinalStringFrozenDictionary { internal OrdinalStringFrozenDictionary_RightJustifiedCaseInsensitiveAsciiSubstring(string[] keys, TValue[] values, IEqualityComparer comparer, int minimumLength, int maximumLengthDiff, int hashIndex, int hashCount) : base(keys, values, comparer, minimumLength, maximumLengthDiff, hashIndex, hashCount) { } private protected override ref readonly TValue GetValueRefOrNullRefCore(string key) { return ref base.GetValueRefOrNullRefCore(key); } private protected override ref readonly TValue GetValueRefOrNullRefCore(TAlternateKey key) { return ref base.GetValueRefOrNullRefCore(key); } private protected override bool Equals(string? x, string? y) { return StringComparer.OrdinalIgnoreCase.Equals(x, y); } private protected override bool Equals(ReadOnlySpan x, string? y) { return MemoryExtensions.Equals(x, y.AsSpan(), StringComparison.OrdinalIgnoreCase); } private protected override int GetHashCode(string s) { return Hashing.GetHashCodeOrdinalIgnoreCaseAscii(s.AsSpan(s.Length + base.HashIndex, base.HashCount)); } private protected override int GetHashCode(ReadOnlySpan s) { return Hashing.GetHashCodeOrdinalIgnoreCaseAscii(s.Slice(s.Length + base.HashIndex, base.HashCount)); } } internal sealed class OrdinalStringFrozenDictionary_RightJustifiedSingleChar : OrdinalStringFrozenDictionary { internal OrdinalStringFrozenDictionary_RightJustifiedSingleChar(string[] keys, TValue[] values, IEqualityComparer comparer, int minimumLength, int maximumLengthDiff, int hashIndex) : base(keys, values, comparer, minimumLength, maximumLengthDiff, hashIndex, 1) { } private protected override ref readonly TValue GetValueRefOrNullRefCore(string key) { return ref base.GetValueRefOrNullRefCore(key); } private protected override ref readonly TValue GetValueRefOrNullRefCore(TAlternateKey key) { return ref base.GetValueRefOrNullRefCore(key); } private protected override bool Equals(string? x, string? y) { return string.Equals(x, y); } private protected override bool Equals(ReadOnlySpan x, string? y) { return x.SequenceEqual(y.AsSpan()); } private protected override int GetHashCode(string s) { return s[s.Length + base.HashIndex]; } private protected override int GetHashCode(ReadOnlySpan s) { return s[s.Length + base.HashIndex]; } } internal sealed class OrdinalStringFrozenDictionary_RightJustifiedSubstring : OrdinalStringFrozenDictionary { internal OrdinalStringFrozenDictionary_RightJustifiedSubstring(string[] keys, TValue[] values, IEqualityComparer comparer, int minimumLength, int maximumLengthDiff, int hashIndex, int hashCount) : base(keys, values, comparer, minimumLength, maximumLengthDiff, hashIndex, hashCount) { } private protected override ref readonly TValue GetValueRefOrNullRefCore(string key) { return ref base.GetValueRefOrNullRefCore(key); } private protected override ref readonly TValue GetValueRefOrNullRefCore(TAlternateKey key) { return ref base.GetValueRefOrNullRefCore(key); } private protected override bool Equals(string? x, string? y) { return string.Equals(x, y); } private protected override bool Equals(ReadOnlySpan x, string? y) { return x.SequenceEqual(y.AsSpan()); } private protected override int GetHashCode(string s) { return Hashing.GetHashCodeOrdinal(s.AsSpan(s.Length + base.HashIndex, base.HashCount)); } private protected override int GetHashCode(ReadOnlySpan s) { return Hashing.GetHashCodeOrdinal(s.Slice(s.Length + base.HashIndex, base.HashCount)); } } internal sealed class OrdinalStringFrozenDictionary_LeftJustifiedSubstring : OrdinalStringFrozenDictionary { internal OrdinalStringFrozenDictionary_LeftJustifiedSubstring(string[] keys, TValue[] values, IEqualityComparer comparer, int minimumLength, int maximumLengthDiff, int hashIndex, int hashCount) : base(keys, values, comparer, minimumLength, maximumLengthDiff, hashIndex, hashCount) { } private protected override ref readonly TValue GetValueRefOrNullRefCore(string key) { return ref base.GetValueRefOrNullRefCore(key); } private protected override ref readonly TValue GetValueRefOrNullRefCore(TAlternateKey key) { return ref base.GetValueRefOrNullRefCore(key); } private protected override bool Equals(string? x, string? y) { return string.Equals(x, y); } private protected override bool Equals(ReadOnlySpan x, string? y) { return x.SequenceEqual(y.AsSpan()); } private protected override int GetHashCode(string s) { return Hashing.GetHashCodeOrdinal(s.AsSpan(base.HashIndex, base.HashCount)); } private protected override int GetHashCode(ReadOnlySpan s) { return Hashing.GetHashCodeOrdinal(s.Slice(base.HashIndex, base.HashCount)); } } internal abstract class OrdinalStringFrozenSet : FrozenSetInternalBase { internal struct GSW : IGenericSpecializedWrapper { private OrdinalStringFrozenSet _set; public int Count => _set.Count; public IEqualityComparer Comparer => _set.Comparer; public void Store(FrozenSet set) { _set = (OrdinalStringFrozenSet)set; } public int FindItemIndex(string item) { return _set.FindItemIndex(item); } public Enumerator GetEnumerator() { return _set.GetEnumerator(); } } private readonly FrozenHashTable _hashTable; private readonly string[] _items; private readonly int _minimumLength; private readonly int _maximumLengthDiff; private protected int HashIndex { get; } private protected int HashCount { get; } private protected override string[] ItemsCore => _items; private protected override int CountCore => _hashTable.Count; internal OrdinalStringFrozenSet(string[] entries, IEqualityComparer comparer, int minimumLength, int maximumLengthDiff, int hashIndex = -1, int hashCount = -1) : base(comparer) { _items = new string[entries.Length]; _minimumLength = minimumLength; _maximumLengthDiff = maximumLengthDiff; HashIndex = hashIndex; HashCount = hashCount; int[] array = ArrayPool.Shared.Rent(entries.Length); Span hashCodes = array.AsSpan(0, entries.Length); for (int i = 0; i < entries.Length; i++) { hashCodes[i] = GetHashCode(entries[i]); } _hashTable = FrozenHashTable.Create(hashCodes); for (int j = 0; j < hashCodes.Length; j++) { int num = hashCodes[j]; _items[num] = entries[j]; } ArrayPool.Shared.Return(array); } private protected virtual bool Equals(string? x, string? y) { return string.Equals(x, y); } private protected virtual bool Equals(ReadOnlySpan x, string? y) { return EqualsOrdinal(x, y); } private protected abstract int GetHashCode(string s); private protected abstract int GetHashCode(ReadOnlySpan s); private protected virtual bool CheckLengthQuick(uint length) { return true; } private protected override Enumerator GetEnumeratorCore() { return new FrozenSet.Enumerator(_items); } [MethodImpl(MethodImplOptions.AggressiveInlining)] private protected override int FindItemIndex(string item) { if (item != null && (uint)(item.Length - _minimumLength) <= (uint)_maximumLengthDiff && CheckLengthQuick((uint)item.Length)) { int hashCode = GetHashCode(item); _hashTable.FindMatchingEntries(hashCode, out var i, out var endIndex); for (; i <= endIndex; i++) { if (hashCode == _hashTable.HashCodes[i] && Equals(item, _items[i])) { return i; } } } return -1; } [MethodImpl(MethodImplOptions.AggressiveInlining)] private protected static bool EqualsOrdinal(ReadOnlySpan x, string? y) { if (!x.IsEmpty || y != null) { return x.SequenceEqual(y.AsSpan()); } return false; } [MethodImpl(MethodImplOptions.AggressiveInlining)] private protected static bool EqualsOrdinalIgnoreCase(ReadOnlySpan x, string? y) { if (!x.IsEmpty || y != null) { return MemoryExtensions.Equals(x, y.AsSpan(), StringComparison.OrdinalIgnoreCase); } return false; } } internal sealed class OrdinalStringFrozenSet_FullCaseInsensitiveAscii : OrdinalStringFrozenSet { private readonly ulong _lengthFilter; internal OrdinalStringFrozenSet_FullCaseInsensitiveAscii(string[] entries, IEqualityComparer comparer, int minimumLength, int maximumLengthDiff, ulong lengthFilter) : base(entries, comparer, minimumLength, maximumLengthDiff) { _lengthFilter = lengthFilter; } private protected override int FindItemIndex(string item) { return base.FindItemIndex(item); } private protected override int FindItemIndex(TAlternate item) { return base.FindItemIndex(item); } private protected override bool Equals(string? x, string? y) { return StringComparer.OrdinalIgnoreCase.Equals(x, y); } private protected override bool Equals(ReadOnlySpan x, string? y) { return OrdinalStringFrozenSet.EqualsOrdinalIgnoreCase(x, y); } private protected override int GetHashCode(string s) { return Hashing.GetHashCodeOrdinalIgnoreCaseAscii(s.AsSpan()); } private protected override int GetHashCode(ReadOnlySpan s) { return Hashing.GetHashCodeOrdinalIgnoreCaseAscii(s); } private protected override bool CheckLengthQuick(uint length) { return (_lengthFilter & (ulong)(1L << (int)(length % 64))) != 0; } } internal sealed class OrdinalStringFrozenSet_FullCaseInsensitive : OrdinalStringFrozenSet { private readonly ulong _lengthFilter; internal OrdinalStringFrozenSet_FullCaseInsensitive(string[] entries, IEqualityComparer comparer, int minimumLength, int maximumLengthDiff, ulong lengthFilter) : base(entries, comparer, minimumLength, maximumLengthDiff) { _lengthFilter = lengthFilter; } private protected override int FindItemIndex(string item) { return base.FindItemIndex(item); } private protected override int FindItemIndex(TAlternate item) { return base.FindItemIndex(item); } private protected override bool Equals(string? x, string? y) { return StringComparer.OrdinalIgnoreCase.Equals(x, y); } private protected override bool Equals(ReadOnlySpan x, string? y) { return OrdinalStringFrozenSet.EqualsOrdinalIgnoreCase(x, y); } private protected override int GetHashCode(string s) { return Hashing.GetHashCodeOrdinalIgnoreCase(s.AsSpan()); } private protected override int GetHashCode(ReadOnlySpan s) { return Hashing.GetHashCodeOrdinalIgnoreCase(s); } private protected override bool CheckLengthQuick(uint length) { return (_lengthFilter & (ulong)(1L << (int)(length % 64))) != 0; } } internal sealed class OrdinalStringFrozenSet_Full : OrdinalStringFrozenSet { private readonly ulong _lengthFilter; internal OrdinalStringFrozenSet_Full(string[] entries, IEqualityComparer comparer, int minimumLength, int maximumLengthDiff, ulong lengthFilter) : base(entries, comparer, minimumLength, maximumLengthDiff) { _lengthFilter = lengthFilter; } private protected override int FindItemIndex(string item) { return base.FindItemIndex(item); } private protected override int FindItemIndex(TAlternate item) { return base.FindItemIndex(item); } private protected override int GetHashCode(string s) { return Hashing.GetHashCodeOrdinal(s.AsSpan()); } private protected override int GetHashCode(ReadOnlySpan s) { return Hashing.GetHashCodeOrdinal(s); } private protected override bool CheckLengthQuick(uint length) { return (_lengthFilter & (ulong)(1L << (int)(length % 64))) != 0; } } internal sealed class OrdinalStringFrozenSet_LeftJustifiedCaseInsensitiveSubstring : OrdinalStringFrozenSet { internal OrdinalStringFrozenSet_LeftJustifiedCaseInsensitiveSubstring(string[] entries, IEqualityComparer comparer, int minimumLength, int maximumLengthDiff, int hashIndex, int hashCount) : base(entries, comparer, minimumLength, maximumLengthDiff, hashIndex, hashCount) { } private protected override int FindItemIndex(string item) { return base.FindItemIndex(item); } private protected override int FindItemIndex(TAlternate item) { return base.FindItemIndex(item); } private protected override bool Equals(string? x, string? y) { return StringComparer.OrdinalIgnoreCase.Equals(x, y); } private protected override bool Equals(ReadOnlySpan x, string? y) { return OrdinalStringFrozenSet.EqualsOrdinalIgnoreCase(x, y); } private protected override int GetHashCode(string s) { return Hashing.GetHashCodeOrdinalIgnoreCase(s.AsSpan(base.HashIndex, base.HashCount)); } private protected override int GetHashCode(ReadOnlySpan s) { return Hashing.GetHashCodeOrdinalIgnoreCase(s.Slice(base.HashIndex, base.HashCount)); } } internal sealed class OrdinalStringFrozenSet_LeftJustifiedCaseInsensitiveAsciiSubstring : OrdinalStringFrozenSet { internal OrdinalStringFrozenSet_LeftJustifiedCaseInsensitiveAsciiSubstring(string[] entries, IEqualityComparer comparer, int minimumLength, int maximumLengthDiff, int hashIndex, int hashCount) : base(entries, comparer, minimumLength, maximumLengthDiff, hashIndex, hashCount) { } private protected override int FindItemIndex(string item) { return base.FindItemIndex(item); } private protected override int FindItemIndex(TAlternate item) { return base.FindItemIndex(item); } private protected override bool Equals(string? x, string? y) { return StringComparer.OrdinalIgnoreCase.Equals(x, y); } private protected override bool Equals(ReadOnlySpan x, string? y) { return OrdinalStringFrozenSet.EqualsOrdinalIgnoreCase(x, y); } private protected override int GetHashCode(string s) { return Hashing.GetHashCodeOrdinalIgnoreCaseAscii(s.AsSpan(base.HashIndex, base.HashCount)); } private protected override int GetHashCode(ReadOnlySpan s) { return Hashing.GetHashCodeOrdinalIgnoreCaseAscii(s.Slice(base.HashIndex, base.HashCount)); } } internal sealed class OrdinalStringFrozenSet_LeftJustifiedSubstring : OrdinalStringFrozenSet { internal OrdinalStringFrozenSet_LeftJustifiedSubstring(string[] entries, IEqualityComparer comparer, int minimumLength, int maximumLengthDiff, int hashIndex, int hashCount) : base(entries, comparer, minimumLength, maximumLengthDiff, hashIndex, hashCount) { } private protected override int FindItemIndex(string item) { return base.FindItemIndex(item); } private protected override int FindItemIndex(TAlternate item) { return base.FindItemIndex(item); } private protected override int GetHashCode(string s) { return Hashing.GetHashCodeOrdinal(s.AsSpan(base.HashIndex, base.HashCount)); } private protected override int GetHashCode(ReadOnlySpan s) { return Hashing.GetHashCodeOrdinal(s.Slice(base.HashIndex, base.HashCount)); } } internal sealed class OrdinalStringFrozenSet_LeftJustifiedSingleChar : OrdinalStringFrozenSet { internal OrdinalStringFrozenSet_LeftJustifiedSingleChar(string[] entries, IEqualityComparer comparer, int minimumLength, int maximumLengthDiff, int hashIndex) : base(entries, comparer, minimumLength, maximumLengthDiff, hashIndex, 1) { } private protected override int FindItemIndex(string item) { return base.FindItemIndex(item); } private protected override int FindItemIndex(TAlternate item) { return base.FindItemIndex(item); } private protected override int GetHashCode(string s) { return s[base.HashIndex]; } private protected override int GetHashCode(ReadOnlySpan s) { return s[base.HashIndex]; } } internal sealed class OrdinalStringFrozenSet_RightJustifiedCaseInsensitiveAsciiSubstring : OrdinalStringFrozenSet { internal OrdinalStringFrozenSet_RightJustifiedCaseInsensitiveAsciiSubstring(string[] entries, IEqualityComparer comparer, int minimumLength, int maximumLengthDiff, int hashIndex, int hashCount) : base(entries, comparer, minimumLength, maximumLengthDiff, hashIndex, hashCount) { } private protected override int FindItemIndex(string item) { return base.FindItemIndex(item); } private protected override int FindItemIndex(TAlternate item) { return base.FindItemIndex(item); } private protected override bool Equals(string? x, string? y) { return StringComparer.OrdinalIgnoreCase.Equals(x, y); } private protected override bool Equals(ReadOnlySpan x, string? y) { return OrdinalStringFrozenSet.EqualsOrdinalIgnoreCase(x, y); } private protected override int GetHashCode(string s) { return Hashing.GetHashCodeOrdinalIgnoreCaseAscii(s.AsSpan(s.Length + base.HashIndex, base.HashCount)); } private protected override int GetHashCode(ReadOnlySpan s) { return Hashing.GetHashCodeOrdinalIgnoreCaseAscii(s.Slice(s.Length + base.HashIndex, base.HashCount)); } } internal sealed class OrdinalStringFrozenSet_RightJustifiedCaseInsensitiveSubstring : OrdinalStringFrozenSet { internal OrdinalStringFrozenSet_RightJustifiedCaseInsensitiveSubstring(string[] entries, IEqualityComparer comparer, int minimumLength, int maximumLengthDiff, int hashIndex, int hashCount) : base(entries, comparer, minimumLength, maximumLengthDiff, hashIndex, hashCount) { } private protected override int FindItemIndex(string item) { return base.FindItemIndex(item); } private protected override int FindItemIndex(TAlternate item) { return base.FindItemIndex(item); } private protected override bool Equals(string? x, string? y) { return StringComparer.OrdinalIgnoreCase.Equals(x, y); } private protected override bool Equals(ReadOnlySpan x, string? y) { return OrdinalStringFrozenSet.EqualsOrdinalIgnoreCase(x, y); } private protected override int GetHashCode(string s) { return Hashing.GetHashCodeOrdinalIgnoreCase(s.AsSpan(s.Length + base.HashIndex, base.HashCount)); } private protected override int GetHashCode(ReadOnlySpan s) { return Hashing.GetHashCodeOrdinalIgnoreCase(s.Slice(s.Length + base.HashIndex, base.HashCount)); } } internal sealed class OrdinalStringFrozenSet_RightJustifiedSubstring : OrdinalStringFrozenSet { internal OrdinalStringFrozenSet_RightJustifiedSubstring(string[] entries, IEqualityComparer comparer, int minimumLength, int maximumLengthDiff, int hashIndex, int hashCount) : base(entries, comparer, minimumLength, maximumLengthDiff, hashIndex, hashCount) { } private protected override int FindItemIndex(string item) { return base.FindItemIndex(item); } private protected override int FindItemIndex(TAlternate item) { return base.FindItemIndex(item); } private protected override int GetHashCode(string s) { return Hashing.GetHashCodeOrdinal(s.AsSpan(s.Length + base.HashIndex, base.HashCount)); } private protected override int GetHashCode(ReadOnlySpan s) { return Hashing.GetHashCodeOrdinal(s.Slice(s.Length + base.HashIndex, base.HashCount)); } } internal sealed class OrdinalStringFrozenSet_RightJustifiedSingleChar : OrdinalStringFrozenSet { internal OrdinalStringFrozenSet_RightJustifiedSingleChar(string[] entries, IEqualityComparer comparer, int minimumLength, int maximumLengthDiff, int hashIndex) : base(entries, comparer, minimumLength, maximumLengthDiff, hashIndex, 1) { } private protected override int FindItemIndex(string item) { return base.FindItemIndex(item); } private protected override int FindItemIndex(TAlternate item) { return base.FindItemIndex(item); } private protected override int GetHashCode(string s) { return s[s.Length + base.HashIndex]; } private protected override int GetHashCode(ReadOnlySpan s) { return s[s.Length + base.HashIndex]; } } } namespace System.Collections.Generic { internal static class KeyValuePairExtensions { [EditorBrowsable(EditorBrowsableState.Never)] public static void Deconstruct(this KeyValuePair source, out TKey key, out TValue value) { key = source.Key; value = source.Value; } } internal interface IReadOnlySet : IReadOnlyCollection, IEnumerable, IEnumerable { bool Contains(T item); bool IsProperSubsetOf(IEnumerable other); bool IsProperSupersetOf(IEnumerable other); bool IsSubsetOf(IEnumerable other); bool IsSupersetOf(IEnumerable other); bool Overlaps(IEnumerable other); bool SetEquals(IEnumerable other); } [DebuggerDisplay("{Value}", Name = "[{Key}]")] internal readonly struct DebugViewDictionaryItem { [DebuggerBrowsable(DebuggerBrowsableState.Collapsed)] public TKey Key { get; } [DebuggerBrowsable(DebuggerBrowsableState.Collapsed)] public TValue Value { get; } public DebugViewDictionaryItem(TKey key, TValue value) { Key = key; Value = value; } public DebugViewDictionaryItem(KeyValuePair keyValue) { Key = keyValue.Key; Value = keyValue.Value; } } internal sealed class IDictionaryDebugView where TKey : notnull { private readonly IDictionary _dict; [DebuggerBrowsable(DebuggerBrowsableState.RootHidden)] public DebugViewDictionaryItem[] Items { get { KeyValuePair[] array = new KeyValuePair[_dict.Count]; _dict.CopyTo(array, 0); DebugViewDictionaryItem[] array2 = new DebugViewDictionaryItem[array.Length]; for (int i = 0; i < array2.Length; i++) { array2[i] = new DebugViewDictionaryItem(array[i]); } return array2; } } public IDictionaryDebugView(IDictionary dictionary) { _dict = dictionary ?? throw new ArgumentNullException("dictionary"); } } internal sealed class DictionaryKeyCollectionDebugView { private readonly ICollection _collection; [DebuggerBrowsable(DebuggerBrowsableState.RootHidden)] public TKey[] Items { get { TKey[] array = new TKey[_collection.Count]; _collection.CopyTo(array, 0); return array; } } public DictionaryKeyCollectionDebugView(ICollection collection) { _collection = collection ?? throw new ArgumentNullException("collection"); } } internal sealed class DictionaryValueCollectionDebugView { private readonly ICollection _collection; [DebuggerBrowsable(DebuggerBrowsableState.RootHidden)] public TValue[] Items { get { TValue[] array = new TValue[_collection.Count]; _collection.CopyTo(array, 0); return array; } } public DictionaryValueCollectionDebugView(ICollection collection) { _collection = collection ?? throw new ArgumentNullException("collection"); } } internal interface IHashKeyCollection { IEqualityComparer KeyComparer { get; } } internal interface ISortKeyCollection { IComparer KeyComparer { get; } } }