From 09600a3eef7d3f318051e894b36253a5a89c8423 Mon Sep 17 00:00:00 2001 From: Filip Navara Date: Thu, 21 Feb 2019 03:23:41 +0100 Subject: [PATCH] Move Thread to shared CoreLib (dotnet/corefxdotnet/coreclr#35462) Signed-off-by: dotnet-bot Commit migrated from https://github.com/dotnet/coreclr/commit/feed8ae9df458f336b2dd76cc9abe934bb2a5751 --- .../System.Private.CoreLib/src/System/AppDomain.cs | 424 +++ .../src/System/AppDomainSetup.cs | 13 + .../src/System/CannotUnloadAppDomainException.cs | 36 + .../src/System/Collections/ArrayList.cs | 2936 ++++++++++++++++++++ .../src/System/LocalDataStoreSlot.cs | 24 + .../src/System/Security/IPermission.cs | 15 + .../src/System/Security/ISecurityEncodable.cs | 12 + .../src/System/Security/IStackWalk.cs | 14 + .../src/System/Security/PermissionSet.cs | 52 + .../System/Security/Permissions/PermissionState.cs | 12 + .../src/System/Security/Principal/IIdentity.cs | 24 + .../src/System/Security/Principal/IPrincipal.cs | 21 + .../System/Security/Principal/PrincipalPolicy.cs | 19 + .../src/System/Security/SecurityElement.cs | 674 +++++ .../src/System/Threading/CompressedStack.cs | 46 + .../src/System/Threading/Thread.Unix.cs | 17 + .../src/System/Threading/Thread.Windows.cs | 18 + .../src/System/Threading/Thread.cs | 456 +++ 18 files changed, 4813 insertions(+) create mode 100644 src/libraries/System.Private.CoreLib/src/System/AppDomain.cs create mode 100644 src/libraries/System.Private.CoreLib/src/System/AppDomainSetup.cs create mode 100644 src/libraries/System.Private.CoreLib/src/System/CannotUnloadAppDomainException.cs create mode 100644 src/libraries/System.Private.CoreLib/src/System/Collections/ArrayList.cs create mode 100644 src/libraries/System.Private.CoreLib/src/System/LocalDataStoreSlot.cs create mode 100644 src/libraries/System.Private.CoreLib/src/System/Security/IPermission.cs create mode 100644 src/libraries/System.Private.CoreLib/src/System/Security/ISecurityEncodable.cs create mode 100644 src/libraries/System.Private.CoreLib/src/System/Security/IStackWalk.cs create mode 100644 src/libraries/System.Private.CoreLib/src/System/Security/PermissionSet.cs create mode 100644 src/libraries/System.Private.CoreLib/src/System/Security/Permissions/PermissionState.cs create mode 100644 src/libraries/System.Private.CoreLib/src/System/Security/Principal/IIdentity.cs create mode 100644 src/libraries/System.Private.CoreLib/src/System/Security/Principal/IPrincipal.cs create mode 100644 src/libraries/System.Private.CoreLib/src/System/Security/Principal/PrincipalPolicy.cs create mode 100644 src/libraries/System.Private.CoreLib/src/System/Security/SecurityElement.cs create mode 100644 src/libraries/System.Private.CoreLib/src/System/Threading/CompressedStack.cs create mode 100644 src/libraries/System.Private.CoreLib/src/System/Threading/Thread.Unix.cs create mode 100644 src/libraries/System.Private.CoreLib/src/System/Threading/Thread.Windows.cs create mode 100644 src/libraries/System.Private.CoreLib/src/System/Threading/Thread.cs diff --git a/src/libraries/System.Private.CoreLib/src/System/AppDomain.cs b/src/libraries/System.Private.CoreLib/src/System/AppDomain.cs new file mode 100644 index 0000000..93f6a2b --- /dev/null +++ b/src/libraries/System.Private.CoreLib/src/System/AppDomain.cs @@ -0,0 +1,424 @@ +// Licensed to the .NET Foundation under one or more agreements. +// The .NET Foundation licenses this file to you under the MIT license. +// See the LICENSE file in the project root for more information. + +#pragma warning disable CS0067 // events are declared but not used + +using System.IO; +using System.Reflection; +using System.Runtime.ExceptionServices; +using System.Runtime.Loader; +using System.Runtime.Remoting; +using System.Security; +using System.Security.Permissions; +using System.Security.Principal; +using System.Threading; + +namespace System +{ + public sealed partial class AppDomain : MarshalByRefObject + { + private static readonly AppDomain s_domain = new AppDomain(); + private readonly object _forLock = new object(); + private IPrincipal _defaultPrincipal; + private PrincipalPolicy _principalPolicy = PrincipalPolicy.NoPrincipal; + private Func s_getWindowsPrincipal; + private Func s_getUnauthenticatedPrincipal; + + private AppDomain() { } + + public static AppDomain CurrentDomain => s_domain; + + public string BaseDirectory => AppContext.BaseDirectory; + + public string RelativeSearchPath => null; + + public AppDomainSetup SetupInformation => new AppDomainSetup(); + + public PermissionSet PermissionSet => new PermissionSet(PermissionState.Unrestricted); + + public event UnhandledExceptionEventHandler UnhandledException + { + add { AppContext.UnhandledException += value; } + remove { AppContext.UnhandledException -= value; } + } + + public string DynamicDirectory => null; + + [ObsoleteAttribute("AppDomain.SetDynamicBase has been deprecated. Please investigate the use of AppDomainSetup.DynamicBase instead. https://go.microsoft.com/fwlink/?linkid=14202")] + public void SetDynamicBase(string path) { } + + public string FriendlyName + { + get + { + Assembly assembly = Assembly.GetEntryAssembly(); + return assembly != null ? assembly.GetName().Name : "DefaultDomain"; + } + } + + public int Id => 1; + + public bool IsFullyTrusted => true; + + public bool IsHomogenous => true; + + public event EventHandler DomainUnload; + + public event EventHandler FirstChanceException + { + add { AppContext.FirstChanceException += value; } + remove { AppContext.FirstChanceException -= value; } + } + + public event EventHandler ProcessExit + { + add { AppContext.ProcessExit += value; } + remove { AppContext.ProcessExit -= value; } + } + + public string ApplyPolicy(string assemblyName) + { + if (assemblyName == null) + { + throw new ArgumentNullException(nameof(assemblyName)); + } + if (assemblyName.Length == 0 || assemblyName[0] == '\0') + { + throw new ArgumentException(SR.ZeroLengthString); + } + + return assemblyName; + } + + public static AppDomain CreateDomain(string friendlyName) + { + if (friendlyName == null) throw new ArgumentNullException(nameof(friendlyName)); + throw new PlatformNotSupportedException(SR.PlatformNotSupported_AppDomains); + } + + public int ExecuteAssembly(string assemblyFile) => ExecuteAssembly(assemblyFile, null); + + public int ExecuteAssembly(string assemblyFile, string[] args) + { + if (assemblyFile == null) + { + throw new ArgumentNullException(nameof(assemblyFile)); + } + string fullPath = Path.GetFullPath(assemblyFile); + Assembly assembly = Assembly.LoadFile(fullPath); + return ExecuteAssembly(assembly, args); + } + + public int ExecuteAssembly(string assemblyFile, string[] args, byte[] hashValue, Configuration.Assemblies.AssemblyHashAlgorithm hashAlgorithm) + { + throw new PlatformNotSupportedException(SR.PlatformNotSupported_CAS); // This api is only meaningful for very specific partial trust/CAS scenarios + } + + private int ExecuteAssembly(Assembly assembly, string[] args) + { + MethodInfo entry = assembly.EntryPoint; + if (entry == null) + { + throw new MissingMethodException(SR.EntryPointNotFound + assembly.FullName); + } + + object result = entry.Invoke( + obj: null, + invokeAttr: BindingFlags.DoNotWrapExceptions, + binder: null, + parameters: entry.GetParameters().Length > 0 ? new object[] { args } : null, + culture: null); + + return result != null ? (int)result : 0; + } + + public int ExecuteAssemblyByName(AssemblyName assemblyName, params string[] args) => + ExecuteAssembly(Assembly.Load(assemblyName), args); + + public int ExecuteAssemblyByName(string assemblyName) => + ExecuteAssemblyByName(assemblyName, null); + + public int ExecuteAssemblyByName(string assemblyName, params string[] args) => + ExecuteAssembly(Assembly.Load(assemblyName), args); + + public object GetData(string name) => AppContext.GetData(name); + + public void SetData(string name, object data) => AppContext.SetData(name, data); + + public bool? IsCompatibilitySwitchSet(string value) + { + bool result; + return AppContext.TryGetSwitch(value, out result) ? result : default(bool?); + } + + public bool IsDefaultAppDomain() => true; + + public bool IsFinalizingForUnload() => false; + + public override string ToString() => + SR.AppDomain_Name + FriendlyName + Environment.NewLine + SR.AppDomain_NoContextPolicies; + + public static void Unload(AppDomain domain) + { + if (domain == null) + { + throw new ArgumentNullException(nameof(domain)); + } + throw new CannotUnloadAppDomainException(SR.NotSupported_Platform); + } + + public Assembly Load(byte[] rawAssembly) => Assembly.Load(rawAssembly); + + public Assembly Load(byte[] rawAssembly, byte[] rawSymbolStore) => Assembly.Load(rawAssembly, rawSymbolStore); + + public Assembly Load(AssemblyName assemblyRef) => Assembly.Load(assemblyRef); + + public Assembly Load(string assemblyString) => Assembly.Load(assemblyString); + + public Assembly[] ReflectionOnlyGetAssemblies() => Array.Empty(); + + public static bool MonitoringIsEnabled + { + get { return false; } + set + { + if (!value) + { + throw new ArgumentException(SR.Arg_MustBeTrue); + } + throw new PlatformNotSupportedException(SR.PlatformNotSupported_AppDomain_ResMon); + } + } + + public long MonitoringSurvivedMemorySize { get { throw CreateResMonNotAvailException(); } } + + public static long MonitoringSurvivedProcessMemorySize { get { throw CreateResMonNotAvailException(); } } + + public long MonitoringTotalAllocatedMemorySize { get { throw CreateResMonNotAvailException(); } } + + public TimeSpan MonitoringTotalProcessorTime { get { throw CreateResMonNotAvailException(); } } + + private static Exception CreateResMonNotAvailException() => new InvalidOperationException(SR.PlatformNotSupported_AppDomain_ResMon); + + [ObsoleteAttribute("AppDomain.GetCurrentThreadId has been deprecated because it does not provide a stable Id when managed threads are running on fibers (aka lightweight threads). To get a stable identifier for a managed thread, use the ManagedThreadId property on Thread. https://go.microsoft.com/fwlink/?linkid=14202", false)] + public static int GetCurrentThreadId() => Environment.CurrentManagedThreadId; + + public bool ShadowCopyFiles => false; + + [ObsoleteAttribute("AppDomain.AppendPrivatePath has been deprecated. Please investigate the use of AppDomainSetup.PrivateBinPath instead. https://go.microsoft.com/fwlink/?linkid=14202")] + public void AppendPrivatePath(string path) { } + + [ObsoleteAttribute("AppDomain.ClearPrivatePath has been deprecated. Please investigate the use of AppDomainSetup.PrivateBinPath instead. https://go.microsoft.com/fwlink/?linkid=14202")] + public void ClearPrivatePath() { } + + [ObsoleteAttribute("AppDomain.ClearShadowCopyPath has been deprecated. Please investigate the use of AppDomainSetup.ShadowCopyDirectories instead. https://go.microsoft.com/fwlink/?linkid=14202")] + public void ClearShadowCopyPath() { } + + [ObsoleteAttribute("AppDomain.SetCachePath has been deprecated. Please investigate the use of AppDomainSetup.CachePath instead. https://go.microsoft.com/fwlink/?linkid=14202")] + public void SetCachePath(string path) { } + + [ObsoleteAttribute("AppDomain.SetShadowCopyFiles has been deprecated. Please investigate the use of AppDomainSetup.ShadowCopyFiles instead. https://go.microsoft.com/fwlink/?linkid=14202")] + public void SetShadowCopyFiles() { } + + [ObsoleteAttribute("AppDomain.SetShadowCopyPath has been deprecated. Please investigate the use of AppDomainSetup.ShadowCopyDirectories instead. https://go.microsoft.com/fwlink/?linkid=14202")] + public void SetShadowCopyPath(string path) { } + + public Assembly[] GetAssemblies() => AssemblyLoadContext.GetLoadedAssemblies(); + + public event AssemblyLoadEventHandler AssemblyLoad + { + add { AssemblyLoadContext.AssemblyLoad += value; } + remove { AssemblyLoadContext.AssemblyLoad -= value; } + } + + public event ResolveEventHandler AssemblyResolve + { + add { AssemblyLoadContext.AssemblyResolve += value; } + remove { AssemblyLoadContext.AssemblyResolve -= value; } + } + + public event ResolveEventHandler ReflectionOnlyAssemblyResolve; + + public event ResolveEventHandler TypeResolve + { + add { AssemblyLoadContext.TypeResolve += value; } + remove { AssemblyLoadContext.TypeResolve -= value; } + } + + public event ResolveEventHandler ResourceResolve + { + add { AssemblyLoadContext.ResourceResolve += value; } + remove { AssemblyLoadContext.ResourceResolve -= value; } + } + + public void SetPrincipalPolicy(PrincipalPolicy policy) + { + _principalPolicy = policy; + } + + public void SetThreadPrincipal(IPrincipal principal) + { + if (principal == null) + { + throw new ArgumentNullException(nameof(principal)); + } + + lock (_forLock) + { + // Check that principal has not been set previously. + if (_defaultPrincipal != null) + { + throw new SystemException(SR.AppDomain_Policy_PrincipalTwice); + } + _defaultPrincipal = principal; + } + } + + public ObjectHandle CreateInstance(string assemblyName, string typeName) + { + if (assemblyName == null) + { + throw new ArgumentNullException(nameof(assemblyName)); + } + + return Activator.CreateInstance(assemblyName, typeName); + } + + public ObjectHandle CreateInstance(string assemblyName, string typeName, bool ignoreCase, BindingFlags bindingAttr, Binder binder, object[] args, System.Globalization.CultureInfo culture, object[] activationAttributes) + { + if (assemblyName == null) + { + throw new ArgumentNullException(nameof(assemblyName)); + } + + return Activator.CreateInstance(assemblyName, + typeName, + ignoreCase, + bindingAttr, + binder, + args, + culture, + activationAttributes); + } + + public ObjectHandle CreateInstance(string assemblyName, string typeName, object[] activationAttributes) + { + if (assemblyName == null) + { + throw new ArgumentNullException(nameof(assemblyName)); + } + + return Activator.CreateInstance(assemblyName, typeName, activationAttributes); + } + + public object CreateInstanceAndUnwrap(string assemblyName, string typeName) + { + ObjectHandle oh = CreateInstance(assemblyName, typeName); + return oh?.Unwrap(); + } + + public object CreateInstanceAndUnwrap(string assemblyName, string typeName, bool ignoreCase, BindingFlags bindingAttr, Binder binder, object[] args, System.Globalization.CultureInfo culture, object[] activationAttributes) + { + ObjectHandle oh = CreateInstance(assemblyName, + typeName, + ignoreCase, + bindingAttr, + binder, + args, + culture, + activationAttributes); + return oh?.Unwrap(); + } + + public object CreateInstanceAndUnwrap(string assemblyName, string typeName, object[] activationAttributes) + { + ObjectHandle oh = CreateInstance(assemblyName, typeName, activationAttributes); + return oh?.Unwrap(); + } + + public ObjectHandle CreateInstanceFrom(string assemblyFile, string typeName) + { + return Activator.CreateInstanceFrom(assemblyFile, typeName); + } + + public ObjectHandle CreateInstanceFrom(string assemblyFile, string typeName, bool ignoreCase, BindingFlags bindingAttr, Binder binder, object[] args, System.Globalization.CultureInfo culture, object[] activationAttributes) + { + return Activator.CreateInstanceFrom(assemblyFile, + typeName, + ignoreCase, + bindingAttr, + binder, + args, + culture, + activationAttributes); + } + + public ObjectHandle CreateInstanceFrom(string assemblyFile, string typeName, object[] activationAttributes) + { + return Activator.CreateInstanceFrom(assemblyFile, typeName, activationAttributes); + } + + public object CreateInstanceFromAndUnwrap(string assemblyFile, string typeName) + { + ObjectHandle oh = CreateInstanceFrom(assemblyFile, typeName); + return oh?.Unwrap(); + } + + public object CreateInstanceFromAndUnwrap(string assemblyFile, string typeName, bool ignoreCase, BindingFlags bindingAttr, Binder binder, object[] args, System.Globalization.CultureInfo culture, object[] activationAttributes) + { + ObjectHandle oh = CreateInstanceFrom(assemblyFile, + typeName, + ignoreCase, + bindingAttr, + binder, + args, + culture, + activationAttributes); + return oh?.Unwrap(); + } + + public object CreateInstanceFromAndUnwrap(string assemblyFile, string typeName, object[] activationAttributes) + { + ObjectHandle oh = CreateInstanceFrom(assemblyFile, typeName, activationAttributes); + return oh?.Unwrap(); + } + + public IPrincipal GetThreadPrincipal() + { + IPrincipal principal = _defaultPrincipal; + if (principal == null) + { + switch (_principalPolicy) + { + case PrincipalPolicy.UnauthenticatedPrincipal: + if (s_getUnauthenticatedPrincipal == null) + { + Type type = Type.GetType("System.Security.Principal.GenericPrincipal, System.Security.Claims", throwOnError: true); + // Don't throw PNSE if null like for WindowsPrincipal as UnauthenticatedPrincipal should + // be available on all platforms. + Volatile.Write(ref s_getUnauthenticatedPrincipal, + (Func)Delegate.CreateDelegate(typeof(Func), type, "GetDefaultInstance")); + } + + principal = s_getUnauthenticatedPrincipal(); + break; + + case PrincipalPolicy.WindowsPrincipal: + if (s_getWindowsPrincipal == null) + { + Type type = Type.GetType("System.Security.Principal.WindowsPrincipal, System.Security.Principal.Windows", throwOnError: true); + Volatile.Write(ref s_getWindowsPrincipal, + (Func)Delegate.CreateDelegate(typeof(Func), type, "GetDefaultInstance", ignoreCase: false, throwOnBindFailure: false) + ?? throw new PlatformNotSupportedException(SR.PlatformNotSupported_Principal)); + } + + principal = s_getWindowsPrincipal(); + break; + } + } + + return principal; + } + } +} diff --git a/src/libraries/System.Private.CoreLib/src/System/AppDomainSetup.cs b/src/libraries/System.Private.CoreLib/src/System/AppDomainSetup.cs new file mode 100644 index 0000000..2b8e71e --- /dev/null +++ b/src/libraries/System.Private.CoreLib/src/System/AppDomainSetup.cs @@ -0,0 +1,13 @@ +// Licensed to the .NET Foundation under one or more agreements. +// The .NET Foundation licenses this file to you under the MIT license. +// See the LICENSE file in the project root for more information. + +namespace System +{ + public sealed class AppDomainSetup + { + internal AppDomainSetup() { } + public string ApplicationBase => AppContext.BaseDirectory; + public string TargetFrameworkName => AppContext.TargetFrameworkName; + } +} diff --git a/src/libraries/System.Private.CoreLib/src/System/CannotUnloadAppDomainException.cs b/src/libraries/System.Private.CoreLib/src/System/CannotUnloadAppDomainException.cs new file mode 100644 index 0000000..f8dce02 --- /dev/null +++ b/src/libraries/System.Private.CoreLib/src/System/CannotUnloadAppDomainException.cs @@ -0,0 +1,36 @@ +// Licensed to the .NET Foundation under one or more agreements. +// The .NET Foundation licenses this file to you under the MIT license. +// See the LICENSE file in the project root for more information. + +using System.Runtime.Serialization; + +namespace System +{ + [Serializable] + [System.Runtime.CompilerServices.TypeForwardedFrom("mscorlib, Version=4.0.0.0, Culture=neutral, PublicKeyToken=b77a5c561934e089")] + public class CannotUnloadAppDomainException : SystemException + { + internal const int COR_E_CANNOTUNLOADAPPDOMAIN = unchecked((int)0x80131015); // corresponds to __HResults.COR_E_CANNOTUNLOADAPPDOMAIN in corelib + public CannotUnloadAppDomainException() + : base(SR.Arg_CannotUnloadAppDomainException) + { + HResult = COR_E_CANNOTUNLOADAPPDOMAIN; + } + + public CannotUnloadAppDomainException(string message) + : base(message) + { + HResult = COR_E_CANNOTUNLOADAPPDOMAIN; + } + + public CannotUnloadAppDomainException(string message, Exception innerException) + : base(message, innerException) + { + HResult = COR_E_CANNOTUNLOADAPPDOMAIN; + } + + protected CannotUnloadAppDomainException(SerializationInfo info, StreamingContext context) : base(info, context) + { + } + } +} diff --git a/src/libraries/System.Private.CoreLib/src/System/Collections/ArrayList.cs b/src/libraries/System.Private.CoreLib/src/System/Collections/ArrayList.cs new file mode 100644 index 0000000..124df2b --- /dev/null +++ b/src/libraries/System.Private.CoreLib/src/System/Collections/ArrayList.cs @@ -0,0 +1,2936 @@ +// Licensed to the .NET Foundation under one or more agreements. +// The .NET Foundation licenses this file to you under the MIT license. +// See the LICENSE file in the project root for more information. + +/*============================================================ +** +** Class: ArrayList +** +** Purpose: Implements a dynamically sized List as an array, +** and provides many convenience methods for treating +** an array as an IList. +** +===========================================================*/ + +using System.Security; +using System.Diagnostics; +using System.Diagnostics.CodeAnalysis; + +namespace System.Collections +{ + // Implements a variable-size List that uses an array of objects to store the + // elements. A ArrayList has a capacity, which is the allocated length + // of the internal array. As elements are added to a ArrayList, the capacity + // of the ArrayList is automatically increased as required by reallocating the + // internal array. + // + [DebuggerTypeProxy(typeof(System.Collections.ArrayList.ArrayListDebugView))] + [DebuggerDisplay("Count = {Count}")] + [Serializable] + [System.Runtime.CompilerServices.TypeForwardedFrom("mscorlib, Version=4.0.0.0, Culture=neutral, PublicKeyToken=b77a5c561934e089")] + public class ArrayList : IList, ICloneable + { + private object[] _items; // Do not rename (binary serialization) + private int _size; // Do not rename (binary serialization) + private int _version; // Do not rename (binary serialization) + + private const int _defaultCapacity = 4; + + // Copy of Array.MaxArrayLength + internal const int MaxArrayLength = 0X7FEFFFFF; + + // Note: this constructor is a bogus constructor that does nothing + // and is for use only with SyncArrayList. + internal ArrayList(bool trash) + { + } + + // Constructs a ArrayList. The list is initially empty and has a capacity + // of zero. Upon adding the first element to the list the capacity is + // increased to _defaultCapacity, and then increased in multiples of two as required. + public ArrayList() + { + _items = Array.Empty(); + } + + // Constructs a ArrayList with a given initial capacity. The list is + // initially empty, but will have room for the given number of elements + // before any reallocations are required. + // + public ArrayList(int capacity) + { + if (capacity < 0) throw new ArgumentOutOfRangeException(nameof(capacity), SR.Format(SR.ArgumentOutOfRange_MustBeNonNegNum, nameof(capacity))); + + if (capacity == 0) + _items = Array.Empty(); + else + _items = new object[capacity]; + } + + // Constructs a ArrayList, copying the contents of the given collection. The + // size and capacity of the new list will both be equal to the size of the + // given collection. + // + public ArrayList(ICollection c) + { + if (c == null) + throw new ArgumentNullException(nameof(c), SR.ArgumentNull_Collection); + + int count = c.Count; + if (count == 0) + { + _items = Array.Empty(); + } + else + { + _items = new object[count]; + AddRange(c); + } + } + + // Gets and sets the capacity of this list. The capacity is the size of + // the internal array used to hold items. When set, the internal + // array of the list is reallocated to the given capacity. + // + public virtual int Capacity + { + get + { + return _items.Length; + } + set + { + if (value < _size) + { + throw new ArgumentOutOfRangeException(nameof(value), SR.ArgumentOutOfRange_SmallCapacity); + } + + // We don't want to update the version number when we change the capacity. + // Some existing applications have dependency on this. + if (value != _items.Length) + { + if (value > 0) + { + object[] newItems = new object[value]; + if (_size > 0) + { + Array.Copy(_items, 0, newItems, 0, _size); + } + _items = newItems; + } + else + { + _items = new object[_defaultCapacity]; + } + } + } + } + + // Read-only property describing how many elements are in the List. + public virtual int Count + { + get + { + return _size; + } + } + + public virtual bool IsFixedSize + { + get { return false; } + } + + + // Is this ArrayList read-only? + public virtual bool IsReadOnly + { + get { return false; } + } + + // Is this ArrayList synchronized (thread-safe)? + public virtual bool IsSynchronized + { + get { return false; } + } + + // Synchronization root for this object. + public virtual object SyncRoot => this; + + // Sets or Gets the element at the given index. + // + public virtual object this[int index] + { + get + { + if (index < 0 || index >= _size) throw new ArgumentOutOfRangeException(nameof(index), SR.ArgumentOutOfRange_Index); + return _items[index]; + } + set + { + if (index < 0 || index >= _size) throw new ArgumentOutOfRangeException(nameof(index), SR.ArgumentOutOfRange_Index); + _items[index] = value; + _version++; + } + } + + // Creates a ArrayList wrapper for a particular IList. This does not + // copy the contents of the IList, but only wraps the IList. So any + // changes to the underlying list will affect the ArrayList. This would + // be useful if you want to Reverse a subrange of an IList, or want to + // use a generic BinarySearch or Sort method without implementing one yourself. + // However, since these methods are generic, the performance may not be + // nearly as good for some operations as they would be on the IList itself. + // + public static ArrayList Adapter(IList list) + { + if (list == null) + throw new ArgumentNullException(nameof(list)); + return new IListWrapper(list); + } + + // Adds the given object to the end of this list. The size of the list is + // increased by one. If required, the capacity of the list is doubled + // before adding the new element. + // + public virtual int Add(object value) + { + if (_size == _items.Length) EnsureCapacity(_size + 1); + _items[_size] = value; + _version++; + return _size++; + } + + // Adds the elements of the given collection to the end of this list. If + // required, the capacity of the list is increased to twice the previous + // capacity or the new size, whichever is larger. + // + public virtual void AddRange(ICollection c) + { + InsertRange(_size, c); + } + + // Searches a section of the list for a given element using a binary search + // algorithm. Elements of the list are compared to the search value using + // the given IComparer interface. If comparer is null, elements of + // the list are compared to the search value using the IComparable + // interface, which in that case must be implemented by all elements of the + // list and the given search value. This method assumes that the given + // section of the list is already sorted; if this is not the case, the + // result will be incorrect. + // + // The method returns the index of the given value in the list. If the + // list does not contain the given value, the method returns a negative + // integer. The bitwise complement operator (~) can be applied to a + // negative result to produce the index of the first element (if any) that + // is larger than the given search value. This is also the index at which + // the search value should be inserted into the list in order for the list + // to remain sorted. + // + // The method uses the Array.BinarySearch method to perform the + // search. + // + public virtual int BinarySearch(int index, int count, object value, IComparer comparer) + { + if (index < 0) + throw new ArgumentOutOfRangeException(nameof(index), SR.ArgumentOutOfRange_NeedNonNegNum); + if (count < 0) + throw new ArgumentOutOfRangeException(nameof(count), SR.ArgumentOutOfRange_NeedNonNegNum); + if (_size - index < count) + throw new ArgumentException(SR.Argument_InvalidOffLen); + + return Array.BinarySearch((Array)_items, index, count, value, comparer); + } + + public virtual int BinarySearch(object value) + { + return BinarySearch(0, Count, value, null); + } + + public virtual int BinarySearch(object value, IComparer comparer) + { + return BinarySearch(0, Count, value, comparer); + } + + + // Clears the contents of ArrayList. + public virtual void Clear() + { + if (_size > 0) + { + Array.Clear(_items, 0, _size); // Don't need to doc this but we clear the elements so that the gc can reclaim the references. + _size = 0; + } + _version++; + } + + // Clones this ArrayList, doing a shallow copy. (A copy is made of all + // Object references in the ArrayList, but the Objects pointed to + // are not cloned). + public virtual object Clone() + { + ArrayList la = new ArrayList(_size); + la._size = _size; + la._version = _version; + Array.Copy(_items, 0, la._items, 0, _size); + return la; + } + + + // Contains returns true if the specified element is in the ArrayList. + // It does a linear, O(n) search. Equality is determined by calling + // item.Equals(). + // + public virtual bool Contains(object item) + { + if (item == null) + { + for (int i = 0; i < _size; i++) + if (_items[i] == null) + return true; + return false; + } + else + { + for (int i = 0; i < _size; i++) + if ((_items[i] != null) && (_items[i].Equals(item))) + return true; + return false; + } + } + + // Copies this ArrayList into array, which must be of a + // compatible array type. + // + public virtual void CopyTo(Array array) + { + CopyTo(array, 0); + } + + // Copies this ArrayList into array, which must be of a + // compatible array type. + // + public virtual void CopyTo(Array array, int arrayIndex) + { + if ((array != null) && (array.Rank != 1)) + throw new ArgumentException(SR.Arg_RankMultiDimNotSupported, nameof(array)); + + // Delegate rest of error checking to Array.Copy. + Array.Copy(_items, 0, array, arrayIndex, _size); + } + + // Copies a section of this list to the given array at the given index. + // + // The method uses the Array.Copy method to copy the elements. + // + public virtual void CopyTo(int index, Array array, int arrayIndex, int count) + { + if (_size - index < count) + throw new ArgumentException(SR.Argument_InvalidOffLen); + if ((array != null) && (array.Rank != 1)) + throw new ArgumentException(SR.Arg_RankMultiDimNotSupported, nameof(array)); + + // Delegate rest of error checking to Array.Copy. + Array.Copy(_items, index, array, arrayIndex, count); + } + + // Ensures that the capacity of this list is at least the given minimum + // value. If the current capacity of the list is less than min, the + // capacity is increased to twice the current capacity or to min, + // whichever is larger. + private void EnsureCapacity(int min) + { + if (_items.Length < min) + { + int newCapacity = _items.Length == 0 ? _defaultCapacity : _items.Length * 2; + // Allow the list to grow to maximum possible capacity (~2G elements) before encountering overflow. + // Note that this check works even when _items.Length overflowed thanks to the (uint) cast + if ((uint)newCapacity > MaxArrayLength) newCapacity = MaxArrayLength; + if (newCapacity < min) newCapacity = min; + Capacity = newCapacity; + } + } + + // Returns a list wrapper that is fixed at the current size. Operations + // that add or remove items will fail, however, replacing items is allowed. + // + public static IList FixedSize(IList list) + { + if (list == null) + throw new ArgumentNullException(nameof(list)); + return new FixedSizeList(list); + } + + // Returns a list wrapper that is fixed at the current size. Operations + // that add or remove items will fail, however, replacing items is allowed. + // + public static ArrayList FixedSize(ArrayList list) + { + if (list == null) + throw new ArgumentNullException(nameof(list)); + return new FixedSizeArrayList(list); + } + + // Returns an enumerator for this list with the given + // permission for removal of elements. If modifications made to the list + // while an enumeration is in progress, the MoveNext and + // GetObject methods of the enumerator will throw an exception. + // + public virtual IEnumerator GetEnumerator() + { + return new ArrayListEnumeratorSimple(this); + } + + // Returns an enumerator for a section of this list with the given + // permission for removal of elements. If modifications made to the list + // while an enumeration is in progress, the MoveNext and + // GetObject methods of the enumerator will throw an exception. + // + public virtual IEnumerator GetEnumerator(int index, int count) + { + if (index < 0) + throw new ArgumentOutOfRangeException(nameof(index), SR.ArgumentOutOfRange_NeedNonNegNum); + if (count < 0) + throw new ArgumentOutOfRangeException(nameof(count), SR.ArgumentOutOfRange_NeedNonNegNum); + if (_size - index < count) + throw new ArgumentException(SR.Argument_InvalidOffLen); + return new ArrayListEnumerator(this, index, count); + } + + // Returns the index of the first occurrence of a given value in a range of + // this list. The list is searched forwards from beginning to end. + // The elements of the list are compared to the given value using the + // Object.Equals method. + // + // This method uses the Array.IndexOf method to perform the + // search. + // + public virtual int IndexOf(object value) + { + return Array.IndexOf((Array)_items, value, 0, _size); + } + + // Returns the index of the first occurrence of a given value in a range of + // this list. The list is searched forwards, starting at index + // startIndex and ending at count number of elements. The + // elements of the list are compared to the given value using the + // Object.Equals method. + // + // This method uses the Array.IndexOf method to perform the + // search. + // + public virtual int IndexOf(object value, int startIndex) + { + if (startIndex > _size) + throw new ArgumentOutOfRangeException(nameof(startIndex), SR.ArgumentOutOfRange_Index); + return Array.IndexOf((Array)_items, value, startIndex, _size - startIndex); + } + + // Returns the index of the first occurrence of a given value in a range of + // this list. The list is searched forwards, starting at index + // startIndex and up to count number of elements. The + // elements of the list are compared to the given value using the + // Object.Equals method. + // + // This method uses the Array.IndexOf method to perform the + // search. + // + public virtual int IndexOf(object value, int startIndex, int count) + { + if (startIndex > _size) + throw new ArgumentOutOfRangeException(nameof(startIndex), SR.ArgumentOutOfRange_Index); + if (count < 0 || startIndex > _size - count) throw new ArgumentOutOfRangeException(nameof(count), SR.ArgumentOutOfRange_Count); + return Array.IndexOf((Array)_items, value, startIndex, count); + } + + // Inserts an element into this list at a given index. The size of the list + // is increased by one. If required, the capacity of the list is doubled + // before inserting the new element. + // + public virtual void Insert(int index, object value) + { + // Note that insertions at the end are legal. + if (index < 0 || index > _size) throw new ArgumentOutOfRangeException(nameof(index), SR.ArgumentOutOfRange_ArrayListInsert); + + if (_size == _items.Length) EnsureCapacity(_size + 1); + if (index < _size) + { + Array.Copy(_items, index, _items, index + 1, _size - index); + } + _items[index] = value; + _size++; + _version++; + } + + // Inserts the elements of the given collection at a given index. If + // required, the capacity of the list is increased to twice the previous + // capacity or the new size, whichever is larger. Ranges may be added + // to the end of the list by setting index to the ArrayList's size. + // + public virtual void InsertRange(int index, ICollection c) + { + if (c == null) + throw new ArgumentNullException(nameof(c), SR.ArgumentNull_Collection); + if (index < 0 || index > _size) throw new ArgumentOutOfRangeException(nameof(index), SR.ArgumentOutOfRange_Index); + + int count = c.Count; + if (count > 0) + { + EnsureCapacity(_size + count); + // shift existing items + if (index < _size) + { + Array.Copy(_items, index, _items, index + count, _size - index); + } + + object[] itemsToInsert = new object[count]; + c.CopyTo(itemsToInsert, 0); + itemsToInsert.CopyTo(_items, index); + _size += count; + _version++; + } + } + + // Returns the index of the last occurrence of a given value in a range of + // this list. The list is searched backwards, starting at the end + // and ending at the first element in the list. The elements of the list + // are compared to the given value using the Object.Equals method. + // + // This method uses the Array.LastIndexOf method to perform the + // search. + // + public virtual int LastIndexOf(object value) + { + return LastIndexOf(value, _size - 1, _size); + } + + // Returns the index of the last occurrence of a given value in a range of + // this list. The list is searched backwards, starting at index + // startIndex and ending at the first element in the list. The + // elements of the list are compared to the given value using the + // Object.Equals method. + // + // This method uses the Array.LastIndexOf method to perform the + // search. + // + public virtual int LastIndexOf(object value, int startIndex) + { + if (startIndex >= _size) + throw new ArgumentOutOfRangeException(nameof(startIndex), SR.ArgumentOutOfRange_Index); + return LastIndexOf(value, startIndex, startIndex + 1); + } + + // Returns the index of the last occurrence of a given value in a range of + // this list. The list is searched backwards, starting at index + // startIndex and up to count elements. The elements of + // the list are compared to the given value using the Object.Equals + // method. + // + // This method uses the Array.LastIndexOf method to perform the + // search. + // + public virtual int LastIndexOf(object value, int startIndex, int count) + { + if (Count != 0 && (startIndex < 0 || count < 0)) + throw new ArgumentOutOfRangeException(startIndex < 0 ? nameof(startIndex) : nameof(count), SR.ArgumentOutOfRange_NeedNonNegNum); + + if (_size == 0) // Special case for an empty list + return -1; + + if (startIndex >= _size || count > startIndex + 1) + throw new ArgumentOutOfRangeException(startIndex >= _size ? nameof(startIndex) : nameof(count), SR.ArgumentOutOfRange_BiggerThanCollection); + + return Array.LastIndexOf((Array)_items, value, startIndex, count); + } + + // Returns a read-only IList wrapper for the given IList. + // + public static IList ReadOnly(IList list) + { + if (list == null) + throw new ArgumentNullException(nameof(list)); + return new ReadOnlyList(list); + } + + // Returns a read-only ArrayList wrapper for the given ArrayList. + // + public static ArrayList ReadOnly(ArrayList list) + { + if (list == null) + throw new ArgumentNullException(nameof(list)); + return new ReadOnlyArrayList(list); + } + + // Removes the element at the given index. The size of the list is + // decreased by one. + // + public virtual void Remove(object obj) + { + int index = IndexOf(obj); + if (index >= 0) + RemoveAt(index); + } + + // Removes the element at the given index. The size of the list is + // decreased by one. + // + public virtual void RemoveAt(int index) + { + if (index < 0 || index >= _size) throw new ArgumentOutOfRangeException(nameof(index), SR.ArgumentOutOfRange_Index); + + _size--; + if (index < _size) + { + Array.Copy(_items, index + 1, _items, index, _size - index); + } + _items[_size] = null; + _version++; + } + + // Removes a range of elements from this list. + // + public virtual void RemoveRange(int index, int count) + { + if (index < 0) + throw new ArgumentOutOfRangeException(nameof(index), SR.ArgumentOutOfRange_NeedNonNegNum); + if (count < 0) + throw new ArgumentOutOfRangeException(nameof(count), SR.ArgumentOutOfRange_NeedNonNegNum); + if (_size - index < count) + throw new ArgumentException(SR.Argument_InvalidOffLen); + + if (count > 0) + { + int i = _size; + _size -= count; + if (index < _size) + { + Array.Copy(_items, index + count, _items, index, _size - index); + } + while (i > _size) _items[--i] = null; + _version++; + } + } + + // Returns an IList that contains count copies of value. + // + public static ArrayList Repeat(object value, int count) + { + if (count < 0) + throw new ArgumentOutOfRangeException(nameof(count), SR.ArgumentOutOfRange_NeedNonNegNum); + + ArrayList list = new ArrayList((count > _defaultCapacity) ? count : _defaultCapacity); + for (int i = 0; i < count; i++) + list.Add(value); + return list; + } + + // Reverses the elements in this list. + public virtual void Reverse() + { + Reverse(0, Count); + } + + // Reverses the elements in a range of this list. Following a call to this + // method, an element in the range given by index and count + // which was previously located at index i will now be located at + // index index + (index + count - i - 1). + // + // This method uses the Array.Reverse method to reverse the + // elements. + // + public virtual void Reverse(int index, int count) + { + if (index < 0) + throw new ArgumentOutOfRangeException(nameof(index), SR.ArgumentOutOfRange_NeedNonNegNum); + if (count < 0) + throw new ArgumentOutOfRangeException(nameof(count), SR.ArgumentOutOfRange_NeedNonNegNum); + if (_size - index < count) + throw new ArgumentException(SR.Argument_InvalidOffLen); + + Array.Reverse(_items, index, count); + _version++; + } + + // Sets the elements starting at the given index to the elements of the + // given collection. + // + public virtual void SetRange(int index, ICollection c) + { + if (c == null) throw new ArgumentNullException(nameof(c), SR.ArgumentNull_Collection); + + int count = c.Count; + if (index < 0 || index > _size - count) throw new ArgumentOutOfRangeException(nameof(index), SR.ArgumentOutOfRange_Index); + + if (count > 0) + { + c.CopyTo(_items, index); + _version++; + } + } + + public virtual ArrayList GetRange(int index, int count) + { + if (index < 0 || count < 0) + throw new ArgumentOutOfRangeException(index < 0 ? nameof(index) : nameof(count), SR.ArgumentOutOfRange_NeedNonNegNum); + if (_size - index < count) + throw new ArgumentException(SR.Argument_InvalidOffLen); + return new Range(this, index, count); + } + + // Sorts the elements in this list. Uses the default comparer and + // Array.Sort. + public virtual void Sort() + { + Sort(0, Count, Comparer.Default); + } + + // Sorts the elements in this list. Uses Array.Sort with the + // provided comparer. + public virtual void Sort(IComparer comparer) + { + Sort(0, Count, comparer); + } + + // Sorts the elements in a section of this list. The sort compares the + // elements to each other using the given IComparer interface. If + // comparer is null, the elements are compared to each other using + // the IComparable interface, which in that case must be implemented by all + // elements of the list. + // + // This method uses the Array.Sort method to sort the elements. + // + public virtual void Sort(int index, int count, IComparer comparer) + { + if (index < 0) + throw new ArgumentOutOfRangeException(nameof(index), SR.ArgumentOutOfRange_NeedNonNegNum); + if (count < 0) + throw new ArgumentOutOfRangeException(nameof(count), SR.ArgumentOutOfRange_NeedNonNegNum); + if (_size - index < count) + throw new ArgumentException(SR.Argument_InvalidOffLen); + + Array.Sort(_items, index, count, comparer); + _version++; + } + + // Returns a thread-safe wrapper around an IList. + // + public static IList Synchronized(IList list) + { + if (list == null) + throw new ArgumentNullException(nameof(list)); + return new SyncIList(list); + } + + // Returns a thread-safe wrapper around a ArrayList. + // + public static ArrayList Synchronized(ArrayList list) + { + if (list == null) + throw new ArgumentNullException(nameof(list)); + return new SyncArrayList(list); + } + + // ToArray returns a new Object array containing the contents of the ArrayList. + // This requires copying the ArrayList, which is an O(n) operation. + public virtual object[] ToArray() + { + if (_size == 0) + return Array.Empty(); + + object[] array = new object[_size]; + Array.Copy(_items, 0, array, 0, _size); + return array; + } + + // ToArray returns a new array of a particular type containing the contents + // of the ArrayList. This requires copying the ArrayList and potentially + // downcasting all elements. This copy may fail and is an O(n) operation. + // Internally, this implementation calls Array.Copy. + // + public virtual Array ToArray(Type type) + { + if (type == null) + throw new ArgumentNullException(nameof(type)); + + Array array = Array.CreateInstance(type, _size); + Array.Copy(_items, 0, array, 0, _size); + return array; + } + + // Sets the capacity of this list to the size of the list. This method can + // be used to minimize a list's memory overhead once it is known that no + // new elements will be added to the list. To completely clear a list and + // release all memory referenced by the list, execute the following + // statements: + // + // list.Clear(); + // list.TrimToSize(); + // + public virtual void TrimToSize() + { + Capacity = _size; + } + + + // This class wraps an IList, exposing it as a ArrayList + // Note this requires reimplementing half of ArrayList... + private class IListWrapper : ArrayList + { + private IList _list; + + internal IListWrapper(IList list) + { + _list = list; + _version = 0; // list doesn't not contain a version number + } + + public override int Capacity + { + get { return _list.Count; } + set + { + if (value < Count) throw new ArgumentOutOfRangeException(nameof(value), SR.ArgumentOutOfRange_SmallCapacity); + } + } + + public override int Count + { + get { return _list.Count; } + } + + public override bool IsReadOnly + { + get { return _list.IsReadOnly; } + } + + public override bool IsFixedSize + { + get { return _list.IsFixedSize; } + } + + + public override bool IsSynchronized + { + get { return _list.IsSynchronized; } + } + + public override object this[int index] + { + get + { + return _list[index]; + } + set + { + _list[index] = value; + _version++; + } + } + + public override object SyncRoot + { + get { return _list.SyncRoot; } + } + + public override int Add(object obj) + { + int i = _list.Add(obj); + _version++; + return i; + } + + public override void AddRange(ICollection c) + { + InsertRange(Count, c); + } + + // Other overloads with automatically work + public override int BinarySearch(int index, int count, object value, IComparer comparer) + { + if (index < 0 || count < 0) + throw new ArgumentOutOfRangeException(index < 0 ? nameof(index) : nameof(count), SR.ArgumentOutOfRange_NeedNonNegNum); + if (Count - index < count) + throw new ArgumentException(SR.Argument_InvalidOffLen); + + if (comparer == null) + comparer = Comparer.Default; + + int lo = index; + int hi = index + count - 1; + int mid; + while (lo <= hi) + { + mid = (lo + hi) / 2; + int r = comparer.Compare(value, _list[mid]); + if (r == 0) + return mid; + if (r < 0) + hi = mid - 1; + else + lo = mid + 1; + } + // return bitwise complement of the first element greater than value. + // Since hi is less than lo now, ~lo is the correct item. + return ~lo; + } + + public override void Clear() + { + // If _list is an array, it will support Clear method. + // We shouldn't allow clear operation on a FixedSized ArrayList + if (_list.IsFixedSize) + { + throw new NotSupportedException(SR.NotSupported_FixedSizeCollection); + } + + _list.Clear(); + _version++; + } + + public override object Clone() + { + // This does not do a shallow copy of _list into a ArrayList! + // This clones the IListWrapper, creating another wrapper class! + return new IListWrapper(_list); + } + + public override bool Contains(object obj) + { + return _list.Contains(obj); + } + + public override void CopyTo(Array array, int index) + { + _list.CopyTo(array, index); + } + + public override void CopyTo(int index, Array array, int arrayIndex, int count) + { + if (array == null) + throw new ArgumentNullException(nameof(array)); + if (index < 0 || arrayIndex < 0) + throw new ArgumentOutOfRangeException(index < 0 ? nameof(index) : nameof(arrayIndex), SR.ArgumentOutOfRange_NeedNonNegNum); + if (count < 0) + throw new ArgumentOutOfRangeException(nameof(count), SR.ArgumentOutOfRange_NeedNonNegNum); + if (array.Length - arrayIndex < count) + throw new ArgumentException(SR.Argument_InvalidOffLen); + if (array.Rank != 1) + throw new ArgumentException(SR.Arg_RankMultiDimNotSupported, nameof(array)); + + if (_list.Count - index < count) + throw new ArgumentException(SR.Argument_InvalidOffLen); + + for (int i = index; i < index + count; i++) + array.SetValue(_list[i], arrayIndex++); + } + + public override IEnumerator GetEnumerator() + { + return _list.GetEnumerator(); + } + + public override IEnumerator GetEnumerator(int index, int count) + { + if (index < 0 || count < 0) + throw new ArgumentOutOfRangeException(index < 0 ? nameof(index) : nameof(count), SR.ArgumentOutOfRange_NeedNonNegNum); + + if (_list.Count - index < count) + throw new ArgumentException(SR.Argument_InvalidOffLen); + + return new IListWrapperEnumWrapper(this, index, count); + } + + public override int IndexOf(object value) + { + return _list.IndexOf(value); + } + + [SuppressMessage("Microsoft.Contracts", "CC1055")] // Skip extra error checking to avoid *potential* AppCompat problems. + public override int IndexOf(object value, int startIndex) + { + return IndexOf(value, startIndex, _list.Count - startIndex); + } + + public override int IndexOf(object value, int startIndex, int count) + { + if (startIndex < 0 || startIndex > Count) throw new ArgumentOutOfRangeException(nameof(startIndex), SR.ArgumentOutOfRange_Index); + if (count < 0 || startIndex > Count - count) throw new ArgumentOutOfRangeException(nameof(count), SR.ArgumentOutOfRange_Count); + + int endIndex = startIndex + count; + if (value == null) + { + for (int i = startIndex; i < endIndex; i++) + if (_list[i] == null) + return i; + return -1; + } + else + { + for (int i = startIndex; i < endIndex; i++) + if (_list[i] != null && _list[i].Equals(value)) + return i; + return -1; + } + } + + public override void Insert(int index, object obj) + { + _list.Insert(index, obj); + _version++; + } + + public override void InsertRange(int index, ICollection c) + { + if (c == null) + throw new ArgumentNullException(nameof(c), SR.ArgumentNull_Collection); + if (index < 0 || index > Count) throw new ArgumentOutOfRangeException(nameof(index), SR.ArgumentOutOfRange_Index); + + if (c.Count > 0) + { + ArrayList al = _list as ArrayList; + if (al != null) + { + // We need to special case ArrayList. + // When c is a range of _list, we need to handle this in a special way. + // See ArrayList.InsertRange for details. + al.InsertRange(index, c); + } + else + { + IEnumerator en = c.GetEnumerator(); + while (en.MoveNext()) + { + _list.Insert(index++, en.Current); + } + } + _version++; + } + } + + public override int LastIndexOf(object value) + { + return LastIndexOf(value, _list.Count - 1, _list.Count); + } + + [SuppressMessage("Microsoft.Contracts", "CC1055")] // Skip extra error checking to avoid *potential* AppCompat problems. + public override int LastIndexOf(object value, int startIndex) + { + return LastIndexOf(value, startIndex, startIndex + 1); + } + + [SuppressMessage("Microsoft.Contracts", "CC1055")] // Skip extra error checking to avoid *potential* AppCompat problems. + public override int LastIndexOf(object value, int startIndex, int count) + { + if (_list.Count == 0) + return -1; + + if (startIndex < 0 || startIndex >= _list.Count) throw new ArgumentOutOfRangeException(nameof(startIndex), SR.ArgumentOutOfRange_Index); + if (count < 0 || count > startIndex + 1) throw new ArgumentOutOfRangeException(nameof(count), SR.ArgumentOutOfRange_Count); + + int endIndex = startIndex - count + 1; + if (value == null) + { + for (int i = startIndex; i >= endIndex; i--) + if (_list[i] == null) + return i; + return -1; + } + else + { + for (int i = startIndex; i >= endIndex; i--) + if (_list[i] != null && _list[i].Equals(value)) + return i; + return -1; + } + } + + public override void Remove(object value) + { + int index = IndexOf(value); + if (index >= 0) + RemoveAt(index); + } + + public override void RemoveAt(int index) + { + _list.RemoveAt(index); + _version++; + } + + public override void RemoveRange(int index, int count) + { + if (index < 0 || count < 0) + throw new ArgumentOutOfRangeException(index < 0 ? nameof(index) : nameof(count), SR.ArgumentOutOfRange_NeedNonNegNum); + + if (_list.Count - index < count) + throw new ArgumentException(SR.Argument_InvalidOffLen); + + if (count > 0) // be consistent with ArrayList + _version++; + + while (count > 0) + { + _list.RemoveAt(index); + count--; + } + } + + public override void Reverse(int index, int count) + { + if (index < 0 || count < 0) + throw new ArgumentOutOfRangeException(index < 0 ? nameof(index) : nameof(count), SR.ArgumentOutOfRange_NeedNonNegNum); + + if (_list.Count - index < count) + throw new ArgumentException(SR.Argument_InvalidOffLen); + + int i = index; + int j = index + count - 1; + while (i < j) + { + object tmp = _list[i]; + _list[i++] = _list[j]; + _list[j--] = tmp; + } + _version++; + } + + public override void SetRange(int index, ICollection c) + { + if (c == null) + { + throw new ArgumentNullException(nameof(c), SR.ArgumentNull_Collection); + } + + if (index < 0 || index > _list.Count - c.Count) + { + throw new ArgumentOutOfRangeException(nameof(index), SR.ArgumentOutOfRange_Index); + } + + if (c.Count > 0) + { + IEnumerator en = c.GetEnumerator(); + while (en.MoveNext()) + { + _list[index++] = en.Current; + } + _version++; + } + } + + public override ArrayList GetRange(int index, int count) + { + if (index < 0 || count < 0) + throw new ArgumentOutOfRangeException(index < 0 ? nameof(index) : nameof(count), SR.ArgumentOutOfRange_NeedNonNegNum); + if (_list.Count - index < count) + throw new ArgumentException(SR.Argument_InvalidOffLen); + return new Range(this, index, count); + } + + public override void Sort(int index, int count, IComparer comparer) + { + if (index < 0 || count < 0) + throw new ArgumentOutOfRangeException(index < 0 ? nameof(index) : nameof(count), SR.ArgumentOutOfRange_NeedNonNegNum); + if (_list.Count - index < count) + throw new ArgumentException(SR.Argument_InvalidOffLen); + + object[] array = new object[count]; + CopyTo(index, array, 0, count); + Array.Sort(array, 0, count, comparer); + for (int i = 0; i < count; i++) + _list[i + index] = array[i]; + + _version++; + } + + + public override object[] ToArray() + { + if (Count == 0) + return Array.Empty(); + + object[] array = new object[Count]; + _list.CopyTo(array, 0); + return array; + } + + public override Array ToArray(Type type) + { + if (type == null) + throw new ArgumentNullException(nameof(type)); + + Array array = Array.CreateInstance(type, _list.Count); + _list.CopyTo(array, 0); + return array; + } + + public override void TrimToSize() + { + // Can't really do much here... + } + + // This is the enumerator for an IList that's been wrapped in another + // class that implements all of ArrayList's methods. + private sealed class IListWrapperEnumWrapper : IEnumerator, ICloneable + { + private IEnumerator _en; + private int _remaining; + private int _initialStartIndex; // for reset + private int _initialCount; // for reset + private bool _firstCall; // firstCall to MoveNext + + internal IListWrapperEnumWrapper(IListWrapper listWrapper, int startIndex, int count) + { + _en = listWrapper.GetEnumerator(); + _initialStartIndex = startIndex; + _initialCount = count; + while (startIndex-- > 0 && _en.MoveNext()) ; + _remaining = count; + _firstCall = true; + } + + private IListWrapperEnumWrapper() { } + + public object Clone() + { + var clone = new IListWrapperEnumWrapper(); + clone._en = (IEnumerator)((ICloneable)_en).Clone(); + clone._initialStartIndex = _initialStartIndex; + clone._initialCount = _initialCount; + clone._remaining = _remaining; + clone._firstCall = _firstCall; + return clone; + } + + public bool MoveNext() + { + if (_firstCall) + { + _firstCall = false; + return _remaining-- > 0 && _en.MoveNext(); + } + if (_remaining < 0) + return false; + bool r = _en.MoveNext(); + return r && _remaining-- > 0; + } + + public object Current + { + get + { + if (_firstCall) + throw new InvalidOperationException(SR.InvalidOperation_EnumNotStarted); + if (_remaining < 0) + throw new InvalidOperationException(SR.InvalidOperation_EnumEnded); + return _en.Current; + } + } + + public void Reset() + { + _en.Reset(); + int startIndex = _initialStartIndex; + while (startIndex-- > 0 && _en.MoveNext()) ; + _remaining = _initialCount; + _firstCall = true; + } + } + } + + private class SyncArrayList : ArrayList + { + private ArrayList _list; + private object _root; + + internal SyncArrayList(ArrayList list) + : base(false) + { + _list = list; + _root = list.SyncRoot; + } + + public override int Capacity + { + get + { + lock (_root) + { + return _list.Capacity; + } + } + [SuppressMessage("Microsoft.Contracts", "CC1055")] // Skip extra error checking to avoid *potential* AppCompat problems. + set + { + lock (_root) + { + _list.Capacity = value; + } + } + } + + public override int Count + { + get { lock (_root) { return _list.Count; } } + } + + public override bool IsReadOnly + { + get { return _list.IsReadOnly; } + } + + public override bool IsFixedSize + { + get { return _list.IsFixedSize; } + } + + + public override bool IsSynchronized + { + get { return true; } + } + + public override object this[int index] + { + get + { + lock (_root) + { + return _list[index]; + } + } + set + { + lock (_root) + { + _list[index] = value; + } + } + } + + public override object SyncRoot + { + get { return _root; } + } + + public override int Add(object value) + { + lock (_root) + { + return _list.Add(value); + } + } + + public override void AddRange(ICollection c) + { + lock (_root) + { + _list.AddRange(c); + } + } + + public override int BinarySearch(object value) + { + lock (_root) + { + return _list.BinarySearch(value); + } + } + + public override int BinarySearch(object value, IComparer comparer) + { + lock (_root) + { + return _list.BinarySearch(value, comparer); + } + } + + [SuppressMessage("Microsoft.Contracts", "CC1055")] // Skip extra error checking to avoid *potential* AppCompat problems. + public override int BinarySearch(int index, int count, object value, IComparer comparer) + { + lock (_root) + { + return _list.BinarySearch(index, count, value, comparer); + } + } + + public override void Clear() + { + lock (_root) + { + _list.Clear(); + } + } + + public override object Clone() + { + lock (_root) + { + return new SyncArrayList((ArrayList)_list.Clone()); + } + } + + public override bool Contains(object item) + { + lock (_root) + { + return _list.Contains(item); + } + } + + public override void CopyTo(Array array) + { + lock (_root) + { + _list.CopyTo(array); + } + } + + public override void CopyTo(Array array, int index) + { + lock (_root) + { + _list.CopyTo(array, index); + } + } + + [SuppressMessage("Microsoft.Contracts", "CC1055")] // Skip extra error checking to avoid *potential* AppCompat problems. + public override void CopyTo(int index, Array array, int arrayIndex, int count) + { + lock (_root) + { + _list.CopyTo(index, array, arrayIndex, count); + } + } + + public override IEnumerator GetEnumerator() + { + lock (_root) + { + return _list.GetEnumerator(); + } + } + + [SuppressMessage("Microsoft.Contracts", "CC1055")] // Skip extra error checking to avoid *potential* AppCompat problems. + public override IEnumerator GetEnumerator(int index, int count) + { + lock (_root) + { + return _list.GetEnumerator(index, count); + } + } + + public override int IndexOf(object value) + { + lock (_root) + { + return _list.IndexOf(value); + } + } + + [SuppressMessage("Microsoft.Contracts", "CC1055")] // Skip extra error checking to avoid *potential* AppCompat problems. + public override int IndexOf(object value, int startIndex) + { + lock (_root) + { + return _list.IndexOf(value, startIndex); + } + } + + [SuppressMessage("Microsoft.Contracts", "CC1055")] // Skip extra error checking to avoid *potential* AppCompat problems. + public override int IndexOf(object value, int startIndex, int count) + { + lock (_root) + { + return _list.IndexOf(value, startIndex, count); + } + } + + public override void Insert(int index, object value) + { + lock (_root) + { + _list.Insert(index, value); + } + } + + [SuppressMessage("Microsoft.Contracts", "CC1055")] // Skip extra error checking to avoid *potential* AppCompat problems. + public override void InsertRange(int index, ICollection c) + { + lock (_root) + { + _list.InsertRange(index, c); + } + } + + public override int LastIndexOf(object value) + { + lock (_root) + { + return _list.LastIndexOf(value); + } + } + + [SuppressMessage("Microsoft.Contracts", "CC1055")] // Skip extra error checking to avoid *potential* AppCompat problems. + public override int LastIndexOf(object value, int startIndex) + { + lock (_root) + { + return _list.LastIndexOf(value, startIndex); + } + } + + [SuppressMessage("Microsoft.Contracts", "CC1055")] // Skip extra error checking to avoid *potential* AppCompat problems. + public override int LastIndexOf(object value, int startIndex, int count) + { + lock (_root) + { + return _list.LastIndexOf(value, startIndex, count); + } + } + + public override void Remove(object value) + { + lock (_root) + { + _list.Remove(value); + } + } + + public override void RemoveAt(int index) + { + lock (_root) + { + _list.RemoveAt(index); + } + } + + [SuppressMessage("Microsoft.Contracts", "CC1055")] // Skip extra error checking to avoid *potential* AppCompat problems. + public override void RemoveRange(int index, int count) + { + lock (_root) + { + _list.RemoveRange(index, count); + } + } + + [SuppressMessage("Microsoft.Contracts", "CC1055")] // Skip extra error checking to avoid *potential* AppCompat problems. + public override void Reverse(int index, int count) + { + lock (_root) + { + _list.Reverse(index, count); + } + } + + [SuppressMessage("Microsoft.Contracts", "CC1055")] // Skip extra error checking to avoid *potential* AppCompat problems. + public override void SetRange(int index, ICollection c) + { + lock (_root) + { + _list.SetRange(index, c); + } + } + + [SuppressMessage("Microsoft.Contracts", "CC1055")] // Skip extra error checking to avoid *potential* AppCompat problems. + public override ArrayList GetRange(int index, int count) + { + lock (_root) + { + return _list.GetRange(index, count); + } + } + + public override void Sort() + { + lock (_root) + { + _list.Sort(); + } + } + + public override void Sort(IComparer comparer) + { + lock (_root) + { + _list.Sort(comparer); + } + } + + [SuppressMessage("Microsoft.Contracts", "CC1055")] // Skip extra error checking to avoid *potential* AppCompat problems. + public override void Sort(int index, int count, IComparer comparer) + { + lock (_root) + { + _list.Sort(index, count, comparer); + } + } + + public override object[] ToArray() + { + lock (_root) + { + return _list.ToArray(); + } + } + + [SuppressMessage("Microsoft.Contracts", "CC1055")] // Skip extra error checking to avoid *potential* AppCompat problems. + public override Array ToArray(Type type) + { + lock (_root) + { + return _list.ToArray(type); + } + } + + public override void TrimToSize() + { + lock (_root) + { + _list.TrimToSize(); + } + } + } + + + private class SyncIList : IList + { + private IList _list; + private object _root; + + internal SyncIList(IList list) + { + _list = list; + _root = list.SyncRoot; + } + + public virtual int Count + { + get { lock (_root) { return _list.Count; } } + } + + public virtual bool IsReadOnly + { + get { return _list.IsReadOnly; } + } + + public virtual bool IsFixedSize + { + get { return _list.IsFixedSize; } + } + + + public virtual bool IsSynchronized + { + get { return true; } + } + + public virtual object this[int index] + { + get + { + lock (_root) + { + return _list[index]; + } + } + set + { + lock (_root) + { + _list[index] = value; + } + } + } + + public virtual object SyncRoot + { + get { return _root; } + } + + public virtual int Add(object value) + { + lock (_root) + { + return _list.Add(value); + } + } + + + public virtual void Clear() + { + lock (_root) + { + _list.Clear(); + } + } + + public virtual bool Contains(object item) + { + lock (_root) + { + return _list.Contains(item); + } + } + + public virtual void CopyTo(Array array, int index) + { + lock (_root) + { + _list.CopyTo(array, index); + } + } + + public virtual IEnumerator GetEnumerator() + { + lock (_root) + { + return _list.GetEnumerator(); + } + } + + public virtual int IndexOf(object value) + { + lock (_root) + { + return _list.IndexOf(value); + } + } + + public virtual void Insert(int index, object value) + { + lock (_root) + { + _list.Insert(index, value); + } + } + + public virtual void Remove(object value) + { + lock (_root) + { + _list.Remove(value); + } + } + + public virtual void RemoveAt(int index) + { + lock (_root) + { + _list.RemoveAt(index); + } + } + } + + private class FixedSizeList : IList + { + private IList _list; + + internal FixedSizeList(IList l) + { + _list = l; + } + + public virtual int Count + { + get { return _list.Count; } + } + + public virtual bool IsReadOnly + { + get { return _list.IsReadOnly; } + } + + public virtual bool IsFixedSize + { + get { return true; } + } + + public virtual bool IsSynchronized + { + get { return _list.IsSynchronized; } + } + + public virtual object this[int index] + { + get + { + return _list[index]; + } + set + { + _list[index] = value; + } + } + + public virtual object SyncRoot + { + get { return _list.SyncRoot; } + } + + public virtual int Add(object obj) + { + throw new NotSupportedException(SR.NotSupported_FixedSizeCollection); + } + + public virtual void Clear() + { + throw new NotSupportedException(SR.NotSupported_FixedSizeCollection); + } + + public virtual bool Contains(object obj) + { + return _list.Contains(obj); + } + + public virtual void CopyTo(Array array, int index) + { + _list.CopyTo(array, index); + } + + public virtual IEnumerator GetEnumerator() + { + return _list.GetEnumerator(); + } + + public virtual int IndexOf(object value) + { + return _list.IndexOf(value); + } + + public virtual void Insert(int index, object obj) + { + throw new NotSupportedException(SR.NotSupported_FixedSizeCollection); + } + + public virtual void Remove(object value) + { + throw new NotSupportedException(SR.NotSupported_FixedSizeCollection); + } + + public virtual void RemoveAt(int index) + { + throw new NotSupportedException(SR.NotSupported_FixedSizeCollection); + } + } + + private class FixedSizeArrayList : ArrayList + { + private ArrayList _list; + + internal FixedSizeArrayList(ArrayList l) + { + _list = l; + _version = _list._version; + } + + public override int Count + { + get { return _list.Count; } + } + + public override bool IsReadOnly + { + get { return _list.IsReadOnly; } + } + + public override bool IsFixedSize + { + get { return true; } + } + + public override bool IsSynchronized + { + get { return _list.IsSynchronized; } + } + + public override object this[int index] + { + get + { + return _list[index]; + } + set + { + _list[index] = value; + _version = _list._version; + } + } + + public override object SyncRoot + { + get { return _list.SyncRoot; } + } + + public override int Add(object obj) + { + throw new NotSupportedException(SR.NotSupported_FixedSizeCollection); + } + + public override void AddRange(ICollection c) + { + throw new NotSupportedException(SR.NotSupported_FixedSizeCollection); + } + + [SuppressMessage("Microsoft.Contracts", "CC1055")] // Skip extra error checking to avoid *potential* AppCompat problems. + public override int BinarySearch(int index, int count, object value, IComparer comparer) + { + return _list.BinarySearch(index, count, value, comparer); + } + + public override int Capacity + { + get { return _list.Capacity; } + [SuppressMessage("Microsoft.Contracts", "CC1055")] // Skip extra error checking to avoid *potential* AppCompat problems. + set + { throw new NotSupportedException(SR.NotSupported_FixedSizeCollection); } + } + + public override void Clear() + { + throw new NotSupportedException(SR.NotSupported_FixedSizeCollection); + } + + public override object Clone() + { + FixedSizeArrayList arrayList = new FixedSizeArrayList(_list); + arrayList._list = (ArrayList)_list.Clone(); + return arrayList; + } + + public override bool Contains(object obj) + { + return _list.Contains(obj); + } + + public override void CopyTo(Array array, int index) + { + _list.CopyTo(array, index); + } + + [SuppressMessage("Microsoft.Contracts", "CC1055")] // Skip extra error checking to avoid *potential* AppCompat problems. + public override void CopyTo(int index, Array array, int arrayIndex, int count) + { + _list.CopyTo(index, array, arrayIndex, count); + } + + public override IEnumerator GetEnumerator() + { + return _list.GetEnumerator(); + } + + [SuppressMessage("Microsoft.Contracts", "CC1055")] // Skip extra error checking to avoid *potential* AppCompat problems. + public override IEnumerator GetEnumerator(int index, int count) + { + return _list.GetEnumerator(index, count); + } + + public override int IndexOf(object value) + { + return _list.IndexOf(value); + } + + [SuppressMessage("Microsoft.Contracts", "CC1055")] // Skip extra error checking to avoid *potential* AppCompat problems. + public override int IndexOf(object value, int startIndex) + { + return _list.IndexOf(value, startIndex); + } + + [SuppressMessage("Microsoft.Contracts", "CC1055")] // Skip extra error checking to avoid *potential* AppCompat problems. + public override int IndexOf(object value, int startIndex, int count) + { + return _list.IndexOf(value, startIndex, count); + } + + public override void Insert(int index, object obj) + { + throw new NotSupportedException(SR.NotSupported_FixedSizeCollection); + } + + [SuppressMessage("Microsoft.Contracts", "CC1055")] // Skip extra error checking to avoid *potential* AppCompat problems. + public override void InsertRange(int index, ICollection c) + { + throw new NotSupportedException(SR.NotSupported_FixedSizeCollection); + } + + public override int LastIndexOf(object value) + { + return _list.LastIndexOf(value); + } + + [SuppressMessage("Microsoft.Contracts", "CC1055")] // Skip extra error checking to avoid *potential* AppCompat problems. + public override int LastIndexOf(object value, int startIndex) + { + return _list.LastIndexOf(value, startIndex); + } + + [SuppressMessage("Microsoft.Contracts", "CC1055")] // Skip extra error checking to avoid *potential* AppCompat problems. + public override int LastIndexOf(object value, int startIndex, int count) + { + return _list.LastIndexOf(value, startIndex, count); + } + + public override void Remove(object value) + { + throw new NotSupportedException(SR.NotSupported_FixedSizeCollection); + } + + public override void RemoveAt(int index) + { + throw new NotSupportedException(SR.NotSupported_FixedSizeCollection); + } + + [SuppressMessage("Microsoft.Contracts", "CC1055")] // Skip extra error checking to avoid *potential* AppCompat problems. + public override void RemoveRange(int index, int count) + { + throw new NotSupportedException(SR.NotSupported_FixedSizeCollection); + } + + [SuppressMessage("Microsoft.Contracts", "CC1055")] // Skip extra error checking to avoid *potential* AppCompat problems. + public override void SetRange(int index, ICollection c) + { + _list.SetRange(index, c); + _version = _list._version; + } + + public override ArrayList GetRange(int index, int count) + { + if (index < 0 || count < 0) + throw new ArgumentOutOfRangeException(index < 0 ? nameof(index) : nameof(count), SR.ArgumentOutOfRange_NeedNonNegNum); + if (Count - index < count) + throw new ArgumentException(SR.Argument_InvalidOffLen); + + return new Range(this, index, count); + } + + [SuppressMessage("Microsoft.Contracts", "CC1055")] // Skip extra error checking to avoid *potential* AppCompat problems. + public override void Reverse(int index, int count) + { + _list.Reverse(index, count); + _version = _list._version; + } + + [SuppressMessage("Microsoft.Contracts", "CC1055")] // Skip extra error checking to avoid *potential* AppCompat problems. + public override void Sort(int index, int count, IComparer comparer) + { + _list.Sort(index, count, comparer); + _version = _list._version; + } + + public override object[] ToArray() + { + return _list.ToArray(); + } + + [SuppressMessage("Microsoft.Contracts", "CC1055")] // Skip extra error checking to avoid *potential* AppCompat problems. + public override Array ToArray(Type type) + { + return _list.ToArray(type); + } + + public override void TrimToSize() + { + throw new NotSupportedException(SR.NotSupported_FixedSizeCollection); + } + } + + private class ReadOnlyList : IList + { + private IList _list; + + internal ReadOnlyList(IList l) + { + _list = l; + } + + public virtual int Count + { + get { return _list.Count; } + } + + public virtual bool IsReadOnly + { + get { return true; } + } + + public virtual bool IsFixedSize + { + get { return true; } + } + + public virtual bool IsSynchronized + { + get { return _list.IsSynchronized; } + } + + public virtual object this[int index] + { + get + { + return _list[index]; + } + set + { + throw new NotSupportedException(SR.NotSupported_ReadOnlyCollection); + } + } + + public virtual object SyncRoot + { + get { return _list.SyncRoot; } + } + + public virtual int Add(object obj) + { + throw new NotSupportedException(SR.NotSupported_ReadOnlyCollection); + } + + public virtual void Clear() + { + throw new NotSupportedException(SR.NotSupported_ReadOnlyCollection); + } + + public virtual bool Contains(object obj) + { + return _list.Contains(obj); + } + + public virtual void CopyTo(Array array, int index) + { + _list.CopyTo(array, index); + } + + public virtual IEnumerator GetEnumerator() + { + return _list.GetEnumerator(); + } + + public virtual int IndexOf(object value) + { + return _list.IndexOf(value); + } + + public virtual void Insert(int index, object obj) + { + throw new NotSupportedException(SR.NotSupported_ReadOnlyCollection); + } + + public virtual void Remove(object value) + { + throw new NotSupportedException(SR.NotSupported_ReadOnlyCollection); + } + + public virtual void RemoveAt(int index) + { + throw new NotSupportedException(SR.NotSupported_ReadOnlyCollection); + } + } + + private class ReadOnlyArrayList : ArrayList + { + private ArrayList _list; + + internal ReadOnlyArrayList(ArrayList l) + { + _list = l; + } + + public override int Count + { + get { return _list.Count; } + } + + public override bool IsReadOnly + { + get { return true; } + } + + public override bool IsFixedSize + { + get { return true; } + } + + public override bool IsSynchronized + { + get { return _list.IsSynchronized; } + } + + public override object this[int index] + { + get + { + return _list[index]; + } + set + { + throw new NotSupportedException(SR.NotSupported_ReadOnlyCollection); + } + } + + public override object SyncRoot + { + get { return _list.SyncRoot; } + } + + public override int Add(object obj) + { + throw new NotSupportedException(SR.NotSupported_ReadOnlyCollection); + } + + public override void AddRange(ICollection c) + { + throw new NotSupportedException(SR.NotSupported_ReadOnlyCollection); + } + + [SuppressMessage("Microsoft.Contracts", "CC1055")] // Skip extra error checking to avoid *potential* AppCompat problems. + public override int BinarySearch(int index, int count, object value, IComparer comparer) + { + return _list.BinarySearch(index, count, value, comparer); + } + + + public override int Capacity + { + get { return _list.Capacity; } + [SuppressMessage("Microsoft.Contracts", "CC1055")] // Skip extra error checking to avoid *potential* AppCompat problems. + set + { throw new NotSupportedException(SR.NotSupported_ReadOnlyCollection); } + } + + public override void Clear() + { + throw new NotSupportedException(SR.NotSupported_ReadOnlyCollection); + } + + public override object Clone() + { + ReadOnlyArrayList arrayList = new ReadOnlyArrayList(_list); + arrayList._list = (ArrayList)_list.Clone(); + return arrayList; + } + + public override bool Contains(object obj) + { + return _list.Contains(obj); + } + + public override void CopyTo(Array array, int index) + { + _list.CopyTo(array, index); + } + + [SuppressMessage("Microsoft.Contracts", "CC1055")] // Skip extra error checking to avoid *potential* AppCompat problems. + public override void CopyTo(int index, Array array, int arrayIndex, int count) + { + _list.CopyTo(index, array, arrayIndex, count); + } + + public override IEnumerator GetEnumerator() + { + return _list.GetEnumerator(); + } + + [SuppressMessage("Microsoft.Contracts", "CC1055")] // Skip extra error checking to avoid *potential* AppCompat problems. + public override IEnumerator GetEnumerator(int index, int count) + { + return _list.GetEnumerator(index, count); + } + + public override int IndexOf(object value) + { + return _list.IndexOf(value); + } + + [SuppressMessage("Microsoft.Contracts", "CC1055")] // Skip extra error checking to avoid *potential* AppCompat problems. + public override int IndexOf(object value, int startIndex) + { + return _list.IndexOf(value, startIndex); + } + + [SuppressMessage("Microsoft.Contracts", "CC1055")] // Skip extra error checking to avoid *potential* AppCompat problems. + public override int IndexOf(object value, int startIndex, int count) + { + return _list.IndexOf(value, startIndex, count); + } + + public override void Insert(int index, object obj) + { + throw new NotSupportedException(SR.NotSupported_ReadOnlyCollection); + } + + [SuppressMessage("Microsoft.Contracts", "CC1055")] // Skip extra error checking to avoid *potential* AppCompat problems. + public override void InsertRange(int index, ICollection c) + { + throw new NotSupportedException(SR.NotSupported_ReadOnlyCollection); + } + + public override int LastIndexOf(object value) + { + return _list.LastIndexOf(value); + } + + [SuppressMessage("Microsoft.Contracts", "CC1055")] // Skip extra error checking to avoid *potential* AppCompat problems. + public override int LastIndexOf(object value, int startIndex) + { + return _list.LastIndexOf(value, startIndex); + } + + [SuppressMessage("Microsoft.Contracts", "CC1055")] // Skip extra error checking to avoid *potential* AppCompat problems. + public override int LastIndexOf(object value, int startIndex, int count) + { + return _list.LastIndexOf(value, startIndex, count); + } + + public override void Remove(object value) + { + throw new NotSupportedException(SR.NotSupported_ReadOnlyCollection); + } + + public override void RemoveAt(int index) + { + throw new NotSupportedException(SR.NotSupported_ReadOnlyCollection); + } + + [SuppressMessage("Microsoft.Contracts", "CC1055")] // Skip extra error checking to avoid *potential* AppCompat problems. + public override void RemoveRange(int index, int count) + { + throw new NotSupportedException(SR.NotSupported_ReadOnlyCollection); + } + + [SuppressMessage("Microsoft.Contracts", "CC1055")] // Skip extra error checking to avoid *potential* AppCompat problems. + public override void SetRange(int index, ICollection c) + { + throw new NotSupportedException(SR.NotSupported_ReadOnlyCollection); + } + + public override ArrayList GetRange(int index, int count) + { + if (index < 0 || count < 0) + throw new ArgumentOutOfRangeException(index < 0 ? nameof(index) : nameof(count), SR.ArgumentOutOfRange_NeedNonNegNum); + if (Count - index < count) + throw new ArgumentException(SR.Argument_InvalidOffLen); + + return new Range(this, index, count); + } + + [SuppressMessage("Microsoft.Contracts", "CC1055")] // Skip extra error checking to avoid *potential* AppCompat problems. + public override void Reverse(int index, int count) + { + throw new NotSupportedException(SR.NotSupported_ReadOnlyCollection); + } + + [SuppressMessage("Microsoft.Contracts", "CC1055")] // Skip extra error checking to avoid *potential* AppCompat problems. + public override void Sort(int index, int count, IComparer comparer) + { + throw new NotSupportedException(SR.NotSupported_ReadOnlyCollection); + } + + public override object[] ToArray() + { + return _list.ToArray(); + } + + [SuppressMessage("Microsoft.Contracts", "CC1055")] // Skip extra error checking to avoid *potential* AppCompat problems. + public override Array ToArray(Type type) + { + return _list.ToArray(type); + } + + public override void TrimToSize() + { + throw new NotSupportedException(SR.NotSupported_ReadOnlyCollection); + } + } + + + // Implements an enumerator for a ArrayList. The enumerator uses the + // internal version number of the list to ensure that no modifications are + // made to the list while an enumeration is in progress. + private sealed class ArrayListEnumerator : IEnumerator, ICloneable + { + private ArrayList _list; + private int _index; + private int _endIndex; // Where to stop. + private int _version; + private object _currentElement; + private int _startIndex; // Save this for Reset. + + internal ArrayListEnumerator(ArrayList list, int index, int count) + { + _list = list; + _startIndex = index; + _index = index - 1; + _endIndex = _index + count; // last valid index + _version = list._version; + _currentElement = null; + } + + public object Clone() => MemberwiseClone(); + + public bool MoveNext() + { + if (_version != _list._version) throw new InvalidOperationException(SR.InvalidOperation_EnumFailedVersion); + if (_index < _endIndex) + { + _currentElement = _list[++_index]; + return true; + } + else + { + _index = _endIndex + 1; + } + + return false; + } + + public object Current + { + get + { + if (_index < _startIndex) + throw new InvalidOperationException(SR.InvalidOperation_EnumNotStarted); + else if (_index > _endIndex) + { + throw new InvalidOperationException(SR.InvalidOperation_EnumEnded); + } + return _currentElement; + } + } + + public void Reset() + { + if (_version != _list._version) throw new InvalidOperationException(SR.InvalidOperation_EnumFailedVersion); + _index = _startIndex - 1; + } + } + + // Implementation of a generic list subrange. An instance of this class + // is returned by the default implementation of List.GetRange. + private class Range : ArrayList + { + private ArrayList _baseList; + private int _baseIndex; + private int _baseSize; + private int _baseVersion; + + internal Range(ArrayList list, int index, int count) : base(false) + { + _baseList = list; + _baseIndex = index; + _baseSize = count; + _baseVersion = list._version; + // we also need to update _version field to make Range of Range work + _version = list._version; + } + + private void InternalUpdateRange() + { + if (_baseVersion != _baseList._version) + throw new InvalidOperationException(SR.InvalidOperation_UnderlyingArrayListChanged); + } + + private void InternalUpdateVersion() + { + _baseVersion++; + _version++; + } + + public override int Add(object value) + { + InternalUpdateRange(); + _baseList.Insert(_baseIndex + _baseSize, value); + InternalUpdateVersion(); + return _baseSize++; + } + + public override void AddRange(ICollection c) + { + if (c == null) + { + throw new ArgumentNullException(nameof(c)); + } + + InternalUpdateRange(); + int count = c.Count; + if (count > 0) + { + _baseList.InsertRange(_baseIndex + _baseSize, c); + InternalUpdateVersion(); + _baseSize += count; + } + } + + public override int BinarySearch(int index, int count, object value, IComparer comparer) + { + if (index < 0 || count < 0) + throw new ArgumentOutOfRangeException(index < 0 ? nameof(index) : nameof(count), SR.ArgumentOutOfRange_NeedNonNegNum); + if (_baseSize - index < count) + throw new ArgumentException(SR.Argument_InvalidOffLen); + + InternalUpdateRange(); + + int i = _baseList.BinarySearch(_baseIndex + index, count, value, comparer); + if (i >= 0) return i - _baseIndex; + return i + _baseIndex; + } + + public override int Capacity + { + get + { + return _baseList.Capacity; + } + + set + { + if (value < Count) throw new ArgumentOutOfRangeException(nameof(value), SR.ArgumentOutOfRange_SmallCapacity); + } + } + + + public override void Clear() + { + InternalUpdateRange(); + if (_baseSize != 0) + { + _baseList.RemoveRange(_baseIndex, _baseSize); + InternalUpdateVersion(); + _baseSize = 0; + } + } + + public override object Clone() + { + InternalUpdateRange(); + Range arrayList = new Range(_baseList, _baseIndex, _baseSize); + arrayList._baseList = (ArrayList)_baseList.Clone(); + return arrayList; + } + + public override bool Contains(object item) + { + InternalUpdateRange(); + if (item == null) + { + for (int i = 0; i < _baseSize; i++) + if (_baseList[_baseIndex + i] == null) + return true; + return false; + } + else + { + for (int i = 0; i < _baseSize; i++) + if (_baseList[_baseIndex + i] != null && _baseList[_baseIndex + i].Equals(item)) + return true; + return false; + } + } + + public override void CopyTo(Array array, int index) + { + if (array == null) + throw new ArgumentNullException(nameof(array)); + if (array.Rank != 1) + throw new ArgumentException(SR.Arg_RankMultiDimNotSupported, nameof(array)); + if (index < 0) + throw new ArgumentOutOfRangeException(nameof(index), SR.ArgumentOutOfRange_NeedNonNegNum); + if (array.Length - index < _baseSize) + throw new ArgumentException(SR.Argument_InvalidOffLen); + + InternalUpdateRange(); + _baseList.CopyTo(_baseIndex, array, index, _baseSize); + } + + public override void CopyTo(int index, Array array, int arrayIndex, int count) + { + if (array == null) + throw new ArgumentNullException(nameof(array)); + if (array.Rank != 1) + throw new ArgumentException(SR.Arg_RankMultiDimNotSupported, nameof(array)); + if (index < 0 || count < 0) + throw new ArgumentOutOfRangeException(index < 0 ? nameof(index) : nameof(count), SR.ArgumentOutOfRange_NeedNonNegNum); + if (array.Length - arrayIndex < count) + throw new ArgumentException(SR.Argument_InvalidOffLen); + if (_baseSize - index < count) + throw new ArgumentException(SR.Argument_InvalidOffLen); + + InternalUpdateRange(); + _baseList.CopyTo(_baseIndex + index, array, arrayIndex, count); + } + + public override int Count + { + get + { + InternalUpdateRange(); + return _baseSize; + } + } + + public override bool IsReadOnly + { + get { return _baseList.IsReadOnly; } + } + + public override bool IsFixedSize + { + get { return _baseList.IsFixedSize; } + } + + public override bool IsSynchronized + { + get { return _baseList.IsSynchronized; } + } + + public override IEnumerator GetEnumerator() + { + return GetEnumerator(0, _baseSize); + } + + public override IEnumerator GetEnumerator(int index, int count) + { + if (index < 0 || count < 0) + throw new ArgumentOutOfRangeException(index < 0 ? nameof(index) : nameof(count), SR.ArgumentOutOfRange_NeedNonNegNum); + if (_baseSize - index < count) + throw new ArgumentException(SR.Argument_InvalidOffLen); + + InternalUpdateRange(); + return _baseList.GetEnumerator(_baseIndex + index, count); + } + + public override ArrayList GetRange(int index, int count) + { + if (index < 0 || count < 0) + throw new ArgumentOutOfRangeException(index < 0 ? nameof(index) : nameof(count), SR.ArgumentOutOfRange_NeedNonNegNum); + if (_baseSize - index < count) + throw new ArgumentException(SR.Argument_InvalidOffLen); + + InternalUpdateRange(); + return new Range(this, index, count); + } + + public override object SyncRoot + { + get + { + return _baseList.SyncRoot; + } + } + + + public override int IndexOf(object value) + { + InternalUpdateRange(); + int i = _baseList.IndexOf(value, _baseIndex, _baseSize); + if (i >= 0) return i - _baseIndex; + return -1; + } + + public override int IndexOf(object value, int startIndex) + { + if (startIndex < 0) + throw new ArgumentOutOfRangeException(nameof(startIndex), SR.ArgumentOutOfRange_NeedNonNegNum); + if (startIndex > _baseSize) + throw new ArgumentOutOfRangeException(nameof(startIndex), SR.ArgumentOutOfRange_Index); + + InternalUpdateRange(); + int i = _baseList.IndexOf(value, _baseIndex + startIndex, _baseSize - startIndex); + if (i >= 0) return i - _baseIndex; + return -1; + } + + public override int IndexOf(object value, int startIndex, int count) + { + if (startIndex < 0 || startIndex > _baseSize) + throw new ArgumentOutOfRangeException(nameof(startIndex), SR.ArgumentOutOfRange_Index); + + if (count < 0 || (startIndex > _baseSize - count)) + throw new ArgumentOutOfRangeException(nameof(count), SR.ArgumentOutOfRange_Count); + + InternalUpdateRange(); + int i = _baseList.IndexOf(value, _baseIndex + startIndex, count); + if (i >= 0) return i - _baseIndex; + return -1; + } + + public override void Insert(int index, object value) + { + if (index < 0 || index > _baseSize) throw new ArgumentOutOfRangeException(nameof(index), SR.ArgumentOutOfRange_Index); + + InternalUpdateRange(); + _baseList.Insert(_baseIndex + index, value); + InternalUpdateVersion(); + _baseSize++; + } + + public override void InsertRange(int index, ICollection c) + { + if (index < 0 || index > _baseSize) throw new ArgumentOutOfRangeException(nameof(index), SR.ArgumentOutOfRange_Index); + if (c == null) + { + throw new ArgumentNullException(nameof(c)); + } + + InternalUpdateRange(); + int count = c.Count; + if (count > 0) + { + _baseList.InsertRange(_baseIndex + index, c); + _baseSize += count; + InternalUpdateVersion(); + } + } + + public override int LastIndexOf(object value) + { + InternalUpdateRange(); + int i = _baseList.LastIndexOf(value, _baseIndex + _baseSize - 1, _baseSize); + if (i >= 0) return i - _baseIndex; + return -1; + } + + [SuppressMessage("Microsoft.Contracts", "CC1055")] // Skip extra error checking to avoid *potential* AppCompat problems. + public override int LastIndexOf(object value, int startIndex) + { + return LastIndexOf(value, startIndex, startIndex + 1); + } + + [SuppressMessage("Microsoft.Contracts", "CC1055")] // Skip extra error checking to avoid *potential* AppCompat problems. + public override int LastIndexOf(object value, int startIndex, int count) + { + InternalUpdateRange(); + if (_baseSize == 0) + return -1; + + if (startIndex >= _baseSize) + throw new ArgumentOutOfRangeException(nameof(startIndex), SR.ArgumentOutOfRange_Index); + if (startIndex < 0) + throw new ArgumentOutOfRangeException(nameof(startIndex), SR.ArgumentOutOfRange_NeedNonNegNum); + + int i = _baseList.LastIndexOf(value, _baseIndex + startIndex, count); + if (i >= 0) return i - _baseIndex; + return -1; + } + + // Don't need to override Remove + + public override void RemoveAt(int index) + { + if (index < 0 || index >= _baseSize) throw new ArgumentOutOfRangeException(nameof(index), SR.ArgumentOutOfRange_Index); + + InternalUpdateRange(); + _baseList.RemoveAt(_baseIndex + index); + InternalUpdateVersion(); + _baseSize--; + } + + public override void RemoveRange(int index, int count) + { + if (index < 0 || count < 0) + throw new ArgumentOutOfRangeException(index < 0 ? nameof(index) : nameof(count), SR.ArgumentOutOfRange_NeedNonNegNum); + if (_baseSize - index < count) + throw new ArgumentException(SR.Argument_InvalidOffLen); + + InternalUpdateRange(); + // No need to call _bastList.RemoveRange if count is 0. + // In addition, _baseList won't change the version number if count is 0. + if (count > 0) + { + _baseList.RemoveRange(_baseIndex + index, count); + InternalUpdateVersion(); + _baseSize -= count; + } + } + + public override void Reverse(int index, int count) + { + if (index < 0 || count < 0) + throw new ArgumentOutOfRangeException(index < 0 ? nameof(index) : nameof(count), SR.ArgumentOutOfRange_NeedNonNegNum); + if (_baseSize - index < count) + throw new ArgumentException(SR.Argument_InvalidOffLen); + + InternalUpdateRange(); + _baseList.Reverse(_baseIndex + index, count); + InternalUpdateVersion(); + } + + [SuppressMessage("Microsoft.Contracts", "CC1055")] // Skip extra error checking to avoid *potential* AppCompat problems. + public override void SetRange(int index, ICollection c) + { + InternalUpdateRange(); + if (index < 0 || index >= _baseSize) throw new ArgumentOutOfRangeException(nameof(index), SR.ArgumentOutOfRange_Index); + _baseList.SetRange(_baseIndex + index, c); + if (c.Count > 0) + { + InternalUpdateVersion(); + } + } + + public override void Sort(int index, int count, IComparer comparer) + { + if (index < 0 || count < 0) + throw new ArgumentOutOfRangeException(index < 0 ? nameof(index) : nameof(count), SR.ArgumentOutOfRange_NeedNonNegNum); + if (_baseSize - index < count) + throw new ArgumentException(SR.Argument_InvalidOffLen); + + InternalUpdateRange(); + _baseList.Sort(_baseIndex + index, count, comparer); + InternalUpdateVersion(); + } + + public override object this[int index] + { + get + { + InternalUpdateRange(); + if (index < 0 || index >= _baseSize) throw new ArgumentOutOfRangeException(nameof(index), SR.ArgumentOutOfRange_Index); + return _baseList[_baseIndex + index]; + } + set + { + InternalUpdateRange(); + if (index < 0 || index >= _baseSize) throw new ArgumentOutOfRangeException(nameof(index), SR.ArgumentOutOfRange_Index); + _baseList[_baseIndex + index] = value; + InternalUpdateVersion(); + } + } + + public override object[] ToArray() + { + InternalUpdateRange(); + if (_baseSize == 0) + return Array.Empty(); + object[] array = new object[_baseSize]; + Array.Copy(_baseList._items, _baseIndex, array, 0, _baseSize); + return array; + } + + public override Array ToArray(Type type) + { + if (type == null) + throw new ArgumentNullException(nameof(type)); + + InternalUpdateRange(); + Array array = Array.CreateInstance(type, _baseSize); + _baseList.CopyTo(_baseIndex, array, 0, _baseSize); + return array; + } + + public override void TrimToSize() + { + throw new NotSupportedException(SR.NotSupported_RangeCollection); + } + } + + private sealed class ArrayListEnumeratorSimple : IEnumerator, ICloneable + { + private ArrayList _list; + private int _index; + private int _version; + private object _currentElement; + private bool _isArrayList; + // this object is used to indicate enumeration has not started or has terminated + private static object s_dummyObject = new object(); + + internal ArrayListEnumeratorSimple(ArrayList list) + { + _list = list; + _index = -1; + _version = list._version; + _isArrayList = (list.GetType() == typeof(ArrayList)); + _currentElement = s_dummyObject; + } + + public object Clone() => MemberwiseClone(); + + public bool MoveNext() + { + if (_version != _list._version) + { + throw new InvalidOperationException(SR.InvalidOperation_EnumFailedVersion); + } + + if (_isArrayList) + { // avoid calling virtual methods if we are operating on ArrayList to improve performance + if (_index < _list._size - 1) + { + _currentElement = _list._items[++_index]; + return true; + } + else + { + _currentElement = s_dummyObject; + _index = _list._size; + return false; + } + } + else + { + if (_index < _list.Count - 1) + { + _currentElement = _list[++_index]; + return true; + } + else + { + _index = _list.Count; + _currentElement = s_dummyObject; + return false; + } + } + } + + public object Current + { + get + { + object temp = _currentElement; + if (s_dummyObject == temp) + { // check if enumeration has not started or has terminated + if (_index == -1) + { + throw new InvalidOperationException(SR.InvalidOperation_EnumNotStarted); + } + else + { + throw new InvalidOperationException(SR.InvalidOperation_EnumEnded); + } + } + + return temp; + } + } + + public void Reset() + { + if (_version != _list._version) + { + throw new InvalidOperationException(SR.InvalidOperation_EnumFailedVersion); + } + + _currentElement = s_dummyObject; + _index = -1; + } + } + + internal class ArrayListDebugView + { + private ArrayList _arrayList; + + public ArrayListDebugView(ArrayList arrayList) + { + if (arrayList == null) + throw new ArgumentNullException(nameof(arrayList)); + + _arrayList = arrayList; + } + + [DebuggerBrowsable(DebuggerBrowsableState.RootHidden)] + public object[] Items + { + get + { + return _arrayList.ToArray(); + } + } + } + } +} diff --git a/src/libraries/System.Private.CoreLib/src/System/LocalDataStoreSlot.cs b/src/libraries/System.Private.CoreLib/src/System/LocalDataStoreSlot.cs new file mode 100644 index 0000000..dae59bc --- /dev/null +++ b/src/libraries/System.Private.CoreLib/src/System/LocalDataStoreSlot.cs @@ -0,0 +1,24 @@ +// Licensed to the .NET Foundation under one or more agreements. +// The .NET Foundation licenses this file to you under the MIT license. +// See the LICENSE file in the project root for more information. + +using System.Threading; + +namespace System +{ + public sealed class LocalDataStoreSlot + { + internal LocalDataStoreSlot(ThreadLocal data) + { + Data = data; + GC.SuppressFinalize(this); + } + + internal ThreadLocal Data { get; private set; } + + [System.Diagnostics.CodeAnalysis.SuppressMessage("Microsoft.Security", "CA1821", Justification = "Finalizer preserved for compat, it is suppressed by the constructor.")] + ~LocalDataStoreSlot() + { + } + } +} diff --git a/src/libraries/System.Private.CoreLib/src/System/Security/IPermission.cs b/src/libraries/System.Private.CoreLib/src/System/Security/IPermission.cs new file mode 100644 index 0000000..a882c0f --- /dev/null +++ b/src/libraries/System.Private.CoreLib/src/System/Security/IPermission.cs @@ -0,0 +1,15 @@ +// Licensed to the .NET Foundation under one or more agreements. +// The .NET Foundation licenses this file to you under the MIT license. +// See the LICENSE file in the project root for more information. + +namespace System.Security +{ + public partial interface IPermission : ISecurityEncodable + { + IPermission Copy(); + void Demand(); + IPermission Intersect(IPermission target); + bool IsSubsetOf(IPermission target); + IPermission Union(IPermission target); + } +} diff --git a/src/libraries/System.Private.CoreLib/src/System/Security/ISecurityEncodable.cs b/src/libraries/System.Private.CoreLib/src/System/Security/ISecurityEncodable.cs new file mode 100644 index 0000000..844bb04 --- /dev/null +++ b/src/libraries/System.Private.CoreLib/src/System/Security/ISecurityEncodable.cs @@ -0,0 +1,12 @@ +// Licensed to the .NET Foundation under one or more agreements. +// The .NET Foundation licenses this file to you under the MIT license. +// See the LICENSE file in the project root for more information. + +namespace System.Security +{ + public partial interface ISecurityEncodable + { + void FromXml(SecurityElement e); + SecurityElement ToXml(); + } +} diff --git a/src/libraries/System.Private.CoreLib/src/System/Security/IStackWalk.cs b/src/libraries/System.Private.CoreLib/src/System/Security/IStackWalk.cs new file mode 100644 index 0000000..f8d472e --- /dev/null +++ b/src/libraries/System.Private.CoreLib/src/System/Security/IStackWalk.cs @@ -0,0 +1,14 @@ +// Licensed to the .NET Foundation under one or more agreements. +// The .NET Foundation licenses this file to you under the MIT license. +// See the LICENSE file in the project root for more information. + +namespace System.Security +{ + public partial interface IStackWalk + { + void Assert(); + void Demand(); + void Deny(); + void PermitOnly(); + } +} diff --git a/src/libraries/System.Private.CoreLib/src/System/Security/PermissionSet.cs b/src/libraries/System.Private.CoreLib/src/System/Security/PermissionSet.cs new file mode 100644 index 0000000..5c07248 --- /dev/null +++ b/src/libraries/System.Private.CoreLib/src/System/Security/PermissionSet.cs @@ -0,0 +1,52 @@ +// Licensed to the .NET Foundation under one or more agreements. +// The .NET Foundation licenses this file to you under the MIT license. +// See the LICENSE file in the project root for more information. + +using System.Security.Permissions; +using System.Collections; +using System.Runtime.Serialization; + +namespace System.Security +{ + public partial class PermissionSet : ICollection, IEnumerable, IDeserializationCallback, ISecurityEncodable, IStackWalk + { + public PermissionSet(PermissionState state) { } + public PermissionSet(PermissionSet permSet) { } + public virtual int Count { get { return 0; } } + public virtual bool IsReadOnly { get { return false; } } + public virtual bool IsSynchronized { get { return false; } } + public virtual object SyncRoot { get { return null; } } + public IPermission AddPermission(IPermission perm) { return AddPermissionImpl(perm); } + protected virtual IPermission AddPermissionImpl(IPermission perm) { return default(IPermission); } + public void Assert() { } + public bool ContainsNonCodeAccessPermissions() { return false; } + [Obsolete] + public static byte[] ConvertPermissionSet(string inFormat, byte[] inData, string outFormat) { return null; } + public virtual PermissionSet Copy() { return default(PermissionSet); } + public virtual void CopyTo(Array array, int index) { } + public void Demand() { } + [Obsolete] + public void Deny() { throw new PlatformNotSupportedException(SR.PlatformNotSupported_CAS); } + public override bool Equals(object o) => base.Equals(o); + public virtual void FromXml(SecurityElement et) { } + public IEnumerator GetEnumerator() { return GetEnumeratorImpl(); } + protected virtual IEnumerator GetEnumeratorImpl() { return Array.Empty().GetEnumerator(); } + public override int GetHashCode() => base.GetHashCode(); + public IPermission GetPermission(Type permClass) { return GetPermissionImpl(permClass); } + protected virtual IPermission GetPermissionImpl(Type permClass) { return default(IPermission); } + public PermissionSet Intersect(PermissionSet other) { return default(PermissionSet); } + public bool IsEmpty() { return false; } + public bool IsSubsetOf(PermissionSet target) { return false; } + public bool IsUnrestricted() { return false; } + public void PermitOnly() { throw new PlatformNotSupportedException(SR.PlatformNotSupported_CAS); } + public IPermission RemovePermission(Type permClass) { return RemovePermissionImpl(permClass); } + protected virtual IPermission RemovePermissionImpl(Type permClass) { return default(IPermission); } + public static void RevertAssert() { } + public IPermission SetPermission(IPermission perm) { return SetPermissionImpl(perm); } + protected virtual IPermission SetPermissionImpl(IPermission perm) { return default(IPermission); } + void IDeserializationCallback.OnDeserialization(object sender) { } + public override string ToString() => base.ToString(); + public virtual SecurityElement ToXml() { return default(SecurityElement); } + public PermissionSet Union(PermissionSet other) { return default(PermissionSet); } + } +} diff --git a/src/libraries/System.Private.CoreLib/src/System/Security/Permissions/PermissionState.cs b/src/libraries/System.Private.CoreLib/src/System/Security/Permissions/PermissionState.cs new file mode 100644 index 0000000..aace3dc --- /dev/null +++ b/src/libraries/System.Private.CoreLib/src/System/Security/Permissions/PermissionState.cs @@ -0,0 +1,12 @@ +// Licensed to the .NET Foundation under one or more agreements. +// The .NET Foundation licenses this file to you under the MIT license. +// See the LICENSE file in the project root for more information. + +namespace System.Security.Permissions +{ + public enum PermissionState + { + None = 0, + Unrestricted = 1, + } +} diff --git a/src/libraries/System.Private.CoreLib/src/System/Security/Principal/IIdentity.cs b/src/libraries/System.Private.CoreLib/src/System/Security/Principal/IIdentity.cs new file mode 100644 index 0000000..a25a976 --- /dev/null +++ b/src/libraries/System.Private.CoreLib/src/System/Security/Principal/IIdentity.cs @@ -0,0 +1,24 @@ +// Licensed to the .NET Foundation under one or more agreements. +// The .NET Foundation licenses this file to you under the MIT license. +// See the LICENSE file in the project root for more information. + +// +// All identities will implement this interface +// + +using System; + +namespace System.Security.Principal +{ + public interface IIdentity + { + // Access to the name string + string Name { get; } + + // Access to Authentication 'type' info + string AuthenticationType { get; } + + // Determine if this represents the unauthenticated identity + bool IsAuthenticated { get; } + } +} diff --git a/src/libraries/System.Private.CoreLib/src/System/Security/Principal/IPrincipal.cs b/src/libraries/System.Private.CoreLib/src/System/Security/Principal/IPrincipal.cs new file mode 100644 index 0000000..37c27bf --- /dev/null +++ b/src/libraries/System.Private.CoreLib/src/System/Security/Principal/IPrincipal.cs @@ -0,0 +1,21 @@ +// Licensed to the .NET Foundation under one or more agreements. +// The .NET Foundation licenses this file to you under the MIT license. +// See the LICENSE file in the project root for more information. + +// +// All roles will implement this interface +// + +using System; + +namespace System.Security.Principal +{ + public interface IPrincipal + { + // Retrieve the identity object + IIdentity Identity { get; } + + // Perform a check for a specific role + bool IsInRole(string role); + } +} diff --git a/src/libraries/System.Private.CoreLib/src/System/Security/Principal/PrincipalPolicy.cs b/src/libraries/System.Private.CoreLib/src/System/Security/Principal/PrincipalPolicy.cs new file mode 100644 index 0000000..53a8ba7 --- /dev/null +++ b/src/libraries/System.Private.CoreLib/src/System/Security/Principal/PrincipalPolicy.cs @@ -0,0 +1,19 @@ +// Licensed to the .NET Foundation under one or more agreements. +// The .NET Foundation licenses this file to you under the MIT license. +// See the LICENSE file in the project root for more information. + +// +// Enum describing what type of principal to create by default (assuming no +// principal has been set on the AppDomain). +// + +namespace System.Security.Principal +{ + public enum PrincipalPolicy + { + // Note: it's important that the default policy has the value 0. + UnauthenticatedPrincipal = 0, + NoPrincipal = 1, + WindowsPrincipal = 2, + } +} diff --git a/src/libraries/System.Private.CoreLib/src/System/Security/SecurityElement.cs b/src/libraries/System.Private.CoreLib/src/System/Security/SecurityElement.cs new file mode 100644 index 0000000..7af11e9 --- /dev/null +++ b/src/libraries/System.Private.CoreLib/src/System/Security/SecurityElement.cs @@ -0,0 +1,674 @@ +// Licensed to the .NET Foundation under one or more agreements. +// The .NET Foundation licenses this file to you under the MIT license. +// See the LICENSE file in the project root for more information.s + +using System.Collections; +using System.Diagnostics; +using System.Globalization; +using System.IO; +using System.Text; + +namespace System.Security +{ + internal interface ISecurityElementFactory + { + SecurityElement CreateSecurityElement(); + + object Copy(); + + string GetTag(); + + string Attribute(string attributeName); + } + + public sealed class SecurityElement : ISecurityElementFactory + { + internal string _tag; + internal string _text; + private ArrayList _children; + internal ArrayList _attributes; + + private const int AttributesTypical = 4 * 2; // 4 attributes, times 2 strings per attribute + private const int ChildrenTypical = 1; + private const string Indent = " "; + + private static readonly char[] s_tagIllegalCharacters = new char[] { ' ', '<', '>' }; + private static readonly char[] s_textIllegalCharacters = new char[] { '<', '>' }; + private static readonly char[] s_valueIllegalCharacters = new char[] { '<', '>', '\"' }; + private static readonly char[] s_escapeChars = new char[] { '<', '>', '\"', '\'', '&' }; + private static readonly string[] s_escapeStringPairs = new string[] + { + // these must be all once character escape sequences or a new escaping algorithm is needed + "<", "<", + ">", ">", + "\"", """, + "\'", "'", + "&", "&" + }; + + //-------------------------- Constructors --------------------------- + + internal SecurityElement() + { + } + + public SecurityElement(string tag) + { + if (tag == null) + throw new ArgumentNullException(nameof(tag)); + + if (!IsValidTag(tag)) + throw new ArgumentException(string.Format(CultureInfo.CurrentCulture, SR.Argument_InvalidElementTag, tag)); + + _tag = tag; + _text = null; + } + + public SecurityElement(string tag, string text) + { + if (tag == null) + throw new ArgumentNullException(nameof(tag)); + + if (!IsValidTag(tag)) + throw new ArgumentException(string.Format(CultureInfo.CurrentCulture, SR.Argument_InvalidElementTag, tag)); + + if (text != null && !IsValidText(text)) + throw new ArgumentException(string.Format(CultureInfo.CurrentCulture, SR.Argument_InvalidElementText, text)); + + _tag = tag; + _text = text; + } + + //-------------------------- Properties ----------------------------- + + public string Tag + { + get + { + return _tag; + } + + set + { + if (value == null) + throw new ArgumentNullException(nameof(Tag)); + + if (!IsValidTag(value)) + throw new ArgumentException(string.Format(CultureInfo.CurrentCulture, SR.Argument_InvalidElementTag, value)); + + _tag = value; + } + } + + public Hashtable Attributes + { + get + { + if (_attributes == null || _attributes.Count == 0) + { + return null; + } + else + { + Hashtable hashtable = new Hashtable(_attributes.Count / 2); + + int iMax = _attributes.Count; + Debug.Assert(iMax % 2 == 0, "Odd number of strings means the attr/value pairs were not added correctly"); + + for (int i = 0; i < iMax; i += 2) + { + hashtable.Add(_attributes[i], _attributes[i + 1]); + } + + return hashtable; + } + } + + set + { + if (value == null || value.Count == 0) + { + _attributes = null; + } + else + { + ArrayList list = new ArrayList(value.Count); + IDictionaryEnumerator enumerator = value.GetEnumerator(); + + while (enumerator.MoveNext()) + { + string attrName = (string)enumerator.Key; + string attrValue = (string)enumerator.Value; + + if (!IsValidAttributeName(attrName)) + throw new ArgumentException(string.Format(CultureInfo.CurrentCulture, SR.Argument_InvalidElementName, attrName)); + + if (!IsValidAttributeValue(attrValue)) + throw new ArgumentException(string.Format(CultureInfo.CurrentCulture, SR.Argument_InvalidElementValue, attrValue)); + + list.Add(attrName); + list.Add(attrValue); + } + + _attributes = list; + } + } + } + + public string Text + { + get + { + return Unescape(_text); + } + + set + { + if (value == null) + { + _text = null; + } + else + { + if (!IsValidText(value)) + throw new ArgumentException(string.Format(CultureInfo.CurrentCulture, SR.Argument_InvalidElementTag, value)); + + _text = value; + } + } + } + + public ArrayList Children + { + get + { + ConvertSecurityElementFactories(); + return _children; + } + + set + { + if (value != null && value.Contains(null)) + { + throw new ArgumentException(SR.ArgumentNull_Child); + } + _children = value; + } + } + + internal void ConvertSecurityElementFactories() + { + if (_children == null) + return; + + for (int i = 0; i < _children.Count; ++i) + { + ISecurityElementFactory iseFactory = _children[i] as ISecurityElementFactory; + if (iseFactory != null && !(_children[i] is SecurityElement)) + _children[i] = iseFactory.CreateSecurityElement(); + } + } + + //-------------------------- Public Methods ----------------------------- + + internal void AddAttributeSafe(string name, string value) + { + if (_attributes == null) + { + _attributes = new ArrayList(AttributesTypical); + } + else + { + int iMax = _attributes.Count; + Debug.Assert(iMax % 2 == 0, "Odd number of strings means the attr/value pairs were not added correctly"); + + for (int i = 0; i < iMax; i += 2) + { + string strAttrName = (string)_attributes[i]; + + if (string.Equals(strAttrName, name)) + throw new ArgumentException(SR.Argument_AttributeNamesMustBeUnique); + } + } + + _attributes.Add(name); + _attributes.Add(value); + } + + public void AddAttribute(string name, string value) + { + if (name == null) + throw new ArgumentNullException(nameof(name)); + + if (value == null) + throw new ArgumentNullException(nameof(value)); + + if (!IsValidAttributeName(name)) + throw new ArgumentException(string.Format(CultureInfo.CurrentCulture, SR.Argument_InvalidElementName, name)); + + if (!IsValidAttributeValue(value)) + throw new ArgumentException(string.Format(CultureInfo.CurrentCulture, SR.Argument_InvalidElementValue, value)); + + AddAttributeSafe(name, value); + } + + public void AddChild(SecurityElement child) + { + if (child == null) + throw new ArgumentNullException(nameof(child)); + + if (_children == null) + _children = new ArrayList(ChildrenTypical); + + _children.Add(child); + } + + public bool Equal(SecurityElement other) + { + if (other == null) + return false; + + // Check if the tags are the same + if (!string.Equals(_tag, other._tag)) + return false; + + // Check if the text is the same + if (!string.Equals(_text, other._text)) + return false; + + // Check if the attributes are the same and appear in the same + // order. + if (_attributes == null || other._attributes == null) + { + if (_attributes != other._attributes) + return false; + } + else + { + int iMax = _attributes.Count; + Debug.Assert(iMax % 2 == 0, "Odd number of strings means the attr/value pairs were not added correctly"); + + // Maybe we can get away by only checking the number of attributes + if (iMax != other._attributes.Count) + return false; + + for (int i = 0; i < iMax; i++) + { + string lhs = (string)_attributes[i]; + string rhs = (string)other._attributes[i]; + + if (!string.Equals(lhs, rhs)) + return false; + } + } + + // Finally we must check the child and make sure they are + // equal and in the same order + if (_children == null || other._children == null) + { + if (_children != other._children) + return false; + } + else + { + // Maybe we can get away by only checking the number of children + if (_children.Count != other._children.Count) + return false; + + ConvertSecurityElementFactories(); + other.ConvertSecurityElementFactories(); + + IEnumerator lhs = _children.GetEnumerator(); + IEnumerator rhs = other._children.GetEnumerator(); + + SecurityElement e1, e2; + while (lhs.MoveNext()) + { + rhs.MoveNext(); + e1 = (SecurityElement)lhs.Current; + e2 = (SecurityElement)rhs.Current; + if (e1 == null || !e1.Equal(e2)) + return false; + } + } + return true; + } + + public SecurityElement Copy() + { + SecurityElement element = new SecurityElement(_tag, _text); + element._children = _children == null ? null : new ArrayList(_children); + element._attributes = _attributes == null ? null : new ArrayList(_attributes); + + return element; + } + + public static bool IsValidTag(string tag) + { + if (tag == null) + return false; + + return tag.IndexOfAny(s_tagIllegalCharacters) == -1; + } + + public static bool IsValidText(string text) + { + if (text == null) + return false; + + return text.IndexOfAny(s_textIllegalCharacters) == -1; + } + + public static bool IsValidAttributeName(string name) + { + return IsValidTag(name); + } + + public static bool IsValidAttributeValue(string value) + { + if (value == null) + return false; + + return value.IndexOfAny(s_valueIllegalCharacters) == -1; + } + + private static string GetEscapeSequence(char c) + { + int iMax = s_escapeStringPairs.Length; + Debug.Assert(iMax % 2 == 0, "Odd number of strings means the attr/value pairs were not added correctly"); + + for (int i = 0; i < iMax; i += 2) + { + string strEscSeq = s_escapeStringPairs[i]; + string strEscValue = s_escapeStringPairs[i + 1]; + + if (strEscSeq[0] == c) + return strEscValue; + } + + Debug.Fail("Unable to find escape sequence for this character"); + return c.ToString(); + } + + public static string Escape(string str) + { + if (str == null) + return null; + + StringBuilder sb = null; + + int strLen = str.Length; + int index; // Pointer into the string that indicates the location of the current '&' character + int newIndex = 0; // Pointer into the string that indicates the start index of the "remaining" string (that still needs to be processed). + + while (true) + { + index = str.IndexOfAny(s_escapeChars, newIndex); + + if (index == -1) + { + if (sb == null) + return str; + else + { + sb.Append(str, newIndex, strLen - newIndex); + return sb.ToString(); + } + } + else + { + if (sb == null) + sb = new StringBuilder(); + + sb.Append(str, newIndex, index - newIndex); + sb.Append(GetEscapeSequence(str[index])); + + newIndex = (index + 1); + } + } + + // no normal exit is possible + } + + private static string GetUnescapeSequence(string str, int index, out int newIndex) + { + int maxCompareLength = str.Length - index; + + int iMax = s_escapeStringPairs.Length; + Debug.Assert(iMax % 2 == 0, "Odd number of strings means the attr/value pairs were not added correctly"); + + for (int i = 0; i < iMax; i += 2) + { + string strEscSeq = s_escapeStringPairs[i]; + string strEscValue = s_escapeStringPairs[i + 1]; + + int length = strEscValue.Length; + + if (length <= maxCompareLength && string.Compare(strEscValue, 0, str, index, length, StringComparison.Ordinal) == 0) + { + newIndex = index + strEscValue.Length; + return strEscSeq; + } + } + + newIndex = index + 1; + return str[index].ToString(); + } + + private static string Unescape(string str) + { + if (str == null) + return null; + + StringBuilder sb = null; + + int strLen = str.Length; + int index; // Pointer into the string that indicates the location of the current '&' character + int newIndex = 0; // Pointer into the string that indicates the start index of the "remainging" string (that still needs to be processed). + + do + { + index = str.IndexOf('&', newIndex); + + if (index == -1) + { + if (sb == null) + return str; + else + { + sb.Append(str, newIndex, strLen - newIndex); + return sb.ToString(); + } + } + else + { + if (sb == null) + sb = new StringBuilder(); + + sb.Append(str, newIndex, index - newIndex); + sb.Append(GetUnescapeSequence(str, index, out newIndex)); // updates the newIndex too + + } + } + while (true); + } + + public override string ToString() + { + StringBuilder sb = new StringBuilder(); + + ToString("", sb, (obj, str) => ((StringBuilder)obj).Append(str)); + + return sb.ToString(); + } + + private void ToString(string indent, object obj, Action write) + { + write(obj, "<"); + write(obj, _tag); + + // If there are any attributes, plop those in. + if (_attributes != null && _attributes.Count > 0) + { + write(obj, " "); + + int iMax = _attributes.Count; + Debug.Assert(iMax % 2 == 0, "Odd number of strings means the attr/value pairs were not added correctly"); + + for (int i = 0; i < iMax; i += 2) + { + string strAttrName = (string)_attributes[i]; + string strAttrValue = (string)_attributes[i + 1]; + + write(obj, strAttrName); + write(obj, "=\""); + write(obj, strAttrValue); + write(obj, "\""); + + if (i != _attributes.Count - 2) + { + write(obj, Environment.NewLine); + } + } + } + + if (_text == null && (_children == null || _children.Count == 0)) + { + // If we are a single tag with no children, just add the end of tag text. + write(obj, "/>"); + write(obj, Environment.NewLine); + } + else + { + // Close the current tag. + write(obj, ">"); + + // Output the text + write(obj, _text); + + // Output any children. + if (_children != null) + { + ConvertSecurityElementFactories(); + + write(obj, Environment.NewLine); + + for (int i = 0; i < _children.Count; ++i) + { + ((SecurityElement)_children[i]).ToString(string.Empty, obj, write); + } + } + + // Output the closing tag + write(obj, ""); + write(obj, Environment.NewLine); + } + } + + public string Attribute(string name) + { + if (name == null) + throw new ArgumentNullException(nameof(name)); + + // Note: we don't check for validity here because an + // if an invalid name is passed we simply won't find it. + if (_attributes == null) + return null; + + // Go through all the attribute and see if we know about + // the one we are asked for + int iMax = _attributes.Count; + Debug.Assert(iMax % 2 == 0, "Odd number of strings means the attr/value pairs were not added correctly"); + + for (int i = 0; i < iMax; i += 2) + { + string strAttrName = (string)_attributes[i]; + + if (string.Equals(strAttrName, name)) + { + string strAttrValue = (string)_attributes[i + 1]; + + return Unescape(strAttrValue); + } + } + + // In the case where we didn't find it, we are expected to + // return null + return null; + } + + public SecurityElement SearchForChildByTag(string tag) + { + // Go through all the children and see if we can + // find the one are are asked for (matching tags) + if (tag == null) + throw new ArgumentNullException(nameof(tag)); + + // Note: we don't check for a valid tag here because + // an invalid tag simply won't be found. + if (_children == null) + return null; + foreach (SecurityElement current in _children) + { + if (current != null && string.Equals(current.Tag, tag)) + return current; + } + return null; + } + + public string SearchForTextOfTag(string tag) + { + // Search on each child in order and each + // child's child, depth-first + if (tag == null) + throw new ArgumentNullException(nameof(tag)); + + // Note: we don't check for a valid tag here because + // an invalid tag simply won't be found. + if (string.Equals(_tag, tag)) + return Unescape(_text); + if (_children == null) + return null; + + foreach (SecurityElement child in Children) + { + string text = child.SearchForTextOfTag(tag); + if (text != null) + return text; + } + return null; + } + + public static SecurityElement FromString(string xml) + { + if (xml == null) + throw new ArgumentNullException(nameof(xml)); + + return default(SecurityElement); + } + + //--------------- ISecurityElementFactory implementation ----------------- + + SecurityElement ISecurityElementFactory.CreateSecurityElement() + { + return this; + } + + string ISecurityElementFactory.GetTag() + { + return ((SecurityElement)this).Tag; + } + + object ISecurityElementFactory.Copy() + { + return ((SecurityElement)this).Copy(); + } + + string ISecurityElementFactory.Attribute(string attributeName) + { + return ((SecurityElement)this).Attribute(attributeName); + } + } +} diff --git a/src/libraries/System.Private.CoreLib/src/System/Threading/CompressedStack.cs b/src/libraries/System.Private.CoreLib/src/System/Threading/CompressedStack.cs new file mode 100644 index 0000000..7f209f5 --- /dev/null +++ b/src/libraries/System.Private.CoreLib/src/System/Threading/CompressedStack.cs @@ -0,0 +1,46 @@ +// Licensed to the .NET Foundation under one or more agreements. +// The .NET Foundation licenses this file to you under the MIT license. +// See the LICENSE file in the project root for more information. + +using System.Runtime.Serialization; + +namespace System.Threading +{ + public sealed class CompressedStack : ISerializable + { + private CompressedStack() + { + } + + public void GetObjectData(SerializationInfo info, StreamingContext context) + { + throw new PlatformNotSupportedException(); + } + + public static CompressedStack Capture() + { + return GetCompressedStack(); + } + + public CompressedStack CreateCopy() + { + return this; + } + + public static CompressedStack GetCompressedStack() + { + return new CompressedStack(); + } + + public static void Run(CompressedStack compressedStack, ContextCallback callback, object state) + { + if (compressedStack == null) + { + throw new ArgumentNullException(nameof(compressedStack)); + } + + // The original code was not checking for a null callback and would throw NullReferenceException + callback(state); + } + } +} diff --git a/src/libraries/System.Private.CoreLib/src/System/Threading/Thread.Unix.cs b/src/libraries/System.Private.CoreLib/src/System/Threading/Thread.Unix.cs new file mode 100644 index 0000000..252969e --- /dev/null +++ b/src/libraries/System.Private.CoreLib/src/System/Threading/Thread.Unix.cs @@ -0,0 +1,17 @@ +// Licensed to the .NET Foundation under one or more agreements. +// The .NET Foundation licenses this file to you under the MIT license. +// See the LICENSE file in the project root for more information. + +using System.Runtime.ConstrainedExecution; + +namespace System.Threading +{ + public sealed partial class Thread + { + public ApartmentState GetApartmentState() => ApartmentState.Unknown; + private static Exception GetApartmentStateChangeFailedException() => new PlatformNotSupportedException(SR.PlatformNotSupported_COMInterop); + private bool TrySetApartmentStateUnchecked(ApartmentState state) => state == GetApartmentState(); + + public void DisableComObjectEagerCleanup() { } + } +} diff --git a/src/libraries/System.Private.CoreLib/src/System/Threading/Thread.Windows.cs b/src/libraries/System.Private.CoreLib/src/System/Threading/Thread.Windows.cs new file mode 100644 index 0000000..6738158 --- /dev/null +++ b/src/libraries/System.Private.CoreLib/src/System/Threading/Thread.Windows.cs @@ -0,0 +1,18 @@ +// Licensed to the .NET Foundation under one or more agreements. +// The .NET Foundation licenses this file to you under the MIT license. +// See the LICENSE file in the project root for more information. + +using System.Runtime.ConstrainedExecution; + +namespace System.Threading +{ + public sealed partial class Thread + { + public ApartmentState GetApartmentState() => _runtimeThread.GetApartmentState(); + private static Exception GetApartmentStateChangeFailedException() => + new InvalidOperationException(SR.Thread_ApartmentState_ChangeFailed); + private bool TrySetApartmentStateUnchecked(ApartmentState state) => _runtimeThread.TrySetApartmentState(state); + + public void DisableComObjectEagerCleanup() => _runtimeThread.DisableComObjectEagerCleanup(); + } +} diff --git a/src/libraries/System.Private.CoreLib/src/System/Threading/Thread.cs b/src/libraries/System.Private.CoreLib/src/System/Threading/Thread.cs new file mode 100644 index 0000000..e9e654a --- /dev/null +++ b/src/libraries/System.Private.CoreLib/src/System/Threading/Thread.cs @@ -0,0 +1,456 @@ +// Licensed to the .NET Foundation under one or more agreements. +// The .NET Foundation licenses this file to you under the MIT license. +// See the LICENSE file in the project root for more information. + +using Internal.Runtime.Augments; +using System.Collections.Generic; +using System.Diagnostics; +using System.Globalization; +using System.Runtime.ConstrainedExecution; +using System.Security.Principal; + +namespace System.Threading +{ + public sealed partial class Thread : CriticalFinalizerObject + { + [ThreadStatic] + private static Thread t_currentThread; + private static AsyncLocal s_asyncLocalPrincipal; + + private readonly RuntimeThread _runtimeThread; + private Delegate _start; + private CultureInfo _startCulture; + private CultureInfo _startUICulture; + + private Thread(RuntimeThread runtimeThread) + { + Debug.Assert(runtimeThread != null); + _runtimeThread = runtimeThread; + } + + public Thread(ThreadStart start) + { + if (start == null) + { + throw new ArgumentNullException(nameof(start)); + } + + _runtimeThread = RuntimeThread.Create(ThreadMain_ThreadStart); + Debug.Assert(_runtimeThread != null); + _start = start; + } + + public Thread(ThreadStart start, int maxStackSize) + { + if (start == null) + { + throw new ArgumentNullException(nameof(start)); + } + if (maxStackSize < 0) + { + throw new ArgumentOutOfRangeException(nameof(maxStackSize), SR.ArgumentOutOfRange_NeedNonnegativeNumber); + } + + _runtimeThread = RuntimeThread.Create(ThreadMain_ThreadStart, maxStackSize); + Debug.Assert(_runtimeThread != null); + _start = start; + } + + public Thread(ParameterizedThreadStart start) + { + if (start == null) + { + throw new ArgumentNullException(nameof(start)); + } + + _runtimeThread = RuntimeThread.Create(ThreadMain_ParameterizedThreadStart); + Debug.Assert(_runtimeThread != null); + _start = start; + } + + public Thread(ParameterizedThreadStart start, int maxStackSize) + { + if (start == null) + { + throw new ArgumentNullException(nameof(start)); + } + if (maxStackSize < 0) + { + throw new ArgumentOutOfRangeException(nameof(maxStackSize), SR.ArgumentOutOfRange_NeedNonnegativeNumber); + } + + _runtimeThread = RuntimeThread.Create(ThreadMain_ParameterizedThreadStart, maxStackSize); + Debug.Assert(_runtimeThread != null); + _start = start; + } + + private Delegate InitializeNewThread() + { + t_currentThread = this; + + Delegate start = _start; + _start = null; + + if (_startCulture != null) + { + CultureInfo.CurrentCulture = _startCulture; + _startCulture = null; + } + + if (_startUICulture != null) + { + CultureInfo.CurrentUICulture = _startUICulture; + _startUICulture = null; + } + + return start; + } + + private void ThreadMain_ThreadStart() + { + ((ThreadStart)InitializeNewThread())(); + } + + private void ThreadMain_ParameterizedThreadStart(object parameter) + { + ((ParameterizedThreadStart)InitializeNewThread())(parameter); + } + + public static Thread CurrentThread + { + get + { + Thread currentThread = t_currentThread; + if (currentThread == null) + { + t_currentThread = currentThread = new Thread(RuntimeThread.CurrentThread); + } + return currentThread; + } + } + + private void RequireCurrentThread() + { + if (this != CurrentThread) + { + throw new InvalidOperationException(SR.Thread_Operation_RequiresCurrentThread); + } + } + + private void SetCultureOnUnstartedThread(CultureInfo value, ref CultureInfo culture) + { + if (value == null) + { + throw new ArgumentNullException(nameof(value)); + } + if ((_runtimeThread.ThreadState & ThreadState.Unstarted) == 0) + { + throw new InvalidOperationException(SR.Thread_Operation_RequiresCurrentThread); + } + culture = value; + } + + public CultureInfo CurrentCulture + { + get + { + RequireCurrentThread(); + return CultureInfo.CurrentCulture; + } + set + { + if (this != CurrentThread) + { + SetCultureOnUnstartedThread(value, ref _startCulture); + return; + } + CultureInfo.CurrentCulture = value; + } + } + + public CultureInfo CurrentUICulture + { + get + { + RequireCurrentThread(); + return CultureInfo.CurrentUICulture; + } + set + { + if (this != CurrentThread) + { + SetCultureOnUnstartedThread(value, ref _startUICulture); + return; + } + CultureInfo.CurrentUICulture = value; + } + } + + public static IPrincipal CurrentPrincipal + { + get + { + if (s_asyncLocalPrincipal is null) + { + CurrentPrincipal = AppDomain.CurrentDomain.GetThreadPrincipal(); + } + return s_asyncLocalPrincipal?.Value; + } + set + { + if (s_asyncLocalPrincipal is null) + { + if (value is null) + { + return; + } + Interlocked.CompareExchange(ref s_asyncLocalPrincipal, new AsyncLocal(), null); + } + s_asyncLocalPrincipal.Value = value; + } + } + + public ExecutionContext ExecutionContext => ExecutionContext.Capture(); + public bool IsAlive => _runtimeThread.IsAlive; + public bool IsBackground { get { return _runtimeThread.IsBackground; } set { _runtimeThread.IsBackground = value; } } + public bool IsThreadPoolThread => _runtimeThread.IsThreadPoolThread; + public int ManagedThreadId => _runtimeThread.ManagedThreadId; + public string Name { get { return _runtimeThread.Name; } set { _runtimeThread.Name = value; } } + public ThreadPriority Priority { get { return _runtimeThread.Priority; } set { _runtimeThread.Priority = value; } } + public ThreadState ThreadState => _runtimeThread.ThreadState; + + public void Abort() + { + throw new PlatformNotSupportedException(SR.PlatformNotSupported_ThreadAbort); + } + + public void Abort(object stateInfo) + { + throw new PlatformNotSupportedException(SR.PlatformNotSupported_ThreadAbort); + } + + public static void ResetAbort() + { + throw new PlatformNotSupportedException(SR.PlatformNotSupported_ThreadAbort); + } + + [ObsoleteAttribute("Thread.Suspend has been deprecated. Please use other classes in System.Threading, such as Monitor, Mutex, Event, and Semaphore, to synchronize Threads or protect resources. https://go.microsoft.com/fwlink/?linkid=14202", false)] + public void Suspend() + { + throw new PlatformNotSupportedException(SR.PlatformNotSupported_ThreadSuspend); + } + + [ObsoleteAttribute("Thread.Resume has been deprecated. Please use other classes in System.Threading, such as Monitor, Mutex, Event, and Semaphore, to synchronize Threads or protect resources. https://go.microsoft.com/fwlink/?linkid=14202", false)] + public void Resume() + { + throw new PlatformNotSupportedException(SR.PlatformNotSupported_ThreadSuspend); + } + + // Currently, no special handling is done for critical regions, and no special handling is necessary to ensure thread + // affinity. If that changes, the relevant functions would instead need to delegate to RuntimeThread. + public static void BeginCriticalRegion() { } + public static void EndCriticalRegion() { } + public static void BeginThreadAffinity() { } + public static void EndThreadAffinity() { } + + public static LocalDataStoreSlot AllocateDataSlot() => LocalDataStore.AllocateSlot(); + public static LocalDataStoreSlot AllocateNamedDataSlot(string name) => LocalDataStore.AllocateNamedSlot(name); + public static LocalDataStoreSlot GetNamedDataSlot(string name) => LocalDataStore.GetNamedSlot(name); + public static void FreeNamedDataSlot(string name) => LocalDataStore.FreeNamedSlot(name); + public static object GetData(LocalDataStoreSlot slot) => LocalDataStore.GetData(slot); + public static void SetData(LocalDataStoreSlot slot, object data) => LocalDataStore.SetData(slot, data); + + [Obsolete("The ApartmentState property has been deprecated. Use GetApartmentState, SetApartmentState or TrySetApartmentState instead.", false)] + public ApartmentState ApartmentState + { + get + { + return GetApartmentState(); + } + set + { + TrySetApartmentState(value); + } + } + + public void SetApartmentState(ApartmentState state) + { + if (!TrySetApartmentState(state)) + { + throw GetApartmentStateChangeFailedException(); + } + } + + public bool TrySetApartmentState(ApartmentState state) + { + switch (state) + { + case ApartmentState.STA: + case ApartmentState.MTA: + case ApartmentState.Unknown: + break; + + default: + throw new ArgumentOutOfRangeException(SR.ArgumentOutOfRange_Enum, nameof(state)); + } + + return TrySetApartmentStateUnchecked(state); + } + + private static int ToTimeoutMilliseconds(TimeSpan timeout) + { + var timeoutMilliseconds = (long)timeout.TotalMilliseconds; + if (timeoutMilliseconds < -1 || timeoutMilliseconds > int.MaxValue) + { + throw new ArgumentOutOfRangeException(nameof(timeout), SR.ArgumentOutOfRange_TimeoutMilliseconds); + } + return (int)timeoutMilliseconds; + } + + [Obsolete("Thread.GetCompressedStack is no longer supported. Please use the System.Threading.CompressedStack class")] + public CompressedStack GetCompressedStack() + { + throw new InvalidOperationException(SR.Thread_GetSetCompressedStack_NotSupported); + } + + [Obsolete("Thread.SetCompressedStack is no longer supported. Please use the System.Threading.CompressedStack class")] + public void SetCompressedStack(CompressedStack stack) + { + throw new InvalidOperationException(SR.Thread_GetSetCompressedStack_NotSupported); + } + + public static int GetCurrentProcessorId() => RuntimeThread.GetCurrentProcessorId(); + public static AppDomain GetDomain() => AppDomain.CurrentDomain; + public static int GetDomainID() => GetDomain().Id; + public override int GetHashCode() => ManagedThreadId; + public void Interrupt() => _runtimeThread.Interrupt(); + public void Join() => _runtimeThread.Join(); + public bool Join(int millisecondsTimeout) => _runtimeThread.Join(millisecondsTimeout); + public bool Join(TimeSpan timeout) => Join(ToTimeoutMilliseconds(timeout)); + public static void MemoryBarrier() => Interlocked.MemoryBarrier(); + public static void Sleep(int millisecondsTimeout) => RuntimeThread.Sleep(millisecondsTimeout); + public static void Sleep(TimeSpan timeout) => Sleep(ToTimeoutMilliseconds(timeout)); + public static void SpinWait(int iterations) => RuntimeThread.SpinWait(iterations); + public static bool Yield() => RuntimeThread.Yield(); + public void Start() => _runtimeThread.Start(); + public void Start(object parameter) => _runtimeThread.Start(parameter); + + public static byte VolatileRead(ref byte address) => Volatile.Read(ref address); + public static double VolatileRead(ref double address) => Volatile.Read(ref address); + public static short VolatileRead(ref short address) => Volatile.Read(ref address); + public static int VolatileRead(ref int address) => Volatile.Read(ref address); + public static long VolatileRead(ref long address) => Volatile.Read(ref address); + public static IntPtr VolatileRead(ref IntPtr address) => Volatile.Read(ref address); + public static object VolatileRead(ref object address) => Volatile.Read(ref address); + [CLSCompliant(false)] + public static sbyte VolatileRead(ref sbyte address) => Volatile.Read(ref address); + public static float VolatileRead(ref float address) => Volatile.Read(ref address); + [CLSCompliant(false)] + public static ushort VolatileRead(ref ushort address) => Volatile.Read(ref address); + [CLSCompliant(false)] + public static uint VolatileRead(ref uint address) => Volatile.Read(ref address); + [CLSCompliant(false)] + public static ulong VolatileRead(ref ulong address) => Volatile.Read(ref address); + [CLSCompliant(false)] + public static UIntPtr VolatileRead(ref UIntPtr address) => Volatile.Read(ref address); + public static void VolatileWrite(ref byte address, byte value) => Volatile.Write(ref address, value); + public static void VolatileWrite(ref double address, double value) => Volatile.Write(ref address, value); + public static void VolatileWrite(ref short address, short value) => Volatile.Write(ref address, value); + public static void VolatileWrite(ref int address, int value) => Volatile.Write(ref address, value); + public static void VolatileWrite(ref long address, long value) => Volatile.Write(ref address, value); + public static void VolatileWrite(ref IntPtr address, IntPtr value) => Volatile.Write(ref address, value); + public static void VolatileWrite(ref object address, object value) => Volatile.Write(ref address, value); + [CLSCompliant(false)] + public static void VolatileWrite(ref sbyte address, sbyte value) => Volatile.Write(ref address, value); + public static void VolatileWrite(ref float address, float value) => Volatile.Write(ref address, value); + [CLSCompliant(false)] + public static void VolatileWrite(ref ushort address, ushort value) => Volatile.Write(ref address, value); + [CLSCompliant(false)] + public static void VolatileWrite(ref uint address, uint value) => Volatile.Write(ref address, value); + [CLSCompliant(false)] + public static void VolatileWrite(ref ulong address, ulong value) => Volatile.Write(ref address, value); + [CLSCompliant(false)] + public static void VolatileWrite(ref UIntPtr address, UIntPtr value) => Volatile.Write(ref address, value); + + /// + /// Manages functionality required to support members of dealing with thread-local data + /// + private static class LocalDataStore + { + private static Dictionary s_nameToSlotMap; + + public static LocalDataStoreSlot AllocateSlot() + { + return new LocalDataStoreSlot(new ThreadLocal()); + } + + public static Dictionary EnsureNameToSlotMap() + { + Dictionary nameToSlotMap = s_nameToSlotMap; + if (nameToSlotMap != null) + { + return nameToSlotMap; + } + + nameToSlotMap = new Dictionary(); + return Interlocked.CompareExchange(ref s_nameToSlotMap, nameToSlotMap, null) ?? nameToSlotMap; + } + + public static LocalDataStoreSlot AllocateNamedSlot(string name) + { + LocalDataStoreSlot slot = AllocateSlot(); + Dictionary nameToSlotMap = EnsureNameToSlotMap(); + lock (nameToSlotMap) + { + nameToSlotMap.Add(name, slot); + } + return slot; + } + + public static LocalDataStoreSlot GetNamedSlot(string name) + { + Dictionary nameToSlotMap = EnsureNameToSlotMap(); + lock (nameToSlotMap) + { + LocalDataStoreSlot slot; + if (!nameToSlotMap.TryGetValue(name, out slot)) + { + slot = AllocateSlot(); + nameToSlotMap[name] = slot; + } + return slot; + } + } + + public static void FreeNamedSlot(string name) + { + Dictionary nameToSlotMap = EnsureNameToSlotMap(); + lock (nameToSlotMap) + { + nameToSlotMap.Remove(name); + } + } + + private static ThreadLocal GetThreadLocal(LocalDataStoreSlot slot) + { + if (slot == null) + { + throw new ArgumentNullException(nameof(slot)); + } + + Debug.Assert(slot.Data != null); + return slot.Data; + } + + public static object GetData(LocalDataStoreSlot slot) + { + return GetThreadLocal(slot).Value; + } + + public static void SetData(LocalDataStoreSlot slot, object value) + { + GetThreadLocal(slot).Value = value; + } + } + } +} -- 2.7.4