diff --git a/dependencies.props b/dependencies.props index efe3a44cc..538d57466 100644 --- a/dependencies.props +++ b/dependencies.props @@ -3,7 +3,7 @@ 5.0.0-preview.5.20230.9 1.0.0-alpha-28820-01 1.0.1-prerelease-00005 - 5.0.0-preview.2.20153.3 + 5.0.0-preview.5.20263.12 4.7.0-preview6.19265.2 2.1.14 15.8.0 diff --git a/src/BuildIntegration/Microsoft.NETCore.Native.Unix.props b/src/BuildIntegration/Microsoft.NETCore.Native.Unix.props index b4b19ed24..fa1598df3 100644 --- a/src/BuildIntegration/Microsoft.NETCore.Native.Unix.props +++ b/src/BuildIntegration/Microsoft.NETCore.Native.Unix.props @@ -57,12 +57,12 @@ See the LICENSE file in the project root for more information. - - - - - - + + + + + + diff --git a/src/Common/src/Interop/Unix/System.Globalization.Native/Interop.Calendar.cs b/src/Common/src/Interop/Interop.Calendar.cs similarity index 98% rename from src/Common/src/Interop/Unix/System.Globalization.Native/Interop.Calendar.cs rename to src/Common/src/Interop/Interop.Calendar.cs index 764bdaf85..0b9e2c283 100644 --- a/src/Common/src/Interop/Unix/System.Globalization.Native/Interop.Calendar.cs +++ b/src/Common/src/Interop/Interop.Calendar.cs @@ -5,7 +5,6 @@ using System; using System.Globalization; using System.Runtime.InteropServices; -using System.Text; internal static partial class Interop { diff --git a/src/Common/src/Interop/Unix/System.Globalization.Native/Interop.Casing.cs b/src/Common/src/Interop/Interop.Casing.cs similarity index 95% rename from src/Common/src/Interop/Unix/System.Globalization.Native/Interop.Casing.cs rename to src/Common/src/Interop/Interop.Casing.cs index 503a864d6..499f9445d 100644 --- a/src/Common/src/Interop/Unix/System.Globalization.Native/Interop.Casing.cs +++ b/src/Common/src/Interop/Interop.Casing.cs @@ -2,10 +2,7 @@ // 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; using System.Runtime.InteropServices; -using System.Security; -using System.Text; internal static partial class Interop { diff --git a/src/Common/src/Interop/Unix/System.Globalization.Native/Interop.Collation.cs b/src/Common/src/Interop/Interop.Collation.cs similarity index 98% rename from src/Common/src/Interop/Unix/System.Globalization.Native/Interop.Collation.cs rename to src/Common/src/Interop/Interop.Collation.cs index 7d0175473..ece19be58 100644 --- a/src/Common/src/Interop/Unix/System.Globalization.Native/Interop.Collation.cs +++ b/src/Common/src/Interop/Interop.Collation.cs @@ -5,7 +5,6 @@ using System; using System.Globalization; using System.Runtime.InteropServices; -using System.Security; internal static partial class Interop { @@ -24,7 +23,7 @@ internal static partial class Interop internal static extern unsafe int IndexOf(IntPtr sortHandle, char* target, int cwTargetLength, char* pSource, int cwSourceLength, CompareOptions options, int* matchLengthPtr); [DllImport(Libraries.GlobalizationNative, CharSet = CharSet.Unicode, EntryPoint = "GlobalizationNative_LastIndexOf")] - internal static extern unsafe int LastIndexOf(IntPtr sortHandle, char* target, int cwTargetLength, char* pSource, int cwSourceLength, CompareOptions options); + internal static extern unsafe int LastIndexOf(IntPtr sortHandle, char* target, int cwTargetLength, char* pSource, int cwSourceLength, CompareOptions options, int* matchLengthPtr); [DllImport(Libraries.GlobalizationNative, CharSet = CharSet.Unicode, EntryPoint = "GlobalizationNative_IndexOfOrdinalIgnoreCase")] internal static extern unsafe int IndexOfOrdinalIgnoreCase(string target, int cwTargetLength, char* pSource, int cwSourceLength, bool findLast); diff --git a/src/Common/src/Interop/Unix/System.Globalization.Native/Interop.ICU.cs b/src/Common/src/Interop/Interop.ICU.cs similarity index 92% rename from src/Common/src/Interop/Unix/System.Globalization.Native/Interop.ICU.cs rename to src/Common/src/Interop/Interop.ICU.cs index f24c26078..0dce07295 100644 --- a/src/Common/src/Interop/Unix/System.Globalization.Native/Interop.ICU.cs +++ b/src/Common/src/Interop/Interop.ICU.cs @@ -2,9 +2,7 @@ // 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; using System.Runtime.InteropServices; -using System.Runtime.CompilerServices; internal static partial class Interop { diff --git a/src/Common/src/Interop/Unix/System.Globalization.Native/Interop.Idna.cs b/src/Common/src/Interop/Interop.Idna.cs similarity index 98% rename from src/Common/src/Interop/Unix/System.Globalization.Native/Interop.Idna.cs rename to src/Common/src/Interop/Interop.Idna.cs index 89b6c3ceb..e9014da1e 100644 --- a/src/Common/src/Interop/Unix/System.Globalization.Native/Interop.Idna.cs +++ b/src/Common/src/Interop/Interop.Idna.cs @@ -2,7 +2,6 @@ // 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; using System.Runtime.InteropServices; internal static partial class Interop diff --git a/src/Common/src/Interop/Interop.Libraries.cs b/src/Common/src/Interop/Interop.Libraries.cs new file mode 100644 index 000000000..4fee38ad3 --- /dev/null +++ b/src/Common/src/Interop/Interop.Libraries.cs @@ -0,0 +1,11 @@ +// 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. + +internal static partial class Interop +{ + internal static partial class Libraries + { + internal const string GlobalizationNative = "libSystem.Globalization.Native"; + } +} diff --git a/src/Common/src/Interop/Unix/System.Globalization.Native/Interop.Locale.cs b/src/Common/src/Interop/Interop.Locale.cs similarity index 99% rename from src/Common/src/Interop/Unix/System.Globalization.Native/Interop.Locale.cs rename to src/Common/src/Interop/Interop.Locale.cs index d9a300fd1..a6517185c 100644 --- a/src/Common/src/Interop/Unix/System.Globalization.Native/Interop.Locale.cs +++ b/src/Common/src/Interop/Interop.Locale.cs @@ -2,7 +2,6 @@ // 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; using System.Runtime.InteropServices; internal static partial class Interop diff --git a/src/Common/src/Interop/Unix/System.Globalization.Native/Interop.Normalization.cs b/src/Common/src/Interop/Interop.Normalization.cs similarity index 68% rename from src/Common/src/Interop/Unix/System.Globalization.Native/Interop.Normalization.cs rename to src/Common/src/Interop/Interop.Normalization.cs index d442da0ea..f981eac64 100644 --- a/src/Common/src/Interop/Unix/System.Globalization.Native/Interop.Normalization.cs +++ b/src/Common/src/Interop/Interop.Normalization.cs @@ -2,7 +2,6 @@ // 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; using System.Runtime.InteropServices; using System.Text; @@ -11,9 +10,9 @@ internal static partial class Interop internal static partial class Globalization { [DllImport(Libraries.GlobalizationNative, CharSet = CharSet.Unicode, EntryPoint = "GlobalizationNative_IsNormalized")] - internal static extern int IsNormalized(NormalizationForm normalizationForm, string src, int srcLen); + internal static extern unsafe int IsNormalized(NormalizationForm normalizationForm, char* src, int srcLen); [DllImport(Libraries.GlobalizationNative, CharSet = CharSet.Unicode, EntryPoint = "GlobalizationNative_NormalizeString")] - internal static extern int NormalizeString(NormalizationForm normalizationForm, string src, int srcLen, [Out] char[] dstBuffer, int dstBufferCapacity); + internal static extern unsafe int NormalizeString(NormalizationForm normalizationForm, char* src, int srcLen, char* dstBuffer, int dstBufferCapacity); } } diff --git a/src/Common/src/Interop/Unix/System.Globalization.Native/Interop.ResultCode.cs b/src/Common/src/Interop/Interop.ResultCode.cs similarity index 100% rename from src/Common/src/Interop/Unix/System.Globalization.Native/Interop.ResultCode.cs rename to src/Common/src/Interop/Interop.ResultCode.cs diff --git a/src/Common/src/Interop/Unix/System.Globalization.Native/Interop.TimeZoneInfo.cs b/src/Common/src/Interop/Interop.TimeZoneInfo.cs similarity index 98% rename from src/Common/src/Interop/Unix/System.Globalization.Native/Interop.TimeZoneInfo.cs rename to src/Common/src/Interop/Interop.TimeZoneInfo.cs index df488b6ff..f60b81f0d 100644 --- a/src/Common/src/Interop/Unix/System.Globalization.Native/Interop.TimeZoneInfo.cs +++ b/src/Common/src/Interop/Interop.TimeZoneInfo.cs @@ -3,7 +3,6 @@ // See the LICENSE file in the project root for more information. using System.Runtime.InteropServices; -using System.Text; internal static partial class Interop { diff --git a/src/Common/src/Interop/Unix/System.Globalization.Native/Interop.Utils.cs b/src/Common/src/Interop/Interop.Utils.cs similarity index 97% rename from src/Common/src/Interop/Unix/System.Globalization.Native/Interop.Utils.cs rename to src/Common/src/Interop/Interop.Utils.cs index 627ab56c9..11534cbde 100644 --- a/src/Common/src/Interop/Unix/System.Globalization.Native/Interop.Utils.cs +++ b/src/Common/src/Interop/Interop.Utils.cs @@ -3,9 +3,7 @@ // See the LICENSE file in the project root for more information. using System; -using System.Diagnostics; using System.Buffers; -using System.Text; internal static partial class Interop { diff --git a/src/Common/src/Interop/Unix/Interop.Errors.cs b/src/Common/src/Interop/Unix/Interop.Errors.cs index 49cc830e0..dad796280 100644 --- a/src/Common/src/Interop/Unix/Interop.Errors.cs +++ b/src/Common/src/Interop/Unix/Interop.Errors.cs @@ -115,7 +115,7 @@ internal static partial class Interop // Represents a platform-agnostic Error and underlying platform-specific errno internal struct ErrorInfo { - private Error _error; + private readonly Error _error; private int _rawErrno; internal ErrorInfo(int errno) diff --git a/src/Common/src/Interop/Unix/Interop.Libraries.cs b/src/Common/src/Interop/Unix/Interop.Libraries.cs index 10118ff30..f51194829 100644 --- a/src/Common/src/Interop/Unix/Interop.Libraries.cs +++ b/src/Common/src/Interop/Unix/Interop.Libraries.cs @@ -7,12 +7,12 @@ internal static partial class Interop internal static partial class Libraries { // Shims - internal const string SystemNative = "System.Native"; - internal const string GlobalizationNative = "System.Globalization.Native"; - internal const string NetSecurityNative = "System.Net.Security.Native"; - internal const string CryptoNative = "System.Security.Cryptography.Native.OpenSsl"; - internal const string CompressionNative = "System.IO.Compression.Native"; - internal const string IOPortsNative = "System.IO.Ports.Native"; + internal const string SystemNative = "libSystem.Native"; + internal const string NetSecurityNative = "libSystem.Net.Security.Native"; + internal const string CryptoNative = "libSystem.Security.Cryptography.Native.OpenSsl"; + internal const string CompressionNative = "libSystem.IO.Compression.Native"; + internal const string IOPortsNative = "libSystem.IO.Ports.Native"; internal const string Libdl = "libdl"; + internal const string HostPolicy = "libhostpolicy"; } } diff --git a/src/Common/src/Interop/Unix/System.Native/Interop.Access.cs b/src/Common/src/Interop/Unix/System.Native/Interop.Access.cs index a723f572a..b9750fa10 100644 --- a/src/Common/src/Interop/Unix/System.Native/Interop.Access.cs +++ b/src/Common/src/Interop/Unix/System.Native/Interop.Access.cs @@ -2,7 +2,6 @@ // 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; using System.Runtime.InteropServices; internal static partial class Interop diff --git a/src/Common/src/Interop/Unix/System.Native/Interop.ChDir.cs b/src/Common/src/Interop/Unix/System.Native/Interop.ChDir.cs index 3c6699518..8979d10f4 100644 --- a/src/Common/src/Interop/Unix/System.Native/Interop.ChDir.cs +++ b/src/Common/src/Interop/Unix/System.Native/Interop.ChDir.cs @@ -2,7 +2,6 @@ // 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; using System.Runtime.InteropServices; internal static partial class Interop diff --git a/src/Common/src/Interop/Unix/System.Native/Interop.EnumerateInterfaceAddresses.cs b/src/Common/src/Interop/Unix/System.Native/Interop.EnumerateInterfaceAddresses.cs index 8e03a33b5..7ad346a9a 100644 --- a/src/Common/src/Interop/Unix/System.Native/Interop.EnumerateInterfaceAddresses.cs +++ b/src/Common/src/Interop/Unix/System.Native/Interop.EnumerateInterfaceAddresses.cs @@ -51,8 +51,8 @@ internal static partial class Interop [DllImport(Libraries.SystemNative, EntryPoint = "SystemNative_EnumerateInterfaceAddresses")] public static extern int EnumerateInterfaceAddresses( IPv4AddressDiscoveredCallback ipv4Found, - IPv6AddressDiscoveredCallback ipv6Found, - LinkLayerAddressDiscoveredCallback linkLayerFound); + IPv6AddressDiscoveredCallback? ipv6Found, + LinkLayerAddressDiscoveredCallback? linkLayerFound); [DllImport(Libraries.SystemNative, EntryPoint = "SystemNative_EnumerateGatewayAddressesForInterface")] public static extern int EnumerateGatewayAddressesForInterface(uint interfaceIndex, DnsAddessDiscoveredCallback onGatewayFound); diff --git a/src/Common/src/Interop/Unix/System.Native/Interop.Fcntl.cs b/src/Common/src/Interop/Unix/System.Native/Interop.Fcntl.cs index cec6451b5..0877ca707 100644 --- a/src/Common/src/Interop/Unix/System.Native/Interop.Fcntl.cs +++ b/src/Common/src/Interop/Unix/System.Native/Interop.Fcntl.cs @@ -17,6 +17,9 @@ internal static partial class Interop [DllImport(Libraries.SystemNative, EntryPoint = "SystemNative_FcntlSetIsNonBlocking", SetLastError=true)] internal static extern int SetIsNonBlocking(SafeHandle fd, int isNonBlocking); + [DllImport(Libraries.SystemNative, EntryPoint = "SystemNative_FcntlGetIsNonBlocking", SetLastError = true)] + internal static extern int GetIsNonBlocking(SafeHandle fd, out bool isNonBlocking); + [DllImport(Libraries.SystemNative, EntryPoint = "SystemNative_FcntlSetFD", SetLastError=true)] internal static extern int SetFD(SafeHandle fd, int flags); diff --git a/src/Common/src/Interop/Unix/System.Native/Interop.GetCpuUtilization.cs b/src/Common/src/Interop/Unix/System.Native/Interop.GetCpuUtilization.cs index a630a3e82..509fef827 100644 --- a/src/Common/src/Interop/Unix/System.Native/Interop.GetCpuUtilization.cs +++ b/src/Common/src/Interop/Unix/System.Native/Interop.GetCpuUtilization.cs @@ -2,8 +2,6 @@ // 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; -using System.Runtime.CompilerServices; using System.Runtime.InteropServices; internal static partial class Interop diff --git a/src/Common/src/Interop/Unix/System.Native/Interop.GetEUid.cs b/src/Common/src/Interop/Unix/System.Native/Interop.GetEUid.cs index 8b525fa32..c964dec14 100644 --- a/src/Common/src/Interop/Unix/System.Native/Interop.GetEUid.cs +++ b/src/Common/src/Interop/Unix/System.Native/Interop.GetEUid.cs @@ -2,7 +2,6 @@ // 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; using System.Runtime.InteropServices; internal static partial class Interop diff --git a/src/Common/src/Interop/Unix/System.Native/Interop.GetPid.cs b/src/Common/src/Interop/Unix/System.Native/Interop.GetPid.cs index 02d259db7..b93f08953 100644 --- a/src/Common/src/Interop/Unix/System.Native/Interop.GetPid.cs +++ b/src/Common/src/Interop/Unix/System.Native/Interop.GetPid.cs @@ -2,7 +2,6 @@ // 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; using System.Runtime.InteropServices; internal static partial class Interop diff --git a/src/Common/src/Interop/Unix/System.Native/Interop.GetPwUid.cs b/src/Common/src/Interop/Unix/System.Native/Interop.GetPwUid.cs index 28b2309d0..5a9a23f87 100644 --- a/src/Common/src/Interop/Unix/System.Native/Interop.GetPwUid.cs +++ b/src/Common/src/Interop/Unix/System.Native/Interop.GetPwUid.cs @@ -2,7 +2,6 @@ // 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; using System.Runtime.InteropServices; internal static partial class Interop diff --git a/src/Common/src/Interop/Unix/System.Native/Interop.GetRandomBytes.cs b/src/Common/src/Interop/Unix/System.Native/Interop.GetRandomBytes.cs index 858506935..fcc9b8db9 100644 --- a/src/Common/src/Interop/Unix/System.Native/Interop.GetRandomBytes.cs +++ b/src/Common/src/Interop/Unix/System.Native/Interop.GetRandomBytes.cs @@ -2,8 +2,6 @@ // 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; -using System.Diagnostics; using System.Runtime.InteropServices; internal static partial class Interop diff --git a/src/Common/src/Interop/Unix/System.Native/Interop.GetSockOpt.cs b/src/Common/src/Interop/Unix/System.Native/Interop.GetSockOpt.cs index d0a724209..4fd722fd2 100644 --- a/src/Common/src/Interop/Unix/System.Native/Interop.GetSockOpt.cs +++ b/src/Common/src/Interop/Unix/System.Native/Interop.GetSockOpt.cs @@ -15,5 +15,8 @@ internal static partial class Interop [DllImport(Libraries.SystemNative, EntryPoint = "SystemNative_GetSockOpt")] internal static extern unsafe Error GetSockOpt(IntPtr socket, SocketOptionLevel optionLevel, SocketOptionName optionName, byte* optionValue, int* optionLen); + + [DllImport(Libraries.SystemNative, EntryPoint = "SystemNative_GetRawSockOpt")] + internal static extern unsafe Error GetRawSockOpt(SafeHandle socket, int optionLevel, int optionName, byte* optionValue, int* optionLen); } } diff --git a/src/Common/src/Interop/Unix/System.Native/Interop.LockFileRegion.cs b/src/Common/src/Interop/Unix/System.Native/Interop.LockFileRegion.cs index 1deb9a431..5f92357e8 100644 --- a/src/Common/src/Interop/Unix/System.Native/Interop.LockFileRegion.cs +++ b/src/Common/src/Interop/Unix/System.Native/Interop.LockFileRegion.cs @@ -2,7 +2,6 @@ // 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; using System.Runtime.InteropServices; internal static partial class Interop diff --git a/src/Common/src/Interop/Unix/System.Native/Interop.MountPoints.FormatInfo.cs b/src/Common/src/Interop/Unix/System.Native/Interop.MountPoints.FormatInfo.cs index ee5e42722..e02afa58e 100644 --- a/src/Common/src/Interop/Unix/System.Native/Interop.MountPoints.FormatInfo.cs +++ b/src/Common/src/Interop/Unix/System.Native/Interop.MountPoints.FormatInfo.cs @@ -44,6 +44,7 @@ internal static partial class Interop bdevfs = 0x62646576, bfs = 0x1BADFACE, binfmt_misc = 0x42494E4D, + bootfs = 0xA56D3FF9, btrfs = 0x9123683E, ceph = 0x00C36400, cgroupfs = 0x0027E0EB, @@ -65,6 +66,7 @@ internal static partial class Interop ext3 = 0xEF53, ext4 = 0xEF53, fat = 0x4006, + fd = 0xF00D1E, fhgfs = 0x19830326, fuse = 0x65735546, fuseblk = 0x65735546, @@ -86,6 +88,7 @@ internal static partial class Interop jffs2 = 0x72B6, jfs = 0x3153464A, kafs = 0x6B414653, + lofs = 0xEF53, /* loopback filesystem, magic same as ext2 */ logfs = 0xC97E8168, lustre = 0x0BD00BD0, minix_old = 0x137F, /* orig. minix */ @@ -227,6 +230,7 @@ internal static partial class Interop case "bdevfs": case "befs": case "bfs": + case "bootfs": case "bpf_fs": case "btrfs": case "btrfs_test": @@ -261,6 +265,7 @@ internal static partial class Interop case "jffs": case "jffs2": case "jfs": + case "lofs": case "logfs": case "lxfs": case "minix (30 char.)": @@ -384,15 +389,18 @@ internal static partial class Interop case "cgroupfs": case "cgroup2fs": case "configfs": + case "cpuset": case "cramfs": case "cramfs-wend": case "cryptkeeper": - case "cpuset": + case "ctfs": case "debugfs": + case "dev": case "devfs": case "devpts": case "devtmpfs": case "encfs": + case "fd": case "fdesc": case "fuse.gvfsd-fuse": case "fusectl": @@ -400,9 +408,11 @@ internal static partial class Interop case "hugetlbfs": case "libpam-encfs": case "ibpam-mount": + case "mntfs": + case "mqueue": case "mtpfs": case "mythtvfs": - case "mqueue": + case "objfs": case "openprom": case "openpromfs": case "pipefs": @@ -417,6 +427,7 @@ internal static partial class Interop case "securityfs": case "selinux": case "selinuxfs": + case "sharefs": case "sockfs": case "sysfs": case "tmpfs": diff --git a/src/Common/src/Interop/Unix/System.Native/Interop.MountPoints.cs b/src/Common/src/Interop/Unix/System.Native/Interop.MountPoints.cs index 134dcb920..21479bca6 100644 --- a/src/Common/src/Interop/Unix/System.Native/Interop.MountPoints.cs +++ b/src/Common/src/Interop/Unix/System.Native/Interop.MountPoints.cs @@ -3,7 +3,6 @@ // See the LICENSE file in the project root for more information. using System; -using System.Collections.Generic; using System.Runtime.InteropServices; internal static partial class Interop diff --git a/src/Common/src/Interop/Unix/System.Native/Interop.PathConf.cs b/src/Common/src/Interop/Unix/System.Native/Interop.PathConf.cs index 7213cb026..e2c127772 100644 --- a/src/Common/src/Interop/Unix/System.Native/Interop.PathConf.cs +++ b/src/Common/src/Interop/Unix/System.Native/Interop.PathConf.cs @@ -2,7 +2,6 @@ // 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; using System.Runtime.InteropServices; internal static partial class Interop diff --git a/src/Common/src/Interop/Unix/System.Native/Interop.Read.cs b/src/Common/src/Interop/Unix/System.Native/Interop.Read.cs index 233feabdb..e37a2ae6c 100644 --- a/src/Common/src/Interop/Unix/System.Native/Interop.Read.cs +++ b/src/Common/src/Interop/Unix/System.Native/Interop.Read.cs @@ -3,7 +3,6 @@ // See the LICENSE file in the project root for more information. using System.Runtime.InteropServices; -using Microsoft.Win32.SafeHandles; internal static partial class Interop { diff --git a/src/Common/src/Interop/Unix/System.Native/Interop.SetSockOpt.cs b/src/Common/src/Interop/Unix/System.Native/Interop.SetSockOpt.cs index 4c92eccac..e958c9fcc 100644 --- a/src/Common/src/Interop/Unix/System.Native/Interop.SetSockOpt.cs +++ b/src/Common/src/Interop/Unix/System.Native/Interop.SetSockOpt.cs @@ -15,5 +15,8 @@ internal static partial class Interop [DllImport(Libraries.SystemNative, EntryPoint = "SystemNative_SetSockOpt")] internal static extern unsafe Error SetSockOpt(IntPtr socket, SocketOptionLevel optionLevel, SocketOptionName optionName, byte* optionValue, int optionLen); + + [DllImport(Libraries.SystemNative, EntryPoint = "SystemNative_SetRawSockOpt")] + internal static extern unsafe Error SetRawSockOpt(SafeHandle socket, int optionLevel, int optionName, byte* optionValue, int optionLen); } } diff --git a/src/Common/src/Interop/Unix/System.Native/Interop.Stat.cs b/src/Common/src/Interop/Unix/System.Native/Interop.Stat.cs index d06fbda71..628bd9c70 100644 --- a/src/Common/src/Interop/Unix/System.Native/Interop.Stat.cs +++ b/src/Common/src/Interop/Unix/System.Native/Interop.Stat.cs @@ -55,7 +55,7 @@ internal static partial class Interop } [DllImport(Libraries.SystemNative, EntryPoint = "SystemNative_FStat", SetLastError = true)] - internal static extern int FStat(SafeFileHandle fd, out FileStatus output); + internal static extern int FStat(SafeHandle fd, out FileStatus output); [DllImport(Libraries.SystemNative, EntryPoint = "SystemNative_Stat", SetLastError = true)] internal static extern int Stat(string path, out FileStatus output); diff --git a/src/Common/src/Interop/Unix/System.Native/Interop.SysLog.cs b/src/Common/src/Interop/Unix/System.Native/Interop.SysLog.cs index 2edde6fbc..8933e9c3d 100644 --- a/src/Common/src/Interop/Unix/System.Native/Interop.SysLog.cs +++ b/src/Common/src/Interop/Unix/System.Native/Interop.SysLog.cs @@ -19,28 +19,6 @@ internal static partial class Interop LOG_NOTICE = 5, /* normal but significant condition */ LOG_INFO = 6, /* informational */ LOG_DEBUG = 7, /* debug-level messages */ - // Facilities - LOG_KERN = (0<<3), /* kernel messages */ - LOG_USER = (1<<3), /* random user-level messages */ - LOG_MAIL = (2<<3), /* mail system */ - LOG_DAEMON = (3<<3), /* system daemons */ - LOG_AUTH = (4<<3), /* authorization messages */ - LOG_SYSLOG = (5<<3), /* messages generated internally by syslogd */ - LOG_LPR = (6<<3), /* line printer subsystem */ - LOG_NEWS = (7<<3), /* network news subsystem */ - LOG_UUCP = (8<<3), /* UUCP subsystem */ - LOG_CRON = (9<<3), /* clock daemon */ - LOG_AUTHPRIV = (10<<3), /* authorization messages (private) */ - LOG_FTP = (11<<3), /* ftp daemon */ - // Between FTP and Local is reserved for system use - LOG_LOCAL0 = (16<<3), /* reserved for local use */ - LOG_LOCAL1 = (17<<3), /* reserved for local use */ - LOG_LOCAL2 = (18<<3), /* reserved for local use */ - LOG_LOCAL3 = (19<<3), /* reserved for local use */ - LOG_LOCAL4 = (20<<3), /* reserved for local use */ - LOG_LOCAL5 = (21<<3), /* reserved for local use */ - LOG_LOCAL6 = (22<<3), /* reserved for local use */ - LOG_LOCAL7 = (23<<3), /* reserved for local use */ } /// diff --git a/src/Common/src/Interop/Unix/System.Native/Interop.Write.cs b/src/Common/src/Interop/Unix/System.Native/Interop.Write.cs index fb06d463b..9c4e0aa2a 100644 --- a/src/Common/src/Interop/Unix/System.Native/Interop.Write.cs +++ b/src/Common/src/Interop/Unix/System.Native/Interop.Write.cs @@ -2,8 +2,8 @@ // 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; using System.Runtime.InteropServices; -using Microsoft.Win32.SafeHandles; internal static partial class Interop { @@ -22,6 +22,6 @@ internal static partial class Interop internal static extern unsafe int Write(SafeHandle fd, byte* buffer, int bufferSize); [DllImport(Libraries.SystemNative, EntryPoint = "SystemNative_Write", SetLastError = true)] - internal static extern unsafe int Write(int fd, byte* buffer, int bufferSize); + internal static extern unsafe int Write(IntPtr fd, byte* buffer, int bufferSize); } } diff --git a/src/Common/src/Interop/Windows/Advapi32/Interop.CryptImportKey.cs b/src/Common/src/Interop/Windows/Advapi32/Interop.CryptImportKey.cs index c741fcd8f..d6d1e3b1b 100644 --- a/src/Common/src/Interop/Windows/Advapi32/Interop.CryptImportKey.cs +++ b/src/Common/src/Interop/Windows/Advapi32/Interop.CryptImportKey.cs @@ -10,9 +10,9 @@ internal partial class Interop internal partial class Advapi32 { [DllImport(Libraries.Advapi32, CharSet = CharSet.Unicode, SetLastError = true)] - internal static extern bool CryptImportKey( + internal static extern unsafe bool CryptImportKey( SafeProvHandle hProv, - byte[] pbData, + byte* pbData, int dwDataLen, SafeKeyHandle hPubKey, int dwFlags, diff --git a/src/Common/src/Interop/Windows/Interop.Libraries.cs b/src/Common/src/Interop/Windows/Interop.Libraries.cs index 8b4df46ca..1c1b3db6a 100644 --- a/src/Common/src/Interop/Windows/Interop.Libraries.cs +++ b/src/Common/src/Interop/Windows/Interop.Libraries.cs @@ -39,5 +39,6 @@ internal static partial class Interop internal const string CompressionNative = "clrcompression.dll"; internal const string CoreWinRT = "api-ms-win-core-winrt-l1-1-0.dll"; internal const string MsQuic = "msquic.dll"; + internal const string HostPolicy = "hostpolicy.dll"; } } diff --git a/src/Common/src/Interop/Windows/Kernel32/Interop.EnumProcessModules.cs b/src/Common/src/Interop/Windows/Kernel32/Interop.EnumProcessModules.cs index 15850d212..581188f8f 100644 --- a/src/Common/src/Interop/Windows/Kernel32/Interop.EnumProcessModules.cs +++ b/src/Common/src/Interop/Windows/Kernel32/Interop.EnumProcessModules.cs @@ -11,6 +11,6 @@ internal partial class Interop internal partial class Kernel32 { [DllImport(Libraries.Kernel32, CharSet = CharSet.Unicode, SetLastError = true, EntryPoint = "K32EnumProcessModules")] - internal static extern bool EnumProcessModules(SafeProcessHandle handle, IntPtr modules, int size, ref int needed); + internal static extern bool EnumProcessModules(SafeProcessHandle handle, IntPtr[]? modules, int size, out int needed); } } diff --git a/src/Common/src/Interop/Windows/Kernel32/Interop.Globalization.cs b/src/Common/src/Interop/Windows/Kernel32/Interop.Globalization.cs index 192e555bb..2aa2d6a17 100644 --- a/src/Common/src/Interop/Windows/Kernel32/Interop.Globalization.cs +++ b/src/Common/src/Interop/Windows/Kernel32/Interop.Globalization.cs @@ -9,6 +9,15 @@ internal static partial class Interop { internal static unsafe partial class Kernel32 { + // Under debug mode only, we'll want to check the error codes + // of some of the p/invokes we make. + +#if DEBUG + private const bool SetLastErrorForDebug = true; +#else + private const bool SetLastErrorForDebug = false; +#endif + internal const uint LOCALE_ALLOW_NEUTRAL_NAMES = 0x08000000; // Flag to allow returning neutral names/lcids for name conversion internal const uint LOCALE_ILANGUAGE = 0x00000001; internal const uint LOCALE_SUPPLEMENTAL = 0x00000002; @@ -31,6 +40,10 @@ internal static partial class Interop internal const uint TIME_NOSECONDS = 0x00000002; + internal const int GEOCLASS_NATION = 16; + internal const int GEO_ISO2 = 4; + internal const int GEOID_NOT_AVAILABLE = -1; + internal const string LOCALE_NAME_USER_DEFAULT = null; internal const string LOCALE_NAME_SYSTEM_DEFAULT = "!x-sys-default-locale"; @@ -40,7 +53,7 @@ internal static partial class Interop [DllImport("kernel32.dll", CharSet = CharSet.Unicode)] internal static extern int LocaleNameToLCID(string lpName, uint dwFlags); - [DllImport("kernel32.dll", CharSet = CharSet.Unicode)] + [DllImport("kernel32.dll", CharSet = CharSet.Unicode, SetLastError = true)] internal static extern int LCMapStringEx( string? lpLocaleName, uint dwMapFlags, @@ -52,7 +65,7 @@ internal static partial class Interop void* lpReserved, IntPtr sortHandle); - [DllImport("kernel32.dll", EntryPoint = "FindNLSStringEx")] + [DllImport("kernel32.dll", EntryPoint = "FindNLSStringEx", SetLastError = SetLastErrorForDebug)] internal static extern int FindNLSStringEx( char* lpLocaleName, uint dwFindNLSStringFlags, @@ -85,14 +98,14 @@ internal static partial class Interop int cchCount2, bool bIgnoreCase); - [DllImport("kernel32.dll", EntryPoint = "FindStringOrdinal")] + [DllImport("kernel32.dll", EntryPoint = "FindStringOrdinal", SetLastError = SetLastErrorForDebug)] internal static extern int FindStringOrdinal( uint dwFindStringOrdinalFlags, char* lpStringSource, int cchSource, char* lpStringValue, int cchValue, - int bIgnoreCase); + BOOL bIgnoreCase); [DllImport("kernel32.dll", CharSet = CharSet.Unicode)] internal static extern bool IsNLSDefinedString( @@ -124,6 +137,12 @@ internal static partial class Interop [DllImport("kernel32.dll", CharSet = CharSet.Unicode)] internal static extern int GetCalendarInfoEx(string? lpLocaleName, uint Calendar, IntPtr lpReserved, uint CalType, IntPtr lpCalData, int cchData, IntPtr lpValue); + [DllImport("kernel32.dll")] + internal static extern int GetUserGeoID(int geoClass); + + [DllImport("kernel32.dll", CharSet = CharSet.Unicode)] + internal static extern int GetGeoInfo(int location, int geoType, char* lpGeoData, int cchData, int LangId); + [DllImport("kernel32.dll", CharSet = CharSet.Unicode)] internal static extern bool EnumCalendarInfoExEx(EnumCalendarInfoProcExEx pCalInfoEnumProcExEx, string lpLocaleName, uint Calendar, string? lpReserved, uint CalType, void* lParam); diff --git a/src/Common/src/Interop/Windows/Kernel32/Interop.IsWow64Process_SafeProcessHandle.cs b/src/Common/src/Interop/Windows/Kernel32/Interop.IsWow64Process_SafeProcessHandle.cs index e5a32facf..dc8626a0a 100644 --- a/src/Common/src/Interop/Windows/Kernel32/Interop.IsWow64Process_SafeProcessHandle.cs +++ b/src/Common/src/Interop/Windows/Kernel32/Interop.IsWow64Process_SafeProcessHandle.cs @@ -10,6 +10,6 @@ internal partial class Interop internal partial class Kernel32 { [DllImport(Libraries.Kernel32, SetLastError = true)] - internal static extern bool IsWow64Process(SafeProcessHandle hProcess, ref bool Wow64Process); + internal static extern bool IsWow64Process(SafeProcessHandle hProcess, out bool Wow64Process); } } diff --git a/src/Common/src/Interop/Windows/Normaliz/Interop.Normalization.cs b/src/Common/src/Interop/Windows/Normaliz/Interop.Normalization.cs index 3e954483d..362b7ffb4 100644 --- a/src/Common/src/Interop/Windows/Normaliz/Interop.Normalization.cs +++ b/src/Common/src/Interop/Windows/Normaliz/Interop.Normalization.cs @@ -3,21 +3,21 @@ // See the LICENSE file in the project root for more information. using System.Runtime.InteropServices; +using System.Text; internal static partial class Interop { internal static partial class Normaliz { [DllImport("Normaliz.dll", CharSet = CharSet.Unicode, SetLastError = true)] - internal static extern bool IsNormalizedString(int normForm, string source, int length); + internal static extern unsafe BOOL IsNormalizedString(NormalizationForm normForm, char* source, int length); [DllImport("Normaliz.dll", CharSet = CharSet.Unicode, SetLastError = true)] - internal static extern int NormalizeString( - int normForm, - string source, + internal static extern unsafe int NormalizeString( + NormalizationForm normForm, + char* source, int sourceLength, - [System.Runtime.InteropServices.OutAttribute] - char[]? destination, + char* destination, int destinationLength); } } diff --git a/src/Common/src/Interop/Windows/NtDll/Interop.NtStatus.cs b/src/Common/src/Interop/Windows/NtDll/Interop.NtStatus.cs index 2d51c44f5..413efdfbf 100644 --- a/src/Common/src/Interop/Windows/NtDll/Interop.NtStatus.cs +++ b/src/Common/src/Interop/Windows/NtDll/Interop.NtStatus.cs @@ -1,4 +1,4 @@ -// Licensed to the .NET Foundation under one or more agreements. +// 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. @@ -7,15 +7,16 @@ internal static partial class Interop internal class StatusOptions { // Error codes from ntstatus.h - internal const uint STATUS_SUCCESS = 0x00000000; - internal const uint STATUS_SOME_NOT_MAPPED = 0x00000107; - internal const uint STATUS_NO_MORE_FILES = 0x80000006; - internal const uint STATUS_INVALID_PARAMETER = 0xC000000D; - internal const uint STATUS_NO_MEMORY = 0xC0000017; - internal const uint STATUS_OBJECT_NAME_NOT_FOUND = 0xC0000034; - internal const uint STATUS_NONE_MAPPED = 0xC0000073; + internal const uint STATUS_SUCCESS = 0x00000000; + internal const uint STATUS_SOME_NOT_MAPPED = 0x00000107; + internal const uint STATUS_NO_MORE_FILES = 0x80000006; + internal const uint STATUS_INVALID_PARAMETER = 0xC000000D; + internal const uint STATUS_FILE_NOT_FOUND = 0xC000000F; + internal const uint STATUS_NO_MEMORY = 0xC0000017; + internal const uint STATUS_ACCESS_DENIED = 0xC0000022; + internal const uint STATUS_OBJECT_NAME_NOT_FOUND = 0xC0000034; + internal const uint STATUS_ACCOUNT_RESTRICTION = 0xC000006E; + internal const uint STATUS_NONE_MAPPED = 0xC0000073; internal const uint STATUS_INSUFFICIENT_RESOURCES = 0xC000009A; - internal const uint STATUS_ACCESS_DENIED = 0xC0000022; - internal const uint STATUS_ACCOUNT_RESTRICTION = 0xc000006e; } } diff --git a/src/Common/src/Interop/Windows/NtDll/Interop.RtlGetVersion.cs b/src/Common/src/Interop/Windows/NtDll/Interop.RtlGetVersion.cs index 17f052150..d01a65913 100644 --- a/src/Common/src/Interop/Windows/NtDll/Interop.RtlGetVersion.cs +++ b/src/Common/src/Interop/Windows/NtDll/Interop.RtlGetVersion.cs @@ -18,19 +18,15 @@ internal partial class Interop return RtlGetVersion(ref osvi); } - internal static unsafe string RtlGetVersion() + [StructLayout(LayoutKind.Sequential, CharSet = CharSet.Unicode)] + internal unsafe struct RTL_OSVERSIONINFOEX { - const string Version = "Microsoft Windows"; - if (RtlGetVersionEx(out RTL_OSVERSIONINFOEX osvi) == 0) - { - return osvi.szCSDVersion[0] != '\0' ? - string.Format("{0} {1}.{2}.{3} {4}", Version, osvi.dwMajorVersion, osvi.dwMinorVersion, osvi.dwBuildNumber, new string(&(osvi.szCSDVersion[0]))) : - string.Format("{0} {1}.{2}.{3}", Version, osvi.dwMajorVersion, osvi.dwMinorVersion, osvi.dwBuildNumber); - } - else - { - return Version; - } + internal uint dwOSVersionInfoSize; + internal uint dwMajorVersion; + internal uint dwMinorVersion; + internal uint dwBuildNumber; + internal uint dwPlatformId; + internal fixed char szCSDVersion[128]; } } } diff --git a/src/Common/src/System/Diagnostics/NetFrameworkUtils.cs b/src/Common/src/System/Diagnostics/NetFrameworkUtils.cs index 59d028c5a..de9f756c1 100644 --- a/src/Common/src/System/Diagnostics/NetFrameworkUtils.cs +++ b/src/Common/src/System/Diagnostics/NetFrameworkUtils.cs @@ -220,7 +220,7 @@ namespace System.Diagnostics StringBuilder installBuilder = new StringBuilder(); installBuilder.Append(installRoot); if (!installRoot.EndsWith("\\", StringComparison.Ordinal)) - installBuilder.Append("\\"); + installBuilder.Append('\\'); installBuilder.Append(version); dllDir = installBuilder.ToString(); } diff --git a/src/Common/src/System/Diagnostics/TraceListenerHelpers.cs b/src/Common/src/System/Diagnostics/TraceListenerHelpers.cs index 6e5bbfa07..4ffd68059 100644 --- a/src/Common/src/System/Diagnostics/TraceListenerHelpers.cs +++ b/src/Common/src/System/Diagnostics/TraceListenerHelpers.cs @@ -2,11 +2,12 @@ // The .NET Foundation licenses this file to you under the MIT license. // See the LICENSE file in the project root for more information. +#nullable enable namespace System.Diagnostics { internal static partial class TraceListenerHelpers { - private static volatile string s_processName; + private static volatile string? s_processName; internal static int GetThreadId() { diff --git a/src/Common/src/System/IO/ChunkedMemoryStream.cs b/src/Common/src/System/IO/ChunkedMemoryStream.cs index a7295c4c2..ceb003f86 100644 --- a/src/Common/src/System/IO/ChunkedMemoryStream.cs +++ b/src/Common/src/System/IO/ChunkedMemoryStream.cs @@ -2,6 +2,7 @@ // The .NET Foundation licenses this file to you under the MIT license. // See the LICENSE file in the project root for more information. +#nullable enable using System.Diagnostics; using System.Threading; using System.Threading.Tasks; @@ -11,8 +12,8 @@ namespace System.IO /// Provides an in-memory stream composed of non-contiguous chunks. internal sealed class ChunkedMemoryStream : Stream { - private MemoryChunk _headChunk; - private MemoryChunk _currentChunk; + private MemoryChunk? _headChunk; + private MemoryChunk? _currentChunk; private const int InitialChunkDefaultSize = 1024; private const int MaxChunkSize = 1024 * InitialChunkDefaultSize; @@ -24,7 +25,7 @@ namespace System.IO { byte[] result = new byte[_totalLength]; int offset = 0; - for (MemoryChunk chunk = _headChunk; chunk != null; chunk = chunk._next) + for (MemoryChunk? chunk = _headChunk; chunk != null; chunk = chunk._next) { Debug.Assert(chunk._next == null || chunk._freeOffset == chunk._buffer.Length); Buffer.BlockCopy(chunk._buffer, 0, result, offset, chunk._freeOffset); @@ -109,7 +110,7 @@ namespace System.IO { internal readonly byte[] _buffer; internal int _freeOffset; - internal MemoryChunk _next; + internal MemoryChunk? _next; internal MemoryChunk(int bufferSize) { _buffer = new byte[bufferSize]; } } diff --git a/src/Common/src/System/IO/DelegatingStream.cs b/src/Common/src/System/IO/DelegatingStream.cs index 889bbb213..cbb3075a1 100644 --- a/src/Common/src/System/IO/DelegatingStream.cs +++ b/src/Common/src/System/IO/DelegatingStream.cs @@ -2,6 +2,7 @@ // The .NET Foundation licenses this file to you under the MIT license. // See the LICENSE file in the project root for more information. +#nullable enable using System.Diagnostics; using System.IO; using System.Threading; @@ -113,7 +114,7 @@ namespace System.Net.Http return _innerStream.ReadAsync(buffer, cancellationToken); } - public override IAsyncResult BeginRead(byte[] buffer, int offset, int count, AsyncCallback callback, object state) + public override IAsyncResult BeginRead(byte[] buffer, int offset, int count, AsyncCallback? callback, object? state) { return _innerStream.BeginRead(buffer, offset, count, callback, state); } @@ -167,7 +168,7 @@ namespace System.Net.Http return _innerStream.WriteAsync(buffer, cancellationToken); } - public override IAsyncResult BeginWrite(byte[] buffer, int offset, int count, AsyncCallback callback, object state) + public override IAsyncResult BeginWrite(byte[] buffer, int offset, int count, AsyncCallback? callback, object? state) { return _innerStream.BeginWrite(buffer, offset, count, callback, state); } diff --git a/src/Common/src/System/IO/FileSystem.Attributes.Windows.cs b/src/Common/src/System/IO/FileSystem.Attributes.Windows.cs index 977293e3f..274f049f5 100644 --- a/src/Common/src/System/IO/FileSystem.Attributes.Windows.cs +++ b/src/Common/src/System/IO/FileSystem.Attributes.Windows.cs @@ -81,7 +81,7 @@ namespace System.IO ) { // Assert so we can track down other cases (if any) to add to our test suite - Debug.Assert(errorCode == Interop.Errors.ERROR_ACCESS_DENIED || errorCode == Interop.Errors.ERROR_SHARING_VIOLATION, + Debug.Assert(errorCode == Interop.Errors.ERROR_ACCESS_DENIED || errorCode == Interop.Errors.ERROR_SHARING_VIOLATION || errorCode == Interop.Errors.ERROR_SEM_TIMEOUT, $"Unexpected error code getting attributes {errorCode} from path {path}"); // Files that are marked for deletion will not let you GetFileAttributes, diff --git a/src/Common/src/System/IO/ReadOnlyMemoryStream.cs b/src/Common/src/System/IO/ReadOnlyMemoryStream.cs index 5ec499dc6..6c826601a 100644 --- a/src/Common/src/System/IO/ReadOnlyMemoryStream.cs +++ b/src/Common/src/System/IO/ReadOnlyMemoryStream.cs @@ -105,7 +105,7 @@ namespace System.IO new ValueTask(Task.FromCanceled(cancellationToken)) : new ValueTask(Read(buffer.Span)); - public override IAsyncResult BeginRead(byte[] buffer, int offset, int count, AsyncCallback callback, object state) => + public override IAsyncResult BeginRead(byte[] buffer, int offset, int count, AsyncCallback? callback, object? state) => TaskToApm.Begin(ReadAsync(buffer, offset, count), callback, state); public override int EndRead(IAsyncResult asyncResult) => diff --git a/src/Common/src/System/IO/RowConfigReader.cs b/src/Common/src/System/IO/RowConfigReader.cs index fcd9d10db..b59fe765b 100644 --- a/src/Common/src/System/IO/RowConfigReader.cs +++ b/src/Common/src/System/IO/RowConfigReader.cs @@ -2,7 +2,9 @@ // The .NET Foundation licenses this file to you under the MIT license. // See the LICENSE file in the project root for more information. +#nullable enable using System.Diagnostics; +using System.Diagnostics.CodeAnalysis; using System.Globalization; namespace System.IO @@ -47,8 +49,7 @@ namespace System.IO /// public string GetNextValue(string key) { - string value; - if (!TryGetNextValue(key, out value)) + if (!TryGetNextValue(key, out string? value)) { throw new InvalidOperationException("Couldn't get next value with key " + key); } @@ -62,7 +63,7 @@ namespace System.IO /// Tries to get the next occurrence of the given key from the current position of the reader. /// If successful, returns true and stores the result in 'value'. Otherwise, returns false. /// - public bool TryGetNextValue(string key, out string value) + public bool TryGetNextValue(string key, [NotNullWhen(true)] out string? value) { Debug.Assert(_buffer != null); if (_currentIndex >= _buffer.Length) diff --git a/src/Common/src/System/Runtime/ExceptionServices/ExceptionStackTrace.cs b/src/Common/src/System/Runtime/ExceptionServices/ExceptionStackTrace.cs index c8b633ca7..57647f3ab 100644 --- a/src/Common/src/System/Runtime/ExceptionServices/ExceptionStackTrace.cs +++ b/src/Common/src/System/Runtime/ExceptionServices/ExceptionStackTrace.cs @@ -2,6 +2,7 @@ // The .NET Foundation licenses this file to you under the MIT license. // See the LICENSE file in the project root for more information. +#nullable enable using System.Diagnostics; using System.Reflection; @@ -16,12 +17,12 @@ namespace System.Runtime.ExceptionServices Debug.Assert(exception != null, "Expected non-null Exception"); const string ExceptionRemoteStackTraceStringName = "_remoteStackTraceString"; - FieldInfo fi = typeof(Exception).GetField(ExceptionRemoteStackTraceStringName, BindingFlags.NonPublic | BindingFlags.Instance); + FieldInfo? fi = typeof(Exception).GetField(ExceptionRemoteStackTraceStringName, BindingFlags.NonPublic | BindingFlags.Instance); if (fi != null) { string text = - (string)fi.GetValue(exception) + + (string?)fi.GetValue(exception) + Environment.StackTrace + Environment.NewLine + "--- End of stack trace from AddCurrentStack ---" + Environment.NewLine; fi.SetValue(exception, text); diff --git a/src/Common/src/System/StrongToWeakReference.cs b/src/Common/src/System/StrongToWeakReference.cs index f49a9f13d..83dfd05dc 100644 --- a/src/Common/src/System/StrongToWeakReference.cs +++ b/src/Common/src/System/StrongToWeakReference.cs @@ -9,7 +9,7 @@ namespace System /// Provides an object wrapper that can transition between strong and weak references to the object. internal sealed class StrongToWeakReference : WeakReference where T : class { - private T _strongRef; + private T? _strongRef; /// Initializes the instance with a strong reference to the specified object. /// The object to wrap. @@ -30,9 +30,9 @@ namespace System } /// Gets the wrapped object. - public new T Target => _strongRef ?? WeakTarget; + public new T? Target => _strongRef ?? WeakTarget; /// Gets the wrapped object via its weak reference. - private T WeakTarget => base.Target as T; + private T? WeakTarget => base.Target as T; } } diff --git a/src/Common/src/System/Text/StringBuilderCache.cs b/src/Common/src/System/Text/StringBuilderCache.cs index aac2c2e8a..4d96cb301 100644 --- a/src/Common/src/System/Text/StringBuilderCache.cs +++ b/src/Common/src/System/Text/StringBuilderCache.cs @@ -11,7 +11,7 @@ namespace System.Text // The value 360 was chosen in discussion with performance experts as a compromise between using // as litle memory per thread as possible and still covering a large part of short-lived // StringBuilder creations on the startup path of VS designers. - private const int MaxBuilderSize = 360; + internal const int MaxBuilderSize = 360; private const int DefaultCapacity = 16; // == StringBuilder.DefaultCapacity // WARNING: We allow diagnostic tools to directly inspect this member (t_cachedInstance). diff --git a/src/Common/src/System/Threading/Tasks/RendezvousAwaitable.cs b/src/Common/src/System/Threading/Tasks/RendezvousAwaitable.cs index 84134884f..890c1ab75 100644 --- a/src/Common/src/System/Threading/Tasks/RendezvousAwaitable.cs +++ b/src/Common/src/System/Threading/Tasks/RendezvousAwaitable.cs @@ -2,7 +2,9 @@ // The .NET Foundation licenses this file to you under the MIT license. // See the LICENSE file in the project root for more information. +#nullable enable using System.Diagnostics; +using System.Diagnostics.CodeAnalysis; using System.Runtime.CompilerServices; using System.Runtime.ExceptionServices; @@ -19,11 +21,11 @@ namespace System.Threading.Tasks /// The continuation to invoke when the operation completes, or if the operation /// has completed before OnCompleted is called. /// - private Action _continuation; + private Action? _continuation; /// The exception representing the failed async operation, if it failed. - private ExceptionDispatchInfo _error; + private ExceptionDispatchInfo? _error; /// The result of the async operation, if it succeeded. - private TResult _result; + [AllowNull] private TResult _result = default; #if DEBUG private bool _resultSet; #endif @@ -39,7 +41,7 @@ namespace System.Threading.Tasks { get { - Action c = Volatile.Read(ref _continuation); + Action? c = Volatile.Read(ref _continuation); Debug.Assert(c == null || c == s_completionSentinel); return c != null; } @@ -55,7 +57,7 @@ namespace System.Threading.Tasks // Propagate any error if there is one, clearing it out first to prepare for reuse. // We don't need to clear a result, as result and error are mutually exclusive. - ExceptionDispatchInfo error = _error; + ExceptionDispatchInfo? error = _error; if (error != null) { _error = null; @@ -101,7 +103,7 @@ namespace System.Threading.Tasks /// Alerts any awaiter that the operation has completed. private void NotifyAwaiter() { - Action c = _continuation ?? Interlocked.CompareExchange(ref _continuation, s_completionSentinel, null); + Action? c = _continuation ?? Interlocked.CompareExchange(ref _continuation, s_completionSentinel, null); if (c != null) { Debug.Assert(c != s_completionSentinel); @@ -122,7 +124,7 @@ namespace System.Threading.Tasks { Debug.Assert(continuation != null); - Action c = _continuation ?? Interlocked.CompareExchange(ref _continuation, continuation, null); + Action? c = _continuation ?? Interlocked.CompareExchange(ref _continuation, continuation, null); if (c != null) { Debug.Assert(c == s_completionSentinel); diff --git a/src/Framework/Framework.depproj b/src/Framework/Framework.depproj index efed62681..386946a02 100644 --- a/src/Framework/Framework.depproj +++ b/src/Framework/Framework.depproj @@ -71,6 +71,8 @@ <_filteredNuGetDeployByFileName Include="@(_nuGetDeployByFileName)" Condition="'%(Identity)' == 'netstandard'" /> <_filteredNuGetDeployByFileName Include="@(_nuGetDeployByFileName)" Condition="'%(Identity)' == 'mscorlib'" /> + <_filteredNuGetDeployByFileName Include="@(_nuGetDeployByFileName)" Condition="$([System.String]::new('%(Identity)').StartsWith('libSystem'))" /> + <_filteredNuGetDeployByFileName Include="@(_nuGetDeployByFileName)" Condition="'%(Identity)' == 'clrcompression'" /> diff --git a/src/ILCompiler.CppCodeGen/src/CppCodeGen/CppWriter.cs b/src/ILCompiler.CppCodeGen/src/CppCodeGen/CppWriter.cs index d3430c6cd..daab1bca5 100644 --- a/src/ILCompiler.CppCodeGen/src/CppCodeGen/CppWriter.cs +++ b/src/ILCompiler.CppCodeGen/src/CppCodeGen/CppWriter.cs @@ -589,6 +589,16 @@ namespace ILCompiler.CppCodeGen sb.AppendLine(); AppendCppMethodDeclaration(sb, method, true); sb.AppendLine(); + + // TODO: workaround unreachable globalization methods + string moduleName = method.GetPInvokeMethodMetadata().Module; + if (moduleName == (_compilation.TypeSystemContext.Target.IsWindows ? "libSystem.Globalization.Native" : "kernel32.dll")) + { + sb.Append("{ throw 0; }"); + methodCodeNodeNeedingCode.SetCode(sb.ToString(), Array.Empty()); + return; + } + sb.Append("{"); sb.Indent(); diff --git a/src/ILCompiler/src/ConfigurablePInvokePolicy.cs b/src/ILCompiler/src/ConfigurablePInvokePolicy.cs index 55044cee5..d4c302ab9 100644 --- a/src/ILCompiler/src/ConfigurablePInvokePolicy.cs +++ b/src/ILCompiler/src/ConfigurablePInvokePolicy.cs @@ -71,7 +71,7 @@ namespace ILCompiler else { // Account for System.Private.CoreLib.Native / System.Globalization.Native / System.Native / etc - return importModule.StartsWith("System."); + return importModule.StartsWith("libSystem."); } } } diff --git a/src/System.Private.CoreLib/shared/Internal/Resources/WindowsRuntimeResourceManagerBase.cs b/src/System.Private.CoreLib/shared/Internal/Resources/WindowsRuntimeResourceManagerBase.cs index 173b2372c..20b73ed41 100644 --- a/src/System.Private.CoreLib/shared/Internal/Resources/WindowsRuntimeResourceManagerBase.cs +++ b/src/System.Private.CoreLib/shared/Internal/Resources/WindowsRuntimeResourceManagerBase.cs @@ -12,7 +12,7 @@ namespace Internal.Resources { public abstract bool Initialize(string libpath, string reswFilename, out PRIExceptionInfo? exceptionInfo); - public abstract string GetString(string stringName, string? startingCulture, string? neutralResourcesCulture); + public abstract string? GetString(string stringName, string? startingCulture, string? neutralResourcesCulture); public abstract CultureInfo? GlobalResourceContextBestFitCultureInfo { diff --git a/src/System.Private.CoreLib/shared/Microsoft/Win32/SafeHandles/SafeFileHandle.Unix.cs b/src/System.Private.CoreLib/shared/Microsoft/Win32/SafeHandles/SafeFileHandle.Unix.cs index ad9e3eaba..4a3b2cee4 100644 --- a/src/System.Private.CoreLib/shared/Microsoft/Win32/SafeHandles/SafeFileHandle.Unix.cs +++ b/src/System.Private.CoreLib/shared/Microsoft/Win32/SafeHandles/SafeFileHandle.Unix.cs @@ -5,7 +5,6 @@ using System; using System.Diagnostics; using System.IO; -using System.Runtime.InteropServices; namespace Microsoft.Win32.SafeHandles { diff --git a/src/System.Private.CoreLib/shared/Resources/Strings.resx b/src/System.Private.CoreLib/shared/Resources/Strings.resx new file mode 100644 index 000000000..c816a9b0f --- /dev/null +++ b/src/System.Private.CoreLib/shared/Resources/Strings.resx @@ -0,0 +1,3739 @@ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + text/microsoft-resx + + + 2.0 + + + System.Resources.ResXResourceReader, System.Windows.Forms, Version=4.0.0.0, Culture=neutral, PublicKeyToken=b77a5c561934e089 + + + System.Resources.ResXResourceWriter, System.Windows.Forms, Version=4.0.0.0, Culture=neutral, PublicKeyToken=b77a5c561934e089 + + + Cannot create an abstract class. + + + Cannot create an instance of {0} because it is an abstract class. + + + Cannot dynamically create an instance of ArgIterator. + + + Cannot create a type for which Type.ContainsGenericParameters is true. + + + Cannot create an instance of {0} because Type.ContainsGenericParameters is true. + + + Cannot create an instance of an interface. + + + Cannot create an instance of {0} because it is an interface. + + + Cannot dynamically create an instance of System.Void. + + + Type initializer was not callable. + + + Cannot set a constant field. + + + Cannot create an instance of void. + + + One or more errors occurred. + + + An element of innerExceptions was null. + + + The serialization stream contains no inner exceptions. + + + (Inner Exception #{0}) + This text is prepended to each inner exception description during aggregate exception formatting + + + Name: + + + There are no context policies. + + + Default principal object cannot be set twice. + + + Ambiguous implementation found. + + + Cannot access member. + + + Attempted to read or write protected memory. This is often an indication that other memory is corrupt. + + + Ambiguous match found. + + + Error in the application. + + + Value does not fall within the expected range. + + + Specified argument was out of the range of valid values. + + + Overflow or underflow in the arithmetic operation. + + + Array lengths must be the same. + + + Destination array is not long enough to copy all the items in the collection. Check array index and length. + + + Attempted to access an element as a type incompatible with the array. + + + Array must not be of length zero. + + + Read an invalid decimal value from the buffer. + + + Format of the executable (.exe) or library (.dll) is invalid. + + + Encountered an invalid type for a default value. + + + Unable to sort because the IComparer.Compare() method returns inconsistent results. Either a value does not compare equal to itself, or one value repeatedly compared to another value yields different results. IComparer: '{0}'. + + + Not enough space available in the buffer. + + + TimeSpan does not accept floating point Not-a-Number values. + + + String cannot contain a minus sign if the base is not 10. + + + The usage of IKeyComparer and IHashCodeProvider/IComparer interfaces cannot be mixed; use one or the other. + + + Attempt to unload the AppDomain failed. + + + Failed to resolve type from string "{0}" which was embedded in custom attribute blob. + + + Must specify property Set or Get or method call for a COM Object. + + + Error HRESULT E_FAIL has been returned from a call to a COM component. + + + Only one of the following binding flags can be set: BindingFlags.SetProperty, BindingFlags.PutDispProperty, BindingFlags.PutRefDispProperty. + + + Cannot specify both CreateInstance and another access type. + + + Error occurred during a cryptographic operation. + + + Binary format of the specified custom attribute was invalid. + + + A datatype misalignment was detected in a load or store instruction. + + + Combination of arguments to the DateTime constructor is out of the legal range. + + + Decimal constructor requires an array or span of four valid decimal bytes. + + + Attempted to access a path that is not on the disk. + + + Attempted to divide by zero. + + + Delegate to an instance method cannot have null 'this'. + + + Cannot bind to the target method because its signature is not compatible with that of the delegate type. + + + Delegates must be of the same type. + + + Dll was not found. + + + Duplicate objects in argument. + + + This ExceptionHandlingClause is not a clause. + + + This ExceptionHandlingClause is not a filter. + + + Array may not be empty. + + + String may not be empty or null. + + + Attempted to read past the end of the stream. + + + Entry point was not found. + + + Object must be the same type as the enum. The type passed in was '{0}'; the enum type was '{1}'. + + + Enum underlying type and the object must be same type or object. Type passed in was '{0}'; the enum underlying type was '{1}'. + + + Illegal enum value: {0}. + + + Literal value was not found. + + + Enum underlying type and the object must be same type or object must be a String. Type passed in was '{0}'; the enum underlying type was '{1}'. + + + Requested value '{0}' was not found. + + + Internal error in the runtime. + + + External component has thrown an exception. + + + Attempted to access a field that is not accessible by the caller. + + + Field '{0}' defined on type '{1}' is not a field on the target object which is of type '{2}'. + + + No arguments can be provided to Get a field value. + + + Cannot specify both GetField and SetProperty. + + + Only the field value can be specified to set a field value. + + + Cannot specify both Get and Set on a field. + + + Cannot specify Set on a Field and Invoke on a method. + + + Cannot specify both SetField and GetProperty. + + + One of the identified items was in an invalid format. + + + Method must be called on a Type for which Type.IsGenericParameter is false. + + + Property Get method was not found. + + + Byte array for GUID must be exactly {0} bytes long. + + + Handle does not support asynchronous operations. The parameters to the FileStream constructor may need to be changed to indicate that the handle was opened synchronously (that is, it was not opened for overlapped I/O). + + + Handle does not support synchronous operations. The parameters to the FileStream constructor may need to be changed to indicate that the handle was opened asynchronously (that is, it was opened explicitly for overlapped I/O). + + + The number style AllowHexSpecifier is not supported on floating point data types. + + + Hashtable's capacity overflowed and went negative. Check load factor, capacity and the current size of the table. + + + All indexes must be of type Int32. + + + Index was outside the bounds of the array. + + + Insufficient stack to continue executing the program safely. This can happen from having too many functions on the call stack or function on the stack using too much stack space. + + + The ANSI string passed in could not be converted from the default ANSI code page to Unicode. + + + Invalid Base. + + + Specified cast is not valid. + + + Attempt has been made to use a COM object that does not have a backing class factory. + + + Specified filter criteria was invalid. + + + Invalid handle. + + + With the AllowHexSpecifier bit set in the enum bit field, the only other valid bits that can be combined into the enum value must be a subset of those in HexNumber. + + + The NeutralResourcesLanguageAttribute on the assembly "{0}" specifies an invalid culture name: "{1}". + + + The NeutralResourcesLanguageAttribute specifies an invalid or unrecognized ultimate resource fallback location: "{0}". + + + Satellite contract version attribute on the assembly '{0}' specifies an invalid version: {1}. + + + Specified OLE variant was invalid. + + + Operation is not valid due to the current state of the object. + + + The return Type must be a type provided by the runtime. + + + The signature Type array contains some invalid type (i.e. null, void) + + + The UTF8 string passed in could not be converted to Unicode. + + + I/O error occurred. + + + The given key was not present in the dictionary. + + + The given key '{0}' was not present in the dictionary. + + + Destination array was not long enough. Check the destination index, length, and the array's lower bounds. + + + Source array was not long enough. Check the source index, length, and the array's lower bounds. + + + Source string was not long enough. Check sourceIndex and count. + + + The arrays' lower bounds must be identical. + + + AsAny cannot be used on return types, ByRef parameters, ArrayWithOffset, or parameters passed from unmanaged to managed. + + + Marshaling directives are invalid. + + + Attempt to access the method failed. + + + Attempt to access the method "{0}" on type "{1}" failed. + + + Attempted to access a non-existing field. + + + Unable to find manifest resource. + + + Attempted to access a missing member. + + + Attempted to access a missing method. + + + Attempted to add multiple callbacks to a delegate that does not support multicast. + + + Object must be of type Boolean. + + + Object must be of type Byte. + + + Object must be of type Char. + + + Object must be of type DateTime. + + + Object must be of type DateTimeOffset. + + + Object must be of type Decimal. + + + Type must derive from Delegate. + + + Object must be of type Double. + + + Drive name must be a root directory (i.e. 'C:\') or a drive letter ('C'). + + + Type provided must be an Enum. + + + The value passed in must be an enum base or an underlying type for an enum, such as an Int32. + + + Object must be of type GUID. + + + Object must be of type Int16. + + + Object must be of type Int32. + + + Object must be of type Int64. + + + Object must be of type IntPtr. + + + Type passed must be an interface. + + + Type must be a Pointer. + + + Object must be an array of primitives. + + + Object must be of type RuntimeAssembly. + + + Object must be of type SByte. + + + Object must be of type Single. + + + Object must be of type String. + + + Object must be of type TimeSpan. + + + Type must be a type provided by the runtime. + + + Argument must be true. + + + Object must be of type UInt16. + + + Object must be of type UInt32. + + + Object must be of type UInt64. + + + Object must be of type UIntPtr. + + + Object must be of type Version. + + + Must specify valid information for parsing in the string. + + + Named parameter value must not be null. + + + Named parameter array cannot be bigger than argument array. + + + No PInvoke conversion exists for value passed to Object-typed parameter. + + + Array was not a one-dimensional array. + + + Array was not a two-dimensional array. + + + Array was not a three-dimensional array. + + + Must provide at least one rank. + + + Argument count must not be negative. + + + Must specify binding flags describing the invoke operation required (BindingFlags.InvokeMethod CreateInstance GetField SetField GetProperty SetProperty). + + + No parameterless constructor defined for type '{0}'. + + + Specified TypeInfo was invalid because it did not support the ITypeInfo interface. + + + Specified TypeLib was invalid because it did not support the ITypeLib interface. + + + The lower bound of target array must be zero. + + + Method cannot be both static and virtual. + + + Number encountered was not a finite quantity. + + + Interface not found. + + + {0} is not a GenericMethodDefinition. MakeGenericMethod may only be called on a method for which MethodBase.IsGenericMethodDefinition is true. + + + Method may only be called on a Type for which Type.IsGenericParameter is true. + + + {0} is not a GenericTypeDefinition. MakeGenericType may only be called on a type for which Type.IsGenericTypeDefinition is true. + + + The method or operation is not implemented. + + + Specified method is not supported. + + + Arrays indexes must be set to an object instance. + + + Object reference not set to an instance of an object. + + + Object type cannot be converted to target type. + + + Object of type '{0}' cannot be converted to type '{1}'. + + + Not a legal OleAut date. + + + OleAut date did not convert to a DateTime correctly. + + + Arithmetic operation resulted in an overflow. + + + Insufficient memory to continue the execution of the program. + + + (Parameter '{0}') + + + Must specify one or more parameters. + + + Parameter count mismatch. + + + The path is empty. + + + Operation is not supported on this platform. + + + Cannot widen from source type to target type either because the source type is a not a primitive type or the conversion cannot be accomplished. + + + Cannot specify both Get and Set on a property. + + + Cannot specify Set on a property and Invoke on a method. + + + Attempted to operate on an array with the incorrect number of dimensions. + + + Indices length does not match the array rank. + + + Only single dimensional arrays are supported for the requested action. + + + Number of lengths and lowerBounds must match. + + + RegistryKey.GetValue does not allow a String that has a length greater than Int32.MaxValue. + + + The specified registry key does not exist. + + + No value exists with that name. + + + Registry value names should not be greater than 16,383 characters. + + + Type parameter must refer to a subclass of ResourceSet. + + + The ResourceReader class does not know how to read this version of .resources files. Expected version: {0} This file: {1} + + + The specified resource name "{0}" does not exist in the resource file. + + + Specified array was not of the expected rank. + + + Specified array was not of the expected type. + + + Security error. + + + Serialization error. + + + Property set method not found. + + + Operation caused a stack overflow. + + + Unicode surrogate characters must be written out as pairs together in the same call, not individually. Consider passing in a character array instead. + + + Object synchronization method was called from an unsynchronized block of code. + + + System error. + + + Exception has been thrown by the target of an invocation. + + + Number of parameters specified does not match the expected number. + + + Thread failed to start. + + + Thread was in an invalid state for the operation being executed. + + + The operation has timed out. + + + Attempt to access the type failed. + + + The TypedReference must be initialized. + + + Failure has occurred while loading a type. + + + A null or zero length string does not represent a valid Type. + + + TypedReferences cannot be redefined as primitives. Field name '{0}'. + + + Type had been unloaded. + + + Attempted to perform an unauthorized operation. + + + Late bound operations cannot be performed on fields with types for which Type.ContainsGenericParameters is true. + + + Late bound operations cannot be performed on types or methods for which ContainsGenericParameters is true. + + + Unknown TypeCode value. + + + Missing parameter does not have a default value. + + + Version string portion was too short or too long. + + + IAsyncResult object did not come from the corresponding async method on this type. + + + The value "{0}" is not of type "{1}" and cannot be used in this generic collection. + + + Path "{0}" is not an absolute path. + + + An item with the same key has already been added. + + + Item has already been added. Key in dictionary: '{0}' Key being added: '{1}' + + + An item with the same key has already been added. Key: {0} + + + The AdjustmentRule array cannot contain null elements. + + + The elements of the AdjustmentRule array must be in chronological order and must not overlap. + + + The object already has a CCW associated with it. + + + 'handle' has already been bound to the thread pool, or was not opened for asynchronous I/O. + + + Interface maps for generic interfaces on arrays cannot be retrieved. + + + Array or pointer types are not valid. + + + Attribute names must be unique. + + + Interface method must be abstract and virtual. + + + Bad default value. + + + Cannot have private or static constructor. + + + Constructor must have standard calling convention. + + + Incorrect code generation for exception block. + + + Field must be on the same type of the given ConstructorInfo. + + + Field signatures do not have return types. + + + Bad field type in defining field. + + + Format specifier was invalid. + + + A BadImageFormatException has been thrown while parsing the signature. This is likely due to lack of a generic context. Ensure genericTypeArguments and genericMethodArguments are provided and contain enough context. + + + Bad label in ILGenerator. + + + Bad label content in ILGenerator. + + + Visibility of interfaces must be one of the following: NestedAssembly, NestedFamANDAssem, NestedFamily, NestedFamORAssem, NestedPrivate or NestedPublic. + + + Invalid ObjRef provided to '{0}'. + + + Parameter count does not match passed in argument value count. + + + Cannot emit a CustomAttribute with argument of type {0}. + + + Property must be on the same type of the given ConstructorInfo. + + + Incorrect signature format. + + + Data size must be > 1 and < 0x3f0000 + + + Bad type attributes. Invalid layout attribute specified. + + + Bad type attributes. Nested visibility flag set on a non-nested type. + + + Bad type attributes. Non-nested visibility flag set on a nested type. + + + Bad type attributes. Reserved bits set on the type. + + + An invalid type was used as a custom attribute constructor argument, field or property. + + + Cannot use function evaluation to create a TypedReference object. + + + Cannot get TypeToken for a ByRef type. + + + Cannot set parent to an interface. + + + {0} is not a supported code page. + + + CompareOption.Ordinal cannot be used with other options. + + + The DateTimeStyles value RoundtripKind cannot be used with the values AssumeLocal, AssumeUniversal or AdjustToUniversal. + + + The DateTimeStyles values AssumeLocal and AssumeUniversal cannot be used together. + + + Constant does not match the defined type. + + + {0} is not a supported constant type. + + + Null is not a valid constant value for this type. + + + The specified constructor must be declared on a generic type definition. + + + Conversion buffer overflow. + + + The conversion could not be completed because the supplied DateTime did not have the Kind property set correctly. For example, when the Kind property is DateTimeKind.Local, the source time zone must be TimeZoneInfo.Local. + + + Cannot find the method on the object instance. + + + Cannot evaluate a VarArgs function. + + + Culture IETF Name {0} is not a recognized IETF name. + + + {0} is an invalid culture identifier. + + + Culture ID {0} (0x{0:X4}) is a neutral culture; a region cannot be created from it. + + + Culture is not supported. + + + Resolved assembly's simple name should be the same as of the requested assembly. + + + Customized cultures cannot be passed by LCID, only by name. + + + The binary data must result in a DateTime with ticks between DateTime.MinValue.Ticks and DateTime.MaxValue.Ticks. + + + The supplied DateTime must have the Year, Month, and Day properties set to 1. The time cannot be specified more precisely than whole milliseconds. + + + The supplied DateTime includes a TimeOfDay setting. This is not supported. + + + The supplied DateTime represents an invalid time. For example, when the clock is adjusted forward, any time in the period that is skipped is invalid. + + + The supplied DateTime is not in an ambiguous time range. + + + The supplied DateTime must have the Kind property set to DateTimeKind.Unspecified. + + + The supplied DateTime must have the Kind property set to DateTimeKind.Unspecified or DateTimeKind.Utc. + + + The DateTimeStyles value 'NoCurrentDateDefault' is not allowed when parsing DateTimeOffset. + + + The supplied DateTimeOffset is not in an ambiguous time range. + + + Destination is too short. + + + Duplicate type name within an assembly. + + + EmitWriteLine does not support this field or local type. + + + Decimal separator cannot be the empty string. + + + Empty file name is not legal. + + + Empty name is not legal. + + + Empty path name is not legal. + + + Waithandle array may not be empty. + + + Must complete Convert() operation or call Encoder.Reset() before calling GetBytes() or GetByteCount(). Encoder '{0}' fallback '{1}'. + + + The output byte buffer is too small to contain the encoded data, encoding '{0}' fallback '{1}'. + + + The output char buffer is too small to contain the decoded characters, encoding '{0}' fallback '{1}'. + + + '{0}' is not a supported encoding name. For information on defining a custom encoding, see the documentation for the Encoding.RegisterProvider method. + + + The argument type, '{0}', is not the same as the enum type '{1}'. + + + Cannot change fallback when buffer is not empty. Previous Convert() call left data in the fallback buffer. + + + Cannot resolve field {0} because the declaring type of the field handle {1} is generic. Explicitly provide the declaring type to GetFieldFromHandle. + + + The specified field must be declared on a generic type definition. + + + GenericArguments[{0}], '{1}', on '{2}' violates the constraint of type '{3}'. + + + The number of generic arguments provided doesn't equal the arity of the generic type definition. + + + Generic types are not valid. + + + Global members must be static. + + + Must be an array type. + + + Left to right characters may not be mixed with right to left characters in IDN labels. + + + IDN labels must be between 1 and 63 characters long. + + + IDN names must be between 1 and {0} characters long. + + + Invalid IDN encoded string. + + + Label contains character '{0}' not allowed with UseStd3AsciiRules + + + Decoded string is not a valid IDN name. + + + Environment variable name cannot contain equal character. + + + Illegal name. + + + At least one object must implement IComparable. + + + The specified index is out of bounds of the specified array. + + + The specified space is not sufficient to copy the elements from this Collection. + + + 'this' type cannot be an interface itself. + + + Append access can be requested only in write-only mode. + + + Type of argument is not compatible with the generic comparer. + + + Length of the array must be {0}. + + + Target array type is not compatible with the type of items in the collection. + + + Assembly names may not begin with whitespace or contain the characters '/', or '\\' or ':'. + + + Not a valid calendar for the given culture. + + + Invalid Unicode code point found at index {0}. + + + String contains invalid Unicode code points. + + + Unable to translate bytes {0} at index {1} from specified code page to Unicode. + + + Unable to translate Unicode character \\u{0:X4} at index {1} to specified code page. + + + The specified constructor must be declared on the generic type definition of the specified type. + + + The ConstructorInfo object is not valid. + + + Culture name '{0}' is not supported. + + + Culture name '{0}' is not a predefined culture. + + + Invalid DateTimeKind value. + + + An undefined DateTimeStyles value is being used. + + + The DigitSubstitution property must be of a valid member of the DigitShapes enumeration. Valid entries include Context, NativeNational or None. + + + Invalid element name '{0}'. + + + Invalid element tag '{0}'. + + + Invalid element text '{0}'. + + + Invalid element value '{0}'. + + + The Enum type should contain one and only one instance field. + + + The value '{0}' is not valid for this usage of the type {1}. + + + The specified field must be declared on the generic type definition of the specified type. + + + Combining FileMode: {0} with FileAccess: {1} is invalid. + + + Value of flags is invalid. + + + The generic type parameter was not valid + + + Generic arguments must be provided for each generic parameter and each generic argument must be a RuntimeType. + + + Every element in the value array should be between one and nine, except for the last element, which can be zero. + + + The handle is invalid. + + + Found a high surrogate char without a following low surrogate at index: {0}. The input may not be in this encoding, or may not contain valid Unicode (UTF-16) characters. + + + The specified ID parameter '{0}' is not supported. + + + This type cannot be represented as a custom attribute. + + + Invalid Label. + + + Found a low surrogate char without a preceding high surrogate at index: {0}. The input may not be in this encoding, or may not contain valid Unicode (UTF-16) characters. + + + The member must be either a field or a property. + + + The specified method must be declared on the generic type definition of the specified type. + + + Invalid name. + + + The NativeDigits array must contain exactly ten members. + + + Each member of the NativeDigits array must be a single text element (one or more UTF16 code points) with a Unicode Nd (Number, Decimal Digit) property indicating it is a digit. + + + The region name {0} should not correspond to neutral culture; a specific culture name is required. + + + Invalid or unsupported normalization form. + + + An undefined NumberStyles value is being used. + + + Offset and length were out of bounds for the array or count is greater than the number of elements from index to the end of the source collection. + + + Ldtoken, Ldftn and Ldvirtftn OpCodes cannot target DynamicMethods. + + + The ParameterInfo object is not valid. + + + Invalid type for ParameterInfo member in Attribute class. + + + Illegal characters in path. + + + The given culture name '{0}' cannot be used to locate a resource file. Resource filenames must consist of only letters, numbers, hyphens or underscores. + + + Offset and length were greater than the size of the SafeBuffer. + + + Invalid seek origin. + + + The specified serialized string '{0}' is not supported. + + + The signature of the startup hook '{0}' in assembly '{1}' was invalid. It must be 'public static void Initialize()'. + + + An undefined TimeSpanStyles value is being used. + + + Token {0:x} is not valid in the scope of module {1}. + + + Cannot build type parameter for custom attribute with a type that does not support the AssemblyQualifiedName property. The type instance supplied was of type '{0}'. + + + Invalid type owner for DynamicMethod. + + + The name of the type is invalid. + + + Cannot use type '{0}'. Only value types without pointers or references are supported. + + + Type '{0}' is not deserializable. + + + Value was invalid. + + + Integer or token was too large to be encoded. + + + Environment variable name or value is too long. + + + Cannot resolve method {0} because the declaring type of the method handle {1} is generic. Explicitly provide the declaring type to GetMethodFromHandle. + + + Method '{0}' has a generic declaring type '{1}'. Explicitly provide the declaring type to GetTokenFor. + + + The specified method cannot be dynamic or global and must be declared on a generic type definition. + + + '{0}' cannot be greater than {1}. + + + Two arrays, {0} and {1}, must be of the same size. + + + was missing default constructor. + + + Argument must be initialized to false + + + Assembly must be a runtime Assembly object. + + + FieldInfo must be a runtime FieldInfo object. + + + MethodInfo must be a runtime MethodInfo object. + + + The object must be a runtime Reflection object. + + + Type must be a runtime Type object. + + + 'type' must contain a TypeBuilder as a generic argument. + + + Type passed in must be derived from System.Attribute or System.Attribute itself. + + + The specified structure must be blittable or have layout information. + + + 'overlapped' has already been freed. + + + 'overlapped' was not allocated by this ThreadPoolBoundHandle instance. + + + Method must represent a generic method definition on a generic type definition. + + + The specified object must not be an instance of a generic type. + + + The specified Type must not be a generic type definition. + + + The specified Type must be a struct containing no references. + + + The type '{0}' may not be used as a type argument. + + + No Era was supplied. + + + There is no region associated with the Invariant Culture (Culture ID: 0x7F). + + + Not a writable property. + + + There are not enough bytes remaining in the accessor to read at this position. + + + There are not enough bytes remaining in the accessor to write at this position. + + + The type or method has {1} generic parameter(s), but {0} generic argument(s) were provided. A generic argument must be provided for each generic parameter. + + + Does not extend Exception. + + + Not currently in an exception block. + + + The specified opcode cannot be passed to EmitCall. + + + Argument passed in is not serializable. + + + Uninitialized Strings cannot be created. + + + The object's type must not be a Windows Runtime type. + + + The object's type must be __ComObject or derived from __ComObject. + + + Offset and capacity were greater than the size of the view. + + + The UTC Offset of the local dateTime parameter does not match the offset argument. + + + Field passed in is not a marshaled member of the type '{0}'. + + + Offset must be within plus or minus 14 hours. + + + Offset must be specified in whole minutes. + + + The UTC Offset for Utc DateTime instances must be 0. + + + Culture name {0} or {1} is not supported. + + + Only mscorlib's assembly is valid. + + + The DateStart property must come before the DateEnd property. + + + Path cannot be the empty string or all whitespace. + + + 'preAllocated' is already in use. + + + Recursive fallback not allowed for character \\u{0:X4}. + + + Recursive fallback not allowed for bytes {0}. + + + Label multiply defined. + + + Token {0:x} is not a valid FieldInfo token in the scope of module {1}. + + + Type handle '{0}' and field handle with declaring type '{1}' are incompatible. Get RuntimeFieldHandle and declaring RuntimeTypeHandle off the same FieldInfo. + + + Token {0:x} is not a valid MemberInfo token in the scope of module {1}. + + + Token {0:x} is not a valid MethodBase token in the scope of module {1}. + + + Type handle '{0}' and method handle with declaring type '{1}' are incompatible. Get RuntimeMethodHandle and declaring RuntimeTypeHandle off the same MethodBase. + + + Token {0} resolves to the special module type representing this module. + + + Token {0:x} is not a valid string token in the scope of module {1}. + + + Token {0:x} is not a valid Type token in the scope of module {1}. + + + The result is out of the supported range for this calendar. The result should be between {0} (Gregorian date) and {1} (Gregorian date), inclusive. + + + The initial count for the semaphore must be greater than or equal to zero and less than the maximum count. + + + Should not specify exception type for catch clause for filter block. + + + Should only set visibility flags when creating EnumBuilder. + + + Completed signature cannot be modified. + + + Stream was not readable. + + + Stream was not writable. + + + The first char in the string is the null character. + + + String cannot be of zero length. + + + The structure must not be a value class. + + + The TimeSpan parameter cannot be specified more precisely than whole minutes. + + + The tzfile does not begin with the magic characters 'TZif'. Please verify that the file is not corrupt. + + + The TZif data structure is corrupt. + + + fromInclusive must be less than or equal to toExclusive. + + + Exception blocks may have at most one finally clause. + + + The DaylightTransitionStart property must not equal the DaylightTransitionEnd property. + + + Field '{0}' in TypedReferences cannot be static. + + + The type must not be a Windows Runtime type. + + + The specified type must be visible from COM. + + + The type must not be imported from COM. + + + Type name was too long. The fully qualified type name must be less than 1,024 characters. + + + Type '{0}' does not have an activation factory because it is not activatable by Windows Runtime. + + + The type must be __ComObject or be derived from __ComObject. + + + The Type object is not valid. + + + The IL Generator cannot be used while there are unclosed exceptions. + + + Unexpected TypeKind when marshaling Windows.Foundation.TypeName. + + + Unknown unmanaged calling convention for function signature. + + + The UnmanagedMemoryAccessor capacity and offset would wrap around the high end of the address space. + + + Local passed in does not belong to this ILGenerator. + + + Non-matching symbol scope. + + + The UTC time represented when the offset is applied must be between year 0 and 10,000. + + + The length of the name exceeds the maximum limit. + + + Cannot marshal type '{0}' to Windows Runtime. Only 'System.RuntimeType' is supported. + + + MethodOverride's body must be from this type. + + + The buffer is not associated with this pool and may not be returned to it. + + + Object is not a array with the same number of elements as the array to compare it to. + + + Object contains non-primitive or non-blittable data. + + + Argument must be of type {0}. + + + The last element of an eight element tuple must be a Tuple. + + + Argument must be of type {0}. + + + The last element of an eight element ValueTuple must be a ValueTuple. + + + Array cannot be null. + + + At least one element in the specified array was null. + + + Found a null value within an array. + + + Assembly cannot be null. + + + AssemblyName cannot be null. + + + AssemblyName.Name cannot be null or an empty string. + + + Buffer cannot be null. + + + Cannot have a null child. + + + Collection cannot be null. + + + Dictionary cannot be null. + + + File name cannot be null. + + + Value cannot be null. + + + GUID cannot be null. + + + Key cannot be null. + + + Path cannot be null. + + + SafeHandle cannot be null. + + + Stream cannot be null. + + + String reference not set to an instance of a String. + + + Type cannot be null. + + + Type in TypedReference cannot be null. + + + The waitHandles parameter cannot be null. + + + Actual value was {0}. + + + The number of bytes cannot exceed the virtual address space on a 32 bit machine. + + + Value to add was out of range. + + + Number was less than the array's lower bound in the first dimension. + + + Higher indices will exceed Int32.MaxValue because of large lower bound and/or length. + + + Hour, Minute, and Second parameters describe an un-representable DateTime. + + + Year, Month, and Day parameters describe an un-representable DateTime. + + + Larger than collection size. + + + The number of bytes requested does not fit into BinaryReader's internal buffer. + + + Argument must be between {0} and {1}. + + + Specified time is not supported in this calendar. It should be between {0} (Gregorian date) and {1} (Gregorian date), inclusive. + + + Capacity exceeds maximum capacity. + + + Count must be positive and count must refer to a location within the string/array/collection. + + + The added or subtracted value results in an un-representable DateTime. + + + Months value must be between +/-120000. + + + Ticks must be between DateTime.MinValue.Ticks and DateTime.MaxValue.Ticks. + + + Years value must be between +/-10000. + + + Day must be between 1 and {0} for month {1}. + + + The DayOfWeek enumeration must be in the range 0 through 6. + + + The Day parameter must be in the range 1 through 31. + + + Decimal can only round to between 0 and 28 digits of precision. + + + Decimal's scale value must be between 0 and 28, inclusive. + + + endIndex cannot be greater than startIndex. + + + Enum value was out of legal range. + + + Time value was out of era range. + + + Specified file length was too large for the file system. + + + Not a valid Win32 FileTime. + + + Value must be positive. + + + Too many characters. The resulting number of bytes is larger than what can be returned as an int. + + + Too many bytes. The resulting number of chars is larger than what can be returned as an int. + + + Load factor needs to be between 0.1 and 1.0. + + + Arrays larger than 2GB are not supported. + + + Index was out of range. Must be non-negative and less than the size of the collection. + + + Index and count must refer to a location within the string. + + + Index and count must refer to a location within the buffer. + + + This collection cannot work with indices larger than Int32.MaxValue - 1 (0x7FFFFFFF - 1). + + + Index and length must refer to a location within the string. + + + Index was out of range. Must be non-negative and less than the length of the string. + + + Era value was not valid. + + + A valid high surrogate character is between 0xd800 and 0xdbff, inclusive. + + + A valid low surrogate character is between 0xdc00 and 0xdfff, inclusive. + + + A valid UTF32 value is between 0x000000 and 0x10ffff, inclusive, and should not include surrogate codepoint values (0x00d800 ~ 0x00dfff). + + + The specified length exceeds maximum capacity of SecureString. + + + The length cannot be greater than the capacity. + + + The specified length exceeds the maximum value of {0}. + + + Argument must be less than or equal to 2^31 - 1 milliseconds. + + + Index must be within the bounds of the List. + + + Month must be between one and twelve. + + + The Month parameter must be in the range 1 through 12. + + + Value must be non-negative and less than or equal to Int32.MaxValue. + + + '{0}' must be non-negative. + + + '{0}' must be greater than zero. + + + Non-negative number required. + + + Number must be either non-negative and less than or equal to Int32.MaxValue or -1. + + + Positive number required. + + + The ID parameter must be in the range {0} through {1}. + + + Capacity must be positive. + + + Count cannot be less than zero. + + + Length cannot be less than zero. + + + Offset and length must refer to a position in the string. + + + Either offset did not refer to a position in the string, or there is an insufficient length of destination character array. + + + The specified parameter index is not in range. + + + Pointer startIndex and length do not refer to a valid string. + + + Period must be less than 2^32-2. + + + The position may not be greater or equal to the capacity of the accessor. + + + Valid values are between {0} and {1}, inclusive. + + + Rounding digits must be between 0 and 15, inclusive. + + + capacity was less than the current size. + + + MaxCapacity must be one or greater. + + + StartIndex cannot be less than zero. + + + startIndex cannot be larger than length of string. + + + startIndex must be less than length of string. + + + Stream length must be non-negative and less than 2^31 - 1 - origin. + + + Time-out interval must be less than 2^32-2. + + + The length of the buffer must be less than the maximum UIntPtr value for your platform. + + + UnmanagedMemoryStream length must be non-negative and less than 2^63 - 1 - baseAddress. + + + The UnmanagedMemoryStream capacity would wrap around the high end of the address space. + + + The TimeSpan parameter must be within plus or minus 14.0 hours. + + + The sum of the BaseUtcOffset and DaylightDelta properties must within plus or minus 14.0 hours. + + + Version's parameters must be greater than or equal to zero. + + + The Week parameter must be in the range 1 through 5. + + + Year must be between 1 and 9999. + + + Function does not accept floating point Not-a-Number values. + + + Source array type cannot be assigned to destination array type. + + + Array.ConstrainedCopy will only work on array types that are provably compatible, without any form of boxing, unboxing, widening, or casting of each array element. Change the array types (i.e., copy a Derived[] to a Base[]), or use a mitigation strategy in the CER for Array.Copy's less powerful reliability contract, such as cloning the array or throwing away the potentially corrupt destination array. + + + Cannot unload non-collectible AssemblyLoadContext. + + + AssemblyLoadContext is unloading or was already unloaded. + + + Assertion failed. + + + Assertion failed: {0} + + + Assumption failed. + + + Assumption failed: {0} + + + The builder was not properly initialized. + + + Bad IL format. + + + Corrupt .resources file. The specified type doesn't exist. + + + Corrupt .resources file. String length must be non-negative. + + + The parameters and the signature of the method don't match. + + + The type serialized in the .resources file was not the same type that the .resources file said it contained. Expected '{0}' but read '{1}'. + + + Corrupt .resources file. The specified data length '{0}' is not a valid position in the stream. + + + Corrupt .resources file. A resource name extends past the end of the stream. + + + Corrupt .resources file. The resource name for name index {0} extends past the end of the stream. + + + Corrupt .resources file. Invalid offset '{0}' into data section. + + + Corrupt .resources file. Unable to read resources from this file because of invalid header information. Try regenerating the .resources file. + + + Corrupt .resources file. String for name index '{0}' extends past the end of the file. + + + Corrupt .resources file. Invalid offset '{0}' into name section. + + + Corrupt .resources file. Resource name extends past the end of the file. + + + Corrupt .resources file. The specified type doesn't match the available data in the stream. + + + No tokens were supplied. + + + The CancellationTokenSource has been disposed. + + + The SyncRoot property may not be used for the synchronization of concurrent collections. + + + Task {2} completed. + + + Task {2} scheduled to TaskScheduler {0}. + + + Task {2} executing. + + + Beginning wait ({3}) on Task {2}. + + + Ending wait on Task {2}. + + + Abstract event source must not declare event methods ({0} with ID {1}). + + + Abstract event source must not declare {0} nested type. + + + Getting out of bounds during scalar addition. + + + Bad Hexidecimal digit "{0}". + + + Channel {0} does not match event channel value {1}. + + + Data descriptors are out of range. + + + Multiple definitions for string "{0}". + + + The type of {0} is not expected in {1}. + + + Must have an even number of Hexidecimal digits. + + + Channel {0} has a value of {1} which is outside the legal range (16-254). + + + Event {0} has ID {1} which is already in use. + + + Event {0} (with ID {1}) has a non-default opcode but not a task. + + + Event method {0} (with ID {1}) is an explicit interface method implementation. Re-write method as implicit implementation. + + + Event {0} (with ID {1}) has a name that is not the concatenation of its task name and opcode. + + + Event name {0} used more than once. If you wish to overload a method, the overloaded method should have a NonEvent attribute. + + + Event {0} was called with {1} argument(s), but it is defined with {2} parameter(s). + + + An instance of EventSource with Guid {0} already exists. + + + The payload for a single event is too large. + + + Event {0} specifies an Admin channel {1}. It must specify a Message property. + + + Keyword {0} has a value of {1} which is outside the legal range (0-0x0000080000000000). + + + Opcode {0} has a value of {1} which is outside the legal range (11-238). + + + Task {0} has a value of {1} which is outside the legal range (1-65535). + + + Illegal value "{0}" (prefix strings with @ to indicate a literal string). + + + Incorrectly-authored TypeInfo - a type should be serialized as one field or as one group + + + Invalid command value. + + + Can't specify both etw event format flags. + + + Keywords {0} and {1} are defined with the same value ({2}). + + + Value {0} for keyword {1} needs to be a power of 2. + + + Creating an EventListener inside a EventListener callback. + + + Listener not found. + + + An error occurred when writing to a listener. + + + Attempt to define more than the maximum limit of 8 channels for a provider. + + + Event {0} was assigned event ID {1} but {2} was passed to WriteEvent. + + + The Guid of an EventSource must be non zero. + + + The name of an EventSource must not be null. + + + Event IDs must be positive integers. + + + No Free Buffers available from the operating system (e.g. event rate too fast). + + + The API supports only anonymous types or types decorated with the EventDataAttribute. Non-compliant type: {0} dataType. + + + EventSource expects the first parameter of the Event method to be of type Guid and to be named "relatedActivityId" when calling WriteEventWithRelatedActivityId. + + + Arrays of Binary are not supported. + + + Arrays of Nil are not supported. + + + Arrays of null-terminated string are not supported. + + + Enumerables of custom-serialized data are not supported + + + Nested arrays/enumerables are not supported. + + + Null passed as a event argument. + + + Opcodes {0} and {1} are defined with the same value ({2}). + + + Pins are out of range. + + + Recursive type definition is not supported. + + + An event with stop suffix must follow a corresponding event with a start suffix. + + + Tasks {0} and {1} are defined with the same value ({2}). + + + Event {0} (with ID {1}) has the same task/opcode pair as event {2} (with ID {3}). + + + Too many arguments. + + + Too many fields in structure. + + + EventSource({0}, {1}) + + + There must be an even number of trait strings (they are key-value pairs). + + + Event source types must be sealed or abstract. + + + Event source types must derive from EventSource. + + + Use of undefined channel value {0} for event {1}. + + + Use of undefined keyword value {0} for event {1}. + + + Use of undefined opcode value {0} for event {1}. + + + Unknown ETW trait "{0}". + + + Unsupported type {0} in event source. + + + Event {0} specifies an illegal or unsupported formatting message ("{1}"). + + + Event {0} was called with a different type as defined (argument "{1}"). This may cause the event to be displayed incorrectly. + + + --- End of inner exception stack trace --- + + + --- End of stack trace from previous location --- + + + Exception of type '{0}' was thrown. + + + An exception was not handled in an AsyncLocal<T> notification callback. + + + Could not resolve assembly '{0}'. + + + Duplicate AttributeUsageAttribute found on attribute type {0}. + + + Too many bytes in what should have been a 7-bit encoded integer. + + + Invalid digits for the specified base. + + + The input is not a valid Base-64 string as it contains a non-base 64 character, more than two padding characters, or an illegal character among the padding characters. + + + String '{0}' was not recognized as a valid Boolean. + + + Could not determine the order of year, month, and date from '{0}'. + + + String '{0}' was not recognized as a valid DateTime. + + + The DateTime represented by the string '{0}' is not supported in calendar '{1}'. + + + String '{0}' was not recognized as a valid DateTime because the day of week was incorrect. + + + Format specifier '{0}' was invalid. + + + No format specifiers were provided. + + + Cannot find a matching quote character for the character '{0}'. + + + String '{0}' was not recognized as a valid TimeSpan. + + + The DateTime represented by the string '{0}' is out of range. + + + Input string was either empty or contained only whitespace. + + + Additional non-parsable characters are at the end of the string. + + + Expected {0xdddddddd, etc}. + + + Could not find a brace, or the length between the previous token and the brace was zero (i.e., '0x,'etc.). + + + Could not find a comma, or the length between the previous token and the comma was zero (i.e., '0x,'etc.). + + + Dashes are in the wrong position for GUID parsing. + + + Could not find the ending brace. + + + Expected 0x prefix. + + + Guid string should only contain hexadecimal characters. + + + Guid should contain 32 digits with 4 dashes (xxxxxxxx-xxxx-xxxx-xxxx-xxxxxxxxxxxx). + + + Unrecognized Guid format. + + + Index (zero based) must be greater than or equal to zero and less than the size of the argument list. + + + Format string can be only "G", "g", "X", "x", "F", "f", "D" or "d". + + + Format string can be only "D", "d", "N", "n", "P", "p", "B", "b", "X" or "x". + + + Input string was not in a correct format. + + + There must be at least a partial date with a year present in the input string '{0}'. + + + String must be exactly one character long. + + + Could not find any recognizable digits. + + + The time zone offset of string '{0}' must be within plus or minus 14 hours. + + + DateTime pattern '{0}' appears more than once with different values. + + + String cannot have zero length. + + + The string '{0}' was not recognized as a valid DateTime. There is an unknown word starting at index '{1}'. + + + The UTC representation of the date '{0}' falls outside the year range 1-9999. + + + Unicode + + + Unicode (UTF-32) + + + Unicode (UTF-32 Big-Endian) + + + Unicode (Big-Endian) + + + US-ASCII + + + Western European (ISO) + + + Unicode (UTF-7) + + + Unicode (UTF-8) + + + Array does not have that many dimensions. + + + Unmanaged memory stream position was beyond the capacity of the stream. + + + Insufficient available memory to meet the expected demands of an operation at this time. Please try again later. + + + Insufficient memory to meet the expected demands of an operation, and this system is likely to never satisfy this request. If this is a 32 bit system, consider booting in 3 GB mode. + + + Insufficient available memory to meet the expected demands of an operation at this time, possibly due to virtual address space fragmentation. Please try again later. + + + Type mismatch between source and destination types. + + + Cannot marshal: Encountered unmappable character. + + + Structures containing SafeHandle fields are not allowed in this operation. + + + SafeHandle fields cannot be created from an unmanaged handle. + + + CriticalHandle fields cannot be created from an unmanaged handle. + + + Null object cannot be converted to a value type. + + + Object cannot be coerced to the original type of the ByRef VARIANT it was obtained from. + + + Object cannot be cast to DBNull. + + + At least one element in the source array could not be cast down to the destination array type. + + + Object cannot be cast to Empty. + + + Object cannot be cast from DBNull to other types. + + + Invalid cast from '{0}' to '{1}'. + + + Object must implement IConvertible. + + + OleAut reported a type mismatch. + + + Object cannot be stored in an array of this type. + + + Object in an IPropertyValue is of type '{0}' which cannot be convereted to a '{1}' due to array element '{2}': {3}. + + + Object in an IPropertyValue is of type '{0}' with value '{1}', which cannot be converted to a '{2}'. + + + Object in an IPropertyValue is of type '{0}', which cannot be converted to a '{1}'. + + + AsyncFlowControl objects can be used to restore flow only on a Context that had its flow suppressed. + + + The stream is currently in use by a previous operation on the stream. + + + Method '{0}' does not have a method body. + + + ILGenerator usage is invalid. + + + Opcodes using a short-form index cannot address a local position over 255. + + + Interface must be declared abstract. + + + Method '{0}' cannot have a method body. + + + Type must be declared abstract if any of its methods are abstract. + + + The method cannot be called twice on the same instance. + + + Unable to import a global method or field from a different module. + + + A resolver is already set for the assembly. + + + Cannot remove the last element from an empty collection. + + + Cannot restore context flow when it is not suppressed. + + + Context flow is already suppressed. + + + AsyncFlowControl object can be used only once to call Undo(). + + + AsyncFlowControl object must be used on the thread where it was created. + + + Instances of abstract classes cannot be created. + + + Instances of function pointers cannot be created. + + + The collection backing this Dictionary contains too many elements. + + + The collection backing this List contains too many elements. + + + A prior operation on this collection was interrupted by an exception. Collection's state is no longer trusted. + + + Computer name could not be obtained. + + + Operations that change non-concurrent collections must have exclusive access. A concurrent update was performed on this collection and corrupted its state. The collection's state is no longer correct. + + + Interface cannot have constructors. + + + Internal Error in DateTime and Calendar operations. + + + Unable to access ILGenerator on a constructor created with DefineDefaultConstructor. + + + EndRead can only be called once for each asynchronous operation. + + + EndWrite can only be called once for each asynchronous operation. + + + Enumeration already finished. + + + Collection was modified; enumeration operation may not execute. + + + Enumeration has not started. Call MoveNext. + + + Enumeration has either not started or has already finished. + + + This API does not support EventInfo tokens. + + + Type '{0}' is not a delegate type. EventTokenTable may only be used with delegate types. + + + The generic parameters are already defined on this MethodBuilder. + + + OSVersion's call to GetVersionEx failed. + + + Type definition of the global function has been completed. + + + Handle is not initialized. + + + Handle is not pinned. + + + Hashtable insert failed. Load factor too high. The most common cause is multiple threads writing to the Hashtable simultaneously. + + + Failed to compare two elements in the array. + + + Type definition of the method is complete. + + + The signature of the MethodBuilder can no longer be modified because an operation on the MethodBuilder caused the methodDef token to be created. For example, a call to SetCustomAttribute requires the methodDef token to emit the CustomAttribute token. + + + Method already has a body. + + + You must call Initialize on this object instance before using it. + + + NativeOverlapped cannot be reused for multiple operations. + + + You cannot have more than one dynamic module in each dynamic assembly in this version of the runtime. + + + Cannot add the event handler since no public add method exists for the event. + + + Cannot remove the event handler since no public remove method exists for the event. + + + Not a debug ModuleBuilder. + + + The requested operation is invalid for DynamicMethod. + + + Calling convention must be VarArgs. + + + This operation is only valid on generic types. + + + Adding or removing event handlers dynamically is not supported on WinRT events. + + + This API is not available when the concurrent GC is enabled. + + + Underlying type information on enumeration is not specified. + + + Nullable object must have a value. + + + The underlying array is null. + + + Cannot call Set on a null context + + + The requested operation is invalid when called on a null ModuleHandle. + + + Local variable scope was not properly closed. + + + Cannot pack a packed Overlapped again. + + + This API does not support PropertyInfo tokens. + + + Instance is read-only. + + + '{0}': ResourceSet derived classes must provide a constructor that takes a String file name and a constructor that takes a Stream. + + + Resource '{0}' was not a Stream - call GetObject instead. + + + Resource '{0}' was not a String - call GetObject instead. + + + Resource was of type '{0}' instead of String - call GetObject instead. + + + The NoGCRegion mode is in progress.End it and then set a different mode. + + + Method body should not exist. + + + The thread was created with a ThreadStart delegate that does not accept a parameter. + + + Timeouts are not supported on this stream. + + + The Timer was already closed using an incompatible Dispose method. + + + The given type cannot be boxed. + + + Unable to change after type has been created. + + + Type has not been created. + + + This range in the underlying list is invalid. A possible cause is that elements were removed. + + + Unknown enum type. + + + This property has already been set and cannot be modified. + + + Either the IAsyncResult object did not come from the corresponding async method on this type, or the End method was called multiple times with the same IAsyncResult. + + + Either the IAsyncResult object did not come from the corresponding async method on this type, or EndRead was called multiple times with the same IAsyncResult. + + + Either the IAsyncResult object did not come from the corresponding async method on this type, or EndWrite was called multiple times with the same IAsyncResult. + + + Common Language Runtime detected an invalid program. + + + The time zone ID '{0}' was found on the local computer, but the file at '{1}' was corrupt. + + + The time zone ID '{0}' was found on the local computer, but the registry information was corrupt. + + + Invalid Julian day in POSIX strings. + + + There are no ttinfo structures in the tzfile. At least one ttinfo structure is required in order to construct a TimeZoneInfo object. + + + '{0}' is not a valid POSIX-TZ-environment-variable MDate rule. A valid rule has the format 'Mm.w.d'. + + + Invariant failed. + + + Invariant failed: {0} + + + Unable to read beyond the end of the stream. + + + Could not load the specified file. + + + File name: '{0}' + + + Unable to find the specified file. + + + Could not find file '{0}'. + + + Cannot create '{0}' because a file or directory with the same name already exists. + + + BindHandle for ThreadPool failed on this handle. + + + The file '{0}' already exists. + + + The OS handle's position is not what FileStream expected. Do not use a handle simultaneously in one FileStream and in Win32 code or another FileStream. This may cause data loss. + + + The file is too long. This operation is currently limited to supporting files less than 2 gigabytes in size. + + + IO operation will not work. Most likely the file will become too long or the handle was not opened to support synchronous IO operations. + + + Unable to expand length of this stream beyond its capacity. + + + BinaryReader encountered an invalid string length of {0} characters. + + + Unable seek backward to overwrite data that previously existed in a file opened in Append mode. + + + An attempt was made to move the position before the beginning of the stream. + + + Unable to truncate data that previously existed in a file opened in Append mode. + + + The process cannot access the file '{0}' because it is being used by another process. + + + The process cannot access the file because it is being used by another process. + + + Stream was too long. + + + Could not find a part of the path. + + + Could not find a part of the path '{0}'. + + + The specified file name or path is too long, or a component of the specified path is too long. + + + The path '{0}' is too long, or a component of the specified path is too long. + + + [Unknown] + + + The lazily-initialized type does not have a public, parameterless constructor. + + + The mode argument specifies an invalid value. + + + ValueFactory returned null. + + + Value is not created. + + + ValueFactory attempted to access the Value property of this instance. + + + The spinCount argument must be in the range 0 to {0}, inclusive. + + + There are too many threads currently waiting on the event. A maximum of {0} waiting threads are supported. + + + The event has been disposed. + + + Marshaler restriction: Excessively long string. + + + Constructor on type '{0}' not found. + + + Field not found. + + + Field '{0}' not found. + + + A case-insensitive lookup for resource file "{0}" in assembly "{1}" found multiple entries. Remove the duplicates or specify the exact case. + + + Could not find the resource "{0}" among the resources {2} embedded in the assembly "{1}", nor among the resources in any satellite assemblies for the specified culture. Perhaps the resources were embedded with an incorrect name. + + + Could not find any resources appropriate for the specified culture (or the neutral culture) on disk. + + + Unable to open Package Resource Index. + + + Unable to load resources for resource file "{0}" in package "{1}". + + + Member not found. + + + Member '{0}' not found. + + + TypedReference can only be made on nested value Types. + + + FieldInfo does not match the target Type. + + + Method '{0}' not found. + + + The satellite assembly named "{1}" for fallback culture "{0}" either could not be found or could not be loaded. This is generally a setup problem. Please consider reinstalling or repairing the application. + + + Resource lookup fell back to the ultimate fallback resources in a satellite assembly, but that satellite either was not found or could not be loaded. Please consider reinstalling or repairing the application. + + + Delegates that are not of type MulticastDelegate may not be combined. + + + An assembly (probably "{1}") must be rewritten using the code contracts binary rewriter (CCRewrite) because it is calling Contract.{0} and the CONTRACTS_FULL symbol is defined. Remove any explicit definitions of the CONTRACTS_FULL symbol from your project and rebuild. CCRewrite can be downloaded from http://go.microsoft.com/fwlink/?LinkID=169180. \r\nAfter the rewriter is installed, it can be enabled in Visual Studio from the project's Properties page on the Code Contracts pane. Ensure that "Perform Runtime Contract Checking" is enabled, which will define CONTRACTS_FULL. + + + This non-CLS method is not implemented. + + + Activation Attributes are not supported. + + + {0} is not supported in AppX. + + + Assembly.LoadFrom with hashValue is not supported. + + + Cannot create boxed ByRef-like values. + + + Cannot create arrays of ByRef-like values. + + + ByRef to ByRef-like return values are not supported in reflection invocation. + + + ByRef to void return values are not supported in reflection invocation. + + + Vararg calling convention not supported. + + + Equals() on Span and ReadOnlySpan is not supported. Use operator== instead. + + + GetHashCode() on Span and ReadOnlySpan is not supported. + + + ChangeType operation is not supported. + + + Resolving to a collectible assembly is not supported. + + + A non-collectible assembly may not reference a collectible assembly. + + + WinRT Interop is not supported for collectible types. + + + CreateInstance cannot be used with an object of type TypeBuilder. + + + Only one DBNull instance may exist, and calls to DBNull deserialization methods are not allowed. + + + The invoked member is not supported in a dynamic assembly. + + + Wrong MethodAttributes or CallingConventions for DynamicMethod. Only public, static, standard supported + + + The invoked member is not supported in a dynamic module. + + + FileStream was asked to open a device that was not a file. For support for devices like 'com1:' or 'lpt1:', call CreateFile, then use the FileStream constructors that take an OS handle as an IntPtr. + + + Collection was of a fixed size. + + + Generic methods with NativeCallableAttribute are invalid. + + + This operation is invalid on overlapping buffers. + + + Invoking default method with named arguments is not supported. + + + Illegal one-byte branch at position: {0}. Requested branch was: {1}. + + + Mutating a key collection derived from a dictionary is not allowed. + + + Cannot create uninitialized instances of types requiring managed activation. + + + The number of WaitHandles must be less than or equal to 64. + + + The number of WaitHandles on a STA thread must be less than or equal to 63. + + + Memory stream is not expandable. + + + Module argument must be a ModuleBuilder. + + + Methods with NativeCallableAttribute cannot be used as delegate target. + + + No data is available for encoding {0}. For information on defining a custom encoding, see the documentation for the Encoding.RegisterProvider method. + + + Non-blittable parameter types are invalid for NativeCallable methods. + + + Not supported in a non-reflected type. + + + Non-static methods with NativeCallableAttribute are invalid. + + + Parent does not have a default constructor. The default constructor must be explicitly defined. + + + Cannot resolve {0} to a TypeInfo object. + + + This feature is not implemented. + + + Found an obsolete .resources file in assembly '{0}'. Rebuild that .resources file then rebuild that assembly. + + + The given Variant type is not supported by this OleAut function. + + + Cannot create arrays of open type. + + + Output streams do not support TypeBuilders. + + + A Primary Interop Assembly is not supported in AppX. + + + The specified operation is not supported on Ranges. + + + Accessor does not support reading. + + + Collection is read-only. + + + Cannot read resources that depend on serialization. + + + SignalAndWait on a STA thread is not supported. + + + The string comparison type passed in is currently not supported. + + + Derived classes must provide an implementation. + + + Not supported in an array method of a type definition that is not complete. + + + Stack size too deep. Possibly too many arguments. + + + Type is not supported. + + + The invoked member is not supported before the type is created. + + + This operation is not supported for an UnmanagedMemoryStream created from a SafeBuffer. + + + The UnitySerializationHolder object is designed to transmit information about other types and is not serializable itself. + + + TypeCode '{0}' was not valid. + + + WaitAll for multiple handles on a STA thread is not supported. + + + Stream does not support reading. + + + Stream does not support seeking. + + + Stream does not support writing. + + + Custom marshalers for value types are not currently supported. + + + Mutating a value collection derived from a dictionary is not allowed. + + + Arrays of System.Void are not supported. + + + Accessor does not support writing. + + + This .resources file should not be read with this reader. The resource reader type is "{0}". + + + The pointer for this method was null. + + + Cannot access a closed file. + + + Cannot access a disposed object. + + + Object name: '{0}'. + + + Cannot write to a closed TextWriter. + + + Cannot read from a closed TextReader. + + + Cannot access a closed resource set. + + + Cannot access a closed Stream. + + + Cannot access a closed accessor. + + + Safe handle has been closed. + + + The operation was canceled. + + + Value was either too large or too small for an unsigned byte. + + + Value was either too large or too small for a character. + + + Value was either too large or too small for a Currency. + + + Value was either too large or too small for a Decimal. + + + The duration cannot be returned for TimeSpan.MinValue because the absolute value of TimeSpan.MinValue exceeds the value of TimeSpan.MaxValue. + + + Value was either too large or too small for an Int16. + + + Value was either too large or too small for an Int32. + + + Value was either too large or too small for an Int64. + + + Negating the minimum value of a twos complement number is invalid. + + + The string was being parsed as an unsigned number and could not have a negative sign. + + + Value was either too large or too small for a signed byte. + + + The TimeSpan string '{0}' could not be parsed because at least one of the numeric components is out of range or contains too many digits. + + + TimeSpan overflowed because the duration is too long. + + + Value was either too large or too small for a UInt16. + + + Value was either too large or too small for a UInt32. + + + Value was either too large or too small for a UInt64. + + + ArgIterator is not supported on this platform. + + + COM Interop is not supported on this platform. + + + The named version of this synchronization primitive is not supported on this platform. + + + Wait operations on multiple wait handles including a named synchronization primitive are not supported on this platform. + + + Locking/unlocking file regions is not supported on this platform. Use FileShare on the entire file instead. + + + ReflectionOnly loading is not supported on this platform. + + + Remoting is not supported on this platform. + + + Secure binary serialization is not supported on this platform. + + + Strong-name signing is not supported on this platform. + + + Windows Runtime is not supported on this operating system. + + + This API is specific to the way in which Windows handles asynchronous I/O, and is not supported on this platform. + + + Marshalling a System.Type to an unmanaged ITypeInfo or marshalling an ITypeInfo to a System.Type is not supported on this platform. + + + Marshalling an IDispatchEx to an IReflect or IExpando is not supported on this platform. + + + Secondary AppDomains are not supported on this platform. + + + Code Access Security is not supported on this platform. + + + Windows Principal functionality is not supported on this platform. + + + Thread abort is not supported on this platform. + + + Thread suspend is not supported on this platform. + + + Postcondition failed. + + + Postcondition failed: {0} + + + Postcondition failed after throwing an exception. + + + Postcondition failed after throwing an exception: {0} + + + Precondition failed. + + + Precondition failed: {0} + + + The home directory of the current user could not be determined. + + + Only single dimension arrays are supported here. + + + The specified arrays must have the same number of dimensions. + + + Unable to load one or more of the requested types. + + + ResourceReader is closed. + + + Stream is not a valid resource file. + + + Multiple custom attributes of the same type found. + + + Ambiguous match found. + + + An Int32 must be provided for the filter criteria. + + + A String must be provided for the filter criteria. + + + '{0}' field specified was not found. + + + '{0}' property specified was not found. + + + Object does not match target type. + + + Non-static field requires a target. + + + Non-static method requires a target. + + + An object that does not derive from System.Exception has been wrapped in a RuntimeWrappedException. + + + The time zone ID '{0}' was found on the local computer, but the application does not have permission to read the file. + + + The time zone ID '{0}' was found on the local computer, but the application does not have permission to read the registry information. + + + Requested registry access is not allowed. + + + The initialCount argument must be non-negative and less than or equal to the maximumCount. + + + The maximumCount argument must be a positive number. If a maximum is not required, use the constructor without a maxCount parameter. + + + The semaphore has been disposed. + + + The releaseCount argument must be greater than zero. + + + The timeout must represent a value between -1 and Int32.MaxValue, inclusive. + + + Non existent ParameterInfo. Position bigger than member's parameters length. + + + The value of the field '{0}' is invalid. The serialized data is corrupt. + + + Invalid serialized DateTime data. Ticks must be between DateTime.MinValue.Ticks and DateTime.MaxValue.Ticks. + + + Serializing delegates is not supported on this platform. + + + Insufficient state to return the real object. + + + An error occurred while deserializing the object. The serialized data is corrupt. + + + The serialized data contained an invalid escape sequence '\\{0}'. + + + OnDeserialization method was called while the object was not being deserialized. + + + An IntPtr or UIntPtr with an eight byte value cannot be deserialized on a machine with a four byte word size. + + + Only system-provided types can be passed to the GetUninitializedObject method. '{0}' is not a valid instance of a type. + + + The keys and values arrays have different sizes. + + + Invalid serialized DateTime data. Unable to find 'ticks' or 'dateData'. + + + The Keys for this Hashtable are missing. + + + The values for this dictionary are missing. + + + Serialized member does not have a ParameterInfo. + + + Member '{0}' was not found. + + + One of the serialized keys is null. + + + Version value must be positive. + + + Cannot add the same member twice to a SerializationInfo object. + + + The serialized Capacity property of StringBuilder must be positive, less than or equal to MaxCapacity and greater than or equal to the String length. + + + The serialized MaxCapacity property of StringBuilder must be positive and greater than or equal to the String length. + + + Setter must have parameters. + + + The calling thread does not hold the lock. + + + Thread tracking is disabled. + + + The timeout must be a value between -1 and Int32.MaxValue, inclusive. + + + The calling thread already holds the lock. + + + The tookLock argument must be set to false before calling this method. + + + The condition argument is null. + + + The timeout must represent a value between -1 and Int32.MaxValue, inclusive. + + + in {0}:line {1} + + + The specified TaskContinuationOptions combined LongRunning and ExecuteSynchronously. Synchronous continuations should not be long running. + + + The specified TaskContinuationOptions excluded all continuation kinds. + + + The value needs to translate in milliseconds to -1 (signifying an infinite timeout), 0 or a positive integer less than or equal to Int32.MaxValue. + + + The value needs to be either -1 (signifying an infinite timeout), 0 or a positive integer. + + + A task may only be disposed if it is in a completion state (RanToCompletion, Faulted or Canceled). + + + It is invalid to specify TaskCreationOptions.LongRunning in calls to FromAsync. + + + It is invalid to specify TaskCreationOptions.PreferFairness in calls to FromAsync. + + + The tasks argument contains no tasks. + + + It is invalid to exclude specific continuation kinds for continuations off of multiple tasks. + + + The tasks argument included a null value. + + + RunSynchronously may not be called on a task that was already started. + + + RunSynchronously may not be called on a continuation task. + + + RunSynchronously may not be called on a task not bound to a delegate, such as the task returned from an asynchronous method. + + + RunSynchronously may not be called on a task that has already completed. + + + Start may not be called on a task that was already started. + + + Start may not be called on a continuation task. + + + Start may not be called on a promise-style task. + + + Start may not be called on a task that has completed. + + + The task has been disposed. + + + The tasks array included at least one null element. + + + A task was canceled. + + + The exceptions collection was empty. + + + The exceptions collection included at least one null element. + + + A Task's exception(s) were not observed either by Waiting on the Task or accessing its Exception property. As a result, the unobserved exception was rethrown by the finalizer thread. + + + (Internal)Expected an Exception or an IEnumerable<Exception> + + + ExecuteTask may not be called for a task which was previously queued to a different TaskScheduler. + + + The current SynchronizationContext may not be used as a TaskScheduler. + + + The TryExecuteTaskInline call to the underlying scheduler succeeded, but the task body was not invoked. + + + An exception was thrown by a TaskScheduler. + + + {Not yet computed} + + + An attempt was made to transition a task to a final state when it had already completed. + + + Failed to set the specified COM apartment state. + + + Use CompressedStack.(Capture/Run) instead. + + + This operation must be performed on the same thread as that represented by the Thread instance. + + + The wait completed due to an abandoned mutex. + + + No handle of the given name exists. + + + A WaitHandle with system-wide name '{0}' cannot be created. A WaitHandle of a different type might have the same name. + + + The WaitHandle cannot be signaled because it would exceed its maximum count. + + + Adding the specified count to the semaphore would cause it to exceed its maximum count. + + + Thread was interrupted from a waiting state. + + + The ThreadLocal object has been disposed. + + + ValueFactory attempted to access the Value property of this instance. + + + The ThreadLocal object is not tracking values. To use the Values property, use a ThreadLocal constructor that accepts the trackAllValues parameter and set the parameter to true. + + + The time zone ID '{0}' was not found on the local computer. + + + Type constructor threw an exception. + + + The type initializer for '{0}' threw an exception. + + + Could not resolve nested type '{0}' in type "{1}'. + + + Could not resolve type '{0}'. + + + Could not resolve type '{0}' in assembly '{1}'. + + + Access to the path is denied. + + + Access to the path '{0}' is denied. + + + MemoryStream's internal buffer cannot be accessed. + + + Access to the registry key '{0}' is denied. + + + Unknown error "{0}". + + + Operation could destabilize the runtime. + + + at + + + ---- DEBUG ASSERTION FAILED ---- + + + ---- Assert Long Message ---- + + + ---- Assert Short Message ---- + + + A read lock may not be acquired with the write lock held in this mode. + + + Recursive read lock acquisitions not allowed in this mode. + + + Recursive write lock acquisitions not allowed in this mode. + + + Recursive upgradeable lock acquisitions not allowed in this mode. + + + Write lock may not be acquired with read lock held. This pattern is prone to deadlocks. Please ensure that read locks are released before taking a write lock. If an upgrade is necessary, use an upgrade lock in place of the read lock. + + + The upgradeable lock is being released without being held. + + + The read lock is being released without being held. + + + The lock is being disposed while still being used. It either is being held by a thread and/or has active waiters waiting to acquire the lock. + + + Upgradeable lock may not be acquired with read lock held. + + + Upgradeable lock may not be acquired with write lock held in this mode. Acquiring Upgradeable lock gives the ability to read along with an option to upgrade to a writer. + + + The write lock is being released without being held. + + + This method is not supported on signature types. + + + Release all references before disposing this instance. + + + HashCode is a mutable struct and should not be compared with other HashCodes. Use ToHashCode to retrieve the computed hash code. + + + HashCode is a mutable struct and should not be compared with other HashCodes. + + + Specified type is not supported + + + The read operation returned an invalid length. + + + Basepath argument is not fully qualified. + + + Number of elements in source vector is greater than the destination array + + + The method was called with a null array argument. + + + Abstract methods cannot be prepared. + + + The given generic instantiation was invalid. + + + Overlapping spans have mismatching alignment. + + + At least {0} element(s) are expected in the parameter "{1}". + + + The string must be null-terminated. + + + The week parameter must be in the range 1 through 53. + + + PInvoke methods must be static and native and cannot be abstract. + + + PInvoke methods cannot exist on interfaces. + + + Method has been already defined. + + + Cannot extract a Unicode scalar value from the specified index in the input. + + + Characters following the format symbol must be a number of {0} or less. + + + The 'G' format combined with a precision is not supported. + + + Precision cannot be larger than {0}. + + + Cannot load hostpolicy library. AssemblyDependencyResolver is currently only supported if the runtime is hosted through hostpolicy library. + + + Dependency resolution failed for component {0} with error code {1}. Detailed error: {2} + + + The supplied object does not implement ICloneable. + + + The returned enumerator does not implement IEnumVARIANT. + + + Array size exceeds addressing limitations. + + + ArrayWithOffset: offset exceeds array size. + + + An action was attempted during deserialization that could lead to a security vulnerability. The action has been aborted. + + + An action was attempted during deserialization that could lead to a security vulnerability. The action has been aborted. To allow the action, set the '{0}' AppContext switch to true. + + + The startup hook simple assembly name '{0}' is invalid. It must be a valid assembly name and it may not contain directory separator, space or comma characters and must not end with '.dll'. + + + Startup hook assembly '{0}' failed to load. See inner exception for details. + + + COM register function must be static. + + + COM unregister function must be static. + + + COM register function must have a System.Type parameter and a void return type. + + + COM unregister function must have a System.Type parameter and a void return type. + + + Type '{0}' has more than one COM registration function. + + + Type '{0}' has more than one COM unregistration function. + + + Attempt to update previously set global instance. + + + The callback populated its buffer with ill-formed UTF-8 data. Callbacks are required to populate the buffer only with well-formed UTF-8 data. + + + The input buffer contained ill-formed UTF-16 data. + + + The input buffer contained ill-formed UTF-8 data. + + + Cannot create the desired substring because it would split a multi-byte UTF-8 subsequence. + + + Cannot call Utf8Span.Equals(object). Use Equals(Utf8Span) or operator == instead. + + + UTF-16 surrogate code points (U+D800..U+DFFF) are disallowed. + + + Argument cannot be an empty span. + + + Argument cannot be null or empty. + + + Length of items must be same as length of keys. + + + Cannot write to a BufferedStream while the read buffer is not empty if the underlying stream is not seekable. Ensure that the stream underlying this BufferedStream can seek or avoid interleaving read and write operations on this BufferedStream. + + + Found invalid data while decoding. + + + Resource type in the ResourceScope enum is going from a more restrictive resource type to a more general one. From: "{0}" To: "{1}" + + + The type parameter cannot be null when scoping the resource's visibility to Private or Assembly. + + + Unknown value for the ResourceScope: {0} Too many resource type bits may be set. + + + Unknown value for the ResourceScope: {0} Too many resource visibility bits may be set. + + + The parameter '{0}' cannot be an empty string. + + + ApplicationId cannot have an empty string for the name. + + + FrameworkName is invalid. + + + FrameworkName version component is invalid. + + + FrameworkName version component is missing. + + + FrameworkName cannot have less than two components or more than three components. + + + Non-exhaustive switch expression failed to match its input. + + + Attempted to marshal an object across a context boundary. + + + Attempted to access an unloaded AppDomain. + + + Unmatched value was {0}. + + diff --git a/src/System.Private.CoreLib/shared/System.Private.CoreLib.Shared.projitems b/src/System.Private.CoreLib/shared/System.Private.CoreLib.Shared.projitems index db57ae845..536fe0bf7 100644 --- a/src/System.Private.CoreLib/shared/System.Private.CoreLib.Shared.projitems +++ b/src/System.Private.CoreLib/shared/System.Private.CoreLib.Shared.projitems @@ -149,6 +149,7 @@ + @@ -239,16 +240,24 @@ + + + + + + + + @@ -266,14 +275,22 @@ + + + + + + + + @@ -286,6 +303,8 @@ + + @@ -477,6 +496,7 @@ + @@ -735,7 +755,6 @@ - @@ -859,7 +878,7 @@ - + @@ -967,12 +986,64 @@ - + + + Common\Interop\Interop.Libraries.cs + + + Common\Interop\Interop.Calendar.cs + + + Common\Interop\Interop.Casing.cs + + + Common\Interop\Interop.Collation.cs + + + Common\Interop\Interop.ICU.cs + + + Common\Interop\Interop.Idna.cs + + + Common\Interop\Interop.Locale.cs + + + Common\Interop\Interop.Normalization.cs + + + Common\Interop\Interop.ResultCode.cs + + + Common\Interop\Interop.TimeZoneInfo.cs + + + Common\Interop\Interop.Utils.cs + + + Common\Interop\Interop.Errors.cs + + + + Common\Interop\Windows\Interop.BOOL.cs + + + Common\Interop\Windows\Kernel32\Interop.Globalization.cs + + + Common\Interop\Windows\Kernel32\Interop.ResolveLocaleName.cs + + + Common\Interop\Windows\Normaliz\Interop.Idna.cs + + + Common\Interop\Windows\Normaliz\Interop.Normalization.cs + Common\System\HResults.cs @@ -1018,6 +1089,11 @@ + + + + + @@ -1025,7 +1101,9 @@ + + @@ -1052,12 +1130,14 @@ + + @@ -1165,9 +1245,6 @@ Common\Interop\Windows\Crypt32\Interop.CryptProtectMemory.cs - - Common\Interop\Windows\Interop.BOOL.cs - Common\Interop\Windows\Interop.BOOLEAN.cs @@ -1282,12 +1359,6 @@ Common\Interop\Windows\Kernel32\Interop.GetTempPathW.cs - - Common\Interop\Windows\Kernel32\Interop.GetVersionExW.cs - - - Common\Interop\Windows\Kernel32\Interop.Globalization.cs - Common\Interop\Windows\Kernel32\Interop.GlobalMemoryStatusEx.cs @@ -1336,9 +1407,6 @@ Common\Interop\Windows\Kernel32\Interop.ReadFile_SafeHandle_NativeOverlapped.cs - - Common\Interop\Windows\Kernel32\Interop.ResolveLocaleName.cs - Common\Interop\Windows\Kernel32\Interop.SECURITY_ATTRIBUTES.cs @@ -1399,18 +1467,15 @@ Common\Interop\Windows\Kernel32\Interop.WriteFile_SafeHandle_NativeOverlapped.cs - - Common\Interop\Windows\Normaliz\Interop.Idna.cs - - - Common\Interop\Windows\Normaliz\Interop.Normalization.cs - Common\Interop\Windows\NtDll\Interop.NtQueryInformationFile.cs Common\Interop\Windows\NtDll\Interop.NtQuerySystemInformation.cs + + Common\Interop\Windows\NtDll\Interop.RtlGetVersion.cs + Common\Interop\Windows\NtDll\Interop.SYSTEM_LEAP_SECOND_INFORMATION.cs @@ -1455,15 +1520,8 @@ - - - - + - - - - @@ -1486,6 +1544,9 @@ + + + @@ -1500,7 +1561,6 @@ - Common\Interop\Windows\OleAut32\Interop.SysAllocStringLen.cs @@ -1545,7 +1605,7 @@ Common\System\IO\Win32Marshal.cs - + @@ -1566,36 +1626,6 @@ Common\Interop\Unix\Interop.Libraries.cs - - Common\Interop\Unix\System.Globalization.Native\Interop.Calendar.cs - - - Common\Interop\Unix\System.Globalization.Native\Interop.Casing.cs - - - Common\Interop\Unix\System.Globalization.Native\Interop.Collation.cs - - - Common\Interop\Unix\System.Globalization.Native\Interop.ICU.cs - - - Common\Interop\Unix\System.Globalization.Native\Interop.Idna.cs - - - Common\Interop\Unix\System.Globalization.Native\Interop.Locale.cs - - - Common\Interop\Unix\System.Globalization.Native\Interop.Normalization.cs - - - Common\Interop\Unix\System.Globalization.Native\Interop.ResultCode.cs - - - Common\Interop\Unix\System.Globalization.Native\Interop.TimeZoneInfo.cs - - - Common\Interop\Unix\System.Globalization.Native\Interop.Utils.cs - Common\Interop\Unix\System.Native\Interop.Access.cs @@ -1705,22 +1735,15 @@ + - - - - + - - - - - - - + + diff --git a/src/System.Private.CoreLib/shared/System/AppContext.cs b/src/System.Private.CoreLib/shared/System/AppContext.cs index c79e8ee9f..907356696 100644 --- a/src/System.Private.CoreLib/shared/System/AppContext.cs +++ b/src/System.Private.CoreLib/shared/System/AppContext.cs @@ -22,7 +22,7 @@ namespace System public static string BaseDirectory => // The value of APP_CONTEXT_BASE_DIRECTORY key has to be a string and it is not allowed to be any other type. // Otherwise the caller will get invalid cast exception - (string?)GetData("APP_CONTEXT_BASE_DIRECTORY") ?? + GetData("APP_CONTEXT_BASE_DIRECTORY") as string ?? (s_defaultBaseDirectory ??= GetBaseDirectoryCore()); public static string? TargetFrameworkName => diff --git a/src/System.Private.CoreLib/shared/System/AppContextConfigHelper.cs b/src/System.Private.CoreLib/shared/System/AppContextConfigHelper.cs index a55076348..4bb3e180d 100644 --- a/src/System.Private.CoreLib/shared/System/AppContextConfigHelper.cs +++ b/src/System.Private.CoreLib/shared/System/AppContextConfigHelper.cs @@ -12,7 +12,7 @@ namespace System { try { - object config = AppContext.GetData(configName); + object? config = AppContext.GetData(configName); int result = defaultValue; switch (config) { @@ -54,7 +54,7 @@ namespace System { try { - object config = AppContext.GetData(configName); + object? config = AppContext.GetData(configName); short result = defaultValue; switch (config) { diff --git a/src/System.Private.CoreLib/shared/System/AppDomain.cs b/src/System.Private.CoreLib/shared/System/AppDomain.cs index 68379b235..7cd1e8e97 100644 --- a/src/System.Private.CoreLib/shared/System/AppDomain.cs +++ b/src/System.Private.CoreLib/shared/System/AppDomain.cs @@ -149,8 +149,7 @@ namespace System public bool? IsCompatibilitySwitchSet(string value) { - bool result; - return AppContext.TryGetSwitch(value, out result) ? result : default(bool?); + return AppContext.TryGetSwitch(value, out bool result) ? result : default(bool?); } public bool IsDefaultAppDomain() => true; diff --git a/src/System.Private.CoreLib/shared/System/Array.cs b/src/System.Private.CoreLib/shared/System/Array.cs index 5e22383eb..fa80d26e4 100644 --- a/src/System.Private.CoreLib/shared/System/Array.cs +++ b/src/System.Private.CoreLib/shared/System/Array.cs @@ -7,6 +7,7 @@ using System.Collections.Generic; using System.Collections.ObjectModel; using System.Diagnostics; using System.Diagnostics.CodeAnalysis; +using System.Numerics; using System.Reflection; using System.Runtime.CompilerServices; using System.Runtime.InteropServices; @@ -26,6 +27,11 @@ namespace System internal const int MaxArrayLength = 0X7FEFFFFF; internal const int MaxByteArrayLength = 0x7FFFFFC7; + // This is the threshold where Introspective sort switches to Insertion sort. + // Empirically, 16 seems to speed up most cases without slowing down others, at least for integers. + // Large value types may benefit from a smaller number. + internal const int IntrosortSizeThreshold = 16; + // This ctor exists solely to prevent C# from generating a protected .ctor that violates the surface area. private protected Array() { } @@ -510,9 +516,7 @@ namespace System if (comparer == Comparer.Default) { CorElementType et = array.GetCorElementTypeOfElementType(); - if (et.IsPrimitiveType() - // IntPtr/UIntPtr does not implement IComparable - && (et != CorElementType.ELEMENT_TYPE_I) && (et != CorElementType.ELEMENT_TYPE_U)) + if (et.IsPrimitiveType()) { if (value == null) return ~index; @@ -538,15 +542,27 @@ namespace System result = GenericBinarySearch(array, adjustedIndex, length, value); break; case CorElementType.ELEMENT_TYPE_I4: +#if TARGET_32BIT + case CorElementType.ELEMENT_TYPE_I: +#endif result = GenericBinarySearch(array, adjustedIndex, length, value); break; case CorElementType.ELEMENT_TYPE_U4: +#if TARGET_32BIT + case CorElementType.ELEMENT_TYPE_U: +#endif result = GenericBinarySearch(array, adjustedIndex, length, value); break; case CorElementType.ELEMENT_TYPE_I8: +#if TARGET_64BIT + case CorElementType.ELEMENT_TYPE_I: +#endif result = GenericBinarySearch(array, adjustedIndex, length, value); break; case CorElementType.ELEMENT_TYPE_U8: +#if TARGET_64BIT + case CorElementType.ELEMENT_TYPE_U: +#endif result = GenericBinarySearch(array, adjustedIndex, length, value); break; case CorElementType.ELEMENT_TYPE_R4: @@ -1674,15 +1690,27 @@ namespace System GenericSort(keys, items, adjustedIndex, length); return; case CorElementType.ELEMENT_TYPE_I4: +#if TARGET_32BIT + case CorElementType.ELEMENT_TYPE_I: +#endif GenericSort(keys, items, adjustedIndex, length); return; case CorElementType.ELEMENT_TYPE_U4: +#if TARGET_32BIT + case CorElementType.ELEMENT_TYPE_U: +#endif GenericSort(keys, items, adjustedIndex, length); return; case CorElementType.ELEMENT_TYPE_I8: +#if TARGET_64BIT + case CorElementType.ELEMENT_TYPE_I: +#endif GenericSort(keys, items, adjustedIndex, length); return; case CorElementType.ELEMENT_TYPE_U8: +#if TARGET_64BIT + case CorElementType.ELEMENT_TYPE_U: +#endif GenericSort(keys, items, adjustedIndex, length); return; case CorElementType.ELEMENT_TYPE_R4: @@ -1691,10 +1719,6 @@ namespace System case CorElementType.ELEMENT_TYPE_R8: GenericSort(keys, items, adjustedIndex, length); return; - case CorElementType.ELEMENT_TYPE_I: - case CorElementType.ELEMENT_TYPE_U: - // IntPtr/UIntPtr does not implement IComparable - break; } static void GenericSort(Array keys, Array? items, int adjustedIndex, int length) where T: struct @@ -1898,11 +1922,11 @@ namespace System try { - IntroSort(left, length + left - 1, 2 * IntrospectiveSortUtilities.FloorLog2PlusOne(length)); + IntroSort(left, length + left - 1, 2 * (BitOperations.Log2((uint)length) + 1)); } catch (IndexOutOfRangeException) { - IntrospectiveSortUtilities.ThrowOrIgnoreBadComparer(comparer); + ThrowHelper.ThrowArgumentException_BadComparer(comparer); } catch (Exception e) { @@ -1912,20 +1936,22 @@ namespace System private void IntroSort(int lo, int hi, int depthLimit) { + Debug.Assert(hi >= lo); + Debug.Assert(depthLimit >= 0); + while (hi > lo) { int partitionSize = hi - lo + 1; - if (partitionSize <= IntrospectiveSortUtilities.IntrosortSizeThreshold) + if (partitionSize <= IntrosortSizeThreshold) { - if (partitionSize == 1) - { - return; - } + Debug.Assert(partitionSize >= 2); + if (partitionSize == 2) { SwapIfGreater(lo, hi); return; } + if (partitionSize == 3) { SwapIfGreater(lo, hi - 1); @@ -1953,8 +1979,11 @@ namespace System private int PickPivotAndPartition(int lo, int hi) { + Debug.Assert(hi - lo >= IntrosortSizeThreshold); + // Compute median-of-three. But also partition them, since we've done the comparison. int mid = lo + (hi - lo) / 2; + // Sort lo, mid and hi appropriately, then pick mid as the pivot. SwapIfGreater(lo, mid); SwapIfGreater(lo, hi); @@ -1976,7 +2005,10 @@ namespace System } // Put pivot in the right location. - Swap(left, hi - 1); + if (left != hi - 1) + { + Swap(left, hi - 1); + } return left; } @@ -2104,11 +2136,11 @@ namespace System try { - IntroSort(left, length + left - 1, 2 * IntrospectiveSortUtilities.FloorLog2PlusOne(length)); + IntroSort(left, length + left - 1, 2 * (BitOperations.Log2((uint)length) + 1)); } catch (IndexOutOfRangeException) { - IntrospectiveSortUtilities.ThrowOrIgnoreBadComparer(comparer); + ThrowHelper.ThrowArgumentException_BadComparer(comparer); } catch (Exception e) { @@ -2118,20 +2150,22 @@ namespace System private void IntroSort(int lo, int hi, int depthLimit) { + Debug.Assert(hi >= lo); + Debug.Assert(depthLimit >= 0); + while (hi > lo) { int partitionSize = hi - lo + 1; - if (partitionSize <= IntrospectiveSortUtilities.IntrosortSizeThreshold) + if (partitionSize <= IntrosortSizeThreshold) { - if (partitionSize == 1) - { - return; - } + Debug.Assert(partitionSize >= 2); + if (partitionSize == 2) { SwapIfGreater(lo, hi); return; } + if (partitionSize == 3) { SwapIfGreater(lo, hi - 1); @@ -2159,6 +2193,8 @@ namespace System private int PickPivotAndPartition(int lo, int hi) { + Debug.Assert(hi - lo >= IntrosortSizeThreshold); + // Compute median-of-three. But also partition them, since we've done the comparison. int mid = lo + (hi - lo) / 2; @@ -2182,7 +2218,10 @@ namespace System } // Put pivot in the right location. - Swap(left, hi - 1); + if (left != hi - 1) + { + Swap(left, hi - 1); + } return left; } diff --git a/src/System.Private.CoreLib/shared/System/BitConverter.cs b/src/System.Private.CoreLib/shared/System/BitConverter.cs index 25719466d..bf604f41a 100644 --- a/src/System.Private.CoreLib/shared/System/BitConverter.cs +++ b/src/System.Private.CoreLib/shared/System/BitConverter.cs @@ -4,6 +4,8 @@ using System.Runtime.CompilerServices; using System.Runtime.InteropServices; +using System.Runtime.Intrinsics; +using System.Runtime.Intrinsics.X86; using Internal.Runtime.CompilerServices; @@ -449,24 +451,52 @@ namespace System [MethodImpl(MethodImplOptions.AggressiveInlining)] public static unsafe long DoubleToInt64Bits(double value) { + // Workaround for https://github.com/dotnet/runtime/issues/11413 + if (Sse2.X64.IsSupported) + { + Vector128 vec = Vector128.CreateScalarUnsafe(value).AsInt64(); + return Sse2.X64.ConvertToInt64(vec); + } + return *((long*)&value); } [MethodImpl(MethodImplOptions.AggressiveInlining)] public static unsafe double Int64BitsToDouble(long value) { + // Workaround for https://github.com/dotnet/runtime/issues/11413 + if (Sse2.X64.IsSupported) + { + Vector128 vec = Vector128.CreateScalarUnsafe(value).AsDouble(); + return vec.ToScalar(); + } + return *((double*)&value); } [MethodImpl(MethodImplOptions.AggressiveInlining)] public static unsafe int SingleToInt32Bits(float value) { + // Workaround for https://github.com/dotnet/runtime/issues/11413 + if (Sse2.IsSupported) + { + Vector128 vec = Vector128.CreateScalarUnsafe(value).AsInt32(); + return Sse2.ConvertToInt32(vec); + } + return *((int*)&value); } [MethodImpl(MethodImplOptions.AggressiveInlining)] public static unsafe float Int32BitsToSingle(int value) { + // Workaround for https://github.com/dotnet/runtime/issues/11413 + if (Sse2.IsSupported) + { + Vector128 vec = Vector128.CreateScalarUnsafe(value).AsSingle(); + return vec.ToScalar(); + } + return *((float*)&value); } } diff --git a/src/System.Private.CoreLib/shared/System/Boolean.cs b/src/System.Private.CoreLib/shared/System/Boolean.cs index aad5656aa..71a498d24 100644 --- a/src/System.Private.CoreLib/shared/System/Boolean.cs +++ b/src/System.Private.CoreLib/shared/System/Boolean.cs @@ -12,6 +12,7 @@ ** ===========================================================*/ +using System.Diagnostics.CodeAnalysis; using System.Runtime.CompilerServices; using System.Runtime.Versioning; @@ -223,7 +224,7 @@ namespace System // Determines whether a String represents true or false. // - public static bool TryParse(string? value, out bool result) + public static bool TryParse([NotNullWhen(true)] string? value, out bool result) { if (value == null) { diff --git a/src/System.Private.CoreLib/shared/System/Buffers/Text/Utf8Parser/ParserHelpers.cs b/src/System.Private.CoreLib/shared/System/Buffers/Text/Utf8Parser/ParserHelpers.cs index d5f50473f..5d0562e9d 100644 --- a/src/System.Private.CoreLib/shared/System/Buffers/Text/Utf8Parser/ParserHelpers.cs +++ b/src/System.Private.CoreLib/shared/System/Buffers/Text/Utf8Parser/ParserHelpers.cs @@ -2,7 +2,10 @@ // 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.Diagnostics; +using System.Diagnostics.CodeAnalysis; using System.Runtime.CompilerServices; +using Internal.Runtime.CompilerServices; namespace System.Buffers.Text { @@ -70,5 +73,23 @@ namespace System.Buffers.Text value = default; return TryParseThrowFormatException(out bytesConsumed); } + + // + // Enable use of ThrowHelper from TryParse() routines without introducing dozens of non-code-coveraged "value= default; bytesConsumed = 0; return false" boilerplate. + // + [DoesNotReturn] + [StackTraceHidden] + public static bool TryParseThrowFormatException(ReadOnlySpan source, out T value, out int bytesConsumed) where T : struct + { + // The parameters to this method are ordered the same as our callers' parameters + // allowing the JIT to avoid unnecessary register swapping or spilling. + + Unsafe.SkipInit(out value); // bypass language initialization rules since we're about to throw + Unsafe.SkipInit(out bytesConsumed); + ThrowHelper.ThrowFormatException_BadFormatSpecifier(); + + Debug.Fail("Control should never reach this point."); + return false; + } } } diff --git a/src/System.Private.CoreLib/shared/System/Buffers/Text/Utf8Parser/Utf8Parser.Boolean.cs b/src/System.Private.CoreLib/shared/System/Buffers/Text/Utf8Parser/Utf8Parser.Boolean.cs index 1c5e4f243..ae771e9b7 100644 --- a/src/System.Private.CoreLib/shared/System/Buffers/Text/Utf8Parser/Utf8Parser.Boolean.cs +++ b/src/System.Private.CoreLib/shared/System/Buffers/Text/Utf8Parser/Utf8Parser.Boolean.cs @@ -30,7 +30,7 @@ namespace System.Buffers.Text public static bool TryParse(ReadOnlySpan source, out bool value, out int bytesConsumed, char standardFormat = default) { if (!(standardFormat == default(char) || standardFormat == 'G' || standardFormat == 'l')) - return ParserHelpers.TryParseThrowFormatException(out value, out bytesConsumed); + ThrowHelper.ThrowFormatException_BadFormatSpecifier(); if (source.Length >= 4) { @@ -42,7 +42,7 @@ namespace System.Buffers.Text return true; } - if (source.Length >= 5) + if (4 < (uint)source.Length) { if (dw == 0x534c4146 /* 'SLAF' */ && (source[4] & ~0x20) == 'E') { diff --git a/src/System.Private.CoreLib/shared/System/Buffers/Text/Utf8Parser/Utf8Parser.Guid.cs b/src/System.Private.CoreLib/shared/System/Buffers/Text/Utf8Parser/Utf8Parser.Guid.cs index cdc2f5e5c..e5b48387d 100644 --- a/src/System.Private.CoreLib/shared/System/Buffers/Text/Utf8Parser/Utf8Parser.Guid.cs +++ b/src/System.Private.CoreLib/shared/System/Buffers/Text/Utf8Parser/Utf8Parser.Guid.cs @@ -29,19 +29,25 @@ namespace System.Buffers.Text /// public static bool TryParse(ReadOnlySpan source, out Guid value, out int bytesConsumed, char standardFormat = default) { + FastPath: + if (standardFormat == default) + { + return TryParseGuidCore(source, out value, out bytesConsumed, ends: 0); + } + switch (standardFormat) { - case default(char): case 'D': - return TryParseGuidCore(source, false, ' ', ' ', out value, out bytesConsumed); + standardFormat = default; + goto FastPath; case 'B': - return TryParseGuidCore(source, true, '{', '}', out value, out bytesConsumed); + return TryParseGuidCore(source, out value, out bytesConsumed, ends: '{' | ('}' << 8)); case 'P': - return TryParseGuidCore(source, true, '(', ')', out value, out bytesConsumed); + return TryParseGuidCore(source, out value, out bytesConsumed, ends: '(' | (')' << 8)); case 'N': return TryParseGuidN(source, out value, out bytesConsumed); default: - return ParserHelpers.TryParseThrowFormatException(out value, out bytesConsumed); + return ParserHelpers.TryParseThrowFormatException(source, out value, out bytesConsumed); } } @@ -97,9 +103,9 @@ namespace System.Buffers.Text } // {8-4-4-4-12}, where number is the number of hex digits, and {/} are ends. - private static bool TryParseGuidCore(ReadOnlySpan source, bool ends, char begin, char end, out Guid value, out int bytesConsumed) + private static bool TryParseGuidCore(ReadOnlySpan source, out Guid value, out int bytesConsumed, int ends) { - int expectedCodingUnits = 36 + (ends ? 2 : 0); // 32 hex digits + 4 delimiters + 2 optional ends + int expectedCodingUnits = 36 + ((ends != 0) ? 2 : 0); // 32 hex digits + 4 delimiters + 2 optional ends if (source.Length < expectedCodingUnits) { @@ -108,9 +114,16 @@ namespace System.Buffers.Text return false; } - if (ends) + // The 'ends' parameter is a 16-bit value where the byte denoting the starting + // brace is at byte position 0 and the byte denoting the closing brace is at + // byte position 1. If no braces are expected, has value 0. + // Default: ends = 0 + // Braces: ends = "}{" + // Parens: ends = ")(" + + if (ends != 0) { - if (source[0] != begin) + if (source[0] != (byte)ends) { value = default; bytesConsumed = 0; @@ -118,6 +131,7 @@ namespace System.Buffers.Text } source = source.Slice(1); // skip beginning + ends >>= 8; // shift the closing brace to byte position 0 } if (!TryParseUInt32X(source, out uint i1, out int justConsumed)) @@ -226,7 +240,7 @@ namespace System.Buffers.Text return false; // 12 digits } - if (ends && source[justConsumed] != end) + if (ends != 0 && source[justConsumed] != (byte)ends) { value = default; bytesConsumed = 0; diff --git a/src/System.Private.CoreLib/shared/System/Buffers/Text/Utf8Parser/Utf8Parser.Integer.Signed.cs b/src/System.Private.CoreLib/shared/System/Buffers/Text/Utf8Parser/Utf8Parser.Integer.Signed.cs index d6cc01b8a..10e8bd0a2 100644 --- a/src/System.Private.CoreLib/shared/System/Buffers/Text/Utf8Parser/Utf8Parser.Integer.Signed.cs +++ b/src/System.Private.CoreLib/shared/System/Buffers/Text/Utf8Parser/Utf8Parser.Integer.Signed.cs @@ -35,26 +35,31 @@ namespace System.Buffers.Text [CLSCompliant(false)] public static bool TryParse(ReadOnlySpan source, out sbyte value, out int bytesConsumed, char standardFormat = default) { - switch (standardFormat) + FastPath: + if (standardFormat == default) + { + return TryParseSByteD(source, out value, out bytesConsumed); + } + + // There's small but measurable overhead when entering the switch block below. + // We optimize for the default case by hoisting it above the switch block. + + switch (standardFormat | 0x20) // convert to lowercase { - case default(char): case 'g': - case 'G': case 'd': - case 'D': - return TryParseSByteD(source, out value, out bytesConsumed); + standardFormat = default; + goto FastPath; case 'n': - case 'N': return TryParseSByteN(source, out value, out bytesConsumed); case 'x': - case 'X': - value = default; + Unsafe.SkipInit(out value); // will be populated by TryParseByteX return TryParseByteX(source, out Unsafe.As(ref value), out bytesConsumed); default: - return ParserHelpers.TryParseThrowFormatException(out value, out bytesConsumed); + return ParserHelpers.TryParseThrowFormatException(source, out value, out bytesConsumed); } } @@ -81,26 +86,31 @@ namespace System.Buffers.Text /// public static bool TryParse(ReadOnlySpan source, out short value, out int bytesConsumed, char standardFormat = default) { - switch (standardFormat) + FastPath: + if (standardFormat == default) + { + return TryParseInt16D(source, out value, out bytesConsumed); + } + + // There's small but measurable overhead when entering the switch block below. + // We optimize for the default case by hoisting it above the switch block. + + switch (standardFormat | 0x20) // convert to lowercase { - case default(char): case 'g': - case 'G': case 'd': - case 'D': - return TryParseInt16D(source, out value, out bytesConsumed); + standardFormat = default; + goto FastPath; case 'n': - case 'N': return TryParseInt16N(source, out value, out bytesConsumed); case 'x': - case 'X': - value = default; + Unsafe.SkipInit(out value); // will be populated by TryParseUInt16X return TryParseUInt16X(source, out Unsafe.As(ref value), out bytesConsumed); default: - return ParserHelpers.TryParseThrowFormatException(out value, out bytesConsumed); + return ParserHelpers.TryParseThrowFormatException(source, out value, out bytesConsumed); } } @@ -127,26 +137,31 @@ namespace System.Buffers.Text /// public static bool TryParse(ReadOnlySpan source, out int value, out int bytesConsumed, char standardFormat = default) { - switch (standardFormat) + FastPath: + if (standardFormat == default) + { + return TryParseInt32D(source, out value, out bytesConsumed); + } + + // There's small but measurable overhead when entering the switch block below. + // We optimize for the default case by hoisting it above the switch block. + + switch (standardFormat | 0x20) // convert to lowercase { - case default(char): case 'g': - case 'G': case 'd': - case 'D': - return TryParseInt32D(source, out value, out bytesConsumed); + standardFormat = default; + goto FastPath; case 'n': - case 'N': return TryParseInt32N(source, out value, out bytesConsumed); case 'x': - case 'X': - value = default; + Unsafe.SkipInit(out value); // will be populated by TryParseUInt32X return TryParseUInt32X(source, out Unsafe.As(ref value), out bytesConsumed); default: - return ParserHelpers.TryParseThrowFormatException(out value, out bytesConsumed); + return ParserHelpers.TryParseThrowFormatException(source, out value, out bytesConsumed); } } @@ -173,26 +188,31 @@ namespace System.Buffers.Text /// public static bool TryParse(ReadOnlySpan source, out long value, out int bytesConsumed, char standardFormat = default) { - switch (standardFormat) + FastPath: + if (standardFormat == default) + { + return TryParseInt64D(source, out value, out bytesConsumed); + } + + // There's small but measurable overhead when entering the switch block below. + // We optimize for the default case by hoisting it above the switch block. + + switch (standardFormat | 0x20) // convert to lowercase { - case default(char): case 'g': - case 'G': case 'd': - case 'D': - return TryParseInt64D(source, out value, out bytesConsumed); + standardFormat = default; + goto FastPath; case 'n': - case 'N': return TryParseInt64N(source, out value, out bytesConsumed); case 'x': - case 'X': - value = default; + Unsafe.SkipInit(out value); // will be populated by TryParseUInt64X return TryParseUInt64X(source, out Unsafe.As(ref value), out bytesConsumed); default: - return ParserHelpers.TryParseThrowFormatException(out value, out bytesConsumed); + return ParserHelpers.TryParseThrowFormatException(source, out value, out bytesConsumed); } } } diff --git a/src/System.Private.CoreLib/shared/System/Buffers/Text/Utf8Parser/Utf8Parser.Integer.Unsigned.cs b/src/System.Private.CoreLib/shared/System/Buffers/Text/Utf8Parser/Utf8Parser.Integer.Unsigned.cs index 476889c1f..5d3237f19 100644 --- a/src/System.Private.CoreLib/shared/System/Buffers/Text/Utf8Parser/Utf8Parser.Integer.Unsigned.cs +++ b/src/System.Private.CoreLib/shared/System/Buffers/Text/Utf8Parser/Utf8Parser.Integer.Unsigned.cs @@ -29,25 +29,30 @@ namespace System.Buffers.Text /// public static bool TryParse(ReadOnlySpan source, out byte value, out int bytesConsumed, char standardFormat = default) { - switch (standardFormat) + FastPath: + if (standardFormat == default) + { + return TryParseByteD(source, out value, out bytesConsumed); + } + + // There's small but measurable overhead when entering the switch block below. + // We optimize for the default case by hoisting it above the switch block. + + switch (standardFormat | 0x20) // convert to lowercase { - case default(char): case 'g': - case 'G': case 'd': - case 'D': - return TryParseByteD(source, out value, out bytesConsumed); + standardFormat = default; + goto FastPath; case 'n': - case 'N': return TryParseByteN(source, out value, out bytesConsumed); case 'x': - case 'X': return TryParseByteX(source, out value, out bytesConsumed); default: - return ParserHelpers.TryParseThrowFormatException(out value, out bytesConsumed); + return ParserHelpers.TryParseThrowFormatException(source, out value, out bytesConsumed); } } @@ -75,25 +80,30 @@ namespace System.Buffers.Text [CLSCompliant(false)] public static bool TryParse(ReadOnlySpan source, out ushort value, out int bytesConsumed, char standardFormat = default) { - switch (standardFormat) + FastPath: + if (standardFormat == default) + { + return TryParseUInt16D(source, out value, out bytesConsumed); + } + + // There's small but measurable overhead when entering the switch block below. + // We optimize for the default case by hoisting it above the switch block. + + switch (standardFormat | 0x20) // convert to lowercase { - case default(char): case 'g': - case 'G': case 'd': - case 'D': - return TryParseUInt16D(source, out value, out bytesConsumed); + standardFormat = default; + goto FastPath; case 'n': - case 'N': return TryParseUInt16N(source, out value, out bytesConsumed); case 'x': - case 'X': return TryParseUInt16X(source, out value, out bytesConsumed); default: - return ParserHelpers.TryParseThrowFormatException(out value, out bytesConsumed); + return ParserHelpers.TryParseThrowFormatException(source, out value, out bytesConsumed); } } @@ -121,25 +131,30 @@ namespace System.Buffers.Text [CLSCompliant(false)] public static bool TryParse(ReadOnlySpan source, out uint value, out int bytesConsumed, char standardFormat = default) { - switch (standardFormat) + FastPath: + if (standardFormat == default) + { + return TryParseUInt32D(source, out value, out bytesConsumed); + } + + // There's small but measurable overhead when entering the switch block below. + // We optimize for the default case by hoisting it above the switch block. + + switch (standardFormat | 0x20) // convert to lowercase { - case default(char): case 'g': - case 'G': case 'd': - case 'D': - return TryParseUInt32D(source, out value, out bytesConsumed); + standardFormat = default; + goto FastPath; case 'n': - case 'N': return TryParseUInt32N(source, out value, out bytesConsumed); case 'x': - case 'X': return TryParseUInt32X(source, out value, out bytesConsumed); default: - return ParserHelpers.TryParseThrowFormatException(out value, out bytesConsumed); + return ParserHelpers.TryParseThrowFormatException(source, out value, out bytesConsumed); } } @@ -167,25 +182,30 @@ namespace System.Buffers.Text [CLSCompliant(false)] public static bool TryParse(ReadOnlySpan source, out ulong value, out int bytesConsumed, char standardFormat = default) { - switch (standardFormat) + FastPath: + if (standardFormat == default) + { + return TryParseUInt64D(source, out value, out bytesConsumed); + } + + // There's small but measurable overhead when entering the switch block below. + // We optimize for the default case by hoisting it above the switch block. + + switch (standardFormat | 0x20) // convert to lowercase { - case default(char): case 'g': - case 'G': case 'd': - case 'D': - return TryParseUInt64D(source, out value, out bytesConsumed); + standardFormat = default; + goto FastPath; case 'n': - case 'N': return TryParseUInt64N(source, out value, out bytesConsumed); case 'x': - case 'X': return TryParseUInt64X(source, out value, out bytesConsumed); default: - return ParserHelpers.TryParseThrowFormatException(out value, out bytesConsumed); + return ParserHelpers.TryParseThrowFormatException(source, out value, out bytesConsumed); } } } diff --git a/src/System.Private.CoreLib/shared/System/Byte.cs b/src/System.Private.CoreLib/shared/System/Byte.cs index 88d349a4b..c58709748 100644 --- a/src/System.Private.CoreLib/shared/System/Byte.cs +++ b/src/System.Private.CoreLib/shared/System/Byte.cs @@ -2,6 +2,7 @@ // 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.Diagnostics.CodeAnalysis; using System.Globalization; using System.Runtime.CompilerServices; using System.Runtime.InteropServices; @@ -117,7 +118,7 @@ namespace System return (byte)i; } - public static bool TryParse(string? s, out byte result) + public static bool TryParse([NotNullWhen(true)] string? s, out byte result) { if (s == null) { @@ -133,7 +134,7 @@ namespace System return TryParse(s, NumberStyles.Integer, NumberFormatInfo.CurrentInfo, out result); } - public static bool TryParse(string? s, NumberStyles style, IFormatProvider? provider, out byte result) + public static bool TryParse([NotNullWhen(true)] string? s, NumberStyles style, IFormatProvider? provider, out byte result) { NumberFormatInfo.ValidateParseStyleInteger(style); @@ -166,7 +167,7 @@ namespace System public override string ToString() { - return Number.UInt32ToDecStr(m_value, -1); + return Number.UInt32ToDecStr(m_value); } public string ToString(string? format) @@ -176,7 +177,7 @@ namespace System public string ToString(IFormatProvider? provider) { - return Number.FormatUInt32(m_value, null, provider); + return Number.UInt32ToDecStr(m_value); } public string ToString(string? format, IFormatProvider? provider) diff --git a/src/System.Private.CoreLib/shared/System/Char.cs b/src/System.Private.CoreLib/shared/System/Char.cs index 02e49c904..2ccf35ee7 100644 --- a/src/System.Private.CoreLib/shared/System/Char.cs +++ b/src/System.Private.CoreLib/shared/System/Char.cs @@ -13,6 +13,7 @@ ===========================================================*/ using System.Diagnostics; +using System.Diagnostics.CodeAnalysis; using System.Globalization; using System.Runtime.InteropServices; using System.Text; @@ -182,7 +183,7 @@ namespace System return s[0]; } - public static bool TryParse(string? s, out char result) + public static bool TryParse([NotNullWhen(true)] string? s, out char result) { result = '\0'; if (s == null) @@ -353,10 +354,7 @@ namespace System } // Converts a character to upper-case for invariant culture. - public static char ToUpperInvariant(char c) - { - return TextInfo.Invariant.ToUpper(c); - } + public static char ToUpperInvariant(char c) => TextInfo.ToUpperInvariant(c); /*===================================ToLower==================================== ** @@ -382,10 +380,7 @@ namespace System } // Converts a character to lower-case for invariant culture. - public static char ToLowerInvariant(char c) - { - return TextInfo.Invariant.ToLower(c); - } + public static char ToLowerInvariant(char c) => TextInfo.ToLowerInvariant(c); // // IConvertible implementation diff --git a/src/System.Private.CoreLib/shared/System/Collections/Concurrent/ConcurrentQueue.cs b/src/System.Private.CoreLib/shared/System/Collections/Concurrent/ConcurrentQueue.cs index ae86c6f96..480890eca 100644 --- a/src/System.Private.CoreLib/shared/System/Collections/Concurrent/ConcurrentQueue.cs +++ b/src/System.Private.CoreLib/shared/System/Collections/Concurrent/ConcurrentQueue.cs @@ -222,9 +222,7 @@ namespace System.Collections.Concurrent public T[] ToArray() { // Snap the current contents for enumeration. - ConcurrentQueueSegment head, tail; - int headHead, tailTail; - SnapForObservation(out head, out headHead, out tail, out tailTail); + SnapForObservation(out ConcurrentQueueSegment head, out int headHead, out ConcurrentQueueSegment tail, out int tailTail); // Count the number of items in that snapped set, and use it to allocate an // array of the right size. @@ -450,9 +448,7 @@ namespace System.Collections.Concurrent } // Snap for enumeration - ConcurrentQueueSegment head, tail; - int headHead, tailTail; - SnapForObservation(out head, out headHead, out tail, out tailTail); + SnapForObservation(out ConcurrentQueueSegment head, out int headHead, out ConcurrentQueueSegment tail, out int tailTail); // Get the number of items to be enumerated long count = GetCount(head, headHead, tail, tailTail); @@ -484,9 +480,7 @@ namespace System.Collections.Concurrent /// public IEnumerator GetEnumerator() { - ConcurrentQueueSegment head, tail; - int headHead, tailTail; - SnapForObservation(out head, out headHead, out tail, out tailTail); + SnapForObservation(out ConcurrentQueueSegment head, out int headHead, out ConcurrentQueueSegment tail, out int tailTail); return Enumerate(head, headHead, tail, tailTail); } diff --git a/src/System.Private.CoreLib/shared/System/Collections/Generic/ArraySortHelper.cs b/src/System.Private.CoreLib/shared/System/Collections/Generic/ArraySortHelper.cs index 46b9890df..c0da64353 100644 --- a/src/System.Private.CoreLib/shared/System/Collections/Generic/ArraySortHelper.cs +++ b/src/System.Private.CoreLib/shared/System/Collections/Generic/ArraySortHelper.cs @@ -2,50 +2,23 @@ // The .NET Foundation licenses this file to you under the MIT license. // See the LICENSE file in the project root for more information. -/*============================================================ -** -** -** -** -** -** Purpose: class to sort arrays -** -** -===========================================================*/ - using System.Diagnostics; -using System.Diagnostics.CodeAnalysis; +using System.Numerics; using System.Runtime.CompilerServices; +using System.Runtime.InteropServices; +using Internal.Runtime.CompilerServices; + +#pragma warning disable SA1121 // explicitly using type aliases instead of built-in types +#if TARGET_64BIT +using nint = System.Int64; +#else +using nint = System.Int32; +#endif namespace System.Collections.Generic { #region ArraySortHelper for single arrays - internal static class IntrospectiveSortUtilities - { - // This is the threshold where Introspective sort switches to Insertion sort. - // Empirically, 16 seems to speed up most cases without slowing down others, at least for integers. - // Large value types may benefit from a smaller number. - internal const int IntrosortSizeThreshold = 16; - - internal static int FloorLog2PlusOne(int n) - { - int result = 0; - while (n >= 1) - { - result++; - n /= 2; - } - return result; - } - - [DoesNotReturn] - internal static void ThrowOrIgnoreBadComparer(object? comparer) - { - throw new ArgumentException(SR.Format(SR.Arg_BogusIComparer, comparer)); - } - } - internal partial class ArraySortHelper { #region IArraySortHelper Members @@ -61,11 +34,11 @@ namespace System.Collections.Generic } catch (IndexOutOfRangeException) { - IntrospectiveSortUtilities.ThrowOrIgnoreBadComparer(comparer); + ThrowHelper.ThrowArgumentException_BadComparer(comparer); } catch (Exception e) { - throw new InvalidOperationException(SR.InvalidOperation_IComparerFailed, e); + ThrowHelper.ThrowInvalidOperationException(ExceptionResource.InvalidOperation_IComparerFailed, e); } } @@ -78,7 +51,8 @@ namespace System.Collections.Generic } catch (Exception e) { - throw new InvalidOperationException(SR.InvalidOperation_IComparerFailed, e); + ThrowHelper.ThrowInvalidOperationException(ExceptionResource.InvalidOperation_IComparerFailed, e); + return 0; } } @@ -95,11 +69,11 @@ namespace System.Collections.Generic } catch (IndexOutOfRangeException) { - IntrospectiveSortUtilities.ThrowOrIgnoreBadComparer(comparer); + ThrowHelper.ThrowArgumentException_BadComparer(comparer); } catch (Exception e) { - throw new InvalidOperationException(SR.InvalidOperation_IComparerFailed, e); + ThrowHelper.ThrowInvalidOperationException(ExceptionResource.InvalidOperation_IComparerFailed, e); } } @@ -131,26 +105,24 @@ namespace System.Collections.Generic private static void SwapIfGreater(Span keys, Comparison comparer, int i, int j) { - if (i != j) + Debug.Assert(i != j); + + if (comparer(keys[i], keys[j]) > 0) { - if (comparer(keys[i], keys[j]) > 0) - { - T key = keys[i]; - keys[i] = keys[j]; - keys[j] = key; - } + T key = keys[i]; + keys[i] = keys[j]; + keys[j] = key; } } [MethodImpl(MethodImplOptions.AggressiveInlining)] private static void Swap(Span a, int i, int j) { - if (i != j) - { - T t = a[i]; - a[i] = a[j]; - a[j] = t; - } + Debug.Assert(i != j); + + T t = a[i]; + a[i] = a[j]; + a[j] = t; } internal static void IntrospectiveSort(Span keys, Comparison comparer) @@ -159,53 +131,51 @@ namespace System.Collections.Generic if (keys.Length > 1) { - IntroSort(keys, 2 * IntrospectiveSortUtilities.FloorLog2PlusOne(keys.Length), comparer); + IntroSort(keys, 2 * (BitOperations.Log2((uint)keys.Length) + 1), comparer); } } private static void IntroSort(Span keys, int depthLimit, Comparison comparer) { - int lo = 0; - int hi = keys.Length - 1; - + Debug.Assert(!keys.IsEmpty); + Debug.Assert(depthLimit >= 0); Debug.Assert(comparer != null); - while (hi > lo) + int hi = keys.Length - 1; + while (hi > 0) { - int partitionSize = hi - lo + 1; - if (partitionSize <= IntrospectiveSortUtilities.IntrosortSizeThreshold) + int partitionSize = hi + 1; + + if (partitionSize <= Array.IntrosortSizeThreshold) { - if (partitionSize == 1) - { - return; - } + Debug.Assert(partitionSize >= 2); if (partitionSize == 2) { - SwapIfGreater(keys, comparer, lo, hi); + SwapIfGreater(keys, comparer, 0, hi); return; } if (partitionSize == 3) { - SwapIfGreater(keys, comparer, lo, hi - 1); - SwapIfGreater(keys, comparer, lo, hi); + SwapIfGreater(keys, comparer, 0, hi - 1); + SwapIfGreater(keys, comparer, 0, hi); SwapIfGreater(keys, comparer, hi - 1, hi); return; } - InsertionSort(keys[lo..(hi+1)], comparer); + InsertionSort(keys.Slice(0, hi+1), comparer); return; } if (depthLimit == 0) { - HeapSort(keys[lo..(hi+1)], comparer); + HeapSort(keys.Slice(0, hi+1), comparer); return; } depthLimit--; - int p = PickPivotAndPartition(keys[lo..(hi+1)], comparer); + int p = PickPivotAndPartition(keys.Slice(0, hi+1), comparer); // Note we've already partitioned around the pivot and do not have to move the pivot again. IntroSort(keys[(p+1)..(hi+1)], depthLimit, comparer); @@ -215,23 +185,22 @@ namespace System.Collections.Generic private static int PickPivotAndPartition(Span keys, Comparison comparer) { + Debug.Assert(keys.Length >= Array.IntrosortSizeThreshold); Debug.Assert(comparer != null); - Debug.Assert(!keys.IsEmpty); - int lo = 0; int hi = keys.Length - 1; // Compute median-of-three. But also partition them, since we've done the comparison. - int middle = lo + ((hi - lo) / 2); + int middle = hi >> 1; // Sort lo, mid and hi appropriately, then pick mid as the pivot. - SwapIfGreater(keys, comparer, lo, middle); // swap the low with the mid point - SwapIfGreater(keys, comparer, lo, hi); // swap the low with the high + SwapIfGreater(keys, comparer, 0, middle); // swap the low with the mid point + SwapIfGreater(keys, comparer, 0, hi); // swap the low with the high SwapIfGreater(keys, comparer, middle, hi); // swap the middle with the high T pivot = keys[middle]; Swap(keys, middle, hi - 1); - int left = lo, right = hi - 1; // We already partitioned lo and hi and put the pivot in hi - 1. And we pre-increment & decrement below. + int left = 0, right = hi - 1; // We already partitioned lo and hi and put the pivot in hi - 1. And we pre-increment & decrement below. while (left < right) { @@ -245,7 +214,10 @@ namespace System.Collections.Generic } // Put pivot in the right location. - Swap(keys, left, hi - 1); + if (left != hi - 1) + { + Swap(keys, left, hi - 1); + } return left; } @@ -254,20 +226,16 @@ namespace System.Collections.Generic Debug.Assert(comparer != null); Debug.Assert(!keys.IsEmpty); - int lo = 0; - int hi = keys.Length - 1; - - int n = hi - lo + 1; - - for (int i = n / 2; i >= 1; i--) + int n = keys.Length; + for (int i = n >> 1; i >= 1; i--) { - DownHeap(keys, i, n, lo, comparer); + DownHeap(keys, i, n, 0, comparer); } for (int i = n; i > 1; i--) { - Swap(keys, lo, lo + i - 1); - DownHeap(keys, 1, i - 1, lo, comparer); + Swap(keys, 0, i - 1); + DownHeap(keys, 1, i - 1, 0, comparer); } } @@ -278,7 +246,7 @@ namespace System.Collections.Generic Debug.Assert(lo < keys.Length); T d = keys[lo + i - 1]; - while (i <= n / 2) + while (i <= n >> 1) { int child = 2 * i; if (child < n && comparer(keys[lo + child - 1], keys[lo + child]) < 0) @@ -327,7 +295,10 @@ namespace System.Collections.Generic { if (comparer == null || comparer == Comparer.Default) { - IntrospectiveSort(keys); + if (keys.Length > 1) + { + IntroSort(keys, 2 * (BitOperations.Log2((uint)keys.Length) + 1)); + } } else { @@ -336,11 +307,11 @@ namespace System.Collections.Generic } catch (IndexOutOfRangeException) { - IntrospectiveSortUtilities.ThrowOrIgnoreBadComparer(comparer); + ThrowHelper.ThrowArgumentException_BadComparer(comparer); } catch (Exception e) { - throw new InvalidOperationException(SR.InvalidOperation_IComparerFailed, e); + ThrowHelper.ThrowInvalidOperationException(ExceptionResource.InvalidOperation_IComparerFailed, e); } } @@ -362,7 +333,8 @@ namespace System.Collections.Generic } catch (Exception e) { - throw new InvalidOperationException(SR.InvalidOperation_IComparerFailed, e); + ThrowHelper.ThrowInvalidOperationException(ExceptionResource.InvalidOperation_IComparerFailed, e); + return 0; } } @@ -406,147 +378,140 @@ namespace System.Collections.Generic return ~lo; } - private static void SwapIfGreater(Span keys, int i, int j) - { - Debug.Assert(0 <= i && i < keys.Length); - Debug.Assert(0 <= j && j < keys.Length); - - if (i != j) - { - if (keys[i] != null && keys[i].CompareTo(keys[j]) > 0) - { - T key = keys[i]; - keys[i] = keys[j]; - keys[j] = key; - } - } - } - + /// Swaps the values in the two references if the first is greater than the second. [MethodImpl(MethodImplOptions.AggressiveInlining)] - private static void Swap(Span a, int i, int j) + private static void SwapIfGreater(ref T i, ref T j) { - if (i != j) + if (i != null && i.CompareTo(j) > 0) { - T t = a[i]; - a[i] = a[j]; - a[j] = t; + Swap(ref i, ref j); } } - internal static void IntrospectiveSort(Span keys) + /// Swaps the values in the two references, regardless of whether the two references are the same. + [MethodImpl(MethodImplOptions.AggressiveInlining)] + private static void Swap(ref T i, ref T j) { - if (keys.Length > 1) - { - IntroSort(keys, 2 * IntrospectiveSortUtilities.FloorLog2PlusOne(keys.Length)); - } + Debug.Assert(!Unsafe.AreSame(ref i, ref j)); + + T t = i; + i = j; + j = t; } private static void IntroSort(Span keys, int depthLimit) { - int lo = 0; - int hi = keys.Length - 1; + Debug.Assert(!keys.IsEmpty); + Debug.Assert(depthLimit >= 0); - while (hi > lo) + int hi = keys.Length - 1; + while (hi > 0) { - int partitionSize = hi - lo + 1; - if (partitionSize <= IntrospectiveSortUtilities.IntrosortSizeThreshold) + int partitionSize = hi + 1; + + if (partitionSize <= Array.IntrosortSizeThreshold) { - if (partitionSize == 1) - { - return; - } + Debug.Assert(partitionSize >= 2); + if (partitionSize == 2) { - SwapIfGreater(keys, lo, hi); - return; - } - if (partitionSize == 3) - { - SwapIfGreater(keys, lo, hi - 1); - SwapIfGreater(keys, lo, hi); - SwapIfGreater(keys, hi - 1, hi); + SwapIfGreater(ref keys[0], ref keys[1]); return; } - InsertionSort(keys[lo..(hi+1)]); + if (partitionSize == 3) + { + ref T hiRef = ref keys[2]; + ref T him1Ref = ref keys[1]; + ref T loRef = ref keys[0]; + + SwapIfGreater(ref loRef, ref him1Ref); + SwapIfGreater(ref loRef, ref hiRef); + SwapIfGreater(ref him1Ref, ref hiRef); + return; + } + + InsertionSort(keys.Slice(0, partitionSize)); return; } if (depthLimit == 0) { - HeapSort(keys[lo..(hi+1)]); + HeapSort(keys.Slice(0, partitionSize)); return; } depthLimit--; - int p = PickPivotAndPartition(keys[lo..(hi+1)]); + int p = PickPivotAndPartition(keys.Slice(0, partitionSize)); // Note we've already partitioned around the pivot and do not have to move the pivot again. - IntroSort(keys[(p+1)..(hi+1)], depthLimit); + IntroSort(keys[(p+1)..partitionSize], depthLimit); hi = p - 1; } } private static int PickPivotAndPartition(Span keys) { - Debug.Assert(!keys.IsEmpty); + Debug.Assert(keys.Length >= Array.IntrosortSizeThreshold); - int lo = 0; - int hi = keys.Length - 1; + // Use median-of-three to select a pivot. Grab a reference to the 0th, Length-1th, and Length/2th elements, and sort them. + ref T zeroRef = ref MemoryMarshal.GetReference(keys); + ref T lastRef = ref Unsafe.Add(ref zeroRef, keys.Length - 1); + ref T middleRef = ref Unsafe.Add(ref zeroRef, (keys.Length - 1) >> 1); + SwapIfGreater(ref zeroRef, ref middleRef); + SwapIfGreater(ref zeroRef, ref lastRef); + SwapIfGreater(ref middleRef, ref lastRef); - // Compute median-of-three. But also partition them, since we've done the comparison. - int middle = lo + ((hi - lo) / 2); + // Select the middle value as the pivot, and move it to be just before the last element. + ref T nextToLastRef = ref Unsafe.Add(ref zeroRef, keys.Length - 2); + T pivot = middleRef; + Swap(ref middleRef, ref nextToLastRef); - // Sort lo, mid and hi appropriately, then pick mid as the pivot. - SwapIfGreater(keys, lo, middle); // swap the low with the mid point - SwapIfGreater(keys, lo, hi); // swap the low with the high - SwapIfGreater(keys, middle, hi); // swap the middle with the high - - T pivot = keys[middle]; - Swap(keys, middle, hi - 1); - int left = lo, right = hi - 1; // We already partitioned lo and hi and put the pivot in hi - 1. And we pre-increment & decrement below. - - while (left < right) + // Walk the left and right pointers, swapping elements as necessary, until they cross. + ref T leftRef = ref zeroRef, rightRef = ref nextToLastRef; + while (Unsafe.IsAddressLessThan(ref leftRef, ref rightRef)) { if (pivot == null) { - while (left < (hi - 1) && keys[++left] == null) ; - while (right > lo && keys[--right] != null) ; + while (Unsafe.IsAddressLessThan(ref leftRef, ref nextToLastRef) && (leftRef = ref Unsafe.Add(ref leftRef, 1)) == null) ; + while (Unsafe.IsAddressGreaterThan(ref rightRef, ref zeroRef) && (rightRef = ref Unsafe.Add(ref rightRef, -1)) == null) ; } else { - while (pivot.CompareTo(keys[++left]) > 0) ; - while (pivot.CompareTo(keys[--right]) < 0) ; + while (Unsafe.IsAddressLessThan(ref leftRef, ref nextToLastRef) && pivot.CompareTo(leftRef = ref Unsafe.Add(ref leftRef, 1)) > 0) ; + while (Unsafe.IsAddressGreaterThan(ref rightRef, ref zeroRef) && pivot.CompareTo(rightRef = ref Unsafe.Add(ref rightRef, -1)) < 0) ; } - if (left >= right) + if (!Unsafe.IsAddressLessThan(ref leftRef, ref rightRef)) + { break; + } - Swap(keys, left, right); + Swap(ref leftRef, ref rightRef); } - // Put pivot in the right location. - Swap(keys, left, hi - 1); - return left; + // Put the pivot in the correct location. + if (!Unsafe.AreSame(ref leftRef, ref nextToLastRef)) + { + Swap(ref leftRef, ref nextToLastRef); + } + return (int)((nint)Unsafe.ByteOffset(ref zeroRef, ref leftRef) / Unsafe.SizeOf()); } private static void HeapSort(Span keys) { Debug.Assert(!keys.IsEmpty); - int lo = 0; - int hi = keys.Length - 1; - - int n = hi - lo + 1; - for (int i = n / 2; i >= 1; i = i - 1) + int n = keys.Length; + for (int i = n >> 1; i >= 1; i--) { - DownHeap(keys, i, n, lo); + DownHeap(keys, i, n, 0); } for (int i = n; i > 1; i--) { - Swap(keys, lo, lo + i - 1); - DownHeap(keys, 1, i - 1, lo); + Swap(ref keys[0], ref keys[i - 1]); + DownHeap(keys, 1, i - 1, 0); } } @@ -556,7 +521,7 @@ namespace System.Collections.Generic Debug.Assert(lo < keys.Length); T d = keys[lo + i - 1]; - while (i <= n / 2) + while (i <= n >> 1) { int child = 2 * i; if (child < n && (keys[lo + child - 1] == null || keys[lo + child - 1].CompareTo(keys[lo + child]) < 0)) @@ -578,16 +543,16 @@ namespace System.Collections.Generic { for (int i = 0; i < keys.Length - 1; i++) { - T t = keys[i + 1]; + T t = Unsafe.Add(ref MemoryMarshal.GetReference(keys), i + 1); int j = i; - while (j >= 0 && (t == null || t.CompareTo(keys[j]) < 0)) + while (j >= 0 && (t == null || t.CompareTo(Unsafe.Add(ref MemoryMarshal.GetReference(keys), j)) < 0)) { - keys[j + 1] = keys[j]; + Unsafe.Add(ref MemoryMarshal.GetReference(keys), j + 1) = Unsafe.Add(ref MemoryMarshal.GetReference(keys), j); j--; } - keys[j + 1] = t; + Unsafe.Add(ref MemoryMarshal.GetReference(keys), j + 1) = t; } } } @@ -608,11 +573,11 @@ namespace System.Collections.Generic } catch (IndexOutOfRangeException) { - IntrospectiveSortUtilities.ThrowOrIgnoreBadComparer(comparer); + ThrowHelper.ThrowArgumentException_BadComparer(comparer); } catch (Exception e) { - throw new InvalidOperationException(SR.InvalidOperation_IComparerFailed, e); + ThrowHelper.ThrowInvalidOperationException(ExceptionResource.InvalidOperation_IComparerFailed, e); } } @@ -621,35 +586,32 @@ namespace System.Collections.Generic Debug.Assert(comparer != null); Debug.Assert(0 <= i && i < keys.Length && i < values.Length); Debug.Assert(0 <= j && j < keys.Length && j < values.Length); + Debug.Assert(i != j); - if (i != j) + if (comparer.Compare(keys[i], keys[j]) > 0) { - if (comparer.Compare(keys[i], keys[j]) > 0) - { - TKey key = keys[i]; - keys[i] = keys[j]; - keys[j] = key; + TKey key = keys[i]; + keys[i] = keys[j]; + keys[j] = key; - TValue value = values[i]; - values[i] = values[j]; - values[j] = value; - } + TValue value = values[i]; + values[i] = values[j]; + values[j] = value; } } [MethodImpl(MethodImplOptions.AggressiveInlining)] private static void Swap(Span keys, Span values, int i, int j) { - if (i != j) - { - TKey k = keys[i]; - keys[i] = keys[j]; - keys[j] = k; + Debug.Assert(i != j); - TValue v = values[i]; - values[i] = values[j]; - values[j] = v; - } + TKey k = keys[i]; + keys[i] = keys[j]; + keys[j] = k; + + TValue v = values[i]; + values[i] = values[j]; + values[j] = v; } internal static void IntrospectiveSort(Span keys, Span values, IComparer comparer) @@ -659,79 +621,77 @@ namespace System.Collections.Generic if (keys.Length > 1) { - IntroSort(keys, values, 2 * IntrospectiveSortUtilities.FloorLog2PlusOne(keys.Length), comparer); + IntroSort(keys, values, 2 * (BitOperations.Log2((uint)keys.Length) + 1), comparer); } } private static void IntroSort(Span keys, Span values, int depthLimit, IComparer comparer) { + Debug.Assert(!keys.IsEmpty); + Debug.Assert(values.Length == keys.Length); + Debug.Assert(depthLimit >= 0); Debug.Assert(comparer != null); - int lo = 0; int hi = keys.Length - 1; - - while (hi > lo) + while (hi > 0) { - int partitionSize = hi - lo + 1; - if (partitionSize <= IntrospectiveSortUtilities.IntrosortSizeThreshold) + int partitionSize = hi + 1; + + if (partitionSize <= Array.IntrosortSizeThreshold) { - if (partitionSize == 1) - { - return; - } + Debug.Assert(partitionSize >= 2); if (partitionSize == 2) { - SwapIfGreaterWithValues(keys, values, comparer, lo, hi); + SwapIfGreaterWithValues(keys, values, comparer, 0, hi); return; } if (partitionSize == 3) { - SwapIfGreaterWithValues(keys, values, comparer, lo, hi - 1); - SwapIfGreaterWithValues(keys, values, comparer, lo, hi); + SwapIfGreaterWithValues(keys, values, comparer, 0, hi - 1); + SwapIfGreaterWithValues(keys, values, comparer, 0, hi); SwapIfGreaterWithValues(keys, values, comparer, hi - 1, hi); return; } - InsertionSort(keys[lo..(hi+1)], values[lo..(hi+1)], comparer); + InsertionSort(keys.Slice(0, partitionSize), values.Slice(0, partitionSize), comparer); return; } if (depthLimit == 0) { - HeapSort(keys[lo..(hi+1)], values[lo..(hi+1)], comparer); + HeapSort(keys.Slice(0, partitionSize), values.Slice(0, partitionSize), comparer); return; } depthLimit--; - int p = PickPivotAndPartition(keys[lo..(hi+1)], values[lo..(hi+1)], comparer); + int p = PickPivotAndPartition(keys.Slice(0, partitionSize), values.Slice(0, partitionSize), comparer); // Note we've already partitioned around the pivot and do not have to move the pivot again. - IntroSort(keys[(p+1)..(hi+1)], values[(p+1)..(hi+1)], depthLimit, comparer); + IntroSort(keys[(p+1)..partitionSize], values[(p+1)..partitionSize], depthLimit, comparer); hi = p - 1; } } private static int PickPivotAndPartition(Span keys, Span values, IComparer comparer) { + Debug.Assert(keys.Length >= Array.IntrosortSizeThreshold); Debug.Assert(comparer != null); - Debug.Assert(!keys.IsEmpty); - int lo = 0; int hi = keys.Length - 1; // Compute median-of-three. But also partition them, since we've done the comparison. - int middle = lo + ((hi - lo) / 2); + int middle = hi >> 1; // Sort lo, mid and hi appropriately, then pick mid as the pivot. - SwapIfGreaterWithValues(keys, values, comparer, lo, middle); // swap the low with the mid point - SwapIfGreaterWithValues(keys, values, comparer, lo, hi); // swap the low with the high + SwapIfGreaterWithValues(keys, values, comparer, 0, middle); // swap the low with the mid point + SwapIfGreaterWithValues(keys, values, comparer, 0, hi); // swap the low with the high SwapIfGreaterWithValues(keys, values, comparer, middle, hi); // swap the middle with the high TKey pivot = keys[middle]; Swap(keys, values, middle, hi - 1); - int left = lo, right = hi - 1; // We already partitioned lo and hi and put the pivot in hi - 1. And we pre-increment & decrement below. + int left = 0, right = hi - 1; // We already partitioned lo and hi and put the pivot in hi - 1. And we pre-increment & decrement below. while (left < right) { @@ -745,7 +705,10 @@ namespace System.Collections.Generic } // Put pivot in the right location. - Swap(keys, values, left, hi - 1); + if (left != hi - 1) + { + Swap(keys, values, left, hi - 1); + } return left; } @@ -754,19 +717,16 @@ namespace System.Collections.Generic Debug.Assert(comparer != null); Debug.Assert(!keys.IsEmpty); - int lo = 0; - int hi = keys.Length - 1; - - int n = hi - lo + 1; - for (int i = n / 2; i >= 1; i--) + int n = keys.Length; + for (int i = n >> 1; i >= 1; i--) { - DownHeap(keys, values, i, n, lo, comparer); + DownHeap(keys, values, i, n, 0, comparer); } for (int i = n; i > 1; i--) { - Swap(keys, values, lo, lo + i - 1); - DownHeap(keys, values, 1, i - 1, lo, comparer); + Swap(keys, values, 0, i - 1); + DownHeap(keys, values, 1, i - 1, 0, comparer); } } @@ -779,7 +739,7 @@ namespace System.Collections.Generic TKey d = keys[lo + i - 1]; TValue dValue = values[lo + i - 1]; - while (i <= n / 2) + while (i <= n >> 1) { int child = 2 * i; if (child < n && comparer.Compare(keys[lo + child - 1], keys[lo + child]) < 0) @@ -842,44 +802,42 @@ namespace System.Collections.Generic } catch (IndexOutOfRangeException) { - IntrospectiveSortUtilities.ThrowOrIgnoreBadComparer(comparer); + ThrowHelper.ThrowArgumentException_BadComparer(comparer); } catch (Exception e) { - throw new InvalidOperationException(SR.InvalidOperation_IComparerFailed, e); + ThrowHelper.ThrowInvalidOperationException(ExceptionResource.InvalidOperation_IComparerFailed, e); } } private static void SwapIfGreaterWithValues(Span keys, Span values, int i, int j) { - if (i != j) - { - if (keys[i] != null && keys[i].CompareTo(keys[j]) > 0) - { - TKey key = keys[i]; - keys[i] = keys[j]; - keys[j] = key; + Debug.Assert(i != j); - TValue value = values[i]; - values[i] = values[j]; - values[j] = value; - } + if (keys[i] != null && keys[i].CompareTo(keys[j]) > 0) + { + TKey key = keys[i]; + keys[i] = keys[j]; + keys[j] = key; + + TValue value = values[i]; + values[i] = values[j]; + values[j] = value; } } [MethodImpl(MethodImplOptions.AggressiveInlining)] private static void Swap(Span keys, Span values, int i, int j) { - if (i != j) - { - TKey k = keys[i]; - keys[i] = keys[j]; - keys[j] = k; + Debug.Assert(i != j); - TValue v = values[i]; - values[i] = values[j]; - values[j] = v; - } + TKey k = keys[i]; + keys[i] = keys[j]; + keys[j] = k; + + TValue v = values[i]; + values[i] = values[j]; + values[j] = v; } internal static void IntrospectiveSort(Span keys, Span values) @@ -888,83 +846,82 @@ namespace System.Collections.Generic if (keys.Length > 1) { - IntroSort(keys, values, 2 * IntrospectiveSortUtilities.FloorLog2PlusOne(keys.Length)); + IntroSort(keys, values, 2 * (BitOperations.Log2((uint)keys.Length) + 1)); } } private static void IntroSort(Span keys, Span values, int depthLimit) { - int lo = 0; - int hi = keys.Length - 1; + Debug.Assert(!keys.IsEmpty); + Debug.Assert(values.Length == keys.Length); + Debug.Assert(depthLimit >= 0); - while (hi > lo) + int hi = keys.Length - 1; + while (hi > 0) { - int partitionSize = hi - lo + 1; - if (partitionSize <= IntrospectiveSortUtilities.IntrosortSizeThreshold) + int partitionSize = hi + 1; + + if (partitionSize <= Array.IntrosortSizeThreshold) { - if (partitionSize == 1) - { - return; - } + Debug.Assert(partitionSize >= 2); if (partitionSize == 2) { - SwapIfGreaterWithValues(keys, values, lo, hi); + SwapIfGreaterWithValues(keys, values, 0, hi); return; } if (partitionSize == 3) { - SwapIfGreaterWithValues(keys, values, lo, hi - 1); - SwapIfGreaterWithValues(keys, values, lo, hi); + SwapIfGreaterWithValues(keys, values, 0, hi - 1); + SwapIfGreaterWithValues(keys, values, 0, hi); SwapIfGreaterWithValues(keys, values, hi - 1, hi); return; } - InsertionSort(keys[lo..(hi+1)], values[lo..(hi+1)]); + InsertionSort(keys.Slice(0, partitionSize), values.Slice(0, partitionSize)); return; } if (depthLimit == 0) { - HeapSort(keys[lo..(hi+1)], values[lo..(hi+1)]); + HeapSort(keys.Slice(0, partitionSize), values.Slice(0, partitionSize)); return; } depthLimit--; - int p = PickPivotAndPartition(keys[lo..(hi+1)], values[lo..(hi+1)]); + int p = PickPivotAndPartition(keys.Slice(0, partitionSize), values.Slice(0, partitionSize)); // Note we've already partitioned around the pivot and do not have to move the pivot again. - IntroSort(keys[(p+1)..(hi+1)], values[(p+1)..(hi+1)], depthLimit); + IntroSort(keys[(p+1)..partitionSize], values[(p+1)..partitionSize], depthLimit); hi = p - 1; } } private static int PickPivotAndPartition(Span keys, Span values) { - Debug.Assert(!keys.IsEmpty); + Debug.Assert(keys.Length >= Array.IntrosortSizeThreshold); - int lo = 0; int hi = keys.Length - 1; // Compute median-of-three. But also partition them, since we've done the comparison. - int middle = lo + ((hi - lo) / 2); + int middle = hi >> 1; // Sort lo, mid and hi appropriately, then pick mid as the pivot. - SwapIfGreaterWithValues(keys, values, lo, middle); // swap the low with the mid point - SwapIfGreaterWithValues(keys, values, lo, hi); // swap the low with the high + SwapIfGreaterWithValues(keys, values, 0, middle); // swap the low with the mid point + SwapIfGreaterWithValues(keys, values, 0, hi); // swap the low with the high SwapIfGreaterWithValues(keys, values, middle, hi); // swap the middle with the high TKey pivot = keys[middle]; Swap(keys, values, middle, hi - 1); - int left = lo, right = hi - 1; // We already partitioned lo and hi and put the pivot in hi - 1. And we pre-increment & decrement below. + int left = 0, right = hi - 1; // We already partitioned lo and hi and put the pivot in hi - 1. And we pre-increment & decrement below. while (left < right) { if (pivot == null) { while (left < (hi - 1) && keys[++left] == null) ; - while (right > lo && keys[--right] != null) ; + while (right > 0 && keys[--right] != null) ; } else { @@ -979,7 +936,10 @@ namespace System.Collections.Generic } // Put pivot in the right location. - Swap(keys, values, left, hi - 1); + if (left != hi - 1) + { + Swap(keys, values, left, hi - 1); + } return left; } @@ -987,19 +947,16 @@ namespace System.Collections.Generic { Debug.Assert(!keys.IsEmpty); - int lo = 0; - int hi = keys.Length - 1; - - int n = hi - lo + 1; - for (int i = n / 2; i >= 1; i--) + int n = keys.Length; + for (int i = n >> 1; i >= 1; i--) { - DownHeap(keys, values, i, n, lo); + DownHeap(keys, values, i, n, 0); } for (int i = n; i > 1; i--) { - Swap(keys, values, lo, lo + i - 1); - DownHeap(keys, values, 1, i - 1, lo); + Swap(keys, values, 0, i - 1); + DownHeap(keys, values, 1, i - 1, 0); } } @@ -1011,7 +968,7 @@ namespace System.Collections.Generic TKey d = keys[lo + i - 1]; TValue dValue = values[lo + i - 1]; - while (i <= n / 2) + while (i <= n >> 1) { int child = 2 * i; if (child < n && (keys[lo + child - 1] == null || keys[lo + child - 1].CompareTo(keys[lo + child]) < 0)) diff --git a/src/System.Private.CoreLib/shared/System/Collections/Generic/Dictionary.cs b/src/System.Private.CoreLib/shared/System/Collections/Generic/Dictionary.cs index 76a6333ce..84ea4bf24 100644 --- a/src/System.Private.CoreLib/shared/System/Collections/Generic/Dictionary.cs +++ b/src/System.Private.CoreLib/shared/System/Collections/Generic/Dictionary.cs @@ -512,7 +512,6 @@ namespace System.Collections.Generic if (behavior == InsertionBehavior.OverwriteExisting) { entries[i].value = value; - _version++; return true; } @@ -555,7 +554,6 @@ namespace System.Collections.Generic if (behavior == InsertionBehavior.OverwriteExisting) { entries[i].value = value; - _version++; return true; } @@ -595,7 +593,6 @@ namespace System.Collections.Generic if (behavior == InsertionBehavior.OverwriteExisting) { entries[i].value = value; - _version++; return true; } diff --git a/src/System.Private.CoreLib/shared/System/Collections/Generic/IReadOnlySet.cs b/src/System.Private.CoreLib/shared/System/Collections/Generic/IReadOnlySet.cs new file mode 100644 index 000000000..8a2bf719c --- /dev/null +++ b/src/System.Private.CoreLib/shared/System/Collections/Generic/IReadOnlySet.cs @@ -0,0 +1,62 @@ +// 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.Collections.Generic +{ + /// + /// Provides a readonly abstraction of a set. + /// + /// The type of elements in the set. + public interface IReadOnlySet : IReadOnlyCollection + { + /// + /// Determines if the set contains a specific item + /// + /// The item to check if the set contains. + /// if found; otherwise . + bool Contains(T item); + /// + /// Determines whether the current set is a proper (strict) subset of a specified collection. + /// + /// The collection to compare to the current set. + /// if the current set is a proper subset of other; otherwise . + /// other is . + bool IsProperSubsetOf(IEnumerable other); + /// + /// Determines whether the current set is a proper (strict) superset of a specified collection. + /// + /// The collection to compare to the current set. + /// if the collection is a proper superset of other; otherwise . + /// other is . + bool IsProperSupersetOf(IEnumerable other); + /// + /// Determine whether the current set is a subset of a specified collection. + /// + /// The collection to compare to the current set. + /// if the current set is a subset of other; otherwise . + /// other is . + bool IsSubsetOf(IEnumerable other); + /// + /// Determine whether the current set is a super set of a specified collection. + /// + /// The collection to compare to the current set + /// if the current set is a subset of other; otherwise . + /// other is . + bool IsSupersetOf(IEnumerable other); + /// + /// Determines whether the current set overlaps with the specified collection. + /// + /// The collection to compare to the current set. + /// if the current set and other share at least one common element; otherwise, . + /// other is . + bool Overlaps(IEnumerable other); + /// + /// Determines whether the current set and the specified collection contain the same elements. + /// + /// The collection to compare to the current set. + /// if the current set is equal to other; otherwise, . + /// other is . + bool SetEquals(IEnumerable other); + } +} diff --git a/src/System.Private.CoreLib/shared/System/Collections/Generic/ISet.cs b/src/System.Private.CoreLib/shared/System/Collections/Generic/ISet.cs index 657adf787..ce71acba6 100644 --- a/src/System.Private.CoreLib/shared/System/Collections/Generic/ISet.cs +++ b/src/System.Private.CoreLib/shared/System/Collections/Generic/ISet.cs @@ -2,8 +2,6 @@ // 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.CompilerServices; - namespace System.Collections.Generic { /// diff --git a/src/System.Private.CoreLib/shared/System/Collections/Hashtable.cs b/src/System.Private.CoreLib/shared/System/Collections/Hashtable.cs index e90c277cc..705fe24db 100644 --- a/src/System.Private.CoreLib/shared/System/Collections/Hashtable.cs +++ b/src/System.Private.CoreLib/shared/System/Collections/Hashtable.cs @@ -480,11 +480,9 @@ namespace System.Collections throw new ArgumentNullException(nameof(key), SR.ArgumentNull_Key); } - uint seed; - uint incr; // Take a snapshot of buckets, in case another thread resizes table bucket[] lbuckets = _buckets; - uint hashcode = InitHash(key, lbuckets.Length, out seed, out incr); + uint hashcode = InitHash(key, lbuckets.Length, out uint seed, out uint incr); int ntry = 0; bucket b; @@ -639,12 +637,10 @@ namespace System.Collections throw new ArgumentNullException(nameof(key), SR.ArgumentNull_Key); } - uint seed; - uint incr; // Take a snapshot of buckets, in case another thread does a resize bucket[] lbuckets = _buckets; - uint hashcode = InitHash(key, lbuckets.Length, out seed, out incr); + uint hashcode = InitHash(key, lbuckets.Length, out uint seed, out uint incr); int ntry = 0; bucket b; @@ -858,11 +854,9 @@ namespace System.Collections rehash(); } - uint seed; - uint incr; // Assume we only have one thread writing concurrently. Modify // buckets to contain new data, as long as we insert in the right order. - uint hashcode = InitHash(key, _buckets.Length, out seed, out incr); + uint hashcode = InitHash(key, _buckets.Length, out uint seed, out uint incr); int ntry = 0; int emptySlotNumber = -1; // We use the empty slot number to cache the first empty slot. We chose to reuse slots // create by remove that have the collision bit set over using up new slots. @@ -994,10 +988,8 @@ namespace System.Collections Debug.Assert(!_isWriterInProgress, "Race condition detected in usages of Hashtable - multiple threads appear to be writing to a Hashtable instance simultaneously! Don't do that - use Hashtable.Synchronized."); - uint seed; - uint incr; // Assuming only one concurrent writer, write directly into buckets. - uint hashcode = InitHash(key, _buckets.Length, out seed, out incr); + uint hashcode = InitHash(key, _buckets.Length, out uint seed, out uint incr); int ntry = 0; bucket b; @@ -1116,8 +1108,7 @@ namespace System.Collections return; } - SerializationInfo? siInfo; - HashHelpers.SerializationInfoTable.TryGetValue(this, out siInfo); + HashHelpers.SerializationInfoTable.TryGetValue(this, out SerializationInfo? siInfo); if (siInfo == null) { diff --git a/src/System.Private.CoreLib/shared/System/Convert.cs b/src/System.Private.CoreLib/shared/System/Convert.cs index 50ee261c3..ec6b92a96 100644 --- a/src/System.Private.CoreLib/shared/System/Convert.cs +++ b/src/System.Private.CoreLib/shared/System/Convert.cs @@ -528,11 +528,7 @@ namespace System return (char)value; } - public static char ToChar(int value) - { - if (value < 0 || value > char.MaxValue) ThrowCharOverflowException(); - return (char)value; - } + public static char ToChar(int value) => ToChar((uint)value); [CLSCompliant(false)] public static char ToChar(uint value) @@ -541,11 +537,7 @@ namespace System return (char)value; } - public static char ToChar(long value) - { - if (value < 0 || value > char.MaxValue) ThrowCharOverflowException(); - return (char)value; - } + public static char ToChar(long value) => ToChar((ulong)value); [CLSCompliant(false)] public static char ToChar(ulong value) @@ -667,7 +659,7 @@ namespace System [CLSCompliant(false)] public static sbyte ToSByte(uint value) { - if (value > sbyte.MaxValue) ThrowSByteOverflowException(); + if (value > (uint)sbyte.MaxValue) ThrowSByteOverflowException(); return (sbyte)value; } @@ -708,13 +700,13 @@ namespace System { if (value == null) return 0; - return sbyte.Parse(value, CultureInfo.CurrentCulture); + return sbyte.Parse(value); } [CLSCompliant(false)] public static sbyte ToSByte(string value, IFormatProvider? provider) { - return sbyte.Parse(value, NumberStyles.Integer, provider); + return sbyte.Parse(value, provider); } [CLSCompliant(false)] @@ -757,13 +749,13 @@ namespace System [CLSCompliant(false)] public static byte ToByte(sbyte value) { - if (value < byte.MinValue) ThrowByteOverflowException(); + if (value < 0) ThrowByteOverflowException(); return (byte)value; } public static byte ToByte(short value) { - if (value < byte.MinValue || value > byte.MaxValue) ThrowByteOverflowException(); + if ((uint)value > byte.MaxValue) ThrowByteOverflowException(); return (byte)value; } @@ -774,11 +766,7 @@ namespace System return (byte)value; } - public static byte ToByte(int value) - { - if (value < byte.MinValue || value > byte.MaxValue) ThrowByteOverflowException(); - return (byte)value; - } + public static byte ToByte(int value) => ToByte((uint)value); [CLSCompliant(false)] public static byte ToByte(uint value) @@ -787,11 +775,7 @@ namespace System return (byte)value; } - public static byte ToByte(long value) - { - if (value < byte.MinValue || value > byte.MaxValue) ThrowByteOverflowException(); - return (byte)value; - } + public static byte ToByte(long value) => ToByte((ulong)value); [CLSCompliant(false)] public static byte ToByte(ulong value) @@ -819,14 +803,14 @@ namespace System { if (value == null) return 0; - return byte.Parse(value, CultureInfo.CurrentCulture); + return byte.Parse(value); } public static byte ToByte(string? value, IFormatProvider? provider) { if (value == null) return 0; - return byte.Parse(value, NumberStyles.Integer, provider); + return byte.Parse(value, provider); } public static byte ToByte(DateTime value) @@ -887,7 +871,7 @@ namespace System [CLSCompliant(false)] public static short ToInt16(uint value) { - if (value > short.MaxValue) ThrowInt16OverflowException(); + if (value > (uint)short.MaxValue) ThrowInt16OverflowException(); return (short)value; } @@ -928,14 +912,14 @@ namespace System { if (value == null) return 0; - return short.Parse(value, CultureInfo.CurrentCulture); + return short.Parse(value); } public static short ToInt16(string? value, IFormatProvider? provider) { if (value == null) return 0; - return short.Parse(value, NumberStyles.Integer, provider); + return short.Parse(value, provider); } public static short ToInt16(DateTime value) @@ -993,11 +977,7 @@ namespace System } [CLSCompliant(false)] - public static ushort ToUInt16(int value) - { - if (value < 0 || value > ushort.MaxValue) ThrowUInt16OverflowException(); - return (ushort)value; - } + public static ushort ToUInt16(int value) => ToUInt16((uint)value); [CLSCompliant(false)] public static ushort ToUInt16(ushort value) @@ -1013,11 +993,7 @@ namespace System } [CLSCompliant(false)] - public static ushort ToUInt16(long value) - { - if (value < 0 || value > ushort.MaxValue) ThrowUInt16OverflowException(); - return (ushort)value; - } + public static ushort ToUInt16(long value) => ToUInt16((ulong)value); [CLSCompliant(false)] public static ushort ToUInt16(ulong value) @@ -1049,7 +1025,7 @@ namespace System { if (value == null) return 0; - return ushort.Parse(value, CultureInfo.CurrentCulture); + return ushort.Parse(value); } [CLSCompliant(false)] @@ -1057,7 +1033,7 @@ namespace System { if (value == null) return 0; - return ushort.Parse(value, NumberStyles.Integer, provider); + return ushort.Parse(value, provider); } [CLSCompliant(false)] @@ -1116,7 +1092,7 @@ namespace System [CLSCompliant(false)] public static int ToInt32(uint value) { - if (value > int.MaxValue) ThrowInt32OverflowException(); + if ((int)value < 0) ThrowInt32OverflowException(); return (int)value; } @@ -1177,14 +1153,14 @@ namespace System { if (value == null) return 0; - return int.Parse(value, CultureInfo.CurrentCulture); + return int.Parse(value); } public static int ToInt32(string? value, IFormatProvider? provider) { if (value == null) return 0; - return int.Parse(value, NumberStyles.Integer, provider); + return int.Parse(value, provider); } public static int ToInt32(DateTime value) @@ -1261,11 +1237,7 @@ namespace System } [CLSCompliant(false)] - public static uint ToUInt32(long value) - { - if (value < 0 || value > uint.MaxValue) ThrowUInt32OverflowException(); - return (uint)value; - } + public static uint ToUInt32(long value) => ToUInt32((ulong)value); [CLSCompliant(false)] public static uint ToUInt32(ulong value) @@ -1304,7 +1276,7 @@ namespace System { if (value == null) return 0; - return uint.Parse(value, CultureInfo.CurrentCulture); + return uint.Parse(value); } [CLSCompliant(false)] @@ -1312,7 +1284,7 @@ namespace System { if (value == null) return 0; - return uint.Parse(value, NumberStyles.Integer, provider); + return uint.Parse(value, provider); } [CLSCompliant(false)] @@ -1382,7 +1354,7 @@ namespace System [CLSCompliant(false)] public static long ToInt64(ulong value) { - if (value > long.MaxValue) ThrowInt64OverflowException(); + if ((long)value < 0) ThrowInt64OverflowException(); return (long)value; } @@ -1410,14 +1382,14 @@ namespace System { if (value == null) return 0; - return long.Parse(value, CultureInfo.CurrentCulture); + return long.Parse(value); } public static long ToInt64(string? value, IFormatProvider? provider) { if (value == null) return 0; - return long.Parse(value, NumberStyles.Integer, provider); + return long.Parse(value, provider); } public static long ToInt64(DateTime value) @@ -1529,7 +1501,7 @@ namespace System { if (value == null) return 0; - return ulong.Parse(value, CultureInfo.CurrentCulture); + return ulong.Parse(value); } [CLSCompliant(false)] @@ -1537,7 +1509,7 @@ namespace System { if (value == null) return 0; - return ulong.Parse(value, NumberStyles.Integer, provider); + return ulong.Parse(value, provider); } [CLSCompliant(false)] @@ -1629,14 +1601,14 @@ namespace System { if (value == null) return 0; - return float.Parse(value, CultureInfo.CurrentCulture); + return float.Parse(value); } public static float ToSingle(string? value, IFormatProvider? provider) { if (value == null) return 0; - return float.Parse(value, NumberStyles.Float | NumberStyles.AllowThousands, provider); + return float.Parse(value, provider); } public static float ToSingle(bool value) @@ -1732,14 +1704,14 @@ namespace System { if (value == null) return 0; - return double.Parse(value, CultureInfo.CurrentCulture); + return double.Parse(value); } public static double ToDouble(string? value, IFormatProvider? provider) { if (value == null) return 0; - return double.Parse(value, NumberStyles.Float | NumberStyles.AllowThousands, provider); + return double.Parse(value, provider); } public static double ToDouble(bool value) @@ -1830,14 +1802,14 @@ namespace System { if (value == null) return 0m; - return decimal.Parse(value, CultureInfo.CurrentCulture); + return decimal.Parse(value); } public static decimal ToDecimal(string? value, IFormatProvider? provider) { if (value == null) return 0m; - return decimal.Parse(value, NumberStyles.Number, provider); + return decimal.Parse(value, provider); } public static decimal ToDecimal(decimal value) @@ -1879,7 +1851,7 @@ namespace System { if (value == null) return new DateTime(0); - return DateTime.Parse(value, CultureInfo.CurrentCulture); + return DateTime.Parse(value); } public static DateTime ToDateTime(string? value, IFormatProvider? provider) @@ -2000,7 +1972,7 @@ namespace System [CLSCompliant(false)] public static string ToString(sbyte value) { - return value.ToString(CultureInfo.CurrentCulture); + return value.ToString(); } [CLSCompliant(false)] @@ -2011,7 +1983,7 @@ namespace System public static string ToString(byte value) { - return value.ToString(CultureInfo.CurrentCulture); + return value.ToString(); } public static string ToString(byte value, IFormatProvider? provider) @@ -2021,7 +1993,7 @@ namespace System public static string ToString(short value) { - return value.ToString(CultureInfo.CurrentCulture); + return value.ToString(); } public static string ToString(short value, IFormatProvider? provider) @@ -2032,7 +2004,7 @@ namespace System [CLSCompliant(false)] public static string ToString(ushort value) { - return value.ToString(CultureInfo.CurrentCulture); + return value.ToString(); } [CLSCompliant(false)] @@ -2043,7 +2015,7 @@ namespace System public static string ToString(int value) { - return value.ToString(CultureInfo.CurrentCulture); + return value.ToString(); } public static string ToString(int value, IFormatProvider? provider) @@ -2054,7 +2026,7 @@ namespace System [CLSCompliant(false)] public static string ToString(uint value) { - return value.ToString(CultureInfo.CurrentCulture); + return value.ToString(); } [CLSCompliant(false)] @@ -2065,7 +2037,7 @@ namespace System public static string ToString(long value) { - return value.ToString(CultureInfo.CurrentCulture); + return value.ToString(); } public static string ToString(long value, IFormatProvider? provider) @@ -2076,7 +2048,7 @@ namespace System [CLSCompliant(false)] public static string ToString(ulong value) { - return value.ToString(CultureInfo.CurrentCulture); + return value.ToString(); } [CLSCompliant(false)] @@ -2087,7 +2059,7 @@ namespace System public static string ToString(float value) { - return value.ToString(CultureInfo.CurrentCulture); + return value.ToString(); } public static string ToString(float value, IFormatProvider? provider) @@ -2097,7 +2069,7 @@ namespace System public static string ToString(double value) { - return value.ToString(CultureInfo.CurrentCulture); + return value.ToString(); } public static string ToString(double value, IFormatProvider? provider) @@ -2107,7 +2079,7 @@ namespace System public static string ToString(decimal value) { - return value.ToString(CultureInfo.CurrentCulture); + return value.ToString(); } public static string ToString(decimal value, IFormatProvider? provider) @@ -2157,7 +2129,7 @@ namespace System } int r = ParseNumbers.StringToInt(value.AsSpan(), fromBase, ParseNumbers.IsTight | ParseNumbers.TreatAsUnsigned); - if (r < byte.MinValue || r > byte.MaxValue) + if ((uint)r > byte.MaxValue) ThrowByteOverflowException(); return (byte)r; } @@ -2231,7 +2203,7 @@ namespace System } int r = ParseNumbers.StringToInt(value.AsSpan(), fromBase, ParseNumbers.IsTight | ParseNumbers.TreatAsUnsigned); - if (r < ushort.MinValue || r > ushort.MaxValue) + if ((uint)r > ushort.MaxValue) ThrowUInt16OverflowException(); return (ushort)r; } diff --git a/src/System.Private.CoreLib/shared/System/DateTime.cs b/src/System.Private.CoreLib/shared/System/DateTime.cs index a03da9563..023d79501 100644 --- a/src/System.Private.CoreLib/shared/System/DateTime.cs +++ b/src/System.Private.CoreLib/shared/System/DateTime.cs @@ -3,6 +3,7 @@ // See the LICENSE file in the project root for more information. using System.Diagnostics; +using System.Diagnostics.CodeAnalysis; using System.Globalization; using System.Runtime.InteropServices; using System.Runtime.CompilerServices; @@ -751,8 +752,7 @@ namespace System // Because the ticks conversion between UTC and local is lossy, we need to capture whether the // time is in a repeated hour so that it can be passed to the DateTime constructor. DateTime utcDt = new DateTime(ticks, DateTimeKind.Utc); - bool isDaylightSavings = false; - offsetTicks = TimeZoneInfo.GetUtcOffsetFromUtc(utcDt, TimeZoneInfo.Local, out isDaylightSavings, out isAmbiguousLocalDst).Ticks; + offsetTicks = TimeZoneInfo.GetUtcOffsetFromUtc(utcDt, TimeZoneInfo.Local, out bool isDaylightSavings, out isAmbiguousLocalDst).Ticks; } ticks += offsetTicks; // Another behaviour of parsing is to cause small times to wrap around, so that they can be used @@ -1079,8 +1079,7 @@ namespace System get { DateTime utc = UtcNow; - bool isAmbiguousLocalDst; - long offset = TimeZoneInfo.GetDateTimeNowUtcOffsetFromUtc(utc, out isAmbiguousLocalDst).Ticks; + long offset = TimeZoneInfo.GetDateTimeNowUtcOffsetFromUtc(utc, out bool isAmbiguousLocalDst).Ticks; long tick = utc.Ticks + offset; if (tick > DateTime.MaxTicks) { @@ -1290,9 +1289,7 @@ namespace System { return this; } - bool isDaylightSavings = false; - bool isAmbiguousLocalDst = false; - long offset = TimeZoneInfo.GetUtcOffsetFromUtc(this, TimeZoneInfo.Local, out isDaylightSavings, out isAmbiguousLocalDst).Ticks; + long offset = TimeZoneInfo.GetUtcOffsetFromUtc(this, TimeZoneInfo.Local, out bool isDaylightSavings, out bool isAmbiguousLocalDst).Ticks; long tick = Ticks + offset; if (tick > DateTime.MaxTicks) { @@ -1359,7 +1356,7 @@ namespace System return TimeZoneInfo.ConvertTimeToUtc(this, TimeZoneInfoOptions.NoThrowOnInvalidTime); } - public static bool TryParse(string? s, out DateTime result) + public static bool TryParse([NotNullWhen(true)] string? s, out DateTime result) { if (s == null) { @@ -1374,7 +1371,7 @@ namespace System return DateTimeParse.TryParse(s, DateTimeFormatInfo.CurrentInfo, DateTimeStyles.None, out result); } - public static bool TryParse(string? s, IFormatProvider? provider, DateTimeStyles styles, out DateTime result) + public static bool TryParse([NotNullWhen(true)] string? s, IFormatProvider? provider, DateTimeStyles styles, out DateTime result) { DateTimeFormatInfo.ValidateStyles(styles, nameof(styles)); @@ -1393,7 +1390,7 @@ namespace System return DateTimeParse.TryParse(s, DateTimeFormatInfo.GetInstance(provider), styles, out result); } - public static bool TryParseExact(string? s, string? format, IFormatProvider? provider, DateTimeStyles style, out DateTime result) + public static bool TryParseExact([NotNullWhen(true)] string? s, [NotNullWhen(true)] string? format, IFormatProvider? provider, DateTimeStyles style, out DateTime result) { DateTimeFormatInfo.ValidateStyles(style, nameof(style)); @@ -1412,7 +1409,7 @@ namespace System return DateTimeParse.TryParseExact(s, format, DateTimeFormatInfo.GetInstance(provider), style, out result); } - public static bool TryParseExact(string? s, string?[]? formats, IFormatProvider? provider, DateTimeStyles style, out DateTime result) + public static bool TryParseExact([NotNullWhen(true)] string? s, [NotNullWhen(true)] string?[]? formats, IFormatProvider? provider, DateTimeStyles style, out DateTime result) { DateTimeFormatInfo.ValidateStyles(style, nameof(style)); @@ -1425,7 +1422,7 @@ namespace System return DateTimeParse.TryParseExactMultiple(s, formats, DateTimeFormatInfo.GetInstance(provider), style, out result); } - public static bool TryParseExact(ReadOnlySpan s, string?[]? formats, IFormatProvider? provider, DateTimeStyles style, out DateTime result) + public static bool TryParseExact(ReadOnlySpan s, [NotNullWhen(true)] string?[]? formats, IFormatProvider? provider, DateTimeStyles style, out DateTime result) { DateTimeFormatInfo.ValidateStyles(style, nameof(style)); return DateTimeParse.TryParseExactMultiple(s, formats, DateTimeFormatInfo.GetInstance(provider), style, out result); diff --git a/src/System.Private.CoreLib/shared/System/DateTimeOffset.cs b/src/System.Private.CoreLib/shared/System/DateTimeOffset.cs index 81a061241..45338f361 100644 --- a/src/System.Private.CoreLib/shared/System/DateTimeOffset.cs +++ b/src/System.Private.CoreLib/shared/System/DateTimeOffset.cs @@ -3,6 +3,7 @@ // See the LICENSE file in the project root for more information. using System.Diagnostics; +using System.Diagnostics.CodeAnalysis; using System.Globalization; using System.Runtime.InteropServices; using System.Runtime.Serialization; @@ -479,11 +480,10 @@ namespace System { if (input == null) ThrowHelper.ThrowArgumentNullException(ExceptionArgument.input); - TimeSpan offset; DateTime dateResult = DateTimeParse.Parse(input, DateTimeFormatInfo.CurrentInfo, DateTimeStyles.None, - out offset); + out TimeSpan offset); return new DateTimeOffset(dateResult.Ticks, offset); } @@ -502,11 +502,10 @@ namespace System styles = ValidateStyles(styles, nameof(styles)); if (input == null) ThrowHelper.ThrowArgumentNullException(ExceptionArgument.input); - TimeSpan offset; DateTime dateResult = DateTimeParse.Parse(input, DateTimeFormatInfo.GetInstance(formatProvider), styles, - out offset); + out TimeSpan offset); return new DateTimeOffset(dateResult.Ticks, offset); } @@ -538,12 +537,11 @@ namespace System if (input == null) ThrowHelper.ThrowArgumentNullException(ExceptionArgument.input); if (format == null) ThrowHelper.ThrowArgumentNullException(ExceptionArgument.format); - TimeSpan offset; DateTime dateResult = DateTimeParse.ParseExact(input, format, DateTimeFormatInfo.GetInstance(formatProvider), styles, - out offset); + out TimeSpan offset); return new DateTimeOffset(dateResult.Ticks, offset); } @@ -559,12 +557,11 @@ namespace System styles = ValidateStyles(styles, nameof(styles)); if (input == null) ThrowHelper.ThrowArgumentNullException(ExceptionArgument.input); - TimeSpan offset; DateTime dateResult = DateTimeParse.ParseExactMultiple(input, formats, DateTimeFormatInfo.GetInstance(formatProvider), styles, - out offset); + out TimeSpan offset); return new DateTimeOffset(dateResult.Ticks, offset); } @@ -652,15 +649,13 @@ namespace System public DateTimeOffset ToUniversalTime() => new DateTimeOffset(UtcDateTime); - public static bool TryParse(string? input, out DateTimeOffset result) + public static bool TryParse([NotNullWhen(true)] string? input, out DateTimeOffset result) { - TimeSpan offset; - DateTime dateResult; bool parsed = DateTimeParse.TryParse(input, DateTimeFormatInfo.CurrentInfo, DateTimeStyles.None, - out dateResult, - out offset); + out DateTime dateResult, + out TimeSpan offset); result = new DateTimeOffset(dateResult.Ticks, offset); return parsed; } @@ -672,7 +667,7 @@ namespace System return parsed; } - public static bool TryParse(string? input, IFormatProvider? formatProvider, DateTimeStyles styles, out DateTimeOffset result) + public static bool TryParse([NotNullWhen(true)] string? input, IFormatProvider? formatProvider, DateTimeStyles styles, out DateTimeOffset result) { styles = ValidateStyles(styles, nameof(styles)); if (input == null) @@ -681,13 +676,11 @@ namespace System return false; } - TimeSpan offset; - DateTime dateResult; bool parsed = DateTimeParse.TryParse(input, DateTimeFormatInfo.GetInstance(formatProvider), styles, - out dateResult, - out offset); + out DateTime dateResult, + out TimeSpan offset); result = new DateTimeOffset(dateResult.Ticks, offset); return parsed; } @@ -700,7 +693,7 @@ namespace System return parsed; } - public static bool TryParseExact(string? input, string? format, IFormatProvider? formatProvider, DateTimeStyles styles, + public static bool TryParseExact([NotNullWhen(true)] string? input, [NotNullWhen(true)] string? format, IFormatProvider? formatProvider, DateTimeStyles styles, out DateTimeOffset result) { styles = ValidateStyles(styles, nameof(styles)); @@ -710,14 +703,12 @@ namespace System return false; } - TimeSpan offset; - DateTime dateResult; bool parsed = DateTimeParse.TryParseExact(input, format, DateTimeFormatInfo.GetInstance(formatProvider), styles, - out dateResult, - out offset); + out DateTime dateResult, + out TimeSpan offset); result = new DateTimeOffset(dateResult.Ticks, offset); return parsed; } @@ -731,7 +722,7 @@ namespace System return parsed; } - public static bool TryParseExact(string? input, string?[]? formats, IFormatProvider? formatProvider, DateTimeStyles styles, + public static bool TryParseExact([NotNullWhen(true)] string? input, [NotNullWhen(true)] string?[]? formats, IFormatProvider? formatProvider, DateTimeStyles styles, out DateTimeOffset result) { styles = ValidateStyles(styles, nameof(styles)); @@ -741,20 +732,18 @@ namespace System return false; } - TimeSpan offset; - DateTime dateResult; bool parsed = DateTimeParse.TryParseExactMultiple(input, formats, DateTimeFormatInfo.GetInstance(formatProvider), styles, - out dateResult, - out offset); + out DateTime dateResult, + out TimeSpan offset); result = new DateTimeOffset(dateResult.Ticks, offset); return parsed; } public static bool TryParseExact( - ReadOnlySpan input, string?[]? formats, IFormatProvider? formatProvider, DateTimeStyles styles, out DateTimeOffset result) + ReadOnlySpan input, [NotNullWhen(true)] string?[]? formats, IFormatProvider? formatProvider, DateTimeStyles styles, out DateTimeOffset result) { styles = ValidateStyles(styles, nameof(styles)); bool parsed = DateTimeParse.TryParseExactMultiple(input, formats, DateTimeFormatInfo.GetInstance(formatProvider), styles, out DateTime dateResult, out TimeSpan offset); diff --git a/src/System.Private.CoreLib/shared/System/Decimal.cs b/src/System.Private.CoreLib/shared/System/Decimal.cs index da61628ab..cc32ce562 100644 --- a/src/System.Private.CoreLib/shared/System/Decimal.cs +++ b/src/System.Private.CoreLib/shared/System/Decimal.cs @@ -4,6 +4,7 @@ using System.Buffers.Binary; using System.Diagnostics; +using System.Diagnostics.CodeAnalysis; using System.Globalization; using System.Runtime.CompilerServices; using System.Runtime.InteropServices; @@ -480,7 +481,7 @@ namespace System return Number.ParseDecimal(s, style, NumberFormatInfo.GetInstance(provider)); } - public static bool TryParse(string? s, out decimal result) + public static bool TryParse([NotNullWhen(true)] string? s, out decimal result) { if (s == null) { @@ -496,7 +497,7 @@ namespace System return Number.TryParseDecimal(s, NumberStyles.Number, NumberFormatInfo.CurrentInfo, out result) == Number.ParsingStatus.OK; } - public static bool TryParse(string? s, NumberStyles style, IFormatProvider? provider, out decimal result) + public static bool TryParse([NotNullWhen(true)] string? s, NumberStyles style, IFormatProvider? provider, out decimal result) { NumberFormatInfo.ValidateParseStyleFloatingPoint(style); @@ -936,9 +937,9 @@ namespace System [CLSCompliant(false)] public static explicit operator ulong(decimal value) => ToUInt64(value); - public static explicit operator float(decimal value) => ToSingle(value); + public static explicit operator float(decimal value) => DecCalc.VarR4FromDec(in value); - public static explicit operator double(decimal value) => ToDouble(value); + public static explicit operator double(decimal value) => DecCalc.VarR8FromDec(in value); public static decimal operator +(decimal d) => d; @@ -1051,12 +1052,12 @@ namespace System float IConvertible.ToSingle(IFormatProvider? provider) { - return Convert.ToSingle(this); + return DecCalc.VarR4FromDec(in this); } double IConvertible.ToDouble(IFormatProvider? provider) { - return Convert.ToDouble(this); + return DecCalc.VarR8FromDec(in this); } decimal IConvertible.ToDecimal(IFormatProvider? provider) diff --git a/src/System.Private.CoreLib/shared/System/DefaultBinder.cs b/src/System.Private.CoreLib/shared/System/DefaultBinder.cs index fed9a020f..2f76cbc8a 100644 --- a/src/System.Private.CoreLib/shared/System/DefaultBinder.cs +++ b/src/System.Private.CoreLib/shared/System/DefaultBinder.cs @@ -600,7 +600,6 @@ namespace System { if (newMin == 2) { - currentMin = i; ambig = false; currentMin = i; } diff --git a/src/System.Private.CoreLib/shared/System/Diagnostics/CodeAnalysis/NullableAttributes.cs b/src/System.Private.CoreLib/shared/System/Diagnostics/CodeAnalysis/NullableAttributes.cs index 0b24c01a7..2c4e91c3e 100644 --- a/src/System.Private.CoreLib/shared/System/Diagnostics/CodeAnalysis/NullableAttributes.cs +++ b/src/System.Private.CoreLib/shared/System/Diagnostics/CodeAnalysis/NullableAttributes.cs @@ -125,4 +125,71 @@ namespace System.Diagnostics.CodeAnalysis /// Gets the condition parameter value. public bool ParameterValue { get; } } + + /// Specifies that the method or property will ensure that the listed field and property members have not-null values. + [AttributeUsage(AttributeTargets.Method | AttributeTargets.Property, Inherited = false, AllowMultiple = true)] +#if INTERNAL_NULLABLE_ATTRIBUTES + internal +#else + public +#endif + sealed class MemberNotNullAttribute : Attribute + { + /// Initializes the attribute with a field or property member. + /// + /// The field or property member that is promised to be not-null. + /// + public MemberNotNullAttribute(string member) => Members = new[] { member }; + + /// Initializes the attribute with the list of field and property members. + /// + /// The list of field and property members that are promised to be not-null. + /// + public MemberNotNullAttribute(params string[] members) => Members = members; + + /// Gets field or property member names. + public string[] Members { get; } + } + + /// Specifies that the method or property will ensure that the listed field and property members have not-null values when returning with the specified return value condition. + [AttributeUsage(AttributeTargets.Method | AttributeTargets.Property, Inherited = false, AllowMultiple = true)] +#if INTERNAL_NULLABLE_ATTRIBUTES + internal +#else + public +#endif + sealed class MemberNotNullWhenAttribute : Attribute + { + /// Initializes the attribute with the specified return value condition and a field or property member. + /// + /// The return value condition. If the method returns this value, the associated parameter will not be null. + /// + /// + /// The field or property member that is promised to be not-null. + /// + public MemberNotNullWhenAttribute(bool returnValue, string member) + { + ReturnValue = returnValue; + Members = new[] { member }; + } + + /// Initializes the attribute with the specified return value condition and list of field and property members. + /// + /// The return value condition. If the method returns this value, the associated parameter will not be null. + /// + /// + /// The list of field and property members that are promised to be not-null. + /// + public MemberNotNullWhenAttribute(bool returnValue, params string[] members) + { + ReturnValue = returnValue; + Members = members; + } + + /// Gets the return value condition. + public bool ReturnValue { get; } + + /// Gets field or property member names. + public string[] Members { get; } + } } diff --git a/src/System.Private.CoreLib/shared/System/Diagnostics/DebugProvider.Unix.cs b/src/System.Private.CoreLib/shared/System/Diagnostics/DebugProvider.Unix.cs index 9259c4fbe..2cc40f94e 100644 --- a/src/System.Private.CoreLib/shared/System/Diagnostics/DebugProvider.Unix.cs +++ b/src/System.Private.CoreLib/shared/System/Diagnostics/DebugProvider.Unix.cs @@ -2,8 +2,6 @@ // The .NET Foundation licenses this file to you under the MIT license. // See the LICENSE file in the project root for more information. -using Microsoft.Win32.SafeHandles; - namespace System.Diagnostics { public partial class DebugProvider @@ -56,7 +54,7 @@ namespace System.Diagnostics } else { - Interop.Sys.SysLog(Interop.Sys.SysLogPriority.LOG_USER | Interop.Sys.SysLogPriority.LOG_DEBUG, "%s", message); + Interop.Sys.SysLog(Interop.Sys.SysLogPriority.LOG_DEBUG, "%s", message); } } @@ -89,7 +87,7 @@ namespace System.Diagnostics int totalBytesWritten = 0; while (bufCount > 0) { - int bytesWritten = Interop.Sys.Write(2 /* stderr */, buf + totalBytesWritten, bufCount); + int bytesWritten = Interop.Sys.Write((IntPtr)2 /* stderr */, buf + totalBytesWritten, bufCount); if (bytesWritten < 0) { // On error, simply stop writing the debug output. This could commonly happen if stderr diff --git a/src/System.Private.CoreLib/shared/System/Diagnostics/Tracing/CounterGroup.cs b/src/System.Private.CoreLib/shared/System/Diagnostics/Tracing/CounterGroup.cs index e4086d1d6..987a554f4 100644 --- a/src/System.Private.CoreLib/shared/System/Diagnostics/Tracing/CounterGroup.cs +++ b/src/System.Private.CoreLib/shared/System/Diagnostics/Tracing/CounterGroup.cs @@ -102,8 +102,7 @@ namespace System.Diagnostics.Tracing EnsureEventSourceIndexAvailable(eventSourceIndex); Debug.Assert(s_counterGroups != null); WeakReference weakRef = CounterGroup.s_counterGroups[eventSourceIndex]; - CounterGroup? ret = null; - if (weakRef == null || !weakRef.TryGetTarget(out ret)) + if (weakRef == null || !weakRef.TryGetTarget(out CounterGroup? ret)) { ret = new CounterGroup(eventSource); CounterGroup.s_counterGroups[eventSourceIndex] = new WeakReference(ret); diff --git a/src/System.Private.CoreLib/shared/System/Diagnostics/Tracing/EventPipe.cs b/src/System.Private.CoreLib/shared/System/Diagnostics/Tracing/EventPipe.cs new file mode 100644 index 000000000..308c19ada --- /dev/null +++ b/src/System.Private.CoreLib/shared/System/Diagnostics/Tracing/EventPipe.cs @@ -0,0 +1,277 @@ +// 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.Collections.Generic; +using System.Runtime.InteropServices; +using System.Threading; + +#if FEATURE_PERFTRACING + +namespace System.Diagnostics.Tracing +{ + [StructLayout(LayoutKind.Sequential)] + internal struct EventPipeEventInstanceData + { + internal IntPtr ProviderID; + internal uint EventID; + internal uint ThreadID; + internal long TimeStamp; + internal Guid ActivityId; + internal Guid ChildActivityId; + internal IntPtr Payload; + internal uint PayloadLength; + } + + [StructLayout(LayoutKind.Sequential)] + internal struct EventPipeSessionInfo + { + internal long StartTimeAsUTCFileTime; + internal long StartTimeStamp; + internal long TimeStampFrequency; + } + + [StructLayout(LayoutKind.Sequential)] + internal struct EventPipeProviderConfiguration + { + [MarshalAs(UnmanagedType.LPWStr)] + private readonly string m_providerName; + private readonly ulong m_keywords; + private readonly uint m_loggingLevel; + + [MarshalAs(UnmanagedType.LPWStr)] + private readonly string? m_filterData; + + internal EventPipeProviderConfiguration( + string providerName, + ulong keywords, + uint loggingLevel, + string? filterData) + { + if (string.IsNullOrEmpty(providerName)) + { + throw new ArgumentNullException(nameof(providerName)); + } + if (loggingLevel > 5) // 5 == Verbose, the highest value in EventPipeLoggingLevel. + { + throw new ArgumentOutOfRangeException(nameof(loggingLevel)); + } + m_providerName = providerName; + m_keywords = keywords; + m_loggingLevel = loggingLevel; + m_filterData = filterData; + } + + internal string ProviderName + { + get { return m_providerName; } + } + + internal ulong Keywords + { + get { return m_keywords; } + } + + internal uint LoggingLevel + { + get { return m_loggingLevel; } + } + + internal string? FilterData => m_filterData; + } + + internal enum EventPipeSerializationFormat + { + NetPerf, + NetTrace + } + + internal sealed class EventPipeWaitHandle : WaitHandle + { + } + + internal sealed class EventPipeConfiguration + { + private readonly string m_outputFile; + private readonly EventPipeSerializationFormat m_format; + private readonly uint m_circularBufferSizeInMB; + private readonly List m_providers; + private TimeSpan m_minTimeBetweenSamples = TimeSpan.FromMilliseconds(1); + + internal EventPipeConfiguration( + string outputFile, + EventPipeSerializationFormat format, + uint circularBufferSizeInMB) + { + if (string.IsNullOrEmpty(outputFile)) + { + throw new ArgumentNullException(nameof(outputFile)); + } + if (circularBufferSizeInMB == 0) + { + throw new ArgumentOutOfRangeException(nameof(circularBufferSizeInMB)); + } + m_outputFile = outputFile; + m_format = format; + m_circularBufferSizeInMB = circularBufferSizeInMB; + m_providers = new List(); + } + + internal string OutputFile + { + get { return m_outputFile; } + } + + internal EventPipeSerializationFormat Format + { + get { return m_format; } + } + + internal uint CircularBufferSizeInMB + { + get { return m_circularBufferSizeInMB; } + } + + internal EventPipeProviderConfiguration[] Providers + { + get { return m_providers.ToArray(); } + } + + internal void EnableProvider(string providerName, ulong keywords, uint loggingLevel) + { + EnableProviderWithFilter(providerName, keywords, loggingLevel, null); + } + + internal void EnableProviderWithFilter(string providerName, ulong keywords, uint loggingLevel, string? filterData) + { + m_providers.Add(new EventPipeProviderConfiguration( + providerName, + keywords, + loggingLevel, + filterData)); + } + + private void EnableProviderConfiguration(EventPipeProviderConfiguration providerConfig) + { + m_providers.Add(providerConfig); + } + + internal void EnableProviderRange(EventPipeProviderConfiguration[] providerConfigs) + { + foreach (EventPipeProviderConfiguration config in providerConfigs) + { + EnableProviderConfiguration(config); + } + } + + internal void SetProfilerSamplingRate(TimeSpan minTimeBetweenSamples) + { + if (minTimeBetweenSamples.Ticks <= 0) + { + throw new ArgumentOutOfRangeException(nameof(minTimeBetweenSamples)); + } + + m_minTimeBetweenSamples = minTimeBetweenSamples; + } + } + + internal static class EventPipe + { + private static ulong s_sessionID = 0; + + internal static void Enable(EventPipeConfiguration configuration) + { + if (configuration == null) + { + throw new ArgumentNullException(nameof(configuration)); + } + + if (configuration.Providers == null) + { + throw new ArgumentNullException(nameof(configuration.Providers)); + } + + EventPipeProviderConfiguration[] providers = configuration.Providers; + + s_sessionID = EventPipeInternal.Enable( + configuration.OutputFile, + configuration.Format, + configuration.CircularBufferSizeInMB, + providers); + } + + internal static void Disable() + { + EventPipeInternal.Disable(s_sessionID); + } + } + + internal static partial class EventPipeInternal + { + private unsafe struct EventPipeProviderConfigurationNative + { + private char* m_pProviderName; + private ulong m_keywords; + private uint m_loggingLevel; + private char* m_pFilterData; + + internal static void MarshalToNative(EventPipeProviderConfiguration managed, ref EventPipeProviderConfigurationNative native) + { + native.m_pProviderName = (char*)Marshal.StringToCoTaskMemUni(managed.ProviderName); + native.m_keywords = managed.Keywords; + native.m_loggingLevel = managed.LoggingLevel; + native.m_pFilterData = (char*)Marshal.StringToCoTaskMemUni(managed.FilterData); + } + + internal void Release() + { + if (m_pProviderName != null) + { + Marshal.FreeCoTaskMem((IntPtr)m_pProviderName); + } + if (m_pFilterData != null) + { + Marshal.FreeCoTaskMem((IntPtr)m_pFilterData); + } + } + } + + internal static unsafe ulong Enable( + string? outputFile, + EventPipeSerializationFormat format, + uint circularBufferSizeInMB, + EventPipeProviderConfiguration[] providers) + { + Span providersNative = new Span((void*)Marshal.AllocCoTaskMem(sizeof(EventPipeProviderConfigurationNative) * providers.Length), providers.Length); + providersNative.Clear(); + + try + { + for (int i = 0; i < providers.Length; i++) + { + EventPipeProviderConfigurationNative.MarshalToNative(providers[i], ref providersNative[i]); + } + + fixed (char* outputFilePath = outputFile) + fixed (EventPipeProviderConfigurationNative* providersNativePointer = providersNative) + { + return Enable(outputFilePath, format, circularBufferSizeInMB, providersNativePointer, (uint)providersNative.Length); + } + } + finally + { + for (int i = 0; i < providers.Length; i++) + { + providersNative[i].Release(); + } + + fixed (EventPipeProviderConfigurationNative* providersNativePointer = providersNative) + { + Marshal.FreeCoTaskMem((IntPtr)providersNativePointer); + } + } + } + } +} + +#endif // FEATURE_PERFTRACING diff --git a/src/System.Private.CoreLib/shared/System/Diagnostics/Tracing/EventPipeEventDispatcher.cs b/src/System.Private.CoreLib/shared/System/Diagnostics/Tracing/EventPipeEventDispatcher.cs new file mode 100644 index 000000000..f2d9b30bf --- /dev/null +++ b/src/System.Private.CoreLib/shared/System/Diagnostics/Tracing/EventPipeEventDispatcher.cs @@ -0,0 +1,226 @@ +// 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.Collections.Generic; +using System.Threading; +using System.Threading.Tasks; +using Microsoft.Win32.SafeHandles; + +namespace System.Diagnostics.Tracing +{ +#if FEATURE_PERFTRACING + internal sealed class EventPipeEventDispatcher + { + internal sealed class EventListenerSubscription + { + internal EventKeywords MatchAnyKeywords { get; private set; } + internal EventLevel Level { get; private set; } + + internal EventListenerSubscription(EventKeywords matchAnyKeywords, EventLevel level) + { + MatchAnyKeywords = matchAnyKeywords; + Level = level; + } + } + + internal static readonly EventPipeEventDispatcher Instance = new EventPipeEventDispatcher(); + + private readonly IntPtr m_RuntimeProviderID; + + private ulong m_sessionID = 0; + private DateTime m_syncTimeUtc; + private long m_syncTimeQPC; + private long m_timeQPCFrequency; + + private bool m_stopDispatchTask; + private readonly EventPipeWaitHandle m_dispatchTaskWaitHandle = new EventPipeWaitHandle(); + private Task? m_dispatchTask = null; + private readonly object m_dispatchControlLock = new object(); + private readonly Dictionary m_subscriptions = new Dictionary(); + + private const uint DefaultEventListenerCircularMBSize = 10; + + private EventPipeEventDispatcher() + { + // Get the ID of the runtime provider so that it can be used as a filter when processing events. + m_RuntimeProviderID = EventPipeInternal.GetProvider(NativeRuntimeEventSource.EventSourceName); + m_dispatchTaskWaitHandle.SafeWaitHandle = new SafeWaitHandle(IntPtr.Zero, false); + } + + internal void SendCommand(EventListener eventListener, EventCommand command, bool enable, EventLevel level, EventKeywords matchAnyKeywords) + { + if (command == EventCommand.Update && enable) + { + lock (m_dispatchControlLock) + { + // Add the new subscription. This will overwrite an existing subscription for the listener if one exists. + m_subscriptions[eventListener] = new EventListenerSubscription(matchAnyKeywords, level); + + // Commit the configuration change. + CommitDispatchConfiguration(); + } + } + else if (command == EventCommand.Update && !enable) + { + RemoveEventListener(eventListener); + } + } + + internal void RemoveEventListener(EventListener listener) + { + lock (m_dispatchControlLock) + { + // Remove the event listener from the list of subscribers. + if (m_subscriptions.ContainsKey(listener)) + { + m_subscriptions.Remove(listener); + } + + // Commit the configuration change. + CommitDispatchConfiguration(); + } + } + + private void CommitDispatchConfiguration() + { + Debug.Assert(Monitor.IsEntered(m_dispatchControlLock)); + + // Ensure that the dispatch task is stopped. + // This is a no-op if the task is already stopped. + StopDispatchTask(); + + // Stop tracing. + // This is a no-op if it's already disabled. + EventPipeInternal.Disable(m_sessionID); + + // Check to see if tracing should be enabled. + if (m_subscriptions.Count <= 0) + { + return; + } + + // Determine the keywords and level that should be used based on the set of enabled EventListeners. + EventKeywords aggregatedKeywords = EventKeywords.None; + EventLevel highestLevel = EventLevel.LogAlways; + + foreach (EventListenerSubscription subscription in m_subscriptions.Values) + { + aggregatedKeywords |= subscription.MatchAnyKeywords; + highestLevel = (subscription.Level > highestLevel) ? subscription.Level : highestLevel; + } + + // Enable the EventPipe session. + EventPipeProviderConfiguration[] providerConfiguration = new EventPipeProviderConfiguration[] + { + new EventPipeProviderConfiguration(NativeRuntimeEventSource.EventSourceName, (ulong)aggregatedKeywords, (uint)highestLevel, null) + }; + + m_sessionID = EventPipeInternal.Enable(null, EventPipeSerializationFormat.NetTrace, DefaultEventListenerCircularMBSize, providerConfiguration); + Debug.Assert(m_sessionID != 0); + + // Get the session information that is required to properly dispatch events. + EventPipeSessionInfo sessionInfo; + unsafe + { + if (!EventPipeInternal.GetSessionInfo(m_sessionID, &sessionInfo)) + { + Debug.Fail("GetSessionInfo returned false."); + } + } + + m_syncTimeUtc = DateTime.FromFileTimeUtc(sessionInfo.StartTimeAsUTCFileTime); + m_syncTimeQPC = sessionInfo.StartTimeStamp; + m_timeQPCFrequency = sessionInfo.TimeStampFrequency; + + // Start the dispatch task. + StartDispatchTask(); + } + + private void StartDispatchTask() + { + Debug.Assert(Monitor.IsEntered(m_dispatchControlLock)); + + if (m_dispatchTask == null) + { + m_stopDispatchTask = false; + // Create a SafeWaitHandle that won't release the handle when done + m_dispatchTaskWaitHandle.SafeWaitHandle = new SafeWaitHandle(EventPipeInternal.GetWaitHandle(m_sessionID), false); + + m_dispatchTask = Task.Factory.StartNew(DispatchEventsToEventListeners, CancellationToken.None, TaskCreationOptions.LongRunning, TaskScheduler.Default); + } + } + + private void StopDispatchTask() + { + Debug.Assert(Monitor.IsEntered(m_dispatchControlLock)); + + if (m_dispatchTask != null) + { + m_stopDispatchTask = true; + Debug.Assert(!m_dispatchTaskWaitHandle.SafeWaitHandle.IsInvalid); + EventWaitHandle.Set(m_dispatchTaskWaitHandle.SafeWaitHandle); + m_dispatchTask.Wait(); + m_dispatchTask = null; + } + } + + private unsafe void DispatchEventsToEventListeners() + { + // Struct to fill with the call to GetNextEvent. + EventPipeEventInstanceData instanceData; + + while (!m_stopDispatchTask) + { + bool eventsReceived = false; + // Get the next event. + while (!m_stopDispatchTask && EventPipeInternal.GetNextEvent(m_sessionID, &instanceData)) + { + eventsReceived = true; + + // Filter based on provider. + if (instanceData.ProviderID == m_RuntimeProviderID) + { + // Dispatch the event. + ReadOnlySpan payload = new ReadOnlySpan((void*)instanceData.Payload, (int)instanceData.PayloadLength); + DateTime dateTimeStamp = TimeStampToDateTime(instanceData.TimeStamp); + NativeRuntimeEventSource.Log.ProcessEvent(instanceData.EventID, instanceData.ThreadID, dateTimeStamp, instanceData.ActivityId, instanceData.ChildActivityId, payload); + } + } + + // Wait for more events. + if (!m_stopDispatchTask) + { + if (!eventsReceived) + { + // Future TODO: this would make more sense to handle in EventPipeSession/EventPipe native code. + Debug.Assert(!m_dispatchTaskWaitHandle.SafeWaitHandle.IsInvalid); + m_dispatchTaskWaitHandle.WaitOne(); + } + + Thread.Sleep(10); + } + } + } + + /// + /// Converts a QueryPerformanceCounter (QPC) timestamp to a UTC DateTime. + /// + private DateTime TimeStampToDateTime(long timeStamp) + { + if (timeStamp == long.MaxValue) + { + return DateTime.MaxValue; + } + + Debug.Assert((m_syncTimeUtc.Ticks != 0) && (m_syncTimeQPC != 0) && (m_timeQPCFrequency != 0)); + long inTicks = (long)((timeStamp - m_syncTimeQPC) * 10000000.0 / m_timeQPCFrequency) + m_syncTimeUtc.Ticks; + if ((inTicks < 0) || (DateTime.MaxTicks < inTicks)) + { + inTicks = DateTime.MaxTicks; + } + + return new DateTime(inTicks, DateTimeKind.Utc); + } + } +#endif // FEATURE_PERFTRACING +} diff --git a/src/System.Private.CoreLib/shared/System/Diagnostics/Tracing/EventPipeEventProvider.cs b/src/System.Private.CoreLib/shared/System/Diagnostics/Tracing/EventPipeEventProvider.cs new file mode 100644 index 000000000..34a7b861e --- /dev/null +++ b/src/System.Private.CoreLib/shared/System/Diagnostics/Tracing/EventPipeEventProvider.cs @@ -0,0 +1,89 @@ +// 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.Diagnostics.Tracing +{ + internal sealed class EventPipeEventProvider : IEventProvider + { + // The EventPipeProvider handle. + private IntPtr m_provHandle = IntPtr.Zero; + + // Register an event provider. + unsafe uint IEventProvider.EventRegister( + EventSource eventSource, + Interop.Advapi32.EtwEnableCallback enableCallback, + void* callbackContext, + ref long registrationHandle) + { + uint returnStatus = 0; + m_provHandle = EventPipeInternal.CreateProvider(eventSource.Name, enableCallback); + if (m_provHandle != IntPtr.Zero) + { + // Fixed registration handle because a new EventPipeEventProvider + // will be created for each new EventSource. + registrationHandle = 1; + } + else + { + // Unable to create the provider. + returnStatus = 1; + } + + return returnStatus; + } + + // Unregister an event provider. + uint IEventProvider.EventUnregister(long registrationHandle) + { + EventPipeInternal.DeleteProvider(m_provHandle); + return 0; + } + + // Write an event. + unsafe EventProvider.WriteEventErrorCode IEventProvider.EventWriteTransfer( + long registrationHandle, + in EventDescriptor eventDescriptor, + IntPtr eventHandle, + Guid* activityId, + Guid* relatedActivityId, + int userDataCount, + EventProvider.EventData* userData) + { + if (eventHandle != IntPtr.Zero) + { + if (userDataCount == 0) + { + EventPipeInternal.WriteEventData(eventHandle, null, 0, activityId, relatedActivityId); + return EventProvider.WriteEventErrorCode.NoError; + } + + // If Channel == 11, this is a TraceLogging event. + // The first 3 descriptors contain event metadata that is emitted for ETW and should be discarded on EventPipe. + // EventPipe metadata is provided via the EventPipeEventProvider.DefineEventHandle. + if (eventDescriptor.Channel == 11) + { + userData += 3; + userDataCount -= 3; + Debug.Assert(userDataCount >= 0); + } + EventPipeInternal.WriteEventData(eventHandle, userData, (uint)userDataCount, activityId, relatedActivityId); + } + + return EventProvider.WriteEventErrorCode.NoError; + } + + // Get or set the per-thread activity ID. + int IEventProvider.EventActivityIdControl(Interop.Advapi32.ActivityControl ControlCode, ref Guid ActivityId) + { + return EventPipeInternal.EventActivityIdControl((uint)ControlCode, ref ActivityId); + } + + // Define an EventPipeEvent handle. + unsafe IntPtr IEventProvider.DefineEventHandle(uint eventID, string eventName, long keywords, uint eventVersion, uint level, byte* pMetadata, uint metadataLength) + { + IntPtr eventHandlePtr = EventPipeInternal.DefineEvent(m_provHandle, eventID, keywords, eventVersion, level, pMetadata, metadataLength); + return eventHandlePtr; + } + } +} diff --git a/src/System.Private.CoreLib/shared/System/Diagnostics/Tracing/EventPipeMetadataGenerator.cs b/src/System.Private.CoreLib/shared/System/Diagnostics/Tracing/EventPipeMetadataGenerator.cs new file mode 100644 index 000000000..fd81d0596 --- /dev/null +++ b/src/System.Private.CoreLib/shared/System/Diagnostics/Tracing/EventPipeMetadataGenerator.cs @@ -0,0 +1,412 @@ +// 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.Reflection; +using EventMetadata = System.Diagnostics.Tracing.EventSource.EventMetadata; + +namespace System.Diagnostics.Tracing +{ +#if FEATURE_PERFTRACING + internal sealed class EventPipeMetadataGenerator + { + public static EventPipeMetadataGenerator Instance = new EventPipeMetadataGenerator(); + + private EventPipeMetadataGenerator() { } + + public byte[]? GenerateEventMetadata(EventMetadata eventMetadata) + { + ParameterInfo[] parameters = eventMetadata.Parameters; + EventParameterInfo[] eventParams = new EventParameterInfo[parameters.Length]; + for (int i = 0; i < parameters.Length; i++) + { + eventParams[i].SetInfo(parameters[i].Name!, parameters[i].ParameterType); + } + + return GenerateMetadata( + eventMetadata.Descriptor.EventId, + eventMetadata.Name, + eventMetadata.Descriptor.Keywords, + eventMetadata.Descriptor.Level, + eventMetadata.Descriptor.Version, + eventParams); + } + + public byte[]? GenerateEventMetadata( + int eventId, + string eventName, + EventKeywords keywords, + EventLevel level, + uint version, + TraceLoggingEventTypes eventTypes) + { + TraceLoggingTypeInfo[] typeInfos = eventTypes.typeInfos; + string[]? paramNames = eventTypes.paramNames; + EventParameterInfo[] eventParams = new EventParameterInfo[typeInfos.Length]; + for (int i = 0; i < typeInfos.Length; i++) + { + string paramName = string.Empty; + if (paramNames != null) + { + paramName = paramNames[i]; + } + eventParams[i].SetInfo(paramName, typeInfos[i].DataType, typeInfos[i]); + } + + return GenerateMetadata(eventId, eventName, (long)keywords, (uint)level, version, eventParams); + } + + internal unsafe byte[]? GenerateMetadata( + int eventId, + string eventName, + long keywords, + uint level, + uint version, + EventParameterInfo[] parameters) + { + byte[]? metadata = null; + try + { + // eventID : 4 bytes + // eventName : (eventName.Length + 1) * 2 bytes + // keywords : 8 bytes + // eventVersion : 4 bytes + // level : 4 bytes + // parameterCount : 4 bytes + uint metadataLength = 24 + ((uint)eventName.Length + 1) * 2; + uint defaultMetadataLength = metadataLength; + + // Check for an empty payload. + // Write calls with no arguments by convention have a parameter of + // type NullTypeInfo which is serialized as nothing. + if ((parameters.Length == 1) && (parameters[0].ParameterType == typeof(EmptyStruct))) + { + parameters = Array.Empty(); + } + + // Increase the metadataLength for parameters. + foreach (EventParameterInfo parameter in parameters) + { + int pMetadataLength = parameter.GetMetadataLength(); + // The call above may return -1 which means we failed to get the metadata length. + // We then return a default metadata blob (with parameterCount of 0) to prevent it from generating malformed metadata. + if (pMetadataLength < 0) + { + parameters = Array.Empty(); + metadataLength = defaultMetadataLength; + break; + } + metadataLength += (uint)pMetadataLength; + } + + metadata = new byte[metadataLength]; + + // Write metadata: eventID, eventName, keywords, eventVersion, level, parameterCount, param1 type, param1 name... + fixed (byte* pMetadata = metadata) + { + uint offset = 0; + WriteToBuffer(pMetadata, metadataLength, ref offset, (uint)eventId); + fixed (char* pEventName = eventName) + { + WriteToBuffer(pMetadata, metadataLength, ref offset, (byte*)pEventName, ((uint)eventName.Length + 1) * 2); + } + WriteToBuffer(pMetadata, metadataLength, ref offset, keywords); + WriteToBuffer(pMetadata, metadataLength, ref offset, version); + WriteToBuffer(pMetadata, metadataLength, ref offset, level); + WriteToBuffer(pMetadata, metadataLength, ref offset, (uint)parameters.Length); + foreach (EventParameterInfo parameter in parameters) + { + if (!parameter.GenerateMetadata(pMetadata, ref offset, metadataLength)) + { + // If we fail to generate metadata for any parameter, we should return the "default" metadata without any parameters + return GenerateMetadata(eventId, eventName, keywords, level, version, Array.Empty()); + } + } + Debug.Assert(metadataLength == offset); + } + } + catch + { + // If a failure occurs during metadata generation, make sure that we don't return + // malformed metadata. Instead, return a null metadata blob. + // Consumers can either build in knowledge of the event or skip it entirely. + metadata = null; + } + + return metadata; + } + + // Copy src to buffer and modify the offset. + // Note: We know the buffer size ahead of time to make sure no buffer overflow. + internal static unsafe void WriteToBuffer(byte* buffer, uint bufferLength, ref uint offset, byte* src, uint srcLength) + { + Debug.Assert(bufferLength >= (offset + srcLength)); + for (int i = 0; i < srcLength; i++) + { + *(byte*)(buffer + offset + i) = *(byte*)(src + i); + } + offset += srcLength; + } + + // Copy uint value to buffer. + internal static unsafe void WriteToBuffer(byte* buffer, uint bufferLength, ref uint offset, uint value) + { + Debug.Assert(bufferLength >= (offset + 4)); + *(uint*)(buffer + offset) = value; + offset += 4; + } + + // Copy long value to buffer. + internal static unsafe void WriteToBuffer(byte* buffer, uint bufferLength, ref uint offset, long value) + { + Debug.Assert(bufferLength >= (offset + 8)); + *(long*)(buffer + offset) = value; + offset += 8; + } + + // Copy char value to buffer. + internal static unsafe void WriteToBuffer(byte* buffer, uint bufferLength, ref uint offset, char value) + { + Debug.Assert(bufferLength >= (offset + 2)); + *(char*)(buffer + offset) = value; + offset += 2; + } + } + + internal struct EventParameterInfo + { + internal string ParameterName; + internal Type ParameterType; + internal TraceLoggingTypeInfo? TypeInfo; + + internal void SetInfo(string name, Type type, TraceLoggingTypeInfo? typeInfo = null) + { + ParameterName = name; + ParameterType = type; + TypeInfo = typeInfo; + } + + internal unsafe bool GenerateMetadata(byte* pMetadataBlob, ref uint offset, uint blobSize) + { + TypeCode typeCode = GetTypeCodeExtended(ParameterType); + if (typeCode == TypeCode.Object) + { + // Each nested struct is serialized as: + // TypeCode.Object : 4 bytes + // Number of properties : 4 bytes + // Property description 0...N + // Nested struct property name : NULL-terminated string. + EventPipeMetadataGenerator.WriteToBuffer(pMetadataBlob, blobSize, ref offset, (uint)TypeCode.Object); + + if (!(TypeInfo is InvokeTypeInfo invokeTypeInfo)) + { + return false; + } + + // Get the set of properties to be serialized. + PropertyAnalysis[]? properties = invokeTypeInfo.properties; + if (properties != null) + { + // Write the count of serializable properties. + EventPipeMetadataGenerator.WriteToBuffer(pMetadataBlob, blobSize, ref offset, (uint)properties.Length); + + foreach (PropertyAnalysis prop in properties) + { + if (!GenerateMetadataForProperty(prop, pMetadataBlob, ref offset, blobSize)) + { + return false; + } + } + } + else + { + // This struct has zero serializable properties so we just write the property count. + EventPipeMetadataGenerator.WriteToBuffer(pMetadataBlob, blobSize, ref offset, (uint)0); + } + + // Top-level structs don't have a property name, but for simplicity we write a NULL-char to represent the name. + EventPipeMetadataGenerator.WriteToBuffer(pMetadataBlob, blobSize, ref offset, '\0'); + } + else + { + // Write parameter type. + EventPipeMetadataGenerator.WriteToBuffer(pMetadataBlob, blobSize, ref offset, (uint)typeCode); + + // Write parameter name. + fixed (char* pParameterName = ParameterName) + { + EventPipeMetadataGenerator.WriteToBuffer(pMetadataBlob, blobSize, ref offset, (byte*)pParameterName, ((uint)ParameterName.Length + 1) * 2); + } + } + return true; + } + + private static unsafe bool GenerateMetadataForProperty(PropertyAnalysis property, byte* pMetadataBlob, ref uint offset, uint blobSize) + { + Debug.Assert(property != null); + Debug.Assert(pMetadataBlob != null); + + // Check if this property is a nested struct. + if (property.typeInfo is InvokeTypeInfo invokeTypeInfo) + { + // Each nested struct is serialized as: + // TypeCode.Object : 4 bytes + // Number of properties : 4 bytes + // Property description 0...N + // Nested struct property name : NULL-terminated string. + EventPipeMetadataGenerator.WriteToBuffer(pMetadataBlob, blobSize, ref offset, (uint)TypeCode.Object); + + // Get the set of properties to be serialized. + PropertyAnalysis[]? properties = invokeTypeInfo.properties; + if (properties != null) + { + // Write the count of serializable properties. + EventPipeMetadataGenerator.WriteToBuffer(pMetadataBlob, blobSize, ref offset, (uint)properties.Length); + + foreach (PropertyAnalysis prop in properties) + { + if (!GenerateMetadataForProperty(prop, pMetadataBlob, ref offset, blobSize)) + { + return false; + } + } + } + else + { + // This struct has zero serializable properties so we just write the property count. + EventPipeMetadataGenerator.WriteToBuffer(pMetadataBlob, blobSize, ref offset, (uint)0); + } + + // Write the property name. + fixed (char* pPropertyName = property.name) + { + EventPipeMetadataGenerator.WriteToBuffer(pMetadataBlob, blobSize, ref offset, (byte*)pPropertyName, ((uint)property.name.Length + 1) * 2); + } + } + else + { + // Each primitive type is serialized as: + // TypeCode : 4 bytes + // PropertyName : NULL-terminated string + TypeCode typeCode = GetTypeCodeExtended(property.typeInfo.DataType); + + // EventPipe does not support this type. Throw, which will cause no metadata to be registered for this event. + if (typeCode == TypeCode.Object) + { + return false; + } + + // Write the type code. + EventPipeMetadataGenerator.WriteToBuffer(pMetadataBlob, blobSize, ref offset, (uint)typeCode); + + // Write the property name. + fixed (char* pPropertyName = property.name) + { + EventPipeMetadataGenerator.WriteToBuffer(pMetadataBlob, blobSize, ref offset, (byte*)pPropertyName, ((uint)property.name.Length + 1) * 2); + } + } + return true; + } + + internal int GetMetadataLength() + { + int ret = 0; + + TypeCode typeCode = GetTypeCodeExtended(ParameterType); + if (typeCode == TypeCode.Object) + { + if (!(TypeInfo is InvokeTypeInfo typeInfo)) + { + return -1; + } + + // Each nested struct is serialized as: + // TypeCode.Object : 4 bytes + // Number of properties : 4 bytes + // Property description 0...N + // Nested struct property name : NULL-terminated string. + ret += sizeof(uint) // TypeCode + + sizeof(uint); // Property count + + // Get the set of properties to be serialized. + PropertyAnalysis[]? properties = typeInfo.properties; + if (properties != null) + { + foreach (PropertyAnalysis prop in properties) + { + ret += (int)GetMetadataLengthForProperty(prop); + } + } + + // For simplicity when writing a reader, we write a NULL char + // after the metadata for a top-level struct (for its name) so that + // readers don't have do special case the outer-most struct. + ret += sizeof(char); + } + else + { + ret += (int)(sizeof(uint) + ((ParameterName.Length + 1) * 2)); + } + + return ret; + } + + private static uint GetMetadataLengthForProperty(PropertyAnalysis property) + { + Debug.Assert(property != null); + + uint ret = 0; + + // Check if this property is a nested struct. + if (property.typeInfo is InvokeTypeInfo invokeTypeInfo) + { + // Each nested struct is serialized as: + // TypeCode.Object : 4 bytes + // Number of properties : 4 bytes + // Property description 0...N + // Nested struct property name : NULL-terminated string. + ret += sizeof(uint) // TypeCode + + sizeof(uint); // Property count + + // Get the set of properties to be serialized. + PropertyAnalysis[]? properties = invokeTypeInfo.properties; + if (properties != null) + { + foreach (PropertyAnalysis prop in properties) + { + ret += GetMetadataLengthForProperty(prop); + } + } + + // Add the size of the property name. + ret += (uint)((property.name.Length + 1) * 2); + } + else + { + ret += (uint)(sizeof(uint) + ((property.name.Length + 1) * 2)); + } + + return ret; + } + + private static TypeCode GetTypeCodeExtended(Type parameterType) + { + // Guid is not part of TypeCode, we decided to use 17 to represent it, as it's the "free slot" + // see https://github.com/dotnet/coreclr/issues/16105#issuecomment-361749750 for more + const TypeCode GuidTypeCode = (TypeCode)17; + + if (parameterType == typeof(Guid)) // Guid is not a part of TypeCode enum + return GuidTypeCode; + + // IntPtr and UIntPtr are converted to their non-pointer types. + if (parameterType == typeof(IntPtr)) + return IntPtr.Size == 4 ? TypeCode.Int32 : TypeCode.Int64; + + if (parameterType == typeof(UIntPtr)) + return UIntPtr.Size == 4 ? TypeCode.UInt32 : TypeCode.UInt64; + + return Type.GetTypeCode(parameterType); + } + } + +#endif // FEATURE_PERFTRACING +} diff --git a/src/System.Private.CoreLib/shared/System/Diagnostics/Tracing/EventPipePayloadDecoder.cs b/src/System.Private.CoreLib/shared/System/Diagnostics/Tracing/EventPipePayloadDecoder.cs new file mode 100644 index 000000000..6d5441832 --- /dev/null +++ b/src/System.Private.CoreLib/shared/System/Diagnostics/Tracing/EventPipePayloadDecoder.cs @@ -0,0 +1,149 @@ +// 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.Buffers.Binary; +using System.Reflection; +using System.Runtime.InteropServices; +using System.Text; + +namespace System.Diagnostics.Tracing +{ +#if FEATURE_PERFTRACING + internal static class EventPipePayloadDecoder + { + /// + /// Given the metadata for an event and an event payload, decode and deserialize the event payload. + /// + internal static object[] DecodePayload(ref EventSource.EventMetadata metadata, ReadOnlySpan payload) + { + ParameterInfo[] parameters = metadata.Parameters; + object[] decodedFields = new object[parameters.Length]; + for (int i = 0; i < parameters.Length; i++) + { + // It is possible that an older version of the event was emitted. + // If this happens, the payload might be missing arguments at the end. + // We can just leave these unset. + if (payload.Length <= 0) + { + break; + } + + Type parameterType = parameters[i].ParameterType; + if (parameterType == typeof(IntPtr)) + { + if (IntPtr.Size == 8) + { + decodedFields[i] = (IntPtr)BinaryPrimitives.ReadInt64LittleEndian(payload); + } + else + { + decodedFields[i] = (IntPtr)BinaryPrimitives.ReadInt32LittleEndian(payload); + } + payload = payload.Slice(IntPtr.Size); + } + else if (parameterType == typeof(int)) + { + decodedFields[i] = BinaryPrimitives.ReadInt32LittleEndian(payload); + payload = payload.Slice(sizeof(int)); + } + else if (parameterType == typeof(uint)) + { + decodedFields[i] = BinaryPrimitives.ReadUInt32LittleEndian(payload); + payload = payload.Slice(sizeof(uint)); + } + else if (parameterType == typeof(long)) + { + decodedFields[i] = BinaryPrimitives.ReadInt64LittleEndian(payload); + payload = payload.Slice(sizeof(long)); + } + else if (parameterType == typeof(ulong)) + { + decodedFields[i] = BinaryPrimitives.ReadUInt64LittleEndian(payload); + payload = payload.Slice(sizeof(ulong)); + } + else if (parameterType == typeof(byte)) + { + decodedFields[i] = MemoryMarshal.Read(payload); + payload = payload.Slice(sizeof(byte)); + } + else if (parameterType == typeof(sbyte)) + { + decodedFields[i] = MemoryMarshal.Read(payload); + payload = payload.Slice(sizeof(sbyte)); + } + else if (parameterType == typeof(short)) + { + decodedFields[i] = BinaryPrimitives.ReadInt16LittleEndian(payload); + payload = payload.Slice(sizeof(short)); + } + else if (parameterType == typeof(ushort)) + { + decodedFields[i] = BinaryPrimitives.ReadUInt16LittleEndian(payload); + payload = payload.Slice(sizeof(ushort)); + } + else if (parameterType == typeof(float)) + { + decodedFields[i] = BitConverter.Int32BitsToSingle(BinaryPrimitives.ReadInt32LittleEndian(payload)); + payload = payload.Slice(sizeof(float)); + } + else if (parameterType == typeof(double)) + { + decodedFields[i] = BitConverter.Int64BitsToDouble(BinaryPrimitives.ReadInt64LittleEndian(payload)); + payload = payload.Slice(sizeof(double)); + } + else if (parameterType == typeof(bool)) + { + // The manifest defines a bool as a 32bit type (WIN32 BOOL), not 1 bit as CLR Does. + decodedFields[i] = (BinaryPrimitives.ReadInt32LittleEndian(payload) == 1); + payload = payload.Slice(sizeof(int)); + } + else if (parameterType == typeof(Guid)) + { + const int sizeOfGuid = 16; + decodedFields[i] = new Guid(payload.Slice(0, sizeOfGuid)); + payload = payload.Slice(sizeOfGuid); + } + else if (parameterType == typeof(char)) + { + decodedFields[i] = (char)BinaryPrimitives.ReadUInt16LittleEndian(payload); + payload = payload.Slice(sizeof(char)); + } + else if (parameterType == typeof(string)) + { + // Try to find null terminator (0x00) from the byte span + // NOTE: we do this by hand instead of using IndexOf because payload may be unaligned due to + // mixture of different types being stored in the same buffer. (see eventpipe.cpp:CopyData) + int byteCount = -1; + for (int j = 1; j < payload.Length; j += 2) + { + if (payload[j - 1] == (byte)(0) && payload[j] == (byte)(0)) + { + byteCount = j + 1; + break; + } + } + + ReadOnlySpan charPayload; + if (byteCount < 0) + { + charPayload = MemoryMarshal.Cast(payload); + payload = default; + } + else + { + charPayload = MemoryMarshal.Cast(payload.Slice(0, byteCount - 2)); + payload = payload.Slice(byteCount); + } + decodedFields[i] = BitConverter.IsLittleEndian ? new string(charPayload) : Encoding.Unicode.GetString(MemoryMarshal.Cast(charPayload)); + } + else + { + Debug.Fail("Unsupported type encountered."); + } + } + + return decodedFields; + } + } +#endif // FEATURE_PERFTRACING +} diff --git a/src/System.Private.CoreLib/shared/System/Diagnostics/Tracing/EventProvider.cs b/src/System.Private.CoreLib/shared/System/Diagnostics/Tracing/EventProvider.cs index b0ed1c98c..fd0bd6eab 100644 --- a/src/System.Private.CoreLib/shared/System/Diagnostics/Tracing/EventProvider.cs +++ b/src/System.Private.CoreLib/shared/System/Diagnostics/Tracing/EventProvider.cs @@ -13,7 +13,7 @@ using System.Collections.Generic; using System.Globalization; using System.Numerics; using System.Runtime.InteropServices; -#if CORECLR && TARGET_WINDOWS +#if (CORECLR || MONO) && TARGET_WINDOWS using Internal.Win32; #endif #if ES_BUILD_AGAINST_DOTNET_V35 @@ -288,10 +288,8 @@ namespace System.Diagnostics.Tracing filterData = null; // read filter data only when a session is being *added* - byte[]? data; - int keyIndex; if (bEnabling && - GetDataFromController(etwSessionId, filterData, out command, out data, out keyIndex)) + GetDataFromController(etwSessionId, filterData, out command, out byte[]? data, out int keyIndex)) { args = new Dictionary(4); // data can be null if the filterArgs had a very large size which failed our sanity check @@ -469,42 +467,59 @@ namespace System.Diagnostics.Tracing // does not have this issue. #if (TARGET_WINDOWS && (ES_SESSION_INFO || !ES_BUILD_STANDALONE)) int buffSize = 256; // An initial guess that probably works most of the time. - byte* buffer; - while (true) + byte* stackSpace = stackalloc byte[buffSize]; + byte* buffer = stackSpace; + try { - byte* space = stackalloc byte[buffSize]; - buffer = space; - int hr = 0; - - fixed (Guid* provider = &m_providerId) + while (true) { - hr = Interop.Advapi32.EnumerateTraceGuidsEx(Interop.Advapi32.TRACE_QUERY_INFO_CLASS.TraceGuidQueryInfo, - provider, sizeof(Guid), buffer, buffSize, out buffSize); + int hr = 0; + + fixed (Guid* provider = &m_providerId) + { + hr = Interop.Advapi32.EnumerateTraceGuidsEx(Interop.Advapi32.TRACE_QUERY_INFO_CLASS.TraceGuidQueryInfo, + provider, sizeof(Guid), buffer, buffSize, out buffSize); + } + if (hr == 0) + break; + if (hr != Interop.Errors.ERROR_INSUFFICIENT_BUFFER) + return; + + if (buffer != stackSpace) + { + byte* toFree = buffer; + buffer = null; + Marshal.FreeHGlobal((IntPtr)toFree); + } + buffer = (byte*)Marshal.AllocHGlobal(buffSize); + } + + var providerInfos = (Interop.Advapi32.TRACE_GUID_INFO*)buffer; + var providerInstance = (Interop.Advapi32.TRACE_PROVIDER_INSTANCE_INFO*)&providerInfos[1]; + int processId = unchecked((int)Interop.Kernel32.GetCurrentProcessId()); + // iterate over the instances of the EventProvider in all processes + for (int i = 0; i < providerInfos->InstanceCount; i++) + { + if (providerInstance->Pid == processId) + { + var enabledInfos = (Interop.Advapi32.TRACE_ENABLE_INFO*)&providerInstance[1]; + // iterate over the list of active ETW sessions "listening" to the current provider + for (int j = 0; j < providerInstance->EnableCount; j++) + action(enabledInfos[j].LoggerId, enabledInfos[j].MatchAllKeyword, ref sessionList); + } + if (providerInstance->NextOffset == 0) + break; + Debug.Assert(0 <= providerInstance->NextOffset && providerInstance->NextOffset < buffSize); + byte* structBase = (byte*)providerInstance; + providerInstance = (Interop.Advapi32.TRACE_PROVIDER_INSTANCE_INFO*)&structBase[providerInstance->NextOffset]; } - if (hr == 0) - break; - if (hr != Interop.Errors.ERROR_INSUFFICIENT_BUFFER) - return; } - - var providerInfos = (Interop.Advapi32.TRACE_GUID_INFO*)buffer; - var providerInstance = (Interop.Advapi32.TRACE_PROVIDER_INSTANCE_INFO*)&providerInfos[1]; - int processId = unchecked((int)Interop.Kernel32.GetCurrentProcessId()); - // iterate over the instances of the EventProvider in all processes - for (int i = 0; i < providerInfos->InstanceCount; i++) + finally { - if (providerInstance->Pid == processId) + if (buffer != null && buffer != stackSpace) { - var enabledInfos = (Interop.Advapi32.TRACE_ENABLE_INFO*)&providerInstance[1]; - // iterate over the list of active ETW sessions "listening" to the current provider - for (int j = 0; j < providerInstance->EnableCount; j++) - action(enabledInfos[j].LoggerId, enabledInfos[j].MatchAllKeyword, ref sessionList); + Marshal.FreeHGlobal((IntPtr)buffer); } - if (providerInstance->NextOffset == 0) - break; - Debug.Assert(0 <= providerInstance->NextOffset && providerInstance->NextOffset < buffSize); - byte* structBase = (byte*)providerInstance; - providerInstance = (Interop.Advapi32.TRACE_PROVIDER_INSTANCE_INFO*)&structBase[providerInstance->NextOffset]; } #else #if !ES_BUILD_PCL && TARGET_WINDOWS // TODO command arguments don't work on PCL builds... diff --git a/src/System.Private.CoreLib/shared/System/Diagnostics/Tracing/EventSource.cs b/src/System.Private.CoreLib/shared/System/Diagnostics/Tracing/EventSource.cs index 9e08f5bec..fd42fb69b 100644 --- a/src/System.Private.CoreLib/shared/System/Diagnostics/Tracing/EventSource.cs +++ b/src/System.Private.CoreLib/shared/System/Diagnostics/Tracing/EventSource.cs @@ -649,10 +649,8 @@ namespace System.Diagnostics.Tracing { m_config = ValidateSettings(settings); - Guid eventSourceGuid; - string? eventSourceName; - GetMetadata(out eventSourceGuid, out eventSourceName, out _, out _); + GetMetadata(out Guid eventSourceGuid, out string? eventSourceName, out _, out _); if (eventSourceGuid.Equals(Guid.Empty) || eventSourceName == null) { @@ -1373,28 +1371,29 @@ namespace System.Diagnostics.Tracing int dataCount, IntPtr data) { +#if FEATURE_MANAGED_ETW || FEATURE_PERFTRACING + bool allAreNull = true; #if FEATURE_MANAGED_ETW - if (m_etwProvider == null) + allAreNull &= (m_etwProvider == null); + if (m_etwProvider != null + && !m_etwProvider.WriteEventRaw(ref eventDescriptor, eventHandle, activityID, relatedActivityID, dataCount, data)) { ThrowEventSourceException(eventName); } - else - { - if (!m_etwProvider.WriteEventRaw(ref eventDescriptor, eventHandle, activityID, relatedActivityID, dataCount, data)) - ThrowEventSourceException(eventName); - } #endif // FEATURE_MANAGED_ETW #if FEATURE_PERFTRACING - if (m_eventPipeProvider == null) + allAreNull &= (m_eventPipeProvider == null); + if (m_eventPipeProvider != null + && !m_eventPipeProvider.WriteEventRaw(ref eventDescriptor, eventHandle, activityID, relatedActivityID, dataCount, data)) { ThrowEventSourceException(eventName); } - else - { - if (!m_eventPipeProvider.WriteEventRaw(ref eventDescriptor, eventHandle, activityID, relatedActivityID, dataCount, data)) - ThrowEventSourceException(eventName); - } #endif // FEATURE_PERFTRACING + if (allAreNull) + { + ThrowEventSourceException(eventName); + } +#endif // FEATURE_MANAGED_ETW || FEATURE_PERFTRACING } // FrameworkEventSource is on the startup path for the framework, so we have this internal overload that it can use @@ -2150,49 +2149,95 @@ namespace System.Diagnostics.Tracing } } - private unsafe void WriteEventString(EventLevel level, long keywords, string msgString) + // WriteEventString is used for logging an error message (or similar) to + // ETW and EventPipe providers. It is not a general purpose API, it will + // log the message with Level=LogAlways and Keywords=All to make sure whoever + // is listening gets the message. + private unsafe void WriteEventString(string msgString) { +#if FEATURE_MANAGED_ETW || FEATURE_PERFTRACING + bool allAreNull = true; #if FEATURE_MANAGED_ETW - if (m_etwProvider != null) + allAreNull &= (m_etwProvider == null); +#endif // FEATURE_MANAGED_ETW +#if FEATURE_PERFTRACING + allAreNull &= (m_eventPipeProvider == null); +#endif // FEATURE_PERFTRACING + if (allAreNull) { - const string EventName = "EventSourceMessage"; - if (SelfDescribingEvents) - { - EventSourceOptions opt = new EventSourceOptions - { - Keywords = (EventKeywords)unchecked(keywords), - Level = level - }; - var msg = new { message = msgString }; - var tlet = new TraceLoggingEventTypes(EventName, EventTags.None, new Type[] { msg.GetType() }); - WriteMultiMergeInner(EventName, ref opt, tlet, null, null, msg); - } - else - { - // We want the name of the provider to show up so if we don't have a manifest we create - // on that at least has the provider name (I don't define any events). - if (m_rawManifest == null && m_outOfBandMessageCount == 1) - { - ManifestBuilder manifestBuilder = new ManifestBuilder(Name, Guid, Name, null, EventManifestOptions.None); - manifestBuilder.StartEvent(EventName, new EventAttribute(0) { Level = EventLevel.LogAlways, Task = (EventTask)0xFFFE }); - manifestBuilder.AddEventParameter(typeof(string), "message"); - manifestBuilder.EndEvent(); - SendManifest(manifestBuilder.CreateManifest()); - } + return; + } - // We use this low level routine to bypass the enabled checking, since the eventSource itself is only partially inited. - fixed (char* msgStringPtr = msgString) + EventLevel level = EventLevel.LogAlways; + long keywords = -1; + const string EventName = "EventSourceMessage"; + if (SelfDescribingEvents) + { + EventSourceOptions opt = new EventSourceOptions + { + Keywords = (EventKeywords)unchecked(keywords), + Level = level + }; + var msg = new { message = msgString }; + var tlet = new TraceLoggingEventTypes(EventName, EventTags.None, new Type[] { msg.GetType() }); + WriteMultiMergeInner(EventName, ref opt, tlet, null, null, msg); + } + else + { + // We want the name of the provider to show up so if we don't have a manifest we create + // on that at least has the provider name (I don't define any events). + if (m_rawManifest == null && m_outOfBandMessageCount == 1) + { + ManifestBuilder manifestBuilder = new ManifestBuilder(Name, Guid, Name, null, EventManifestOptions.None); + manifestBuilder.StartEvent(EventName, new EventAttribute(0) { Level = level, Task = (EventTask)0xFFFE }); + manifestBuilder.AddEventParameter(typeof(string), "message"); + manifestBuilder.EndEvent(); + SendManifest(manifestBuilder.CreateManifest()); + } + + // We use this low level routine to bypass the enabled checking, since the eventSource itself is only partially inited. + fixed (char* msgStringPtr = msgString) + { + EventDescriptor descr = new EventDescriptor(0, 0, 0, (byte)level, 0, 0, keywords); + EventProvider.EventData data = default; + data.Ptr = (ulong)msgStringPtr; + data.Size = (uint)(2 * (msgString.Length + 1)); + data.Reserved = 0; +#if FEATURE_MANAGED_ETW + if (m_etwProvider != null) { - EventDescriptor descr = new EventDescriptor(0, 0, 0, (byte)level, 0, 0, keywords); - EventProvider.EventData data = default; - data.Ptr = (ulong)msgStringPtr; - data.Size = (uint)(2 * (msgString.Length + 1)); - data.Reserved = 0; m_etwProvider.WriteEvent(ref descr, IntPtr.Zero, null, null, 1, (IntPtr)((void*)&data)); } +#endif // FEATURE_MANAGED_ETW +#if FEATURE_PERFTRACING + if (m_eventPipeProvider != null) + { + if (m_writeEventStringEventHandle == IntPtr.Zero) + { + lock (m_createEventLock) + { + if (m_writeEventStringEventHandle == IntPtr.Zero) + { + string eventName = "EventSourceMessage"; + EventParameterInfo paramInfo = default(EventParameterInfo); + paramInfo.SetInfo("message", typeof(string)); + byte[]? metadata = EventPipeMetadataGenerator.Instance.GenerateMetadata(0, eventName, keywords, (uint)level, 0, new EventParameterInfo[] { paramInfo }); + uint metadataLength = (metadata != null) ? (uint)metadata.Length : 0; + + fixed (byte* pMetadata = metadata) + { + m_writeEventStringEventHandle = m_eventPipeProvider.m_eventProvider.DefineEventHandle(0, eventName, keywords, 0, (uint)level, pMetadata, metadataLength); + } + } + } + } + + m_eventPipeProvider.WriteEvent(ref descr, m_writeEventStringEventHandle, null, null, 1, (IntPtr)((void*)&data)); + } +#endif // FEATURE_PERFTRACING } } -#endif // FEATURE_MANAGED_ETW +#endif // FEATURE_MANAGED_ETW || FEATURE_PERFTRACING } /// @@ -2871,13 +2916,10 @@ namespace System.Diagnostics.Tracing if (m_eventData == null) { Guid eventSourceGuid = Guid.Empty; - string? eventSourceName = null; - EventMetadata[]? eventData = null; - byte[]? manifest = null; // Try the GetMetadata provided by the ILTransform in ProjectN. The default sets all to null, and in that case we fall back // to the reflection approach. - GetMetadata(out eventSourceGuid, out eventSourceName, out eventData, out manifest); + GetMetadata(out eventSourceGuid, out string? eventSourceName, out EventMetadata[]? eventData, out byte[]? manifest); if (eventSourceGuid.Equals(Guid.Empty) || eventSourceName == null || eventData == null || manifest == null) { @@ -3808,7 +3850,7 @@ namespace System.Diagnostics.Tracing msg = "Reached message limit. End of EventSource error messages."; } - WriteEventString(EventLevel.LogAlways, -1, msg); + WriteEventString(msg); WriteStringToAllListeners("EventSourceMessage", msg); } catch { } // If we fail during last chance logging, well, we have to give up.... @@ -3865,6 +3907,8 @@ namespace System.Diagnostics.Tracing private volatile OverideEventProvider m_etwProvider = null!; // This hooks up ETW commands to our 'OnEventCommand' callback #endif #if FEATURE_PERFTRACING + private object m_createEventLock = new object(); + private IntPtr m_writeEventStringEventHandle = IntPtr.Zero; private volatile OverideEventProvider m_eventPipeProvider = null!; #endif private bool m_completelyInited; // The EventSource constructor has returned without exception. @@ -5551,8 +5595,7 @@ namespace System.Diagnostics.Tracing if (channelTab.Count == MaxCountChannels) ManifestError(SR.EventSource_MaxChannelExceeded); - ChannelInfo? info; - if (!channelTab.TryGetValue((int)channel, out info)) + if (!channelTab.TryGetValue((int)channel, out ChannelInfo? info)) { // If we were not given an explicit channel, allocate one. if (channelKeyword != 0) @@ -5876,8 +5919,7 @@ namespace System.Diagnostics.Tracing #if FEATURE_MANAGED_ETW_CHANNELS private string? GetChannelName(EventChannel channel, string eventName, string? eventMessage) { - ChannelInfo? info = null; - if (channelTab == null || !channelTab.TryGetValue((int)channel, out info)) + if (channelTab == null || !channelTab.TryGetValue((int)channel, out ChannelInfo? info)) { if (channel < EventChannel.Admin) // || channel > EventChannel.Debug) ManifestError(SR.Format(SR.EventSource_UndefinedChannel, channel, eventName)); @@ -5909,9 +5951,8 @@ namespace System.Diagnostics.Tracing if (task == EventTask.None) return ""; - string? ret; taskTab ??= new Dictionary(); - if (!taskTab.TryGetValue((int)task, out ret)) + if (!taskTab.TryGetValue((int)task, out string? ret)) ret = taskTab[(int)task] = eventName; return ret; } @@ -5944,8 +5985,7 @@ namespace System.Diagnostics.Tracing return "win:Receive"; } - string? ret; - if (opcodeTab == null || !opcodeTab.TryGetValue((int)opcode, out ret)) + if (opcodeTab == null || !opcodeTab.TryGetValue((int)opcode, out string? ret)) { ManifestError(SR.Format(SR.EventSource_UndefinedOpcode, opcode, eventName), true); ret = null; @@ -6052,7 +6092,6 @@ namespace System.Diagnostics.Tracing { StringBuilder? stringBuilder = null; // We lazily create this int writtenSoFar = 0; - int chIdx = -1; for (int i = 0; ;) { if (i >= eventMessage.Length) @@ -6063,6 +6102,7 @@ namespace System.Diagnostics.Tracing return stringBuilder.ToString(); } + int chIdx; if (eventMessage[i] == '%') { // handle format message escaping character '%' by escaping it @@ -6125,8 +6165,7 @@ namespace System.Diagnostics.Tracing private int TranslateIndexToManifestConvention(int idx, string evtName) { - List? byteArrArgIndices; - if (perEventByteArrayArgIndices.TryGetValue(evtName, out byteArrArgIndices)) + if (perEventByteArrayArgIndices.TryGetValue(evtName, out List? byteArrArgIndices)) { foreach (int byArrIdx in byteArrArgIndices) { diff --git a/src/System.Private.CoreLib/shared/System/Diagnostics/Tracing/NativeRuntimeEventSource.cs b/src/System.Private.CoreLib/shared/System/Diagnostics/Tracing/NativeRuntimeEventSource.cs new file mode 100644 index 000000000..5272f5077 --- /dev/null +++ b/src/System.Private.CoreLib/shared/System/Diagnostics/Tracing/NativeRuntimeEventSource.cs @@ -0,0 +1,49 @@ +// 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.Diagnostics.Tracing +{ + /// + /// NativeRuntimeEventSource is an EventSource that represents the ETW/EventPipe events emitted by the native runtime. + /// Most of NativeRuntimeEventSource is auto-generated by scripts/genRuntimeEventSources.py based on the contents of the Microsoft-Windows-DotNETRuntime provider. + /// + [EventSource(Guid = "5E5BB766-BBFC-5662-0548-1D44FAD9BB56", Name = "Microsoft-Windows-DotNETRuntime")] + internal sealed partial class NativeRuntimeEventSource : EventSource + { + internal const string EventSourceName = "Microsoft-Windows-DotNETRuntime"; + internal static NativeRuntimeEventSource Log = new NativeRuntimeEventSource(); + + // The NativeRuntimeEventSource GUID is {5e5bb766-bbfc-5662-0548-1d44fad9bb56} + private NativeRuntimeEventSource() : base(new Guid(0x5e5bb766, 0xbbfc, 0x5662, 0x05, 0x48, 0x1d, 0x44, 0xfa, 0xd9, 0xbb, 0x56), EventSourceName) { } + + /// + /// Dispatch a single event with the specified event ID and payload. + /// + /// The eventID corresponding to the event as defined in the auto-generated portion of the NativeRuntimeEventSource class. + /// The thread ID of the operating system thread. + /// The current timestamp. + /// The ID of the current activity. + /// The ID of the current child activity. + /// A span pointing to the data payload for the event. + [NonEvent] + internal unsafe void ProcessEvent(uint eventID, uint osThreadID, DateTime timeStamp, Guid activityId, Guid childActivityId, ReadOnlySpan payload) + { + // Make sure the eventID is valid. + if (eventID >= m_eventData!.Length) + { + return; + } + + // Decode the payload. + object[] decodedPayloadFields = EventPipePayloadDecoder.DecodePayload(ref m_eventData[eventID], payload); + WriteToAllListeners( + eventId: (int)eventID, + osThreadId: &osThreadID, + timeStamp: &timeStamp, + activityID: &activityId, + childActivityID: &childActivityId, + args: decodedPayloadFields); + } + } +} diff --git a/src/System.Private.CoreLib/shared/System/Diagnostics/Tracing/RuntimeEventSource.cs b/src/System.Private.CoreLib/shared/System/Diagnostics/Tracing/RuntimeEventSource.cs new file mode 100644 index 000000000..336e981bd --- /dev/null +++ b/src/System.Private.CoreLib/shared/System/Diagnostics/Tracing/RuntimeEventSource.cs @@ -0,0 +1,85 @@ +// 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.Diagnostics.Tracing +{ + /// + /// RuntimeEventSource is an EventSource that represents events emitted by the managed runtime. + /// + [EventSource(Guid = "49592C0F-5A05-516D-AA4B-A64E02026C89", Name = "System.Runtime")] + internal sealed class RuntimeEventSource : EventSource + { + internal const string EventSourceName = "System.Runtime"; + + private static RuntimeEventSource? s_RuntimeEventSource; + private PollingCounter? _gcHeapSizeCounter; + private IncrementingPollingCounter? _gen0GCCounter; + private IncrementingPollingCounter? _gen1GCCounter; + private IncrementingPollingCounter? _gen2GCCounter; + private PollingCounter? _cpuTimeCounter; + private PollingCounter? _workingSetCounter; + private PollingCounter? _threadPoolThreadCounter; + private IncrementingPollingCounter? _monitorContentionCounter; + private PollingCounter? _threadPoolQueueCounter; + private IncrementingPollingCounter? _completedItemsCounter; + private IncrementingPollingCounter? _allocRateCounter; + private PollingCounter? _timerCounter; + +#if !MONO + private IncrementingPollingCounter? _exceptionCounter; + private PollingCounter? _gcTimeCounter; + private PollingCounter? _gen0SizeCounter; + private PollingCounter? _gen1SizeCounter; + private PollingCounter? _gen2SizeCounter; + private PollingCounter? _lohSizeCounter; + private PollingCounter? _assemblyCounter; +#endif + + public static void Initialize() + { + s_RuntimeEventSource = new RuntimeEventSource(); + } + + private RuntimeEventSource() : base(new Guid(0x49592C0F, 0x5A05, 0x516D, 0xAA, 0x4B, 0xA6, 0x4E, 0x02, 0x02, 0x6C, 0x89), EventSourceName, EventSourceSettings.EtwSelfDescribingEventFormat) + { + } + + protected override void OnEventCommand(EventCommandEventArgs command) + { + if (command.Command == EventCommand.Enable) + { + // NOTE: These counters will NOT be disposed on disable command because we may be introducing + // a race condition by doing that. We still want to create these lazily so that we aren't adding + // overhead by at all times even when counters aren't enabled. + + // On disable, PollingCounters will stop polling for values so it should be fine to leave them around. + _cpuTimeCounter ??= new PollingCounter("cpu-usage", this, () => RuntimeEventSourceHelper.GetCpuUsage()) { DisplayName = "CPU Usage", DisplayUnits = "%" }; + _workingSetCounter ??= new PollingCounter("working-set", this, () => (double)(Environment.WorkingSet / 1000000)) { DisplayName = "Working Set", DisplayUnits = "MB" }; + _gcHeapSizeCounter ??= new PollingCounter("gc-heap-size", this, () => (double)(GC.GetTotalMemory(false) / 1000000)) { DisplayName = "GC Heap Size", DisplayUnits = "MB" }; + _gen0GCCounter ??= new IncrementingPollingCounter("gen-0-gc-count", this, () => GC.CollectionCount(0)) { DisplayName = "Gen 0 GC Count", DisplayRateTimeScale = new TimeSpan(0, 1, 0) }; + _gen1GCCounter ??= new IncrementingPollingCounter("gen-1-gc-count", this, () => GC.CollectionCount(1)) { DisplayName = "Gen 1 GC Count", DisplayRateTimeScale = new TimeSpan(0, 1, 0) }; + _gen2GCCounter ??= new IncrementingPollingCounter("gen-2-gc-count", this, () => GC.CollectionCount(2)) { DisplayName = "Gen 2 GC Count", DisplayRateTimeScale = new TimeSpan(0, 1, 0) }; + _threadPoolThreadCounter ??= new PollingCounter("threadpool-thread-count", this, () => ThreadPool.ThreadCount) { DisplayName = "ThreadPool Thread Count" }; + _monitorContentionCounter ??= new IncrementingPollingCounter("monitor-lock-contention-count", this, () => Monitor.LockContentionCount) { DisplayName = "Monitor Lock Contention Count", DisplayRateTimeScale = new TimeSpan(0, 0, 1) }; + _threadPoolQueueCounter ??= new PollingCounter("threadpool-queue-length", this, () => ThreadPool.PendingWorkItemCount) { DisplayName = "ThreadPool Queue Length" }; + _completedItemsCounter ??= new IncrementingPollingCounter("threadpool-completed-items-count", this, () => ThreadPool.CompletedWorkItemCount) { DisplayName = "ThreadPool Completed Work Item Count", DisplayRateTimeScale = new TimeSpan(0, 0, 1) }; + _allocRateCounter ??= new IncrementingPollingCounter("alloc-rate", this, () => GC.GetTotalAllocatedBytes()) { DisplayName = "Allocation Rate", DisplayUnits = "B", DisplayRateTimeScale = new TimeSpan(0, 0, 1) }; + _timerCounter ??= new PollingCounter("active-timer-count", this, () => Timer.ActiveCount) { DisplayName = "Number of Active Timers" }; + +#if !MONO + _exceptionCounter ??= new IncrementingPollingCounter("exception-count", this, () => Exception.GetExceptionCount()) { DisplayName = "Exception Count", DisplayRateTimeScale = new TimeSpan(0, 0, 1) }; + _gcTimeCounter ??= new PollingCounter("time-in-gc", this, () => GC.GetLastGCPercentTimeInGC()) { DisplayName = "% Time in GC since last GC", DisplayUnits = "%" }; + _gen0SizeCounter ??= new PollingCounter("gen-0-size", this, () => GC.GetGenerationSize(0)) { DisplayName = "Gen 0 Size", DisplayUnits = "B" }; + _gen1SizeCounter ??= new PollingCounter("gen-1-size", this, () => GC.GetGenerationSize(1)) { DisplayName = "Gen 1 Size", DisplayUnits = "B" }; + _gen2SizeCounter ??= new PollingCounter("gen-2-size", this, () => GC.GetGenerationSize(2)) { DisplayName = "Gen 2 Size", DisplayUnits = "B" }; + _lohSizeCounter ??= new PollingCounter("loh-size", this, () => GC.GetGenerationSize(3)) { DisplayName = "LOH Size", DisplayUnits = "B" }; + _assemblyCounter ??= new PollingCounter("assembly-count", this, () => System.Reflection.Assembly.GetAssemblyCount()) { DisplayName = "Number of Assemblies Loaded" }; +#endif + } + + } + } +} diff --git a/src/System.Private.CoreLib/shared/System/Diagnostics/Tracing/RuntimeEventSourceHelper.Unix.cs b/src/System.Private.CoreLib/shared/System/Diagnostics/Tracing/RuntimeEventSourceHelper.Unix.cs new file mode 100644 index 000000000..7b6e43f9f --- /dev/null +++ b/src/System.Private.CoreLib/shared/System/Diagnostics/Tracing/RuntimeEventSourceHelper.Unix.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.Diagnostics.Tracing +{ + internal static class RuntimeEventSourceHelper + { + private static Interop.Sys.ProcessCpuInformation s_cpuInfo; + + internal static int GetCpuUsage() => + Interop.Sys.GetCpuUtilization(ref s_cpuInfo) / Environment.ProcessorCount; + } +} diff --git a/src/System.Private.CoreLib/shared/System/Diagnostics/Tracing/RuntimeEventSourceHelper.Windows.cs b/src/System.Private.CoreLib/shared/System/Diagnostics/Tracing/RuntimeEventSourceHelper.Windows.cs new file mode 100644 index 000000000..ad198646d --- /dev/null +++ b/src/System.Private.CoreLib/shared/System/Diagnostics/Tracing/RuntimeEventSourceHelper.Windows.cs @@ -0,0 +1,49 @@ +// 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.Diagnostics.Tracing +{ + internal static class RuntimeEventSourceHelper + { + private static long s_prevProcUserTime = 0; + private static long s_prevProcKernelTime = 0; + private static long s_prevSystemUserTime = 0; + private static long s_prevSystemKernelTime = 0; + + internal static int GetCpuUsage() + { + // Returns the current process' CPU usage as a percentage + + int cpuUsage; + + if (!Interop.Kernel32.GetProcessTimes(Interop.Kernel32.GetCurrentProcess(), out _, out _, out long procKernelTime, out long procUserTime)) + { + return 0; + } + + if (!Interop.Kernel32.GetSystemTimes(out _, out long systemUserTime, out long systemKernelTime)) + { + return 0; + } + + if (s_prevSystemUserTime == 0 && s_prevSystemKernelTime == 0) // These may be 0 when we report CPU usage for the first time, in which case we should just return 0. + { + cpuUsage = 0; + } + else + { + long totalProcTime = (procUserTime - s_prevProcUserTime) + (procKernelTime - s_prevProcKernelTime); + long totalSystemTime = (systemUserTime - s_prevSystemUserTime) + (systemKernelTime - s_prevSystemKernelTime); + cpuUsage = (int)(totalProcTime * 100 / totalSystemTime); + } + + s_prevProcUserTime = procUserTime; + s_prevProcKernelTime = procKernelTime; + s_prevSystemUserTime = systemUserTime; + s_prevSystemKernelTime = systemKernelTime; + + return cpuUsage; + } + } +} diff --git a/src/System.Private.CoreLib/shared/System/Diagnostics/Tracing/TraceLogging/TraceLoggingEventHandleTable.cs b/src/System.Private.CoreLib/shared/System/Diagnostics/Tracing/TraceLogging/TraceLoggingEventHandleTable.cs new file mode 100644 index 000000000..9c294cf8e --- /dev/null +++ b/src/System.Private.CoreLib/shared/System/Diagnostics/Tracing/TraceLogging/TraceLoggingEventHandleTable.cs @@ -0,0 +1,61 @@ +// 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.Diagnostics.Tracing +{ +#if FEATURE_PERFTRACING + /// + /// Per-EventSource data structure for caching EventPipe EventHandles associated with TraceLogging events. + /// + internal sealed class TraceLoggingEventHandleTable + { + private const int DefaultLength = 10; + private IntPtr[] m_innerTable; + + internal TraceLoggingEventHandleTable() + { + m_innerTable = new IntPtr[DefaultLength]; + } + + internal IntPtr this[int eventID] + { + get + { + IntPtr ret = IntPtr.Zero; + IntPtr[] innerTable = Volatile.Read(ref m_innerTable); + + if (eventID >= 0 && eventID < innerTable.Length) + { + ret = innerTable[eventID]; + } + + return ret; + } + } + + internal void SetEventHandle(int eventID, IntPtr eventHandle) + { + // Set operations must be serialized to ensure that re-size operations don't lose concurrent writes. + Debug.Assert(Monitor.IsEntered(this)); + + if (eventID >= m_innerTable.Length) + { + int newSize = m_innerTable.Length * 2; + if (newSize <= eventID) + { + newSize = eventID + 1; + } + + IntPtr[] newTable = new IntPtr[newSize]; + Array.Copy(m_innerTable, newTable, m_innerTable.Length); + Volatile.Write(ref m_innerTable, newTable); + } + + m_innerTable[eventID] = eventHandle; + } + } +#endif +} diff --git a/src/System.Private.CoreLib/shared/System/Diagnostics/Tracing/TraceLogging/TraceLoggingEventSource.cs b/src/System.Private.CoreLib/shared/System/Diagnostics/Tracing/TraceLogging/TraceLoggingEventSource.cs index 736e78d3a..aa13daa55 100644 --- a/src/System.Private.CoreLib/shared/System/Diagnostics/Tracing/TraceLogging/TraceLoggingEventSource.cs +++ b/src/System.Private.CoreLib/shared/System/Diagnostics/Tracing/TraceLogging/TraceLoggingEventSource.cs @@ -523,8 +523,7 @@ namespace System.Diagnostics.Tracing fixed (EventSourceOptions* pOptions = &options) { - EventDescriptor descriptor; - NameInfo? nameInfo = this.UpdateDescriptor(eventName, eventTypes, ref options, out descriptor); + NameInfo? nameInfo = this.UpdateDescriptor(eventName, eventTypes, ref options, out EventDescriptor descriptor); if (nameInfo == null) { return; @@ -591,9 +590,8 @@ namespace System.Diagnostics.Tracing { fixed (EventSourceOptions* pOptions = &options) { - EventDescriptor descriptor; options.Opcode = options.IsOpcodeSet ? options.Opcode : GetOpcodeWithDefault(options.Opcode, eventName); - NameInfo? nameInfo = this.UpdateDescriptor(eventName, eventTypes, ref options, out descriptor); + NameInfo? nameInfo = this.UpdateDescriptor(eventName, eventTypes, ref options, out EventDescriptor descriptor); if (nameInfo == null) { return; @@ -764,8 +762,7 @@ namespace System.Diagnostics.Tracing if (m_traits[i].StartsWith("ETW_", StringComparison.Ordinal)) { string etwTrait = m_traits[i].Substring(4); - byte traitNum; - if (!byte.TryParse(etwTrait, out traitNum)) + if (!byte.TryParse(etwTrait, out byte traitNum)) { if (etwTrait == "GROUP") { diff --git a/src/System.Private.CoreLib/shared/System/Diagnostics/Tracing/TraceLogging/TraceLoggingTypeInfo.cs b/src/System.Private.CoreLib/shared/System/Diagnostics/Tracing/TraceLogging/TraceLoggingTypeInfo.cs index a5de12342..b0b537e76 100644 --- a/src/System.Private.CoreLib/shared/System/Diagnostics/Tracing/TraceLogging/TraceLoggingTypeInfo.cs +++ b/src/System.Private.CoreLib/shared/System/Diagnostics/Tracing/TraceLogging/TraceLoggingTypeInfo.cs @@ -164,8 +164,7 @@ namespace System.Diagnostics.Tracing { Dictionary cache = threadCache ??= new Dictionary(); - TraceLoggingTypeInfo? instance; - if (!cache.TryGetValue(type, out instance)) + if (!cache.TryGetValue(type, out TraceLoggingTypeInfo? instance)) { recursionCheck ??= new List(); int recursionCheckCount = recursionCheck.Count; diff --git a/src/System.Private.CoreLib/shared/System/Diagnostics/Tracing/TraceLogging/XplatEventLogger.cs b/src/System.Private.CoreLib/shared/System/Diagnostics/Tracing/TraceLogging/XplatEventLogger.cs new file mode 100644 index 000000000..f027781f4 --- /dev/null +++ b/src/System.Private.CoreLib/shared/System/Diagnostics/Tracing/TraceLogging/XplatEventLogger.cs @@ -0,0 +1,204 @@ +// 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; +using System.Runtime.CompilerServices; +using System.Collections.ObjectModel; +using System.Collections.Generic; +using System.Diagnostics; +using System.Text; +using System.Runtime.InteropServices; +using System.Runtime.Versioning; + +#if FEATURE_EVENTSOURCE_XPLAT + +namespace System.Diagnostics.Tracing +{ + internal class XplatEventLogger : EventListener + { + private static Lazy eventSourceNameFilter = new Lazy(() => CompatibilitySwitch.GetValueInternal("EventSourceFilter")); + private static Lazy eventSourceEventFilter = new Lazy(() => CompatibilitySwitch.GetValueInternal("EventNameFilter")); + + public XplatEventLogger() {} + + private static bool initializedPersistentListener = false; + + public static EventListener? InitializePersistentListener() + { + try + { + if (!initializedPersistentListener && XplatEventLogger.IsEventSourceLoggingEnabled()) + { + initializedPersistentListener = true; + return new XplatEventLogger(); + } + } + catch (Exception) { } + + return null; + } + + [DllImport(RuntimeHelpers.QCall, CharSet = CharSet.Unicode)] + private static extern bool IsEventSourceLoggingEnabled(); + + [DllImport(RuntimeHelpers.QCall, CharSet = CharSet.Unicode)] + private static extern void LogEventSource(int eventID, string? eventName, string eventSourceName, string payload); + + private static readonly List escape_seq = new List { '\b', '\f', '\n', '\r', '\t', '\"', '\\' }; + private static readonly Dictionary seq_mapping = new Dictionary() + { + {'\b', "b"}, + {'\f', "f"}, + {'\n', "n"}, + {'\r', "r"}, + {'\t', "t"}, + {'\"', "\\\""}, + {'\\', "\\\\"} + }; + + private static void minimalJsonserializer(string payload, StringBuilder sb) + { + foreach (var elem in payload) + { + if (escape_seq.Contains(elem)) + { + sb.Append("\\\\"); + sb.Append(seq_mapping[elem]); + } + else + { + sb.Append(elem); + } + } + } + + private static string Serialize(ReadOnlyCollection? payloadName, ReadOnlyCollection? payload, string? eventMessage) + { + if (payloadName == null || payload == null) + return string.Empty; + + if (payloadName.Count == 0 || payload.Count == 0) + return string.Empty; + + int eventDataCount = payloadName.Count; + + if (payloadName.Count != payload.Count) + { + eventDataCount = Math.Min(payloadName.Count, payload.Count); + } + + var sb = StringBuilderCache.Acquire(); + + sb.Append('{'); + + // If the event has a message, send that as well as a pseudo-field + if (!string.IsNullOrEmpty(eventMessage)) + { + sb.Append("\\\"EventSource_Message\\\":\\\""); + minimalJsonserializer(eventMessage, sb); + sb.Append("\\\""); + if (eventDataCount != 0) + sb.Append(", "); + } + + for (int i = 0; i < eventDataCount; i++) + { + if (i != 0) + sb.Append(", "); + + var fieldstr = payloadName[i].ToString(); + + sb.Append("\\\""); + sb.Append(fieldstr); + sb.Append("\\\""); + sb.Append(':'); + + switch (payload[i]) + { + case string str: + { + sb.Append("\\\""); + minimalJsonserializer(str, sb); + sb.Append("\\\""); + break; + } + case byte[] byteArr: + { + sb.Append("\\\""); + AppendByteArrayAsHexString(sb, byteArr); + sb.Append("\\\""); + break; + } + default: + { + if (payload[i] != null) + { + sb.Append(payload[i]!.ToString()); // TODO-NULLABLE: Indexer nullability tracked (https://github.com/dotnet/roslyn/issues/34644) + } + break; + } + } + } + sb.Append('}'); + return StringBuilderCache.GetStringAndRelease(sb); + } + + private static void AppendByteArrayAsHexString(StringBuilder builder, byte[] byteArray) + { + Debug.Assert(builder != null); + Debug.Assert(byteArray != null); + + ReadOnlySpan hexFormat = "X2"; + Span hex = stackalloc char[2]; + for (int i=0; i= 0)) + { + EnableEvents(eventSource, EventLevel.LogAlways, EventKeywords.All, null); + } + } + + protected internal override void OnEventWritten(EventWrittenEventArgs eventData) + { + string? eventFilter = eventSourceEventFilter.Value; + if (string.IsNullOrEmpty(eventFilter) || (eventData.EventName!.IndexOf(eventFilter, StringComparison.OrdinalIgnoreCase) >= 0)) + { + LogOnEventWritten(eventData); + } + } + + private void LogOnEventWritten(EventWrittenEventArgs eventData) + { + string payload = ""; + if (eventData.Payload != null) + { + try{ + payload = Serialize(eventData.PayloadNames, eventData.Payload, eventData.Message); + } + catch (Exception ex) + { + payload = "XplatEventLogger failed with Exception " + ex.ToString(); + } + } + + LogEventSource(eventData.EventId, eventData.EventName, eventData.EventSource.Name, payload); + } + } +} +#endif //FEATURE_EVENTSOURCE_XPLAT diff --git a/src/System.Private.CoreLib/shared/System/Double.cs b/src/System.Private.CoreLib/shared/System/Double.cs index fedbed02d..fd15e7145 100644 --- a/src/System.Private.CoreLib/shared/System/Double.cs +++ b/src/System.Private.CoreLib/shared/System/Double.cs @@ -12,6 +12,7 @@ ** ===========================================================*/ +using System.Diagnostics.CodeAnalysis; using System.Globalization; using System.Runtime.CompilerServices; using System.Runtime.InteropServices; @@ -321,7 +322,7 @@ namespace System return Number.ParseDouble(s, style, NumberFormatInfo.GetInstance(provider)); } - public static bool TryParse(string? s, out double result) + public static bool TryParse([NotNullWhen(true)] string? s, out double result) { if (s == null) { @@ -337,7 +338,7 @@ namespace System return TryParse(s, NumberStyles.Float | NumberStyles.AllowThousands, NumberFormatInfo.CurrentInfo, out result); } - public static bool TryParse(string? s, NumberStyles style, IFormatProvider? provider, out double result) + public static bool TryParse([NotNullWhen(true)] string? s, NumberStyles style, IFormatProvider? provider, out double result) { NumberFormatInfo.ValidateParseStyleFloatingPoint(style); diff --git a/src/System.Private.CoreLib/shared/System/Environment.NoRegistry.cs b/src/System.Private.CoreLib/shared/System/Environment.NoRegistry.cs index 6e699b1f3..06e35e387 100644 --- a/src/System.Private.CoreLib/shared/System/Environment.NoRegistry.cs +++ b/src/System.Private.CoreLib/shared/System/Environment.NoRegistry.cs @@ -2,9 +2,7 @@ // 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.Diagnostics; using System.Collections; -using Microsoft.Win32; namespace System { diff --git a/src/System.Private.CoreLib/shared/System/Environment.Unix.GetFolderPathCore.cs b/src/System.Private.CoreLib/shared/System/Environment.Unix.GetFolderPathCore.cs new file mode 100644 index 000000000..ad37bba37 --- /dev/null +++ b/src/System.Private.CoreLib/shared/System/Environment.Unix.GetFolderPathCore.cs @@ -0,0 +1,250 @@ +// 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.Collections; +using System.Collections.Generic; +using System.Diagnostics; +using System.IO; +using System.Reflection; +using System.Runtime.InteropServices; +using System.Text; +using System.Threading; + +namespace System +{ + public static partial class Environment + { + private static Func? s_directoryCreateDirectory; + + private static string GetFolderPathCore(SpecialFolder folder, SpecialFolderOption option) + { + // Get the path for the SpecialFolder + string path = GetFolderPathCoreWithoutValidation(folder); + Debug.Assert(path != null); + + // If we didn't get one, or if we got one but we're not supposed to verify it, + // or if we're supposed to verify it and it passes verification, return the path. + if (path.Length == 0 || + option == SpecialFolderOption.DoNotVerify || + Interop.Sys.Access(path, Interop.Sys.AccessMode.R_OK) == 0) + { + return path; + } + + // Failed verification. If None, then we're supposed to return an empty string. + // If Create, we're supposed to create it and then return the path. + if (option == SpecialFolderOption.None) + { + return string.Empty; + } + else + { + Debug.Assert(option == SpecialFolderOption.Create); + + Func createDirectory = LazyInitializer.EnsureInitialized(ref s_directoryCreateDirectory, () => + { + Type dirType = Type.GetType("System.IO.Directory, System.IO.FileSystem, Version=4.0.0.0, Culture=neutral, PublicKeyToken=b03f5f7f11d50a3a", throwOnError: true)!; + MethodInfo mi = dirType.GetTypeInfo().GetDeclaredMethod("CreateDirectory")!; + return (Func)mi.CreateDelegate(typeof(Func)); + }); + createDirectory(path); + + return path; + } + } + + private static string GetFolderPathCoreWithoutValidation(SpecialFolder folder) + { + // First handle any paths that involve only static paths, avoiding the overheads of getting user-local paths. + // https://www.freedesktop.org/software/systemd/man/file-hierarchy.html + switch (folder) + { + case SpecialFolder.CommonApplicationData: return "/usr/share"; + case SpecialFolder.CommonTemplates: return "/usr/share/templates"; +#if TARGET_OSX + case SpecialFolder.ProgramFiles: return "/Applications"; + case SpecialFolder.System: return "/System"; +#endif + } + + // All other paths are based on the XDG Base Directory Specification: + // https://specifications.freedesktop.org/basedir-spec/latest/ + string? home = null; + try + { + home = PersistedFiles.GetHomeDirectory(); + } + catch (Exception exc) + { + Debug.Fail($"Unable to get home directory: {exc}"); + } + + // Fall back to '/' when we can't determine the home directory. + // This location isn't writable by non-root users which provides some safeguard + // that the application doesn't write data which is meant to be private. + if (string.IsNullOrEmpty(home)) + { + home = "/"; + } + + // TODO: Consider caching (or precomputing and caching) all subsequent results. + // This would significantly improve performance for repeated access, at the expense + // of not being responsive to changes in the underlying environment variables, + // configuration files, etc. + + switch (folder) + { + case SpecialFolder.UserProfile: + case SpecialFolder.MyDocuments: // same value as Personal + return home; + case SpecialFolder.ApplicationData: + return GetXdgConfig(home); + case SpecialFolder.LocalApplicationData: + // "$XDG_DATA_HOME defines the base directory relative to which user specific data files should be stored." + // "If $XDG_DATA_HOME is either not set or empty, a default equal to $HOME/.local/share should be used." + string? data = GetEnvironmentVariable("XDG_DATA_HOME"); + if (string.IsNullOrEmpty(data) || data[0] != '/') + { + data = Path.Combine(home, ".local", "share"); + } + return data; + + case SpecialFolder.Desktop: + case SpecialFolder.DesktopDirectory: + return ReadXdgDirectory(home, "XDG_DESKTOP_DIR", "Desktop"); + case SpecialFolder.Templates: + return ReadXdgDirectory(home, "XDG_TEMPLATES_DIR", "Templates"); + case SpecialFolder.MyVideos: + return ReadXdgDirectory(home, "XDG_VIDEOS_DIR", "Videos"); + +#if TARGET_OSX + case SpecialFolder.MyMusic: + return Path.Combine(home, "Music"); + case SpecialFolder.MyPictures: + return Path.Combine(home, "Pictures"); + case SpecialFolder.Fonts: + return Path.Combine(home, "Library", "Fonts"); + case SpecialFolder.Favorites: + return Path.Combine(home, "Library", "Favorites"); + case SpecialFolder.InternetCache: + return Path.Combine(home, "Library", "Caches"); +#else + case SpecialFolder.MyMusic: + return ReadXdgDirectory(home, "XDG_MUSIC_DIR", "Music"); + case SpecialFolder.MyPictures: + return ReadXdgDirectory(home, "XDG_PICTURES_DIR", "Pictures"); + case SpecialFolder.Fonts: + return Path.Combine(home, ".fonts"); +#endif + } + + // No known path for the SpecialFolder + return string.Empty; + } + + private static string GetXdgConfig(string home) + { + // "$XDG_CONFIG_HOME defines the base directory relative to which user specific configuration files should be stored." + // "If $XDG_CONFIG_HOME is either not set or empty, a default equal to $HOME/.config should be used." + string? config = GetEnvironmentVariable("XDG_CONFIG_HOME"); + if (string.IsNullOrEmpty(config) || config[0] != '/') + { + config = Path.Combine(home, ".config"); + } + return config; + } + + private static string ReadXdgDirectory(string homeDir, string key, string fallback) + { + Debug.Assert(!string.IsNullOrEmpty(homeDir), $"Expected non-empty homeDir"); + Debug.Assert(!string.IsNullOrEmpty(key), $"Expected non-empty key"); + Debug.Assert(!string.IsNullOrEmpty(fallback), $"Expected non-empty fallback"); + + string? envPath = GetEnvironmentVariable(key); + if (!string.IsNullOrEmpty(envPath) && envPath[0] == '/') + { + return envPath; + } + + // Use the user-dirs.dirs file to look up the right config. + // Note that the docs also highlight a list of directories in which to look for this file: + // "$XDG_CONFIG_DIRS defines the preference-ordered set of base directories to search for configuration files in addition + // to the $XDG_CONFIG_HOME base directory. The directories in $XDG_CONFIG_DIRS should be separated with a colon ':'. If + // $XDG_CONFIG_DIRS is either not set or empty, a value equal to / etc / xdg should be used." + // For simplicity, we don't currently do that. We can add it if/when necessary. + + string userDirsPath = Path.Combine(GetXdgConfig(homeDir), "user-dirs.dirs"); + if (Interop.Sys.Access(userDirsPath, Interop.Sys.AccessMode.R_OK) == 0) + { + try + { + using (var reader = new StreamReader(userDirsPath)) + { + string? line; + while ((line = reader.ReadLine()) != null) + { + // Example lines: + // XDG_DESKTOP_DIR="$HOME/Desktop" + // XDG_PICTURES_DIR = "/absolute/path" + + // Skip past whitespace at beginning of line + int pos = 0; + SkipWhitespace(line, ref pos); + if (pos >= line.Length) continue; + + // Skip past requested key name + if (string.CompareOrdinal(line, pos, key, 0, key.Length) != 0) continue; + pos += key.Length; + + // Skip past whitespace and past '=' + SkipWhitespace(line, ref pos); + if (pos >= line.Length - 4 || line[pos] != '=') continue; // 4 for ="" and at least one char between quotes + pos++; // skip past '=' + + // Skip past whitespace and past first quote + SkipWhitespace(line, ref pos); + if (pos >= line.Length - 3 || line[pos] != '"') continue; // 3 for "" and at least one char between quotes + pos++; // skip past opening '"' + + // Skip past relative prefix if one exists + bool relativeToHome = false; + const string RelativeToHomePrefix = "$HOME/"; + if (string.CompareOrdinal(line, pos, RelativeToHomePrefix, 0, RelativeToHomePrefix.Length) == 0) + { + relativeToHome = true; + pos += RelativeToHomePrefix.Length; + } + else if (line[pos] != '/') // if not relative to home, must be absolute path + { + continue; + } + + // Find end of path + int endPos = line.IndexOf('"', pos); + if (endPos <= pos) continue; + + // Got we need. Now extract it. + string path = line.Substring(pos, endPos - pos); + return relativeToHome ? + Path.Combine(homeDir, path) : + path; + } + } + } + catch (Exception exc) + { + // assembly not found, file not found, errors reading file, etc. Just eat everything. + Debug.Fail($"Failed reading {userDirsPath}: {exc}"); + } + } + + return Path.Combine(homeDir, fallback); + } + + private static void SkipWhitespace(string line, ref int pos) + { + while (pos < line.Length && char.IsWhiteSpace(line[pos])) pos++; + } + } +} diff --git a/src/System.Private.CoreLib/shared/System/Environment.Unix.cs b/src/System.Private.CoreLib/shared/System/Environment.Unix.cs index 0d2274170..c29a56c14 100644 --- a/src/System.Private.CoreLib/shared/System/Environment.Unix.cs +++ b/src/System.Private.CoreLib/shared/System/Environment.Unix.cs @@ -2,8 +2,6 @@ // 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.Collections; -using System.Collections.Generic; using System.Diagnostics; using System.IO; using System.Reflection; @@ -15,8 +13,6 @@ namespace System { public static partial class Environment { - private static Func? s_directoryCreateDirectory; - public static bool UserInteractive => true; private static string CurrentDirectoryCore @@ -51,236 +47,6 @@ namespace System return result.ToString(); } - private static string GetFolderPathCore(SpecialFolder folder, SpecialFolderOption option) - { - // Get the path for the SpecialFolder - string path = GetFolderPathCoreWithoutValidation(folder); - Debug.Assert(path != null); - - // If we didn't get one, or if we got one but we're not supposed to verify it, - // or if we're supposed to verify it and it passes verification, return the path. - if (path.Length == 0 || - option == SpecialFolderOption.DoNotVerify || - Interop.Sys.Access(path, Interop.Sys.AccessMode.R_OK) == 0) - { - return path; - } - - // Failed verification. If None, then we're supposed to return an empty string. - // If Create, we're supposed to create it and then return the path. - if (option == SpecialFolderOption.None) - { - return string.Empty; - } - else - { - Debug.Assert(option == SpecialFolderOption.Create); - - Func createDirectory = LazyInitializer.EnsureInitialized(ref s_directoryCreateDirectory, () => - { - Type dirType = Type.GetType("System.IO.Directory, System.IO.FileSystem, Version=4.0.0.0, Culture=neutral, PublicKeyToken=b03f5f7f11d50a3a", throwOnError: true)!; - MethodInfo mi = dirType.GetTypeInfo().GetDeclaredMethod("CreateDirectory")!; - return (Func)mi.CreateDelegate(typeof(Func)); - }); - createDirectory(path); - - return path; - } - } - - private static string GetFolderPathCoreWithoutValidation(SpecialFolder folder) - { - // First handle any paths that involve only static paths, avoiding the overheads of getting user-local paths. - // https://www.freedesktop.org/software/systemd/man/file-hierarchy.html - switch (folder) - { - case SpecialFolder.CommonApplicationData: return "/usr/share"; - case SpecialFolder.CommonTemplates: return "/usr/share/templates"; -#if TARGET_OSX - case SpecialFolder.ProgramFiles: return "/Applications"; - case SpecialFolder.System: return "/System"; -#endif - } - - // All other paths are based on the XDG Base Directory Specification: - // https://specifications.freedesktop.org/basedir-spec/latest/ - string? home = null; - try - { - home = PersistedFiles.GetHomeDirectory(); - } - catch (Exception exc) - { - Debug.Fail($"Unable to get home directory: {exc}"); - } - - // Fall back to '/' when we can't determine the home directory. - // This location isn't writable by non-root users which provides some safeguard - // that the application doesn't write data which is meant to be private. - if (string.IsNullOrEmpty(home)) - { - home = "/"; - } - - // TODO: Consider caching (or precomputing and caching) all subsequent results. - // This would significantly improve performance for repeated access, at the expense - // of not being responsive to changes in the underlying environment variables, - // configuration files, etc. - - switch (folder) - { - case SpecialFolder.UserProfile: - case SpecialFolder.MyDocuments: // same value as Personal - return home; - case SpecialFolder.ApplicationData: - return GetXdgConfig(home); - case SpecialFolder.LocalApplicationData: - // "$XDG_DATA_HOME defines the base directory relative to which user specific data files should be stored." - // "If $XDG_DATA_HOME is either not set or empty, a default equal to $HOME/.local/share should be used." - string? data = GetEnvironmentVariable("XDG_DATA_HOME"); - if (string.IsNullOrEmpty(data) || data[0] != '/') - { - data = Path.Combine(home, ".local", "share"); - } - return data; - - case SpecialFolder.Desktop: - case SpecialFolder.DesktopDirectory: - return ReadXdgDirectory(home, "XDG_DESKTOP_DIR", "Desktop"); - case SpecialFolder.Templates: - return ReadXdgDirectory(home, "XDG_TEMPLATES_DIR", "Templates"); - case SpecialFolder.MyVideos: - return ReadXdgDirectory(home, "XDG_VIDEOS_DIR", "Videos"); - -#if TARGET_OSX - case SpecialFolder.MyMusic: - return Path.Combine(home, "Music"); - case SpecialFolder.MyPictures: - return Path.Combine(home, "Pictures"); - case SpecialFolder.Fonts: - return Path.Combine(home, "Library", "Fonts"); - case SpecialFolder.Favorites: - return Path.Combine(home, "Library", "Favorites"); - case SpecialFolder.InternetCache: - return Path.Combine(home, "Library", "Caches"); -#else - case SpecialFolder.MyMusic: - return ReadXdgDirectory(home, "XDG_MUSIC_DIR", "Music"); - case SpecialFolder.MyPictures: - return ReadXdgDirectory(home, "XDG_PICTURES_DIR", "Pictures"); - case SpecialFolder.Fonts: - return Path.Combine(home, ".fonts"); -#endif - } - - // No known path for the SpecialFolder - return string.Empty; - } - - private static string GetXdgConfig(string home) - { - // "$XDG_CONFIG_HOME defines the base directory relative to which user specific configuration files should be stored." - // "If $XDG_CONFIG_HOME is either not set or empty, a default equal to $HOME/.config should be used." - string? config = GetEnvironmentVariable("XDG_CONFIG_HOME"); - if (string.IsNullOrEmpty(config) || config[0] != '/') - { - config = Path.Combine(home, ".config"); - } - return config; - } - - private static string ReadXdgDirectory(string homeDir, string key, string fallback) - { - Debug.Assert(!string.IsNullOrEmpty(homeDir), $"Expected non-empty homeDir"); - Debug.Assert(!string.IsNullOrEmpty(key), $"Expected non-empty key"); - Debug.Assert(!string.IsNullOrEmpty(fallback), $"Expected non-empty fallback"); - - string? envPath = GetEnvironmentVariable(key); - if (!string.IsNullOrEmpty(envPath) && envPath[0] == '/') - { - return envPath; - } - - // Use the user-dirs.dirs file to look up the right config. - // Note that the docs also highlight a list of directories in which to look for this file: - // "$XDG_CONFIG_DIRS defines the preference-ordered set of base directories to search for configuration files in addition - // to the $XDG_CONFIG_HOME base directory. The directories in $XDG_CONFIG_DIRS should be separated with a colon ':'. If - // $XDG_CONFIG_DIRS is either not set or empty, a value equal to / etc / xdg should be used." - // For simplicity, we don't currently do that. We can add it if/when necessary. - - string userDirsPath = Path.Combine(GetXdgConfig(homeDir), "user-dirs.dirs"); - if (Interop.Sys.Access(userDirsPath, Interop.Sys.AccessMode.R_OK) == 0) - { - try - { - using (var reader = new StreamReader(userDirsPath)) - { - string? line; - while ((line = reader.ReadLine()) != null) - { - // Example lines: - // XDG_DESKTOP_DIR="$HOME/Desktop" - // XDG_PICTURES_DIR = "/absolute/path" - - // Skip past whitespace at beginning of line - int pos = 0; - SkipWhitespace(line, ref pos); - if (pos >= line.Length) continue; - - // Skip past requested key name - if (string.CompareOrdinal(line, pos, key, 0, key.Length) != 0) continue; - pos += key.Length; - - // Skip past whitespace and past '=' - SkipWhitespace(line, ref pos); - if (pos >= line.Length - 4 || line[pos] != '=') continue; // 4 for ="" and at least one char between quotes - pos++; // skip past '=' - - // Skip past whitespace and past first quote - SkipWhitespace(line, ref pos); - if (pos >= line.Length - 3 || line[pos] != '"') continue; // 3 for "" and at least one char between quotes - pos++; // skip past opening '"' - - // Skip past relative prefix if one exists - bool relativeToHome = false; - const string RelativeToHomePrefix = "$HOME/"; - if (string.CompareOrdinal(line, pos, RelativeToHomePrefix, 0, RelativeToHomePrefix.Length) == 0) - { - relativeToHome = true; - pos += RelativeToHomePrefix.Length; - } - else if (line[pos] != '/') // if not relative to home, must be absolute path - { - continue; - } - - // Find end of path - int endPos = line.IndexOf('"', pos); - if (endPos <= pos) continue; - - // Got we need. Now extract it. - string path = line.Substring(pos, endPos - pos); - return relativeToHome ? - Path.Combine(homeDir, path) : - path; - } - } - } - catch (Exception exc) - { - // assembly not found, file not found, errors reading file, etc. Just eat everything. - Debug.Fail($"Failed reading {userDirsPath}: {exc}"); - } - } - - return Path.Combine(homeDir, fallback); - } - - private static void SkipWhitespace(string line, ref int pos) - { - while (pos < line.Length && char.IsWhiteSpace(line[pos])) pos++; - } - public static string[] GetLogicalDrives() => Interop.Sys.GetAllMountPoints(); private static bool Is64BitOperatingSystemWhen32BitProcess => false; @@ -454,8 +220,8 @@ namespace System { using (currentProcess) { - object? result = processType!.GetMethod("get_WorkingSet64")?.Invoke(currentProcess, BindingFlags.DoNotWrapExceptions, null, null, null); - if (result is long) return (long)result; + if (processType!.GetMethod("get_WorkingSet64")?.Invoke(currentProcess, BindingFlags.DoNotWrapExceptions, null, null, null) is long result) + return result; } } diff --git a/src/System.Private.CoreLib/shared/System/Environment.Windows.cs b/src/System.Private.CoreLib/shared/System/Environment.Windows.cs index e4ac0a0e8..6a7bd32e4 100644 --- a/src/System.Private.CoreLib/shared/System/Environment.Windows.cs +++ b/src/System.Private.CoreLib/shared/System/Environment.Windows.cs @@ -89,16 +89,16 @@ namespace System private static unsafe OperatingSystem GetOSVersion() { - var version = new Interop.Kernel32.OSVERSIONINFOEX { dwOSVersionInfoSize = sizeof(Interop.Kernel32.OSVERSIONINFOEX) }; - if (!Interop.Kernel32.GetVersionExW(ref version)) + if (Interop.NtDll.RtlGetVersionEx(out Interop.NtDll.RTL_OSVERSIONINFOEX osvi) != 0) { throw new InvalidOperationException(SR.InvalidOperation_GetVersion); } - return new OperatingSystem( - PlatformID.Win32NT, - new Version(version.dwMajorVersion, version.dwMinorVersion, version.dwBuildNumber, (version.wServicePackMajor << 16) | version.wServicePackMinor), - Marshal.PtrToStringUni((IntPtr)version.szCSDVersion)); + var version = new Version((int)osvi.dwMajorVersion, (int)osvi.dwMinorVersion, (int)osvi.dwBuildNumber, 0); + + return osvi.szCSDVersion[0] != '\0' ? + new OperatingSystem(PlatformID.Win32NT, version, new string(&osvi.szCSDVersion[0])) : + new OperatingSystem(PlatformID.Win32NT, version); } public static string SystemDirectory diff --git a/src/System.Private.CoreLib/shared/System/Environment.cs b/src/System.Private.CoreLib/shared/System/Environment.cs index 62571701d..d3f03d051 100644 --- a/src/System.Private.CoreLib/shared/System/Environment.cs +++ b/src/System.Private.CoreLib/shared/System/Environment.cs @@ -142,10 +142,7 @@ namespace System { get { - // FX_PRODUCT_VERSION is expected to be set by the host - // Use AssemblyInformationalVersionAttribute as fallback if the exact product version is not specified by the host - string? versionString = (string?)AppContext.GetData("FX_PRODUCT_VERSION") ?? - typeof(object).Assembly.GetCustomAttribute()?.InformationalVersion; + string? versionString = typeof(object).Assembly.GetCustomAttribute()?.InformationalVersion; ReadOnlySpan versionSpan = versionString.AsSpan(); diff --git a/src/System.Private.CoreLib/shared/System/Globalization/Calendar.cs b/src/System.Private.CoreLib/shared/System/Globalization/Calendar.cs index 7d86971a8..48e34ffaa 100644 --- a/src/System.Private.CoreLib/shared/System/Globalization/Calendar.cs +++ b/src/System.Private.CoreLib/shared/System/Globalization/Calendar.cs @@ -725,7 +725,7 @@ namespace System.Globalization internal static int GetSystemTwoDigitYearSetting(CalendarId CalID, int defaultYearValue) { - int twoDigitYearMax = CalendarData.GetTwoDigitYearMax(CalID); + int twoDigitYearMax = GlobalizationMode.UseNls ? CalendarData.NlsGetTwoDigitYearMax(CalID) : CalendarData.IcuGetTwoDigitYearMax(CalID); return twoDigitYearMax >= 0 ? twoDigitYearMax : defaultYearValue; } } diff --git a/src/System.Private.CoreLib/shared/System/Globalization/CalendarData.Unix.cs b/src/System.Private.CoreLib/shared/System/Globalization/CalendarData.Icu.cs similarity index 94% rename from src/System.Private.CoreLib/shared/System/Globalization/CalendarData.Unix.cs rename to src/System.Private.CoreLib/shared/System/Globalization/CalendarData.Icu.cs index d8ed0072f..b58bc4a31 100644 --- a/src/System.Private.CoreLib/shared/System/Globalization/CalendarData.Unix.cs +++ b/src/System.Private.CoreLib/shared/System/Globalization/CalendarData.Icu.cs @@ -4,7 +4,6 @@ using System.Collections.Generic; using System.Diagnostics; -using System.Security; using System.Text; using Internal.Runtime.CompilerServices; @@ -32,8 +31,10 @@ namespace System.Globalization internal partial class CalendarData { - private bool LoadCalendarDataFromSystem(string localeName, CalendarId calendarId) + private bool IcuLoadCalendarDataFromSystem(string localeName, CalendarId calendarId) { + Debug.Assert(!GlobalizationMode.UseNls); + bool result = true; // these can return null but are later replaced with String.Empty or other non-nullable value @@ -80,17 +81,20 @@ namespace System.Globalization return result; } - internal static int GetTwoDigitYearMax(CalendarId calendarId) + internal static int IcuGetTwoDigitYearMax(CalendarId calendarId) { + Debug.Assert(!GlobalizationMode.UseNls); + // There is no user override for this value on Linux or in ICU. // So just return -1 to use the hard-coded defaults. return -1; } // Call native side to figure out which calendars are allowed - internal static int GetCalendars(string localeName, bool useUserOverride, CalendarId[] calendars) + internal static int IcuGetCalendars(string localeName, bool useUserOverride, CalendarId[] calendars) { Debug.Assert(!GlobalizationMode.Invariant); + Debug.Assert(!GlobalizationMode.UseNls); // NOTE: there are no 'user overrides' on Linux int count = Interop.Globalization.GetCalendars(localeName, calendars, calendars.Length); @@ -105,8 +109,9 @@ namespace System.Globalization return count; } - private static bool SystemSupportsTaiwaneseCalendar() + private static bool IcuSystemSupportsTaiwaneseCalendar() { + Debug.Assert(!GlobalizationMode.UseNls); return true; } @@ -134,7 +139,7 @@ namespace System.Globalization { datePatterns = null; - EnumCalendarsData callbackContext = default; + IcuEnumCalendarsData callbackContext = default; callbackContext.Results = new List(); callbackContext.DisallowDuplicates = true; bool result = EnumCalendarInfo(localeName, calendarId, dataType, ref callbackContext); @@ -359,7 +364,7 @@ namespace System.Globalization { monthNames = null; - EnumCalendarsData callbackContext = default; + IcuEnumCalendarsData callbackContext = default; callbackContext.Results = new List(); bool result = EnumCalendarInfo(localeName, calendarId, dataType, ref callbackContext); if (result) @@ -407,7 +412,7 @@ namespace System.Globalization { calendarData = null; - EnumCalendarsData callbackContext = default; + IcuEnumCalendarsData callbackContext = default; callbackContext.Results = new List(); bool result = EnumCalendarInfo(localeName, calendarId, dataType, ref callbackContext); if (result) @@ -418,7 +423,7 @@ namespace System.Globalization return result; } - private static unsafe bool EnumCalendarInfo(string localeName, CalendarId calendarId, CalendarDataType dataType, ref EnumCalendarsData callbackContext) + private static unsafe bool EnumCalendarInfo(string localeName, CalendarId calendarId, CalendarDataType dataType, ref IcuEnumCalendarsData callbackContext) { return Interop.Globalization.EnumCalendarInfo(EnumCalendarInfoCallback, localeName, calendarId, dataType, (IntPtr)Unsafe.AsPointer(ref callbackContext)); } @@ -427,7 +432,7 @@ namespace System.Globalization { try { - ref EnumCalendarsData callbackContext = ref Unsafe.As(ref *(byte*)context); + ref IcuEnumCalendarsData callbackContext = ref Unsafe.As(ref *(byte*)context); if (callbackContext.DisallowDuplicates) { @@ -451,7 +456,7 @@ namespace System.Globalization } } - private struct EnumCalendarsData + private struct IcuEnumCalendarsData { public List Results; public bool DisallowDuplicates; diff --git a/src/System.Private.CoreLib/shared/System/Globalization/CalendarData.Windows.cs b/src/System.Private.CoreLib/shared/System/Globalization/CalendarData.Nls.cs similarity index 94% rename from src/System.Private.CoreLib/shared/System/Globalization/CalendarData.Windows.cs rename to src/System.Private.CoreLib/shared/System/Globalization/CalendarData.Nls.cs index 8031df90e..79ff55073 100644 --- a/src/System.Private.CoreLib/shared/System/Globalization/CalendarData.Windows.cs +++ b/src/System.Private.CoreLib/shared/System/Globalization/CalendarData.Nls.cs @@ -10,9 +10,10 @@ namespace System.Globalization { internal partial class CalendarData { - private bool LoadCalendarDataFromSystem(string localeName, CalendarId calendarId) + private bool NlsLoadCalendarDataFromSystem(string localeName, CalendarId calendarId) { Debug.Assert(!GlobalizationMode.Invariant); + Debug.Assert(GlobalizationMode.UseNls); bool ret = true; @@ -106,17 +107,23 @@ namespace System.Globalization } // Get native two digit year max - internal static int GetTwoDigitYearMax(CalendarId calendarId) => - GlobalizationMode.Invariant ? Invariant.iTwoDigitYearMax : - CallGetCalendarInfoEx(null, calendarId, CAL_ITWODIGITYEARMAX, out int twoDigitYearMax) ? twoDigitYearMax : - -1; + internal static int NlsGetTwoDigitYearMax(CalendarId calendarId) + { + Debug.Assert(GlobalizationMode.UseNls); + + return GlobalizationMode.Invariant ? Invariant.iTwoDigitYearMax : + CallGetCalendarInfoEx(null, calendarId, CAL_ITWODIGITYEARMAX, out int twoDigitYearMax) ? + twoDigitYearMax : + -1; + } // Call native side to figure out which calendars are allowed - internal static int GetCalendars(string localeName, bool useUserOverride, CalendarId[] calendars) + internal static int NlsGetCalendars(string localeName, bool useUserOverride, CalendarId[] calendars) { Debug.Assert(!GlobalizationMode.Invariant); + Debug.Assert(GlobalizationMode.UseNls); - EnumCalendarsData data = default; + NlsEnumCalendarsData data = default; data.userOverride = 0; data.calendars = new List(); @@ -147,9 +154,10 @@ namespace System.Globalization return data.calendars.Count; } - private static bool SystemSupportsTaiwaneseCalendar() + private static bool NlsSystemSupportsTaiwaneseCalendar() { Debug.Assert(!GlobalizationMode.Invariant); + Debug.Assert(GlobalizationMode.UseNls); // Taiwanese calendar get listed as one of the optional zh-TW calendars only when having zh-TW UI return CallGetCalendarInfoEx("zh-TW", CalendarId.TAIWAN, CAL_SCALNAME, out string _); @@ -221,7 +229,7 @@ namespace System.Globalization // Taiwan calendar data is not always in all language version of OS due to Geopolical reasons. // It is only available in zh-TW localized versions of Windows. // Let's check if OS supports it. If not, fallback to Greogrian localized for Taiwan calendar. - if (!SystemSupportsTaiwaneseCalendar()) + if (!NlsSystemSupportsTaiwaneseCalendar()) { calendar = CalendarId.GREGORIAN; } @@ -410,7 +418,7 @@ namespace System.Globalization // // struct to help our calendar data enumaration callback // - private struct EnumCalendarsData + public struct NlsEnumCalendarsData { public int userOverride; // user override value (if found) public List calendars; // list of calendars found so far @@ -419,7 +427,7 @@ namespace System.Globalization // [NativeCallable(CallingConvention = CallingConvention.StdCall)] private static unsafe Interop.BOOL EnumCalendarsCallback(char* lpCalendarInfoString, uint calendar, IntPtr reserved, void* lParam) { - ref EnumCalendarsData context = ref Unsafe.As(ref *(byte*)lParam); + ref NlsEnumCalendarsData context = ref Unsafe.As(ref *(byte*)lParam); try { // If we had a user override, check to make sure this differs diff --git a/src/System.Private.CoreLib/shared/System/Globalization/CalendarData.cs b/src/System.Private.CoreLib/shared/System/Globalization/CalendarData.cs index 997cfb406..72d14b38d 100644 --- a/src/System.Private.CoreLib/shared/System/Globalization/CalendarData.cs +++ b/src/System.Private.CoreLib/shared/System/Globalization/CalendarData.cs @@ -105,7 +105,11 @@ namespace System.Globalization Debug.Assert(!GlobalizationMode.Invariant); - if (!LoadCalendarDataFromSystem(localeName, calendarId)) + bool loadedCalendarData = GlobalizationMode.UseNls ? + NlsLoadCalendarDataFromSystem(localeName, calendarId) : + IcuLoadCalendarDataFromSystem(localeName, calendarId); + + if (!loadedCalendarData) { // LoadCalendarDataFromSystem sometimes can fail on Linux if the installed ICU package is missing some resources. // The ICU package can miss some resources in some cases like if someone compile and build the ICU package manually or ICU has a regression. @@ -376,5 +380,9 @@ namespace System.Globalization return "en-US"; } + + private bool SystemSupportsTaiwaneseCalendar() => GlobalizationMode.UseNls ? + NlsSystemSupportsTaiwaneseCalendar() : + IcuSystemSupportsTaiwaneseCalendar(); } } diff --git a/src/System.Private.CoreLib/shared/System/Globalization/CharUnicodeInfoData.cs b/src/System.Private.CoreLib/shared/System/Globalization/CharUnicodeInfoData.cs index 287ceb28a..c2d876ea6 100644 --- a/src/System.Private.CoreLib/shared/System/Globalization/CharUnicodeInfoData.cs +++ b/src/System.Private.CoreLib/shared/System/Globalization/CharUnicodeInfoData.cs @@ -35,7 +35,7 @@ namespace System.Globalization 0x1a, 0x39, 0x3a, 0x3b, 0x3b, 0x3b, 0x3b, 0x3b, 0x1a, 0x1a, 0x3c, 0x3b, 0x3b, 0x3b, 0x3b, 0x3b, 0x3b, 0x3b, 0x1a, 0x3d, 0x3b, 0x3b, 0x3b, 0x3b, 0x3b, 0x3b, 0x3b, 0x3b, 0x3b, 0x3b, 0x3b, 0x3b, 0x3b, 0x3b, 0x3b, 0x3b, 0x1a, 0x3e, 0x3b, 0x3f, 0x1a, 0x1a, 0x1a, 0x1a, 0x1a, 0x1a, 0x1a, 0x1a, - 0x1a, 0x1a, 0x1a, 0x40, 0x1a, 0x41, 0x3b, 0x3b, 0x3b, 0x3b, 0x3b, 0x3b, 0x3b, 0x3b, 0x3b, 0x3b, + 0x1a, 0x1a, 0x1a, 0x40, 0x1a, 0x1a, 0x41, 0x3b, 0x3b, 0x3b, 0x3b, 0x3b, 0x3b, 0x3b, 0x3b, 0x3b, 0x3b, 0x3b, 0x3b, 0x3b, 0x3b, 0x3b, 0x3b, 0x3b, 0x42, 0x43, 0x3b, 0x3b, 0x3b, 0x3b, 0x44, 0x3b, 0x3b, 0x3b, 0x3b, 0x3b, 0x3b, 0x3b, 0x3b, 0x3b, 0x45, 0x46, 0x47, 0x48, 0x49, 0x4a, 0x3b, 0x3b, 0x4b, 0x4c, 0x3b, 0x3b, 0x4d, 0x4e, 0x4f, 0x50, 0x51, 0x52, 0x53, 0x54, 0x55, 0x56, 0x3b, 0x57, @@ -47,7 +47,7 @@ namespace System.Globalization 0x1a, 0x1a, 0x1a, 0x58, 0x1a, 0x1a, 0x1a, 0x1a, 0x1a, 0x1a, 0x1a, 0x59, 0x5a, 0x1a, 0x1a, 0x1a, 0x1a, 0x1a, 0x1a, 0x1a, 0x1a, 0x1a, 0x1a, 0x5b, 0x1a, 0x1a, 0x1a, 0x1a, 0x1a, 0x1a, 0x1a, 0x1a, 0x1a, 0x1a, 0x1a, 0x1a, 0x1a, 0x5c, 0x3b, 0x3b, 0x3b, 0x3b, 0x3b, 0x3b, 0x1a, 0x5d, 0x3b, 0x57, - 0x3b, 0x3b, 0x3b, 0x3b, 0x3b, 0x3b, 0x3b, 0x3b, 0x3b, 0x3b, 0x3b, 0x3b, 0x3b, 0x3b, 0x3b, 0x3b, + 0x1a, 0x1a, 0x1a, 0x1a, 0x1a, 0x1a, 0x1a, 0x1a, 0x1a, 0x5e, 0x3b, 0x3b, 0x3b, 0x3b, 0x3b, 0x3b, 0x3b, 0x3b, 0x3b, 0x3b, 0x3b, 0x3b, 0x3b, 0x3b, 0x3b, 0x3b, 0x3b, 0x3b, 0x3b, 0x3b, 0x3b, 0x3b, 0x3b, 0x3b, 0x3b, 0x3b, 0x3b, 0x3b, 0x3b, 0x3b, 0x3b, 0x3b, 0x3b, 0x3b, 0x3b, 0x3b, 0x3b, 0x3b, 0x3b, 0x3b, 0x3b, 0x3b, 0x3b, 0x3b, 0x3b, 0x3b, 0x3b, 0x3b, 0x3b, 0x3b, 0x3b, 0x3b, 0x3b, 0x3b, @@ -135,7 +135,7 @@ namespace System.Globalization 0x3b, 0x3b, 0x3b, 0x3b, 0x3b, 0x3b, 0x3b, 0x3b, 0x3b, 0x3b, 0x3b, 0x3b, 0x3b, 0x3b, 0x3b, 0x3b, 0x3b, 0x3b, 0x3b, 0x3b, 0x3b, 0x3b, 0x3b, 0x3b, 0x3b, 0x3b, 0x3b, 0x3b, 0x3b, 0x3b, 0x3b, 0x3b, 0x3b, 0x3b, 0x3b, 0x3b, 0x3b, 0x3b, 0x3b, 0x3b, 0x3b, 0x3b, 0x3b, 0x3b, 0x3b, 0x3b, 0x3b, 0x57, - 0x5e, 0x5f, 0x5f, 0x5f, 0x5f, 0x5f, 0x5f, 0x5f, 0x3b, 0x3b, 0x3b, 0x3b, 0x3b, 0x3b, 0x3b, 0x3b, + 0x5f, 0x60, 0x60, 0x60, 0x60, 0x60, 0x60, 0x60, 0x3b, 0x3b, 0x3b, 0x3b, 0x3b, 0x3b, 0x3b, 0x3b, 0x3b, 0x3b, 0x3b, 0x3b, 0x3b, 0x3b, 0x3b, 0x3b, 0x3b, 0x3b, 0x3b, 0x3b, 0x3b, 0x3b, 0x3b, 0x3b, 0x3b, 0x3b, 0x3b, 0x3b, 0x3b, 0x3b, 0x3b, 0x3b, 0x3b, 0x3b, 0x3b, 0x3b, 0x3b, 0x3b, 0x3b, 0x3b, 0x3b, 0x3b, 0x3b, 0x3b, 0x3b, 0x3b, 0x3b, 0x3b, 0x3b, 0x3b, 0x3b, 0x3b, 0x3b, 0x3b, 0x3b, 0x3b, @@ -150,7 +150,7 @@ namespace System.Globalization 0x24, 0x24, 0x24, 0x24, 0x24, 0x24, 0x24, 0x24, 0x24, 0x24, 0x24, 0x24, 0x24, 0x24, 0x24, 0x24, 0x24, 0x24, 0x24, 0x24, 0x24, 0x24, 0x24, 0x24, 0x24, 0x24, 0x24, 0x24, 0x24, 0x24, 0x24, 0x24, 0x24, 0x24, 0x24, 0x24, 0x24, 0x24, 0x24, 0x24, 0x24, 0x24, 0x24, 0x24, 0x24, 0x24, 0x24, 0x24, - 0x24, 0x24, 0x24, 0x24, 0x24, 0x24, 0x24, 0x24, 0x24, 0x24, 0x24, 0x24, 0x24, 0x24, 0x24, 0x60, + 0x24, 0x24, 0x24, 0x24, 0x24, 0x24, 0x24, 0x24, 0x24, 0x24, 0x24, 0x24, 0x24, 0x24, 0x24, 0x61, 0x24, 0x24, 0x24, 0x24, 0x24, 0x24, 0x24, 0x24, 0x24, 0x24, 0x24, 0x24, 0x24, 0x24, 0x24, 0x24, 0x24, 0x24, 0x24, 0x24, 0x24, 0x24, 0x24, 0x24, 0x24, 0x24, 0x24, 0x24, 0x24, 0x24, 0x24, 0x24, 0x24, 0x24, 0x24, 0x24, 0x24, 0x24, 0x24, 0x24, 0x24, 0x24, 0x24, 0x24, 0x24, 0x24, 0x24, 0x24, @@ -158,10 +158,10 @@ namespace System.Globalization 0x24, 0x24, 0x24, 0x24, 0x24, 0x24, 0x24, 0x24, 0x24, 0x24, 0x24, 0x24, 0x24, 0x24, 0x24, 0x24, 0x24, 0x24, 0x24, 0x24, 0x24, 0x24, 0x24, 0x24, 0x24, 0x24, 0x24, 0x24, 0x24, 0x24, 0x24, 0x24, 0x24, 0x24, 0x24, 0x24, 0x24, 0x24, 0x24, 0x24, 0x24, 0x24, 0x24, 0x24, 0x24, 0x24, 0x24, 0x24, - 0x24, 0x24, 0x24, 0x24, 0x24, 0x24, 0x24, 0x24, 0x24, 0x24, 0x24, 0x24, 0x24, 0x24, 0x24, 0x60 + 0x24, 0x24, 0x24, 0x24, 0x24, 0x24, 0x24, 0x24, 0x24, 0x24, 0x24, 0x24, 0x24, 0x24, 0x24, 0x61 }; - private static ReadOnlySpan CategoryCasingLevel2Index => new byte[6208] + private static ReadOnlySpan CategoryCasingLevel2Index => new byte[6272] { 0x00, 0x00, 0x01, 0x00, 0x02, 0x00, 0x03, 0x00, 0x04, 0x00, 0x05, 0x00, 0x06, 0x00, 0x07, 0x00, 0x08, 0x00, 0x01, 0x00, 0x09, 0x00, 0x0a, 0x00, 0x0b, 0x00, 0x0c, 0x00, 0x0d, 0x00, 0x0e, 0x00, @@ -180,380 +180,384 @@ namespace System.Globalization 0x3d, 0x00, 0x3e, 0x00, 0x32, 0x00, 0x22, 0x00, 0x3f, 0x00, 0x32, 0x00, 0x32, 0x00, 0x32, 0x00, 0x32, 0x00, 0x32, 0x00, 0x40, 0x00, 0x41, 0x00, 0x42, 0x00, 0x32, 0x00, 0x43, 0x00, 0x44, 0x00, 0x32, 0x00, 0x45, 0x00, 0x46, 0x00, 0x47, 0x00, 0x32, 0x00, 0x48, 0x00, 0x49, 0x00, 0x4a, 0x00, - 0x4a, 0x00, 0x4a, 0x00, 0x32, 0x00, 0x4b, 0x00, 0x4a, 0x00, 0x4c, 0x00, 0x4d, 0x00, 0x22, 0x00, - 0x4e, 0x00, 0x4f, 0x00, 0x4f, 0x00, 0x50, 0x00, 0x51, 0x00, 0x52, 0x00, 0x53, 0x00, 0x54, 0x00, - 0x55, 0x00, 0x56, 0x00, 0x57, 0x00, 0x58, 0x00, 0x59, 0x00, 0x5a, 0x00, 0x5b, 0x00, 0x5c, 0x00, - 0x5d, 0x00, 0x56, 0x00, 0x57, 0x00, 0x5e, 0x00, 0x5f, 0x00, 0x60, 0x00, 0x61, 0x00, 0x62, 0x00, - 0x63, 0x00, 0x64, 0x00, 0x57, 0x00, 0x65, 0x00, 0x66, 0x00, 0x67, 0x00, 0x5b, 0x00, 0x68, 0x00, - 0x69, 0x00, 0x56, 0x00, 0x57, 0x00, 0x6a, 0x00, 0x6b, 0x00, 0x6c, 0x00, 0x5b, 0x00, 0x6d, 0x00, - 0x6e, 0x00, 0x6f, 0x00, 0x70, 0x00, 0x71, 0x00, 0x72, 0x00, 0x73, 0x00, 0x61, 0x00, 0x74, 0x00, - 0x75, 0x00, 0x76, 0x00, 0x57, 0x00, 0x77, 0x00, 0x78, 0x00, 0x79, 0x00, 0x5b, 0x00, 0x7a, 0x00, - 0x7b, 0x00, 0x76, 0x00, 0x57, 0x00, 0x7c, 0x00, 0x7d, 0x00, 0x7e, 0x00, 0x5b, 0x00, 0x7f, 0x00, - 0x80, 0x00, 0x76, 0x00, 0x4f, 0x00, 0x81, 0x00, 0x82, 0x00, 0x83, 0x00, 0x5b, 0x00, 0x84, 0x00, - 0x85, 0x00, 0x86, 0x00, 0x4f, 0x00, 0x87, 0x00, 0x88, 0x00, 0x89, 0x00, 0x61, 0x00, 0x8a, 0x00, - 0x8b, 0x00, 0x4f, 0x00, 0x4f, 0x00, 0x8c, 0x00, 0x8d, 0x00, 0x8e, 0x00, 0x8f, 0x00, 0x8f, 0x00, - 0x90, 0x00, 0x4f, 0x00, 0x91, 0x00, 0x92, 0x00, 0x93, 0x00, 0x94, 0x00, 0x8f, 0x00, 0x8f, 0x00, - 0x95, 0x00, 0x96, 0x00, 0x97, 0x00, 0x98, 0x00, 0x99, 0x00, 0x4f, 0x00, 0x9a, 0x00, 0x9b, 0x00, - 0x9c, 0x00, 0x9d, 0x00, 0x22, 0x00, 0x9e, 0x00, 0x9f, 0x00, 0xa0, 0x00, 0x8f, 0x00, 0x8f, 0x00, - 0x4f, 0x00, 0x4f, 0x00, 0xa1, 0x00, 0xa2, 0x00, 0xa3, 0x00, 0xa4, 0x00, 0xa5, 0x00, 0xa6, 0x00, - 0xa7, 0x00, 0xa8, 0x00, 0x0b, 0x00, 0x0b, 0x00, 0xa9, 0x00, 0x0d, 0x00, 0x0d, 0x00, 0xaa, 0x00, - 0x4f, 0x00, 0x4f, 0x00, 0x4f, 0x00, 0x4f, 0x00, 0x4f, 0x00, 0x4f, 0x00, 0x4f, 0x00, 0x4f, 0x00, - 0x4f, 0x00, 0x4f, 0x00, 0x4f, 0x00, 0x4f, 0x00, 0x4f, 0x00, 0x4f, 0x00, 0x4f, 0x00, 0x4f, 0x00, - 0x4f, 0x00, 0x4f, 0x00, 0x4f, 0x00, 0x4f, 0x00, 0xab, 0x00, 0xac, 0x00, 0x4f, 0x00, 0x4f, 0x00, - 0xab, 0x00, 0x4f, 0x00, 0x4f, 0x00, 0xad, 0x00, 0xae, 0x00, 0xaf, 0x00, 0x4f, 0x00, 0x4f, 0x00, - 0x4f, 0x00, 0xae, 0x00, 0x4f, 0x00, 0x4f, 0x00, 0x4f, 0x00, 0xb0, 0x00, 0xb1, 0x00, 0xb2, 0x00, - 0x4f, 0x00, 0xb3, 0x00, 0x0b, 0x00, 0x0b, 0x00, 0x0b, 0x00, 0x0b, 0x00, 0x0b, 0x00, 0xb4, 0x00, - 0xb5, 0x00, 0x4f, 0x00, 0x4f, 0x00, 0x4f, 0x00, 0x4f, 0x00, 0x4f, 0x00, 0x4f, 0x00, 0x4f, 0x00, - 0x4f, 0x00, 0x4f, 0x00, 0x4f, 0x00, 0x4f, 0x00, 0x4f, 0x00, 0x4f, 0x00, 0x4f, 0x00, 0x4f, 0x00, - 0x4f, 0x00, 0x4f, 0x00, 0x4f, 0x00, 0x4f, 0x00, 0x4f, 0x00, 0x4f, 0x00, 0x4f, 0x00, 0x4f, 0x00, - 0x4f, 0x00, 0x4f, 0x00, 0x4f, 0x00, 0x4f, 0x00, 0x4f, 0x00, 0x4f, 0x00, 0x4f, 0x00, 0x4f, 0x00, - 0x4f, 0x00, 0x4f, 0x00, 0x4f, 0x00, 0x4f, 0x00, 0x4f, 0x00, 0x4f, 0x00, 0xb6, 0x00, 0x4f, 0x00, - 0xb7, 0x00, 0xb8, 0x00, 0x4f, 0x00, 0x4f, 0x00, 0x4f, 0x00, 0x4f, 0x00, 0xb9, 0x00, 0xba, 0x00, - 0xbb, 0x00, 0xbc, 0x00, 0x4f, 0x00, 0xbd, 0x00, 0x4f, 0x00, 0xbe, 0x00, 0xbb, 0x00, 0xbf, 0x00, - 0x4f, 0x00, 0x4f, 0x00, 0x4f, 0x00, 0xc0, 0x00, 0xc1, 0x00, 0xc2, 0x00, 0xc3, 0x00, 0xc4, 0x00, - 0xc5, 0x00, 0xc3, 0x00, 0x4f, 0x00, 0x4f, 0x00, 0xc6, 0x00, 0x4f, 0x00, 0x4f, 0x00, 0xc7, 0x00, - 0xc8, 0x00, 0x4f, 0x00, 0xc9, 0x00, 0x4f, 0x00, 0x4f, 0x00, 0x4f, 0x00, 0x4f, 0x00, 0xca, 0x00, - 0x4f, 0x00, 0xcb, 0x00, 0xcc, 0x00, 0xcd, 0x00, 0xce, 0x00, 0x4f, 0x00, 0xcf, 0x00, 0xd0, 0x00, - 0x4f, 0x00, 0x4f, 0x00, 0xd1, 0x00, 0x4f, 0x00, 0xd2, 0x00, 0xd3, 0x00, 0xd4, 0x00, 0xd4, 0x00, - 0x4f, 0x00, 0xd5, 0x00, 0x4f, 0x00, 0x4f, 0x00, 0x4f, 0x00, 0xd6, 0x00, 0xd7, 0x00, 0xd8, 0x00, - 0xc3, 0x00, 0xc3, 0x00, 0xd9, 0x00, 0xda, 0x00, 0x8f, 0x00, 0x8f, 0x00, 0x8f, 0x00, 0x8f, 0x00, - 0xdb, 0x00, 0x4f, 0x00, 0x4f, 0x00, 0xdc, 0x00, 0xdd, 0x00, 0xa3, 0x00, 0xde, 0x00, 0xdf, 0x00, - 0xe0, 0x00, 0x4f, 0x00, 0xe1, 0x00, 0xe2, 0x00, 0x4f, 0x00, 0x4f, 0x00, 0xe3, 0x00, 0xe4, 0x00, - 0x4f, 0x00, 0x4f, 0x00, 0xe5, 0x00, 0xe6, 0x00, 0xe7, 0x00, 0xe2, 0x00, 0x4f, 0x00, 0xe8, 0x00, - 0xe9, 0x00, 0x0b, 0x00, 0x0b, 0x00, 0xea, 0x00, 0xeb, 0x00, 0xec, 0x00, 0xed, 0x00, 0xee, 0x00, - 0x0d, 0x00, 0x0d, 0x00, 0xef, 0x00, 0xf0, 0x00, 0xf0, 0x00, 0xf0, 0x00, 0xf1, 0x00, 0xf2, 0x00, - 0x0d, 0x00, 0xf3, 0x00, 0xf0, 0x00, 0xf0, 0x00, 0x22, 0x00, 0x22, 0x00, 0x22, 0x00, 0xf4, 0x00, + 0x4a, 0x00, 0x4a, 0x00, 0x32, 0x00, 0x4b, 0x00, 0x4c, 0x00, 0x4d, 0x00, 0x4e, 0x00, 0x22, 0x00, + 0x4f, 0x00, 0x50, 0x00, 0x50, 0x00, 0x51, 0x00, 0x52, 0x00, 0x53, 0x00, 0x54, 0x00, 0x55, 0x00, + 0x56, 0x00, 0x57, 0x00, 0x58, 0x00, 0x59, 0x00, 0x5a, 0x00, 0x5b, 0x00, 0x5c, 0x00, 0x5d, 0x00, + 0x5e, 0x00, 0x57, 0x00, 0x58, 0x00, 0x5f, 0x00, 0x60, 0x00, 0x61, 0x00, 0x62, 0x00, 0x63, 0x00, + 0x64, 0x00, 0x65, 0x00, 0x58, 0x00, 0x66, 0x00, 0x67, 0x00, 0x68, 0x00, 0x5c, 0x00, 0x69, 0x00, + 0x6a, 0x00, 0x57, 0x00, 0x58, 0x00, 0x6b, 0x00, 0x6c, 0x00, 0x6d, 0x00, 0x5c, 0x00, 0x6e, 0x00, + 0x6f, 0x00, 0x70, 0x00, 0x71, 0x00, 0x72, 0x00, 0x73, 0x00, 0x74, 0x00, 0x62, 0x00, 0x75, 0x00, + 0x76, 0x00, 0x77, 0x00, 0x58, 0x00, 0x78, 0x00, 0x79, 0x00, 0x7a, 0x00, 0x5c, 0x00, 0x7b, 0x00, + 0x7c, 0x00, 0x77, 0x00, 0x58, 0x00, 0x7d, 0x00, 0x7e, 0x00, 0x7f, 0x00, 0x5c, 0x00, 0x80, 0x00, + 0x81, 0x00, 0x77, 0x00, 0x50, 0x00, 0x82, 0x00, 0x83, 0x00, 0x84, 0x00, 0x5c, 0x00, 0x85, 0x00, + 0x86, 0x00, 0x87, 0x00, 0x50, 0x00, 0x88, 0x00, 0x89, 0x00, 0x8a, 0x00, 0x62, 0x00, 0x8b, 0x00, + 0x8c, 0x00, 0x50, 0x00, 0x50, 0x00, 0x8d, 0x00, 0x8e, 0x00, 0x8f, 0x00, 0x90, 0x00, 0x90, 0x00, + 0x91, 0x00, 0x50, 0x00, 0x92, 0x00, 0x93, 0x00, 0x94, 0x00, 0x95, 0x00, 0x90, 0x00, 0x90, 0x00, + 0x96, 0x00, 0x97, 0x00, 0x98, 0x00, 0x99, 0x00, 0x9a, 0x00, 0x50, 0x00, 0x9b, 0x00, 0x9c, 0x00, + 0x9d, 0x00, 0x9e, 0x00, 0x22, 0x00, 0x9f, 0x00, 0xa0, 0x00, 0xa1, 0x00, 0x90, 0x00, 0x90, 0x00, + 0x50, 0x00, 0x50, 0x00, 0xa2, 0x00, 0xa3, 0x00, 0xa4, 0x00, 0xa5, 0x00, 0xa6, 0x00, 0xa7, 0x00, + 0xa8, 0x00, 0xa9, 0x00, 0x0b, 0x00, 0x0b, 0x00, 0xaa, 0x00, 0x0d, 0x00, 0x0d, 0x00, 0xab, 0x00, + 0x50, 0x00, 0x50, 0x00, 0x50, 0x00, 0x50, 0x00, 0x50, 0x00, 0x50, 0x00, 0x50, 0x00, 0x50, 0x00, + 0x50, 0x00, 0x50, 0x00, 0x50, 0x00, 0x50, 0x00, 0x50, 0x00, 0x50, 0x00, 0x50, 0x00, 0x50, 0x00, + 0x50, 0x00, 0x50, 0x00, 0x50, 0x00, 0x50, 0x00, 0xac, 0x00, 0xad, 0x00, 0x50, 0x00, 0x50, 0x00, + 0xac, 0x00, 0x50, 0x00, 0x50, 0x00, 0xae, 0x00, 0xaf, 0x00, 0xb0, 0x00, 0x50, 0x00, 0x50, 0x00, + 0x50, 0x00, 0xaf, 0x00, 0x50, 0x00, 0x50, 0x00, 0x50, 0x00, 0xb1, 0x00, 0xb2, 0x00, 0xb3, 0x00, + 0x50, 0x00, 0xb4, 0x00, 0x0b, 0x00, 0x0b, 0x00, 0x0b, 0x00, 0x0b, 0x00, 0x0b, 0x00, 0xb5, 0x00, + 0xb6, 0x00, 0x50, 0x00, 0x50, 0x00, 0x50, 0x00, 0x50, 0x00, 0x50, 0x00, 0x50, 0x00, 0x50, 0x00, + 0x50, 0x00, 0x50, 0x00, 0x50, 0x00, 0x50, 0x00, 0x50, 0x00, 0x50, 0x00, 0x50, 0x00, 0x50, 0x00, + 0x50, 0x00, 0x50, 0x00, 0x50, 0x00, 0x50, 0x00, 0x50, 0x00, 0x50, 0x00, 0x50, 0x00, 0x50, 0x00, + 0x50, 0x00, 0x50, 0x00, 0x50, 0x00, 0x50, 0x00, 0x50, 0x00, 0x50, 0x00, 0x50, 0x00, 0x50, 0x00, + 0x50, 0x00, 0x50, 0x00, 0x50, 0x00, 0x50, 0x00, 0x50, 0x00, 0x50, 0x00, 0xb7, 0x00, 0x50, 0x00, + 0xb8, 0x00, 0xb9, 0x00, 0x50, 0x00, 0x50, 0x00, 0x50, 0x00, 0x50, 0x00, 0xba, 0x00, 0xbb, 0x00, + 0xbc, 0x00, 0xbd, 0x00, 0x50, 0x00, 0xbe, 0x00, 0x50, 0x00, 0xbf, 0x00, 0xbc, 0x00, 0xc0, 0x00, + 0x50, 0x00, 0x50, 0x00, 0x50, 0x00, 0xc1, 0x00, 0xc2, 0x00, 0xc3, 0x00, 0xc4, 0x00, 0xc5, 0x00, + 0xc6, 0x00, 0xc4, 0x00, 0x50, 0x00, 0x50, 0x00, 0xc7, 0x00, 0x50, 0x00, 0x50, 0x00, 0xc8, 0x00, + 0xc9, 0x00, 0x50, 0x00, 0xca, 0x00, 0x50, 0x00, 0x50, 0x00, 0x50, 0x00, 0x50, 0x00, 0xcb, 0x00, + 0x50, 0x00, 0xcc, 0x00, 0xcd, 0x00, 0xce, 0x00, 0xcf, 0x00, 0x50, 0x00, 0xd0, 0x00, 0xd1, 0x00, + 0x50, 0x00, 0x50, 0x00, 0xd2, 0x00, 0x50, 0x00, 0xd3, 0x00, 0xd4, 0x00, 0xd5, 0x00, 0xd5, 0x00, + 0x50, 0x00, 0xd6, 0x00, 0x50, 0x00, 0x50, 0x00, 0x50, 0x00, 0xd7, 0x00, 0xd8, 0x00, 0xd9, 0x00, + 0xc4, 0x00, 0xc4, 0x00, 0xda, 0x00, 0xdb, 0x00, 0xdc, 0x00, 0x90, 0x00, 0x90, 0x00, 0x90, 0x00, + 0xdd, 0x00, 0x50, 0x00, 0x50, 0x00, 0xde, 0x00, 0xdf, 0x00, 0xa4, 0x00, 0xe0, 0x00, 0xe1, 0x00, + 0xe2, 0x00, 0x50, 0x00, 0xe3, 0x00, 0xe4, 0x00, 0x50, 0x00, 0x50, 0x00, 0xe5, 0x00, 0xe6, 0x00, + 0x50, 0x00, 0x50, 0x00, 0xe7, 0x00, 0xe8, 0x00, 0xe9, 0x00, 0xe4, 0x00, 0x50, 0x00, 0xea, 0x00, + 0xeb, 0x00, 0x0b, 0x00, 0x0b, 0x00, 0xec, 0x00, 0xed, 0x00, 0xee, 0x00, 0xef, 0x00, 0xf0, 0x00, + 0x0d, 0x00, 0x0d, 0x00, 0xf1, 0x00, 0xf2, 0x00, 0xf2, 0x00, 0xf2, 0x00, 0xf3, 0x00, 0xf4, 0x00, + 0x0d, 0x00, 0xf5, 0x00, 0xf2, 0x00, 0xf2, 0x00, 0x22, 0x00, 0x22, 0x00, 0x22, 0x00, 0xf6, 0x00, 0x0f, 0x00, 0x0f, 0x00, 0x0f, 0x00, 0x0f, 0x00, 0x0f, 0x00, 0x0f, 0x00, 0x0f, 0x00, 0x0f, 0x00, - 0x0f, 0x00, 0xf5, 0x00, 0x0f, 0x00, 0x0f, 0x00, 0x0f, 0x00, 0x0f, 0x00, 0x0f, 0x00, 0x0f, 0x00, - 0xf6, 0x00, 0xf7, 0x00, 0xf6, 0x00, 0xf6, 0x00, 0xf7, 0x00, 0xf8, 0x00, 0xf6, 0x00, 0xf9, 0x00, - 0xfa, 0x00, 0xfa, 0x00, 0xfa, 0x00, 0xfb, 0x00, 0xfc, 0x00, 0xfd, 0x00, 0xfe, 0x00, 0xff, 0x00, - 0x00, 0x01, 0x01, 0x01, 0x02, 0x01, 0x03, 0x01, 0x04, 0x01, 0x05, 0x01, 0x06, 0x01, 0x07, 0x01, - 0x08, 0x01, 0x09, 0x01, 0x0a, 0x01, 0x0a, 0x01, 0x0b, 0x01, 0x0c, 0x01, 0x0d, 0x01, 0x0e, 0x01, - 0x0f, 0x01, 0x10, 0x01, 0x11, 0x01, 0x12, 0x01, 0x13, 0x01, 0x14, 0x01, 0x15, 0x01, 0x15, 0x01, - 0x16, 0x01, 0x17, 0x01, 0x18, 0x01, 0xd4, 0x00, 0x19, 0x01, 0x1a, 0x01, 0xd4, 0x00, 0x1b, 0x01, - 0x1c, 0x01, 0x1c, 0x01, 0x1c, 0x01, 0x1c, 0x01, 0x1c, 0x01, 0x1c, 0x01, 0x1c, 0x01, 0x1c, 0x01, - 0x1c, 0x01, 0x1c, 0x01, 0x1c, 0x01, 0x1c, 0x01, 0x1c, 0x01, 0x1c, 0x01, 0x1c, 0x01, 0x1c, 0x01, - 0x1d, 0x01, 0xd4, 0x00, 0x1e, 0x01, 0x1f, 0x01, 0x20, 0x01, 0x20, 0x01, 0x20, 0x01, 0x21, 0x01, - 0xd4, 0x00, 0x22, 0x01, 0x1c, 0x01, 0x23, 0x01, 0xd4, 0x00, 0x24, 0x01, 0x25, 0x01, 0xd4, 0x00, - 0xd4, 0x00, 0xd4, 0x00, 0x26, 0x01, 0x8f, 0x00, 0x27, 0x01, 0x8f, 0x00, 0x14, 0x01, 0x14, 0x01, - 0x14, 0x01, 0x28, 0x01, 0x20, 0x01, 0x20, 0x01, 0x20, 0x01, 0x20, 0x01, 0x29, 0x01, 0x14, 0x01, - 0xd4, 0x00, 0xd4, 0x00, 0xd4, 0x00, 0xd4, 0x00, 0xd4, 0x00, 0xd4, 0x00, 0xd4, 0x00, 0xd4, 0x00, - 0xd4, 0x00, 0xd4, 0x00, 0xd4, 0x00, 0x2a, 0x01, 0x2b, 0x01, 0xd4, 0x00, 0xd4, 0x00, 0x2c, 0x01, - 0xd4, 0x00, 0xd4, 0x00, 0xd4, 0x00, 0xd4, 0x00, 0xd4, 0x00, 0xd4, 0x00, 0x2d, 0x01, 0xd4, 0x00, - 0xd4, 0x00, 0xd4, 0x00, 0x2e, 0x01, 0xd4, 0x00, 0xd4, 0x00, 0xd4, 0x00, 0xd4, 0x00, 0xd4, 0x00, - 0xd4, 0x00, 0xd4, 0x00, 0xd4, 0x00, 0xd4, 0x00, 0xd4, 0x00, 0xd4, 0x00, 0x2f, 0x01, 0x30, 0x01, - 0x14, 0x01, 0x31, 0x01, 0xd4, 0x00, 0xd4, 0x00, 0x32, 0x01, 0x1c, 0x01, 0x33, 0x01, 0x1c, 0x01, - 0x20, 0x01, 0x20, 0x01, 0x20, 0x01, 0x20, 0x01, 0x20, 0x01, 0x20, 0x01, 0x20, 0x01, 0x20, 0x01, - 0x20, 0x01, 0x20, 0x01, 0x20, 0x01, 0x20, 0x01, 0x20, 0x01, 0x20, 0x01, 0x20, 0x01, 0x20, 0x01, - 0x1c, 0x01, 0x1c, 0x01, 0x1c, 0x01, 0x1c, 0x01, 0x1c, 0x01, 0x1c, 0x01, 0x1c, 0x01, 0x1c, 0x01, - 0x34, 0x01, 0x35, 0x01, 0x1c, 0x01, 0x1c, 0x01, 0x1c, 0x01, 0x36, 0x01, 0x1c, 0x01, 0x37, 0x01, - 0x1c, 0x01, 0x1c, 0x01, 0x1c, 0x01, 0x1c, 0x01, 0x1c, 0x01, 0x1c, 0x01, 0x1c, 0x01, 0x1c, 0x01, - 0x1c, 0x01, 0x1c, 0x01, 0x1c, 0x01, 0x1c, 0x01, 0x1c, 0x01, 0x1c, 0x01, 0x1c, 0x01, 0x1c, 0x01, - 0xd4, 0x00, 0xd4, 0x00, 0xd4, 0x00, 0x1c, 0x01, 0x38, 0x01, 0xd4, 0x00, 0xd4, 0x00, 0x39, 0x01, - 0xd4, 0x00, 0x3a, 0x01, 0xd4, 0x00, 0xd4, 0x00, 0xd4, 0x00, 0xd4, 0x00, 0xd4, 0x00, 0xd4, 0x00, - 0x0b, 0x00, 0x0b, 0x00, 0x3b, 0x01, 0x0d, 0x00, 0x0d, 0x00, 0x3c, 0x01, 0x3d, 0x01, 0x3e, 0x01, - 0x0f, 0x00, 0x0f, 0x00, 0x0f, 0x00, 0x0f, 0x00, 0x0f, 0x00, 0x0f, 0x00, 0x3f, 0x01, 0x40, 0x01, - 0x0d, 0x00, 0x0d, 0x00, 0x41, 0x01, 0x4f, 0x00, 0x4f, 0x00, 0x4f, 0x00, 0x42, 0x01, 0x43, 0x01, - 0x4f, 0x00, 0x44, 0x01, 0x45, 0x01, 0x45, 0x01, 0x45, 0x01, 0x45, 0x01, 0x22, 0x00, 0x22, 0x00, - 0x46, 0x01, 0x47, 0x01, 0x48, 0x01, 0x49, 0x01, 0x4a, 0x01, 0x8f, 0x00, 0x8f, 0x00, 0x8f, 0x00, - 0xd4, 0x00, 0x4b, 0x01, 0xd4, 0x00, 0xd4, 0x00, 0xd4, 0x00, 0xd4, 0x00, 0xd4, 0x00, 0x4c, 0x01, - 0xd4, 0x00, 0xd4, 0x00, 0xd4, 0x00, 0xd4, 0x00, 0xd4, 0x00, 0xd4, 0x00, 0xd4, 0x00, 0xd4, 0x00, - 0xd4, 0x00, 0xd4, 0x00, 0xd4, 0x00, 0xd4, 0x00, 0xd4, 0x00, 0x4d, 0x01, 0x8f, 0x00, 0x4e, 0x01, - 0x4f, 0x01, 0x50, 0x01, 0x51, 0x01, 0x52, 0x01, 0x8b, 0x00, 0x4f, 0x00, 0x4f, 0x00, 0x4f, 0x00, - 0x4f, 0x00, 0x53, 0x01, 0xb5, 0x00, 0x4f, 0x00, 0x4f, 0x00, 0x4f, 0x00, 0x4f, 0x00, 0x54, 0x01, - 0x55, 0x01, 0x4f, 0x00, 0x4f, 0x00, 0x8b, 0x00, 0x4f, 0x00, 0x4f, 0x00, 0x4f, 0x00, 0x4f, 0x00, - 0xcb, 0x00, 0x56, 0x01, 0x4f, 0x00, 0x57, 0x01, 0xd4, 0x00, 0xd4, 0x00, 0x4c, 0x01, 0x4f, 0x00, - 0x20, 0x01, 0x58, 0x01, 0x59, 0x01, 0x20, 0x01, 0x5a, 0x01, 0x5b, 0x01, 0x20, 0x01, 0x5c, 0x01, - 0x59, 0x01, 0x20, 0x01, 0x20, 0x01, 0x5d, 0x01, 0x5e, 0x01, 0x20, 0x01, 0x20, 0x01, 0x20, 0x01, - 0x20, 0x01, 0x20, 0x01, 0x20, 0x01, 0x20, 0x01, 0x20, 0x01, 0x20, 0x01, 0x20, 0x01, 0x5f, 0x01, - 0x20, 0x01, 0x20, 0x01, 0x20, 0x01, 0x20, 0x01, 0x20, 0x01, 0x60, 0x01, 0x20, 0x01, 0x61, 0x01, - 0x4f, 0x00, 0x4f, 0x00, 0x4f, 0x00, 0x4f, 0x00, 0x4f, 0x00, 0x4f, 0x00, 0x4f, 0x00, 0x4f, 0x00, - 0x4f, 0x00, 0x4f, 0x00, 0x4f, 0x00, 0x4f, 0x00, 0x4f, 0x00, 0x4f, 0x00, 0x4f, 0x00, 0x4f, 0x00, - 0x4f, 0x00, 0x4f, 0x00, 0x4f, 0x00, 0x4f, 0x00, 0x4f, 0x00, 0x4f, 0x00, 0x4f, 0x00, 0x4f, 0x00, - 0x4f, 0x00, 0x4f, 0x00, 0x4f, 0x00, 0x4f, 0x00, 0x4f, 0x00, 0x4f, 0x00, 0x4f, 0x00, 0x4f, 0x00, - 0x4f, 0x00, 0x4f, 0x00, 0x4f, 0x00, 0x4f, 0x00, 0x4f, 0x00, 0x4f, 0x00, 0x4f, 0x00, 0x4f, 0x00, - 0x4f, 0x00, 0x4f, 0x00, 0x4f, 0x00, 0x4f, 0x00, 0x4f, 0x00, 0x4f, 0x00, 0x4f, 0x00, 0x4f, 0x00, - 0x4f, 0x00, 0x4f, 0x00, 0x4f, 0x00, 0x4f, 0x00, 0x4f, 0x00, 0x4f, 0x00, 0x4f, 0x00, 0x4f, 0x00, - 0x4f, 0x00, 0x4f, 0x00, 0x4f, 0x00, 0xca, 0x00, 0xd4, 0x00, 0xd4, 0x00, 0xd4, 0x00, 0xd4, 0x00, - 0x4f, 0x00, 0x4f, 0x00, 0x4f, 0x00, 0x4f, 0x00, 0x4f, 0x00, 0x4f, 0x00, 0x4f, 0x00, 0x4f, 0x00, - 0x4f, 0x00, 0x4f, 0x00, 0x4f, 0x00, 0x4f, 0x00, 0x4f, 0x00, 0x4f, 0x00, 0x4f, 0x00, 0x4f, 0x00, - 0x4f, 0x00, 0x4f, 0x00, 0x4f, 0x00, 0x4f, 0x00, 0x4f, 0x00, 0x4f, 0x00, 0x4f, 0x00, 0x4f, 0x00, - 0x4f, 0x00, 0x4f, 0x00, 0x4f, 0x00, 0x4f, 0x00, 0x4f, 0x00, 0x4f, 0x00, 0x4f, 0x00, 0x8f, 0x00, - 0x4f, 0x00, 0x62, 0x01, 0x4f, 0x00, 0x4f, 0x00, 0x4f, 0x00, 0x4f, 0x00, 0x4f, 0x00, 0x4f, 0x00, - 0x4f, 0x00, 0x4f, 0x00, 0x4f, 0x00, 0x4f, 0x00, 0x4f, 0x00, 0x4f, 0x00, 0x4f, 0x00, 0x4f, 0x00, - 0x4f, 0x00, 0x4f, 0x00, 0x4f, 0x00, 0x4f, 0x00, 0x4f, 0x00, 0x4f, 0x00, 0x4f, 0x00, 0x4f, 0x00, - 0x4f, 0x00, 0x4f, 0x00, 0x4f, 0x00, 0x4f, 0x00, 0x4f, 0x00, 0x4f, 0x00, 0x4f, 0x00, 0x4f, 0x00, - 0x4f, 0x00, 0x4f, 0x00, 0x4f, 0x00, 0x4f, 0x00, 0x4f, 0x00, 0x4f, 0x00, 0x4f, 0x00, 0x4f, 0x00, - 0x9a, 0x00, 0xd4, 0x00, 0xd4, 0x00, 0xd4, 0x00, 0x26, 0x01, 0x4f, 0x00, 0x4f, 0x00, 0xe8, 0x00, - 0x4f, 0x00, 0x4f, 0x00, 0x4f, 0x00, 0x4f, 0x00, 0x4f, 0x00, 0x4f, 0x00, 0x4f, 0x00, 0x4f, 0x00, - 0x4f, 0x00, 0x4f, 0x00, 0x4f, 0x00, 0x4f, 0x00, 0x4f, 0x00, 0x4f, 0x00, 0x4f, 0x00, 0x4f, 0x00, - 0x63, 0x01, 0x4f, 0x00, 0x64, 0x01, 0x8f, 0x00, 0x0f, 0x00, 0x0f, 0x00, 0x65, 0x01, 0x66, 0x01, - 0x0f, 0x00, 0x67, 0x01, 0x4f, 0x00, 0x4f, 0x00, 0x4f, 0x00, 0x4f, 0x00, 0x68, 0x01, 0x69, 0x01, - 0x21, 0x00, 0x6a, 0x01, 0x6b, 0x01, 0x6c, 0x01, 0x0f, 0x00, 0x0f, 0x00, 0x0f, 0x00, 0x6d, 0x01, - 0x6e, 0x01, 0x6f, 0x01, 0x70, 0x01, 0x71, 0x01, 0x72, 0x01, 0x8f, 0x00, 0x8f, 0x00, 0x73, 0x01, - 0x74, 0x01, 0x4f, 0x00, 0x75, 0x01, 0x76, 0x01, 0x4f, 0x00, 0x4f, 0x00, 0x4f, 0x00, 0x77, 0x01, - 0x78, 0x01, 0x4f, 0x00, 0x4f, 0x00, 0x79, 0x01, 0x7a, 0x01, 0xc3, 0x00, 0x22, 0x00, 0x7b, 0x01, - 0xe2, 0x00, 0x4f, 0x00, 0x7c, 0x01, 0x4f, 0x00, 0x7d, 0x01, 0x7e, 0x01, 0x4f, 0x00, 0x9a, 0x00, - 0x4e, 0x00, 0x4f, 0x00, 0x4f, 0x00, 0x7f, 0x01, 0x80, 0x01, 0x81, 0x01, 0x82, 0x01, 0x83, 0x01, - 0x4f, 0x00, 0x4f, 0x00, 0x84, 0x01, 0x85, 0x01, 0x86, 0x01, 0x87, 0x01, 0x4f, 0x00, 0x88, 0x01, - 0x4f, 0x00, 0x4f, 0x00, 0x4f, 0x00, 0x89, 0x01, 0x8a, 0x01, 0x8b, 0x01, 0x8c, 0x01, 0x8d, 0x01, - 0x8e, 0x01, 0x8f, 0x01, 0x45, 0x01, 0x0d, 0x00, 0x0d, 0x00, 0x90, 0x01, 0x91, 0x01, 0x0d, 0x00, - 0x0d, 0x00, 0x0d, 0x00, 0x0d, 0x00, 0x0d, 0x00, 0x4f, 0x00, 0x4f, 0x00, 0x92, 0x01, 0xc3, 0x00, - 0x4f, 0x00, 0x4f, 0x00, 0x4f, 0x00, 0x4f, 0x00, 0x4f, 0x00, 0x4f, 0x00, 0x4f, 0x00, 0x4f, 0x00, - 0x4f, 0x00, 0x4f, 0x00, 0x4f, 0x00, 0x4f, 0x00, 0x4f, 0x00, 0x4f, 0x00, 0x4f, 0x00, 0x4f, 0x00, - 0x4f, 0x00, 0x4f, 0x00, 0x4f, 0x00, 0x4f, 0x00, 0x4f, 0x00, 0x4f, 0x00, 0x4f, 0x00, 0x4f, 0x00, - 0x4f, 0x00, 0x4f, 0x00, 0x93, 0x01, 0x4f, 0x00, 0x94, 0x01, 0x4f, 0x00, 0x4f, 0x00, 0xd1, 0x00, - 0x95, 0x01, 0x95, 0x01, 0x95, 0x01, 0x95, 0x01, 0x95, 0x01, 0x95, 0x01, 0x95, 0x01, 0x95, 0x01, - 0x95, 0x01, 0x95, 0x01, 0x95, 0x01, 0x95, 0x01, 0x95, 0x01, 0x95, 0x01, 0x95, 0x01, 0x95, 0x01, - 0x95, 0x01, 0x95, 0x01, 0x95, 0x01, 0x95, 0x01, 0x95, 0x01, 0x95, 0x01, 0x95, 0x01, 0x95, 0x01, - 0x95, 0x01, 0x95, 0x01, 0x95, 0x01, 0x95, 0x01, 0x95, 0x01, 0x95, 0x01, 0x95, 0x01, 0x95, 0x01, + 0x0f, 0x00, 0xf7, 0x00, 0x0f, 0x00, 0x0f, 0x00, 0x0f, 0x00, 0x0f, 0x00, 0x0f, 0x00, 0x0f, 0x00, + 0xf8, 0x00, 0xf9, 0x00, 0xf8, 0x00, 0xf8, 0x00, 0xf9, 0x00, 0xfa, 0x00, 0xf8, 0x00, 0xfb, 0x00, + 0xfc, 0x00, 0xfc, 0x00, 0xfc, 0x00, 0xfd, 0x00, 0xfe, 0x00, 0xff, 0x00, 0x00, 0x01, 0x01, 0x01, + 0x02, 0x01, 0x03, 0x01, 0x04, 0x01, 0x05, 0x01, 0x06, 0x01, 0x07, 0x01, 0x08, 0x01, 0x09, 0x01, + 0x0a, 0x01, 0x0b, 0x01, 0x0c, 0x01, 0x0c, 0x01, 0x0d, 0x01, 0x0e, 0x01, 0x0f, 0x01, 0xdc, 0x00, + 0x10, 0x01, 0x11, 0x01, 0x12, 0x01, 0x13, 0x01, 0x14, 0x01, 0x15, 0x01, 0x16, 0x01, 0x16, 0x01, + 0x17, 0x01, 0x18, 0x01, 0x19, 0x01, 0xd5, 0x00, 0x1a, 0x01, 0x1b, 0x01, 0xd5, 0x00, 0x1c, 0x01, + 0x1d, 0x01, 0x1d, 0x01, 0x1d, 0x01, 0x1d, 0x01, 0x1d, 0x01, 0x1d, 0x01, 0x1d, 0x01, 0x1d, 0x01, + 0x1d, 0x01, 0x1d, 0x01, 0x1d, 0x01, 0x1d, 0x01, 0x1d, 0x01, 0x1d, 0x01, 0x1d, 0x01, 0x1d, 0x01, + 0x1e, 0x01, 0xd5, 0x00, 0x1f, 0x01, 0x20, 0x01, 0x21, 0x01, 0x21, 0x01, 0x21, 0x01, 0x22, 0x01, + 0xd5, 0x00, 0x23, 0x01, 0x1d, 0x01, 0x24, 0x01, 0xd5, 0x00, 0x25, 0x01, 0x26, 0x01, 0xd5, 0x00, + 0xd5, 0x00, 0xd5, 0x00, 0x27, 0x01, 0x90, 0x00, 0x28, 0x01, 0x90, 0x00, 0x15, 0x01, 0x15, 0x01, + 0x15, 0x01, 0x29, 0x01, 0x21, 0x01, 0x21, 0x01, 0x21, 0x01, 0x21, 0x01, 0x2a, 0x01, 0x15, 0x01, + 0xd5, 0x00, 0xd5, 0x00, 0xd5, 0x00, 0xd5, 0x00, 0xd5, 0x00, 0xd5, 0x00, 0xd5, 0x00, 0xd5, 0x00, + 0xd5, 0x00, 0xd5, 0x00, 0xd5, 0x00, 0x2b, 0x01, 0x2c, 0x01, 0xd5, 0x00, 0xd5, 0x00, 0x2d, 0x01, + 0xd5, 0x00, 0xd5, 0x00, 0xd5, 0x00, 0xd5, 0x00, 0xd5, 0x00, 0xd5, 0x00, 0x2e, 0x01, 0xd5, 0x00, + 0xd5, 0x00, 0xd5, 0x00, 0x2f, 0x01, 0xd5, 0x00, 0xd5, 0x00, 0xd5, 0x00, 0xd5, 0x00, 0xd5, 0x00, + 0xd5, 0x00, 0xd5, 0x00, 0xd5, 0x00, 0xd5, 0x00, 0xd5, 0x00, 0xd5, 0x00, 0x30, 0x01, 0x31, 0x01, + 0x15, 0x01, 0x32, 0x01, 0xd5, 0x00, 0xd5, 0x00, 0x33, 0x01, 0x1d, 0x01, 0x34, 0x01, 0x1d, 0x01, + 0x21, 0x01, 0x21, 0x01, 0x21, 0x01, 0x21, 0x01, 0x21, 0x01, 0x21, 0x01, 0x21, 0x01, 0x21, 0x01, + 0x21, 0x01, 0x21, 0x01, 0x21, 0x01, 0x21, 0x01, 0x21, 0x01, 0x21, 0x01, 0x21, 0x01, 0x21, 0x01, + 0x1d, 0x01, 0x1d, 0x01, 0x1d, 0x01, 0x1d, 0x01, 0x1d, 0x01, 0x1d, 0x01, 0x1d, 0x01, 0x1d, 0x01, + 0x35, 0x01, 0x36, 0x01, 0x1d, 0x01, 0x1d, 0x01, 0x1d, 0x01, 0x37, 0x01, 0x1d, 0x01, 0x38, 0x01, + 0x1d, 0x01, 0x1d, 0x01, 0x1d, 0x01, 0x1d, 0x01, 0x1d, 0x01, 0x1d, 0x01, 0x1d, 0x01, 0x1d, 0x01, + 0x1d, 0x01, 0x1d, 0x01, 0x1d, 0x01, 0x1d, 0x01, 0x1d, 0x01, 0x1d, 0x01, 0x1d, 0x01, 0x1d, 0x01, + 0xd5, 0x00, 0xd5, 0x00, 0xd5, 0x00, 0x1d, 0x01, 0x39, 0x01, 0xd5, 0x00, 0xd5, 0x00, 0x3a, 0x01, + 0xd5, 0x00, 0x3b, 0x01, 0xd5, 0x00, 0xd5, 0x00, 0xd5, 0x00, 0xd5, 0x00, 0xd5, 0x00, 0xd5, 0x00, + 0x0b, 0x00, 0x0b, 0x00, 0x3c, 0x01, 0x0d, 0x00, 0x0d, 0x00, 0x3d, 0x01, 0x3e, 0x01, 0x3f, 0x01, + 0x0f, 0x00, 0x0f, 0x00, 0x0f, 0x00, 0x0f, 0x00, 0x0f, 0x00, 0x0f, 0x00, 0x40, 0x01, 0x41, 0x01, + 0x0d, 0x00, 0x0d, 0x00, 0x42, 0x01, 0x50, 0x00, 0x50, 0x00, 0x50, 0x00, 0x43, 0x01, 0x44, 0x01, + 0x50, 0x00, 0x45, 0x01, 0x46, 0x01, 0x46, 0x01, 0x46, 0x01, 0x46, 0x01, 0x22, 0x00, 0x22, 0x00, + 0x47, 0x01, 0x48, 0x01, 0x49, 0x01, 0x4a, 0x01, 0x4b, 0x01, 0x4c, 0x01, 0x90, 0x00, 0x90, 0x00, + 0xd5, 0x00, 0x4d, 0x01, 0xd5, 0x00, 0xd5, 0x00, 0xd5, 0x00, 0xd5, 0x00, 0xd5, 0x00, 0x4e, 0x01, + 0xd5, 0x00, 0xd5, 0x00, 0xd5, 0x00, 0xd5, 0x00, 0xd5, 0x00, 0xd5, 0x00, 0xd5, 0x00, 0xd5, 0x00, + 0xd5, 0x00, 0xd5, 0x00, 0xd5, 0x00, 0xd5, 0x00, 0xd5, 0x00, 0x4f, 0x01, 0x90, 0x00, 0x50, 0x01, + 0x51, 0x01, 0x52, 0x01, 0x53, 0x01, 0x54, 0x01, 0x8c, 0x00, 0x50, 0x00, 0x50, 0x00, 0x50, 0x00, + 0x50, 0x00, 0x55, 0x01, 0xb6, 0x00, 0x50, 0x00, 0x50, 0x00, 0x50, 0x00, 0x50, 0x00, 0x56, 0x01, + 0x57, 0x01, 0x50, 0x00, 0x50, 0x00, 0x8c, 0x00, 0x50, 0x00, 0x50, 0x00, 0x50, 0x00, 0x50, 0x00, + 0xcc, 0x00, 0x58, 0x01, 0x50, 0x00, 0x50, 0x00, 0xd5, 0x00, 0xd5, 0x00, 0x4e, 0x01, 0x50, 0x00, + 0x21, 0x01, 0x59, 0x01, 0x5a, 0x01, 0x21, 0x01, 0x5b, 0x01, 0x5c, 0x01, 0x21, 0x01, 0x5d, 0x01, + 0x5a, 0x01, 0x21, 0x01, 0x21, 0x01, 0x5e, 0x01, 0x5f, 0x01, 0x21, 0x01, 0x21, 0x01, 0x21, 0x01, + 0x21, 0x01, 0x21, 0x01, 0x21, 0x01, 0x21, 0x01, 0x21, 0x01, 0x21, 0x01, 0x21, 0x01, 0x60, 0x01, + 0x21, 0x01, 0x21, 0x01, 0x21, 0x01, 0x21, 0x01, 0x21, 0x01, 0x61, 0x01, 0x21, 0x01, 0x62, 0x01, + 0x50, 0x00, 0x50, 0x00, 0x50, 0x00, 0x50, 0x00, 0x50, 0x00, 0x50, 0x00, 0x50, 0x00, 0x50, 0x00, + 0x50, 0x00, 0x50, 0x00, 0x50, 0x00, 0x50, 0x00, 0x50, 0x00, 0x50, 0x00, 0x50, 0x00, 0x50, 0x00, + 0x50, 0x00, 0x50, 0x00, 0x50, 0x00, 0x50, 0x00, 0x50, 0x00, 0x50, 0x00, 0x50, 0x00, 0x50, 0x00, + 0x50, 0x00, 0x50, 0x00, 0x50, 0x00, 0x50, 0x00, 0x50, 0x00, 0x50, 0x00, 0x50, 0x00, 0x50, 0x00, + 0x50, 0x00, 0x50, 0x00, 0x50, 0x00, 0x50, 0x00, 0x50, 0x00, 0x50, 0x00, 0x50, 0x00, 0x50, 0x00, + 0x50, 0x00, 0x50, 0x00, 0x50, 0x00, 0x50, 0x00, 0x50, 0x00, 0x50, 0x00, 0x50, 0x00, 0x50, 0x00, + 0x50, 0x00, 0x50, 0x00, 0x50, 0x00, 0x50, 0x00, 0x50, 0x00, 0x50, 0x00, 0x50, 0x00, 0x50, 0x00, + 0x50, 0x00, 0x50, 0x00, 0x50, 0x00, 0x50, 0x00, 0xd5, 0x00, 0xd5, 0x00, 0xd5, 0x00, 0xd5, 0x00, + 0x50, 0x00, 0x50, 0x00, 0x50, 0x00, 0x50, 0x00, 0x50, 0x00, 0x50, 0x00, 0x50, 0x00, 0x50, 0x00, + 0x50, 0x00, 0x50, 0x00, 0x50, 0x00, 0x50, 0x00, 0x50, 0x00, 0x50, 0x00, 0x50, 0x00, 0x50, 0x00, + 0x50, 0x00, 0x50, 0x00, 0x50, 0x00, 0x50, 0x00, 0x50, 0x00, 0x50, 0x00, 0x50, 0x00, 0x50, 0x00, + 0x50, 0x00, 0x50, 0x00, 0x50, 0x00, 0x50, 0x00, 0x50, 0x00, 0x50, 0x00, 0x50, 0x00, 0x9b, 0x00, + 0x50, 0x00, 0x63, 0x01, 0x50, 0x00, 0x50, 0x00, 0x50, 0x00, 0x50, 0x00, 0x50, 0x00, 0x50, 0x00, + 0x50, 0x00, 0x50, 0x00, 0x50, 0x00, 0x50, 0x00, 0x50, 0x00, 0x50, 0x00, 0x50, 0x00, 0x50, 0x00, + 0x50, 0x00, 0x50, 0x00, 0x50, 0x00, 0x50, 0x00, 0x50, 0x00, 0x50, 0x00, 0x50, 0x00, 0x50, 0x00, + 0x50, 0x00, 0x50, 0x00, 0x50, 0x00, 0x50, 0x00, 0x50, 0x00, 0x50, 0x00, 0x50, 0x00, 0x50, 0x00, + 0x50, 0x00, 0x50, 0x00, 0x50, 0x00, 0x50, 0x00, 0x50, 0x00, 0x50, 0x00, 0x50, 0x00, 0x50, 0x00, + 0x9b, 0x00, 0xd5, 0x00, 0xd5, 0x00, 0xd5, 0x00, 0x27, 0x01, 0x50, 0x00, 0x50, 0x00, 0xea, 0x00, + 0x50, 0x00, 0x50, 0x00, 0x50, 0x00, 0x50, 0x00, 0x50, 0x00, 0x50, 0x00, 0x50, 0x00, 0x50, 0x00, + 0x50, 0x00, 0x50, 0x00, 0x50, 0x00, 0x50, 0x00, 0x50, 0x00, 0x50, 0x00, 0x50, 0x00, 0x50, 0x00, + 0x64, 0x01, 0x50, 0x00, 0x65, 0x01, 0x90, 0x00, 0x0f, 0x00, 0x0f, 0x00, 0x66, 0x01, 0x67, 0x01, + 0x0f, 0x00, 0x68, 0x01, 0x50, 0x00, 0x50, 0x00, 0x50, 0x00, 0x50, 0x00, 0x69, 0x01, 0x6a, 0x01, + 0x21, 0x00, 0x6b, 0x01, 0x6c, 0x01, 0x6d, 0x01, 0x0f, 0x00, 0x0f, 0x00, 0x0f, 0x00, 0x6e, 0x01, + 0x6f, 0x01, 0x70, 0x01, 0x71, 0x01, 0x72, 0x01, 0x73, 0x01, 0x90, 0x00, 0x90, 0x00, 0x74, 0x01, + 0x75, 0x01, 0x50, 0x00, 0x76, 0x01, 0x77, 0x01, 0x50, 0x00, 0x50, 0x00, 0x50, 0x00, 0x78, 0x01, + 0x79, 0x01, 0x50, 0x00, 0x50, 0x00, 0x7a, 0x01, 0x7b, 0x01, 0xc4, 0x00, 0x22, 0x00, 0x7c, 0x01, + 0xe4, 0x00, 0x50, 0x00, 0x7d, 0x01, 0x50, 0x00, 0x7e, 0x01, 0x7f, 0x01, 0x50, 0x00, 0x9b, 0x00, + 0x4f, 0x00, 0x50, 0x00, 0x50, 0x00, 0x80, 0x01, 0x81, 0x01, 0x82, 0x01, 0x83, 0x01, 0x84, 0x01, + 0x50, 0x00, 0x50, 0x00, 0x85, 0x01, 0x86, 0x01, 0x87, 0x01, 0x88, 0x01, 0x50, 0x00, 0x89, 0x01, + 0x50, 0x00, 0x50, 0x00, 0x50, 0x00, 0x8a, 0x01, 0x8b, 0x01, 0x8c, 0x01, 0x8d, 0x01, 0x8e, 0x01, + 0x8f, 0x01, 0x90, 0x01, 0x46, 0x01, 0x0d, 0x00, 0x0d, 0x00, 0x91, 0x01, 0x92, 0x01, 0x0d, 0x00, + 0x0d, 0x00, 0x0d, 0x00, 0x0d, 0x00, 0x0d, 0x00, 0x50, 0x00, 0x50, 0x00, 0x93, 0x01, 0xc4, 0x00, + 0x50, 0x00, 0x50, 0x00, 0x50, 0x00, 0x50, 0x00, 0x50, 0x00, 0x50, 0x00, 0x50, 0x00, 0x50, 0x00, + 0x50, 0x00, 0x50, 0x00, 0x50, 0x00, 0x50, 0x00, 0x50, 0x00, 0x50, 0x00, 0x50, 0x00, 0x50, 0x00, + 0x50, 0x00, 0x50, 0x00, 0x50, 0x00, 0x50, 0x00, 0x50, 0x00, 0x50, 0x00, 0x50, 0x00, 0x50, 0x00, + 0x50, 0x00, 0x50, 0x00, 0x94, 0x01, 0x50, 0x00, 0x95, 0x01, 0x50, 0x00, 0x50, 0x00, 0xd2, 0x00, 0x96, 0x01, 0x96, 0x01, 0x96, 0x01, 0x96, 0x01, 0x96, 0x01, 0x96, 0x01, 0x96, 0x01, 0x96, 0x01, 0x96, 0x01, 0x96, 0x01, 0x96, 0x01, 0x96, 0x01, 0x96, 0x01, 0x96, 0x01, 0x96, 0x01, 0x96, 0x01, 0x96, 0x01, 0x96, 0x01, 0x96, 0x01, 0x96, 0x01, 0x96, 0x01, 0x96, 0x01, 0x96, 0x01, 0x96, 0x01, 0x96, 0x01, 0x96, 0x01, 0x96, 0x01, 0x96, 0x01, 0x96, 0x01, 0x96, 0x01, 0x96, 0x01, 0x96, 0x01, - 0x96, 0x01, 0x96, 0x01, 0x96, 0x01, 0x96, 0x01, 0x96, 0x01, 0x96, 0x01, 0x96, 0x01, 0x96, 0x01, - 0x96, 0x01, 0x96, 0x01, 0x96, 0x01, 0x96, 0x01, 0x96, 0x01, 0x96, 0x01, 0x96, 0x01, 0x96, 0x01, - 0x4f, 0x00, 0x4f, 0x00, 0x4f, 0x00, 0x4f, 0x00, 0x4f, 0x00, 0x4f, 0x00, 0x4f, 0x00, 0x4f, 0x00, - 0x4f, 0x00, 0x4f, 0x00, 0x4f, 0x00, 0x4f, 0x00, 0x4f, 0x00, 0x4f, 0x00, 0x4f, 0x00, 0x4f, 0x00, - 0x4f, 0x00, 0x4f, 0x00, 0x4f, 0x00, 0x4f, 0x00, 0x4f, 0x00, 0x4f, 0x00, 0xcf, 0x00, 0x4f, 0x00, - 0x4f, 0x00, 0x4f, 0x00, 0x4f, 0x00, 0x4f, 0x00, 0x4f, 0x00, 0xd2, 0x00, 0x8f, 0x00, 0x8f, 0x00, - 0x97, 0x01, 0x98, 0x01, 0x99, 0x01, 0x9a, 0x01, 0x9b, 0x01, 0x32, 0x00, 0x32, 0x00, 0x32, 0x00, - 0x32, 0x00, 0x32, 0x00, 0x32, 0x00, 0x9c, 0x01, 0x9d, 0x01, 0x9e, 0x01, 0x32, 0x00, 0x32, 0x00, + 0x97, 0x01, 0x97, 0x01, 0x97, 0x01, 0x97, 0x01, 0x97, 0x01, 0x97, 0x01, 0x97, 0x01, 0x97, 0x01, + 0x97, 0x01, 0x97, 0x01, 0x97, 0x01, 0x97, 0x01, 0x97, 0x01, 0x97, 0x01, 0x97, 0x01, 0x97, 0x01, + 0x97, 0x01, 0x97, 0x01, 0x97, 0x01, 0x97, 0x01, 0x97, 0x01, 0x97, 0x01, 0x97, 0x01, 0x97, 0x01, + 0x97, 0x01, 0x97, 0x01, 0x97, 0x01, 0x97, 0x01, 0x97, 0x01, 0x97, 0x01, 0x97, 0x01, 0x97, 0x01, + 0x97, 0x01, 0x97, 0x01, 0x97, 0x01, 0x97, 0x01, 0x97, 0x01, 0x97, 0x01, 0x97, 0x01, 0x97, 0x01, + 0x97, 0x01, 0x97, 0x01, 0x97, 0x01, 0x97, 0x01, 0x97, 0x01, 0x97, 0x01, 0x97, 0x01, 0x97, 0x01, + 0x50, 0x00, 0x50, 0x00, 0x50, 0x00, 0x50, 0x00, 0x50, 0x00, 0x50, 0x00, 0x50, 0x00, 0x50, 0x00, + 0x50, 0x00, 0x50, 0x00, 0x50, 0x00, 0x50, 0x00, 0x50, 0x00, 0x50, 0x00, 0x50, 0x00, 0x50, 0x00, + 0x50, 0x00, 0x50, 0x00, 0x50, 0x00, 0x50, 0x00, 0x50, 0x00, 0x50, 0x00, 0xd0, 0x00, 0x50, 0x00, + 0x50, 0x00, 0x50, 0x00, 0x50, 0x00, 0x50, 0x00, 0x50, 0x00, 0xd3, 0x00, 0x90, 0x00, 0x90, 0x00, + 0x98, 0x01, 0x99, 0x01, 0x9a, 0x01, 0x9b, 0x01, 0x9c, 0x01, 0x32, 0x00, 0x32, 0x00, 0x32, 0x00, + 0x32, 0x00, 0x32, 0x00, 0x32, 0x00, 0x9d, 0x01, 0x9e, 0x01, 0x9f, 0x01, 0x32, 0x00, 0x32, 0x00, 0x32, 0x00, 0x32, 0x00, 0x32, 0x00, 0x32, 0x00, 0x32, 0x00, 0x32, 0x00, 0x32, 0x00, 0x32, 0x00, 0x32, 0x00, 0x32, 0x00, 0x32, 0x00, 0x32, 0x00, 0x32, 0x00, 0x32, 0x00, 0x32, 0x00, 0x32, 0x00, - 0x32, 0x00, 0x32, 0x00, 0x32, 0x00, 0x9f, 0x01, 0x4a, 0x00, 0x32, 0x00, 0x32, 0x00, 0x32, 0x00, - 0x32, 0x00, 0xa0, 0x01, 0x32, 0x00, 0x32, 0x00, 0xa1, 0x01, 0x0b, 0x01, 0x0b, 0x01, 0xa2, 0x01, - 0x22, 0x00, 0xa3, 0x01, 0x22, 0x00, 0xa4, 0x01, 0xa5, 0x01, 0xa6, 0x01, 0xa7, 0x01, 0xa8, 0x01, - 0x32, 0x00, 0x32, 0x00, 0x32, 0x00, 0x32, 0x00, 0x32, 0x00, 0x32, 0x00, 0x32, 0x00, 0xa9, 0x01, - 0xaa, 0x01, 0x03, 0x00, 0x04, 0x00, 0x05, 0x00, 0x06, 0x00, 0xab, 0x01, 0xac, 0x01, 0xad, 0x01, - 0x4f, 0x00, 0xae, 0x01, 0x4f, 0x00, 0xcb, 0x00, 0xaf, 0x01, 0xb0, 0x01, 0xb1, 0x01, 0xb2, 0x01, - 0xb3, 0x01, 0x4f, 0x00, 0xaf, 0x00, 0xb4, 0x01, 0xcf, 0x00, 0xcf, 0x00, 0x8f, 0x00, 0x8f, 0x00, - 0x4f, 0x00, 0x4f, 0x00, 0x4f, 0x00, 0x4f, 0x00, 0x4f, 0x00, 0x4f, 0x00, 0x4f, 0x00, 0x57, 0x01, + 0x32, 0x00, 0x32, 0x00, 0x32, 0x00, 0xa0, 0x01, 0x4a, 0x00, 0x32, 0x00, 0x32, 0x00, 0x32, 0x00, + 0x32, 0x00, 0xa1, 0x01, 0x32, 0x00, 0x32, 0x00, 0x4c, 0x00, 0x0d, 0x01, 0x0d, 0x01, 0xa2, 0x01, + 0x22, 0x00, 0xa3, 0x01, 0x22, 0x00, 0xa4, 0x01, 0xa5, 0x01, 0xa6, 0x01, 0xa7, 0x01, 0x4b, 0x00, + 0x32, 0x00, 0x32, 0x00, 0x32, 0x00, 0x32, 0x00, 0x32, 0x00, 0x32, 0x00, 0x32, 0x00, 0xa8, 0x01, + 0xa9, 0x01, 0x03, 0x00, 0x04, 0x00, 0x05, 0x00, 0x06, 0x00, 0xaa, 0x01, 0xab, 0x01, 0xac, 0x01, + 0x50, 0x00, 0xad, 0x01, 0x50, 0x00, 0xcc, 0x00, 0xae, 0x01, 0xaf, 0x01, 0xb0, 0x01, 0xb1, 0x01, + 0xb2, 0x01, 0x50, 0x00, 0xb0, 0x00, 0xb3, 0x01, 0xd0, 0x00, 0xd0, 0x00, 0x90, 0x00, 0x90, 0x00, + 0x50, 0x00, 0x50, 0x00, 0x50, 0x00, 0x50, 0x00, 0x50, 0x00, 0x50, 0x00, 0x50, 0x00, 0xb4, 0x01, 0xb5, 0x01, 0xb6, 0x01, 0xb6, 0x01, 0xb7, 0x01, 0xb8, 0x01, 0xb8, 0x01, 0xb8, 0x01, 0xb9, 0x01, - 0xba, 0x01, 0x4e, 0x01, 0xbb, 0x01, 0x8f, 0x00, 0x8f, 0x00, 0x20, 0x01, 0x20, 0x01, 0xbc, 0x01, - 0x8f, 0x00, 0x8f, 0x00, 0x8f, 0x00, 0x8f, 0x00, 0x8f, 0x00, 0x8f, 0x00, 0x8f, 0x00, 0x8f, 0x00, - 0x4f, 0x00, 0x9a, 0x00, 0x4f, 0x00, 0x4f, 0x00, 0x4f, 0x00, 0x67, 0x00, 0xbd, 0x01, 0xbe, 0x01, - 0x4f, 0x00, 0x4f, 0x00, 0xbf, 0x01, 0x4f, 0x00, 0xc0, 0x01, 0x4f, 0x00, 0x4f, 0x00, 0xc1, 0x01, - 0x4f, 0x00, 0xc2, 0x01, 0x4f, 0x00, 0x4f, 0x00, 0xc3, 0x01, 0xc4, 0x01, 0x8f, 0x00, 0x8f, 0x00, - 0x0b, 0x00, 0x0b, 0x00, 0xc5, 0x01, 0x0d, 0x00, 0x0d, 0x00, 0x4f, 0x00, 0x4f, 0x00, 0x4f, 0x00, - 0x4f, 0x00, 0xcf, 0x00, 0xc3, 0x00, 0x0b, 0x00, 0x0b, 0x00, 0xc6, 0x01, 0x0d, 0x00, 0xc7, 0x01, - 0x4f, 0x00, 0x4f, 0x00, 0xc8, 0x01, 0x4f, 0x00, 0x4f, 0x00, 0x4f, 0x00, 0xc9, 0x01, 0x8f, 0x00, - 0x8f, 0x00, 0x8f, 0x00, 0x8f, 0x00, 0x8f, 0x00, 0x8f, 0x00, 0x8f, 0x00, 0x8f, 0x00, 0x8f, 0x00, - 0x4f, 0x00, 0x4f, 0x00, 0x4f, 0x00, 0x4f, 0x00, 0x4f, 0x00, 0x4f, 0x00, 0x4f, 0x00, 0x4f, 0x00, - 0x4f, 0x00, 0x4f, 0x00, 0x4f, 0x00, 0x4f, 0x00, 0x4f, 0x00, 0x4f, 0x00, 0x4f, 0x00, 0x4f, 0x00, - 0x4f, 0x00, 0x4f, 0x00, 0x4f, 0x00, 0x44, 0x01, 0x4f, 0x00, 0xca, 0x00, 0xc8, 0x01, 0x8f, 0x00, - 0x8f, 0x00, 0x8f, 0x00, 0x8f, 0x00, 0x8f, 0x00, 0x8f, 0x00, 0x8f, 0x00, 0x8f, 0x00, 0x8f, 0x00, - 0xca, 0x01, 0x32, 0x00, 0x32, 0x00, 0xcb, 0x01, 0x32, 0x00, 0xcc, 0x01, 0x32, 0x00, 0xcd, 0x01, - 0x32, 0x00, 0xce, 0x01, 0xcf, 0x01, 0x4a, 0x00, 0x4a, 0x00, 0x4a, 0x00, 0x32, 0x00, 0xd0, 0x01, - 0x32, 0x00, 0xd1, 0x01, 0x32, 0x00, 0xd2, 0x01, 0x4a, 0x00, 0x4a, 0x00, 0x4a, 0x00, 0x4a, 0x00, - 0x32, 0x00, 0x32, 0x00, 0x32, 0x00, 0xd3, 0x01, 0xd4, 0x01, 0xd5, 0x01, 0xd4, 0x01, 0xd4, 0x01, - 0xd6, 0x01, 0xd7, 0x01, 0x32, 0x00, 0xd8, 0x01, 0xd9, 0x01, 0xda, 0x01, 0x32, 0x00, 0xdb, 0x01, - 0x32, 0x00, 0xdc, 0x01, 0x4a, 0x00, 0x4a, 0x00, 0xdd, 0x01, 0x32, 0x00, 0xde, 0x01, 0xdf, 0x01, - 0x32, 0x00, 0x32, 0x00, 0x32, 0x00, 0xe0, 0x01, 0x32, 0x00, 0xe1, 0x01, 0x32, 0x00, 0xe2, 0x01, - 0x32, 0x00, 0xe3, 0x01, 0xe4, 0x01, 0x4a, 0x00, 0x4a, 0x00, 0x4a, 0x00, 0x4a, 0x00, 0x4a, 0x00, - 0x32, 0x00, 0x32, 0x00, 0x32, 0x00, 0x32, 0x00, 0xe5, 0x01, 0x4a, 0x00, 0x4a, 0x00, 0x4a, 0x00, - 0xe6, 0x01, 0xe6, 0x01, 0xe6, 0x01, 0xe7, 0x01, 0xe8, 0x01, 0xe8, 0x01, 0xe8, 0x01, 0xe9, 0x01, - 0x32, 0x00, 0x32, 0x00, 0xea, 0x01, 0xeb, 0x01, 0x4a, 0x00, 0x4a, 0x00, 0x4a, 0x00, 0x4a, 0x00, + 0xba, 0x01, 0xbb, 0x01, 0xbc, 0x01, 0x90, 0x00, 0x90, 0x00, 0x21, 0x01, 0x21, 0x01, 0xbd, 0x01, + 0x90, 0x00, 0x90, 0x00, 0x90, 0x00, 0x90, 0x00, 0x90, 0x00, 0x90, 0x00, 0x90, 0x00, 0x90, 0x00, + 0x50, 0x00, 0x9b, 0x00, 0x50, 0x00, 0x50, 0x00, 0x50, 0x00, 0x68, 0x00, 0xbe, 0x01, 0xbf, 0x01, + 0x50, 0x00, 0x50, 0x00, 0xc0, 0x01, 0x50, 0x00, 0xc1, 0x01, 0x50, 0x00, 0x50, 0x00, 0xc2, 0x01, + 0x50, 0x00, 0xc3, 0x01, 0x50, 0x00, 0x50, 0x00, 0xc4, 0x01, 0xc5, 0x01, 0x90, 0x00, 0x90, 0x00, + 0x0b, 0x00, 0x0b, 0x00, 0xc6, 0x01, 0x0d, 0x00, 0x0d, 0x00, 0x50, 0x00, 0x50, 0x00, 0x50, 0x00, + 0x50, 0x00, 0xd0, 0x00, 0xc4, 0x00, 0x0b, 0x00, 0x0b, 0x00, 0xc7, 0x01, 0x0d, 0x00, 0xc8, 0x01, + 0x50, 0x00, 0x50, 0x00, 0xc9, 0x01, 0x50, 0x00, 0x50, 0x00, 0x50, 0x00, 0xca, 0x01, 0x90, 0x00, + 0x90, 0x00, 0x90, 0x00, 0x90, 0x00, 0x90, 0x00, 0x90, 0x00, 0x90, 0x00, 0x90, 0x00, 0x90, 0x00, + 0x50, 0x00, 0x50, 0x00, 0x50, 0x00, 0x50, 0x00, 0x50, 0x00, 0x50, 0x00, 0x50, 0x00, 0x50, 0x00, + 0x50, 0x00, 0x50, 0x00, 0x50, 0x00, 0x50, 0x00, 0x50, 0x00, 0x50, 0x00, 0x50, 0x00, 0x50, 0x00, + 0x50, 0x00, 0x50, 0x00, 0x50, 0x00, 0x45, 0x01, 0x50, 0x00, 0xcb, 0x00, 0xc9, 0x01, 0x90, 0x00, + 0x90, 0x00, 0x90, 0x00, 0x90, 0x00, 0x90, 0x00, 0x90, 0x00, 0x90, 0x00, 0x90, 0x00, 0x90, 0x00, + 0xcb, 0x01, 0x32, 0x00, 0x32, 0x00, 0xcc, 0x01, 0x32, 0x00, 0xcd, 0x01, 0x32, 0x00, 0xce, 0x01, + 0x32, 0x00, 0xcf, 0x01, 0xd0, 0x01, 0x4a, 0x00, 0x4a, 0x00, 0x4a, 0x00, 0x32, 0x00, 0xd1, 0x01, + 0x32, 0x00, 0xd2, 0x01, 0x32, 0x00, 0xd3, 0x01, 0x4a, 0x00, 0x4a, 0x00, 0x4a, 0x00, 0x4a, 0x00, + 0x32, 0x00, 0x32, 0x00, 0x32, 0x00, 0xd4, 0x01, 0xd5, 0x01, 0xd6, 0x01, 0xd5, 0x01, 0xd5, 0x01, + 0xd7, 0x01, 0xd8, 0x01, 0x32, 0x00, 0xd9, 0x01, 0xda, 0x01, 0xdb, 0x01, 0x32, 0x00, 0xdc, 0x01, + 0x32, 0x00, 0xdd, 0x01, 0x4a, 0x00, 0x4a, 0x00, 0xde, 0x01, 0x32, 0x00, 0xdf, 0x01, 0xe0, 0x01, + 0x32, 0x00, 0x32, 0x00, 0x32, 0x00, 0xe1, 0x01, 0x32, 0x00, 0xe2, 0x01, 0x32, 0x00, 0xe3, 0x01, + 0x32, 0x00, 0xe4, 0x01, 0xe5, 0x01, 0x4a, 0x00, 0x4a, 0x00, 0x4a, 0x00, 0x4a, 0x00, 0x4a, 0x00, + 0x32, 0x00, 0x32, 0x00, 0x32, 0x00, 0x32, 0x00, 0xe6, 0x01, 0x4a, 0x00, 0x4a, 0x00, 0x4a, 0x00, + 0xe7, 0x01, 0xe7, 0x01, 0xe7, 0x01, 0xe8, 0x01, 0xe9, 0x01, 0xe9, 0x01, 0xe9, 0x01, 0xea, 0x01, + 0x32, 0x00, 0x32, 0x00, 0xeb, 0x01, 0xec, 0x01, 0x4a, 0x00, 0x4a, 0x00, 0x4a, 0x00, 0x4a, 0x00, 0x4a, 0x00, 0x4a, 0x00, 0x4a, 0x00, 0x4a, 0x00, 0x4a, 0x00, 0x4a, 0x00, 0x4a, 0x00, 0x4a, 0x00, - 0x4a, 0x00, 0x4a, 0x00, 0x4a, 0x00, 0x4a, 0x00, 0x4a, 0x00, 0x4a, 0x00, 0x14, 0x01, 0xec, 0x01, - 0x4a, 0x00, 0x4a, 0x00, 0x4a, 0x00, 0x4a, 0x00, 0x4a, 0x00, 0x4a, 0x00, 0x4a, 0x00, 0x4a, 0x00, - 0x32, 0x00, 0xdc, 0x01, 0xed, 0x01, 0x32, 0x00, 0x40, 0x00, 0xee, 0x01, 0x4a, 0x00, 0x4a, 0x00, - 0x4a, 0x00, 0x4a, 0x00, 0x4a, 0x00, 0x4a, 0x00, 0x4a, 0x00, 0x4a, 0x00, 0x32, 0x00, 0xef, 0x01, - 0xf0, 0x01, 0x4f, 0x00, 0x4f, 0x00, 0xf1, 0x01, 0xf2, 0x01, 0xf3, 0x01, 0xf4, 0x01, 0xf5, 0x01, - 0xe0, 0x00, 0x4f, 0x00, 0x4f, 0x00, 0xf6, 0x01, 0xf7, 0x01, 0x4f, 0x00, 0xc7, 0x00, 0xc3, 0x00, - 0xf8, 0x01, 0x4f, 0x00, 0xf9, 0x01, 0xfa, 0x01, 0xfb, 0x01, 0x4f, 0x00, 0x4f, 0x00, 0xfc, 0x01, - 0xe0, 0x00, 0x4f, 0x00, 0x4f, 0x00, 0xfd, 0x01, 0xfe, 0x01, 0xff, 0x01, 0x00, 0x02, 0x01, 0x02, - 0x4f, 0x00, 0x64, 0x00, 0x02, 0x02, 0x03, 0x02, 0x8f, 0x00, 0x8f, 0x00, 0x8f, 0x00, 0x8f, 0x00, - 0x04, 0x02, 0x05, 0x02, 0x06, 0x02, 0x4f, 0x00, 0x4f, 0x00, 0x07, 0x02, 0x08, 0x02, 0xc3, 0x00, - 0x09, 0x02, 0x56, 0x00, 0x57, 0x00, 0x0a, 0x02, 0x0b, 0x02, 0x0c, 0x02, 0x0d, 0x02, 0x0e, 0x02, - 0x8f, 0x00, 0x8f, 0x00, 0x8f, 0x00, 0x8f, 0x00, 0x8f, 0x00, 0x8f, 0x00, 0x8f, 0x00, 0x8f, 0x00, - 0x4f, 0x00, 0x4f, 0x00, 0x4f, 0x00, 0x0f, 0x02, 0x10, 0x02, 0x11, 0x02, 0x8f, 0x00, 0x8f, 0x00, - 0x4f, 0x00, 0x4f, 0x00, 0x4f, 0x00, 0x12, 0x02, 0x13, 0x02, 0xc3, 0x00, 0x8f, 0x00, 0x8f, 0x00, - 0x8f, 0x00, 0x8f, 0x00, 0x8f, 0x00, 0x8f, 0x00, 0x8f, 0x00, 0x8f, 0x00, 0x8f, 0x00, 0x8f, 0x00, - 0x4f, 0x00, 0x4f, 0x00, 0x14, 0x02, 0x15, 0x02, 0x16, 0x02, 0x17, 0x02, 0x8f, 0x00, 0x8f, 0x00, - 0x4f, 0x00, 0x4f, 0x00, 0x4f, 0x00, 0x18, 0x02, 0x19, 0x02, 0xc3, 0x00, 0x1a, 0x02, 0x8f, 0x00, - 0x4f, 0x00, 0x4f, 0x00, 0x1b, 0x02, 0x1c, 0x02, 0xc3, 0x00, 0x8f, 0x00, 0x8f, 0x00, 0x8f, 0x00, - 0x4f, 0x00, 0xb0, 0x00, 0x1d, 0x02, 0x1e, 0x02, 0x8f, 0x00, 0x8f, 0x00, 0x8f, 0x00, 0x8f, 0x00, - 0x8f, 0x00, 0x8f, 0x00, 0x8f, 0x00, 0x8f, 0x00, 0x8f, 0x00, 0x8f, 0x00, 0x8f, 0x00, 0x8f, 0x00, - 0x4f, 0x00, 0x4f, 0x00, 0x02, 0x02, 0x1f, 0x02, 0x8f, 0x00, 0x8f, 0x00, 0x8f, 0x00, 0x8f, 0x00, - 0x8f, 0x00, 0x8f, 0x00, 0x0b, 0x00, 0x0b, 0x00, 0x0d, 0x00, 0x0d, 0x00, 0x97, 0x00, 0x20, 0x02, - 0x8f, 0x00, 0x8f, 0x00, 0x8f, 0x00, 0x8f, 0x00, 0x8f, 0x00, 0x8f, 0x00, 0x8f, 0x00, 0x8f, 0x00, - 0x8f, 0x00, 0x8f, 0x00, 0x21, 0x02, 0x4f, 0x00, 0x4f, 0x00, 0x22, 0x02, 0x23, 0x02, 0x8f, 0x00, - 0x24, 0x02, 0x4f, 0x00, 0x4f, 0x00, 0x25, 0x02, 0x26, 0x02, 0x27, 0x02, 0x4f, 0x00, 0x4f, 0x00, - 0x28, 0x02, 0x29, 0x02, 0x2a, 0x02, 0x8f, 0x00, 0x4f, 0x00, 0x4f, 0x00, 0x4f, 0x00, 0xc7, 0x00, - 0x8f, 0x00, 0x8f, 0x00, 0x8f, 0x00, 0x8f, 0x00, 0x8f, 0x00, 0x8f, 0x00, 0x8f, 0x00, 0x8f, 0x00, - 0x8f, 0x00, 0x8f, 0x00, 0x8f, 0x00, 0x8f, 0x00, 0x8f, 0x00, 0x8f, 0x00, 0x8f, 0x00, 0x8f, 0x00, - 0x57, 0x00, 0x4f, 0x00, 0x14, 0x02, 0x2b, 0x02, 0x2c, 0x02, 0x97, 0x00, 0xb2, 0x00, 0x2d, 0x02, - 0x4f, 0x00, 0x2e, 0x02, 0x2f, 0x02, 0x30, 0x02, 0x8f, 0x00, 0x8f, 0x00, 0x8f, 0x00, 0x8f, 0x00, - 0x31, 0x02, 0x4f, 0x00, 0x4f, 0x00, 0x32, 0x02, 0x33, 0x02, 0xc3, 0x00, 0x34, 0x02, 0x4f, 0x00, - 0x35, 0x02, 0x36, 0x02, 0xc3, 0x00, 0x8f, 0x00, 0x8f, 0x00, 0x8f, 0x00, 0x8f, 0x00, 0x8f, 0x00, - 0x8f, 0x00, 0x8f, 0x00, 0x8f, 0x00, 0x8f, 0x00, 0x8f, 0x00, 0x8f, 0x00, 0x8f, 0x00, 0x8f, 0x00, - 0x8f, 0x00, 0x8f, 0x00, 0x8f, 0x00, 0x8f, 0x00, 0x8f, 0x00, 0x8f, 0x00, 0x4f, 0x00, 0x37, 0x02, - 0x8f, 0x00, 0x8f, 0x00, 0x8f, 0x00, 0x8f, 0x00, 0x8f, 0x00, 0x8f, 0x00, 0x8f, 0x00, 0x8f, 0x00, - 0x8f, 0x00, 0x8f, 0x00, 0x8f, 0x00, 0x8f, 0x00, 0xb6, 0x01, 0x38, 0x02, 0x39, 0x02, 0x3a, 0x02, - 0x4f, 0x00, 0x4f, 0x00, 0x4f, 0x00, 0x4f, 0x00, 0x4f, 0x00, 0x4f, 0x00, 0x4f, 0x00, 0x4f, 0x00, - 0x4f, 0x00, 0x4f, 0x00, 0x4f, 0x00, 0x4f, 0x00, 0x4f, 0x00, 0x4f, 0x00, 0x4f, 0x00, 0x4f, 0x00, - 0x4f, 0x00, 0x4f, 0x00, 0x4f, 0x00, 0x4f, 0x00, 0x4f, 0x00, 0x4f, 0x00, 0x4f, 0x00, 0x4f, 0x00, - 0x4f, 0x00, 0xd2, 0x00, 0x8f, 0x00, 0x8f, 0x00, 0x8f, 0x00, 0x8f, 0x00, 0x8f, 0x00, 0x8f, 0x00, - 0x15, 0x01, 0x15, 0x01, 0x15, 0x01, 0x15, 0x01, 0x15, 0x01, 0x15, 0x01, 0x3b, 0x02, 0x3c, 0x02, - 0x4f, 0x00, 0x4f, 0x00, 0x4f, 0x00, 0x4f, 0x00, 0x4f, 0x00, 0x4f, 0x00, 0x4f, 0x00, 0x4f, 0x00, - 0x4f, 0x00, 0x4f, 0x00, 0x4f, 0x00, 0x4f, 0x00, 0x93, 0x01, 0x8f, 0x00, 0x8f, 0x00, 0x8f, 0x00, - 0x8f, 0x00, 0x8f, 0x00, 0x8f, 0x00, 0x8f, 0x00, 0x8f, 0x00, 0x8f, 0x00, 0x8f, 0x00, 0x8f, 0x00, - 0x8f, 0x00, 0x8f, 0x00, 0x8f, 0x00, 0x8f, 0x00, 0x8f, 0x00, 0x8f, 0x00, 0x8f, 0x00, 0x8f, 0x00, - 0x8f, 0x00, 0x8f, 0x00, 0x8f, 0x00, 0x8f, 0x00, 0x8f, 0x00, 0x8f, 0x00, 0x8f, 0x00, 0x8f, 0x00, - 0x8f, 0x00, 0x8f, 0x00, 0x8f, 0x00, 0x8f, 0x00, 0x8f, 0x00, 0x8f, 0x00, 0x8f, 0x00, 0x8f, 0x00, - 0x8f, 0x00, 0x8f, 0x00, 0x8f, 0x00, 0x8f, 0x00, 0x8f, 0x00, 0x8f, 0x00, 0x8f, 0x00, 0x8f, 0x00, - 0x4f, 0x00, 0x4f, 0x00, 0xcb, 0x00, 0x3d, 0x02, 0x8f, 0x00, 0x8f, 0x00, 0x8f, 0x00, 0x8f, 0x00, - 0x8f, 0x00, 0x8f, 0x00, 0x8f, 0x00, 0x8f, 0x00, 0x8f, 0x00, 0x8f, 0x00, 0x8f, 0x00, 0x8f, 0x00, - 0x8f, 0x00, 0x8f, 0x00, 0x8f, 0x00, 0x8f, 0x00, 0x8f, 0x00, 0x8f, 0x00, 0x8f, 0x00, 0x8f, 0x00, - 0x8f, 0x00, 0x8f, 0x00, 0x8f, 0x00, 0x8f, 0x00, 0x8f, 0x00, 0x8f, 0x00, 0x8f, 0x00, 0x8f, 0x00, - 0x4f, 0x00, 0x4f, 0x00, 0x4f, 0x00, 0x4f, 0x00, 0x44, 0x01, 0x8f, 0x00, 0x8f, 0x00, 0x8f, 0x00, - 0x8f, 0x00, 0x8f, 0x00, 0x8f, 0x00, 0x8f, 0x00, 0x8f, 0x00, 0x8f, 0x00, 0x8f, 0x00, 0x8f, 0x00, - 0x8f, 0x00, 0x8f, 0x00, 0x8f, 0x00, 0x8f, 0x00, 0x8f, 0x00, 0x8f, 0x00, 0x8f, 0x00, 0x8f, 0x00, - 0x8f, 0x00, 0x8f, 0x00, 0x8f, 0x00, 0x8f, 0x00, 0x8f, 0x00, 0x8f, 0x00, 0x8f, 0x00, 0x8f, 0x00, - 0x4f, 0x00, 0x4f, 0x00, 0x4f, 0x00, 0xc7, 0x00, 0x4f, 0x00, 0xcb, 0x00, 0x81, 0x01, 0x8f, 0x00, - 0x8f, 0x00, 0x8f, 0x00, 0x8f, 0x00, 0x8f, 0x00, 0x8f, 0x00, 0x4f, 0x00, 0xcf, 0x00, 0x3e, 0x02, - 0x4f, 0x00, 0x4f, 0x00, 0x4f, 0x00, 0x3f, 0x02, 0x40, 0x02, 0x41, 0x02, 0x42, 0x02, 0x43, 0x02, - 0x4f, 0x00, 0x8f, 0x00, 0x8f, 0x00, 0x8f, 0x00, 0x8f, 0x00, 0x8f, 0x00, 0x8f, 0x00, 0x8f, 0x00, - 0x8f, 0x00, 0x8f, 0x00, 0x8f, 0x00, 0x8f, 0x00, 0x0b, 0x00, 0x0b, 0x00, 0x0d, 0x00, 0x0d, 0x00, - 0xb6, 0x01, 0x44, 0x02, 0x8f, 0x00, 0x8f, 0x00, 0x8f, 0x00, 0x8f, 0x00, 0x8f, 0x00, 0x8f, 0x00, - 0x4f, 0x00, 0x4f, 0x00, 0x4f, 0x00, 0x4f, 0x00, 0x45, 0x02, 0x46, 0x02, 0x47, 0x02, 0x47, 0x02, - 0x48, 0x02, 0x49, 0x02, 0x8f, 0x00, 0x8f, 0x00, 0x8f, 0x00, 0x8f, 0x00, 0x4a, 0x02, 0x8f, 0x00, - 0x4f, 0x00, 0x4f, 0x00, 0x4f, 0x00, 0x4f, 0x00, 0x4f, 0x00, 0x4f, 0x00, 0x4f, 0x00, 0x4f, 0x00, - 0x4f, 0x00, 0x4f, 0x00, 0x4f, 0x00, 0x4f, 0x00, 0x4f, 0x00, 0x4f, 0x00, 0x4f, 0x00, 0x4f, 0x00, - 0x4f, 0x00, 0x4f, 0x00, 0x4f, 0x00, 0x4f, 0x00, 0x4f, 0x00, 0x4f, 0x00, 0x4f, 0x00, 0x4f, 0x00, - 0x4f, 0x00, 0x4f, 0x00, 0x4f, 0x00, 0x4f, 0x00, 0x4f, 0x00, 0x4f, 0x00, 0x4f, 0x00, 0xc8, 0x01, - 0x4f, 0x00, 0x4f, 0x00, 0x4f, 0x00, 0x4f, 0x00, 0x4f, 0x00, 0x4f, 0x00, 0x4f, 0x00, 0x4f, 0x00, - 0x4f, 0x00, 0x4f, 0x00, 0x4f, 0x00, 0x4f, 0x00, 0x4f, 0x00, 0x4f, 0x00, 0x4f, 0x00, 0x4b, 0x02, - 0x8f, 0x00, 0x8f, 0x00, 0x8f, 0x00, 0x8f, 0x00, 0x8f, 0x00, 0x8f, 0x00, 0x8f, 0x00, 0x8f, 0x00, - 0x8f, 0x00, 0x8f, 0x00, 0x8f, 0x00, 0x8f, 0x00, 0x8f, 0x00, 0x8f, 0x00, 0x8f, 0x00, 0x8f, 0x00, - 0x4f, 0x00, 0x4f, 0x00, 0x4f, 0x00, 0x4f, 0x00, 0x4f, 0x00, 0x4f, 0x00, 0x4f, 0x00, 0x4f, 0x00, - 0x4f, 0x00, 0x4f, 0x00, 0x4f, 0x00, 0x4f, 0x00, 0x4f, 0x00, 0x4f, 0x00, 0x4f, 0x00, 0x4f, 0x00, - 0x4f, 0x00, 0xcb, 0x00, 0x8f, 0x00, 0x8f, 0x00, 0x8f, 0x00, 0x4b, 0x02, 0x4c, 0x02, 0x4f, 0x00, - 0x4f, 0x00, 0x4f, 0x00, 0x4f, 0x00, 0x4f, 0x00, 0x4f, 0x00, 0x4f, 0x00, 0x4f, 0x00, 0x4f, 0x00, - 0x4f, 0x00, 0x4f, 0x00, 0x4f, 0x00, 0x4f, 0x00, 0x4f, 0x00, 0x4f, 0x00, 0x4f, 0x00, 0x4f, 0x00, - 0x4f, 0x00, 0x4f, 0x00, 0x4f, 0x00, 0x4f, 0x00, 0x4f, 0x00, 0x4f, 0x00, 0x4f, 0x00, 0xd1, 0x00, - 0x8f, 0x00, 0x8f, 0x00, 0x8f, 0x00, 0x8f, 0x00, 0x8f, 0x00, 0x8f, 0x00, 0x8f, 0x00, 0x8f, 0x00, - 0x8f, 0x00, 0x8f, 0x00, 0x8f, 0x00, 0x8f, 0x00, 0x8f, 0x00, 0x8f, 0x00, 0x8f, 0x00, 0x8f, 0x00, - 0x4f, 0x00, 0x4f, 0x00, 0x4f, 0x00, 0x4f, 0x00, 0x4f, 0x00, 0x4f, 0x00, 0x57, 0x01, 0x9a, 0x00, - 0xc7, 0x00, 0x4d, 0x02, 0x4e, 0x02, 0x8f, 0x00, 0x8f, 0x00, 0x8f, 0x00, 0x8f, 0x00, 0x8f, 0x00, - 0x8f, 0x00, 0x8f, 0x00, 0x8f, 0x00, 0x8f, 0x00, 0x8f, 0x00, 0x8f, 0x00, 0x8f, 0x00, 0x8f, 0x00, - 0x8f, 0x00, 0x8f, 0x00, 0x8f, 0x00, 0x8f, 0x00, 0x8f, 0x00, 0x8f, 0x00, 0x8f, 0x00, 0x8f, 0x00, - 0x20, 0x01, 0x20, 0x01, 0x20, 0x01, 0x20, 0x01, 0x20, 0x01, 0x20, 0x01, 0x20, 0x01, 0x20, 0x01, - 0x20, 0x01, 0x20, 0x01, 0x20, 0x01, 0x20, 0x01, 0x20, 0x01, 0x20, 0x01, 0x20, 0x01, 0x4f, 0x02, - 0x20, 0x01, 0x20, 0x01, 0x50, 0x02, 0x20, 0x01, 0x20, 0x01, 0x20, 0x01, 0x51, 0x02, 0x52, 0x02, - 0x53, 0x02, 0x20, 0x01, 0x54, 0x02, 0x20, 0x01, 0x20, 0x01, 0x20, 0x01, 0x55, 0x02, 0x8f, 0x00, - 0xd4, 0x00, 0xd4, 0x00, 0xd4, 0x00, 0xd4, 0x00, 0x56, 0x02, 0x8f, 0x00, 0x8f, 0x00, 0x8f, 0x00, - 0x8f, 0x00, 0x8f, 0x00, 0x8f, 0x00, 0x8f, 0x00, 0x8f, 0x00, 0x8f, 0x00, 0xb6, 0x01, 0x57, 0x02, - 0xd4, 0x00, 0xd4, 0x00, 0xd4, 0x00, 0xd4, 0x00, 0xd4, 0x00, 0x26, 0x01, 0xb6, 0x01, 0x58, 0x02, - 0x8f, 0x00, 0x8f, 0x00, 0x8f, 0x00, 0x8f, 0x00, 0x8f, 0x00, 0x8f, 0x00, 0x8f, 0x00, 0x8f, 0x00, - 0x0b, 0x00, 0x59, 0x02, 0x0d, 0x00, 0x5a, 0x02, 0x5b, 0x02, 0x5c, 0x02, 0xf6, 0x00, 0x0b, 0x00, - 0x5d, 0x02, 0x5e, 0x02, 0x5f, 0x02, 0x60, 0x02, 0x61, 0x02, 0x0b, 0x00, 0x59, 0x02, 0x0d, 0x00, - 0x62, 0x02, 0x63, 0x02, 0x0d, 0x00, 0x64, 0x02, 0x65, 0x02, 0x66, 0x02, 0x67, 0x02, 0x0b, 0x00, - 0x68, 0x02, 0x0d, 0x00, 0x0b, 0x00, 0x59, 0x02, 0x0d, 0x00, 0x5a, 0x02, 0x5b, 0x02, 0x0d, 0x00, - 0xf6, 0x00, 0x0b, 0x00, 0x5d, 0x02, 0x67, 0x02, 0x0b, 0x00, 0x68, 0x02, 0x0d, 0x00, 0x0b, 0x00, - 0x59, 0x02, 0x0d, 0x00, 0x69, 0x02, 0x0b, 0x00, 0x6a, 0x02, 0x6b, 0x02, 0x6c, 0x02, 0x6d, 0x02, - 0x0d, 0x00, 0x6e, 0x02, 0x0b, 0x00, 0x6f, 0x02, 0x70, 0x02, 0x71, 0x02, 0x72, 0x02, 0x0d, 0x00, - 0x73, 0x02, 0x0b, 0x00, 0x74, 0x02, 0x0d, 0x00, 0x75, 0x02, 0x76, 0x02, 0x76, 0x02, 0x76, 0x02, - 0x20, 0x01, 0x20, 0x01, 0x20, 0x01, 0x20, 0x01, 0x20, 0x01, 0x20, 0x01, 0x20, 0x01, 0x20, 0x01, - 0x20, 0x01, 0x20, 0x01, 0x20, 0x01, 0x20, 0x01, 0x20, 0x01, 0x20, 0x01, 0x20, 0x01, 0x20, 0x01, - 0x20, 0x01, 0x20, 0x01, 0x20, 0x01, 0x20, 0x01, 0x20, 0x01, 0x20, 0x01, 0x20, 0x01, 0x20, 0x01, - 0x20, 0x01, 0x20, 0x01, 0x20, 0x01, 0x20, 0x01, 0x20, 0x01, 0x20, 0x01, 0x20, 0x01, 0x20, 0x01, - 0x22, 0x00, 0x22, 0x00, 0x22, 0x00, 0x77, 0x02, 0x22, 0x00, 0x22, 0x00, 0x78, 0x02, 0x79, 0x02, - 0x7a, 0x02, 0x7b, 0x02, 0x7c, 0x02, 0x8f, 0x00, 0x8f, 0x00, 0x8f, 0x00, 0x8f, 0x00, 0x8f, 0x00, - 0x8f, 0x00, 0x8f, 0x00, 0x8f, 0x00, 0x8f, 0x00, 0x8f, 0x00, 0x8f, 0x00, 0x8f, 0x00, 0x8f, 0x00, - 0x8f, 0x00, 0x8f, 0x00, 0x8f, 0x00, 0x8f, 0x00, 0x8f, 0x00, 0x8f, 0x00, 0x8f, 0x00, 0x8f, 0x00, - 0x7d, 0x02, 0x7e, 0x02, 0x7f, 0x02, 0x8f, 0x00, 0x8f, 0x00, 0x8f, 0x00, 0x8f, 0x00, 0x8f, 0x00, - 0x8f, 0x00, 0x8f, 0x00, 0x8f, 0x00, 0x8f, 0x00, 0x8f, 0x00, 0x8f, 0x00, 0x8f, 0x00, 0x8f, 0x00, - 0x4f, 0x00, 0x4f, 0x00, 0x9a, 0x00, 0x80, 0x02, 0x81, 0x02, 0x8f, 0x00, 0x8f, 0x00, 0x8f, 0x00, - 0x8f, 0x00, 0x8f, 0x00, 0x8f, 0x00, 0x8f, 0x00, 0x8f, 0x00, 0x8f, 0x00, 0x8f, 0x00, 0x8f, 0x00, - 0x8f, 0x00, 0x8f, 0x00, 0x8f, 0x00, 0x8f, 0x00, 0x8f, 0x00, 0x8f, 0x00, 0x8f, 0x00, 0x8f, 0x00, - 0x8f, 0x00, 0x8f, 0x00, 0x8f, 0x00, 0x8f, 0x00, 0x4f, 0x00, 0x4f, 0x00, 0x82, 0x02, 0x83, 0x02, - 0x8f, 0x00, 0x8f, 0x00, 0x8f, 0x00, 0x8f, 0x00, 0x8f, 0x00, 0x8f, 0x00, 0x8f, 0x00, 0x8f, 0x00, - 0x8f, 0x00, 0x8f, 0x00, 0x8f, 0x00, 0x8f, 0x00, 0x8f, 0x00, 0x8f, 0x00, 0x8f, 0x00, 0x8f, 0x00, + 0x4a, 0x00, 0x4a, 0x00, 0x4a, 0x00, 0x4a, 0x00, 0x4a, 0x00, 0x4a, 0x00, 0x15, 0x01, 0xed, 0x01, + 0x32, 0x00, 0x32, 0x00, 0xee, 0x01, 0xef, 0x01, 0x4a, 0x00, 0x4a, 0x00, 0x4a, 0x00, 0x4a, 0x00, + 0x32, 0x00, 0xdd, 0x01, 0xf0, 0x01, 0x32, 0x00, 0x40, 0x00, 0xf1, 0x01, 0x4a, 0x00, 0x4a, 0x00, + 0x4a, 0x00, 0x4a, 0x00, 0x4a, 0x00, 0x32, 0x00, 0xf2, 0x01, 0x4a, 0x00, 0x32, 0x00, 0xf3, 0x01, + 0xf4, 0x01, 0x50, 0x00, 0x50, 0x00, 0xf5, 0x01, 0xf6, 0x01, 0xf7, 0x01, 0xf8, 0x01, 0xf9, 0x01, + 0xe2, 0x00, 0x50, 0x00, 0x50, 0x00, 0xfa, 0x01, 0xfb, 0x01, 0x50, 0x00, 0xc8, 0x00, 0xc4, 0x00, + 0xfc, 0x01, 0x50, 0x00, 0xfd, 0x01, 0xfe, 0x01, 0xff, 0x01, 0x50, 0x00, 0x50, 0x00, 0x00, 0x02, + 0xe2, 0x00, 0x50, 0x00, 0x50, 0x00, 0x01, 0x02, 0x02, 0x02, 0x03, 0x02, 0x04, 0x02, 0x05, 0x02, + 0x50, 0x00, 0x65, 0x00, 0x06, 0x02, 0x07, 0x02, 0x90, 0x00, 0x90, 0x00, 0x90, 0x00, 0x90, 0x00, + 0x08, 0x02, 0x09, 0x02, 0x0a, 0x02, 0x50, 0x00, 0x50, 0x00, 0x0b, 0x02, 0x0c, 0x02, 0xc4, 0x00, + 0x0d, 0x02, 0x57, 0x00, 0x58, 0x00, 0x0e, 0x02, 0x0f, 0x02, 0x10, 0x02, 0x11, 0x02, 0x12, 0x02, + 0x90, 0x00, 0x90, 0x00, 0x90, 0x00, 0x90, 0x00, 0x90, 0x00, 0x90, 0x00, 0x90, 0x00, 0x90, 0x00, + 0x50, 0x00, 0x50, 0x00, 0x50, 0x00, 0x13, 0x02, 0x14, 0x02, 0x15, 0x02, 0x16, 0x02, 0x90, 0x00, + 0x50, 0x00, 0x50, 0x00, 0x50, 0x00, 0x17, 0x02, 0x18, 0x02, 0xc4, 0x00, 0x90, 0x00, 0x90, 0x00, + 0x90, 0x00, 0x90, 0x00, 0x90, 0x00, 0x90, 0x00, 0x90, 0x00, 0x90, 0x00, 0x90, 0x00, 0x90, 0x00, + 0x50, 0x00, 0x50, 0x00, 0x19, 0x02, 0x1a, 0x02, 0x1b, 0x02, 0x1c, 0x02, 0x90, 0x00, 0x90, 0x00, + 0x50, 0x00, 0x50, 0x00, 0x50, 0x00, 0x1d, 0x02, 0x1e, 0x02, 0xc4, 0x00, 0x1f, 0x02, 0x90, 0x00, + 0x50, 0x00, 0x50, 0x00, 0x20, 0x02, 0x21, 0x02, 0xc4, 0x00, 0x90, 0x00, 0x90, 0x00, 0x90, 0x00, + 0x50, 0x00, 0xb1, 0x00, 0x22, 0x02, 0x23, 0x02, 0x90, 0x00, 0x90, 0x00, 0x90, 0x00, 0x90, 0x00, + 0x90, 0x00, 0x90, 0x00, 0x90, 0x00, 0x90, 0x00, 0x90, 0x00, 0x90, 0x00, 0x90, 0x00, 0x90, 0x00, + 0x50, 0x00, 0x50, 0x00, 0x06, 0x02, 0x24, 0x02, 0x90, 0x00, 0x90, 0x00, 0x90, 0x00, 0x90, 0x00, + 0x90, 0x00, 0x90, 0x00, 0x0b, 0x00, 0x0b, 0x00, 0x0d, 0x00, 0x0d, 0x00, 0x98, 0x00, 0x25, 0x02, + 0x26, 0x02, 0x27, 0x02, 0x50, 0x00, 0x28, 0x02, 0x29, 0x02, 0xc4, 0x00, 0x90, 0x00, 0x90, 0x00, + 0x90, 0x00, 0x90, 0x00, 0x2a, 0x02, 0x50, 0x00, 0x50, 0x00, 0x2b, 0x02, 0x2c, 0x02, 0x90, 0x00, + 0x2d, 0x02, 0x50, 0x00, 0x50, 0x00, 0x2e, 0x02, 0x2f, 0x02, 0x30, 0x02, 0x50, 0x00, 0x50, 0x00, + 0x31, 0x02, 0x32, 0x02, 0x33, 0x02, 0x90, 0x00, 0x50, 0x00, 0x50, 0x00, 0x50, 0x00, 0xc8, 0x00, + 0x90, 0x00, 0x90, 0x00, 0x90, 0x00, 0x90, 0x00, 0x90, 0x00, 0x90, 0x00, 0x90, 0x00, 0x90, 0x00, + 0x90, 0x00, 0x90, 0x00, 0x90, 0x00, 0x90, 0x00, 0x90, 0x00, 0x90, 0x00, 0x90, 0x00, 0x90, 0x00, + 0x58, 0x00, 0x50, 0x00, 0x19, 0x02, 0x34, 0x02, 0x35, 0x02, 0x98, 0x00, 0xb3, 0x00, 0x36, 0x02, + 0x50, 0x00, 0x37, 0x02, 0x38, 0x02, 0x39, 0x02, 0x90, 0x00, 0x90, 0x00, 0x90, 0x00, 0x90, 0x00, + 0x3a, 0x02, 0x50, 0x00, 0x50, 0x00, 0x3b, 0x02, 0x3c, 0x02, 0xc4, 0x00, 0x3d, 0x02, 0x50, 0x00, + 0x3e, 0x02, 0x3f, 0x02, 0xc4, 0x00, 0x90, 0x00, 0x90, 0x00, 0x90, 0x00, 0x90, 0x00, 0x90, 0x00, + 0x90, 0x00, 0x90, 0x00, 0x90, 0x00, 0x90, 0x00, 0x90, 0x00, 0x90, 0x00, 0x90, 0x00, 0x90, 0x00, + 0x90, 0x00, 0x90, 0x00, 0x90, 0x00, 0x90, 0x00, 0x90, 0x00, 0x90, 0x00, 0x50, 0x00, 0x40, 0x02, + 0x90, 0x00, 0x90, 0x00, 0x90, 0x00, 0x90, 0x00, 0x90, 0x00, 0x90, 0x00, 0x90, 0x00, 0x90, 0x00, + 0x90, 0x00, 0x90, 0x00, 0x90, 0x00, 0x68, 0x00, 0xb6, 0x01, 0x41, 0x02, 0x42, 0x02, 0x43, 0x02, + 0x50, 0x00, 0x50, 0x00, 0x50, 0x00, 0x50, 0x00, 0x50, 0x00, 0x50, 0x00, 0x50, 0x00, 0x50, 0x00, + 0x50, 0x00, 0x50, 0x00, 0x50, 0x00, 0x50, 0x00, 0x50, 0x00, 0x50, 0x00, 0x50, 0x00, 0x50, 0x00, + 0x50, 0x00, 0x50, 0x00, 0x50, 0x00, 0x50, 0x00, 0x50, 0x00, 0x50, 0x00, 0x50, 0x00, 0x50, 0x00, + 0x50, 0x00, 0xd3, 0x00, 0x90, 0x00, 0x90, 0x00, 0x90, 0x00, 0x90, 0x00, 0x90, 0x00, 0x90, 0x00, + 0x16, 0x01, 0x16, 0x01, 0x16, 0x01, 0x16, 0x01, 0x16, 0x01, 0x16, 0x01, 0x44, 0x02, 0x45, 0x02, + 0x50, 0x00, 0x50, 0x00, 0x50, 0x00, 0x50, 0x00, 0x50, 0x00, 0x50, 0x00, 0x50, 0x00, 0x50, 0x00, + 0x50, 0x00, 0x50, 0x00, 0x50, 0x00, 0x50, 0x00, 0x94, 0x01, 0x90, 0x00, 0x90, 0x00, 0x90, 0x00, + 0x90, 0x00, 0x90, 0x00, 0x90, 0x00, 0x90, 0x00, 0x90, 0x00, 0x90, 0x00, 0x90, 0x00, 0x90, 0x00, + 0x90, 0x00, 0x90, 0x00, 0x90, 0x00, 0x90, 0x00, 0x90, 0x00, 0x90, 0x00, 0x90, 0x00, 0x90, 0x00, + 0x90, 0x00, 0x90, 0x00, 0x90, 0x00, 0x90, 0x00, 0x90, 0x00, 0x90, 0x00, 0x90, 0x00, 0x90, 0x00, + 0x90, 0x00, 0x90, 0x00, 0x90, 0x00, 0x90, 0x00, 0x90, 0x00, 0x90, 0x00, 0x90, 0x00, 0x90, 0x00, + 0x90, 0x00, 0x90, 0x00, 0x90, 0x00, 0x90, 0x00, 0x90, 0x00, 0x90, 0x00, 0x90, 0x00, 0x90, 0x00, + 0x50, 0x00, 0x50, 0x00, 0xcc, 0x00, 0x46, 0x02, 0x90, 0x00, 0x90, 0x00, 0x90, 0x00, 0x90, 0x00, + 0x90, 0x00, 0x90, 0x00, 0x90, 0x00, 0x90, 0x00, 0x90, 0x00, 0x90, 0x00, 0x90, 0x00, 0x90, 0x00, + 0x90, 0x00, 0x90, 0x00, 0x90, 0x00, 0x90, 0x00, 0x90, 0x00, 0x90, 0x00, 0x90, 0x00, 0x90, 0x00, + 0x90, 0x00, 0x90, 0x00, 0x90, 0x00, 0x90, 0x00, 0x90, 0x00, 0x90, 0x00, 0x90, 0x00, 0x90, 0x00, + 0x50, 0x00, 0x50, 0x00, 0x50, 0x00, 0x50, 0x00, 0x45, 0x01, 0x90, 0x00, 0x90, 0x00, 0x90, 0x00, + 0x90, 0x00, 0x90, 0x00, 0x90, 0x00, 0x90, 0x00, 0x90, 0x00, 0x90, 0x00, 0x90, 0x00, 0x90, 0x00, + 0x90, 0x00, 0x90, 0x00, 0x90, 0x00, 0x90, 0x00, 0x90, 0x00, 0x90, 0x00, 0x90, 0x00, 0x90, 0x00, + 0x90, 0x00, 0x90, 0x00, 0x90, 0x00, 0x90, 0x00, 0x90, 0x00, 0x90, 0x00, 0x90, 0x00, 0x90, 0x00, + 0x50, 0x00, 0x50, 0x00, 0x50, 0x00, 0xc8, 0x00, 0x50, 0x00, 0xcc, 0x00, 0x82, 0x01, 0x90, 0x00, + 0x90, 0x00, 0x90, 0x00, 0x90, 0x00, 0x90, 0x00, 0x90, 0x00, 0x50, 0x00, 0xd0, 0x00, 0x47, 0x02, + 0x50, 0x00, 0x50, 0x00, 0x50, 0x00, 0x48, 0x02, 0x49, 0x02, 0x4a, 0x02, 0x4b, 0x02, 0x4c, 0x02, + 0x50, 0x00, 0x90, 0x00, 0x90, 0x00, 0x90, 0x00, 0x90, 0x00, 0x90, 0x00, 0x90, 0x00, 0x90, 0x00, + 0x90, 0x00, 0x90, 0x00, 0x90, 0x00, 0x90, 0x00, 0x0b, 0x00, 0x0b, 0x00, 0x0d, 0x00, 0x0d, 0x00, + 0xb6, 0x01, 0x4d, 0x02, 0x90, 0x00, 0x90, 0x00, 0x90, 0x00, 0x90, 0x00, 0x90, 0x00, 0x90, 0x00, + 0x50, 0x00, 0x50, 0x00, 0x50, 0x00, 0x50, 0x00, 0x4e, 0x02, 0x4f, 0x02, 0x50, 0x02, 0x50, 0x02, + 0x51, 0x02, 0x52, 0x02, 0x90, 0x00, 0x90, 0x00, 0x90, 0x00, 0x90, 0x00, 0x53, 0x02, 0x54, 0x02, + 0x50, 0x00, 0x50, 0x00, 0x50, 0x00, 0x50, 0x00, 0x50, 0x00, 0x50, 0x00, 0x50, 0x00, 0x50, 0x00, + 0x50, 0x00, 0x50, 0x00, 0x50, 0x00, 0x50, 0x00, 0x50, 0x00, 0x50, 0x00, 0x50, 0x00, 0x50, 0x00, + 0x50, 0x00, 0x50, 0x00, 0x50, 0x00, 0x50, 0x00, 0x50, 0x00, 0x50, 0x00, 0x50, 0x00, 0x50, 0x00, + 0x50, 0x00, 0x50, 0x00, 0x50, 0x00, 0x50, 0x00, 0x50, 0x00, 0x50, 0x00, 0x50, 0x00, 0xc9, 0x01, + 0x50, 0x00, 0x50, 0x00, 0x50, 0x00, 0x50, 0x00, 0x50, 0x00, 0x50, 0x00, 0x50, 0x00, 0x50, 0x00, + 0x50, 0x00, 0x50, 0x00, 0x50, 0x00, 0x50, 0x00, 0x50, 0x00, 0xcb, 0x00, 0x90, 0x00, 0x90, 0x00, + 0xc8, 0x00, 0x90, 0x00, 0x90, 0x00, 0x90, 0x00, 0x90, 0x00, 0x90, 0x00, 0x90, 0x00, 0x90, 0x00, + 0x90, 0x00, 0x90, 0x00, 0x90, 0x00, 0x90, 0x00, 0x90, 0x00, 0x90, 0x00, 0x90, 0x00, 0x90, 0x00, + 0x50, 0x00, 0x50, 0x00, 0x50, 0x00, 0x50, 0x00, 0x50, 0x00, 0x50, 0x00, 0x50, 0x00, 0x50, 0x00, + 0x50, 0x00, 0x50, 0x00, 0x50, 0x00, 0x50, 0x00, 0x50, 0x00, 0x50, 0x00, 0x50, 0x00, 0x50, 0x00, + 0x50, 0x00, 0xcc, 0x00, 0x90, 0x00, 0x90, 0x00, 0x90, 0x00, 0x55, 0x02, 0x56, 0x02, 0x50, 0x00, + 0x50, 0x00, 0x50, 0x00, 0x50, 0x00, 0x50, 0x00, 0x50, 0x00, 0x50, 0x00, 0x50, 0x00, 0x50, 0x00, + 0x50, 0x00, 0x50, 0x00, 0x50, 0x00, 0x50, 0x00, 0x50, 0x00, 0x50, 0x00, 0x50, 0x00, 0x50, 0x00, + 0x50, 0x00, 0x50, 0x00, 0x50, 0x00, 0x50, 0x00, 0x50, 0x00, 0x50, 0x00, 0x50, 0x00, 0xd2, 0x00, + 0x90, 0x00, 0x90, 0x00, 0x90, 0x00, 0x90, 0x00, 0x90, 0x00, 0x90, 0x00, 0x90, 0x00, 0x90, 0x00, + 0x90, 0x00, 0x90, 0x00, 0x90, 0x00, 0x90, 0x00, 0x90, 0x00, 0x90, 0x00, 0x90, 0x00, 0x90, 0x00, + 0x50, 0x00, 0x50, 0x00, 0x50, 0x00, 0x50, 0x00, 0x50, 0x00, 0x50, 0x00, 0xb4, 0x01, 0x9b, 0x00, + 0xc8, 0x00, 0x57, 0x02, 0x58, 0x02, 0x90, 0x00, 0x90, 0x00, 0x90, 0x00, 0x90, 0x00, 0x90, 0x00, + 0x90, 0x00, 0x90, 0x00, 0x90, 0x00, 0x90, 0x00, 0x90, 0x00, 0x90, 0x00, 0x90, 0x00, 0x90, 0x00, + 0x90, 0x00, 0x90, 0x00, 0x90, 0x00, 0x90, 0x00, 0x90, 0x00, 0x90, 0x00, 0x90, 0x00, 0x90, 0x00, + 0x21, 0x01, 0x21, 0x01, 0x21, 0x01, 0x21, 0x01, 0x21, 0x01, 0x21, 0x01, 0x21, 0x01, 0x21, 0x01, + 0x21, 0x01, 0x21, 0x01, 0x21, 0x01, 0x21, 0x01, 0x21, 0x01, 0x21, 0x01, 0x21, 0x01, 0x59, 0x02, + 0x21, 0x01, 0x21, 0x01, 0x5a, 0x02, 0x21, 0x01, 0x21, 0x01, 0x21, 0x01, 0x5b, 0x02, 0x5c, 0x02, + 0x5d, 0x02, 0x21, 0x01, 0x5e, 0x02, 0x21, 0x01, 0x21, 0x01, 0x21, 0x01, 0x5f, 0x02, 0x90, 0x00, + 0xd5, 0x00, 0xd5, 0x00, 0xd5, 0x00, 0xd5, 0x00, 0x60, 0x02, 0x90, 0x00, 0x90, 0x00, 0x90, 0x00, + 0x90, 0x00, 0x90, 0x00, 0x90, 0x00, 0x90, 0x00, 0x90, 0x00, 0x90, 0x00, 0xb6, 0x01, 0x61, 0x02, + 0xd5, 0x00, 0xd5, 0x00, 0xd5, 0x00, 0xd5, 0x00, 0xd5, 0x00, 0x27, 0x01, 0xb6, 0x01, 0x62, 0x02, + 0x90, 0x00, 0x90, 0x00, 0x90, 0x00, 0x90, 0x00, 0x90, 0x00, 0x90, 0x00, 0x90, 0x00, 0x90, 0x00, + 0x0b, 0x00, 0x63, 0x02, 0x0d, 0x00, 0x64, 0x02, 0x65, 0x02, 0x66, 0x02, 0xf8, 0x00, 0x0b, 0x00, + 0x67, 0x02, 0x68, 0x02, 0x69, 0x02, 0x6a, 0x02, 0x6b, 0x02, 0x0b, 0x00, 0x63, 0x02, 0x0d, 0x00, + 0x6c, 0x02, 0x6d, 0x02, 0x0d, 0x00, 0x6e, 0x02, 0x6f, 0x02, 0x70, 0x02, 0x71, 0x02, 0x0b, 0x00, + 0x72, 0x02, 0x0d, 0x00, 0x0b, 0x00, 0x63, 0x02, 0x0d, 0x00, 0x64, 0x02, 0x65, 0x02, 0x0d, 0x00, + 0xf8, 0x00, 0x0b, 0x00, 0x67, 0x02, 0x71, 0x02, 0x0b, 0x00, 0x72, 0x02, 0x0d, 0x00, 0x0b, 0x00, + 0x63, 0x02, 0x0d, 0x00, 0x73, 0x02, 0x0b, 0x00, 0x74, 0x02, 0x75, 0x02, 0x76, 0x02, 0x77, 0x02, + 0x0d, 0x00, 0x78, 0x02, 0x0b, 0x00, 0x79, 0x02, 0x7a, 0x02, 0x7b, 0x02, 0x7c, 0x02, 0x0d, 0x00, + 0x7d, 0x02, 0x0b, 0x00, 0x7e, 0x02, 0x0d, 0x00, 0x7f, 0x02, 0x80, 0x02, 0x80, 0x02, 0x80, 0x02, + 0x21, 0x01, 0x21, 0x01, 0x21, 0x01, 0x21, 0x01, 0x21, 0x01, 0x21, 0x01, 0x21, 0x01, 0x21, 0x01, + 0x21, 0x01, 0x21, 0x01, 0x21, 0x01, 0x21, 0x01, 0x21, 0x01, 0x21, 0x01, 0x21, 0x01, 0x21, 0x01, + 0x21, 0x01, 0x21, 0x01, 0x21, 0x01, 0x21, 0x01, 0x21, 0x01, 0x21, 0x01, 0x21, 0x01, 0x21, 0x01, + 0x21, 0x01, 0x21, 0x01, 0x21, 0x01, 0x21, 0x01, 0x21, 0x01, 0x21, 0x01, 0x21, 0x01, 0x21, 0x01, + 0x22, 0x00, 0x22, 0x00, 0x22, 0x00, 0x81, 0x02, 0x22, 0x00, 0x22, 0x00, 0x82, 0x02, 0x83, 0x02, + 0x84, 0x02, 0x85, 0x02, 0x86, 0x02, 0x90, 0x00, 0x90, 0x00, 0x90, 0x00, 0x90, 0x00, 0x90, 0x00, + 0x90, 0x00, 0x90, 0x00, 0x90, 0x00, 0x90, 0x00, 0x90, 0x00, 0x90, 0x00, 0x90, 0x00, 0x90, 0x00, + 0x90, 0x00, 0x90, 0x00, 0x90, 0x00, 0x90, 0x00, 0x90, 0x00, 0x90, 0x00, 0x90, 0x00, 0x90, 0x00, + 0x87, 0x02, 0x88, 0x02, 0x89, 0x02, 0x90, 0x00, 0x90, 0x00, 0x90, 0x00, 0x90, 0x00, 0x90, 0x00, + 0x90, 0x00, 0x90, 0x00, 0x90, 0x00, 0x90, 0x00, 0x90, 0x00, 0x90, 0x00, 0x90, 0x00, 0x90, 0x00, + 0x50, 0x00, 0x50, 0x00, 0x9b, 0x00, 0x8a, 0x02, 0x8b, 0x02, 0x90, 0x00, 0x90, 0x00, 0x90, 0x00, + 0x90, 0x00, 0x90, 0x00, 0x90, 0x00, 0x90, 0x00, 0x90, 0x00, 0x90, 0x00, 0x90, 0x00, 0x90, 0x00, + 0x90, 0x00, 0x90, 0x00, 0x90, 0x00, 0x90, 0x00, 0x90, 0x00, 0x90, 0x00, 0x90, 0x00, 0x90, 0x00, + 0x90, 0x00, 0x90, 0x00, 0x90, 0x00, 0x90, 0x00, 0x50, 0x00, 0x50, 0x00, 0x8c, 0x02, 0x8d, 0x02, + 0x90, 0x00, 0x90, 0x00, 0x90, 0x00, 0x90, 0x00, 0x90, 0x00, 0x90, 0x00, 0x90, 0x00, 0x90, 0x00, + 0x90, 0x00, 0x90, 0x00, 0x90, 0x00, 0x90, 0x00, 0x90, 0x00, 0x90, 0x00, 0x90, 0x00, 0x90, 0x00, 0x32, 0x00, 0x32, 0x00, 0x32, 0x00, 0x32, 0x00, 0x32, 0x00, 0x32, 0x00, 0x32, 0x00, 0x32, 0x00, - 0x32, 0x00, 0x32, 0x00, 0x32, 0x00, 0x32, 0x00, 0x84, 0x02, 0x85, 0x02, 0x4a, 0x00, 0x4a, 0x00, - 0xe6, 0x01, 0xe6, 0x01, 0x86, 0x02, 0xe8, 0x01, 0x87, 0x02, 0x88, 0x02, 0x4a, 0x00, 0x4a, 0x00, + 0x32, 0x00, 0x32, 0x00, 0x32, 0x00, 0x32, 0x00, 0x8e, 0x02, 0x8f, 0x02, 0x4a, 0x00, 0x4a, 0x00, + 0xe7, 0x01, 0xe7, 0x01, 0x90, 0x02, 0xe9, 0x01, 0x91, 0x02, 0x92, 0x02, 0x4a, 0x00, 0x4a, 0x00, 0x4a, 0x00, 0x4a, 0x00, 0x4a, 0x00, 0x4a, 0x00, 0x4a, 0x00, 0x4a, 0x00, 0x4a, 0x00, 0x4a, 0x00, 0x4a, 0x00, 0x4a, 0x00, 0x4a, 0x00, 0x4a, 0x00, 0x4a, 0x00, 0x4a, 0x00, 0x4a, 0x00, 0x4a, 0x00, 0x4a, 0x00, 0x4a, 0x00, 0x4a, 0x00, 0x4a, 0x00, 0x4a, 0x00, 0x4a, 0x00, 0x4a, 0x00, 0x4a, 0x00, 0x4a, 0x00, 0x4a, 0x00, 0x4a, 0x00, 0x4a, 0x00, 0x4a, 0x00, 0x4a, 0x00, 0x4a, 0x00, 0x4a, 0x00, 0x4a, 0x00, 0x4a, 0x00, 0x4a, 0x00, 0x4a, 0x00, 0x4a, 0x00, 0x4a, 0x00, 0x4a, 0x00, 0x4a, 0x00, - 0x4a, 0x00, 0x4a, 0x00, 0x4a, 0x00, 0x4a, 0x00, 0x4a, 0x00, 0x4a, 0x00, 0x4a, 0x00, 0x89, 0x02, - 0xd4, 0x01, 0xd4, 0x01, 0x8a, 0x02, 0x8b, 0x02, 0x4a, 0x00, 0x4a, 0x00, 0x4a, 0x00, 0x4a, 0x00, - 0x89, 0x02, 0xd4, 0x01, 0x8c, 0x02, 0x8d, 0x02, 0x4a, 0x00, 0x4a, 0x00, 0x4a, 0x00, 0x4a, 0x00, + 0x4a, 0x00, 0x4a, 0x00, 0x4a, 0x00, 0x4a, 0x00, 0x4a, 0x00, 0x4a, 0x00, 0x4a, 0x00, 0x93, 0x02, + 0xd5, 0x01, 0xd5, 0x01, 0x94, 0x02, 0x95, 0x02, 0x4a, 0x00, 0x4a, 0x00, 0x4a, 0x00, 0x4a, 0x00, + 0x93, 0x02, 0xd5, 0x01, 0x96, 0x02, 0x97, 0x02, 0x4a, 0x00, 0x4a, 0x00, 0x4a, 0x00, 0x4a, 0x00, 0x4a, 0x00, 0x4a, 0x00, 0x4a, 0x00, 0x4a, 0x00, 0x4a, 0x00, 0x4a, 0x00, 0x4a, 0x00, 0x4a, 0x00, - 0x8e, 0x02, 0x32, 0x00, 0x8f, 0x02, 0x90, 0x02, 0x91, 0x02, 0x92, 0x02, 0x93, 0x02, 0x94, 0x02, - 0x95, 0x02, 0x96, 0x02, 0x97, 0x02, 0x96, 0x02, 0x4a, 0x00, 0x4a, 0x00, 0x4a, 0x00, 0x98, 0x02, + 0x98, 0x02, 0x32, 0x00, 0x99, 0x02, 0x9a, 0x02, 0x9b, 0x02, 0x9c, 0x02, 0x9d, 0x02, 0x9e, 0x02, + 0x9f, 0x02, 0xa0, 0x02, 0xa1, 0x02, 0xa0, 0x02, 0x4a, 0x00, 0x4a, 0x00, 0x4a, 0x00, 0xa2, 0x02, 0x4a, 0x00, 0x4a, 0x00, 0x4a, 0x00, 0x4a, 0x00, 0x4a, 0x00, 0x4a, 0x00, 0x4a, 0x00, 0x4a, 0x00, 0x4a, 0x00, 0x4a, 0x00, 0x4a, 0x00, 0x4a, 0x00, 0x4a, 0x00, 0x4a, 0x00, 0x4a, 0x00, 0x4a, 0x00, - 0xd4, 0x00, 0xd4, 0x00, 0x4e, 0x01, 0xd4, 0x00, 0xd4, 0x00, 0xd4, 0x00, 0xd4, 0x00, 0xd4, 0x00, - 0xd4, 0x00, 0x4c, 0x01, 0x99, 0x02, 0x9a, 0x02, 0x9a, 0x02, 0x9a, 0x02, 0xd4, 0x00, 0x4d, 0x01, - 0x9b, 0x02, 0x20, 0x01, 0x61, 0x01, 0x20, 0x01, 0x20, 0x01, 0x20, 0x01, 0x9c, 0x02, 0x20, 0x01, - 0x20, 0x01, 0x20, 0x01, 0x9d, 0x02, 0x8f, 0x00, 0x8f, 0x00, 0x8f, 0x00, 0x9e, 0x02, 0x20, 0x01, - 0x9f, 0x02, 0x20, 0x01, 0x20, 0x01, 0xa0, 0x02, 0x55, 0x02, 0xa1, 0x02, 0x4d, 0x01, 0x8f, 0x00, - 0x8f, 0x00, 0x8f, 0x00, 0x8f, 0x00, 0x8f, 0x00, 0x8f, 0x00, 0x8f, 0x00, 0x8f, 0x00, 0x8f, 0x00, - 0xd4, 0x00, 0xd4, 0x00, 0xd4, 0x00, 0xd4, 0x00, 0xd4, 0x00, 0xd4, 0x00, 0xd4, 0x00, 0xd4, 0x00, - 0xd4, 0x00, 0xd4, 0x00, 0xd4, 0x00, 0xd4, 0x00, 0xd4, 0x00, 0xd4, 0x00, 0xd4, 0x00, 0xa2, 0x02, - 0xd4, 0x00, 0xd4, 0x00, 0xd4, 0x00, 0xd4, 0x00, 0xd4, 0x00, 0xd4, 0x00, 0xd4, 0x00, 0xd4, 0x00, - 0xd4, 0x00, 0xd4, 0x00, 0xd4, 0x00, 0xd4, 0x00, 0xd4, 0x00, 0xd4, 0x00, 0xd4, 0x00, 0xd4, 0x00, - 0xd4, 0x00, 0xd4, 0x00, 0xd4, 0x00, 0xd4, 0x00, 0xd4, 0x00, 0xd4, 0x00, 0xd4, 0x00, 0xd4, 0x00, - 0xd4, 0x00, 0xd4, 0x00, 0xd4, 0x00, 0xd4, 0x00, 0xd4, 0x00, 0xd4, 0x00, 0xd4, 0x00, 0xd4, 0x00, - 0xd4, 0x00, 0xd4, 0x00, 0xd4, 0x00, 0xd4, 0x00, 0xd4, 0x00, 0xd4, 0x00, 0xd4, 0x00, 0xd4, 0x00, - 0xd4, 0x00, 0xd4, 0x00, 0xd4, 0x00, 0xd4, 0x00, 0xd4, 0x00, 0x4d, 0x01, 0xa3, 0x02, 0x27, 0x01, - 0xd4, 0x00, 0xd4, 0x00, 0xd4, 0x00, 0xd4, 0x00, 0xd4, 0x00, 0xd4, 0x00, 0xd4, 0x00, 0x4c, 0x01, - 0xd4, 0x00, 0xd4, 0x00, 0xd4, 0x00, 0xd4, 0x00, 0xd4, 0x00, 0xa4, 0x02, 0x4e, 0x01, 0x8f, 0x00, - 0x4e, 0x01, 0xd4, 0x00, 0xd4, 0x00, 0xd4, 0x00, 0xa5, 0x02, 0xb3, 0x00, 0xd4, 0x00, 0xd4, 0x00, - 0xa5, 0x02, 0xd4, 0x00, 0xa6, 0x02, 0x8f, 0x00, 0x8f, 0x00, 0x8f, 0x00, 0x8f, 0x00, 0x8f, 0x00, - 0xa7, 0x02, 0xd4, 0x00, 0xd4, 0x00, 0xd4, 0x00, 0xd4, 0x00, 0xd4, 0x00, 0xd4, 0x00, 0xa8, 0x02, - 0xd4, 0x00, 0xd4, 0x00, 0xa9, 0x02, 0xd4, 0x00, 0xaa, 0x02, 0xd4, 0x00, 0xd4, 0x00, 0xd4, 0x00, - 0xd4, 0x00, 0xd4, 0x00, 0xd4, 0x00, 0xd4, 0x00, 0xd4, 0x00, 0x4c, 0x01, 0xa6, 0x02, 0xab, 0x02, - 0xac, 0x02, 0x4d, 0x01, 0x8f, 0x00, 0x8f, 0x00, 0x8f, 0x00, 0x8f, 0x00, 0x8f, 0x00, 0x8f, 0x00, - 0x8f, 0x00, 0x8f, 0x00, 0x8f, 0x00, 0x8f, 0x00, 0x8f, 0x00, 0x8f, 0x00, 0x8f, 0x00, 0x8f, 0x00, - 0x8f, 0x00, 0x8f, 0x00, 0x8f, 0x00, 0x8f, 0x00, 0x8f, 0x00, 0x8f, 0x00, 0x8f, 0x00, 0x8f, 0x00, - 0x8f, 0x00, 0x8f, 0x00, 0x8f, 0x00, 0x8f, 0x00, 0x8f, 0x00, 0x8f, 0x00, 0x8f, 0x00, 0x8f, 0x00, - 0x8f, 0x00, 0x8f, 0x00, 0x8f, 0x00, 0x8f, 0x00, 0x8f, 0x00, 0x8f, 0x00, 0x8f, 0x00, 0x8f, 0x00, - 0x8f, 0x00, 0x8f, 0x00, 0x8f, 0x00, 0x8f, 0x00, 0x8f, 0x00, 0x8f, 0x00, 0x8f, 0x00, 0x8f, 0x00, - 0x8f, 0x00, 0x8f, 0x00, 0x8f, 0x00, 0x8f, 0x00, 0x8f, 0x00, 0x8f, 0x00, 0x8f, 0x00, 0xad, 0x02, - 0x4f, 0x00, 0x4f, 0x00, 0x4f, 0x00, 0x4f, 0x00, 0x4f, 0x00, 0x4f, 0x00, 0x4f, 0x00, 0x4f, 0x00, - 0x4f, 0x00, 0x4f, 0x00, 0x4f, 0x00, 0x4f, 0x00, 0x4f, 0x00, 0x44, 0x01, 0x8f, 0x00, 0x8f, 0x00, - 0x4f, 0x00, 0x4f, 0x00, 0x4f, 0x00, 0x4f, 0x00, 0x4f, 0x00, 0x4f, 0x00, 0x4f, 0x00, 0x4f, 0x00, - 0x4f, 0x00, 0x4f, 0x00, 0x4f, 0x00, 0x4f, 0x00, 0x4f, 0x00, 0x4f, 0x00, 0x4f, 0x00, 0x4f, 0x00, - 0x4f, 0x00, 0x4f, 0x00, 0x4f, 0x00, 0x4f, 0x00, 0x4f, 0x00, 0x4f, 0x00, 0x4f, 0x00, 0x4f, 0x00, - 0x4f, 0x00, 0x4f, 0x00, 0x4f, 0x00, 0x4f, 0x00, 0x4f, 0x00, 0x4f, 0x00, 0x4f, 0x00, 0x4f, 0x00, - 0x4f, 0x00, 0x4f, 0x00, 0x4f, 0x00, 0xd0, 0x00, 0x4f, 0x00, 0x4f, 0x00, 0x4f, 0x00, 0x4f, 0x00, - 0x4f, 0x00, 0x4f, 0x00, 0x4f, 0x00, 0x4f, 0x00, 0x4f, 0x00, 0x4f, 0x00, 0x4f, 0x00, 0x4f, 0x00, - 0x4f, 0x00, 0xcf, 0x00, 0x4f, 0x00, 0x4f, 0x00, 0x4f, 0x00, 0x4f, 0x00, 0x4f, 0x00, 0x4f, 0x00, - 0x4f, 0x00, 0x4f, 0x00, 0x4f, 0x00, 0x4f, 0x00, 0x4f, 0x00, 0x4f, 0x00, 0x4f, 0x00, 0x4f, 0x00, - 0x4f, 0x00, 0x4f, 0x00, 0x4f, 0x00, 0x4f, 0x00, 0x4f, 0x00, 0x4f, 0x00, 0x4f, 0x00, 0x4f, 0x00, - 0x4f, 0x00, 0x4f, 0x00, 0x4f, 0x00, 0x4f, 0x00, 0x4f, 0x00, 0x4f, 0x00, 0x4f, 0x00, 0x4f, 0x00, - 0x4f, 0x00, 0x4f, 0x00, 0x4f, 0x00, 0x4f, 0x00, 0x4f, 0x00, 0x4f, 0x00, 0x4f, 0x00, 0x4f, 0x00, - 0x4f, 0x00, 0x4f, 0x00, 0xae, 0x02, 0x4f, 0x00, 0x4f, 0x00, 0x4f, 0x00, 0x4f, 0x00, 0x4f, 0x00, - 0x4f, 0x00, 0x4f, 0x00, 0x4f, 0x00, 0x4f, 0x00, 0x4f, 0x00, 0x4f, 0x00, 0x4f, 0x00, 0x4f, 0x00, - 0x4f, 0x00, 0x4f, 0x00, 0x4f, 0x00, 0x4f, 0x00, 0x4f, 0x00, 0x4f, 0x00, 0x4f, 0x00, 0x4f, 0x00, - 0x4f, 0x00, 0x4f, 0x00, 0x4f, 0x00, 0x4f, 0x00, 0x4f, 0x00, 0x4f, 0x00, 0x4f, 0x00, 0x4f, 0x00, - 0x4f, 0x00, 0x4f, 0x00, 0x4f, 0x00, 0x4f, 0x00, 0x4f, 0x00, 0x4f, 0x00, 0x4f, 0x00, 0x4f, 0x00, - 0x4f, 0x00, 0x4f, 0x00, 0x4f, 0x00, 0x4f, 0x00, 0x4f, 0x00, 0x4f, 0x00, 0x4f, 0x00, 0x4f, 0x00, - 0x4f, 0x00, 0x4f, 0x00, 0x4f, 0x00, 0x4f, 0x00, 0x4f, 0x00, 0x4f, 0x00, 0x67, 0x00, 0x8f, 0x00, - 0x4f, 0x00, 0xcf, 0x00, 0x8f, 0x00, 0x8f, 0x00, 0x8f, 0x00, 0x8f, 0x00, 0x8f, 0x00, 0x8f, 0x00, - 0x8f, 0x00, 0x8f, 0x00, 0x8f, 0x00, 0x8f, 0x00, 0x8f, 0x00, 0x8f, 0x00, 0x8f, 0x00, 0x8f, 0x00, - 0x8f, 0x00, 0x8f, 0x00, 0x8f, 0x00, 0x8f, 0x00, 0x8f, 0x00, 0x8f, 0x00, 0x8f, 0x00, 0x8f, 0x00, - 0x8f, 0x00, 0x8f, 0x00, 0x8f, 0x00, 0x8f, 0x00, 0x8f, 0x00, 0x8f, 0x00, 0x8f, 0x00, 0x8f, 0x00, - 0xaf, 0x02, 0x0b, 0x01, 0xb0, 0x02, 0xb0, 0x02, 0xb0, 0x02, 0xb0, 0x02, 0xb0, 0x02, 0xb0, 0x02, - 0x0b, 0x01, 0x0b, 0x01, 0x0b, 0x01, 0x0b, 0x01, 0x0b, 0x01, 0x0b, 0x01, 0x0b, 0x01, 0x0b, 0x01, + 0xd5, 0x00, 0xd5, 0x00, 0x50, 0x01, 0xd5, 0x00, 0xd5, 0x00, 0xd5, 0x00, 0xd5, 0x00, 0xd5, 0x00, + 0xd5, 0x00, 0x4e, 0x01, 0xa3, 0x02, 0xa4, 0x02, 0xa4, 0x02, 0xa4, 0x02, 0xd5, 0x00, 0x4f, 0x01, + 0xa5, 0x02, 0x21, 0x01, 0x62, 0x01, 0x21, 0x01, 0x21, 0x01, 0x21, 0x01, 0xa6, 0x02, 0x21, 0x01, + 0x21, 0x01, 0x21, 0x01, 0xa7, 0x02, 0x90, 0x00, 0x90, 0x00, 0x90, 0x00, 0xa8, 0x02, 0x21, 0x01, + 0xa9, 0x02, 0x21, 0x01, 0x21, 0x01, 0xaa, 0x02, 0x5f, 0x02, 0xab, 0x02, 0x4f, 0x01, 0x90, 0x00, + 0x90, 0x00, 0x90, 0x00, 0x90, 0x00, 0x90, 0x00, 0x90, 0x00, 0x90, 0x00, 0x90, 0x00, 0x90, 0x00, + 0xd5, 0x00, 0xd5, 0x00, 0xd5, 0x00, 0xd5, 0x00, 0xd5, 0x00, 0xd5, 0x00, 0xd5, 0x00, 0xd5, 0x00, + 0xd5, 0x00, 0xd5, 0x00, 0xd5, 0x00, 0xd5, 0x00, 0xd5, 0x00, 0xd5, 0x00, 0xd5, 0x00, 0xac, 0x02, + 0xd5, 0x00, 0xd5, 0x00, 0xd5, 0x00, 0xd5, 0x00, 0xd5, 0x00, 0xd5, 0x00, 0xd5, 0x00, 0xd5, 0x00, + 0xd5, 0x00, 0xd5, 0x00, 0xd5, 0x00, 0xd5, 0x00, 0xd5, 0x00, 0xd5, 0x00, 0xd5, 0x00, 0xd5, 0x00, + 0xd5, 0x00, 0xd5, 0x00, 0xd5, 0x00, 0xd5, 0x00, 0xd5, 0x00, 0xd5, 0x00, 0xd5, 0x00, 0xd5, 0x00, + 0xd5, 0x00, 0xd5, 0x00, 0xd5, 0x00, 0xd5, 0x00, 0xd5, 0x00, 0xd5, 0x00, 0xd5, 0x00, 0xd5, 0x00, + 0xd5, 0x00, 0xd5, 0x00, 0xd5, 0x00, 0xd5, 0x00, 0xd5, 0x00, 0xd5, 0x00, 0xd5, 0x00, 0xd5, 0x00, + 0xd5, 0x00, 0xd5, 0x00, 0xd5, 0x00, 0xd5, 0x00, 0xd5, 0x00, 0xad, 0x02, 0xbb, 0x01, 0xbb, 0x01, + 0xd5, 0x00, 0xd5, 0x00, 0xd5, 0x00, 0xd5, 0x00, 0xd5, 0x00, 0xd5, 0x00, 0xd5, 0x00, 0x4e, 0x01, + 0xd5, 0x00, 0xd5, 0x00, 0xd5, 0x00, 0xd5, 0x00, 0xd5, 0x00, 0xae, 0x02, 0x50, 0x01, 0x90, 0x00, + 0x50, 0x01, 0xd5, 0x00, 0xd5, 0x00, 0xd5, 0x00, 0xad, 0x02, 0xb4, 0x00, 0xd5, 0x00, 0xd5, 0x00, + 0xad, 0x02, 0xd5, 0x00, 0xaf, 0x02, 0xb0, 0x02, 0x90, 0x00, 0x90, 0x00, 0x90, 0x00, 0x90, 0x00, + 0xd5, 0x00, 0xd5, 0x00, 0xd5, 0x00, 0xd5, 0x00, 0xd5, 0x00, 0xd5, 0x00, 0xd5, 0x00, 0xb1, 0x02, + 0xd5, 0x00, 0xd5, 0x00, 0xd5, 0x00, 0xd5, 0x00, 0xb2, 0x02, 0xd5, 0x00, 0xd5, 0x00, 0xd5, 0x00, + 0xd5, 0x00, 0xd5, 0x00, 0xd5, 0x00, 0xd5, 0x00, 0xd5, 0x00, 0x4e, 0x01, 0xaf, 0x02, 0xb3, 0x02, + 0x27, 0x01, 0xd5, 0x00, 0xae, 0x02, 0x27, 0x01, 0xb4, 0x02, 0x27, 0x01, 0x90, 0x00, 0x90, 0x00, + 0xd5, 0x00, 0xd5, 0x00, 0xd5, 0x00, 0xd5, 0x00, 0xd5, 0x00, 0xd5, 0x00, 0xd5, 0x00, 0xd5, 0x00, + 0xd5, 0x00, 0xb5, 0x02, 0xd5, 0x00, 0xd5, 0x00, 0x28, 0x01, 0x90, 0x00, 0x90, 0x00, 0xb6, 0x02, + 0x90, 0x00, 0x90, 0x00, 0x90, 0x00, 0x90, 0x00, 0x90, 0x00, 0x90, 0x00, 0x90, 0x00, 0x90, 0x00, + 0x90, 0x00, 0x90, 0x00, 0x90, 0x00, 0x90, 0x00, 0x90, 0x00, 0x90, 0x00, 0x90, 0x00, 0x90, 0x00, + 0x90, 0x00, 0x90, 0x00, 0x90, 0x00, 0x90, 0x00, 0x90, 0x00, 0x90, 0x00, 0x90, 0x00, 0x90, 0x00, + 0x90, 0x00, 0x90, 0x00, 0x90, 0x00, 0x90, 0x00, 0x90, 0x00, 0x90, 0x00, 0x90, 0x00, 0xb7, 0x02, + 0x50, 0x00, 0x50, 0x00, 0x50, 0x00, 0x50, 0x00, 0x50, 0x00, 0x50, 0x00, 0x50, 0x00, 0x50, 0x00, + 0x50, 0x00, 0x50, 0x00, 0x50, 0x00, 0x50, 0x00, 0x50, 0x00, 0xd0, 0x00, 0x90, 0x00, 0x90, 0x00, + 0x50, 0x00, 0x50, 0x00, 0x50, 0x00, 0x50, 0x00, 0x50, 0x00, 0x50, 0x00, 0x50, 0x00, 0x50, 0x00, + 0x50, 0x00, 0x50, 0x00, 0x50, 0x00, 0x50, 0x00, 0x50, 0x00, 0x50, 0x00, 0x50, 0x00, 0x50, 0x00, + 0x50, 0x00, 0x50, 0x00, 0x50, 0x00, 0x50, 0x00, 0x50, 0x00, 0x50, 0x00, 0x50, 0x00, 0x50, 0x00, + 0x50, 0x00, 0x50, 0x00, 0x50, 0x00, 0x50, 0x00, 0x50, 0x00, 0x50, 0x00, 0x50, 0x00, 0x50, 0x00, + 0x50, 0x00, 0x50, 0x00, 0x50, 0x00, 0xd1, 0x00, 0x50, 0x00, 0x50, 0x00, 0x50, 0x00, 0x50, 0x00, + 0x50, 0x00, 0x50, 0x00, 0x50, 0x00, 0x50, 0x00, 0x50, 0x00, 0x50, 0x00, 0x50, 0x00, 0x50, 0x00, + 0x50, 0x00, 0xd0, 0x00, 0x50, 0x00, 0x50, 0x00, 0x50, 0x00, 0x50, 0x00, 0x50, 0x00, 0x50, 0x00, + 0x50, 0x00, 0x50, 0x00, 0x50, 0x00, 0x50, 0x00, 0x50, 0x00, 0x50, 0x00, 0x50, 0x00, 0x50, 0x00, + 0x50, 0x00, 0x50, 0x00, 0x50, 0x00, 0x50, 0x00, 0x50, 0x00, 0x50, 0x00, 0x50, 0x00, 0x50, 0x00, + 0x50, 0x00, 0x50, 0x00, 0x50, 0x00, 0x50, 0x00, 0x50, 0x00, 0x50, 0x00, 0x50, 0x00, 0x50, 0x00, + 0x50, 0x00, 0x50, 0x00, 0x50, 0x00, 0x50, 0x00, 0x50, 0x00, 0x50, 0x00, 0x50, 0x00, 0x50, 0x00, + 0x50, 0x00, 0x50, 0x00, 0x16, 0x02, 0x50, 0x00, 0x50, 0x00, 0x50, 0x00, 0x50, 0x00, 0x50, 0x00, + 0x50, 0x00, 0x50, 0x00, 0x50, 0x00, 0x50, 0x00, 0x50, 0x00, 0x50, 0x00, 0x50, 0x00, 0x50, 0x00, + 0x50, 0x00, 0x50, 0x00, 0x50, 0x00, 0x50, 0x00, 0x50, 0x00, 0x50, 0x00, 0x50, 0x00, 0x50, 0x00, + 0x50, 0x00, 0x50, 0x00, 0x50, 0x00, 0x50, 0x00, 0x50, 0x00, 0x50, 0x00, 0x50, 0x00, 0x50, 0x00, + 0x50, 0x00, 0x50, 0x00, 0x50, 0x00, 0x50, 0x00, 0x50, 0x00, 0x50, 0x00, 0x50, 0x00, 0x50, 0x00, + 0x50, 0x00, 0x50, 0x00, 0x50, 0x00, 0x50, 0x00, 0x50, 0x00, 0x50, 0x00, 0x50, 0x00, 0x50, 0x00, + 0x50, 0x00, 0x50, 0x00, 0x50, 0x00, 0x50, 0x00, 0x50, 0x00, 0x50, 0x00, 0x68, 0x00, 0x90, 0x00, + 0x50, 0x00, 0xd0, 0x00, 0x90, 0x00, 0x90, 0x00, 0x90, 0x00, 0x90, 0x00, 0x90, 0x00, 0x90, 0x00, + 0x90, 0x00, 0x90, 0x00, 0x90, 0x00, 0x90, 0x00, 0x90, 0x00, 0x90, 0x00, 0x90, 0x00, 0x90, 0x00, + 0x90, 0x00, 0x90, 0x00, 0x90, 0x00, 0x90, 0x00, 0x90, 0x00, 0x90, 0x00, 0x90, 0x00, 0x90, 0x00, + 0x90, 0x00, 0x90, 0x00, 0x90, 0x00, 0x90, 0x00, 0x90, 0x00, 0x90, 0x00, 0x90, 0x00, 0x90, 0x00, + 0x50, 0x00, 0x50, 0x00, 0x50, 0x00, 0x50, 0x00, 0x50, 0x00, 0x50, 0x00, 0x50, 0x00, 0x50, 0x00, + 0x50, 0x00, 0x50, 0x00, 0x50, 0x00, 0x50, 0x00, 0x50, 0x00, 0x50, 0x00, 0x50, 0x00, 0x50, 0x00, + 0x50, 0x00, 0x50, 0x00, 0x50, 0x00, 0x50, 0x00, 0xb4, 0x01, 0x90, 0x00, 0x90, 0x00, 0x90, 0x00, + 0x90, 0x00, 0x90, 0x00, 0x90, 0x00, 0x90, 0x00, 0x90, 0x00, 0x90, 0x00, 0x90, 0x00, 0x90, 0x00, + 0xb8, 0x02, 0x0d, 0x01, 0xb9, 0x02, 0xb9, 0x02, 0xb9, 0x02, 0xb9, 0x02, 0xb9, 0x02, 0xb9, 0x02, + 0x0d, 0x01, 0x0d, 0x01, 0x0d, 0x01, 0x0d, 0x01, 0x0d, 0x01, 0x0d, 0x01, 0x0d, 0x01, 0x0d, 0x01, 0x22, 0x00, 0x22, 0x00, 0x22, 0x00, 0x22, 0x00, 0x22, 0x00, 0x22, 0x00, 0x22, 0x00, 0x22, 0x00, - 0x22, 0x00, 0x22, 0x00, 0x22, 0x00, 0x22, 0x00, 0x22, 0x00, 0x22, 0x00, 0x22, 0x00, 0x0b, 0x01, - 0x0b, 0x01, 0x0b, 0x01, 0x0b, 0x01, 0x0b, 0x01, 0x0b, 0x01, 0x0b, 0x01, 0x0b, 0x01, 0x0b, 0x01, - 0x0b, 0x01, 0x0b, 0x01, 0x0b, 0x01, 0x0b, 0x01, 0x0b, 0x01, 0x0b, 0x01, 0x0b, 0x01, 0x0b, 0x01, - 0x0b, 0x01, 0x0b, 0x01, 0x0b, 0x01, 0x0b, 0x01, 0x0b, 0x01, 0x0b, 0x01, 0x0b, 0x01, 0x0b, 0x01, - 0x0b, 0x01, 0x0b, 0x01, 0x0b, 0x01, 0x0b, 0x01, 0x0b, 0x01, 0x0b, 0x01, 0x0b, 0x01, 0x0b, 0x01, - 0x96, 0x01, 0x96, 0x01, 0x96, 0x01, 0x96, 0x01, 0x96, 0x01, 0x96, 0x01, 0x96, 0x01, 0x96, 0x01, - 0x96, 0x01, 0x96, 0x01, 0x96, 0x01, 0x96, 0x01, 0x96, 0x01, 0x96, 0x01, 0x96, 0x01, 0x96, 0x01, - 0x96, 0x01, 0x96, 0x01, 0x96, 0x01, 0x96, 0x01, 0x96, 0x01, 0x96, 0x01, 0x96, 0x01, 0x96, 0x01, - 0x96, 0x01, 0x96, 0x01, 0x96, 0x01, 0x96, 0x01, 0x96, 0x01, 0x96, 0x01, 0x96, 0x01, 0xb1, 0x02 + 0x22, 0x00, 0x22, 0x00, 0x22, 0x00, 0x22, 0x00, 0x22, 0x00, 0x22, 0x00, 0x22, 0x00, 0x0d, 0x01, + 0x0d, 0x01, 0x0d, 0x01, 0x0d, 0x01, 0x0d, 0x01, 0x0d, 0x01, 0x0d, 0x01, 0x0d, 0x01, 0x0d, 0x01, + 0x0d, 0x01, 0x0d, 0x01, 0x0d, 0x01, 0x0d, 0x01, 0x0d, 0x01, 0x0d, 0x01, 0x0d, 0x01, 0x0d, 0x01, + 0x0d, 0x01, 0x0d, 0x01, 0x0d, 0x01, 0x0d, 0x01, 0x0d, 0x01, 0x0d, 0x01, 0x0d, 0x01, 0x0d, 0x01, + 0x0d, 0x01, 0x0d, 0x01, 0x0d, 0x01, 0x0d, 0x01, 0x0d, 0x01, 0x0d, 0x01, 0x0d, 0x01, 0x0d, 0x01, + 0x97, 0x01, 0x97, 0x01, 0x97, 0x01, 0x97, 0x01, 0x97, 0x01, 0x97, 0x01, 0x97, 0x01, 0x97, 0x01, + 0x97, 0x01, 0x97, 0x01, 0x97, 0x01, 0x97, 0x01, 0x97, 0x01, 0x97, 0x01, 0x97, 0x01, 0x97, 0x01, + 0x97, 0x01, 0x97, 0x01, 0x97, 0x01, 0x97, 0x01, 0x97, 0x01, 0x97, 0x01, 0x97, 0x01, 0x97, 0x01, + 0x97, 0x01, 0x97, 0x01, 0x97, 0x01, 0x97, 0x01, 0x97, 0x01, 0x97, 0x01, 0x97, 0x01, 0xba, 0x02 }; - private static ReadOnlySpan CategoryCasingLevel3Index => new byte[11040] + private static ReadOnlySpan CategoryCasingLevel3Index => new byte[11184] { 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x01, 0x01, 0x01, 0x01, 0x01, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, @@ -630,7 +634,8 @@ namespace System.Globalization 0x1f, 0x1f, 0x1f, 0x1f, 0x1f, 0x1f, 0x1f, 0x1f, 0x1f, 0x17, 0x17, 0x17, 0x1c, 0x1c, 0x1e, 0x1c, 0x1f, 0x1f, 0x1f, 0x1f, 0x1f, 0x1f, 0x1f, 0x1f, 0x1f, 0x1f, 0x1f, 0x1c, 0x1c, 0x1c, 0x1c, 0x1c, 0x1c, 0x1c, 0x1c, 0x1c, 0x1c, 0x1c, 0x1c, 0x1c, 0x1c, 0x1c, 0x1c, 0x1c, 0x1c, 0x1c, 0x1c, 0x1c, - 0x1f, 0x1f, 0x1f, 0x1f, 0x1f, 0x1c, 0x1f, 0x1f, 0x1f, 0x1f, 0x1f, 0x1f, 0x1f, 0x1f, 0x1c, 0x1c, + 0x1f, 0x1f, 0x1f, 0x1f, 0x1f, 0x1c, 0x1f, 0x1f, 0x1f, 0x1f, 0x1f, 0x1f, 0x1f, 0x1f, 0x1f, 0x1f, + 0x1f, 0x1f, 0x1f, 0x1f, 0x1f, 0x1f, 0x1f, 0x1f, 0x1c, 0x1c, 0x1c, 0x1c, 0x1c, 0x1c, 0x1c, 0x1c, 0x1c, 0x1c, 0x1c, 0x17, 0x17, 0x17, 0x17, 0x17, 0x17, 0x17, 0x17, 0x17, 0x17, 0x17, 0x17, 0x17, 0x17, 0x17, 0x11, 0x17, 0x17, 0x17, 0x17, 0x17, 0x17, 0x17, 0x17, 0x17, 0x17, 0x17, 0x17, 0x17, 0x17, 0x17, 0x17, 0x26, 0x0f, 0x0f, 0x0f, 0x0f, 0x0f, 0x0f, 0x0f, 0x0f, 0x0f, 0x0f, 0x0f, 0x0f, @@ -663,7 +668,7 @@ namespace System.Globalization 0x18, 0x17, 0x26, 0x26, 0x18, 0x0f, 0x0f, 0x0f, 0x0f, 0x0f, 0x0f, 0x0f, 0x0f, 0x18, 0x18, 0x0f, 0x0f, 0x18, 0x0f, 0x0f, 0x18, 0x0f, 0x0f, 0x0f, 0x0f, 0x0f, 0x18, 0x18, 0x17, 0x0f, 0x26, 0x17, 0x26, 0x17, 0x17, 0x17, 0x17, 0x18, 0x18, 0x26, 0x26, 0x18, 0x18, 0x26, 0x26, 0x17, 0x18, 0x18, - 0x18, 0x18, 0x18, 0x18, 0x18, 0x18, 0x17, 0x26, 0x18, 0x18, 0x18, 0x18, 0x0f, 0x0f, 0x18, 0x0f, + 0x18, 0x18, 0x18, 0x18, 0x18, 0x17, 0x17, 0x26, 0x18, 0x18, 0x18, 0x18, 0x0f, 0x0f, 0x18, 0x0f, 0x19, 0x0f, 0x28, 0x28, 0x28, 0x28, 0x28, 0x28, 0x18, 0x18, 0x18, 0x18, 0x18, 0x18, 0x18, 0x18, 0x18, 0x18, 0x17, 0x0f, 0x18, 0x0f, 0x0f, 0x0f, 0x0f, 0x0f, 0x0f, 0x18, 0x18, 0x18, 0x0f, 0x0f, 0x0f, 0x18, 0x0f, 0x0f, 0x0f, 0x0f, 0x18, 0x18, 0x18, 0x0f, 0x0f, 0x18, 0x0f, 0x18, 0x0f, 0x0f, @@ -683,12 +688,12 @@ namespace System.Globalization 0x26, 0x26, 0x26, 0x26, 0x26, 0x18, 0x29, 0x26, 0x26, 0x18, 0x26, 0x26, 0x17, 0x17, 0x18, 0x18, 0x18, 0x18, 0x18, 0x18, 0x18, 0x26, 0x26, 0x18, 0x18, 0x18, 0x18, 0x18, 0x18, 0x18, 0x0f, 0x18, 0x18, 0x0f, 0x0f, 0x18, 0x18, 0x18, 0x18, 0x18, 0x18, 0x18, 0x18, 0x18, 0x18, 0x18, 0x18, 0x18, - 0x17, 0x17, 0x26, 0x26, 0x18, 0x0f, 0x0f, 0x0f, 0x0f, 0x0f, 0x0f, 0x0f, 0x0f, 0x18, 0x0f, 0x0f, + 0x17, 0x17, 0x26, 0x26, 0x0f, 0x0f, 0x0f, 0x0f, 0x0f, 0x0f, 0x0f, 0x0f, 0x0f, 0x18, 0x0f, 0x0f, 0x0f, 0x0f, 0x0f, 0x0f, 0x0f, 0x0f, 0x0f, 0x0f, 0x0f, 0x0f, 0x0f, 0x17, 0x17, 0x0f, 0x26, 0x26, 0x26, 0x17, 0x17, 0x17, 0x17, 0x18, 0x26, 0x26, 0x26, 0x18, 0x26, 0x26, 0x26, 0x17, 0x0f, 0x19, 0x18, 0x18, 0x18, 0x18, 0x0f, 0x0f, 0x0f, 0x26, 0x28, 0x28, 0x28, 0x28, 0x28, 0x28, 0x28, 0x0f, 0x28, 0x28, 0x28, 0x28, 0x28, 0x28, 0x28, 0x28, 0x28, 0x19, 0x0f, 0x0f, 0x0f, 0x0f, 0x0f, 0x0f, - 0x18, 0x18, 0x26, 0x26, 0x18, 0x0f, 0x0f, 0x0f, 0x0f, 0x0f, 0x0f, 0x0f, 0x0f, 0x0f, 0x0f, 0x0f, + 0x18, 0x17, 0x26, 0x26, 0x18, 0x0f, 0x0f, 0x0f, 0x0f, 0x0f, 0x0f, 0x0f, 0x0f, 0x0f, 0x0f, 0x0f, 0x0f, 0x0f, 0x0f, 0x0f, 0x0f, 0x0f, 0x0f, 0x18, 0x18, 0x18, 0x0f, 0x0f, 0x0f, 0x0f, 0x0f, 0x0f, 0x0f, 0x0f, 0x18, 0x0f, 0x0f, 0x0f, 0x0f, 0x0f, 0x0f, 0x0f, 0x0f, 0x0f, 0x18, 0x0f, 0x18, 0x18, 0x0f, 0x0f, 0x0f, 0x0f, 0x0f, 0x0f, 0x0f, 0x18, 0x18, 0x18, 0x17, 0x18, 0x18, 0x18, 0x18, 0x26, @@ -773,7 +778,8 @@ namespace System.Globalization 0x17, 0x26, 0x17, 0x26, 0x26, 0x17, 0x17, 0x17, 0x17, 0x17, 0x17, 0x17, 0x17, 0x26, 0x26, 0x26, 0x26, 0x26, 0x26, 0x17, 0x17, 0x17, 0x17, 0x17, 0x17, 0x17, 0x17, 0x17, 0x17, 0x18, 0x18, 0x17, 0x1b, 0x1b, 0x1b, 0x1b, 0x1b, 0x1b, 0x1b, 0x15, 0x1b, 0x1b, 0x1b, 0x1b, 0x1b, 0x1b, 0x18, 0x18, - 0x17, 0x17, 0x17, 0x17, 0x17, 0x17, 0x17, 0x17, 0x17, 0x17, 0x17, 0x17, 0x17, 0x17, 0x1a, 0x18, + 0x17, 0x17, 0x17, 0x17, 0x17, 0x17, 0x17, 0x17, 0x17, 0x17, 0x17, 0x17, 0x17, 0x17, 0x1a, 0x17, + 0x17, 0x18, 0x18, 0x18, 0x18, 0x18, 0x18, 0x18, 0x18, 0x18, 0x18, 0x18, 0x18, 0x18, 0x18, 0x18, 0x17, 0x17, 0x17, 0x17, 0x26, 0x0f, 0x0f, 0x0f, 0x0f, 0x0f, 0x0f, 0x0f, 0x0f, 0x0f, 0x0f, 0x0f, 0x0f, 0x0f, 0x0f, 0x0f, 0x17, 0x26, 0x17, 0x17, 0x17, 0x17, 0x17, 0x26, 0x17, 0x26, 0x26, 0x26, 0x26, 0x26, 0x17, 0x26, 0x26, 0x0f, 0x0f, 0x0f, 0x0f, 0x0f, 0x0f, 0x0f, 0x18, 0x18, 0x18, 0x18, @@ -825,7 +831,6 @@ namespace System.Globalization 0x2e, 0x2e, 0x2e, 0x2e, 0x2e, 0x2e, 0x2e, 0x2e, 0x2e, 0x2e, 0x2e, 0x2e, 0x2e, 0x2e, 0x2e, 0x2e, 0x17, 0x17, 0x17, 0x17, 0x17, 0x17, 0x17, 0x17, 0x17, 0x17, 0x17, 0x17, 0x17, 0x1a, 0x1a, 0x1a, 0x1a, 0x17, 0x1a, 0x1a, 0x1a, 0x17, 0x17, 0x17, 0x17, 0x17, 0x17, 0x17, 0x17, 0x17, 0x17, 0x17, - 0x17, 0x18, 0x18, 0x18, 0x18, 0x18, 0x18, 0x18, 0x18, 0x18, 0x18, 0x18, 0x18, 0x18, 0x18, 0x18, 0x0e, 0x0e, 0x0a, 0x0e, 0x0e, 0x0e, 0x0e, 0x0a, 0x0e, 0x0e, 0x0d, 0x0a, 0x0a, 0x0a, 0x0d, 0x0d, 0x0a, 0x0a, 0x0a, 0x0d, 0x0e, 0x0a, 0x0e, 0x0e, 0x07, 0x0a, 0x0a, 0x0a, 0x0a, 0x0a, 0x0e, 0x0e, 0x0e, 0x0e, 0x0e, 0x0e, 0x0a, 0x0e, 0x0a, 0x0e, 0x0a, 0x0e, 0x0a, 0x0a, 0x0a, 0x0a, 0x0e, 0x0d, @@ -869,7 +874,7 @@ namespace System.Globalization 0x07, 0x07, 0x07, 0x07, 0x07, 0x07, 0x07, 0x07, 0x07, 0x07, 0x07, 0x07, 0x05, 0x06, 0x07, 0x07, 0x07, 0x07, 0x07, 0x07, 0x07, 0x0e, 0x0e, 0x07, 0x07, 0x07, 0x07, 0x07, 0x07, 0x0e, 0x0e, 0x0e, 0x0e, 0x0e, 0x0e, 0x0e, 0x18, 0x18, 0x0e, 0x0e, 0x0e, 0x0e, 0x0e, 0x0e, 0x0e, 0x0e, 0x0e, 0x0e, - 0x0e, 0x0e, 0x0e, 0x0e, 0x0e, 0x0e, 0x18, 0x18, 0x0e, 0x0e, 0x0e, 0x0e, 0x0e, 0x0e, 0x0e, 0x0e, + 0x0e, 0x0e, 0x0e, 0x0e, 0x0e, 0x0e, 0x18, 0x0e, 0x0e, 0x0e, 0x0e, 0x0e, 0x0e, 0x0e, 0x0e, 0x0e, 0x0a, 0x0a, 0x0a, 0x0a, 0x0a, 0x0a, 0x0a, 0x0a, 0x0a, 0x0a, 0x0a, 0x0a, 0x0a, 0x0a, 0x0a, 0x18, 0x0d, 0x0d, 0x0d, 0x0d, 0x0d, 0x0d, 0x0d, 0x0d, 0x0d, 0x0d, 0x0d, 0x0d, 0x0d, 0x0d, 0x0d, 0x18, 0x0a, 0x0d, 0x0a, 0x0a, 0x0a, 0x0d, 0x0d, 0x0a, 0x0d, 0x0a, 0x0d, 0x0a, 0x0d, 0x0a, 0x0a, 0x0a, @@ -886,6 +891,7 @@ namespace System.Globalization 0x10, 0x13, 0x05, 0x06, 0x05, 0x06, 0x05, 0x06, 0x05, 0x06, 0x03, 0x03, 0x03, 0x03, 0x03, 0x16, 0x03, 0x03, 0x03, 0x03, 0x03, 0x03, 0x03, 0x03, 0x03, 0x03, 0x08, 0x08, 0x03, 0x03, 0x03, 0x03, 0x08, 0x03, 0x05, 0x03, 0x03, 0x03, 0x03, 0x03, 0x03, 0x03, 0x03, 0x03, 0x03, 0x03, 0x03, 0x03, + 0x0e, 0x0e, 0x03, 0x18, 0x18, 0x18, 0x18, 0x18, 0x18, 0x18, 0x18, 0x18, 0x18, 0x18, 0x18, 0x18, 0x0e, 0x0e, 0x0e, 0x0e, 0x0e, 0x0e, 0x0e, 0x0e, 0x0e, 0x0e, 0x18, 0x0e, 0x0e, 0x0e, 0x0e, 0x0e, 0x0e, 0x0e, 0x0e, 0x0e, 0x18, 0x18, 0x18, 0x18, 0x18, 0x18, 0x18, 0x18, 0x18, 0x18, 0x18, 0x18, 0x0e, 0x0e, 0x0e, 0x0e, 0x0e, 0x0e, 0x18, 0x18, 0x18, 0x18, 0x18, 0x18, 0x18, 0x18, 0x18, 0x18, @@ -898,7 +904,6 @@ namespace System.Globalization 0x0f, 0x0f, 0x0f, 0x0f, 0x0f, 0x0f, 0x0f, 0x0f, 0x0f, 0x0f, 0x0f, 0x03, 0x15, 0x15, 0x15, 0x0f, 0x18, 0x18, 0x18, 0x18, 0x18, 0x0f, 0x0f, 0x0f, 0x0f, 0x0f, 0x0f, 0x0f, 0x0f, 0x0f, 0x0f, 0x0f, 0x19, 0x19, 0x28, 0x28, 0x28, 0x28, 0x19, 0x19, 0x19, 0x19, 0x19, 0x19, 0x19, 0x19, 0x19, 0x19, - 0x0f, 0x0f, 0x0f, 0x0f, 0x0f, 0x0f, 0x0f, 0x0f, 0x0f, 0x0f, 0x0f, 0x18, 0x18, 0x18, 0x18, 0x18, 0x19, 0x19, 0x19, 0x19, 0x19, 0x19, 0x19, 0x19, 0x19, 0x19, 0x19, 0x19, 0x19, 0x0e, 0x0e, 0x18, 0x28, 0x28, 0x28, 0x28, 0x28, 0x28, 0x28, 0x28, 0x28, 0x28, 0x19, 0x19, 0x19, 0x19, 0x19, 0x19, 0x19, 0x19, 0x19, 0x19, 0x19, 0x19, 0x19, 0x19, 0x28, 0x28, 0x28, 0x28, 0x28, 0x28, 0x28, 0x28, @@ -925,10 +930,10 @@ namespace System.Globalization 0x0a, 0x0d, 0x0a, 0x0d, 0x0d, 0x0d, 0x0a, 0x0d, 0x0a, 0x0d, 0x0a, 0x0d, 0x0a, 0x0d, 0x0a, 0x0d, 0x0a, 0x0d, 0x0a, 0x0d, 0x0a, 0x0d, 0x0a, 0x0d, 0x0a, 0x0d, 0x0a, 0x0a, 0x0a, 0x0a, 0x0a, 0x0d, 0x0a, 0x0a, 0x0a, 0x0a, 0x0a, 0x0d, 0x0a, 0x0d, 0x0a, 0x0d, 0x0a, 0x0d, 0x0a, 0x0d, 0x0a, 0x0d, - 0x18, 0x18, 0x0a, 0x0d, 0x0a, 0x0a, 0x0a, 0x18, 0x18, 0x18, 0x18, 0x18, 0x18, 0x18, 0x18, 0x18, - 0x18, 0x18, 0x18, 0x18, 0x18, 0x18, 0x18, 0x0f, 0x15, 0x15, 0x0d, 0x0f, 0x0f, 0x0f, 0x0f, 0x0f, + 0x18, 0x18, 0x0a, 0x0d, 0x0a, 0x0a, 0x0a, 0x0a, 0x0d, 0x0a, 0x0d, 0x18, 0x18, 0x18, 0x18, 0x18, + 0x18, 0x18, 0x18, 0x18, 0x18, 0x0a, 0x0d, 0x0f, 0x15, 0x15, 0x0d, 0x0f, 0x0f, 0x0f, 0x0f, 0x0f, 0x0f, 0x0f, 0x17, 0x0f, 0x0f, 0x0f, 0x17, 0x0f, 0x0f, 0x0f, 0x0f, 0x17, 0x0f, 0x0f, 0x0f, 0x0f, - 0x0f, 0x0f, 0x0f, 0x26, 0x26, 0x17, 0x17, 0x26, 0x0e, 0x0e, 0x0e, 0x0e, 0x18, 0x18, 0x18, 0x18, + 0x0f, 0x0f, 0x0f, 0x26, 0x26, 0x17, 0x17, 0x26, 0x0e, 0x0e, 0x0e, 0x0e, 0x17, 0x18, 0x18, 0x18, 0x28, 0x28, 0x28, 0x28, 0x28, 0x28, 0x19, 0x19, 0x04, 0x0e, 0x18, 0x18, 0x18, 0x18, 0x18, 0x18, 0x0f, 0x0f, 0x0f, 0x0f, 0x03, 0x03, 0x03, 0x03, 0x18, 0x18, 0x18, 0x18, 0x18, 0x18, 0x18, 0x18, 0x26, 0x26, 0x0f, 0x0f, 0x0f, 0x0f, 0x0f, 0x0f, 0x0f, 0x0f, 0x0f, 0x0f, 0x0f, 0x0f, 0x0f, 0x0f, @@ -956,7 +961,7 @@ namespace System.Globalization 0x18, 0x0f, 0x0f, 0x0f, 0x0f, 0x0f, 0x0f, 0x18, 0x18, 0x0f, 0x0f, 0x0f, 0x0f, 0x0f, 0x0f, 0x18, 0x18, 0x0f, 0x0f, 0x0f, 0x0f, 0x0f, 0x0f, 0x18, 0x18, 0x18, 0x18, 0x18, 0x18, 0x18, 0x18, 0x18, 0x0d, 0x0d, 0x0d, 0x0d, 0x0d, 0x0d, 0x0d, 0x0d, 0x0d, 0x0d, 0x0d, 0x2f, 0x15, 0x15, 0x15, 0x15, - 0x0d, 0x0d, 0x0d, 0x0d, 0x0d, 0x0d, 0x0d, 0x0d, 0x18, 0x18, 0x18, 0x18, 0x18, 0x18, 0x18, 0x18, + 0x0d, 0x0d, 0x0d, 0x0d, 0x0d, 0x0d, 0x0d, 0x0d, 0x0d, 0x15, 0x0b, 0x0b, 0x18, 0x18, 0x18, 0x18, 0x0f, 0x0f, 0x0f, 0x26, 0x26, 0x17, 0x26, 0x26, 0x17, 0x26, 0x26, 0x1b, 0x26, 0x17, 0x18, 0x18, 0x0f, 0x0f, 0x0f, 0x0f, 0x18, 0x18, 0x18, 0x18, 0x18, 0x18, 0x18, 0x18, 0x18, 0x18, 0x18, 0x18, 0x0f, 0x0f, 0x0f, 0x0f, 0x0f, 0x0f, 0x0f, 0x18, 0x18, 0x18, 0x18, 0x0f, 0x0f, 0x0f, 0x0f, 0x0f, @@ -972,14 +977,12 @@ namespace System.Globalization 0x1c, 0x1c, 0x1c, 0x1f, 0x1f, 0x1f, 0x1f, 0x1f, 0x1f, 0x1f, 0x1f, 0x1f, 0x1f, 0x1f, 0x1f, 0x1f, 0x1f, 0x1f, 0x1f, 0x1f, 0x1f, 0x1f, 0x1f, 0x1f, 0x1f, 0x1f, 0x1f, 0x1f, 0x1f, 0x1f, 0x06, 0x05, 0x1c, 0x1c, 0x1f, 0x1f, 0x1f, 0x1f, 0x1f, 0x1f, 0x1f, 0x1f, 0x1f, 0x1f, 0x1f, 0x1f, 0x1f, 0x1f, - 0x1f, 0x1f, 0x1f, 0x1f, 0x1f, 0x1f, 0x1f, 0x1f, 0x1c, 0x1c, 0x1c, 0x1c, 0x1c, 0x1c, 0x1c, 0x1c, 0x1f, 0x1f, 0x1f, 0x1f, 0x1f, 0x1f, 0x1f, 0x1f, 0x1f, 0x1f, 0x1f, 0x1f, 0x21, 0x0e, 0x1c, 0x1c, 0x03, 0x03, 0x03, 0x03, 0x03, 0x03, 0x03, 0x05, 0x06, 0x03, 0x18, 0x18, 0x18, 0x18, 0x18, 0x18, 0x03, 0x08, 0x08, 0x0c, 0x0c, 0x05, 0x06, 0x05, 0x06, 0x05, 0x06, 0x05, 0x06, 0x05, 0x06, 0x05, 0x06, 0x05, 0x06, 0x05, 0x06, 0x03, 0x03, 0x05, 0x06, 0x03, 0x03, 0x03, 0x03, 0x0c, 0x0c, 0x0c, 0x03, 0x03, 0x03, 0x18, 0x03, 0x03, 0x03, 0x03, 0x08, 0x05, 0x06, 0x05, 0x06, 0x05, 0x06, 0x03, 0x03, 0x03, 0x07, 0x08, 0x07, 0x07, 0x07, 0x18, 0x03, 0x04, 0x03, 0x03, 0x18, 0x18, 0x18, 0x18, - 0x1f, 0x1f, 0x1f, 0x1f, 0x1f, 0x1c, 0x1f, 0x1f, 0x1f, 0x1f, 0x1f, 0x1f, 0x1f, 0x1f, 0x1f, 0x1f, 0x1f, 0x1f, 0x1f, 0x1f, 0x1f, 0x1f, 0x1f, 0x1f, 0x1f, 0x1f, 0x1f, 0x1f, 0x1f, 0x1c, 0x1c, 0x11, 0x18, 0x03, 0x03, 0x03, 0x04, 0x03, 0x03, 0x03, 0x05, 0x06, 0x03, 0x07, 0x03, 0x08, 0x03, 0x03, 0x0d, 0x0d, 0x0d, 0x0d, 0x0d, 0x0d, 0x0d, 0x0d, 0x0d, 0x0d, 0x0d, 0x05, 0x07, 0x06, 0x07, 0x05, @@ -992,12 +995,14 @@ namespace System.Globalization 0x2e, 0x2e, 0x2e, 0x2e, 0x2e, 0x2e, 0x2e, 0x2e, 0x2e, 0x11, 0x11, 0x11, 0x0e, 0x0e, 0x2e, 0x2e, 0x0f, 0x0f, 0x0f, 0x0f, 0x0f, 0x0f, 0x0f, 0x0f, 0x0f, 0x0f, 0x0f, 0x0f, 0x18, 0x0f, 0x0f, 0x0f, 0x0f, 0x0f, 0x0f, 0x0f, 0x0f, 0x0f, 0x0f, 0x0f, 0x0f, 0x0f, 0x0f, 0x18, 0x0f, 0x0f, 0x18, 0x0f, + 0x0f, 0x0f, 0x0f, 0x0f, 0x0f, 0x0f, 0x0f, 0x0f, 0x0f, 0x0f, 0x0f, 0x18, 0x18, 0x18, 0x18, 0x18, 0x1b, 0x03, 0x1b, 0x18, 0x18, 0x18, 0x18, 0x28, 0x28, 0x28, 0x28, 0x28, 0x28, 0x28, 0x28, 0x28, 0x28, 0x28, 0x28, 0x28, 0x28, 0x28, 0x28, 0x28, 0x28, 0x28, 0x28, 0x28, 0x28, 0x28, 0x28, 0x28, 0x28, 0x28, 0x28, 0x28, 0x18, 0x18, 0x18, 0x19, 0x19, 0x19, 0x19, 0x19, 0x19, 0x19, 0x19, 0x19, 0x33, 0x33, 0x33, 0x33, 0x33, 0x33, 0x33, 0x33, 0x33, 0x33, 0x33, 0x33, 0x33, 0x33, 0x33, 0x33, 0x33, 0x33, 0x33, 0x33, 0x33, 0x12, 0x12, 0x12, 0x12, 0x0e, 0x0e, 0x0e, 0x0e, 0x0e, 0x0e, 0x0e, 0x0e, 0x0e, 0x0e, 0x0e, 0x0e, 0x0e, 0x0e, 0x0e, 0x0e, 0x0e, 0x12, 0x12, 0x0e, 0x19, 0x19, 0x18, + 0x0e, 0x0e, 0x0e, 0x0e, 0x0e, 0x0e, 0x0e, 0x0e, 0x0e, 0x0e, 0x0e, 0x0e, 0x0e, 0x18, 0x18, 0x18, 0x0e, 0x18, 0x18, 0x18, 0x18, 0x18, 0x18, 0x18, 0x18, 0x18, 0x18, 0x18, 0x18, 0x18, 0x18, 0x18, 0x19, 0x19, 0x19, 0x19, 0x19, 0x19, 0x19, 0x19, 0x19, 0x19, 0x19, 0x19, 0x19, 0x17, 0x18, 0x18, 0x17, 0x12, 0x12, 0x12, 0x12, 0x12, 0x12, 0x12, 0x12, 0x12, 0x12, 0x12, 0x12, 0x12, 0x12, 0x12, @@ -1048,8 +1053,11 @@ namespace System.Globalization 0x1f, 0x1f, 0x1f, 0x1f, 0x17, 0x17, 0x17, 0x17, 0x1c, 0x1c, 0x1c, 0x1c, 0x1c, 0x1c, 0x1c, 0x1c, 0x09, 0x09, 0x09, 0x09, 0x09, 0x09, 0x09, 0x09, 0x09, 0x09, 0x1c, 0x1c, 0x1c, 0x1c, 0x1c, 0x1c, 0x12, 0x12, 0x12, 0x12, 0x12, 0x12, 0x12, 0x12, 0x12, 0x12, 0x12, 0x12, 0x12, 0x12, 0x12, 0x1c, + 0x1f, 0x1f, 0x1f, 0x1f, 0x1f, 0x1f, 0x1f, 0x1f, 0x1f, 0x1f, 0x1c, 0x17, 0x17, 0x1d, 0x1c, 0x1c, + 0x1f, 0x1f, 0x1c, 0x1c, 0x1c, 0x1c, 0x1c, 0x1c, 0x1c, 0x1c, 0x1c, 0x1c, 0x1c, 0x1c, 0x1c, 0x1c, 0x34, 0x34, 0x34, 0x34, 0x34, 0x34, 0x34, 0x1f, 0x1c, 0x1c, 0x1c, 0x1c, 0x1c, 0x1c, 0x1c, 0x1c, 0x17, 0x34, 0x34, 0x34, 0x34, 0x1e, 0x1e, 0x1e, 0x1e, 0x1e, 0x1c, 0x1c, 0x1c, 0x1c, 0x1c, 0x1c, + 0x1f, 0x1f, 0x1f, 0x1f, 0x1f, 0x34, 0x34, 0x34, 0x34, 0x34, 0x34, 0x34, 0x1c, 0x1c, 0x1c, 0x1c, 0x1f, 0x1f, 0x1f, 0x1f, 0x1f, 0x1f, 0x1f, 0x1c, 0x1c, 0x1c, 0x1c, 0x1c, 0x1c, 0x1c, 0x1c, 0x1c, 0x26, 0x17, 0x26, 0x0f, 0x0f, 0x0f, 0x0f, 0x0f, 0x0f, 0x0f, 0x0f, 0x0f, 0x0f, 0x0f, 0x0f, 0x0f, 0x0f, 0x0f, 0x0f, 0x0f, 0x0f, 0x0f, 0x0f, 0x0f, 0x17, 0x17, 0x17, 0x17, 0x17, 0x17, 0x17, 0x17, @@ -1062,10 +1070,10 @@ namespace System.Globalization 0x17, 0x17, 0x17, 0x0f, 0x0f, 0x0f, 0x0f, 0x0f, 0x0f, 0x0f, 0x0f, 0x0f, 0x0f, 0x0f, 0x0f, 0x0f, 0x0f, 0x0f, 0x0f, 0x0f, 0x0f, 0x0f, 0x0f, 0x17, 0x17, 0x17, 0x17, 0x17, 0x26, 0x17, 0x17, 0x17, 0x17, 0x17, 0x17, 0x17, 0x17, 0x18, 0x27, 0x27, 0x27, 0x27, 0x27, 0x27, 0x27, 0x27, 0x27, 0x27, - 0x1b, 0x1b, 0x1b, 0x1b, 0x0f, 0x26, 0x26, 0x18, 0x18, 0x18, 0x18, 0x18, 0x18, 0x18, 0x18, 0x18, + 0x1b, 0x1b, 0x1b, 0x1b, 0x0f, 0x26, 0x26, 0x0f, 0x18, 0x18, 0x18, 0x18, 0x18, 0x18, 0x18, 0x18, 0x0f, 0x0f, 0x0f, 0x17, 0x1b, 0x1b, 0x0f, 0x18, 0x18, 0x18, 0x18, 0x18, 0x18, 0x18, 0x18, 0x18, 0x0f, 0x0f, 0x0f, 0x26, 0x26, 0x26, 0x17, 0x17, 0x17, 0x17, 0x17, 0x17, 0x17, 0x17, 0x17, 0x26, - 0x26, 0x0f, 0x0f, 0x0f, 0x0f, 0x1b, 0x1b, 0x1b, 0x1b, 0x17, 0x17, 0x17, 0x17, 0x1b, 0x18, 0x18, + 0x26, 0x0f, 0x0f, 0x0f, 0x0f, 0x1b, 0x1b, 0x1b, 0x1b, 0x17, 0x17, 0x17, 0x17, 0x1b, 0x26, 0x17, 0x27, 0x27, 0x27, 0x27, 0x27, 0x27, 0x27, 0x27, 0x27, 0x27, 0x0f, 0x1b, 0x0f, 0x1b, 0x1b, 0x1b, 0x18, 0x28, 0x28, 0x28, 0x28, 0x28, 0x28, 0x28, 0x28, 0x28, 0x28, 0x28, 0x28, 0x28, 0x28, 0x28, 0x28, 0x28, 0x28, 0x28, 0x28, 0x18, 0x18, 0x18, 0x18, 0x18, 0x18, 0x18, 0x18, 0x18, 0x18, 0x18, @@ -1084,7 +1092,8 @@ namespace System.Globalization 0x17, 0x17, 0x17, 0x17, 0x17, 0x18, 0x18, 0x18, 0x18, 0x18, 0x18, 0x18, 0x18, 0x18, 0x18, 0x18, 0x0f, 0x0f, 0x0f, 0x0f, 0x0f, 0x26, 0x26, 0x26, 0x17, 0x17, 0x17, 0x17, 0x17, 0x17, 0x17, 0x17, 0x26, 0x26, 0x17, 0x17, 0x17, 0x26, 0x17, 0x0f, 0x0f, 0x0f, 0x0f, 0x1b, 0x1b, 0x1b, 0x1b, 0x1b, - 0x27, 0x27, 0x27, 0x27, 0x27, 0x27, 0x27, 0x27, 0x27, 0x27, 0x18, 0x1b, 0x18, 0x1b, 0x17, 0x0f, + 0x27, 0x27, 0x27, 0x27, 0x27, 0x27, 0x27, 0x27, 0x27, 0x27, 0x1b, 0x1b, 0x18, 0x1b, 0x17, 0x0f, + 0x0f, 0x0f, 0x18, 0x18, 0x18, 0x18, 0x18, 0x18, 0x18, 0x18, 0x18, 0x18, 0x18, 0x18, 0x18, 0x18, 0x26, 0x26, 0x26, 0x17, 0x17, 0x17, 0x17, 0x17, 0x17, 0x26, 0x17, 0x26, 0x26, 0x26, 0x26, 0x17, 0x17, 0x26, 0x17, 0x17, 0x0f, 0x0f, 0x1b, 0x0f, 0x18, 0x18, 0x18, 0x18, 0x18, 0x18, 0x18, 0x18, 0x0f, 0x0f, 0x0f, 0x0f, 0x0f, 0x0f, 0x0f, 0x0f, 0x0f, 0x0f, 0x0f, 0x0f, 0x0f, 0x0f, 0x0f, 0x26, @@ -1100,6 +1109,10 @@ namespace System.Globalization 0x27, 0x27, 0x27, 0x27, 0x27, 0x27, 0x27, 0x27, 0x27, 0x27, 0x28, 0x28, 0x1b, 0x1b, 0x1b, 0x19, 0x17, 0x17, 0x17, 0x17, 0x17, 0x17, 0x17, 0x17, 0x26, 0x17, 0x17, 0x1b, 0x18, 0x18, 0x18, 0x18, 0x28, 0x28, 0x28, 0x18, 0x18, 0x18, 0x18, 0x18, 0x18, 0x18, 0x18, 0x18, 0x18, 0x18, 0x18, 0x0f, + 0x0f, 0x0f, 0x0f, 0x0f, 0x0f, 0x0f, 0x0f, 0x18, 0x18, 0x0f, 0x18, 0x18, 0x0f, 0x0f, 0x0f, 0x0f, + 0x0f, 0x0f, 0x0f, 0x0f, 0x18, 0x0f, 0x0f, 0x18, 0x0f, 0x0f, 0x0f, 0x0f, 0x0f, 0x0f, 0x0f, 0x0f, + 0x26, 0x26, 0x26, 0x26, 0x26, 0x26, 0x18, 0x26, 0x26, 0x18, 0x18, 0x17, 0x17, 0x26, 0x17, 0x0f, + 0x26, 0x0f, 0x26, 0x17, 0x1b, 0x1b, 0x1b, 0x18, 0x18, 0x18, 0x18, 0x18, 0x18, 0x18, 0x18, 0x18, 0x0f, 0x0f, 0x0f, 0x0f, 0x0f, 0x0f, 0x0f, 0x0f, 0x18, 0x18, 0x0f, 0x0f, 0x0f, 0x0f, 0x0f, 0x0f, 0x0f, 0x26, 0x26, 0x26, 0x17, 0x17, 0x17, 0x17, 0x18, 0x18, 0x17, 0x17, 0x26, 0x26, 0x26, 0x26, 0x17, 0x0f, 0x1b, 0x0f, 0x26, 0x18, 0x18, 0x18, 0x18, 0x18, 0x18, 0x18, 0x18, 0x18, 0x18, 0x18, @@ -1141,7 +1154,8 @@ namespace System.Globalization 0x26, 0x26, 0x26, 0x26, 0x26, 0x26, 0x26, 0x26, 0x26, 0x26, 0x26, 0x26, 0x26, 0x26, 0x26, 0x26, 0x26, 0x26, 0x26, 0x26, 0x26, 0x26, 0x26, 0x26, 0x18, 0x18, 0x18, 0x18, 0x18, 0x18, 0x18, 0x17, 0x17, 0x17, 0x17, 0x15, 0x15, 0x15, 0x15, 0x15, 0x15, 0x15, 0x15, 0x15, 0x15, 0x15, 0x15, 0x15, - 0x15, 0x15, 0x03, 0x15, 0x18, 0x18, 0x18, 0x18, 0x18, 0x18, 0x18, 0x18, 0x18, 0x18, 0x18, 0x18, + 0x15, 0x15, 0x03, 0x15, 0x17, 0x18, 0x18, 0x18, 0x18, 0x18, 0x18, 0x18, 0x18, 0x18, 0x18, 0x18, + 0x26, 0x26, 0x18, 0x18, 0x18, 0x18, 0x18, 0x18, 0x18, 0x18, 0x18, 0x18, 0x18, 0x18, 0x18, 0x18, 0x0f, 0x0f, 0x0f, 0x18, 0x18, 0x18, 0x18, 0x18, 0x18, 0x18, 0x18, 0x18, 0x18, 0x18, 0x18, 0x18, 0x18, 0x18, 0x18, 0x18, 0x0f, 0x0f, 0x0f, 0x0f, 0x18, 0x18, 0x18, 0x18, 0x18, 0x18, 0x18, 0x18, 0x0f, 0x0f, 0x0f, 0x0f, 0x0f, 0x0f, 0x0f, 0x0f, 0x0f, 0x0f, 0x18, 0x18, 0x19, 0x17, 0x17, 0x1b, @@ -1222,26 +1236,25 @@ namespace System.Globalization 0x07, 0x07, 0x1c, 0x1c, 0x1c, 0x1c, 0x1c, 0x1c, 0x1c, 0x1c, 0x1c, 0x1c, 0x1c, 0x1c, 0x1c, 0x1c, 0x0e, 0x0e, 0x0e, 0x0e, 0x0e, 0x0e, 0x0e, 0x0e, 0x0e, 0x0e, 0x0e, 0x0e, 0x0e, 0x0e, 0x0e, 0x18, 0x18, 0x0e, 0x0e, 0x0e, 0x0e, 0x0e, 0x0e, 0x0e, 0x0e, 0x0e, 0x0e, 0x0e, 0x0e, 0x0e, 0x0e, 0x0e, - 0x12, 0x12, 0x12, 0x12, 0x12, 0x12, 0x12, 0x12, 0x12, 0x12, 0x12, 0x12, 0x12, 0x18, 0x18, 0x18, - 0x19, 0x19, 0x19, 0x19, 0x19, 0x19, 0x19, 0x19, 0x19, 0x19, 0x0e, 0x0e, 0x0e, 0x18, 0x18, 0x18, - 0x19, 0x19, 0x19, 0x19, 0x19, 0x19, 0x19, 0x19, 0x19, 0x19, 0x19, 0x19, 0x19, 0x18, 0x18, 0x18, + 0x12, 0x12, 0x12, 0x12, 0x12, 0x12, 0x12, 0x12, 0x12, 0x12, 0x12, 0x12, 0x12, 0x0e, 0x0e, 0x0e, + 0x19, 0x19, 0x19, 0x19, 0x19, 0x19, 0x19, 0x19, 0x19, 0x19, 0x0e, 0x0e, 0x0e, 0x0e, 0x0e, 0x0e, + 0x19, 0x19, 0x19, 0x19, 0x19, 0x19, 0x19, 0x19, 0x19, 0x19, 0x19, 0x19, 0x19, 0x0e, 0x18, 0x18, 0x18, 0x18, 0x18, 0x18, 0x18, 0x18, 0x19, 0x19, 0x19, 0x19, 0x19, 0x19, 0x19, 0x19, 0x19, 0x19, 0x19, 0x19, 0x19, 0x18, 0x18, 0x18, 0x18, 0x18, 0x18, 0x18, 0x18, 0x18, 0x18, 0x18, 0x18, 0x18, 0x19, 0x19, 0x19, 0x19, 0x19, 0x19, 0x19, 0x19, 0x19, 0x19, 0x19, 0x19, 0x18, 0x18, 0x18, 0x18, 0x19, 0x19, 0x18, 0x18, 0x18, 0x18, 0x18, 0x18, 0x18, 0x18, 0x18, 0x18, 0x18, 0x18, 0x18, 0x18, 0x0e, 0x0e, 0x0e, 0x0e, 0x0e, 0x0e, 0x0e, 0x0e, 0x0e, 0x0e, 0x0e, 0x0b, 0x0b, 0x0b, 0x0b, 0x0b, - 0x0e, 0x0e, 0x0e, 0x0e, 0x0e, 0x0e, 0x0e, 0x0e, 0x0e, 0x0e, 0x0e, 0x0e, 0x0e, 0x18, 0x18, 0x18, - 0x0e, 0x0e, 0x0e, 0x0e, 0x0e, 0x0e, 0x0e, 0x0e, 0x0e, 0x18, 0x18, 0x18, 0x18, 0x18, 0x18, 0x18, 0x0e, 0x0e, 0x0e, 0x0e, 0x0e, 0x0e, 0x0e, 0x0e, 0x18, 0x18, 0x18, 0x18, 0x18, 0x18, 0x18, 0x18, + 0x0e, 0x0e, 0x0e, 0x0e, 0x0e, 0x0e, 0x0e, 0x0e, 0x0e, 0x18, 0x18, 0x18, 0x18, 0x18, 0x18, 0x18, 0x0e, 0x0e, 0x0e, 0x0e, 0x0e, 0x0e, 0x0e, 0x0e, 0x0e, 0x0e, 0x0e, 0x0e, 0x0e, 0x0e, 0x18, 0x18, + 0x0e, 0x0e, 0x18, 0x18, 0x18, 0x18, 0x18, 0x18, 0x18, 0x18, 0x18, 0x18, 0x18, 0x18, 0x18, 0x18, + 0x0e, 0x0e, 0x0e, 0x0e, 0x0e, 0x0e, 0x0e, 0x0e, 0x0e, 0x18, 0x0e, 0x0e, 0x0e, 0x0e, 0x0e, 0x0e, 0x0e, 0x0e, 0x0e, 0x0e, 0x0e, 0x0e, 0x0e, 0x0e, 0x0e, 0x0e, 0x0e, 0x0e, 0x18, 0x0e, 0x0e, 0x0e, - 0x0e, 0x0e, 0x18, 0x0e, 0x0e, 0x0e, 0x0e, 0x18, 0x18, 0x18, 0x0e, 0x0e, 0x0e, 0x0e, 0x0e, 0x0e, - 0x0e, 0x0e, 0x0e, 0x18, 0x18, 0x0e, 0x0e, 0x0e, 0x0e, 0x0e, 0x0e, 0x18, 0x18, 0x18, 0x0e, 0x0e, - 0x0e, 0x0e, 0x0e, 0x0e, 0x0e, 0x0e, 0x0e, 0x0e, 0x0e, 0x0e, 0x0e, 0x18, 0x18, 0x0e, 0x0e, 0x0e, - 0x0e, 0x0e, 0x0e, 0x0e, 0x18, 0x18, 0x18, 0x18, 0x0e, 0x0e, 0x0e, 0x18, 0x18, 0x18, 0x18, 0x18, + 0x0e, 0x0e, 0x0e, 0x0e, 0x0e, 0x18, 0x18, 0x18, 0x0e, 0x0e, 0x0e, 0x18, 0x18, 0x18, 0x18, 0x18, 0x0e, 0x0e, 0x0e, 0x18, 0x18, 0x18, 0x18, 0x18, 0x18, 0x18, 0x18, 0x18, 0x18, 0x18, 0x18, 0x18, + 0x0e, 0x0e, 0x0e, 0x18, 0x0e, 0x0e, 0x0e, 0x0e, 0x0e, 0x0e, 0x0e, 0x0e, 0x0e, 0x0e, 0x0e, 0x0e, + 0x09, 0x09, 0x09, 0x09, 0x09, 0x09, 0x09, 0x09, 0x09, 0x09, 0x18, 0x18, 0x18, 0x18, 0x18, 0x18, 0x18, 0x18, 0x18, 0x18, 0x18, 0x18, 0x18, 0x18, 0x18, 0x18, 0x18, 0x18, 0x18, 0x18, 0x2e, 0x2e, - 0x0f, 0x0f, 0x18, 0x18, 0x18, 0x18, 0x18, 0x18, 0x18, 0x18, 0x18, 0x18, 0x18, 0x18, 0x18, 0x18, 0x2e, 0x11, 0x2e, 0x2e, 0x2e, 0x2e, 0x2e, 0x2e, 0x2e, 0x2e, 0x2e, 0x2e, 0x2e, 0x2e, 0x2e, 0x2e, 0x11, 0x11, 0x11, 0x11, 0x11, 0x11, 0x11, 0x11, 0x11, 0x11, 0x11, 0x11, 0x11, 0x11, 0x11, 0x11, 0x31, 0x31, 0x31, 0x31, 0x31, 0x31, 0x31, 0x31, 0x31, 0x31, 0x31, 0x31, 0x31, 0x31, 0x2e, 0x2e @@ -1283,7 +1296,7 @@ namespace System.Globalization 0x0a, 0x0a, 0x0a, 0x0a, 0x0a, 0x0a, 0x0a, 0x0a, 0x0a, 0x0a, 0x0a, 0x0a, 0x0a, 0x0a, 0x0a, 0x0a, 0x0a, 0x0a, 0x0a, 0x0a, 0x0a, 0x0a, 0x0a, 0x0a, 0x0a, 0x0a, 0x0a, 0x0a, 0x0a, 0x0a, 0x39, 0x0a, 0x0a, 0x0a, 0x0a, 0x0a, 0x0a, 0x0a, 0x0a, 0x0a, 0x3a, 0x3b, 0x0a, 0x3c, 0x0a, 0x3d, 0x0a, 0x0a, - 0x3e, 0x3f, 0x0a, 0x0a, 0x40, 0x0a, 0x41, 0x0a, 0x42, 0x43, 0x44, 0x45, 0x46, 0x47, 0x47, 0x48, + 0x3e, 0x3f, 0x0a, 0x0a, 0x40, 0x0a, 0x41, 0x0a, 0x42, 0x43, 0x44, 0x45, 0x46, 0x47, 0x48, 0x49, 0x0a, 0x0a, 0x0a, 0x0a, 0x0a, 0x0a, 0x0a, 0x0a, 0x0a, 0x0a, 0x0a, 0x0a, 0x0a, 0x0a, 0x0a, 0x0a, 0x0a, 0x0a, 0x0a, 0x0a, 0x0a, 0x0a, 0x0a, 0x0a, 0x0a, 0x0a, 0x0a, 0x0a, 0x0a, 0x0a, 0x0a, 0x0a, 0x0a, 0x0a, 0x0a, 0x0a, 0x0a, 0x0a, 0x0a, 0x0a, 0x0a, 0x0a, 0x0a, 0x0a, 0x0a, 0x0a, 0x0a, 0x0a, @@ -1291,7 +1304,7 @@ namespace System.Globalization 0x0a, 0x0a, 0x0a, 0x0a, 0x0a, 0x0a, 0x0a, 0x0a, 0x0a, 0x0a, 0x0a, 0x0a, 0x0a, 0x0a, 0x0a, 0x0a, 0x0a, 0x0a, 0x0a, 0x0a, 0x0a, 0x0a, 0x0a, 0x0a, 0x0a, 0x0a, 0x0a, 0x0a, 0x0a, 0x0a, 0x0a, 0x0a, 0x0a, 0x0a, 0x0a, 0x0a, 0x0a, 0x0a, 0x0a, 0x0a, 0x0a, 0x0a, 0x0a, 0x0a, 0x0a, 0x0a, 0x0a, 0x0a, - 0x0a, 0x0a, 0x0a, 0x0a, 0x0a, 0x0a, 0x0a, 0x0a, 0x0a, 0x0a, 0x0a, 0x0a, 0x49, 0x0a, 0x0a, 0x0a, + 0x0a, 0x0a, 0x0a, 0x0a, 0x0a, 0x0a, 0x0a, 0x0a, 0x0a, 0x0a, 0x0a, 0x0a, 0x4a, 0x0a, 0x0a, 0x0a, 0x0a, 0x0a, 0x0a, 0x0a, 0x0a, 0x0a, 0x0a, 0x0a, 0x0a, 0x0a, 0x0a, 0x0a, 0x0a, 0x0a, 0x0a, 0x0a, 0x0a, 0x0a, 0x0a, 0x0a, 0x0a, 0x0a, 0x0a, 0x0a, 0x0a, 0x0a, 0x0a, 0x0a, 0x0a, 0x0a, 0x0a, 0x0a, 0x0a, 0x0a, 0x0a, 0x0a, 0x0a, 0x0a, 0x0a, 0x0a, 0x0a, 0x0a, 0x0a, 0x0a, 0x0a, 0x0a, 0x0a, 0x0a, @@ -1380,7 +1393,7 @@ namespace System.Globalization 0x0a, 0x0a, 0x0a, 0x0a, 0x0a, 0x0a, 0x0a, 0x0a, 0x0a, 0x0a, 0x0a, 0x0a, 0x0a, 0x0a, 0x0a, 0x0a, 0x0a, 0x0a, 0x0a, 0x0a, 0x0a, 0x0a, 0x0a, 0x0a, 0x0a, 0x0a, 0x0a, 0x0a, 0x0a, 0x0a, 0x0a, 0x0a, 0x0a, 0x0a, 0x0a, 0x0a, 0x0a, 0x0a, 0x0a, 0x0a, 0x0a, 0x0a, 0x0a, 0x0a, 0x0a, 0x0a, 0x0a, 0x0a, - 0x4a, 0x4b, 0x4b, 0x4b, 0x4b, 0x4b, 0x4b, 0x4b, 0x0a, 0x0a, 0x0a, 0x0a, 0x0a, 0x0a, 0x0a, 0x0a, + 0x4b, 0x4c, 0x4c, 0x4c, 0x4c, 0x4c, 0x4c, 0x4c, 0x0a, 0x0a, 0x0a, 0x0a, 0x0a, 0x0a, 0x0a, 0x0a, 0x0a, 0x0a, 0x0a, 0x0a, 0x0a, 0x0a, 0x0a, 0x0a, 0x0a, 0x0a, 0x0a, 0x0a, 0x0a, 0x0a, 0x0a, 0x0a, 0x0a, 0x0a, 0x0a, 0x0a, 0x0a, 0x0a, 0x0a, 0x0a, 0x0a, 0x0a, 0x0a, 0x0a, 0x0a, 0x0a, 0x0a, 0x0a, 0x0a, 0x0a, 0x0a, 0x0a, 0x0a, 0x0a, 0x0a, 0x0a, 0x0a, 0x0a, 0x0a, 0x0a, 0x0a, 0x0a, 0x0a, 0x0a, @@ -1406,7 +1419,7 @@ namespace System.Globalization 0x0a, 0x0a, 0x0a, 0x0a, 0x0a, 0x0a, 0x0a, 0x0a, 0x0a, 0x0a, 0x0a, 0x0a, 0x0a, 0x0a, 0x0a, 0x0a }; - private static ReadOnlySpan NumericGraphemeLevel2Index => new byte[4864] + private static ReadOnlySpan NumericGraphemeLevel2Index => new byte[4928] { 0x00, 0x00, 0x01, 0x00, 0x02, 0x00, 0x03, 0x00, 0x02, 0x00, 0x02, 0x00, 0x02, 0x00, 0x04, 0x00, 0x01, 0x00, 0x01, 0x00, 0x05, 0x00, 0x06, 0x00, 0x02, 0x00, 0x02, 0x00, 0x02, 0x00, 0x02, 0x00, @@ -1435,7 +1448,7 @@ namespace System.Globalization 0x34, 0x00, 0x02, 0x00, 0x02, 0x00, 0x35, 0x00, 0x36, 0x00, 0x37, 0x00, 0x20, 0x00, 0x38, 0x00, 0x21, 0x00, 0x02, 0x00, 0x02, 0x00, 0x39, 0x00, 0x3a, 0x00, 0x37, 0x00, 0x20, 0x00, 0x02, 0x00, 0x3b, 0x00, 0x02, 0x00, 0x02, 0x00, 0x3c, 0x00, 0x3d, 0x00, 0x3e, 0x00, 0x20, 0x00, 0x3f, 0x00, - 0x40, 0x00, 0x02, 0x00, 0x02, 0x00, 0x02, 0x00, 0x41, 0x00, 0x42, 0x00, 0x29, 0x00, 0x40, 0x00, + 0x21, 0x00, 0x02, 0x00, 0x02, 0x00, 0x02, 0x00, 0x40, 0x00, 0x41, 0x00, 0x29, 0x00, 0x42, 0x00, 0x02, 0x00, 0x02, 0x00, 0x02, 0x00, 0x43, 0x00, 0x44, 0x00, 0x03, 0x00, 0x02, 0x00, 0x02, 0x00, 0x02, 0x00, 0x02, 0x00, 0x02, 0x00, 0x45, 0x00, 0x46, 0x00, 0x03, 0x00, 0x02, 0x00, 0x02, 0x00, 0x02, 0x00, 0x47, 0x00, 0x48, 0x00, 0x49, 0x00, 0x02, 0x00, 0x02, 0x00, 0x02, 0x00, 0x4a, 0x00, @@ -1461,247 +1474,251 @@ namespace System.Globalization 0x02, 0x00, 0x02, 0x00, 0x64, 0x00, 0x65, 0x00, 0x29, 0x00, 0x02, 0x00, 0x02, 0x00, 0x02, 0x00, 0x02, 0x00, 0x02, 0x00, 0x02, 0x00, 0x02, 0x00, 0x02, 0x00, 0x66, 0x00, 0x02, 0x00, 0x02, 0x00, 0x02, 0x00, 0x67, 0x00, 0x02, 0x00, 0x02, 0x00, 0x02, 0x00, 0x68, 0x00, 0x69, 0x00, 0x6a, 0x00, - 0x03, 0x00, 0x03, 0x00, 0x02, 0x00, 0x6b, 0x00, 0x02, 0x00, 0x02, 0x00, 0x02, 0x00, 0x02, 0x00, - 0x6c, 0x00, 0x02, 0x00, 0x02, 0x00, 0x6d, 0x00, 0x6e, 0x00, 0x03, 0x00, 0x0e, 0x00, 0x6f, 0x00, - 0x70, 0x00, 0x02, 0x00, 0x71, 0x00, 0x03, 0x00, 0x02, 0x00, 0x02, 0x00, 0x72, 0x00, 0x3b, 0x00, - 0x02, 0x00, 0x02, 0x00, 0x73, 0x00, 0x74, 0x00, 0x03, 0x00, 0x03, 0x00, 0x02, 0x00, 0x02, 0x00, - 0x02, 0x00, 0x02, 0x00, 0x02, 0x00, 0x02, 0x00, 0x02, 0x00, 0x75, 0x00, 0x76, 0x00, 0x77, 0x00, + 0x03, 0x00, 0x03, 0x00, 0x02, 0x00, 0x07, 0x00, 0x0f, 0x00, 0x02, 0x00, 0x02, 0x00, 0x02, 0x00, + 0x6b, 0x00, 0x02, 0x00, 0x02, 0x00, 0x6c, 0x00, 0x6d, 0x00, 0x03, 0x00, 0x0e, 0x00, 0x6e, 0x00, + 0x6f, 0x00, 0x02, 0x00, 0x70, 0x00, 0x03, 0x00, 0x02, 0x00, 0x02, 0x00, 0x71, 0x00, 0x3b, 0x00, + 0x02, 0x00, 0x02, 0x00, 0x72, 0x00, 0x73, 0x00, 0x03, 0x00, 0x03, 0x00, 0x02, 0x00, 0x02, 0x00, + 0x02, 0x00, 0x02, 0x00, 0x02, 0x00, 0x02, 0x00, 0x02, 0x00, 0x74, 0x00, 0x75, 0x00, 0x76, 0x00, 0x02, 0x00, 0x02, 0x00, 0x02, 0x00, 0x02, 0x00, 0x02, 0x00, 0x02, 0x00, 0x02, 0x00, 0x02, 0x00, - 0x02, 0x00, 0x02, 0x00, 0x02, 0x00, 0x02, 0x00, 0x07, 0x00, 0x07, 0x00, 0x07, 0x00, 0x78, 0x00, - 0x79, 0x00, 0x02, 0x00, 0x7a, 0x00, 0x7b, 0x00, 0x7c, 0x00, 0x02, 0x00, 0x01, 0x00, 0x7d, 0x00, - 0x7e, 0x00, 0x02, 0x00, 0x02, 0x00, 0x02, 0x00, 0x02, 0x00, 0x07, 0x00, 0x07, 0x00, 0x0f, 0x00, - 0x02, 0x00, 0x02, 0x00, 0x7f, 0x00, 0x7c, 0x00, 0x02, 0x00, 0x80, 0x00, 0x81, 0x00, 0x81, 0x00, - 0x82, 0x00, 0x83, 0x00, 0x84, 0x00, 0x02, 0x00, 0x02, 0x00, 0x02, 0x00, 0x02, 0x00, 0x02, 0x00, + 0x02, 0x00, 0x02, 0x00, 0x02, 0x00, 0x02, 0x00, 0x07, 0x00, 0x07, 0x00, 0x07, 0x00, 0x77, 0x00, + 0x78, 0x00, 0x02, 0x00, 0x79, 0x00, 0x7a, 0x00, 0x7b, 0x00, 0x02, 0x00, 0x01, 0x00, 0x7c, 0x00, + 0x7d, 0x00, 0x02, 0x00, 0x02, 0x00, 0x02, 0x00, 0x02, 0x00, 0x07, 0x00, 0x07, 0x00, 0x0f, 0x00, + 0x02, 0x00, 0x02, 0x00, 0x7e, 0x00, 0x7b, 0x00, 0x02, 0x00, 0x7f, 0x00, 0x80, 0x00, 0x80, 0x00, + 0x81, 0x00, 0x82, 0x00, 0x83, 0x00, 0x02, 0x00, 0x02, 0x00, 0x02, 0x00, 0x02, 0x00, 0x02, 0x00, 0x02, 0x00, 0x02, 0x00, 0x02, 0x00, 0x02, 0x00, 0x02, 0x00, 0x02, 0x00, 0x02, 0x00, 0x02, 0x00, 0x02, 0x00, 0x02, 0x00, 0x02, 0x00, 0x02, 0x00, 0x02, 0x00, 0x02, 0x00, 0x02, 0x00, 0x02, 0x00, - 0x02, 0x00, 0x85, 0x00, 0x86, 0x00, 0x02, 0x00, 0x02, 0x00, 0x02, 0x00, 0x02, 0x00, 0x02, 0x00, - 0x86, 0x00, 0x02, 0x00, 0x02, 0x00, 0x02, 0x00, 0x87, 0x00, 0x02, 0x00, 0x88, 0x00, 0x89, 0x00, - 0x02, 0x00, 0x02, 0x00, 0x02, 0x00, 0x02, 0x00, 0x02, 0x00, 0x02, 0x00, 0x8a, 0x00, 0x8b, 0x00, - 0x8c, 0x00, 0x8d, 0x00, 0x02, 0x00, 0x02, 0x00, 0x7f, 0x00, 0x02, 0x00, 0x8e, 0x00, 0x8f, 0x00, + 0x02, 0x00, 0x84, 0x00, 0x85, 0x00, 0x02, 0x00, 0x02, 0x00, 0x02, 0x00, 0x02, 0x00, 0x02, 0x00, + 0x85, 0x00, 0x02, 0x00, 0x02, 0x00, 0x02, 0x00, 0x86, 0x00, 0x02, 0x00, 0x87, 0x00, 0x88, 0x00, + 0x02, 0x00, 0x02, 0x00, 0x02, 0x00, 0x02, 0x00, 0x02, 0x00, 0x02, 0x00, 0x89, 0x00, 0x8a, 0x00, + 0x8b, 0x00, 0x8c, 0x00, 0x02, 0x00, 0x02, 0x00, 0x7e, 0x00, 0x02, 0x00, 0x8d, 0x00, 0x8e, 0x00, 0x02, 0x00, 0x02, 0x00, 0x02, 0x00, 0x02, 0x00, 0x02, 0x00, 0x02, 0x00, 0x02, 0x00, 0x02, 0x00, - 0x02, 0x00, 0x02, 0x00, 0x85, 0x00, 0x90, 0x00, 0x91, 0x00, 0x02, 0x00, 0x02, 0x00, 0x92, 0x00, - 0x93, 0x00, 0x94, 0x00, 0x95, 0x00, 0x95, 0x00, 0x95, 0x00, 0x95, 0x00, 0x95, 0x00, 0x95, 0x00, - 0x96, 0x00, 0x95, 0x00, 0x95, 0x00, 0x95, 0x00, 0x95, 0x00, 0x95, 0x00, 0x95, 0x00, 0x95, 0x00, - 0x97, 0x00, 0x98, 0x00, 0x99, 0x00, 0x9a, 0x00, 0x9b, 0x00, 0x9c, 0x00, 0x9d, 0x00, 0x9e, 0x00, - 0x9f, 0x00, 0xa0, 0x00, 0xa1, 0x00, 0xa2, 0x00, 0x02, 0x00, 0x02, 0x00, 0x02, 0x00, 0x02, 0x00, + 0x02, 0x00, 0x02, 0x00, 0x84, 0x00, 0x8f, 0x00, 0x90, 0x00, 0x02, 0x00, 0x02, 0x00, 0x91, 0x00, + 0x92, 0x00, 0x93, 0x00, 0x94, 0x00, 0x94, 0x00, 0x94, 0x00, 0x94, 0x00, 0x94, 0x00, 0x94, 0x00, + 0x95, 0x00, 0x94, 0x00, 0x94, 0x00, 0x94, 0x00, 0x94, 0x00, 0x94, 0x00, 0x94, 0x00, 0x94, 0x00, + 0x96, 0x00, 0x97, 0x00, 0x98, 0x00, 0x99, 0x00, 0x9a, 0x00, 0x9b, 0x00, 0x9c, 0x00, 0x9d, 0x00, + 0x9e, 0x00, 0x9f, 0x00, 0xa0, 0x00, 0xa1, 0x00, 0x02, 0x00, 0x02, 0x00, 0x02, 0x00, 0x02, 0x00, 0x02, 0x00, 0x02, 0x00, 0x02, 0x00, 0x02, 0x00, 0x02, 0x00, 0x02, 0x00, 0x02, 0x00, 0x02, 0x00, 0x02, 0x00, 0x02, 0x00, 0x02, 0x00, 0x02, 0x00, 0x02, 0x00, 0x02, 0x00, 0x02, 0x00, 0x02, 0x00, - 0x02, 0x00, 0x02, 0x00, 0x02, 0x00, 0xa3, 0x00, 0x02, 0x00, 0x02, 0x00, 0x02, 0x00, 0x02, 0x00, + 0x02, 0x00, 0x02, 0x00, 0x02, 0x00, 0xa2, 0x00, 0x02, 0x00, 0x02, 0x00, 0x02, 0x00, 0x02, 0x00, 0x02, 0x00, 0x02, 0x00, 0x02, 0x00, 0x02, 0x00, 0x02, 0x00, 0x02, 0x00, 0x02, 0x00, 0x02, 0x00, 0x02, 0x00, 0x02, 0x00, 0x02, 0x00, 0x02, 0x00, 0x02, 0x00, 0x02, 0x00, 0x02, 0x00, 0x02, 0x00, 0x02, 0x00, 0x02, 0x00, 0x02, 0x00, 0x02, 0x00, 0x02, 0x00, 0x02, 0x00, 0x02, 0x00, 0x02, 0x00, - 0xa4, 0x00, 0xa5, 0x00, 0x02, 0x00, 0x02, 0x00, 0x02, 0x00, 0xa6, 0x00, 0x02, 0x00, 0x02, 0x00, + 0xa3, 0x00, 0xa4, 0x00, 0x02, 0x00, 0x02, 0x00, 0x02, 0x00, 0xa5, 0x00, 0x02, 0x00, 0x02, 0x00, 0x02, 0x00, 0x02, 0x00, 0x02, 0x00, 0x02, 0x00, 0x02, 0x00, 0x02, 0x00, 0x02, 0x00, 0x02, 0x00, 0x02, 0x00, 0x02, 0x00, 0x02, 0x00, 0x02, 0x00, 0x02, 0x00, 0x02, 0x00, 0x02, 0x00, 0x02, 0x00, - 0x02, 0x00, 0x02, 0x00, 0x02, 0x00, 0x02, 0x00, 0x02, 0x00, 0x02, 0x00, 0xa7, 0x00, 0xa8, 0x00, - 0x02, 0x00, 0x02, 0x00, 0x02, 0x00, 0x02, 0x00, 0x02, 0x00, 0x02, 0x00, 0x02, 0x00, 0xa7, 0x00, + 0x02, 0x00, 0x02, 0x00, 0x02, 0x00, 0x02, 0x00, 0x02, 0x00, 0x02, 0x00, 0xa6, 0x00, 0xa7, 0x00, + 0x02, 0x00, 0x02, 0x00, 0x02, 0x00, 0x02, 0x00, 0x02, 0x00, 0x02, 0x00, 0x02, 0x00, 0xa6, 0x00, 0x02, 0x00, 0x02, 0x00, 0x02, 0x00, 0x02, 0x00, 0x02, 0x00, 0x02, 0x00, 0x07, 0x00, 0x07, 0x00, - 0xa9, 0x00, 0x02, 0x00, 0xaa, 0x00, 0xab, 0x00, 0x02, 0x00, 0x02, 0x00, 0x02, 0x00, 0x02, 0x00, + 0xa8, 0x00, 0x02, 0x00, 0xa9, 0x00, 0xaa, 0x00, 0x02, 0x00, 0x02, 0x00, 0x02, 0x00, 0x02, 0x00, + 0x02, 0x00, 0xab, 0x00, 0x02, 0x00, 0x02, 0x00, 0x02, 0x00, 0x02, 0x00, 0x02, 0x00, 0x02, 0x00, + 0x02, 0x00, 0x02, 0x00, 0x02, 0x00, 0x02, 0x00, 0x02, 0x00, 0x02, 0x00, 0x02, 0x00, 0x02, 0x00, 0x02, 0x00, 0xac, 0x00, 0x02, 0x00, 0x02, 0x00, 0x02, 0x00, 0x02, 0x00, 0x02, 0x00, 0x02, 0x00, - 0x02, 0x00, 0x02, 0x00, 0x02, 0x00, 0x02, 0x00, 0x02, 0x00, 0x02, 0x00, 0x02, 0x00, 0x02, 0x00, - 0x02, 0x00, 0xad, 0x00, 0x02, 0x00, 0x02, 0x00, 0x02, 0x00, 0x02, 0x00, 0x02, 0x00, 0x02, 0x00, - 0x02, 0x00, 0x02, 0x00, 0xae, 0x00, 0x02, 0x00, 0xaf, 0x00, 0xb0, 0x00, 0x02, 0x00, 0x02, 0x00, - 0xae, 0x00, 0xb1, 0x00, 0x02, 0x00, 0xb2, 0x00, 0x02, 0x00, 0x02, 0x00, 0x02, 0x00, 0x02, 0x00, + 0x02, 0x00, 0x02, 0x00, 0xad, 0x00, 0x02, 0x00, 0xae, 0x00, 0xaf, 0x00, 0x02, 0x00, 0x02, 0x00, + 0xad, 0x00, 0xb0, 0x00, 0x02, 0x00, 0xb1, 0x00, 0x02, 0x00, 0x02, 0x00, 0x02, 0x00, 0x02, 0x00, 0x02, 0x00, 0x02, 0x00, 0x02, 0x00, 0x02, 0x00, 0x02, 0x00, 0x02, 0x00, 0x02, 0x00, 0x02, 0x00, 0x02, 0x00, 0x02, 0x00, 0x02, 0x00, 0x02, 0x00, 0x02, 0x00, 0x02, 0x00, 0x02, 0x00, 0x02, 0x00, - 0x02, 0x00, 0x02, 0x00, 0x03, 0x00, 0x02, 0x00, 0x02, 0x00, 0x02, 0x00, 0xa7, 0x00, 0xb3, 0x00, - 0x02, 0x00, 0x35, 0x00, 0x02, 0x00, 0x02, 0x00, 0x02, 0x00, 0x02, 0x00, 0xb4, 0x00, 0xb5, 0x00, + 0x02, 0x00, 0x02, 0x00, 0x03, 0x00, 0x02, 0x00, 0x02, 0x00, 0x02, 0x00, 0xa6, 0x00, 0xb2, 0x00, + 0x02, 0x00, 0x35, 0x00, 0x02, 0x00, 0x02, 0x00, 0x02, 0x00, 0x02, 0x00, 0xb3, 0x00, 0xb4, 0x00, 0x02, 0x00, 0x02, 0x00, 0x02, 0x00, 0x02, 0x00, 0x02, 0x00, 0x02, 0x00, 0x02, 0x00, 0x02, 0x00, 0x02, 0x00, 0x02, 0x00, 0x02, 0x00, 0x02, 0x00, 0x02, 0x00, 0x02, 0x00, 0x02, 0x00, 0x02, 0x00, - 0xb6, 0x00, 0x02, 0x00, 0xb7, 0x00, 0xb8, 0x00, 0x02, 0x00, 0x02, 0x00, 0x02, 0x00, 0x02, 0x00, - 0xb9, 0x00, 0x02, 0x00, 0x02, 0x00, 0xba, 0x00, 0xbb, 0x00, 0x03, 0x00, 0x07, 0x00, 0xbc, 0x00, - 0x03, 0x00, 0x02, 0x00, 0xbd, 0x00, 0x02, 0x00, 0xbe, 0x00, 0x3b, 0x00, 0x55, 0x00, 0xbf, 0x00, - 0x1c, 0x00, 0x02, 0x00, 0x02, 0x00, 0xc0, 0x00, 0xc1, 0x00, 0x03, 0x00, 0xc2, 0x00, 0x03, 0x00, - 0x02, 0x00, 0x02, 0x00, 0xc3, 0x00, 0xc4, 0x00, 0xc5, 0x00, 0x03, 0x00, 0x02, 0x00, 0xc6, 0x00, - 0x02, 0x00, 0x02, 0x00, 0x02, 0x00, 0xc7, 0x00, 0x13, 0x00, 0x02, 0x00, 0xc8, 0x00, 0xc9, 0x00, + 0xb5, 0x00, 0x02, 0x00, 0xb6, 0x00, 0xb7, 0x00, 0x02, 0x00, 0x02, 0x00, 0x02, 0x00, 0x02, 0x00, + 0xb8, 0x00, 0x02, 0x00, 0x02, 0x00, 0xb9, 0x00, 0xba, 0x00, 0x03, 0x00, 0x07, 0x00, 0xbb, 0x00, + 0x03, 0x00, 0x02, 0x00, 0xbc, 0x00, 0x02, 0x00, 0xbd, 0x00, 0x3b, 0x00, 0x55, 0x00, 0xbe, 0x00, + 0x1c, 0x00, 0x02, 0x00, 0x02, 0x00, 0xbf, 0x00, 0xc0, 0x00, 0x03, 0x00, 0xc1, 0x00, 0x03, 0x00, + 0x02, 0x00, 0x02, 0x00, 0xc2, 0x00, 0xc3, 0x00, 0xc4, 0x00, 0x03, 0x00, 0x02, 0x00, 0xc5, 0x00, + 0x02, 0x00, 0x02, 0x00, 0x02, 0x00, 0xc6, 0x00, 0x13, 0x00, 0x02, 0x00, 0xc7, 0x00, 0xc8, 0x00, 0x02, 0x00, 0x02, 0x00, 0x02, 0x00, 0x02, 0x00, 0x02, 0x00, 0x02, 0x00, 0x02, 0x00, 0x02, 0x00, - 0x02, 0x00, 0x02, 0x00, 0x02, 0x00, 0x02, 0x00, 0x02, 0x00, 0x02, 0x00, 0xca, 0x00, 0x03, 0x00, - 0xcb, 0x00, 0xcc, 0x00, 0xcd, 0x00, 0xce, 0x00, 0xcd, 0x00, 0xcf, 0x00, 0xcd, 0x00, 0xcb, 0x00, - 0xcc, 0x00, 0xcd, 0x00, 0xce, 0x00, 0xcd, 0x00, 0xcf, 0x00, 0xcd, 0x00, 0xcb, 0x00, 0xcc, 0x00, - 0xcd, 0x00, 0xce, 0x00, 0xcd, 0x00, 0xcf, 0x00, 0xcd, 0x00, 0xcb, 0x00, 0xcc, 0x00, 0xcd, 0x00, - 0xce, 0x00, 0xcd, 0x00, 0xcf, 0x00, 0xcd, 0x00, 0xcb, 0x00, 0xcc, 0x00, 0xcd, 0x00, 0xce, 0x00, - 0xcd, 0x00, 0xcf, 0x00, 0xcd, 0x00, 0xcb, 0x00, 0xcc, 0x00, 0xcd, 0x00, 0xce, 0x00, 0xcd, 0x00, - 0xcf, 0x00, 0xcd, 0x00, 0xcb, 0x00, 0xcc, 0x00, 0xcd, 0x00, 0xce, 0x00, 0xcd, 0x00, 0xcf, 0x00, - 0xcd, 0x00, 0xcb, 0x00, 0xcc, 0x00, 0xcd, 0x00, 0xce, 0x00, 0xcd, 0x00, 0xcf, 0x00, 0xcd, 0x00, - 0xcb, 0x00, 0xcc, 0x00, 0xcd, 0x00, 0xce, 0x00, 0xcd, 0x00, 0xcf, 0x00, 0xcd, 0x00, 0xcb, 0x00, - 0xcc, 0x00, 0xcd, 0x00, 0xce, 0x00, 0xcd, 0x00, 0xcf, 0x00, 0xcd, 0x00, 0xcb, 0x00, 0xcc, 0x00, - 0xcd, 0x00, 0xce, 0x00, 0xcd, 0x00, 0xcf, 0x00, 0xcd, 0x00, 0xcb, 0x00, 0xcc, 0x00, 0xcd, 0x00, - 0xce, 0x00, 0xcd, 0x00, 0xcf, 0x00, 0xcd, 0x00, 0xcb, 0x00, 0xcc, 0x00, 0xcd, 0x00, 0xce, 0x00, - 0xcd, 0x00, 0xcf, 0x00, 0xcd, 0x00, 0xcb, 0x00, 0xcc, 0x00, 0xcd, 0x00, 0xce, 0x00, 0xcd, 0x00, - 0xcf, 0x00, 0xcd, 0x00, 0xcb, 0x00, 0xcc, 0x00, 0xcd, 0x00, 0xce, 0x00, 0xcd, 0x00, 0xcf, 0x00, - 0xcd, 0x00, 0xcb, 0x00, 0xcc, 0x00, 0xcd, 0x00, 0xce, 0x00, 0xcd, 0x00, 0xcf, 0x00, 0xcd, 0x00, - 0xcb, 0x00, 0xcc, 0x00, 0xcd, 0x00, 0xce, 0x00, 0xcd, 0x00, 0xcf, 0x00, 0xcd, 0x00, 0xcb, 0x00, - 0xcc, 0x00, 0xcd, 0x00, 0xce, 0x00, 0xcd, 0x00, 0xcf, 0x00, 0xcd, 0x00, 0xcb, 0x00, 0xcc, 0x00, - 0xcd, 0x00, 0xce, 0x00, 0xcd, 0x00, 0xcf, 0x00, 0xcd, 0x00, 0xcb, 0x00, 0xcc, 0x00, 0xcd, 0x00, - 0xce, 0x00, 0xcd, 0x00, 0xcf, 0x00, 0xcd, 0x00, 0xcb, 0x00, 0xcc, 0x00, 0xcd, 0x00, 0xce, 0x00, - 0xcd, 0x00, 0xcf, 0x00, 0xcd, 0x00, 0xcb, 0x00, 0xcc, 0x00, 0xcd, 0x00, 0xce, 0x00, 0xcd, 0x00, - 0xcf, 0x00, 0xcd, 0x00, 0xcb, 0x00, 0xcc, 0x00, 0xcd, 0x00, 0xce, 0x00, 0xcd, 0x00, 0xcf, 0x00, - 0xcd, 0x00, 0xcb, 0x00, 0xcc, 0x00, 0xcd, 0x00, 0xce, 0x00, 0xcd, 0x00, 0xcf, 0x00, 0xcd, 0x00, - 0xcb, 0x00, 0xcc, 0x00, 0xcd, 0x00, 0xce, 0x00, 0xcd, 0x00, 0xcf, 0x00, 0xcd, 0x00, 0xcb, 0x00, - 0xcc, 0x00, 0xcd, 0x00, 0xce, 0x00, 0xcd, 0x00, 0xcf, 0x00, 0xcd, 0x00, 0xcb, 0x00, 0xcc, 0x00, - 0xcd, 0x00, 0xce, 0x00, 0xcd, 0x00, 0xcf, 0x00, 0xcd, 0x00, 0xcb, 0x00, 0xcc, 0x00, 0xcd, 0x00, - 0xce, 0x00, 0xcd, 0x00, 0xcf, 0x00, 0xcd, 0x00, 0xcb, 0x00, 0xcc, 0x00, 0xcd, 0x00, 0xce, 0x00, - 0xcd, 0x00, 0xcf, 0x00, 0xcd, 0x00, 0xcb, 0x00, 0xcc, 0x00, 0xcd, 0x00, 0xce, 0x00, 0xcd, 0x00, - 0xcf, 0x00, 0xcd, 0x00, 0xcb, 0x00, 0xcc, 0x00, 0xcd, 0x00, 0xce, 0x00, 0xcd, 0x00, 0xcf, 0x00, - 0xcd, 0x00, 0xcb, 0x00, 0xcc, 0x00, 0xcd, 0x00, 0xce, 0x00, 0xcd, 0x00, 0xcf, 0x00, 0xcd, 0x00, - 0xcb, 0x00, 0xcc, 0x00, 0xcd, 0x00, 0xce, 0x00, 0xcd, 0x00, 0xcf, 0x00, 0xcd, 0x00, 0xcb, 0x00, - 0xcc, 0x00, 0xcd, 0x00, 0xce, 0x00, 0xcd, 0x00, 0xcf, 0x00, 0xcd, 0x00, 0xcb, 0x00, 0xcc, 0x00, - 0xcd, 0x00, 0xce, 0x00, 0xcd, 0x00, 0xcf, 0x00, 0xcd, 0x00, 0xcb, 0x00, 0xcc, 0x00, 0xcd, 0x00, - 0xce, 0x00, 0xcd, 0x00, 0xd0, 0x00, 0x56, 0x00, 0xd1, 0x00, 0x58, 0x00, 0x58, 0x00, 0xd2, 0x00, + 0x02, 0x00, 0x02, 0x00, 0x02, 0x00, 0x02, 0x00, 0x02, 0x00, 0x02, 0x00, 0xc9, 0x00, 0x03, 0x00, + 0xca, 0x00, 0xcb, 0x00, 0xcc, 0x00, 0xcd, 0x00, 0xcc, 0x00, 0xce, 0x00, 0xcc, 0x00, 0xca, 0x00, + 0xcb, 0x00, 0xcc, 0x00, 0xcd, 0x00, 0xcc, 0x00, 0xce, 0x00, 0xcc, 0x00, 0xca, 0x00, 0xcb, 0x00, + 0xcc, 0x00, 0xcd, 0x00, 0xcc, 0x00, 0xce, 0x00, 0xcc, 0x00, 0xca, 0x00, 0xcb, 0x00, 0xcc, 0x00, + 0xcd, 0x00, 0xcc, 0x00, 0xce, 0x00, 0xcc, 0x00, 0xca, 0x00, 0xcb, 0x00, 0xcc, 0x00, 0xcd, 0x00, + 0xcc, 0x00, 0xce, 0x00, 0xcc, 0x00, 0xca, 0x00, 0xcb, 0x00, 0xcc, 0x00, 0xcd, 0x00, 0xcc, 0x00, + 0xce, 0x00, 0xcc, 0x00, 0xca, 0x00, 0xcb, 0x00, 0xcc, 0x00, 0xcd, 0x00, 0xcc, 0x00, 0xce, 0x00, + 0xcc, 0x00, 0xca, 0x00, 0xcb, 0x00, 0xcc, 0x00, 0xcd, 0x00, 0xcc, 0x00, 0xce, 0x00, 0xcc, 0x00, + 0xca, 0x00, 0xcb, 0x00, 0xcc, 0x00, 0xcd, 0x00, 0xcc, 0x00, 0xce, 0x00, 0xcc, 0x00, 0xca, 0x00, + 0xcb, 0x00, 0xcc, 0x00, 0xcd, 0x00, 0xcc, 0x00, 0xce, 0x00, 0xcc, 0x00, 0xca, 0x00, 0xcb, 0x00, + 0xcc, 0x00, 0xcd, 0x00, 0xcc, 0x00, 0xce, 0x00, 0xcc, 0x00, 0xca, 0x00, 0xcb, 0x00, 0xcc, 0x00, + 0xcd, 0x00, 0xcc, 0x00, 0xce, 0x00, 0xcc, 0x00, 0xca, 0x00, 0xcb, 0x00, 0xcc, 0x00, 0xcd, 0x00, + 0xcc, 0x00, 0xce, 0x00, 0xcc, 0x00, 0xca, 0x00, 0xcb, 0x00, 0xcc, 0x00, 0xcd, 0x00, 0xcc, 0x00, + 0xce, 0x00, 0xcc, 0x00, 0xca, 0x00, 0xcb, 0x00, 0xcc, 0x00, 0xcd, 0x00, 0xcc, 0x00, 0xce, 0x00, + 0xcc, 0x00, 0xca, 0x00, 0xcb, 0x00, 0xcc, 0x00, 0xcd, 0x00, 0xcc, 0x00, 0xce, 0x00, 0xcc, 0x00, + 0xca, 0x00, 0xcb, 0x00, 0xcc, 0x00, 0xcd, 0x00, 0xcc, 0x00, 0xce, 0x00, 0xcc, 0x00, 0xca, 0x00, + 0xcb, 0x00, 0xcc, 0x00, 0xcd, 0x00, 0xcc, 0x00, 0xce, 0x00, 0xcc, 0x00, 0xca, 0x00, 0xcb, 0x00, + 0xcc, 0x00, 0xcd, 0x00, 0xcc, 0x00, 0xce, 0x00, 0xcc, 0x00, 0xca, 0x00, 0xcb, 0x00, 0xcc, 0x00, + 0xcd, 0x00, 0xcc, 0x00, 0xce, 0x00, 0xcc, 0x00, 0xca, 0x00, 0xcb, 0x00, 0xcc, 0x00, 0xcd, 0x00, + 0xcc, 0x00, 0xce, 0x00, 0xcc, 0x00, 0xca, 0x00, 0xcb, 0x00, 0xcc, 0x00, 0xcd, 0x00, 0xcc, 0x00, + 0xce, 0x00, 0xcc, 0x00, 0xca, 0x00, 0xcb, 0x00, 0xcc, 0x00, 0xcd, 0x00, 0xcc, 0x00, 0xce, 0x00, + 0xcc, 0x00, 0xca, 0x00, 0xcb, 0x00, 0xcc, 0x00, 0xcd, 0x00, 0xcc, 0x00, 0xce, 0x00, 0xcc, 0x00, + 0xca, 0x00, 0xcb, 0x00, 0xcc, 0x00, 0xcd, 0x00, 0xcc, 0x00, 0xce, 0x00, 0xcc, 0x00, 0xca, 0x00, + 0xcb, 0x00, 0xcc, 0x00, 0xcd, 0x00, 0xcc, 0x00, 0xce, 0x00, 0xcc, 0x00, 0xca, 0x00, 0xcb, 0x00, + 0xcc, 0x00, 0xcd, 0x00, 0xcc, 0x00, 0xce, 0x00, 0xcc, 0x00, 0xca, 0x00, 0xcb, 0x00, 0xcc, 0x00, + 0xcd, 0x00, 0xcc, 0x00, 0xce, 0x00, 0xcc, 0x00, 0xca, 0x00, 0xcb, 0x00, 0xcc, 0x00, 0xcd, 0x00, + 0xcc, 0x00, 0xce, 0x00, 0xcc, 0x00, 0xca, 0x00, 0xcb, 0x00, 0xcc, 0x00, 0xcd, 0x00, 0xcc, 0x00, + 0xce, 0x00, 0xcc, 0x00, 0xca, 0x00, 0xcb, 0x00, 0xcc, 0x00, 0xcd, 0x00, 0xcc, 0x00, 0xce, 0x00, + 0xcc, 0x00, 0xca, 0x00, 0xcb, 0x00, 0xcc, 0x00, 0xcd, 0x00, 0xcc, 0x00, 0xce, 0x00, 0xcc, 0x00, + 0xca, 0x00, 0xcb, 0x00, 0xcc, 0x00, 0xcd, 0x00, 0xcc, 0x00, 0xce, 0x00, 0xcc, 0x00, 0xca, 0x00, + 0xcb, 0x00, 0xcc, 0x00, 0xcd, 0x00, 0xcc, 0x00, 0xce, 0x00, 0xcc, 0x00, 0xca, 0x00, 0xcb, 0x00, + 0xcc, 0x00, 0xcd, 0x00, 0xcc, 0x00, 0xce, 0x00, 0xcc, 0x00, 0xca, 0x00, 0xcb, 0x00, 0xcc, 0x00, + 0xcd, 0x00, 0xcc, 0x00, 0xcf, 0x00, 0x56, 0x00, 0xd0, 0x00, 0x58, 0x00, 0x58, 0x00, 0xd1, 0x00, 0x02, 0x00, 0x02, 0x00, 0x02, 0x00, 0x02, 0x00, 0x02, 0x00, 0x02, 0x00, 0x02, 0x00, 0x02, 0x00, 0x02, 0x00, 0x02, 0x00, 0x02, 0x00, 0x02, 0x00, 0x02, 0x00, 0x02, 0x00, 0x02, 0x00, 0x02, 0x00, - 0x02, 0x00, 0x02, 0x00, 0x02, 0x00, 0x02, 0x00, 0x02, 0x00, 0x02, 0x00, 0xd3, 0x00, 0xd4, 0x00, - 0x02, 0x00, 0x02, 0x00, 0x02, 0x00, 0xd5, 0x00, 0x02, 0x00, 0xd6, 0x00, 0x02, 0x00, 0xd7, 0x00, + 0x02, 0x00, 0x02, 0x00, 0x02, 0x00, 0x02, 0x00, 0x02, 0x00, 0x02, 0x00, 0xd2, 0x00, 0xd3, 0x00, + 0x02, 0x00, 0x02, 0x00, 0x02, 0x00, 0xd4, 0x00, 0x02, 0x00, 0xd5, 0x00, 0x02, 0x00, 0xd6, 0x00, 0x02, 0x00, 0x02, 0x00, 0x02, 0x00, 0x02, 0x00, 0x02, 0x00, 0x02, 0x00, 0x02, 0x00, 0x02, 0x00, 0x02, 0x00, 0x02, 0x00, 0x02, 0x00, 0x02, 0x00, 0x02, 0x00, 0x02, 0x00, 0x02, 0x00, 0x02, 0x00, - 0x02, 0x00, 0xd8, 0x00, 0x02, 0x00, 0x02, 0x00, 0x02, 0x00, 0x02, 0x00, 0x02, 0x00, 0x02, 0x00, + 0x02, 0x00, 0xd7, 0x00, 0x02, 0x00, 0x02, 0x00, 0x02, 0x00, 0x02, 0x00, 0x02, 0x00, 0x02, 0x00, 0x02, 0x00, 0x02, 0x00, 0x02, 0x00, 0x02, 0x00, 0x02, 0x00, 0x02, 0x00, 0x02, 0x00, 0x02, 0x00, 0x07, 0x00, 0x02, 0x00, 0x07, 0x00, 0x02, 0x00, 0x02, 0x00, 0x02, 0x00, 0x02, 0x00, 0x02, 0x00, 0x02, 0x00, 0x02, 0x00, 0x02, 0x00, 0x02, 0x00, 0x02, 0x00, 0x02, 0x00, 0x02, 0x00, 0x04, 0x00, 0x02, 0x00, 0x03, 0x00, 0x02, 0x00, 0x02, 0x00, 0x02, 0x00, 0x02, 0x00, 0x02, 0x00, 0x02, 0x00, - 0x02, 0x00, 0x35, 0x00, 0x02, 0x00, 0x02, 0x00, 0x02, 0x00, 0x02, 0x00, 0x02, 0x00, 0xd9, 0x00, + 0x02, 0x00, 0x35, 0x00, 0x02, 0x00, 0x02, 0x00, 0x02, 0x00, 0x02, 0x00, 0x02, 0x00, 0xd8, 0x00, 0x02, 0x00, 0x02, 0x00, 0x02, 0x00, 0x02, 0x00, 0x02, 0x00, 0x02, 0x00, 0x02, 0x00, 0x02, 0x00, 0x02, 0x00, 0x02, 0x00, 0x02, 0x00, 0x02, 0x00, 0x02, 0x00, 0x02, 0x00, 0x02, 0x00, 0x02, 0x00, - 0xda, 0x00, 0xdb, 0x00, 0xdc, 0x00, 0xdd, 0x00, 0xde, 0x00, 0xdf, 0x00, 0xe0, 0x00, 0xe1, 0x00, - 0xe2, 0x00, 0x02, 0x00, 0x02, 0x00, 0x02, 0x00, 0x02, 0x00, 0x02, 0x00, 0x02, 0x00, 0xe3, 0x00, + 0xd9, 0x00, 0xda, 0x00, 0xdb, 0x00, 0xdc, 0x00, 0xdd, 0x00, 0xde, 0x00, 0xdf, 0x00, 0xe0, 0x00, + 0xe1, 0x00, 0x02, 0x00, 0x02, 0x00, 0x02, 0x00, 0x02, 0x00, 0x02, 0x00, 0x02, 0x00, 0xe2, 0x00, 0x02, 0x00, 0x02, 0x00, 0x02, 0x00, 0x02, 0x00, 0x02, 0x00, 0x02, 0x00, 0x02, 0x00, 0x02, 0x00, - 0x02, 0x00, 0x02, 0x00, 0x02, 0x00, 0x02, 0x00, 0x02, 0x00, 0x02, 0x00, 0xe4, 0x00, 0xe5, 0x00, - 0x02, 0x00, 0x02, 0x00, 0xe6, 0x00, 0x02, 0x00, 0xe7, 0x00, 0x02, 0x00, 0x02, 0x00, 0xe8, 0x00, - 0x02, 0x00, 0x02, 0x00, 0x02, 0x00, 0x02, 0x00, 0x02, 0x00, 0xe9, 0x00, 0x02, 0x00, 0x02, 0x00, + 0x02, 0x00, 0x02, 0x00, 0x02, 0x00, 0x02, 0x00, 0x02, 0x00, 0x02, 0x00, 0xe3, 0x00, 0xe4, 0x00, + 0x02, 0x00, 0x02, 0x00, 0xe5, 0x00, 0x02, 0x00, 0xe6, 0x00, 0x02, 0x00, 0x02, 0x00, 0xe7, 0x00, + 0x02, 0x00, 0x02, 0x00, 0x02, 0x00, 0x02, 0x00, 0x02, 0x00, 0xe8, 0x00, 0x02, 0x00, 0x02, 0x00, 0x02, 0x00, 0x02, 0x00, 0x02, 0x00, 0x02, 0x00, 0x02, 0x00, 0x02, 0x00, 0x02, 0x00, 0x02, 0x00, 0x02, 0x00, 0x02, 0x00, 0x03, 0x00, 0x02, 0x00, 0x02, 0x00, 0x02, 0x00, 0x02, 0x00, 0x02, 0x00, 0x02, 0x00, 0x02, 0x00, 0x02, 0x00, 0x02, 0x00, 0x02, 0x00, 0x02, 0x00, 0x02, 0x00, 0x02, 0x00, 0x02, 0x00, 0x02, 0x00, 0x02, 0x00, 0x02, 0x00, 0x02, 0x00, 0x02, 0x00, 0x02, 0x00, 0x02, 0x00, - 0x02, 0x00, 0x02, 0x00, 0x02, 0x00, 0x02, 0x00, 0x02, 0x00, 0xea, 0x00, 0x02, 0x00, 0xeb, 0x00, - 0x02, 0x00, 0x02, 0x00, 0xec, 0x00, 0x02, 0x00, 0x02, 0x00, 0x02, 0x00, 0x02, 0x00, 0xed, 0x00, - 0x02, 0x00, 0xee, 0x00, 0x02, 0x00, 0x02, 0x00, 0x02, 0x00, 0x02, 0x00, 0x02, 0x00, 0x02, 0x00, - 0x02, 0x00, 0x02, 0x00, 0x02, 0x00, 0xef, 0x00, 0xf0, 0x00, 0xf1, 0x00, 0xf2, 0x00, 0xf3, 0x00, - 0xf4, 0x00, 0x02, 0x00, 0x02, 0x00, 0xf5, 0x00, 0xf6, 0x00, 0x02, 0x00, 0x02, 0x00, 0xf7, 0x00, - 0x02, 0x00, 0xf8, 0x00, 0x02, 0x00, 0x02, 0x00, 0x02, 0x00, 0x02, 0x00, 0xf9, 0x00, 0x02, 0x00, - 0x02, 0x00, 0x02, 0x00, 0x02, 0x00, 0x02, 0x00, 0x02, 0x00, 0xfa, 0x00, 0x02, 0x00, 0xfa, 0x00, - 0x02, 0x00, 0x02, 0x00, 0xfb, 0x00, 0x02, 0x00, 0x02, 0x00, 0x02, 0x00, 0x02, 0x00, 0x02, 0x00, + 0x02, 0x00, 0x02, 0x00, 0x02, 0x00, 0x02, 0x00, 0x02, 0x00, 0xe9, 0x00, 0x02, 0x00, 0xea, 0x00, + 0x02, 0x00, 0x02, 0x00, 0xeb, 0x00, 0x02, 0x00, 0x02, 0x00, 0x02, 0x00, 0x02, 0x00, 0xec, 0x00, + 0x02, 0x00, 0xed, 0x00, 0x02, 0x00, 0x02, 0x00, 0x02, 0x00, 0x02, 0x00, 0x02, 0x00, 0x02, 0x00, + 0x02, 0x00, 0x02, 0x00, 0x02, 0x00, 0xee, 0x00, 0xef, 0x00, 0xf0, 0x00, 0xf1, 0x00, 0xf2, 0x00, + 0xf3, 0x00, 0x02, 0x00, 0x02, 0x00, 0xf4, 0x00, 0xf5, 0x00, 0x02, 0x00, 0x02, 0x00, 0xf6, 0x00, + 0x02, 0x00, 0xf7, 0x00, 0x02, 0x00, 0x02, 0x00, 0x02, 0x00, 0x02, 0x00, 0xf8, 0x00, 0x02, 0x00, + 0x02, 0x00, 0x02, 0x00, 0x02, 0x00, 0x02, 0x00, 0x02, 0x00, 0xf9, 0x00, 0x02, 0x00, 0xf9, 0x00, + 0x02, 0x00, 0x02, 0x00, 0xfa, 0x00, 0x02, 0x00, 0x02, 0x00, 0x02, 0x00, 0x02, 0x00, 0x02, 0x00, 0x02, 0x00, 0x02, 0x00, 0x02, 0x00, 0x02, 0x00, 0x02, 0x00, 0x02, 0x00, 0x02, 0x00, 0x02, 0x00, - 0x02, 0x00, 0x02, 0x00, 0x02, 0x00, 0x02, 0x00, 0x02, 0x00, 0x02, 0x00, 0x02, 0x00, 0xfc, 0x00, - 0x02, 0x00, 0x02, 0x00, 0xfd, 0x00, 0x03, 0x00, 0x02, 0x00, 0x02, 0x00, 0x02, 0x00, 0x02, 0x00, - 0x02, 0x00, 0x02, 0x00, 0x02, 0x00, 0x02, 0x00, 0x02, 0x00, 0x02, 0x00, 0x02, 0x00, 0x02, 0x00, - 0x02, 0x00, 0x02, 0x00, 0x02, 0x00, 0x02, 0x00, 0x02, 0x00, 0x02, 0x00, 0xfe, 0x00, 0xff, 0x00, + 0x02, 0x00, 0x02, 0x00, 0x02, 0x00, 0x02, 0x00, 0x02, 0x00, 0x02, 0x00, 0x02, 0x00, 0xfb, 0x00, + 0x02, 0x00, 0x02, 0x00, 0xfc, 0x00, 0x03, 0x00, 0x02, 0x00, 0x02, 0x00, 0x02, 0x00, 0x02, 0x00, 0x02, 0x00, 0x02, 0x00, 0x02, 0x00, 0x02, 0x00, 0x02, 0x00, 0x02, 0x00, 0x02, 0x00, 0x02, 0x00, + 0x02, 0x00, 0x02, 0x00, 0x02, 0x00, 0x02, 0x00, 0x02, 0x00, 0x02, 0x00, 0xfd, 0x00, 0xfe, 0x00, + 0x02, 0x00, 0x02, 0x00, 0xff, 0x00, 0x02, 0x00, 0x02, 0x00, 0x02, 0x00, 0x02, 0x00, 0x02, 0x00, 0x02, 0x00, 0x00, 0x01, 0x01, 0x01, 0x02, 0x00, 0x15, 0x00, 0x02, 0x01, 0x02, 0x00, 0x02, 0x00, + 0x02, 0x00, 0x02, 0x00, 0x02, 0x00, 0x02, 0x00, 0x03, 0x01, 0x02, 0x00, 0x02, 0x00, 0x02, 0x00, + 0x04, 0x01, 0x02, 0x00, 0x02, 0x00, 0x05, 0x01, 0x06, 0x01, 0x07, 0x01, 0x08, 0x01, 0xa6, 0x00, + 0x6f, 0x00, 0x02, 0x00, 0x02, 0x00, 0x09, 0x01, 0x0a, 0x01, 0x02, 0x00, 0x02, 0x00, 0x03, 0x00, + 0x0b, 0x01, 0x02, 0x00, 0x0c, 0x01, 0x0d, 0x01, 0x0e, 0x01, 0x02, 0x00, 0x02, 0x00, 0x0f, 0x01, + 0x6f, 0x00, 0x02, 0x00, 0x02, 0x00, 0x10, 0x01, 0x11, 0x01, 0x03, 0x00, 0x12, 0x01, 0x13, 0x01, + 0x02, 0x00, 0x02, 0x00, 0x14, 0x01, 0x15, 0x01, 0x02, 0x00, 0x02, 0x00, 0x02, 0x00, 0x02, 0x00, + 0x02, 0x00, 0x02, 0x00, 0x02, 0x00, 0x02, 0x00, 0x02, 0x00, 0xa6, 0x00, 0x16, 0x01, 0x03, 0x00, + 0x3b, 0x00, 0x02, 0x00, 0x02, 0x00, 0x3c, 0x00, 0x17, 0x01, 0x24, 0x00, 0x18, 0x01, 0x19, 0x01, 0x02, 0x00, 0x02, 0x00, 0x02, 0x00, 0x02, 0x00, 0x02, 0x00, 0x02, 0x00, 0x02, 0x00, 0x02, 0x00, - 0x03, 0x01, 0x02, 0x00, 0x02, 0x00, 0x04, 0x01, 0x05, 0x01, 0x06, 0x01, 0x07, 0x01, 0xa7, 0x00, - 0x70, 0x00, 0x02, 0x00, 0x02, 0x00, 0x08, 0x01, 0x09, 0x01, 0x02, 0x00, 0x02, 0x00, 0x03, 0x00, - 0x0a, 0x01, 0x02, 0x00, 0x0b, 0x01, 0x0c, 0x01, 0x0d, 0x01, 0x02, 0x00, 0x02, 0x00, 0x0e, 0x01, - 0x70, 0x00, 0x02, 0x00, 0x02, 0x00, 0x0f, 0x01, 0x10, 0x01, 0x03, 0x00, 0x11, 0x01, 0x12, 0x01, - 0x02, 0x00, 0x02, 0x00, 0x13, 0x01, 0x14, 0x01, 0x02, 0x00, 0x02, 0x00, 0x02, 0x00, 0x02, 0x00, - 0x02, 0x00, 0x02, 0x00, 0x02, 0x00, 0x02, 0x00, 0x02, 0x00, 0xa7, 0x00, 0x15, 0x01, 0x03, 0x00, - 0x3b, 0x00, 0x02, 0x00, 0x02, 0x00, 0x3c, 0x00, 0x16, 0x01, 0x24, 0x00, 0x17, 0x01, 0x18, 0x01, + 0x02, 0x00, 0x02, 0x00, 0x02, 0x00, 0x1a, 0x01, 0x1b, 0x01, 0x1c, 0x01, 0x02, 0x00, 0x02, 0x00, + 0x02, 0x00, 0x02, 0x00, 0x02, 0x00, 0x1d, 0x01, 0x1e, 0x01, 0x03, 0x00, 0x02, 0x00, 0x02, 0x00, 0x02, 0x00, 0x02, 0x00, 0x02, 0x00, 0x02, 0x00, 0x02, 0x00, 0x02, 0x00, 0x02, 0x00, 0x02, 0x00, - 0x02, 0x00, 0x02, 0x00, 0x02, 0x00, 0x19, 0x01, 0x1a, 0x01, 0x1b, 0x01, 0x02, 0x00, 0x02, 0x00, - 0x02, 0x00, 0x02, 0x00, 0x02, 0x00, 0x1c, 0x01, 0x1d, 0x01, 0x03, 0x00, 0x02, 0x00, 0x02, 0x00, + 0x02, 0x00, 0x02, 0x00, 0xa6, 0x00, 0x1f, 0x01, 0x0f, 0x00, 0x20, 0x01, 0x02, 0x00, 0x02, 0x00, + 0x02, 0x00, 0x02, 0x00, 0x02, 0x00, 0x21, 0x01, 0x0f, 0x00, 0x03, 0x00, 0x02, 0x00, 0x02, 0x00, + 0x02, 0x00, 0x02, 0x00, 0x22, 0x01, 0x23, 0x01, 0x03, 0x00, 0x02, 0x00, 0x02, 0x00, 0x02, 0x00, + 0x02, 0x00, 0x4f, 0x00, 0x24, 0x01, 0x25, 0x01, 0x02, 0x00, 0x02, 0x00, 0x02, 0x00, 0x02, 0x00, 0x02, 0x00, 0x02, 0x00, 0x02, 0x00, 0x02, 0x00, 0x02, 0x00, 0x02, 0x00, 0x02, 0x00, 0x02, 0x00, - 0x02, 0x00, 0x02, 0x00, 0xa7, 0x00, 0x1e, 0x01, 0x0f, 0x00, 0x1f, 0x01, 0x02, 0x00, 0x02, 0x00, - 0x02, 0x00, 0x02, 0x00, 0x02, 0x00, 0x20, 0x01, 0x0f, 0x00, 0x03, 0x00, 0x02, 0x00, 0x02, 0x00, - 0x02, 0x00, 0x02, 0x00, 0x21, 0x01, 0x22, 0x01, 0x03, 0x00, 0x02, 0x00, 0x02, 0x00, 0x02, 0x00, - 0x02, 0x00, 0x4f, 0x00, 0x23, 0x01, 0x24, 0x01, 0x02, 0x00, 0x02, 0x00, 0x02, 0x00, 0x02, 0x00, - 0x02, 0x00, 0x02, 0x00, 0x02, 0x00, 0x02, 0x00, 0x02, 0x00, 0x02, 0x00, 0x02, 0x00, 0x02, 0x00, - 0x02, 0x00, 0x02, 0x00, 0x13, 0x01, 0x25, 0x01, 0x02, 0x00, 0x02, 0x00, 0x02, 0x00, 0x02, 0x00, - 0x02, 0x00, 0x02, 0x00, 0x02, 0x00, 0x02, 0x00, 0x02, 0x00, 0x02, 0x00, 0x26, 0x01, 0x27, 0x01, - 0x02, 0x00, 0x02, 0x00, 0x02, 0x00, 0x02, 0x00, 0x02, 0x00, 0x02, 0x00, 0x02, 0x00, 0x02, 0x00, - 0x02, 0x00, 0x02, 0x00, 0x02, 0x00, 0x02, 0x00, 0x02, 0x00, 0x28, 0x01, 0x29, 0x01, 0x02, 0x00, - 0x2a, 0x01, 0x02, 0x00, 0x02, 0x00, 0x2b, 0x01, 0x24, 0x00, 0x2c, 0x01, 0x02, 0x00, 0x02, 0x00, - 0x2d, 0x01, 0x2e, 0x01, 0x02, 0x00, 0x02, 0x00, 0x02, 0x00, 0x02, 0x00, 0x02, 0x00, 0x02, 0x00, + 0x02, 0x00, 0x02, 0x00, 0x14, 0x01, 0x26, 0x01, 0x02, 0x00, 0x02, 0x00, 0x02, 0x00, 0x02, 0x00, + 0x02, 0x00, 0x02, 0x00, 0x02, 0x00, 0x02, 0x00, 0x02, 0x00, 0x02, 0x00, 0x27, 0x01, 0x28, 0x01, + 0x02, 0x00, 0x02, 0x00, 0x02, 0x00, 0x29, 0x01, 0x2a, 0x01, 0x03, 0x00, 0x02, 0x00, 0x02, 0x00, + 0x02, 0x00, 0x02, 0x00, 0x02, 0x00, 0x02, 0x00, 0x02, 0x00, 0x2b, 0x01, 0x2c, 0x01, 0x02, 0x00, + 0x2d, 0x01, 0x02, 0x00, 0x02, 0x00, 0x2e, 0x01, 0x24, 0x00, 0x2f, 0x01, 0x02, 0x00, 0x02, 0x00, + 0x30, 0x01, 0x31, 0x01, 0x02, 0x00, 0x02, 0x00, 0x02, 0x00, 0x02, 0x00, 0x02, 0x00, 0x02, 0x00, 0x02, 0x00, 0x02, 0x00, 0x02, 0x00, 0x02, 0x00, 0x02, 0x00, 0x02, 0x00, 0x02, 0x00, 0x02, 0x00, 0x02, 0x00, 0x02, 0x00, 0x02, 0x00, 0x02, 0x00, 0x02, 0x00, 0x02, 0x00, 0x02, 0x00, 0x02, 0x00, - 0x02, 0x00, 0x02, 0x00, 0x2f, 0x01, 0x30, 0x01, 0x02, 0x00, 0x31, 0x01, 0x32, 0x01, 0x02, 0x00, - 0x02, 0x00, 0x33, 0x01, 0x34, 0x01, 0x35, 0x01, 0x02, 0x00, 0x02, 0x00, 0x02, 0x00, 0x02, 0x00, - 0x02, 0x00, 0x02, 0x00, 0x02, 0x00, 0x36, 0x01, 0x37, 0x01, 0x03, 0x00, 0x02, 0x00, 0x02, 0x00, - 0x38, 0x01, 0x39, 0x01, 0x03, 0x00, 0x02, 0x00, 0x02, 0x00, 0x02, 0x00, 0x02, 0x00, 0x02, 0x00, + 0x02, 0x00, 0x02, 0x00, 0x32, 0x01, 0x33, 0x01, 0x02, 0x00, 0x34, 0x01, 0x35, 0x01, 0x02, 0x00, + 0x02, 0x00, 0x36, 0x01, 0x37, 0x01, 0x38, 0x01, 0x02, 0x00, 0x02, 0x00, 0x02, 0x00, 0x02, 0x00, + 0x02, 0x00, 0x02, 0x00, 0x02, 0x00, 0x39, 0x01, 0x3a, 0x01, 0x03, 0x00, 0x02, 0x00, 0x02, 0x00, + 0x3b, 0x01, 0x3c, 0x01, 0x03, 0x00, 0x02, 0x00, 0x02, 0x00, 0x02, 0x00, 0x02, 0x00, 0x02, 0x00, 0x02, 0x00, 0x02, 0x00, 0x02, 0x00, 0x02, 0x00, 0x02, 0x00, 0x02, 0x00, 0x02, 0x00, 0x02, 0x00, - 0x02, 0x00, 0x02, 0x00, 0x02, 0x00, 0x02, 0x00, 0x02, 0x00, 0x02, 0x00, 0x02, 0x00, 0x3a, 0x01, + 0x02, 0x00, 0x02, 0x00, 0x02, 0x00, 0x02, 0x00, 0x02, 0x00, 0x02, 0x00, 0x02, 0x00, 0x3d, 0x01, 0x02, 0x00, 0x02, 0x00, 0x02, 0x00, 0x02, 0x00, 0x02, 0x00, 0x02, 0x00, 0x02, 0x00, 0x02, 0x00, - 0x02, 0x00, 0x02, 0x00, 0x02, 0x00, 0x02, 0x00, 0x3b, 0x01, 0x3c, 0x01, 0x02, 0x00, 0x02, 0x00, - 0x3d, 0x01, 0x3e, 0x01, 0x3f, 0x01, 0x40, 0x01, 0x41, 0x01, 0x42, 0x01, 0x43, 0x01, 0x02, 0x00, + 0x02, 0x00, 0x02, 0x00, 0x02, 0x00, 0x02, 0x00, 0x3e, 0x01, 0x3f, 0x01, 0x02, 0x00, 0x02, 0x00, + 0x40, 0x01, 0x41, 0x01, 0x42, 0x01, 0x43, 0x01, 0x44, 0x01, 0x45, 0x01, 0x46, 0x01, 0x02, 0x00, 0x02, 0x00, 0x02, 0x00, 0x02, 0x00, 0x02, 0x00, 0x02, 0x00, 0x02, 0x00, 0x02, 0x00, 0x02, 0x00, 0x02, 0x00, 0x02, 0x00, 0x02, 0x00, 0x02, 0x00, 0x02, 0x00, 0x02, 0x00, 0x02, 0x00, 0x02, 0x00, 0x02, 0x00, 0x02, 0x00, 0x02, 0x00, 0x02, 0x00, 0x02, 0x00, 0x02, 0x00, 0x02, 0x00, 0x02, 0x00, - 0x02, 0x00, 0x02, 0x00, 0x02, 0x00, 0x44, 0x01, 0x02, 0x00, 0x02, 0x00, 0x02, 0x00, 0x02, 0x00, + 0x02, 0x00, 0x02, 0x00, 0x02, 0x00, 0x47, 0x01, 0x02, 0x00, 0x02, 0x00, 0x02, 0x00, 0x02, 0x00, 0x02, 0x00, 0x02, 0x00, 0x02, 0x00, 0x02, 0x00, 0x02, 0x00, 0x02, 0x00, 0x02, 0x00, 0x02, 0x00, 0x02, 0x00, 0x02, 0x00, 0x02, 0x00, 0x02, 0x00, 0x02, 0x00, 0x02, 0x00, 0x02, 0x00, 0x02, 0x00, 0x02, 0x00, 0x02, 0x00, 0x02, 0x00, 0x02, 0x00, 0x02, 0x00, 0x02, 0x00, 0x02, 0x00, 0x02, 0x00, 0x02, 0x00, 0x02, 0x00, 0x02, 0x00, 0x02, 0x00, 0x02, 0x00, 0x02, 0x00, 0x03, 0x00, 0x02, 0x00, - 0x02, 0x00, 0x02, 0x00, 0x02, 0x00, 0x02, 0x00, 0x02, 0x00, 0x02, 0x00, 0x02, 0x00, 0x18, 0x01, - 0x02, 0x00, 0x02, 0x00, 0x02, 0x00, 0x05, 0x01, 0x02, 0x00, 0x45, 0x01, 0x46, 0x01, 0x02, 0x00, + 0x02, 0x00, 0x02, 0x00, 0x02, 0x00, 0x02, 0x00, 0x02, 0x00, 0x02, 0x00, 0x02, 0x00, 0x19, 0x01, + 0x02, 0x00, 0x02, 0x00, 0x02, 0x00, 0x06, 0x01, 0x02, 0x00, 0x48, 0x01, 0x49, 0x01, 0x02, 0x00, 0x02, 0x00, 0x02, 0x00, 0x02, 0x00, 0x02, 0x00, 0x02, 0x00, 0x02, 0x00, 0x02, 0x00, 0x02, 0x00, 0x02, 0x00, 0x02, 0x00, 0x02, 0x00, 0x02, 0x00, 0x02, 0x00, 0x02, 0x00, 0x02, 0x00, 0x02, 0x00, - 0x47, 0x01, 0x48, 0x01, 0x02, 0x00, 0x02, 0x00, 0x02, 0x00, 0x02, 0x00, 0x02, 0x00, 0x02, 0x00, - 0x02, 0x00, 0x02, 0x00, 0x02, 0x00, 0x02, 0x00, 0xa7, 0x00, 0x49, 0x01, 0x4a, 0x01, 0x4a, 0x01, - 0x4b, 0x01, 0x0a, 0x01, 0x02, 0x00, 0x02, 0x00, 0x02, 0x00, 0x02, 0x00, 0x02, 0x00, 0x02, 0x00, + 0x4a, 0x01, 0x4b, 0x01, 0x02, 0x00, 0x02, 0x00, 0x02, 0x00, 0x02, 0x00, 0x02, 0x00, 0x02, 0x00, + 0x02, 0x00, 0x02, 0x00, 0x02, 0x00, 0x02, 0x00, 0xa6, 0x00, 0x4c, 0x01, 0x4d, 0x01, 0x4d, 0x01, + 0x4e, 0x01, 0x0b, 0x01, 0x02, 0x00, 0x02, 0x00, 0x02, 0x00, 0x02, 0x00, 0x4f, 0x01, 0xb8, 0x00, 0x02, 0x00, 0x02, 0x00, 0x02, 0x00, 0x02, 0x00, 0x02, 0x00, 0x02, 0x00, 0x02, 0x00, 0x02, 0x00, - 0x02, 0x00, 0x4c, 0x01, 0x4d, 0x01, 0x02, 0x00, 0x02, 0x00, 0x02, 0x00, 0x02, 0x00, 0x02, 0x00, + 0x02, 0x00, 0x50, 0x01, 0x51, 0x01, 0x02, 0x00, 0x02, 0x00, 0x02, 0x00, 0x02, 0x00, 0x02, 0x00, 0x02, 0x00, 0x02, 0x00, 0x02, 0x00, 0x02, 0x00, 0x02, 0x00, 0x02, 0x00, 0x02, 0x00, 0x02, 0x00, 0x02, 0x00, 0x02, 0x00, 0x02, 0x00, 0x02, 0x00, 0x02, 0x00, 0x02, 0x00, 0x02, 0x00, 0x02, 0x00, 0x02, 0x00, 0x02, 0x00, 0x02, 0x00, 0x02, 0x00, 0x02, 0x00, 0x02, 0x00, 0x02, 0x00, 0x02, 0x00, 0x02, 0x00, 0x02, 0x00, 0x02, 0x00, 0x02, 0x00, 0x02, 0x00, 0x02, 0x00, 0x02, 0x00, 0x02, 0x00, - 0x02, 0x00, 0x02, 0x00, 0x02, 0x00, 0x02, 0x00, 0x02, 0x00, 0x02, 0x00, 0x4e, 0x01, 0x4f, 0x01, - 0x50, 0x01, 0x02, 0x00, 0x51, 0x01, 0x02, 0x00, 0x02, 0x00, 0x02, 0x00, 0x02, 0x00, 0x02, 0x00, + 0x02, 0x00, 0x02, 0x00, 0x02, 0x00, 0x02, 0x00, 0x02, 0x00, 0x02, 0x00, 0x52, 0x01, 0x53, 0x01, + 0x54, 0x01, 0x02, 0x00, 0x55, 0x01, 0x02, 0x00, 0x02, 0x00, 0x02, 0x00, 0x02, 0x00, 0x02, 0x00, 0x02, 0x00, 0x02, 0x00, 0x02, 0x00, 0x02, 0x00, 0x5d, 0x00, 0x02, 0x00, 0x02, 0x00, 0x02, 0x00, - 0x02, 0x00, 0x02, 0x00, 0x02, 0x00, 0x02, 0x00, 0x02, 0x00, 0x02, 0x00, 0x47, 0x01, 0x52, 0x01, - 0x02, 0x00, 0x02, 0x00, 0x02, 0x00, 0x02, 0x00, 0x02, 0x00, 0x02, 0x00, 0xf0, 0x00, 0x53, 0x01, + 0x02, 0x00, 0x02, 0x00, 0x02, 0x00, 0x02, 0x00, 0x02, 0x00, 0x02, 0x00, 0x4a, 0x01, 0x56, 0x01, + 0x02, 0x00, 0x02, 0x00, 0x02, 0x00, 0x02, 0x00, 0x02, 0x00, 0x02, 0x00, 0xef, 0x00, 0x57, 0x01, 0x02, 0x00, 0x02, 0x00, 0x02, 0x00, 0x02, 0x00, 0x02, 0x00, 0x02, 0x00, 0x02, 0x00, 0x02, 0x00, 0x02, 0x00, 0x02, 0x00, 0x02, 0x00, 0x02, 0x00, 0x02, 0x00, 0x02, 0x00, 0x02, 0x00, 0x02, 0x00, 0x02, 0x00, 0x02, 0x00, 0x02, 0x00, 0x02, 0x00, 0x02, 0x00, 0x02, 0x00, 0x02, 0x00, 0x02, 0x00, 0x02, 0x00, 0x02, 0x00, 0x02, 0x00, 0x02, 0x00, 0x02, 0x00, 0x02, 0x00, 0x02, 0x00, 0x02, 0x00, - 0x02, 0x00, 0x02, 0x00, 0x02, 0x00, 0x02, 0x00, 0x54, 0x01, 0x55, 0x01, 0x56, 0x01, 0x57, 0x01, - 0x07, 0x00, 0x07, 0x00, 0x07, 0x00, 0x58, 0x01, 0x07, 0x00, 0x07, 0x00, 0x4d, 0x00, 0xc2, 0x00, - 0x59, 0x01, 0x0e, 0x00, 0x09, 0x00, 0x02, 0x00, 0x02, 0x00, 0x02, 0x00, 0x02, 0x00, 0x02, 0x00, + 0x02, 0x00, 0x02, 0x00, 0x02, 0x00, 0x02, 0x00, 0x58, 0x01, 0x59, 0x01, 0x5a, 0x01, 0x5b, 0x01, + 0x07, 0x00, 0x07, 0x00, 0x07, 0x00, 0x5c, 0x01, 0x07, 0x00, 0x07, 0x00, 0x4d, 0x00, 0xc1, 0x00, + 0x4f, 0x01, 0x0e, 0x00, 0x09, 0x00, 0x02, 0x00, 0x02, 0x00, 0x02, 0x00, 0x02, 0x00, 0x02, 0x00, 0x02, 0x00, 0x02, 0x00, 0x02, 0x00, 0x02, 0x00, 0x02, 0x00, 0x02, 0x00, 0x02, 0x00, 0x02, 0x00, 0x02, 0x00, 0x02, 0x00, 0x02, 0x00, 0x02, 0x00, 0x02, 0x00, 0x02, 0x00, 0x02, 0x00, 0x02, 0x00, - 0x5a, 0x01, 0x5b, 0x01, 0x5c, 0x01, 0x02, 0x00, 0x02, 0x00, 0x02, 0x00, 0x02, 0x00, 0x02, 0x00, + 0x5d, 0x01, 0x5e, 0x01, 0x5f, 0x01, 0x02, 0x00, 0x02, 0x00, 0x02, 0x00, 0x02, 0x00, 0x02, 0x00, 0x02, 0x00, 0x02, 0x00, 0x02, 0x00, 0x02, 0x00, 0x02, 0x00, 0x02, 0x00, 0x02, 0x00, 0x02, 0x00, - 0x02, 0x00, 0x02, 0x00, 0x02, 0x00, 0x05, 0x01, 0x03, 0x00, 0x02, 0x00, 0x02, 0x00, 0x02, 0x00, + 0x02, 0x00, 0x02, 0x00, 0x02, 0x00, 0x06, 0x01, 0x03, 0x00, 0x02, 0x00, 0x02, 0x00, 0x02, 0x00, 0x02, 0x00, 0x02, 0x00, 0x02, 0x00, 0x02, 0x00, 0x02, 0x00, 0x02, 0x00, 0x02, 0x00, 0x02, 0x00, 0x02, 0x00, 0x02, 0x00, 0x02, 0x00, 0x02, 0x00, 0x02, 0x00, 0x02, 0x00, 0x02, 0x00, 0x02, 0x00, - 0x02, 0x00, 0x02, 0x00, 0x02, 0x00, 0x02, 0x00, 0x02, 0x00, 0x02, 0x00, 0x5d, 0x01, 0x03, 0x00, + 0x02, 0x00, 0x02, 0x00, 0x02, 0x00, 0x02, 0x00, 0x02, 0x00, 0x02, 0x00, 0x60, 0x01, 0x03, 0x00, 0x02, 0x00, 0x02, 0x00, 0x02, 0x00, 0x02, 0x00, 0x02, 0x00, 0x02, 0x00, 0x02, 0x00, 0x02, 0x00, 0x02, 0x00, 0x02, 0x00, 0x02, 0x00, 0x02, 0x00, 0x02, 0x00, 0x02, 0x00, 0x02, 0x00, 0x02, 0x00, 0x02, 0x00, 0x02, 0x00, 0x02, 0x00, 0x02, 0x00, 0x02, 0x00, 0x02, 0x00, 0x02, 0x00, 0x02, 0x00, - 0x02, 0x00, 0x02, 0x00, 0x02, 0x00, 0x02, 0x00, 0xda, 0x00, 0x05, 0x01, 0x02, 0x00, 0x02, 0x00, - 0x02, 0x00, 0x02, 0x00, 0x02, 0x00, 0x02, 0x00, 0x5e, 0x01, 0x03, 0x00, 0x02, 0x00, 0x02, 0x00, + 0x02, 0x00, 0x02, 0x00, 0x02, 0x00, 0x02, 0x00, 0xd9, 0x00, 0x06, 0x01, 0x02, 0x00, 0x02, 0x00, + 0x02, 0x00, 0x02, 0x00, 0x02, 0x00, 0x02, 0x00, 0x61, 0x01, 0x03, 0x00, 0x02, 0x00, 0x02, 0x00, 0x02, 0x00, 0x02, 0x00, 0x02, 0x00, 0x02, 0x00, 0x02, 0x00, 0x02, 0x00, 0x02, 0x00, 0x02, 0x00, - 0x02, 0x00, 0x02, 0x00, 0x02, 0x00, 0x02, 0x00, 0x02, 0x00, 0x02, 0x00, 0x02, 0x00, 0x11, 0x01, - 0x5f, 0x01, 0x60, 0x01, 0x61, 0x01, 0x62, 0x01, 0x02, 0x00, 0x02, 0x00, 0x02, 0x00, 0x02, 0x00, - 0x11, 0x01, 0x5f, 0x01, 0x63, 0x01, 0x64, 0x01, 0x02, 0x00, 0x02, 0x00, 0x02, 0x00, 0x02, 0x00, + 0x02, 0x00, 0x02, 0x00, 0x02, 0x00, 0x02, 0x00, 0x02, 0x00, 0x02, 0x00, 0x02, 0x00, 0x12, 0x01, + 0x62, 0x01, 0x63, 0x01, 0x64, 0x01, 0x65, 0x01, 0x02, 0x00, 0x02, 0x00, 0x02, 0x00, 0x02, 0x00, + 0x12, 0x01, 0x62, 0x01, 0x66, 0x01, 0x67, 0x01, 0x02, 0x00, 0x02, 0x00, 0x02, 0x00, 0x02, 0x00, 0x02, 0x00, 0x02, 0x00, 0x02, 0x00, 0x02, 0x00, 0x02, 0x00, 0x02, 0x00, 0x02, 0x00, 0x02, 0x00, - 0x95, 0x00, 0x95, 0x00, 0x95, 0x00, 0x95, 0x00, 0x95, 0x00, 0x95, 0x00, 0x95, 0x00, 0x95, 0x00, - 0x95, 0x00, 0x95, 0x00, 0x95, 0x00, 0x95, 0x00, 0x95, 0x00, 0x95, 0x00, 0x95, 0x00, 0x95, 0x00, - 0x65, 0x01, 0x02, 0x00, 0x87, 0x00, 0x02, 0x00, 0x02, 0x00, 0x02, 0x00, 0x66, 0x01, 0x67, 0x01, - 0x68, 0x01, 0x69, 0x01, 0x6a, 0x01, 0x95, 0x00, 0x95, 0x00, 0x95, 0x00, 0x6b, 0x01, 0x6c, 0x01, - 0x6d, 0x01, 0x6e, 0x01, 0x87, 0x00, 0x6f, 0x01, 0x88, 0x00, 0x95, 0x00, 0x95, 0x00, 0x95, 0x00, - 0x95, 0x00, 0x95, 0x00, 0x95, 0x00, 0x95, 0x00, 0x95, 0x00, 0x95, 0x00, 0x95, 0x00, 0x95, 0x00, - 0x95, 0x00, 0x95, 0x00, 0x95, 0x00, 0x95, 0x00, 0x95, 0x00, 0x95, 0x00, 0x95, 0x00, 0x95, 0x00, - 0x95, 0x00, 0x95, 0x00, 0x95, 0x00, 0x95, 0x00, 0x95, 0x00, 0x95, 0x00, 0x95, 0x00, 0x70, 0x01, - 0x95, 0x00, 0x95, 0x00, 0x95, 0x00, 0x95, 0x00, 0x95, 0x00, 0x95, 0x00, 0x95, 0x00, 0x95, 0x00, - 0x95, 0x00, 0x95, 0x00, 0x95, 0x00, 0x95, 0x00, 0x95, 0x00, 0x95, 0x00, 0x95, 0x00, 0x95, 0x00, - 0x95, 0x00, 0x95, 0x00, 0x95, 0x00, 0x71, 0x01, 0x72, 0x01, 0x95, 0x00, 0x95, 0x00, 0x95, 0x00, - 0x95, 0x00, 0x95, 0x00, 0x95, 0x00, 0x95, 0x00, 0x95, 0x00, 0x95, 0x00, 0x95, 0x00, 0x95, 0x00, - 0x95, 0x00, 0x95, 0x00, 0x95, 0x00, 0x95, 0x00, 0x95, 0x00, 0x02, 0x00, 0x02, 0x00, 0x02, 0x00, - 0x95, 0x00, 0x95, 0x00, 0x95, 0x00, 0x95, 0x00, 0x95, 0x00, 0x95, 0x00, 0x95, 0x00, 0x95, 0x00, - 0x02, 0x00, 0x02, 0x00, 0x02, 0x00, 0x02, 0x00, 0x02, 0x00, 0x02, 0x00, 0x02, 0x00, 0x73, 0x01, - 0x02, 0x00, 0x02, 0x00, 0x02, 0x00, 0x02, 0x00, 0x02, 0x00, 0x74, 0x01, 0x95, 0x00, 0x95, 0x00, - 0x66, 0x01, 0x02, 0x00, 0x02, 0x00, 0x02, 0x00, 0x75, 0x01, 0x76, 0x01, 0x02, 0x00, 0x02, 0x00, - 0x75, 0x01, 0x02, 0x00, 0x77, 0x01, 0x95, 0x00, 0x95, 0x00, 0x95, 0x00, 0x95, 0x00, 0x95, 0x00, - 0x66, 0x01, 0x95, 0x00, 0x95, 0x00, 0x78, 0x01, 0x93, 0x00, 0x95, 0x00, 0x95, 0x00, 0x95, 0x00, - 0x95, 0x00, 0x95, 0x00, 0x95, 0x00, 0x95, 0x00, 0x95, 0x00, 0x95, 0x00, 0x95, 0x00, 0x95, 0x00, - 0x95, 0x00, 0x95, 0x00, 0x95, 0x00, 0x95, 0x00, 0x95, 0x00, 0x95, 0x00, 0x95, 0x00, 0x95, 0x00, - 0x95, 0x00, 0x95, 0x00, 0x95, 0x00, 0x95, 0x00, 0x95, 0x00, 0x95, 0x00, 0x95, 0x00, 0x95, 0x00, - 0x95, 0x00, 0x95, 0x00, 0x95, 0x00, 0x95, 0x00, 0x95, 0x00, 0x95, 0x00, 0x95, 0x00, 0x95, 0x00, - 0x95, 0x00, 0x95, 0x00, 0x95, 0x00, 0x95, 0x00, 0x95, 0x00, 0x95, 0x00, 0x95, 0x00, 0x95, 0x00, - 0x95, 0x00, 0x95, 0x00, 0x95, 0x00, 0x95, 0x00, 0x95, 0x00, 0x95, 0x00, 0x95, 0x00, 0x95, 0x00, - 0x95, 0x00, 0x95, 0x00, 0x95, 0x00, 0x95, 0x00, 0x95, 0x00, 0x95, 0x00, 0x95, 0x00, 0x95, 0x00, - 0x95, 0x00, 0x95, 0x00, 0x95, 0x00, 0x95, 0x00, 0x95, 0x00, 0x95, 0x00, 0x95, 0x00, 0x95, 0x00, - 0x95, 0x00, 0x95, 0x00, 0x95, 0x00, 0x95, 0x00, 0x95, 0x00, 0x95, 0x00, 0x95, 0x00, 0x71, 0x01, + 0x94, 0x00, 0x94, 0x00, 0x94, 0x00, 0x94, 0x00, 0x94, 0x00, 0x94, 0x00, 0x94, 0x00, 0x94, 0x00, + 0x94, 0x00, 0x94, 0x00, 0x94, 0x00, 0x94, 0x00, 0x94, 0x00, 0x94, 0x00, 0x94, 0x00, 0x94, 0x00, + 0x68, 0x01, 0x02, 0x00, 0x86, 0x00, 0x02, 0x00, 0x02, 0x00, 0x02, 0x00, 0x69, 0x01, 0x6a, 0x01, + 0x6b, 0x01, 0x6c, 0x01, 0x6d, 0x01, 0x94, 0x00, 0x94, 0x00, 0x94, 0x00, 0x6e, 0x01, 0x6f, 0x01, + 0x70, 0x01, 0x71, 0x01, 0x86, 0x00, 0x72, 0x01, 0x87, 0x00, 0x94, 0x00, 0x94, 0x00, 0x94, 0x00, + 0x94, 0x00, 0x94, 0x00, 0x94, 0x00, 0x94, 0x00, 0x94, 0x00, 0x94, 0x00, 0x94, 0x00, 0x94, 0x00, + 0x94, 0x00, 0x94, 0x00, 0x94, 0x00, 0x94, 0x00, 0x94, 0x00, 0x94, 0x00, 0x94, 0x00, 0x94, 0x00, + 0x94, 0x00, 0x94, 0x00, 0x94, 0x00, 0x94, 0x00, 0x94, 0x00, 0x94, 0x00, 0x94, 0x00, 0x73, 0x01, + 0x94, 0x00, 0x94, 0x00, 0x94, 0x00, 0x94, 0x00, 0x94, 0x00, 0x94, 0x00, 0x94, 0x00, 0x94, 0x00, + 0x94, 0x00, 0x94, 0x00, 0x94, 0x00, 0x94, 0x00, 0x94, 0x00, 0x94, 0x00, 0x94, 0x00, 0x94, 0x00, + 0x94, 0x00, 0x94, 0x00, 0x94, 0x00, 0x74, 0x01, 0x75, 0x01, 0x94, 0x00, 0x94, 0x00, 0x94, 0x00, + 0x94, 0x00, 0x94, 0x00, 0x94, 0x00, 0x94, 0x00, 0x94, 0x00, 0x94, 0x00, 0x94, 0x00, 0x94, 0x00, + 0x94, 0x00, 0x94, 0x00, 0x94, 0x00, 0x94, 0x00, 0x94, 0x00, 0x02, 0x00, 0x02, 0x00, 0x02, 0x00, + 0x94, 0x00, 0x94, 0x00, 0x94, 0x00, 0x94, 0x00, 0x94, 0x00, 0x94, 0x00, 0x94, 0x00, 0x94, 0x00, + 0x02, 0x00, 0x02, 0x00, 0x02, 0x00, 0x02, 0x00, 0x02, 0x00, 0x02, 0x00, 0x02, 0x00, 0x76, 0x01, + 0x02, 0x00, 0x02, 0x00, 0x02, 0x00, 0x02, 0x00, 0x02, 0x00, 0x77, 0x01, 0x94, 0x00, 0x94, 0x00, + 0x69, 0x01, 0x02, 0x00, 0x02, 0x00, 0x02, 0x00, 0x78, 0x01, 0x79, 0x01, 0x02, 0x00, 0x02, 0x00, + 0x78, 0x01, 0x02, 0x00, 0x7a, 0x01, 0x94, 0x00, 0x94, 0x00, 0x94, 0x00, 0x94, 0x00, 0x94, 0x00, + 0x69, 0x01, 0x94, 0x00, 0x94, 0x00, 0x7b, 0x01, 0x92, 0x00, 0x94, 0x00, 0x94, 0x00, 0x94, 0x00, + 0x94, 0x00, 0x94, 0x00, 0x94, 0x00, 0x94, 0x00, 0x94, 0x00, 0x94, 0x00, 0x94, 0x00, 0x94, 0x00, + 0x94, 0x00, 0x94, 0x00, 0x94, 0x00, 0x94, 0x00, 0x94, 0x00, 0x94, 0x00, 0x94, 0x00, 0x94, 0x00, + 0x94, 0x00, 0x94, 0x00, 0x94, 0x00, 0x94, 0x00, 0x94, 0x00, 0x94, 0x00, 0x94, 0x00, 0x94, 0x00, 0x02, 0x00, 0x02, 0x00, 0x02, 0x00, 0x02, 0x00, 0x02, 0x00, 0x02, 0x00, 0x02, 0x00, 0x02, 0x00, - 0x02, 0x00, 0x79, 0x01, 0x02, 0x00, 0x02, 0x00, 0x02, 0x00, 0x02, 0x00, 0x02, 0x00, 0x02, 0x00, + 0x02, 0x00, 0x02, 0x00, 0x02, 0x00, 0x02, 0x00, 0x02, 0x00, 0x02, 0x00, 0x02, 0x00, 0x03, 0x00, + 0x94, 0x00, 0x94, 0x00, 0x94, 0x00, 0x94, 0x00, 0x94, 0x00, 0x94, 0x00, 0x94, 0x00, 0x94, 0x00, + 0x94, 0x00, 0x94, 0x00, 0x94, 0x00, 0x94, 0x00, 0x94, 0x00, 0x94, 0x00, 0x94, 0x00, 0x94, 0x00, + 0x94, 0x00, 0x94, 0x00, 0x94, 0x00, 0x94, 0x00, 0x94, 0x00, 0x94, 0x00, 0x94, 0x00, 0x94, 0x00, + 0x94, 0x00, 0x94, 0x00, 0x94, 0x00, 0x94, 0x00, 0x94, 0x00, 0x94, 0x00, 0x94, 0x00, 0x94, 0x00, + 0x94, 0x00, 0x94, 0x00, 0x94, 0x00, 0x94, 0x00, 0x94, 0x00, 0x94, 0x00, 0x94, 0x00, 0x94, 0x00, + 0x94, 0x00, 0x94, 0x00, 0x94, 0x00, 0x94, 0x00, 0x94, 0x00, 0x94, 0x00, 0x94, 0x00, 0x94, 0x00, + 0x94, 0x00, 0x94, 0x00, 0x94, 0x00, 0x94, 0x00, 0x94, 0x00, 0x94, 0x00, 0x94, 0x00, 0x94, 0x00, + 0x94, 0x00, 0x94, 0x00, 0x94, 0x00, 0x94, 0x00, 0x94, 0x00, 0x94, 0x00, 0x94, 0x00, 0x74, 0x01, + 0x02, 0x00, 0x02, 0x00, 0x02, 0x00, 0x02, 0x00, 0x02, 0x00, 0x02, 0x00, 0x02, 0x00, 0x02, 0x00, + 0x02, 0x00, 0x7c, 0x01, 0x02, 0x00, 0x02, 0x00, 0x02, 0x00, 0x02, 0x00, 0x02, 0x00, 0x02, 0x00, 0x02, 0x00, 0x02, 0x00, 0x02, 0x00, 0x02, 0x00, 0x02, 0x00, 0x02, 0x00, 0x02, 0x00, 0x02, 0x00, 0x02, 0x00, 0x02, 0x00, 0x02, 0x00, 0x02, 0x00, 0x02, 0x00, 0x02, 0x00, 0x02, 0x00, 0x02, 0x00, 0x01, 0x00, 0x01, 0x00, 0x07, 0x00, 0x07, 0x00, 0x07, 0x00, 0x07, 0x00, 0x07, 0x00, 0x07, 0x00, @@ -1714,7 +1731,7 @@ namespace System.Globalization 0x01, 0x00, 0x01, 0x00, 0x01, 0x00, 0x01, 0x00, 0x01, 0x00, 0x01, 0x00, 0x01, 0x00, 0x01, 0x00 }; - private static ReadOnlySpan NumericGraphemeLevel3Index => new byte[6048] + private static ReadOnlySpan NumericGraphemeLevel3Index => new byte[6096] { 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x01, 0x00, 0x00, 0x02, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, @@ -1762,7 +1779,7 @@ namespace System.Globalization 0x17, 0x15, 0x15, 0x15, 0x15, 0x15, 0x03, 0x15, 0x15, 0x17, 0x03, 0x17, 0x17, 0x15, 0x03, 0x03, 0x03, 0x03, 0x03, 0x03, 0x03, 0x03, 0x03, 0x03, 0x03, 0x03, 0x15, 0x15, 0x15, 0x15, 0x15, 0x15, 0x03, 0x03, 0x03, 0x03, 0x03, 0x03, 0x03, 0x03, 0x03, 0x03, 0x03, 0x03, 0x15, 0x03, 0x15, 0x15, - 0x03, 0x03, 0x03, 0x03, 0x03, 0x03, 0x15, 0x15, 0x03, 0x03, 0x03, 0x03, 0x03, 0x03, 0x03, 0x03, + 0x03, 0x03, 0x03, 0x03, 0x03, 0x15, 0x15, 0x15, 0x03, 0x03, 0x03, 0x03, 0x03, 0x03, 0x03, 0x03, 0x03, 0x03, 0x12, 0x13, 0x14, 0x18, 0x19, 0x1a, 0x03, 0x03, 0x03, 0x03, 0x03, 0x03, 0x03, 0x03, 0x03, 0x03, 0x15, 0x03, 0x03, 0x03, 0x03, 0x03, 0x03, 0x03, 0x03, 0x03, 0x03, 0x03, 0x03, 0x03, 0x03, 0x03, 0x03, 0x03, 0x03, 0x03, 0x03, 0x03, 0x03, 0x03, 0x03, 0x03, 0x03, 0x03, 0x15, 0x17, @@ -1780,9 +1797,9 @@ namespace System.Globalization 0x17, 0x15, 0x15, 0x15, 0x15, 0x03, 0x17, 0x17, 0x17, 0x03, 0x17, 0x17, 0x17, 0x15, 0x16, 0x03, 0x03, 0x03, 0x03, 0x03, 0x03, 0x03, 0x03, 0x15, 0x23, 0x24, 0x25, 0x26, 0x27, 0x28, 0x29, 0x03, 0x1c, 0x1d, 0x1e, 0x12, 0x13, 0x14, 0x18, 0x19, 0x1a, 0x03, 0x03, 0x03, 0x03, 0x03, 0x03, 0x03, - 0x03, 0x03, 0x17, 0x17, 0x03, 0x03, 0x03, 0x03, 0x03, 0x03, 0x03, 0x03, 0x03, 0x03, 0x03, 0x03, 0x03, 0x03, 0x03, 0x03, 0x03, 0x03, 0x03, 0x03, 0x03, 0x03, 0x15, 0x03, 0x03, 0x03, 0x03, 0x15, 0x17, 0x17, 0x15, 0x15, 0x15, 0x03, 0x15, 0x03, 0x17, 0x17, 0x17, 0x17, 0x17, 0x17, 0x17, 0x15, + 0x03, 0x03, 0x17, 0x17, 0x03, 0x03, 0x03, 0x03, 0x03, 0x03, 0x03, 0x03, 0x03, 0x03, 0x03, 0x03, 0x03, 0x15, 0x03, 0x17, 0x15, 0x15, 0x15, 0x15, 0x15, 0x15, 0x15, 0x03, 0x03, 0x03, 0x03, 0x03, 0x03, 0x03, 0x03, 0x03, 0x03, 0x03, 0x03, 0x15, 0x15, 0x15, 0x15, 0x15, 0x15, 0x15, 0x15, 0x03, 0x03, 0x15, 0x03, 0x17, 0x15, 0x15, 0x15, 0x15, 0x15, 0x15, 0x15, 0x15, 0x15, 0x03, 0x03, 0x03, @@ -1823,7 +1840,6 @@ namespace System.Globalization 0x03, 0x03, 0x03, 0x03, 0x03, 0x17, 0x15, 0x17, 0x15, 0x15, 0x15, 0x15, 0x15, 0x15, 0x15, 0x03, 0x15, 0x03, 0x15, 0x03, 0x03, 0x15, 0x15, 0x15, 0x15, 0x15, 0x15, 0x15, 0x15, 0x17, 0x17, 0x17, 0x17, 0x17, 0x17, 0x15, 0x15, 0x15, 0x15, 0x15, 0x15, 0x15, 0x15, 0x15, 0x15, 0x03, 0x03, 0x15, - 0x15, 0x15, 0x15, 0x15, 0x15, 0x15, 0x15, 0x15, 0x15, 0x15, 0x15, 0x15, 0x15, 0x15, 0x15, 0x03, 0x15, 0x15, 0x15, 0x15, 0x17, 0x03, 0x03, 0x03, 0x03, 0x03, 0x03, 0x03, 0x03, 0x03, 0x03, 0x03, 0x03, 0x03, 0x03, 0x03, 0x15, 0x15, 0x15, 0x15, 0x15, 0x15, 0x15, 0x17, 0x15, 0x17, 0x17, 0x17, 0x17, 0x17, 0x15, 0x17, 0x17, 0x03, 0x03, 0x03, 0x03, 0x03, 0x03, 0x03, 0x03, 0x03, 0x03, 0x03, @@ -1899,7 +1915,7 @@ namespace System.Globalization 0x03, 0x03, 0x03, 0x03, 0x03, 0x03, 0x20, 0x21, 0x22, 0x48, 0x49, 0x4a, 0x4b, 0x4c, 0x4d, 0x1f, 0x15, 0x15, 0x03, 0x03, 0x03, 0x03, 0x03, 0x03, 0x03, 0x03, 0x03, 0x03, 0x03, 0x03, 0x03, 0x03, 0x03, 0x03, 0x15, 0x03, 0x03, 0x03, 0x15, 0x03, 0x03, 0x03, 0x03, 0x15, 0x03, 0x03, 0x03, 0x03, - 0x03, 0x03, 0x03, 0x17, 0x17, 0x15, 0x15, 0x17, 0x03, 0x03, 0x03, 0x03, 0x03, 0x03, 0x03, 0x03, + 0x03, 0x03, 0x03, 0x17, 0x17, 0x15, 0x15, 0x17, 0x03, 0x03, 0x03, 0x03, 0x15, 0x03, 0x03, 0x03, 0x12, 0x13, 0x14, 0x18, 0x19, 0x1a, 0x03, 0x03, 0x03, 0x03, 0x03, 0x03, 0x03, 0x03, 0x03, 0x03, 0x17, 0x17, 0x03, 0x03, 0x03, 0x03, 0x03, 0x03, 0x03, 0x03, 0x03, 0x03, 0x03, 0x03, 0x03, 0x03, 0x03, 0x03, 0x03, 0x03, 0x17, 0x17, 0x17, 0x17, 0x17, 0x17, 0x17, 0x17, 0x17, 0x17, 0x17, 0x17, @@ -1972,9 +1988,11 @@ namespace System.Globalization 0x03, 0x03, 0x03, 0x03, 0x15, 0x15, 0x15, 0x15, 0x03, 0x03, 0x03, 0x03, 0x03, 0x03, 0x03, 0x03, 0x11, 0x0f, 0x10, 0x36, 0x37, 0x38, 0x39, 0x3a, 0x3b, 0x1c, 0x3c, 0x3d, 0x3e, 0x3f, 0x40, 0x41, 0x42, 0x43, 0x1d, 0x82, 0x83, 0x84, 0x5e, 0x85, 0x86, 0x87, 0x88, 0x13, 0x12, 0x52, 0x53, 0x03, + 0x03, 0x03, 0x03, 0x03, 0x03, 0x03, 0x03, 0x03, 0x03, 0x03, 0x03, 0x15, 0x15, 0x03, 0x03, 0x03, 0x03, 0x03, 0x03, 0x03, 0x03, 0x03, 0x03, 0x03, 0x03, 0x03, 0x03, 0x03, 0x03, 0x20, 0x21, 0x22, 0x48, 0x49, 0x1c, 0x3c, 0x3d, 0x1d, 0x13, 0x03, 0x03, 0x03, 0x03, 0x03, 0x03, 0x03, 0x03, 0x03, 0x15, 0x20, 0x1c, 0x3c, 0x1d, 0x03, 0x03, 0x03, 0x03, 0x03, 0x03, 0x03, 0x03, 0x03, 0x03, 0x03, + 0x03, 0x03, 0x03, 0x03, 0x03, 0x20, 0x21, 0x22, 0x48, 0x1c, 0x3c, 0x1d, 0x03, 0x03, 0x03, 0x03, 0x17, 0x15, 0x17, 0x03, 0x03, 0x03, 0x03, 0x03, 0x03, 0x03, 0x03, 0x03, 0x03, 0x03, 0x03, 0x03, 0x03, 0x03, 0x03, 0x03, 0x03, 0x03, 0x03, 0x03, 0x15, 0x15, 0x15, 0x15, 0x15, 0x15, 0x15, 0x15, 0x15, 0x15, 0x15, 0x15, 0x15, 0x15, 0x15, 0x03, 0x03, 0x03, 0x03, 0x03, 0x03, 0x03, 0x03, 0x03, @@ -1988,7 +2006,7 @@ namespace System.Globalization 0x03, 0x03, 0x03, 0x03, 0x03, 0x17, 0x17, 0x03, 0x03, 0x03, 0x03, 0x03, 0x03, 0x03, 0x03, 0x03, 0x03, 0x03, 0x03, 0x15, 0x03, 0x03, 0x03, 0x03, 0x03, 0x03, 0x03, 0x03, 0x03, 0x03, 0x03, 0x03, 0x03, 0x03, 0x03, 0x17, 0x17, 0x17, 0x15, 0x15, 0x15, 0x15, 0x15, 0x15, 0x15, 0x15, 0x15, 0x17, - 0x17, 0x03, 0x16, 0x16, 0x03, 0x03, 0x03, 0x03, 0x03, 0x15, 0x15, 0x15, 0x15, 0x03, 0x03, 0x03, + 0x17, 0x03, 0x16, 0x16, 0x03, 0x03, 0x03, 0x03, 0x03, 0x15, 0x15, 0x15, 0x15, 0x03, 0x17, 0x15, 0x03, 0x20, 0x21, 0x22, 0x48, 0x49, 0x4a, 0x4b, 0x4c, 0x4d, 0x1c, 0x3c, 0x3d, 0x3e, 0x3f, 0x40, 0x41, 0x42, 0x43, 0x1d, 0x1e, 0x03, 0x03, 0x03, 0x03, 0x03, 0x03, 0x03, 0x03, 0x03, 0x03, 0x03, 0x03, 0x03, 0x03, 0x03, 0x03, 0x03, 0x03, 0x03, 0x03, 0x03, 0x03, 0x03, 0x17, 0x17, 0x17, 0x15, @@ -2012,6 +2030,8 @@ namespace System.Globalization 0x15, 0x15, 0x15, 0x15, 0x15, 0x15, 0x15, 0x15, 0x17, 0x15, 0x15, 0x03, 0x03, 0x03, 0x03, 0x03, 0x04, 0x05, 0x06, 0x07, 0x08, 0x09, 0x0a, 0x0b, 0x0c, 0x0d, 0x1c, 0x3c, 0x3d, 0x3e, 0x3f, 0x40, 0x41, 0x42, 0x43, 0x03, 0x03, 0x03, 0x03, 0x03, 0x03, 0x03, 0x03, 0x03, 0x03, 0x03, 0x03, 0x03, + 0x15, 0x17, 0x17, 0x17, 0x17, 0x17, 0x03, 0x17, 0x17, 0x03, 0x03, 0x15, 0x15, 0x17, 0x15, 0x16, + 0x17, 0x16, 0x17, 0x15, 0x03, 0x03, 0x03, 0x03, 0x03, 0x03, 0x03, 0x03, 0x03, 0x03, 0x03, 0x03, 0x03, 0x17, 0x17, 0x17, 0x15, 0x15, 0x15, 0x15, 0x03, 0x03, 0x15, 0x15, 0x17, 0x17, 0x17, 0x17, 0x15, 0x03, 0x03, 0x03, 0x17, 0x03, 0x03, 0x03, 0x03, 0x03, 0x03, 0x03, 0x03, 0x03, 0x03, 0x03, 0x03, 0x15, 0x15, 0x15, 0x15, 0x15, 0x15, 0x15, 0x15, 0x15, 0x15, 0x03, 0x03, 0x03, 0x03, 0x03, @@ -2048,6 +2068,7 @@ namespace System.Globalization 0x03, 0x17, 0x17, 0x17, 0x17, 0x17, 0x17, 0x17, 0x17, 0x17, 0x17, 0x17, 0x17, 0x17, 0x17, 0x17, 0x17, 0x17, 0x17, 0x17, 0x17, 0x17, 0x17, 0x17, 0x17, 0x17, 0x17, 0x17, 0x17, 0x17, 0x17, 0x17, 0x17, 0x17, 0x17, 0x17, 0x17, 0x17, 0x17, 0x17, 0x03, 0x03, 0x03, 0x03, 0x03, 0x03, 0x03, 0x15, + 0x03, 0x03, 0x03, 0x03, 0x15, 0x03, 0x03, 0x03, 0x03, 0x03, 0x03, 0x03, 0x03, 0x03, 0x03, 0x03, 0x03, 0x03, 0x03, 0x03, 0x03, 0x03, 0x03, 0x03, 0x03, 0x03, 0x03, 0x03, 0x03, 0x15, 0x15, 0x03, 0x00, 0x00, 0x00, 0x00, 0x03, 0x03, 0x03, 0x03, 0x03, 0x03, 0x03, 0x03, 0x03, 0x03, 0x03, 0x03, 0x03, 0x03, 0x03, 0x03, 0x03, 0x15, 0x17, 0x15, 0x15, 0x15, 0x03, 0x03, 0x03, 0x17, 0x15, 0x15, @@ -2061,7 +2082,6 @@ namespace System.Globalization 0x0c, 0x0d, 0x04, 0x05, 0x06, 0x07, 0x08, 0x09, 0x0a, 0x0b, 0x0c, 0x0d, 0x04, 0x05, 0x06, 0x07, 0x08, 0x09, 0x0a, 0x0b, 0x0c, 0x0d, 0x04, 0x05, 0x06, 0x07, 0x08, 0x09, 0x0a, 0x0b, 0x0c, 0x0d, 0x15, 0x15, 0x15, 0x15, 0x15, 0x15, 0x15, 0x03, 0x03, 0x03, 0x03, 0x15, 0x15, 0x15, 0x15, 0x15, - 0x03, 0x03, 0x03, 0x03, 0x15, 0x03, 0x03, 0x03, 0x03, 0x03, 0x03, 0x03, 0x03, 0x03, 0x03, 0x03, 0x15, 0x15, 0x15, 0x15, 0x15, 0x15, 0x15, 0x03, 0x15, 0x15, 0x15, 0x15, 0x15, 0x15, 0x15, 0x15, 0x15, 0x15, 0x15, 0x15, 0x15, 0x15, 0x15, 0x15, 0x15, 0x03, 0x03, 0x15, 0x15, 0x15, 0x15, 0x15, 0x15, 0x15, 0x03, 0x15, 0x15, 0x03, 0x15, 0x15, 0x15, 0x15, 0x15, 0x03, 0x03, 0x03, 0x03, 0x03, diff --git a/src/System.Private.CoreLib/shared/System/Globalization/CompareInfo.Unix.cs b/src/System.Private.CoreLib/shared/System/Globalization/CompareInfo.Icu.cs similarity index 80% rename from src/System.Private.CoreLib/shared/System/Globalization/CompareInfo.Unix.cs rename to src/System.Private.CoreLib/shared/System/Globalization/CompareInfo.Icu.cs index 203441346..3cc636bb6 100644 --- a/src/System.Private.CoreLib/shared/System/Globalization/CompareInfo.Unix.cs +++ b/src/System.Private.CoreLib/shared/System/Globalization/CompareInfo.Icu.cs @@ -5,33 +5,26 @@ using System.Buffers; using System.Collections.Generic; using System.Diagnostics; -using System.Runtime.CompilerServices; using System.Runtime.InteropServices; -using System.Security; -using System.Threading; - -using Internal.Runtime.CompilerServices; +using System.Text; namespace System.Globalization { public partial class CompareInfo { - [NonSerialized] - private IntPtr _sortHandle; - [NonSerialized] private bool _isAsciiEqualityOrdinal; - private void InitSort(CultureInfo culture) + private void IcuInitSortHandle() { - _sortName = culture.SortName; - if (GlobalizationMode.Invariant) { _isAsciiEqualityOrdinal = true; } else { + Debug.Assert(!GlobalizationMode.UseNls); + // Inline the following condition to avoid potential implementation cycles within globalization // // _isAsciiEqualityOrdinal = _sortName == "" || _sortName == "en" || _sortName.StartsWith("en-", StringComparison.Ordinal); @@ -43,64 +36,23 @@ namespace System.Globalization } } - internal static unsafe int IndexOfOrdinalCore(string source, string value, int startIndex, int count, bool ignoreCase) + private static unsafe int IcuIndexOfOrdinalCore(ReadOnlySpan source, ReadOnlySpan value, bool ignoreCase, bool fromBeginning) { Debug.Assert(!GlobalizationMode.Invariant); + Debug.Assert(!GlobalizationMode.UseNls); + Debug.Assert(!value.IsEmpty); - Debug.Assert(source != null); - Debug.Assert(value != null); - - if (value.Length == 0) - { - return startIndex; - } - - if (count < value.Length) - { - return -1; - } - - if (ignoreCase) - { - fixed (char* pSource = source) - { - int index = Interop.Globalization.IndexOfOrdinalIgnoreCase(value, value.Length, pSource + startIndex, count, findLast: false); - return index != -1 ? - startIndex + index : - -1; - } - } - - int endIndex = startIndex + (count - value.Length); - for (int i = startIndex; i <= endIndex; i++) - { - int valueIndex, sourceIndex; - - for (valueIndex = 0, sourceIndex = i; - valueIndex < value.Length && source[sourceIndex] == value[valueIndex]; - valueIndex++, sourceIndex++) ; - - if (valueIndex == value.Length) - { - return i; - } - } - - return -1; - } - - internal static unsafe int IndexOfOrdinalCore(ReadOnlySpan source, ReadOnlySpan value, bool ignoreCase, bool fromBeginning) - { - Debug.Assert(!GlobalizationMode.Invariant); - - Debug.Assert(source.Length != 0); - Debug.Assert(value.Length != 0); + // Ordinal (non-linguistic) comparisons require the length of the target string to be no greater + // than the length of the search space. Since our caller already checked for empty target strings, + // the below check also handles the case of empty search space strings. if (source.Length < value.Length) { return -1; } + Debug.Assert(!source.IsEmpty); + if (ignoreCase) { fixed (char* pSource = &MemoryMarshal.GetReference(source)) @@ -146,9 +98,10 @@ namespace System.Globalization return -1; } - internal static unsafe int LastIndexOfOrdinalCore(string source, string value, int startIndex, int count, bool ignoreCase) + private static unsafe int IcuLastIndexOfOrdinalCore(string source, string value, int startIndex, int count, bool ignoreCase) { Debug.Assert(!GlobalizationMode.Invariant); + Debug.Assert(!GlobalizationMode.UseNls); Debug.Assert(source != null); Debug.Assert(value != null); @@ -195,37 +148,31 @@ namespace System.Globalization return -1; } - private static unsafe int CompareStringOrdinalIgnoreCase(ref char string1, int count1, ref char string2, int count2) + private static unsafe int IcuCompareStringOrdinalIgnoreCase(ref char string1, int count1, ref char string2, int count2) { Debug.Assert(!GlobalizationMode.Invariant); + Debug.Assert(!GlobalizationMode.UseNls); + + Debug.Assert(count1 > 0); + Debug.Assert(count2 > 0); fixed (char* char1 = &string1) fixed (char* char2 = &string2) { + Debug.Assert(char1 != null); + Debug.Assert(char2 != null); return Interop.Globalization.CompareStringOrdinalIgnoreCase(char1, count1, char2, count2); } } - // TODO https://github.com/dotnet/runtime/issues/8890: - // This method shouldn't be necessary, as we should be able to just use the overload - // that takes two spans. But due to this issue, that's adding significant overhead. - private unsafe int CompareString(ReadOnlySpan string1, string string2, CompareOptions options) + private unsafe int IcuCompareString(ReadOnlySpan string1, ReadOnlySpan string2, CompareOptions options) { Debug.Assert(!GlobalizationMode.Invariant); - Debug.Assert(string2 != null); + Debug.Assert(!GlobalizationMode.UseNls); Debug.Assert((options & (CompareOptions.Ordinal | CompareOptions.OrdinalIgnoreCase)) == 0); - fixed (char* pString1 = &MemoryMarshal.GetReference(string1)) - fixed (char* pString2 = &string2.GetRawStringData()) - { - return Interop.Globalization.CompareString(_sortHandle, pString1, string1.Length, pString2, string2.Length, options); - } - } - - private unsafe int CompareString(ReadOnlySpan string1, ReadOnlySpan string2, CompareOptions options) - { - Debug.Assert(!GlobalizationMode.Invariant); - Debug.Assert((options & (CompareOptions.Ordinal | CompareOptions.OrdinalIgnoreCase)) == 0); + // GetReference may return nullptr if the input span is defaulted. The native layer handles + // this appropriately; no workaround is needed on the managed side. fixed (char* pString1 = &MemoryMarshal.GetReference(string1)) fixed (char* pString2 = &MemoryMarshal.GetReference(string2)) @@ -234,41 +181,10 @@ namespace System.Globalization } } - internal unsafe int IndexOfCore(string source, string target, int startIndex, int count, CompareOptions options, int* matchLengthPtr) + private unsafe int IcuIndexOfCore(ReadOnlySpan source, ReadOnlySpan target, CompareOptions options, int* matchLengthPtr, bool fromBeginning) { Debug.Assert(!GlobalizationMode.Invariant); - - Debug.Assert(!string.IsNullOrEmpty(source)); - Debug.Assert(target != null); - Debug.Assert((options & CompareOptions.OrdinalIgnoreCase) == 0); - Debug.Assert((options & CompareOptions.Ordinal) == 0); - - int index; - - if (_isAsciiEqualityOrdinal && CanUseAsciiOrdinalForOptions(options)) - { - if ((options & CompareOptions.IgnoreCase) != 0) - index = IndexOfOrdinalIgnoreCaseHelper(source.AsSpan(startIndex, count), target.AsSpan(), options, matchLengthPtr, fromBeginning: true); - else - index = IndexOfOrdinalHelper(source.AsSpan(startIndex, count), target.AsSpan(), options, matchLengthPtr, fromBeginning: true); - } - else - { - fixed (char* pSource = source) - fixed (char* pTarget = target) - { - index = Interop.Globalization.IndexOf(_sortHandle, pTarget, target.Length, pSource + startIndex, count, options, matchLengthPtr); - } - } - - return index != -1 ? index + startIndex : -1; - } - - // For now, this method is only called from Span APIs with either options == CompareOptions.None or CompareOptions.IgnoreCase - internal unsafe int IndexOfCore(ReadOnlySpan source, ReadOnlySpan target, CompareOptions options, int* matchLengthPtr, bool fromBeginning) - { - Debug.Assert(!GlobalizationMode.Invariant); - Debug.Assert(source.Length != 0); + Debug.Assert(!GlobalizationMode.UseNls); Debug.Assert(target.Length != 0); if (_isAsciiEqualityOrdinal && CanUseAsciiOrdinalForOptions(options)) @@ -280,13 +196,16 @@ namespace System.Globalization } else { + // GetReference may return nullptr if the input span is defaulted. The native layer handles + // this appropriately; no workaround is needed on the managed side. + fixed (char* pSource = &MemoryMarshal.GetReference(source)) fixed (char* pTarget = &MemoryMarshal.GetReference(target)) { if (fromBeginning) return Interop.Globalization.IndexOf(_sortHandle, pTarget, target.Length, pSource, source.Length, options, matchLengthPtr); else - return Interop.Globalization.LastIndexOf(_sortHandle, pTarget, target.Length, pSource, source.Length, options); + return Interop.Globalization.LastIndexOf(_sortHandle, pTarget, target.Length, pSource, source.Length, options, matchLengthPtr); } } } @@ -396,7 +315,7 @@ namespace System.Globalization if (fromBeginning) return Interop.Globalization.IndexOf(_sortHandle, b, target.Length, a, source.Length, options, matchLengthPtr); else - return Interop.Globalization.LastIndexOf(_sortHandle, b, target.Length, a, source.Length, options); + return Interop.Globalization.LastIndexOf(_sortHandle, b, target.Length, a, source.Length, options, matchLengthPtr); } } @@ -489,58 +408,15 @@ namespace System.Globalization if (fromBeginning) return Interop.Globalization.IndexOf(_sortHandle, b, target.Length, a, source.Length, options, matchLengthPtr); else - return Interop.Globalization.LastIndexOf(_sortHandle, b, target.Length, a, source.Length, options); + return Interop.Globalization.LastIndexOf(_sortHandle, b, target.Length, a, source.Length, options, matchLengthPtr); } } - private unsafe int LastIndexOfCore(string source, string target, int startIndex, int count, CompareOptions options) + private unsafe bool IcuStartsWith(ReadOnlySpan source, ReadOnlySpan prefix, CompareOptions options) { Debug.Assert(!GlobalizationMode.Invariant); + Debug.Assert(!GlobalizationMode.UseNls); - Debug.Assert(!string.IsNullOrEmpty(source)); - Debug.Assert(target != null); - Debug.Assert((options & CompareOptions.OrdinalIgnoreCase) == 0); - - if (target.Length == 0) - { - return startIndex; - } - - if (options == CompareOptions.Ordinal) - { - return LastIndexOfOrdinalCore(source, target, startIndex, count, ignoreCase: false); - } - - // startIndex is the index into source where we start search backwards from. leftStartIndex is the index into source - // of the start of the string that is count characters away from startIndex. - int leftStartIndex = (startIndex - count + 1); - - int lastIndex; - - if (_isAsciiEqualityOrdinal && CanUseAsciiOrdinalForOptions(options)) - { - if ((options & CompareOptions.IgnoreCase) != 0) - lastIndex = IndexOfOrdinalIgnoreCaseHelper(source.AsSpan(leftStartIndex, count), target.AsSpan(), options, matchLengthPtr: null, fromBeginning: false); - else - lastIndex = IndexOfOrdinalHelper(source.AsSpan(leftStartIndex, count), target.AsSpan(), options, matchLengthPtr: null, fromBeginning: false); - } - else - { - fixed (char* pSource = source) - fixed (char* pTarget = target) - { - lastIndex = Interop.Globalization.LastIndexOf(_sortHandle, pTarget, target.Length, pSource + (startIndex - count + 1), count, options); - } - } - - return lastIndex != -1 ? lastIndex + leftStartIndex : -1; - } - - private unsafe bool StartsWith(ReadOnlySpan source, ReadOnlySpan prefix, CompareOptions options) - { - Debug.Assert(!GlobalizationMode.Invariant); - - Debug.Assert(!source.IsEmpty); Debug.Assert(!prefix.IsEmpty); Debug.Assert((options & (CompareOptions.Ordinal | CompareOptions.OrdinalIgnoreCase)) == 0); @@ -553,7 +429,7 @@ namespace System.Globalization } else { - fixed (char* pSource = &MemoryMarshal.GetReference(source)) + fixed (char* pSource = &MemoryMarshal.GetReference(source)) // could be null (or otherwise unable to be dereferenced) fixed (char* pPrefix = &MemoryMarshal.GetReference(prefix)) { return Interop.Globalization.StartsWith(_sortHandle, pPrefix, prefix.Length, pSource, source.Length, options); @@ -565,13 +441,12 @@ namespace System.Globalization { Debug.Assert(!GlobalizationMode.Invariant); - Debug.Assert(!source.IsEmpty); Debug.Assert(!prefix.IsEmpty); Debug.Assert(_isAsciiEqualityOrdinal); int length = Math.Min(source.Length, prefix.Length); - fixed (char* ap = &MemoryMarshal.GetReference(source)) + fixed (char* ap = &MemoryMarshal.GetReference(source)) // could be null (or otherwise unable to be dereferenced) fixed (char* bp = &MemoryMarshal.GetReference(prefix)) { char* a = ap; @@ -636,13 +511,12 @@ namespace System.Globalization { Debug.Assert(!GlobalizationMode.Invariant); - Debug.Assert(!source.IsEmpty); Debug.Assert(!prefix.IsEmpty); Debug.Assert(_isAsciiEqualityOrdinal); int length = Math.Min(source.Length, prefix.Length); - fixed (char* ap = &MemoryMarshal.GetReference(source)) + fixed (char* ap = &MemoryMarshal.GetReference(source)) // could be null (or otherwise unable to be dereferenced) fixed (char* bp = &MemoryMarshal.GetReference(prefix)) { char* a = ap; @@ -692,11 +566,11 @@ namespace System.Globalization } } - private unsafe bool EndsWith(ReadOnlySpan source, ReadOnlySpan suffix, CompareOptions options) + private unsafe bool IcuEndsWith(ReadOnlySpan source, ReadOnlySpan suffix, CompareOptions options) { Debug.Assert(!GlobalizationMode.Invariant); + Debug.Assert(!GlobalizationMode.UseNls); - Debug.Assert(!source.IsEmpty); Debug.Assert(!suffix.IsEmpty); Debug.Assert((options & (CompareOptions.Ordinal | CompareOptions.OrdinalIgnoreCase)) == 0); @@ -709,7 +583,7 @@ namespace System.Globalization } else { - fixed (char* pSource = &MemoryMarshal.GetReference(source)) + fixed (char* pSource = &MemoryMarshal.GetReference(source)) // could be null (or otherwise unable to be dereferenced) fixed (char* pSuffix = &MemoryMarshal.GetReference(suffix)) { return Interop.Globalization.EndsWith(_sortHandle, pSuffix, suffix.Length, pSource, source.Length, options); @@ -721,13 +595,12 @@ namespace System.Globalization { Debug.Assert(!GlobalizationMode.Invariant); - Debug.Assert(!source.IsEmpty); Debug.Assert(!suffix.IsEmpty); Debug.Assert(_isAsciiEqualityOrdinal); int length = Math.Min(source.Length, suffix.Length); - fixed (char* ap = &MemoryMarshal.GetReference(source)) + fixed (char* ap = &MemoryMarshal.GetReference(source)) // could be null (or otherwise unable to be dereferenced) fixed (char* bp = &MemoryMarshal.GetReference(suffix)) { char* a = ap + source.Length - 1; @@ -759,10 +632,29 @@ namespace System.Globalization continue; } + // The match may be affected by special character. Verify that the preceding character is regular ASCII. + if (a > ap && *(a - 1) >= 0x80) + goto InteropCall; + if (b > bp && *(b - 1) >= 0x80) + goto InteropCall; return false; } - return (source.Length >= suffix.Length); + // The match may be affected by special character. Verify that the preceding character is regular ASCII. + + if (source.Length < suffix.Length) + { + if (*b >= 0x80) + goto InteropCall; + return false; + } + + if (source.Length > suffix.Length) + { + if (*a >= 0x80) + goto InteropCall; + } + return true; InteropCall: return Interop.Globalization.EndsWith(_sortHandle, bp, suffix.Length, ap, source.Length, options); @@ -773,13 +665,12 @@ namespace System.Globalization { Debug.Assert(!GlobalizationMode.Invariant); - Debug.Assert(!source.IsEmpty); Debug.Assert(!suffix.IsEmpty); Debug.Assert(_isAsciiEqualityOrdinal); int length = Math.Min(source.Length, suffix.Length); - fixed (char* ap = &MemoryMarshal.GetReference(source)) + fixed (char* ap = &MemoryMarshal.GetReference(source)) // could be null (or otherwise unable to be dereferenced) fixed (char* bp = &MemoryMarshal.GetReference(suffix)) { char* a = ap + source.Length - 1; @@ -800,19 +691,39 @@ namespace System.Globalization continue; } + // The match may be affected by special character. Verify that the preceding character is regular ASCII. + if (a > ap && *(a - 1) >= 0x80) + goto InteropCall; + if (b > bp && *(b - 1) >= 0x80) + goto InteropCall; return false; } - return (source.Length >= suffix.Length); + // The match may be affected by special character. Verify that the preceding character is regular ASCII. + + if (source.Length < suffix.Length) + { + if (*b >= 0x80) + goto InteropCall; + return false; + } + + if (source.Length > suffix.Length) + { + if (*a >= 0x80) + goto InteropCall; + } + return true; InteropCall: return Interop.Globalization.EndsWith(_sortHandle, bp, suffix.Length, ap, source.Length, options); } } - private unsafe SortKey CreateSortKey(string source, CompareOptions options) + private unsafe SortKey IcuCreateSortKey(string source, CompareOptions options) { Debug.Assert(!GlobalizationMode.Invariant); + Debug.Assert(!GlobalizationMode.UseNls); if (source==null) { throw new ArgumentNullException(nameof(source)); } @@ -836,55 +747,89 @@ namespace System.Globalization } } - return new SortKey(Name, source, options, keyData); + return new SortKey(this, source, options, keyData); } - private static unsafe bool IsSortable(char *text, int length) + private unsafe int IcuGetSortKey(ReadOnlySpan source, Span destination, CompareOptions options) { Debug.Assert(!GlobalizationMode.Invariant); + Debug.Assert(!GlobalizationMode.UseNls); + Debug.Assert((options & ValidCompareMaskOffFlags) == 0); - int index = 0; - UnicodeCategory uc; + // It's ok to pass nullptr (for empty buffers) to ICU's sort key routines. - while (index < length) + int actualSortKeyLength; + + fixed (char* pSource = &MemoryMarshal.GetReference(source)) + fixed (byte* pDest = &MemoryMarshal.GetReference(destination)) { - if (char.IsHighSurrogate(text[index])) - { - if (index == length - 1 || !char.IsLowSurrogate(text[index+1])) - return false; // unpaired surrogate - - uc = CharUnicodeInfo.GetUnicodeCategory(char.ConvertToUtf32(text[index], text[index+1])); - if (uc == UnicodeCategory.PrivateUse || uc == UnicodeCategory.OtherNotAssigned) - return false; - - index += 2; - continue; - } - - if (char.IsLowSurrogate(text[index])) - { - return false; // unpaired surrogate - } - - uc = CharUnicodeInfo.GetUnicodeCategory(text[index]); - if (uc == UnicodeCategory.PrivateUse || uc == UnicodeCategory.OtherNotAssigned) - { - return false; - } - - index++; + actualSortKeyLength = Interop.Globalization.GetSortKey(_sortHandle, pSource, source.Length, pDest, destination.Length, options); } - return true; + // The check below also handles errors due to negative values / overflow being returned. + + if ((uint)actualSortKeyLength > (uint)destination.Length) + { + if (actualSortKeyLength > destination.Length) + { + ThrowHelper.ThrowArgumentException_DestinationTooShort(); + } + else + { + throw new ArgumentException(SR.Arg_ExternalException); + } + } + + return actualSortKeyLength; + } + + private unsafe int IcuGetSortKeyLength(ReadOnlySpan source, CompareOptions options) + { + Debug.Assert(!GlobalizationMode.Invariant); + Debug.Assert(!GlobalizationMode.UseNls); + Debug.Assert((options & ValidCompareMaskOffFlags) == 0); + + // It's ok to pass nullptr (for empty buffers) to ICU's sort key routines. + + fixed (char* pSource = &MemoryMarshal.GetReference(source)) + { + return Interop.Globalization.GetSortKey(_sortHandle, pSource, source.Length, null, 0, options); + } + } + + private static bool IcuIsSortable(ReadOnlySpan text) + { + Debug.Assert(!GlobalizationMode.Invariant); + Debug.Assert(!GlobalizationMode.UseNls); + Debug.Assert(!text.IsEmpty); + + do + { + if (Rune.DecodeFromUtf16(text, out Rune result, out int charsConsumed) != OperationStatus.Done) + { + return false; // found an unpaired surrogate somewhere in the text + } + + UnicodeCategory category = Rune.GetUnicodeCategory(result); + if (category == UnicodeCategory.PrivateUse || category == UnicodeCategory.OtherNotAssigned) + { + return false; // can't sort private use or unassigned code points + } + + text = text.Slice(charsConsumed); + } while (!text.IsEmpty); + + return true; // saw no unsortable data in the buffer } // ----------------------------- // ---- PAL layer ends here ---- // ----------------------------- - internal unsafe int GetHashCodeOfStringCore(ReadOnlySpan source, CompareOptions options) + private unsafe int IcuGetHashCodeOfString(ReadOnlySpan source, CompareOptions options) { Debug.Assert(!GlobalizationMode.Invariant); + Debug.Assert(!GlobalizationMode.UseNls); Debug.Assert((options & (CompareOptions.Ordinal | CompareOptions.OrdinalIgnoreCase)) == 0); // according to ICU User Guide the performance of ucol_getSortKey is worse when it is called with null output buffer @@ -953,9 +898,10 @@ namespace System.Globalization return (options & CompareOptions.IgnoreSymbols) == 0; } - private SortVersion GetSortVersion() + private SortVersion IcuGetSortVersion() { Debug.Assert(!GlobalizationMode.Invariant); + Debug.Assert(!GlobalizationMode.UseNls); int sortVersion = Interop.Globalization.GetSortVersion(_sortHandle); return new SortVersion(sortVersion, LCID, new Guid(sortVersion, 0, 0, 0, 0, 0, 0, diff --git a/src/System.Private.CoreLib/shared/System/Globalization/CompareInfo.Invariant.cs b/src/System.Private.CoreLib/shared/System/Globalization/CompareInfo.Invariant.cs index 4b65d5fcb..9904655ce 100644 --- a/src/System.Private.CoreLib/shared/System/Globalization/CompareInfo.Invariant.cs +++ b/src/System.Private.CoreLib/shared/System/Globalization/CompareInfo.Invariant.cs @@ -40,9 +40,9 @@ namespace System.Globalization } } - internal static unsafe int InvariantLastIndexOf(string source, string value, int startIndex, int count, bool ignoreCase) + private static unsafe int InvariantLastIndexOf(string source, string value, int startIndex, int count, bool ignoreCase) { - Debug.Assert(source != null); + Debug.Assert(!string.IsNullOrEmpty(source)); Debug.Assert(value != null); Debug.Assert(startIndex >= 0 && startIndex < source.Length); @@ -73,7 +73,7 @@ namespace System.Globalization if (valueCount == 0) { - return fromBeginning ? 0 : sourceCount - 1; + return fromBeginning ? 0 : sourceCount; } if (sourceCount < valueCount) @@ -243,7 +243,7 @@ namespace System.Globalization } } - return new SortKey(Name, source, options, keyData); + return new SortKey(this, source, options, keyData); } private static void InvariantCreateSortKeyOrdinal(ReadOnlySpan source, Span sortKey) @@ -269,5 +269,52 @@ namespace System.Globalization sortKey = sortKey.Slice(sizeof(ushort)); } } + + private int InvariantGetSortKey(ReadOnlySpan source, Span destination, CompareOptions options) + { + Debug.Assert(GlobalizationMode.Invariant); + Debug.Assert((options & ValidCompareMaskOffFlags) == 0); + + // Make sure the destination buffer is large enough to hold the source projection. + // Using unsigned arithmetic below also checks for buffer overflow since the incoming + // length is always a non-negative signed integer. + + if ((uint)destination.Length < (uint)source.Length * sizeof(char)) + { + ThrowHelper.ThrowArgumentException_DestinationTooShort(); + } + + if ((options & CompareOptions.IgnoreCase) == 0) + { + InvariantCreateSortKeyOrdinal(source, destination); + } + else + { + InvariantCreateSortKeyOrdinalIgnoreCase(source, destination); + } + + return source.Length * sizeof(char); + } + + private int InvariantGetSortKeyLength(ReadOnlySpan source, CompareOptions options) + { + Debug.Assert(GlobalizationMode.Invariant); + Debug.Assert((options & ValidCompareMaskOffFlags) == 0); + + // In invariant mode, sort keys are simply a byte projection of the source input, + // optionally with casing modifications. We need to make sure we don't overflow + // while computing the length. + + int byteLength = source.Length * sizeof(char); + + if (byteLength < 0) + { + throw new ArgumentException( + paramName: nameof(source), + message: SR.ArgumentOutOfRange_GetByteCountOverflow); + } + + return byteLength; + } } } diff --git a/src/System.Private.CoreLib/shared/System/Globalization/CompareInfo.Windows.cs b/src/System.Private.CoreLib/shared/System/Globalization/CompareInfo.Nls.cs similarity index 58% rename from src/System.Private.CoreLib/shared/System/Globalization/CompareInfo.Windows.cs rename to src/System.Private.CoreLib/shared/System/Globalization/CompareInfo.Nls.cs index 2c72c79a4..2d96f963b 100644 --- a/src/System.Private.CoreLib/shared/System/Globalization/CompareInfo.Windows.cs +++ b/src/System.Private.CoreLib/shared/System/Globalization/CompareInfo.Nls.cs @@ -10,7 +10,13 @@ namespace System.Globalization { public partial class CompareInfo { - internal static unsafe IntPtr GetSortHandle(string cultureName) + private void NlsInitSortHandle() + { + Debug.Assert(GlobalizationMode.UseNls); + _sortHandle = NlsGetSortHandle(_sortName); + } + + internal static unsafe IntPtr NlsGetSortHandle(string cultureName) { if (GlobalizationMode.Invariant) { @@ -36,39 +42,6 @@ namespace System.Globalization return IntPtr.Zero; } - private void InitSort(CultureInfo culture) - { - _sortName = culture.SortName; - _sortHandle = GetSortHandle(_sortName); - } - - private static unsafe int FindStringOrdinal( - uint dwFindStringOrdinalFlags, - string stringSource, - int offset, - int cchSource, - string value, - int cchValue, - bool bIgnoreCase) - { - Debug.Assert(!GlobalizationMode.Invariant); - Debug.Assert(stringSource != null); - Debug.Assert(value != null); - - fixed (char* pSource = stringSource) - fixed (char* pValue = value) - { - int ret = Interop.Kernel32.FindStringOrdinal( - dwFindStringOrdinalFlags, - pSource + offset, - cchSource, - pValue, - cchValue, - bIgnoreCase ? 1 : 0); - return ret < 0 ? ret : ret + offset; - } - } - private static unsafe int FindStringOrdinal( uint dwFindStringOrdinalFlags, ReadOnlySpan source, @@ -82,30 +55,30 @@ namespace System.Globalization fixed (char* pSource = &MemoryMarshal.GetReference(source)) fixed (char* pValue = &MemoryMarshal.GetReference(value)) { + Debug.Assert(pSource != null); + Debug.Assert(pValue != null); + int ret = Interop.Kernel32.FindStringOrdinal( dwFindStringOrdinalFlags, pSource, source.Length, pValue, value.Length, - bIgnoreCase ? 1 : 0); + bIgnoreCase ? Interop.BOOL.TRUE : Interop.BOOL.FALSE); + + Debug.Assert(ret >= -1 && ret <= source.Length); + + // SetLastError is only performed under debug builds. + Debug.Assert(ret >= 0 || Marshal.GetLastWin32Error() == Interop.Errors.ERROR_SUCCESS); + return ret; } } - internal static int IndexOfOrdinalCore(string source, string value, int startIndex, int count, bool ignoreCase) - { - Debug.Assert(!GlobalizationMode.Invariant); - - Debug.Assert(source != null); - Debug.Assert(value != null); - - return FindStringOrdinal(FIND_FROMSTART, source, startIndex, count, value, value.Length, ignoreCase); - } - - internal static int IndexOfOrdinalCore(ReadOnlySpan source, ReadOnlySpan value, bool ignoreCase, bool fromBeginning) + private static int NlsIndexOfOrdinalCore(ReadOnlySpan source, ReadOnlySpan value, bool ignoreCase, bool fromBeginning) { Debug.Assert(!GlobalizationMode.Invariant); + Debug.Assert(GlobalizationMode.UseNls); Debug.Assert(source.Length != 0); Debug.Assert(value.Length != 0); @@ -114,21 +87,42 @@ namespace System.Globalization return FindStringOrdinal(positionFlag, source, value, ignoreCase); } - internal static int LastIndexOfOrdinalCore(string source, string value, int startIndex, int count, bool ignoreCase) + private static int NlsLastIndexOfOrdinalCore(string source, string value, int startIndex, int count, bool ignoreCase) { Debug.Assert(!GlobalizationMode.Invariant); + Debug.Assert(GlobalizationMode.UseNls); Debug.Assert(source != null); Debug.Assert(value != null); - return FindStringOrdinal(FIND_FROMEND, source, startIndex - count + 1, count, value, value.Length, ignoreCase); + int offset = startIndex - count + 1; + int result = FindStringOrdinal(FIND_FROMEND, source.AsSpan(offset, count), value, ignoreCase); + if (result >= 0) + { + result += offset; + } + return result; } - private unsafe int GetHashCodeOfStringCore(ReadOnlySpan source, CompareOptions options) + private unsafe int NlsGetHashCodeOfString(ReadOnlySpan source, CompareOptions options) { Debug.Assert(!GlobalizationMode.Invariant); + Debug.Assert(GlobalizationMode.UseNls); Debug.Assert((options & (CompareOptions.Ordinal | CompareOptions.OrdinalIgnoreCase)) == 0); +#if TARGET_WINDOWS + if (!Environment.IsWindows8OrAbove) + { + // On Windows 7 / Server 2008, LCMapStringEx exhibits strange behaviors if the destination + // buffer is both non-null and too small for the required output. To prevent this from + // causing issues for us, we need to make an immutable copy of the input buffer so that + // its contents can't change between when we calculate the required sort key length and + // when we populate the sort key buffer. + + source = source.ToString(); + } +#endif + // LCMapStringEx doesn't support passing cchSrc = 0, so if given a null or empty input // we'll normalize it to an empty null-terminated string and pass -1 to indicate that // the underlying OS function should read until it encounters the null terminator. @@ -188,68 +182,59 @@ namespace System.Globalization } } - private static unsafe int CompareStringOrdinalIgnoreCase(ref char string1, int count1, ref char string2, int count2) + private static unsafe int NlsCompareStringOrdinalIgnoreCase(ref char string1, int count1, ref char string2, int count2) { Debug.Assert(!GlobalizationMode.Invariant); + Debug.Assert(GlobalizationMode.UseNls); + + Debug.Assert(count1 > 0); + Debug.Assert(count2 > 0); fixed (char* char1 = &string1) fixed (char* char2 = &string2) { + Debug.Assert(char1 != null); + Debug.Assert(char2 != null); + // Use the OS to compare and then convert the result to expected value by subtracting 2 - return Interop.Kernel32.CompareStringOrdinal(char1, count1, char2, count2, true) - 2; - } - } - - // TODO https://github.com/dotnet/runtime/issues/8890: - // This method shouldn't be necessary, as we should be able to just use the overload - // that takes two spans. But due to this issue, that's adding significant overhead. - private unsafe int CompareString(ReadOnlySpan string1, string string2, CompareOptions options) - { - Debug.Assert(string2 != null); - Debug.Assert(!GlobalizationMode.Invariant); - Debug.Assert((options & (CompareOptions.Ordinal | CompareOptions.OrdinalIgnoreCase)) == 0); - - string? localeName = _sortHandle != IntPtr.Zero ? null : _sortName; - - fixed (char* pLocaleName = localeName) - fixed (char* pString1 = &MemoryMarshal.GetReference(string1)) - fixed (char* pString2 = &string2.GetRawStringData()) - { - Debug.Assert(pString1 != null); - int result = Interop.Kernel32.CompareStringEx( - pLocaleName, - (uint)GetNativeCompareFlags(options), - pString1, - string1.Length, - pString2, - string2.Length, - null, - null, - _sortHandle); - + int result = Interop.Kernel32.CompareStringOrdinal(char1, count1, char2, count2, bIgnoreCase: true); if (result == 0) { throw new ArgumentException(SR.Arg_ExternalException); } - - // Map CompareStringEx return value to -1, 0, 1. return result - 2; } } - private unsafe int CompareString(ReadOnlySpan string1, ReadOnlySpan string2, CompareOptions options) + private unsafe int NlsCompareString(ReadOnlySpan string1, ReadOnlySpan string2, CompareOptions options) { Debug.Assert(!GlobalizationMode.Invariant); + Debug.Assert(GlobalizationMode.UseNls); Debug.Assert((options & (CompareOptions.Ordinal | CompareOptions.OrdinalIgnoreCase)) == 0); string? localeName = _sortHandle != IntPtr.Zero ? null : _sortName; + // CompareStringEx may try to dereference the first character of its input, even if an explicit + // length of 0 is specified. To work around potential AVs we'll always ensure zero-length inputs + // are normalized to a null-terminated empty string. + + if (string1.IsEmpty) + { + string1 = string.Empty; + } + + if (string2.IsEmpty) + { + string2 = string.Empty; + } + fixed (char* pLocaleName = localeName) fixed (char* pString1 = &MemoryMarshal.GetReference(string1)) fixed (char* pString2 = &MemoryMarshal.GetReference(string2)) { - Debug.Assert(pString1 != null); - Debug.Assert(pString2 != null); + Debug.Assert(*pString1 >= 0); // assert that we can always dereference this + Debug.Assert(*pString2 >= 0); // assert that we can always dereference this + int result = Interop.Kernel32.CompareStringEx( pLocaleName, (uint)GetNativeCompareFlags(options), @@ -278,176 +263,83 @@ namespace System.Globalization int* pcchFound) { Debug.Assert(!GlobalizationMode.Invariant); - Debug.Assert(!lpStringSource.IsEmpty); Debug.Assert(!lpStringValue.IsEmpty); string? localeName = _sortHandle != IntPtr.Zero ? null : _sortName; + // FindNLSStringEx disallows passing an explicit 0 for cchSource or cchValue. + // The caller should've already checked that 'lpStringValue' isn't empty, + // but it's possible for 'lpStringSource' to be empty. In this case we'll + // substitute an empty null-terminated string and pass -1 so that the NLS + // function uses the implicit string length. + + int lpStringSourceLength = lpStringSource.Length; + if (lpStringSourceLength == 0) + { + lpStringSource = string.Empty; + lpStringSourceLength = -1; + } + fixed (char* pLocaleName = localeName) fixed (char* pSource = &MemoryMarshal.GetReference(lpStringSource)) fixed (char* pValue = &MemoryMarshal.GetReference(lpStringValue)) { - return Interop.Kernel32.FindNLSStringEx( + Debug.Assert(pSource != null && pValue != null); + + int result = Interop.Kernel32.FindNLSStringEx( pLocaleName, dwFindNLSStringFlags, pSource, - lpStringSource.Length, + lpStringSourceLength, pValue, lpStringValue.Length, pcchFound, null, null, _sortHandle); + + Debug.Assert(result >= -1 && result <= lpStringSource.Length); + + // SetLastError is only performed under debug builds. + Debug.Assert(result >= 0 || Marshal.GetLastWin32Error() == Interop.Errors.ERROR_SUCCESS); + + return result; } } - private unsafe int FindString( - uint dwFindNLSStringFlags, - string lpStringSource, - int startSource, - int cchSource, - string lpStringValue, - int startValue, - int cchValue, - int* pcchFound) + private unsafe int NlsIndexOfCore(ReadOnlySpan source, ReadOnlySpan target, CompareOptions options, int* matchLengthPtr, bool fromBeginning) { Debug.Assert(!GlobalizationMode.Invariant); - Debug.Assert(lpStringSource != null); - Debug.Assert(lpStringValue != null); + Debug.Assert(GlobalizationMode.UseNls); - string? localeName = _sortHandle != IntPtr.Zero ? null : _sortName; - - fixed (char* pLocaleName = localeName) - fixed (char* pSource = lpStringSource) - fixed (char* pValue = lpStringValue) - { - char* pS = pSource + startSource; - char* pV = pValue + startValue; - - return Interop.Kernel32.FindNLSStringEx( - pLocaleName, - dwFindNLSStringFlags, - pS, - cchSource, - pV, - cchValue, - pcchFound, - null, - null, - _sortHandle); - } - } - - internal unsafe int IndexOfCore(string source, string target, int startIndex, int count, CompareOptions options, int* matchLengthPtr) - { - Debug.Assert(!GlobalizationMode.Invariant); - - Debug.Assert(source != null); - Debug.Assert(target != null); - Debug.Assert((options & CompareOptions.OrdinalIgnoreCase) == 0); - Debug.Assert((options & CompareOptions.Ordinal) == 0); - - int retValue = FindString(FIND_FROMSTART | (uint)GetNativeCompareFlags(options), source, startIndex, count, - target, 0, target.Length, matchLengthPtr); - if (retValue >= 0) - { - return retValue + startIndex; - } - - return -1; - } - - internal unsafe int IndexOfCore(ReadOnlySpan source, ReadOnlySpan target, CompareOptions options, int* matchLengthPtr, bool fromBeginning) - { - Debug.Assert(!GlobalizationMode.Invariant); - - Debug.Assert(source.Length != 0); Debug.Assert(target.Length != 0); - Debug.Assert(options == CompareOptions.None || options == CompareOptions.IgnoreCase); uint positionFlag = fromBeginning ? (uint)FIND_FROMSTART : FIND_FROMEND; return FindString(positionFlag | (uint)GetNativeCompareFlags(options), source, target, matchLengthPtr); } - private unsafe int LastIndexOfCore(string source, string target, int startIndex, int count, CompareOptions options) + private unsafe bool NlsStartsWith(ReadOnlySpan source, ReadOnlySpan prefix, CompareOptions options) { Debug.Assert(!GlobalizationMode.Invariant); + Debug.Assert(GlobalizationMode.UseNls); - Debug.Assert(!string.IsNullOrEmpty(source)); - Debug.Assert(target != null); - Debug.Assert((options & CompareOptions.OrdinalIgnoreCase) == 0); - - if (target.Length == 0) - return startIndex; - - if ((options & CompareOptions.Ordinal) != 0) - { - return FastLastIndexOfString(source, target, startIndex, count, target.Length); - } - else - { - int retValue = FindString(FIND_FROMEND | (uint)GetNativeCompareFlags(options), source, startIndex - count + 1, - count, target, 0, target.Length, null); - - if (retValue >= 0) - { - return retValue + startIndex - (count - 1); - } - } - - return -1; - } - - private unsafe bool StartsWith(string source, string prefix, CompareOptions options) - { - Debug.Assert(!GlobalizationMode.Invariant); - - Debug.Assert(!string.IsNullOrEmpty(source)); - Debug.Assert(!string.IsNullOrEmpty(prefix)); - Debug.Assert((options & (CompareOptions.Ordinal | CompareOptions.OrdinalIgnoreCase)) == 0); - - return FindString(FIND_STARTSWITH | (uint)GetNativeCompareFlags(options), source, 0, source.Length, - prefix, 0, prefix.Length, null) >= 0; - } - - private unsafe bool StartsWith(ReadOnlySpan source, ReadOnlySpan prefix, CompareOptions options) - { - Debug.Assert(!GlobalizationMode.Invariant); - - Debug.Assert(!source.IsEmpty); Debug.Assert(!prefix.IsEmpty); Debug.Assert((options & (CompareOptions.Ordinal | CompareOptions.OrdinalIgnoreCase)) == 0); return FindString(FIND_STARTSWITH | (uint)GetNativeCompareFlags(options), source, prefix, null) >= 0; } - private unsafe bool EndsWith(string source, string suffix, CompareOptions options) + private unsafe bool NlsEndsWith(ReadOnlySpan source, ReadOnlySpan suffix, CompareOptions options) { Debug.Assert(!GlobalizationMode.Invariant); + Debug.Assert(GlobalizationMode.UseNls); - Debug.Assert(!string.IsNullOrEmpty(source)); - Debug.Assert(!string.IsNullOrEmpty(suffix)); - Debug.Assert((options & (CompareOptions.Ordinal | CompareOptions.OrdinalIgnoreCase)) == 0); - - return FindString(FIND_ENDSWITH | (uint)GetNativeCompareFlags(options), source, 0, source.Length, - suffix, 0, suffix.Length, null) >= 0; - } - - private unsafe bool EndsWith(ReadOnlySpan source, ReadOnlySpan suffix, CompareOptions options) - { - Debug.Assert(!GlobalizationMode.Invariant); - - Debug.Assert(!source.IsEmpty); Debug.Assert(!suffix.IsEmpty); Debug.Assert((options & (CompareOptions.Ordinal | CompareOptions.OrdinalIgnoreCase)) == 0); return FindString(FIND_ENDSWITH | (uint)GetNativeCompareFlags(options), source, suffix, null) >= 0; } - // PAL ends here - [NonSerialized] - private IntPtr _sortHandle; - private const uint LCMAP_SORTKEY = 0x00000400; private const int FIND_STARTSWITH = 0x00100000; @@ -455,53 +347,10 @@ namespace System.Globalization private const int FIND_FROMSTART = 0x00400000; private const int FIND_FROMEND = 0x00800000; - // TODO: Instead of this method could we just have upstack code call LastIndexOfOrdinal with ignoreCase = false? - private static unsafe int FastLastIndexOfString(string source, string target, int startIndex, int sourceCount, int targetCount) - { - int retValue = -1; - - int sourceStartIndex = startIndex - sourceCount + 1; - - fixed (char* pSource = source, spTarget = target) - { - char* spSubSource = pSource + sourceStartIndex; - - int endPattern = sourceCount - targetCount; - if (endPattern < 0) - return -1; - - Debug.Assert(target.Length >= 1); - char patternChar0 = spTarget[0]; - for (int ctrSrc = endPattern; ctrSrc >= 0; ctrSrc--) - { - if (spSubSource[ctrSrc] != patternChar0) - continue; - - int ctrPat; - for (ctrPat = 1; ctrPat < targetCount; ctrPat++) - { - if (spSubSource[ctrSrc + ctrPat] != spTarget[ctrPat]) - break; - } - if (ctrPat == targetCount) - { - retValue = ctrSrc; - break; - } - } - - if (retValue >= 0) - { - retValue += startIndex - sourceCount + 1; - } - } - - return retValue; - } - - private unsafe SortKey CreateSortKey(string source, CompareOptions options) + private unsafe SortKey NlsCreateSortKey(string source, CompareOptions options) { Debug.Assert(!GlobalizationMode.Invariant); + Debug.Assert(GlobalizationMode.UseNls); if (source == null) { throw new ArgumentNullException(nameof(source)); } @@ -549,15 +398,162 @@ namespace System.Globalization } } - return new SortKey(Name, source, options, keyData); + return new SortKey(this, source, options, keyData); } - private static unsafe bool IsSortable(char* text, int length) + private unsafe int NlsGetSortKey(ReadOnlySpan source, Span destination, CompareOptions options) { Debug.Assert(!GlobalizationMode.Invariant); - Debug.Assert(text != null); + Debug.Assert((options & ValidCompareMaskOffFlags) == 0); - return Interop.Kernel32.IsNLSDefinedString(Interop.Kernel32.COMPARE_STRING, 0, IntPtr.Zero, text, length); + // LCMapStringEx doesn't allow cchDest = 0 unless we're trying to query + // the total number of bytes necessary. + + if (destination.IsEmpty) + { + ThrowHelper.ThrowArgumentException_DestinationTooShort(); + } + +#if TARGET_WINDOWS + if (!Environment.IsWindows8OrAbove) + { + // On Windows 7 / Server 2008, LCMapStringEx exhibits strange behaviors if the destination + // buffer is both non-null and too small for the required output. To prevent this from + // causing issues for us, we need to make an immutable copy of the input buffer so that + // its contents can't change between when we calculate the required sort key length and + // when we populate the sort key buffer. + + source = source.ToString(); + } +#endif + + uint flags = LCMAP_SORTKEY | (uint)GetNativeCompareFlags(options); + + // LCMapStringEx doesn't support passing cchSrc = 0, so if given an empty span + // we'll instead normalize to a null-terminated empty string and pass -1 as + // the length to indicate that the implicit null terminator should be used. + + int sourceLength = source.Length; + if (sourceLength == 0) + { + source = string.Empty; + sourceLength = -1; + } + + int actualSortKeyLength; + + fixed (char* pSource = &MemoryMarshal.GetReference(source)) + fixed (byte* pSortKey = &MemoryMarshal.GetReference(destination)) + { + Debug.Assert(pSource != null); + Debug.Assert(pSortKey != null); + +#if TARGET_WINDOWS + if (!Environment.IsWindows8OrAbove) + { + // Manually check that the destination buffer is large enough to hold the full output. + // See earlier comment for reasoning. + + int requiredSortKeyLength = Interop.Kernel32.LCMapStringEx(_sortHandle != IntPtr.Zero ? null : _sortName, + flags, + pSource, sourceLength, + null, 0, + null, null, _sortHandle); + + if (requiredSortKeyLength > destination.Length) + { + ThrowHelper.ThrowArgumentException_DestinationTooShort(); + } + + if (requiredSortKeyLength <= 0) + { + throw new ArgumentException(SR.Arg_ExternalException); + } + } +#endif + + actualSortKeyLength = Interop.Kernel32.LCMapStringEx(_sortHandle != IntPtr.Zero ? null : _sortName, + flags, + pSource, sourceLength, + pSortKey, destination.Length, + null, null, _sortHandle); + } + + if (actualSortKeyLength <= 0) + { + Debug.Assert(actualSortKeyLength == 0, "LCMapStringEx should never return a negative value."); + + // This could fail for a variety of reasons, including NLS being unable + // to allocate a temporary buffer large enough to hold intermediate state, + // or the destination buffer being too small. + + if (Marshal.GetLastWin32Error() == Interop.Errors.ERROR_INSUFFICIENT_BUFFER) + { + ThrowHelper.ThrowArgumentException_DestinationTooShort(); + } + else + { + throw new ArgumentException(SR.Arg_ExternalException); + } + } + + Debug.Assert(actualSortKeyLength <= destination.Length); + return actualSortKeyLength; + } + + private unsafe int NlsGetSortKeyLength(ReadOnlySpan source, CompareOptions options) + { + Debug.Assert(!GlobalizationMode.Invariant); + Debug.Assert((options & ValidCompareMaskOffFlags) == 0); + + uint flags = LCMAP_SORTKEY | (uint)GetNativeCompareFlags(options); + + // LCMapStringEx doesn't support passing cchSrc = 0, so if given an empty span + // we'll instead normalize to a null-terminated empty string and pass -1 as + // the length to indicate that the implicit null terminator should be used. + + int sourceLength = source.Length; + if (sourceLength == 0) + { + source = string.Empty; + sourceLength = -1; + } + + int sortKeyLength; + + fixed (char* pSource = &MemoryMarshal.GetReference(source)) + { + Debug.Assert(pSource != null); + sortKeyLength = Interop.Kernel32.LCMapStringEx(_sortHandle != IntPtr.Zero ? null : _sortName, + flags, + pSource, sourceLength, + null, 0, + null, null, _sortHandle); + } + + if (sortKeyLength <= 0) + { + Debug.Assert(sortKeyLength == 0, "LCMapStringEx should never return a negative value."); + + // This could fail for a variety of reasons, including NLS being unable + // to allocate a temporary buffer large enough to hold intermediate state. + + throw new ArgumentException(SR.Arg_ExternalException); + } + + return sortKeyLength; + } + + private static unsafe bool NlsIsSortable(ReadOnlySpan text) + { + Debug.Assert(!GlobalizationMode.Invariant); + Debug.Assert(GlobalizationMode.UseNls); + Debug.Assert(!text.IsEmpty); + + fixed (char* pText = &MemoryMarshal.GetReference(text)) + { + return Interop.Kernel32.IsNLSDefinedString(Interop.Kernel32.COMPARE_STRING, 0, IntPtr.Zero, pText, text.Length); + } } private const int COMPARE_OPTIONS_ORDINAL = 0x40000000; // Ordinal @@ -598,9 +594,10 @@ namespace System.Globalization return nativeCompareFlags; } - private unsafe SortVersion GetSortVersion() + private unsafe SortVersion NlsGetSortVersion() { Debug.Assert(!GlobalizationMode.Invariant); + Debug.Assert(GlobalizationMode.UseNls); Interop.Kernel32.NlsVersionInfoEx nlsVersion = default; nlsVersion.dwNLSVersionInfoSize = sizeof(Interop.Kernel32.NlsVersionInfoEx); diff --git a/src/System.Private.CoreLib/shared/System/Globalization/CompareInfo.cs b/src/System.Private.CoreLib/shared/System/Globalization/CompareInfo.cs index 1c2df6f61..7fb13f2b5 100644 --- a/src/System.Private.CoreLib/shared/System/Globalization/CompareInfo.cs +++ b/src/System.Private.CoreLib/shared/System/Globalization/CompareInfo.cs @@ -3,10 +3,12 @@ // See the LICENSE file in the project root for more information. using System.Diagnostics; +using System.Diagnostics.CodeAnalysis; using System.Reflection; using System.Runtime.CompilerServices; using System.Runtime.InteropServices; using System.Runtime.Serialization; +using System.Text; using System.Text.Unicode; using Internal.Runtime.CompilerServices; @@ -39,6 +41,9 @@ namespace System.Globalization [OptionalField(VersionAdded = 2)] private string m_name; // The name used to construct this CompareInfo. Do not rename (binary serialization) + [NonSerialized] + private IntPtr _sortHandle; + [NonSerialized] private string _sortName = null!; // The name that defines our behavior @@ -123,24 +128,31 @@ namespace System.Globalization return CultureInfo.GetCultureInfo(name).CompareInfo; } - public static unsafe bool IsSortable(char ch) + public static bool IsSortable(char ch) { - if (GlobalizationMode.Invariant) - { - return true; - } - - char* pChar = &ch; - return IsSortable(pChar, 1); + return IsSortable(MemoryMarshal.CreateReadOnlySpan(ref ch, 1)); } - public static unsafe bool IsSortable(string text) + public static bool IsSortable(string text) { if (text == null) { throw new ArgumentNullException(nameof(text)); } + return IsSortable(text.AsSpan()); + } + + /// + /// Indicates whether a specified Unicode string is sortable. + /// + /// A string of zero or more Unicode characters. + /// + /// if is non-empty and contains + /// only sortable Unicode characters; otherwise, . + /// + public static bool IsSortable(ReadOnlySpan text) + { if (text.Length == 0) { return false; @@ -148,12 +160,38 @@ namespace System.Globalization if (GlobalizationMode.Invariant) { - return true; + return true; // all chars are sortable in invariant mode } - fixed (char* pChar = text) + return (GlobalizationMode.UseNls) ? NlsIsSortable(text) : IcuIsSortable(text); + } + + /// + /// Indicates whether a specified is sortable. + /// + /// A Unicode scalar value. + /// + /// if is a sortable Unicode scalar + /// value; otherwise, . + /// + public static bool IsSortable(Rune value) + { + Span valueAsUtf16 = stackalloc char[Rune.MaxUtf16CharsPerRune]; + int charCount = value.EncodeToUtf16(valueAsUtf16); + return IsSortable(valueAsUtf16.Slice(0, charCount)); + } + + private void InitSort(CultureInfo culture) + { + _sortName = culture.SortName; + + if (GlobalizationMode.UseNls) { - return IsSortable(pChar, text.Length); + NlsInitSortHandle(); + } + else + { + IcuInitSortHandle(); } } @@ -235,121 +273,38 @@ namespace System.Globalization public int Compare(string? string1, string? string2, CompareOptions options) { - if (options == CompareOptions.OrdinalIgnoreCase) - { - return string.Compare(string1, string2, StringComparison.OrdinalIgnoreCase); - } - - // Verify the options before we do any real comparison. - if ((options & CompareOptions.Ordinal) != 0) - { - if (options != CompareOptions.Ordinal) - { - throw new ArgumentException(SR.Argument_CompareOptionOrdinal, nameof(options)); - } - - return string.CompareOrdinal(string1, string2); - } - - if ((options & ValidCompareMaskOffFlags) != 0) - { - throw new ArgumentException(SR.Argument_InvalidFlag, nameof(options)); - } + int retVal; // Our paradigm is that null sorts less than any other string and // that two nulls sort as equal. + if (string1 == null) { - if (string2 == null) - { - return 0; - } - return -1; // null < non-null + retVal = (string2 == null) ? 0 : -1; + goto CheckOptionsAndReturn; } if (string2 == null) { - return 1; // non-null > null + retVal = 1; + goto CheckOptionsAndReturn; } - if (GlobalizationMode.Invariant) - { - if ((options & CompareOptions.IgnoreCase) != 0) - { - return CompareOrdinalIgnoreCase(string1, string2); - } + return Compare(string1.AsSpan(), string2.AsSpan(), options); - return string.CompareOrdinal(string1, string2); - } + CheckOptionsAndReturn: - return CompareString(string1.AsSpan(), string2.AsSpan(), options); - } + // If we're short-circuiting the globalization logic, we still need to check that + // the provided options were valid. - // TODO https://github.com/dotnet/runtime/issues/8890: - // This method shouldn't be necessary, as we should be able to just use the overload - // that takes two spans. But due to this issue, that's adding significant overhead. - internal int Compare(ReadOnlySpan string1, string? string2, CompareOptions options) - { - if (options == CompareOptions.OrdinalIgnoreCase) - { - return CompareOrdinalIgnoreCase(string1, string2.AsSpan()); - } - - // Verify the options before we do any real comparison. - if ((options & CompareOptions.Ordinal) != 0) - { - if (options != CompareOptions.Ordinal) - { - throw new ArgumentException(SR.Argument_CompareOptionOrdinal, nameof(options)); - } - - return string.CompareOrdinal(string1, string2.AsSpan()); - } - - if ((options & ValidCompareMaskOffFlags) != 0) - { - throw new ArgumentException(SR.Argument_InvalidFlag, nameof(options)); - } - - // null sorts less than any other string. - if (string2 == null) - { - return 1; - } - - if (GlobalizationMode.Invariant) - { - return (options & CompareOptions.IgnoreCase) != 0 ? - CompareOrdinalIgnoreCase(string1, string2.AsSpan()) : - string.CompareOrdinal(string1, string2.AsSpan()); - } - - return CompareString(string1, string2, options); - } - - internal int CompareOptionNone(ReadOnlySpan string1, ReadOnlySpan string2) - { - // Check for empty span or span from a null string - if (string1.Length == 0 || string2.Length == 0) - { - return string1.Length - string2.Length; - } - - return GlobalizationMode.Invariant ? - string.CompareOrdinal(string1, string2) : - CompareString(string1, string2, CompareOptions.None); + CheckCompareOptionsForCompare(options); + return retVal; } internal int CompareOptionIgnoreCase(ReadOnlySpan string1, ReadOnlySpan string2) { - // Check for empty span or span from a null string - if (string1.Length == 0 || string2.Length == 0) - { - return string1.Length - string2.Length; - } - return GlobalizationMode.Invariant ? CompareOrdinalIgnoreCase(string1, string2) : - CompareString(string1, string2, CompareOptions.IgnoreCase); + CompareStringCore(string1, string2, CompareOptions.IgnoreCase); } /// @@ -361,7 +316,7 @@ namespace System.Globalization /// public int Compare(string? string1, int offset1, int length1, string? string2, int offset2, int length2) { - return Compare(string1, offset1, length1, string2, offset2, length2, 0); + return Compare(string1, offset1, length1, string2, offset2, length2, CompareOptions.None); } public int Compare(string? string1, int offset1, string? string2, int offset2, CompareOptions options) @@ -372,85 +327,195 @@ namespace System.Globalization public int Compare(string? string1, int offset1, string? string2, int offset2) { - return Compare(string1, offset1, string2, offset2, 0); + return Compare(string1, offset1, string2, offset2, CompareOptions.None); } public int Compare(string? string1, int offset1, int length1, string? string2, int offset2, int length2, CompareOptions options) { - if (options == CompareOptions.OrdinalIgnoreCase) - { - int result = string.Compare(string1, offset1, string2, offset2, length1 < length2 ? length1 : length2, StringComparison.OrdinalIgnoreCase); - if ((length1 != length2) && result == 0) - { - return length1 > length2 ? 1 : -1; - } + ReadOnlySpan span1 = default; + ReadOnlySpan span2 = default; - return result; + if (string1 == null) + { + if (offset1 != 0 || length1 != 0) + { + goto BoundsCheckError; + } } + else if (!string1.TryGetSpan(offset1, length1, out span1)) + { + goto BoundsCheckError; + } + + if (string2 == null) + { + if (offset2 != 0 || length2 != 0) + { + goto BoundsCheckError; + } + } + else if (!string2.TryGetSpan(offset2, length2, out span2)) + { + goto BoundsCheckError; + } + + // At this point both string1 and string2 have been bounds-checked. + + int retVal; + + // Our paradigm is that null sorts less than any other string and + // that two nulls sort as equal. + + if (string1 == null) + { + retVal = (string2 == null) ? 0 : -1; + goto CheckOptionsAndReturn; + } + if (string2 == null) + { + retVal = 1; + goto CheckOptionsAndReturn; + } + + // At this point we know both string1 and string2 weren't null, + // though they may have been empty. + + Debug.Assert(!Unsafe.IsNullRef(ref MemoryMarshal.GetReference(span1))); + Debug.Assert(!Unsafe.IsNullRef(ref MemoryMarshal.GetReference(span2))); + + return Compare(span1, span2, options); + + CheckOptionsAndReturn: + + // If we're short-circuiting the globalization logic, we still need to check that + // the provided options were valid. + + CheckCompareOptionsForCompare(options); + return retVal; + + BoundsCheckError: + + // We know a bounds check error occurred. Now we just need to figure + // out the correct error message to surface. if (length1 < 0 || length2 < 0) { throw new ArgumentOutOfRangeException((length1 < 0) ? nameof(length1) : nameof(length2), SR.ArgumentOutOfRange_NeedPosNum); } + if (offset1 < 0 || offset2 < 0) { throw new ArgumentOutOfRangeException((offset1 < 0) ? nameof(offset1) : nameof(offset2), SR.ArgumentOutOfRange_NeedPosNum); } + if (offset1 > (string1 == null ? 0 : string1.Length) - length1) { throw new ArgumentOutOfRangeException(nameof(string1), SR.ArgumentOutOfRange_OffsetLength); } - if (offset2 > (string2 == null ? 0 : string2.Length) - length2) - { - throw new ArgumentOutOfRangeException(nameof(string2), SR.ArgumentOutOfRange_OffsetLength); - } - if ((options & CompareOptions.Ordinal) != 0) - { - if (options != CompareOptions.Ordinal) - { - throw new ArgumentException(SR.Argument_CompareOptionOrdinal, - nameof(options)); - } - } - else if ((options & ValidCompareMaskOffFlags) != 0) - { - throw new ArgumentException(SR.Argument_InvalidFlag, nameof(options)); - } - if (string1 == null) - { - if (string2 == null) - { - return 0; - } - return -1; - } - if (string2 == null) - { - return 1; - } - - ReadOnlySpan span1 = string1.AsSpan(offset1, length1); - ReadOnlySpan span2 = string2.AsSpan(offset2, length2); - - if (options == CompareOptions.Ordinal) - { - return string.CompareOrdinal(span1, span2); - } - - if (GlobalizationMode.Invariant) - { - if ((options & CompareOptions.IgnoreCase) != 0) - { - return CompareOrdinalIgnoreCase(span1, span2); - } - - return string.CompareOrdinal(span1, span2); - } - - return CompareString(span1, span2, options); + Debug.Assert(offset2 > (string2 == null ? 0 : string2.Length) - length2); + throw new ArgumentOutOfRangeException(nameof(string2), SR.ArgumentOutOfRange_OffsetLength); } + /// + /// Compares two strings. + /// + /// The first string to compare. + /// The second string to compare. + /// The to use during the comparison. + /// + /// Zero if and are equal; + /// or a negative value if sorts before ; + /// or a positive value if sorts after . + /// + /// + /// contains an unsupported combination of flags. + /// + public int Compare(ReadOnlySpan string1, ReadOnlySpan string2, CompareOptions options = CompareOptions.None) + { + if (string1 == string2) // referential equality + length + { + CheckCompareOptionsForCompare(options); + return 0; + } + + if ((options & ValidCompareMaskOffFlags) == 0) + { + // Common case: caller is attempting to perform linguistic comparison. + // Pass the flags down to NLS or ICU unless we're running in invariant + // mode, at which point we normalize the flags to Orginal[IgnoreCase]. + + if (!GlobalizationMode.Invariant) + { + return CompareStringCore(string1, string2, options); + } + else if ((options & CompareOptions.IgnoreCase) == 0) + { + goto ReturnOrdinal; + } + else + { + goto ReturnOrdinalIgnoreCase; + } + } + else + { + // Less common case: caller is attempting to perform non-linguistic comparison, + // or an invalid combination of flags was supplied. + + if (options == CompareOptions.Ordinal) + { + goto ReturnOrdinal; + } + else if (options == CompareOptions.OrdinalIgnoreCase) + { + goto ReturnOrdinalIgnoreCase; + } + else + { + ThrowCompareOptionsCheckFailed(options); + } + } + + ReturnOrdinal: + return string1.SequenceCompareTo(string2); + + ReturnOrdinalIgnoreCase: + return CompareOrdinalIgnoreCase(string1, string2); + } + + // Checks that 'CompareOptions' is valid for a call to Compare, throwing the appropriate + // exception if the check fails. + [MethodImpl(MethodImplOptions.AggressiveInlining)] + [StackTraceHidden] + private static void CheckCompareOptionsForCompare(CompareOptions options) + { + // Any combination of defined CompareOptions flags is valid, except for + // Ordinal and OrdinalIgnoreCase, which may only be used in isolation. + + if ((options & ValidCompareMaskOffFlags) != 0) + { + if (options != CompareOptions.Ordinal && options != CompareOptions.OrdinalIgnoreCase) + { + ThrowCompareOptionsCheckFailed(options); + } + } + } + + [DoesNotReturn] + [StackTraceHidden] + private static void ThrowCompareOptionsCheckFailed(CompareOptions options) + { + throw new ArgumentException( + paramName: nameof(options), + message: ((options & CompareOptions.Ordinal) != 0) ? SR.Argument_CompareOptionOrdinal : SR.Argument_InvalidFlag); + } + + private unsafe int CompareStringCore(ReadOnlySpan string1, ReadOnlySpan string2, CompareOptions options) => + GlobalizationMode.UseNls ? + NlsCompareString(string1, string2, options) : + IcuCompareString(string1, string2, options); + /// /// CompareOrdinalIgnoreCase compare two string ordinally with ignoring the case. /// it assumes the strings are Ascii string till we hit non Ascii character in strA or strB and then we continue the comparison by @@ -528,7 +593,7 @@ namespace System.Globalization range -= length; - return CompareStringOrdinalIgnoreCase(ref charA, lengthA - range, ref charB, lengthB - range); + return CompareStringOrdinalIgnoreCaseCore(ref charA, lengthA - range, ref charB, lengthB - range); } internal static bool EqualsOrdinalIgnoreCase(ref char charA, ref char charB, int length) @@ -638,7 +703,7 @@ namespace System.Globalization { if (!GlobalizationMode.Invariant) { - return CompareStringOrdinalIgnoreCase(ref charA, length, ref charB, length) == 0; + return CompareStringOrdinalIgnoreCaseCore(ref charA, length, ref charB, length) == 0; } else { @@ -670,6 +735,11 @@ namespace System.Globalization } } + private static unsafe int CompareStringOrdinalIgnoreCaseCore(ref char string1, int count1, ref char string2, int count2) => + GlobalizationMode.UseNls ? + NlsCompareStringOrdinalIgnoreCase(ref string1, count1, ref string2, count2) : + IcuCompareStringOrdinalIgnoreCase(ref string1, count1, ref string2, count2); + /// /// Determines whether prefix is a prefix of string. If prefix equals /// string.Empty, true is returned. @@ -678,59 +748,93 @@ namespace System.Globalization { if (source == null) { - throw new ArgumentNullException(nameof(source)); + ThrowHelper.ThrowArgumentNullException(ExceptionArgument.source); } if (prefix == null) { - throw new ArgumentNullException(nameof(prefix)); + ThrowHelper.ThrowArgumentNullException(ExceptionArgument.prefix); } - if (prefix.Length == 0) + return IsPrefix(source.AsSpan(), prefix.AsSpan(), options); + } + + /// + /// Determines whether a string starts with a specific prefix. + /// + /// The string to search within. + /// The prefix to attempt to match at the start of . + /// The to use during the match. + /// + /// if occurs at the start of ; + /// otherwise, . + /// + /// + /// contains an unsupported combination of flags. + /// + public bool IsPrefix(ReadOnlySpan source, ReadOnlySpan prefix, CompareOptions options = CompareOptions.None) + { + // The empty string is trivially a prefix of every other string. For compat with + // earlier versions of the Framework we'll early-exit here before validating the + // 'options' argument. + + if (prefix.IsEmpty) { return true; } - if (source.Length == 0) + + if ((options & ValidIndexMaskOffFlags) == 0) { - return false; + // Common case: caller is attempting to perform a linguistic search. + // Pass the flags down to NLS or ICU unless we're running in invariant + // mode, at which point we normalize the flags to Orginal[IgnoreCase]. + + if (!GlobalizationMode.Invariant) + { + return StartsWithCore(source, prefix, options); + } + else if ((options & CompareOptions.IgnoreCase) == 0) + { + goto ReturnOrdinal; + } + else + { + goto ReturnOrdinalIgnoreCase; + } + } + else + { + // Less common case: caller is attempting to perform non-linguistic comparison, + // or an invalid combination of flags was supplied. + + if (options == CompareOptions.Ordinal) + { + goto ReturnOrdinal; + } + else if (options == CompareOptions.OrdinalIgnoreCase) + { + goto ReturnOrdinalIgnoreCase; + } + else + { + ThrowCompareOptionsCheckFailed(options); + } } - if (options == CompareOptions.OrdinalIgnoreCase) - { - return source.StartsWith(prefix, StringComparison.OrdinalIgnoreCase); - } + ReturnOrdinal: + return source.StartsWith(prefix); - if (options == CompareOptions.Ordinal) - { - return source.StartsWith(prefix, StringComparison.Ordinal); - } - - if ((options & ValidIndexMaskOffFlags) != 0) - { - throw new ArgumentException(SR.Argument_InvalidFlag, nameof(options)); - } - - if (GlobalizationMode.Invariant) - { - return source.StartsWith(prefix, (options & CompareOptions.IgnoreCase) != 0 ? StringComparison.OrdinalIgnoreCase : StringComparison.Ordinal); - } - - return StartsWith(source, prefix, options); + ReturnOrdinalIgnoreCase: + return source.StartsWithOrdinalIgnoreCase(prefix); } - internal bool IsPrefix(ReadOnlySpan source, ReadOnlySpan prefix, CompareOptions options) - { - Debug.Assert(prefix.Length != 0); - Debug.Assert(source.Length != 0); - Debug.Assert((options & ValidIndexMaskOffFlags) == 0); - Debug.Assert(!GlobalizationMode.Invariant); - Debug.Assert((options & (CompareOptions.Ordinal | CompareOptions.OrdinalIgnoreCase)) == 0); - - return StartsWith(source, prefix, options); - } + private unsafe bool StartsWithCore(ReadOnlySpan source, ReadOnlySpan prefix, CompareOptions options) => + GlobalizationMode.UseNls ? + NlsStartsWith(source, prefix, options) : + IcuStartsWith(source, prefix, options); public bool IsPrefix(string source, string prefix) { - return IsPrefix(source, prefix, 0); + return IsPrefix(source, prefix, CompareOptions.None); } /// @@ -741,140 +845,163 @@ namespace System.Globalization { if (source == null) { - throw new ArgumentNullException(nameof(source)); + ThrowHelper.ThrowArgumentNullException(ExceptionArgument.source); } if (suffix == null) { - throw new ArgumentNullException(nameof(suffix)); + ThrowHelper.ThrowArgumentNullException(ExceptionArgument.suffix); } - if (suffix.Length == 0) + return IsSuffix(source.AsSpan(), suffix.AsSpan(), options); + } + + /// + /// Determines whether a string ends with a specific suffix. + /// + /// The string to search within. + /// The suffix to attempt to match at the end of . + /// The to use during the match. + /// + /// if occurs at the end of ; + /// otherwise, . + /// + /// + /// contains an unsupported combination of flags. + /// + public bool IsSuffix(ReadOnlySpan source, ReadOnlySpan suffix, CompareOptions options = CompareOptions.None) + { + // The empty string is trivially a suffix of every other string. For compat with + // earlier versions of the Framework we'll early-exit here before validating the + // 'options' argument. + + if (suffix.IsEmpty) { return true; } - if (source.Length == 0) + + if ((options & ValidIndexMaskOffFlags) == 0) { - return false; + // Common case: caller is attempting to perform a linguistic search. + // Pass the flags down to NLS or ICU unless we're running in invariant + // mode, at which point we normalize the flags to Orginal[IgnoreCase]. + + if (!GlobalizationMode.Invariant) + { + return EndsWithCore(source, suffix, options); + } + else if ((options & CompareOptions.IgnoreCase) == 0) + { + goto ReturnOrdinal; + } + else + { + goto ReturnOrdinalIgnoreCase; + } + } + else + { + // Less common case: caller is attempting to perform non-linguistic comparison, + // or an invalid combination of flags was supplied. + + if (options == CompareOptions.Ordinal) + { + goto ReturnOrdinal; + } + else if (options == CompareOptions.OrdinalIgnoreCase) + { + goto ReturnOrdinalIgnoreCase; + } + else + { + ThrowCompareOptionsCheckFailed(options); + } } - if (options == CompareOptions.OrdinalIgnoreCase) - { - return source.EndsWith(suffix, StringComparison.OrdinalIgnoreCase); - } + ReturnOrdinal: + return source.EndsWith(suffix); - if (options == CompareOptions.Ordinal) - { - return source.EndsWith(suffix, StringComparison.Ordinal); - } - - if ((options & ValidIndexMaskOffFlags) != 0) - { - throw new ArgumentException(SR.Argument_InvalidFlag, nameof(options)); - } - - if (GlobalizationMode.Invariant) - { - return source.EndsWith(suffix, (options & CompareOptions.IgnoreCase) != 0 ? StringComparison.OrdinalIgnoreCase : StringComparison.Ordinal); - } - - return EndsWith(source, suffix, options); - } - - internal bool IsSuffix(ReadOnlySpan source, ReadOnlySpan suffix, CompareOptions options) - { - Debug.Assert(suffix.Length != 0); - Debug.Assert(source.Length != 0); - Debug.Assert((options & ValidIndexMaskOffFlags) == 0); - Debug.Assert(!GlobalizationMode.Invariant); - Debug.Assert((options & (CompareOptions.Ordinal | CompareOptions.OrdinalIgnoreCase)) == 0); - - return EndsWith(source, suffix, options); + ReturnOrdinalIgnoreCase: + return source.EndsWithOrdinalIgnoreCase(suffix); } public bool IsSuffix(string source, string suffix) { - return IsSuffix(source, suffix, 0); + return IsSuffix(source, suffix, CompareOptions.None); } + private unsafe bool EndsWithCore(ReadOnlySpan source, ReadOnlySpan suffix, CompareOptions options) => + GlobalizationMode.UseNls ? + NlsEndsWith(source, suffix, options) : + IcuEndsWith(source, suffix, options); + /// /// Returns the first index where value is found in string. The /// search starts from startIndex and ends at endIndex. Returns -1 if /// the specified value is not found. If value equals string.Empty, /// startIndex is returned. Throws IndexOutOfRange if startIndex or /// endIndex is less than zero or greater than the length of string. - /// Throws ArgumentException if value is null. + /// Throws ArgumentException if value (as a string) is null. /// public int IndexOf(string source, char value) { - if (source == null) - { - throw new ArgumentNullException(nameof(source)); - } - - return IndexOf(source, value, 0, source.Length, CompareOptions.None); + return IndexOf(source, value, CompareOptions.None); } public int IndexOf(string source, string value) { - if (source == null) - throw new ArgumentNullException(nameof(source)); - - return IndexOf(source, value, 0, source.Length, CompareOptions.None); + return IndexOf(source, value, CompareOptions.None); } public int IndexOf(string source, char value, CompareOptions options) { if (source == null) { - throw new ArgumentNullException(nameof(source)); + ThrowHelper.ThrowArgumentNullException(ExceptionArgument.source); } - return IndexOf(source, value, 0, source.Length, options); + return IndexOf(source, MemoryMarshal.CreateReadOnlySpan(ref value, 1), options); } public int IndexOf(string source, string value, CompareOptions options) { if (source == null) { - throw new ArgumentNullException(nameof(source)); + ThrowHelper.ThrowArgumentNullException(ExceptionArgument.source); + } + if (value == null) + { + ThrowHelper.ThrowArgumentNullException(ExceptionArgument.value); } - return IndexOf(source, value, 0, source.Length, options); + return IndexOf(source.AsSpan(), value.AsSpan(), options); } public int IndexOf(string source, char value, int startIndex) { - if (source == null) - { - throw new ArgumentNullException(nameof(source)); - } - - return IndexOf(source, value, startIndex, source.Length - startIndex, CompareOptions.None); + return IndexOf(source, value, startIndex, CompareOptions.None); } public int IndexOf(string source, string value, int startIndex) { - if (source == null) - throw new ArgumentNullException(nameof(source)); - - return IndexOf(source, value, startIndex, source.Length - startIndex, CompareOptions.None); + return IndexOf(source, value, startIndex, CompareOptions.None); } public int IndexOf(string source, char value, int startIndex, CompareOptions options) { if (source == null) { - throw new ArgumentNullException(nameof(source)); + ThrowHelper.ThrowArgumentNullException(ExceptionArgument.source); } return IndexOf(source, value, startIndex, source.Length - startIndex, options); + } public int IndexOf(string source, string value, int startIndex, CompareOptions options) { if (source == null) { - throw new ArgumentNullException(nameof(source)); + ThrowHelper.ThrowArgumentNullException(ExceptionArgument.source); } return IndexOf(source, value, startIndex, source.Length - startIndex, options); @@ -894,241 +1021,312 @@ namespace System.Globalization { if (source == null) { - throw new ArgumentNullException(nameof(source)); - } - if (startIndex < 0 || startIndex > source.Length) - { - throw new ArgumentOutOfRangeException(nameof(startIndex), SR.ArgumentOutOfRange_Index); - } - if (count < 0 || startIndex > source.Length - count) - { - throw new ArgumentOutOfRangeException(nameof(count), SR.ArgumentOutOfRange_Count); + ThrowHelper.ThrowArgumentNullException(ExceptionArgument.source); } - if (source.Length == 0) + if (!source.TryGetSpan(startIndex, count, out ReadOnlySpan sourceSpan)) { - return -1; + // Bounds check failed - figure out exactly what went wrong so that we can + // surface the correct argument exception. + + if ((uint)startIndex > (uint)source.Length) + { + ThrowHelper.ThrowArgumentOutOfRangeException(ExceptionArgument.startIndex, ExceptionResource.ArgumentOutOfRange_Index); + } + else + { + ThrowHelper.ThrowArgumentOutOfRangeException(ExceptionArgument.count, ExceptionResource.ArgumentOutOfRange_Count); + } } - // Validate CompareOptions - // Ordinal can't be selected with other flags - if ((options & ValidIndexMaskOffFlags) != 0 && (options != CompareOptions.Ordinal && options != CompareOptions.OrdinalIgnoreCase)) + int result = IndexOf(sourceSpan, MemoryMarshal.CreateReadOnlySpan(ref value, 1), options); + if (result >= 0) { - throw new ArgumentException(SR.Argument_InvalidFlag, nameof(options)); + result += startIndex; } - - return IndexOf(source, char.ToString(value), startIndex, count, options, null); + return result; } public unsafe int IndexOf(string source, string value, int startIndex, int count, CompareOptions options) { if (source == null) { - throw new ArgumentNullException(nameof(source)); + ThrowHelper.ThrowArgumentNullException(ExceptionArgument.source); } if (value == null) { - throw new ArgumentNullException(nameof(value)); - } - if (startIndex > source.Length) - { - throw new ArgumentOutOfRangeException(nameof(startIndex), SR.ArgumentOutOfRange_Index); + ThrowHelper.ThrowArgumentNullException(ExceptionArgument.value); } - // In Everett we used to return -1 for empty string even if startIndex is negative number so we keeping same behavior here. - // We return 0 if both source and value are empty strings for Everett compatibility too. - if (source.Length == 0) + if (!source.TryGetSpan(startIndex, count, out ReadOnlySpan sourceSpan)) { - if (value.Length == 0) + // Bounds check failed - figure out exactly what went wrong so that we can + // surface the correct argument exception. + + if ((uint)startIndex > (uint)source.Length) { - return 0; + ThrowHelper.ThrowArgumentOutOfRangeException(ExceptionArgument.startIndex, ExceptionResource.ArgumentOutOfRange_Index); } + else + { + ThrowHelper.ThrowArgumentOutOfRangeException(ExceptionArgument.count, ExceptionResource.ArgumentOutOfRange_Count); + } + } + + int result = IndexOf(sourceSpan, value, options); + if (result >= 0) + { + result += startIndex; + } + return result; + } + + /// + /// Searches for the first occurrence of a substring within a source string. + /// + /// The string to search within. + /// The substring to locate within . + /// The to use during the search. + /// + /// The zero-based index into where the substring + /// first appears; or -1 if cannot be found within . + /// + /// + /// contains an unsupported combination of flags. + /// + public unsafe int IndexOf(ReadOnlySpan source, ReadOnlySpan value, CompareOptions options = CompareOptions.None) + { + if ((options & ValidIndexMaskOffFlags) == 0) + { + // Common case: caller is attempting to perform a linguistic search. + // Pass the flags down to NLS or ICU unless we're running in invariant + // mode, at which point we normalize the flags to Orginal[IgnoreCase]. + + if (!GlobalizationMode.Invariant) + { + if (value.IsEmpty) + { + return 0; // Empty target string trivially occurs at index 0 of every search space. + } + else + { + return IndexOfCore(source, value, options, null /* matchLengthPtr */, fromBeginning: true); + } + } + else if ((options & CompareOptions.IgnoreCase) == 0) + { + goto ReturnOrdinal; + } + else + { + goto ReturnOrdinalIgnoreCase; + } + } + else + { + // Less common case: caller is attempting to perform non-linguistic comparison, + // or an invalid combination of flags was supplied. + + if (options == CompareOptions.Ordinal) + { + goto ReturnOrdinal; + } + else if (options == CompareOptions.OrdinalIgnoreCase) + { + goto ReturnOrdinalIgnoreCase; + } + else + { + ThrowHelper.ThrowArgumentException(ExceptionResource.Argument_InvalidFlag, ExceptionArgument.options); + } + } + + ReturnOrdinal: + return source.IndexOf(value); + + ReturnOrdinalIgnoreCase: + return IndexOfOrdinalIgnoreCase(source, value, fromBeginning: true); + } + + /// + /// Searches for the first occurrence of a within a source string. + /// + /// The string to search within. + /// The to locate within . + /// The to use during the search. + /// + /// The zero-based index into where + /// first appears; or -1 if cannot be found within . + /// + /// + /// contains an unsupported combination of flags. + /// + public int IndexOf(ReadOnlySpan source, Rune value, CompareOptions options = CompareOptions.None) + { + Span valueAsUtf16 = stackalloc char[Rune.MaxUtf16CharsPerRune]; + int charCount = value.EncodeToUtf16(valueAsUtf16); + return IndexOf(source, valueAsUtf16.Slice(0, charCount), options); + } + + private static int IndexOfOrdinalCore(ReadOnlySpan source, ReadOnlySpan value, bool ignoreCase, bool fromBeginning) => + GlobalizationMode.UseNls ? + NlsIndexOfOrdinalCore(source, value, ignoreCase, fromBeginning) : + IcuIndexOfOrdinalCore(source, value, ignoreCase, fromBeginning); + + internal static int IndexOfOrdinalIgnoreCase(ReadOnlySpan source, ReadOnlySpan value, bool fromBeginning) + { + if (value.IsEmpty) + { + // Empty target string trivially appears at all indexes of all search spaces. + + return (fromBeginning) ? 0 : source.Length; + } + + if (value.Length > source.Length) + { + // A non-linguistic search compares chars directly against one another, so large + // target strings can never be found inside small search spaces. This check also + // handles empty 'source' spans. + return -1; } - if (startIndex < 0) + if (GlobalizationMode.Invariant) { - throw new ArgumentOutOfRangeException(nameof(startIndex), SR.ArgumentOutOfRange_Index); + return InvariantIndexOf(source, value, ignoreCase: true, fromBeginning); } - - if (count < 0 || startIndex > source.Length - count) + else { - throw new ArgumentOutOfRangeException(nameof(count), SR.ArgumentOutOfRange_Count); + return IndexOfOrdinalCore(source, value, ignoreCase: true, fromBeginning); } - - // Validate CompareOptions - // Ordinal can't be selected with other flags - if ((options & ValidIndexMaskOffFlags) != 0 && (options != CompareOptions.Ordinal && options != CompareOptions.OrdinalIgnoreCase)) - { - throw new ArgumentException(SR.Argument_InvalidFlag, nameof(options)); - } - - return IndexOf(source, value, startIndex, count, options, null); - } - - internal int IndexOfOrdinalIgnoreCase(ReadOnlySpan source, ReadOnlySpan value) - { - Debug.Assert(!GlobalizationMode.Invariant); - Debug.Assert(!source.IsEmpty); - Debug.Assert(!value.IsEmpty); - - return IndexOfOrdinalCore(source, value, ignoreCase: true, fromBeginning: true); - } - - internal int LastIndexOfOrdinal(ReadOnlySpan source, ReadOnlySpan value, bool ignoreCase) - { - Debug.Assert(!GlobalizationMode.Invariant); - Debug.Assert(!source.IsEmpty); - Debug.Assert(!value.IsEmpty); - return IndexOfOrdinalCore(source, value, ignoreCase, fromBeginning: false); - } - - internal unsafe int IndexOf(ReadOnlySpan source, ReadOnlySpan value, CompareOptions options) - { - Debug.Assert(!GlobalizationMode.Invariant); - Debug.Assert(!source.IsEmpty); - Debug.Assert(!value.IsEmpty); - return IndexOfCore(source, value, options, null, fromBeginning: true); - } - - internal unsafe int LastIndexOf(ReadOnlySpan source, ReadOnlySpan value, CompareOptions options) - { - Debug.Assert(!GlobalizationMode.Invariant); - Debug.Assert(!source.IsEmpty); - Debug.Assert(!value.IsEmpty); - return IndexOfCore(source, value, options, null, fromBeginning: false); } /// /// The following IndexOf overload is mainly used by String.Replace. This overload assumes the parameters are already validated /// and the caller is passing a valid matchLengthPtr pointer. /// - internal unsafe int IndexOf(string source, string value, int startIndex, int count, CompareOptions options, int* matchLengthPtr, bool fromBeginning = true) + internal unsafe int IndexOf(ReadOnlySpan source, ReadOnlySpan value, int* matchLengthPtr, CompareOptions options, bool fromBeginning) + { + Debug.Assert(matchLengthPtr != null); + *matchLengthPtr = 0; + + if ((options & ValidIndexMaskOffFlags) == 0) + { + // Common case: caller is attempting to perform a linguistic search. + // Pass the flags down to NLS or ICU unless we're running in invariant + // mode, at which point we normalize the flags to Orginal[IgnoreCase]. + + if (!GlobalizationMode.Invariant) + { + if (value.IsEmpty) + { + // empty target substring trivially occurs at beginning / end of search space + return (fromBeginning) ? 0 : source.Length; + } + else + { + return IndexOfCore(source, value, options, matchLengthPtr, fromBeginning); + } + } + else if ((options & CompareOptions.IgnoreCase) == 0) + { + goto ReturnOrdinal; + } + else + { + goto ReturnOrdinalIgnoreCase; + } + } + else + { + // Less common case: caller is attempting to perform non-linguistic comparison, + // or an invalid combination of flags was supplied. + + if (options == CompareOptions.Ordinal) + { + goto ReturnOrdinal; + } + else if (options == CompareOptions.OrdinalIgnoreCase) + { + goto ReturnOrdinalIgnoreCase; + } + else + { + ThrowHelper.ThrowArgumentException(ExceptionResource.Argument_InvalidFlag, ExceptionArgument.options); + } + } + + ReturnOrdinal: + int retVal = (fromBeginning) ? source.IndexOf(value) : source.LastIndexOf(value); + goto OrdinalReturn; + + ReturnOrdinalIgnoreCase: + retVal = IndexOfOrdinalIgnoreCase(source, value, fromBeginning); + goto OrdinalReturn; + + OrdinalReturn: + // Both Ordinal and OrdinalIgnoreCase match by individual code points in a non-linguistic manner. + // Non-BMP code points will never match BMP code points, so given UTF-16 inputs the match length + // will always be equivalent to the target string length. + + if (retVal >= 0) + { + *matchLengthPtr = value.Length; + } + return retVal; + } + + private unsafe int IndexOfCore(ReadOnlySpan source, ReadOnlySpan target, CompareOptions options, int* matchLengthPtr, bool fromBeginning) => + GlobalizationMode.UseNls ? + NlsIndexOfCore(source, target, options, matchLengthPtr, fromBeginning) : + IcuIndexOfCore(source, target, options, matchLengthPtr, fromBeginning); + + internal static int IndexOfOrdinal(string source, string value, int startIndex, int count, bool ignoreCase) { Debug.Assert(source != null); Debug.Assert(value != null); - Debug.Assert(startIndex >= 0); + Debug.Assert((uint)startIndex <= (uint)source.Length); + Debug.Assert((uint)count <= (uint)(source.Length - startIndex)); - if (matchLengthPtr != null) - { - *matchLengthPtr = 0; - } + // For ordinal (non-linguistic) comparisons, an empty target string is always + // found at the beginning of the search space, and a non-empty target string + // can never be found within an empty search space. This assumption is not + // valid for linguistic comparisons, including InvariantCulture comparisons. if (value.Length == 0) { return startIndex; } - if (startIndex >= source.Length) + if (count == 0) { return -1; } - if (options == CompareOptions.OrdinalIgnoreCase) - { - int res; - if (fromBeginning) - { - res = IndexOfOrdinal(source, value, startIndex, count, ignoreCase: true); - } - else - { - res = LastIndexOfOrdinal(source, value, startIndex, count, ignoreCase: true); - } + int result; - if (res >= 0 && matchLengthPtr != null) - { - *matchLengthPtr = value.Length; - } - return res; - } - - if (GlobalizationMode.Invariant) - { - bool ignoreCase = (options & (CompareOptions.IgnoreCase | CompareOptions.OrdinalIgnoreCase)) != 0; - int res; - - if (fromBeginning) - { - res = IndexOfOrdinal(source, value, startIndex, count, ignoreCase); - } - else - { - res = LastIndexOfOrdinal(source, value, startIndex, count, ignoreCase); - } - - if (res >= 0 && matchLengthPtr != null) - { - *matchLengthPtr = value.Length; - } - return res; - } - - if (options == CompareOptions.Ordinal) - { - int retValue; - - if (fromBeginning) - { - retValue = SpanHelpers.IndexOf( - ref Unsafe.Add(ref source.GetRawStringData(), startIndex), - count, - ref value.GetRawStringData(), - value.Length); - } - else - { - retValue = SpanHelpers.LastIndexOf( - ref Unsafe.Add(ref source.GetRawStringData(), startIndex), - count, - ref value.GetRawStringData(), - value.Length); - } - - if (retValue >= 0) - { - retValue += startIndex; - if (matchLengthPtr != null) - { - *matchLengthPtr = value.Length; - } - } - - return retValue; - } - else - { - if (fromBeginning) - { - // Call the string-based overload, as it special-cases IsFastSort as a perf optimization. - return IndexOfCore(source, value, startIndex, count, options, matchLengthPtr); - } - else - { - return IndexOfCore(source.AsSpan(startIndex, count), value, options, matchLengthPtr, fromBeginning: false); - } - } - } - - internal static int IndexOfOrdinal(string source, string value, int startIndex, int count, bool ignoreCase) - { if (!ignoreCase) { - int result = SpanHelpers.IndexOf( + result = SpanHelpers.IndexOf( ref Unsafe.Add(ref source.GetRawStringData(), startIndex), count, ref value.GetRawStringData(), value.Length); - - return (result >= 0 ? startIndex : 0) + result; } - - if (GlobalizationMode.Invariant) + else if (GlobalizationMode.Invariant) { - return InvariantIndexOf(source, value, startIndex, count, ignoreCase); + result = InvariantIndexOf(source.AsSpan(startIndex, count), value, ignoreCase, fromBeginning: true); + } + else + { + result = IndexOfOrdinalCore(source.AsSpan(startIndex, count), value, ignoreCase, fromBeginning: true); } - return IndexOfOrdinalCore(source, value, startIndex, count, ignoreCase); + if (result >= 0) + { + result += startIndex; + } + return result; } /// @@ -1137,51 +1335,40 @@ namespace System.Globalization /// the specified value is not found. If value equals string.Empty, /// endIndex is returned. Throws IndexOutOfRange if startIndex or /// endIndex is less than zero or greater than the length of string. - /// Throws ArgumentException if value is null. + /// Throws ArgumentException if value (as a string) is null. /// public int LastIndexOf(string source, char value) { - if (source == null) - { - throw new ArgumentNullException(nameof(source)); - } - - // Can't start at negative index, so make sure we check for the length == 0 case. - return LastIndexOf(source, value, source.Length - 1, source.Length, CompareOptions.None); + return LastIndexOf(source, value, CompareOptions.None); } public int LastIndexOf(string source, string value) { - if (source == null) - { - throw new ArgumentNullException(nameof(source)); - } - - // Can't start at negative index, so make sure we check for the length == 0 case. - return LastIndexOf(source, value, source.Length - 1, - source.Length, CompareOptions.None); + return LastIndexOf(source, value, CompareOptions.None); } public int LastIndexOf(string source, char value, CompareOptions options) { if (source == null) { - throw new ArgumentNullException(nameof(source)); + ThrowHelper.ThrowArgumentNullException(ExceptionArgument.source); } - // Can't start at negative index, so make sure we check for the length == 0 case. - return LastIndexOf(source, value, source.Length - 1, source.Length, options); + return LastIndexOf(source, MemoryMarshal.CreateReadOnlySpan(ref value, 1), options); } public int LastIndexOf(string source, string value, CompareOptions options) { if (source == null) { - throw new ArgumentNullException(nameof(source)); + ThrowHelper.ThrowArgumentNullException(ExceptionArgument.source); + } + if (value == null) + { + ThrowHelper.ThrowArgumentNullException(ExceptionArgument.value); } - // Can't start at negative index, so make sure we check for the length == 0 case. - return LastIndexOf(source, value, source.Length - 1, source.Length, options); + return LastIndexOf(source.AsSpan(), value.AsSpan(), options); } public int LastIndexOf(string source, char value, int startIndex) @@ -1218,129 +1405,235 @@ namespace System.Globalization { if (source == null) { - throw new ArgumentNullException(nameof(source)); - } - // Validate CompareOptions - // Ordinal can't be selected with other flags - if ((options & ValidIndexMaskOffFlags) != 0 && - (options != CompareOptions.Ordinal) && - (options != CompareOptions.OrdinalIgnoreCase)) - { - throw new ArgumentException(SR.Argument_InvalidFlag, nameof(options)); + ThrowHelper.ThrowArgumentNullException(ExceptionArgument.source); } - // Special case for 0 length input strings - if (source.Length == 0 && (startIndex == -1 || startIndex == 0)) - { - return -1; - } + TryAgain: - // Make sure we're not out of range - if (startIndex < 0 || startIndex > source.Length) - { - throw new ArgumentOutOfRangeException(nameof(startIndex), SR.ArgumentOutOfRange_Index); - } + // Previous versions of the Framework special-cased empty 'source' to allow startIndex = -1 or startIndex = 0, + // ignoring 'count' and short-circuiting the entire operation. We'll silently fix up the 'count' parameter + // if this occurs. + // + // See the comments just before string.IndexOf(string) for more information on how these computations are + // performed. - // Make sure that we allow startIndex == source.Length - if (startIndex == source.Length) + if ((uint)startIndex >= (uint)source.Length) { - startIndex--; - if (count > 0) + if (startIndex == -1 && source.Length == 0) { - count--; + count = 0; // normalize + } + else if (startIndex == source.Length) + { + // The caller likely had an off-by-one error when invoking the API. The Framework has historically + // allowed for this and tried to fix up the parameters, so we'll continue to do so for compat. + + startIndex--; + if (count > 0) + { + count--; + } + + goto TryAgain; // guaranteed never to loop more than once + } + else + { + ThrowHelper.ThrowArgumentOutOfRangeException(ExceptionArgument.startIndex, ExceptionResource.ArgumentOutOfRange_Index); } } - // 2nd have of this also catches when startIndex == MAXINT, so MAXINT - 0 + 1 == -1, which is < 0. - if (count < 0 || startIndex - count + 1 < 0) + startIndex = startIndex - count + 1; // this will be the actual index where we begin our search + + if (!source.TryGetSpan(startIndex, count, out ReadOnlySpan sourceSpan)) { - throw new ArgumentOutOfRangeException(nameof(count), SR.ArgumentOutOfRange_Count); + ThrowHelper.ThrowCountArgumentOutOfRange_ArgumentOutOfRange_Count(); } - if (options == CompareOptions.OrdinalIgnoreCase) + int retVal = LastIndexOf(sourceSpan, MemoryMarshal.CreateReadOnlySpan(ref value, 1), options); + if (retVal >= 0) { - return source.LastIndexOf(value.ToString(), startIndex, count, StringComparison.OrdinalIgnoreCase); + retVal += startIndex; } - - if (GlobalizationMode.Invariant) - { - return InvariantLastIndexOf(source, char.ToString(value), startIndex, count, (options & (CompareOptions.IgnoreCase | CompareOptions.OrdinalIgnoreCase)) != 0); - } - - return LastIndexOfCore(source, value.ToString(), startIndex, count, options); + return retVal; } public int LastIndexOf(string source, string value, int startIndex, int count, CompareOptions options) { if (source == null) { - throw new ArgumentNullException(nameof(source)); + ThrowHelper.ThrowArgumentNullException(ExceptionArgument.source); } if (value == null) { - throw new ArgumentNullException(nameof(value)); + ThrowHelper.ThrowArgumentNullException(ExceptionArgument.value); } - // Validate CompareOptions - // Ordinal can't be selected with other flags - if ((options & ValidIndexMaskOffFlags) != 0 && - (options != CompareOptions.Ordinal) && - (options != CompareOptions.OrdinalIgnoreCase)) - throw new ArgumentException(SR.Argument_InvalidFlag, nameof(options)); + TryAgain: - // Special case for 0 length input strings - if (source.Length == 0 && (startIndex == -1 || startIndex == 0)) - { - return (value.Length == 0) ? 0 : -1; - } + // Previous versions of the Framework special-cased empty 'source' to allow startIndex = -1 or startIndex = 0, + // ignoring 'count' and short-circuiting the entire operation. We'll silently fix up the 'count' parameter + // if this occurs. + // + // See the comments just before string.IndexOf(string) for more information on how these computations are + // performed. - // Make sure we're not out of range - if (startIndex < 0 || startIndex > source.Length) + if ((uint)startIndex >= (uint)source.Length) { - throw new ArgumentOutOfRangeException(nameof(startIndex), SR.ArgumentOutOfRange_Index); - } - - // Make sure that we allow startIndex == source.Length - if (startIndex == source.Length) - { - startIndex--; - if (count > 0) + if (startIndex == -1 && source.Length == 0) { - count--; + count = 0; // normalize } - - // If we are looking for nothing, just return 0 - if (value.Length == 0 && count >= 0 && startIndex - count + 1 >= 0) + else if (startIndex == source.Length) { - return startIndex; + // The caller likely had an off-by-one error when invoking the API. The Framework has historically + // allowed for this and tried to fix up the parameters, so we'll continue to do so for compat. + + startIndex--; + if (count > 0) + { + count--; + } + + goto TryAgain; // guaranteed never to loop more than once + } + else + { + ThrowHelper.ThrowArgumentOutOfRangeException(ExceptionArgument.startIndex, ExceptionResource.ArgumentOutOfRange_Index); } } - // 2nd half of this also catches when startIndex == MAXINT, so MAXINT - 0 + 1 == -1, which is < 0. - if (count < 0 || startIndex - count + 1 < 0) + startIndex = startIndex - count + 1; // this will be the actual index where we begin our search + + if (!source.TryGetSpan(startIndex, count, out ReadOnlySpan sourceSpan)) { - throw new ArgumentOutOfRangeException(nameof(count), SR.ArgumentOutOfRange_Count); + ThrowHelper.ThrowCountArgumentOutOfRange_ArgumentOutOfRange_Count(); } - if (options == CompareOptions.OrdinalIgnoreCase) + int retVal = LastIndexOf(sourceSpan, value, options); + if (retVal >= 0) { - return LastIndexOfOrdinal(source, value, startIndex, count, ignoreCase: true); + retVal += startIndex; + } + return retVal; + } + + /// + /// Searches for the last occurrence of a substring within a source string. + /// + /// The string to search within. + /// The substring to locate within . + /// The to use during the search. + /// + /// The zero-based index into where the substring + /// last appears; or -1 if cannot be found within . + /// + /// + /// contains an unsupported combination of flags. + /// + public unsafe int LastIndexOf(ReadOnlySpan source, ReadOnlySpan value, CompareOptions options = CompareOptions.None) + { + if ((options & ValidIndexMaskOffFlags) == 0) + { + // Common case: caller is attempting to perform a linguistic search. + // Pass the flags down to NLS or ICU unless we're running in invariant + // mode, at which point we normalize the flags to Orginal[IgnoreCase]. + + if (!GlobalizationMode.Invariant) + { + if (value.IsEmpty) + { + return source.Length; // Empty target string trivially occurs at the last index of every search space. + } + else + { + return IndexOfCore(source, value, options, null /* matchLengthPtr */, fromBeginning: false); + } + } + else if ((options & CompareOptions.IgnoreCase) == 0) + { + goto ReturnOrdinal; + } + else + { + goto ReturnOrdinalIgnoreCase; + } + } + else + { + // Less common case: caller is attempting to perform non-linguistic comparison, + // or an invalid combination of flags was supplied. + + if (options == CompareOptions.Ordinal) + { + goto ReturnOrdinal; + } + else if (options == CompareOptions.OrdinalIgnoreCase) + { + goto ReturnOrdinalIgnoreCase; + } + else + { + throw new ArgumentException( + paramName: nameof(options), + message: SR.Argument_InvalidFlag); + } } - if (GlobalizationMode.Invariant) - return InvariantLastIndexOf(source, value, startIndex, count, (options & (CompareOptions.IgnoreCase | CompareOptions.OrdinalIgnoreCase)) != 0); + ReturnOrdinal: + return source.LastIndexOf(value); - return LastIndexOfCore(source, value, startIndex, count, options); + ReturnOrdinalIgnoreCase: + return IndexOfOrdinalIgnoreCase(source, value, fromBeginning: false); + } + + /// + /// Searches for the last occurrence of a within a source string. + /// + /// The string to search within. + /// The to locate within . + /// The to use during the search. + /// + /// The zero-based index into where + /// last appears; or -1 if cannot be found within . + /// + /// + /// contains an unsupported combination of flags. + /// + public unsafe int LastIndexOf(ReadOnlySpan source, Rune value, CompareOptions options = CompareOptions.None) + { + Span valueAsUtf16 = stackalloc char[Rune.MaxUtf16CharsPerRune]; + int charCount = value.EncodeToUtf16(valueAsUtf16); + return LastIndexOf(source, valueAsUtf16.Slice(0, charCount), options); } internal static int LastIndexOfOrdinal(string source, string value, int startIndex, int count, bool ignoreCase) { + Debug.Assert(!string.IsNullOrEmpty(source)); + Debug.Assert(value != null); + if (GlobalizationMode.Invariant) { return InvariantLastIndexOf(source, value, startIndex, count, ignoreCase); } - return LastIndexOfOrdinalCore(source, value, startIndex, count, ignoreCase); + // For ordinal (non-linguistic) comparisons, an empty target string is always + // found at the end of the search space, and a non-empty target string + // can never be found within an empty search space. This assumption is not + // valid for linguistic comparisons, including InvariantCulture comparisons. + + if (value.Length == 0) + { + return startIndex + 1; // startIndex is the index of the last char to include in the search space + } + + if (count == 0) + { + return -1; + } + + return GlobalizationMode.UseNls ? + NlsLastIndexOfOrdinalCore(source, value, startIndex, count, ignoreCase) : + IcuLastIndexOfOrdinalCore(source, value, startIndex, count, ignoreCase); } /// @@ -1353,7 +1646,7 @@ namespace System.Globalization return InvariantCreateSortKey(source, options); } - return CreateSortKey(source, options); + return CreateSortKeyCore(source, options); } public SortKey GetSortKey(string source) @@ -1363,9 +1656,86 @@ namespace System.Globalization return InvariantCreateSortKey(source, CompareOptions.None); } - return CreateSortKey(source, CompareOptions.None); + return CreateSortKeyCore(source, CompareOptions.None); } + private SortKey CreateSortKeyCore(string source, CompareOptions options) => + GlobalizationMode.UseNls ? + NlsCreateSortKey(source, options) : + IcuCreateSortKey(source, options); + + /// + /// Computes a sort key over the specified input. + /// + /// The text over which to compute the sort key. + /// The buffer into which to write the resulting sort key bytes. + /// The used for computing the sort key. + /// The number of bytes written to . + /// + /// Use to query the required size of . + /// It is acceptable to provide a larger-than-necessary output buffer to this method. + /// + /// + /// is too small to contain the resulting sort key; + /// or contains an unsupported flag; + /// or cannot be processed using the desired + /// under the current . + /// + public int GetSortKey(ReadOnlySpan source, Span destination, CompareOptions options = CompareOptions.None) + { + if ((options & ValidCompareMaskOffFlags) != 0) + { + ThrowHelper.ThrowArgumentException(ExceptionResource.Argument_InvalidFlag, ExceptionArgument.options); + } + + if (GlobalizationMode.Invariant) + { + return InvariantGetSortKey(source, destination, options); + } + else + { + return GetSortKeyCore(source, destination, options); + } + } + + private int GetSortKeyCore(ReadOnlySpan source, Span destination, CompareOptions options) => + GlobalizationMode.UseNls ? + NlsGetSortKey(source, destination, options) : + IcuGetSortKey(source, destination, options); + + /// + /// Returns the length (in bytes) of the sort key that would be produced from the specified input. + /// + /// The text over which to compute the sort key. + /// The used for computing the sort key. + /// The length (in bytes) of the sort key. + /// + /// contains an unsupported flag; + /// or cannot be processed using the desired + /// under the current . + /// + public int GetSortKeyLength(ReadOnlySpan source, CompareOptions options = CompareOptions.None) + { + if ((options & ValidCompareMaskOffFlags) != 0) + { + ThrowHelper.ThrowArgumentException(ExceptionResource.Argument_InvalidFlag, ExceptionArgument.options); + } + + if (GlobalizationMode.Invariant) + { + return InvariantGetSortKeyLength(source, options); + } + else + { + return GetSortKeyLengthCore(source, options); + } + } + + private int GetSortKeyLengthCore(ReadOnlySpan source, CompareOptions options) => + GlobalizationMode.UseNls ? + NlsGetSortKeyLength(source, options) : + IcuGetSortKeyLength(source, options); + public override bool Equals(object? value) { return value is CompareInfo otherCompareInfo @@ -1387,64 +1757,64 @@ namespace System.Globalization { if (source == null) { - throw new ArgumentNullException(nameof(source)); + ThrowHelper.ThrowArgumentNullException(ExceptionArgument.source); } - if ((options & ValidCompareMaskOffFlags) == 0) - { - // No unsupported flags are set - continue on with the regular logic - if (GlobalizationMode.Invariant) - { - return ((options & CompareOptions.IgnoreCase) != 0) ? source.GetHashCodeOrdinalIgnoreCase() : source.GetHashCode(); - } - return GetHashCodeOfStringCore(source, options); - } - else if (options == CompareOptions.Ordinal) - { - // We allow Ordinal in isolation - return source.GetHashCode(); - } - else if (options == CompareOptions.OrdinalIgnoreCase) - { - // We allow OrdinalIgnoreCase in isolation - return source.GetHashCodeOrdinalIgnoreCase(); - } - else - { - // Unsupported combination of flags specified - throw new ArgumentException(SR.Argument_InvalidFlag, nameof(options)); - } + return GetHashCode(source.AsSpan(), options); } public int GetHashCode(ReadOnlySpan source, CompareOptions options) { if ((options & ValidCompareMaskOffFlags) == 0) { - // No unsupported flags are set - continue on with the regular logic - if (GlobalizationMode.Invariant) - { - return ((options & CompareOptions.IgnoreCase) != 0) ? string.GetHashCodeOrdinalIgnoreCase(source) : string.GetHashCode(source); - } + // Common case: caller is attempting to get a linguistic sort key. + // Pass the flags down to NLS or ICU unless we're running in invariant + // mode, at which point we normalize the flags to Orginal[IgnoreCase]. - return GetHashCodeOfStringCore(source, options); - } - else if (options == CompareOptions.Ordinal) - { - // We allow Ordinal in isolation - return string.GetHashCode(source); - } - else if (options == CompareOptions.OrdinalIgnoreCase) - { - // We allow OrdinalIgnoreCase in isolation - return string.GetHashCodeOrdinalIgnoreCase(source); + if (!GlobalizationMode.Invariant) + { + return GetHashCodeOfStringCore(source, options); + } + else if ((options & CompareOptions.IgnoreCase) == 0) + { + goto ReturnOrdinal; + } + else + { + goto ReturnOrdinalIgnoreCase; + } } else { - // Unsupported combination of flags specified - throw new ArgumentException(SR.Argument_InvalidFlag, nameof(options)); + // Less common case: caller is attempting to get a non-linguistic sort key, + // or an invalid combination of flags was supplied. + + if (options == CompareOptions.Ordinal) + { + goto ReturnOrdinal; + } + else if (options == CompareOptions.OrdinalIgnoreCase) + { + goto ReturnOrdinalIgnoreCase; + } + else + { + ThrowCompareOptionsCheckFailed(options); + } } + + ReturnOrdinal: + return string.GetHashCode(source); + + ReturnOrdinalIgnoreCase: + return string.GetHashCodeOrdinalIgnoreCase(source); } + private unsafe int GetHashCodeOfStringCore(ReadOnlySpan source, CompareOptions options) => + GlobalizationMode.UseNls ? + NlsGetHashCodeOfString(source, options) : + IcuGetHashCodeOfString(source, options); + public override string ToString() => "CompareInfo - " + Name; public SortVersion Version @@ -1463,7 +1833,7 @@ namespace System.Globalization } else { - m_SortVersion = GetSortVersion(); + m_SortVersion = GlobalizationMode.UseNls ? NlsGetSortVersion() : IcuGetSortVersion(); } } diff --git a/src/System.Private.CoreLib/shared/System/Globalization/CultureData.Unix.cs b/src/System.Private.CoreLib/shared/System/Globalization/CultureData.Icu.cs similarity index 70% rename from src/System.Private.CoreLib/shared/System/Globalization/CultureData.Unix.cs rename to src/System.Private.CoreLib/shared/System/Globalization/CultureData.Icu.cs index e429353a0..452a75fb1 100644 --- a/src/System.Private.CoreLib/shared/System/Globalization/CultureData.Unix.cs +++ b/src/System.Private.CoreLib/shared/System/Globalization/CultureData.Icu.cs @@ -2,12 +2,8 @@ // 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; using System.Collections.Generic; using System.Diagnostics; -using System.Runtime.InteropServices; -using System.Security; -using System.Text; namespace System.Globalization { @@ -22,11 +18,12 @@ namespace System.Globalization /// This method uses the sRealName field (which is initialized by the constructor before this is called) to /// initialize the rest of the state of CultureData based on the underlying OS globalization library. /// - private unsafe bool InitCultureData() + private unsafe bool IcuInitCultureData() { Debug.Assert(_sRealName != null); Debug.Assert(!GlobalizationMode.Invariant); + Debug.Assert(!GlobalizationMode.UseNls); string realNameBuffer = _sRealName; @@ -77,7 +74,7 @@ namespace System.Globalization _bNeutral = TwoLetterISOCountryName.Length == 0; - _sSpecificCulture = _bNeutral ? LocaleData.GetSpecificCultureName(_sRealName) : _sRealName; + _sSpecificCulture = _bNeutral ? IcuLocaleData.GetSpecificCultureName(_sRealName) : _sRealName; // Remove the sort from sName unless custom culture if (index > 0 && !_bNeutral && !IsCustomCultureId(_iLanguage)) @@ -117,26 +114,28 @@ namespace System.Globalization return true; } - private string GetLocaleInfo(LocaleStringData type) + private string IcuGetLocaleInfo(LocaleStringData type) { Debug.Assert(!GlobalizationMode.Invariant); + Debug.Assert(!GlobalizationMode.UseNls); - Debug.Assert(_sWindowsName != null, "[CultureData.GetLocaleInfo] Expected _sWindowsName to be populated already"); - return GetLocaleInfo(_sWindowsName, type); + Debug.Assert(_sWindowsName != null, "[CultureData.IcuGetLocaleInfo] Expected _sWindowsName to be populated already"); + return IcuGetLocaleInfo(_sWindowsName, type); } // For LOCALE_SPARENT we need the option of using the "real" name (forcing neutral names) instead of the // "windows" name, which can be specific for downlevel (< windows 7) os's. - private unsafe string GetLocaleInfo(string localeName, LocaleStringData type) + private unsafe string IcuGetLocaleInfo(string localeName, LocaleStringData type) { - Debug.Assert(localeName != null, "[CultureData.GetLocaleInfo] Expected localeName to be not be null"); + Debug.Assert(!GlobalizationMode.UseNls); + Debug.Assert(localeName != null, "[CultureData.IcuGetLocaleInfo] Expected localeName to be not be null"); switch (type) { case LocaleStringData.NegativeInfinitySymbol: // not an equivalent in ICU; prefix the PositiveInfinitySymbol with NegativeSign - return GetLocaleInfo(localeName, LocaleStringData.NegativeSign) + - GetLocaleInfo(localeName, LocaleStringData.PositiveInfinitySymbol); + return IcuGetLocaleInfo(localeName, LocaleStringData.NegativeSign) + + IcuGetLocaleInfo(localeName, LocaleStringData.PositiveInfinitySymbol); } char* buffer = stackalloc char[ICU_ULOC_KEYWORD_AND_VALUES_CAPACITY]; @@ -144,18 +143,18 @@ namespace System.Globalization if (!result) { // Failed, just use empty string - Debug.Fail("[CultureData.GetLocaleInfo(LocaleStringData)] Failed"); + Debug.Fail("[CultureData.IcuGetLocaleInfo(LocaleStringData)] Failed"); return string.Empty; } return new string(buffer); } - private int GetLocaleInfo(LocaleNumberData type) + private int IcuGetLocaleInfo(LocaleNumberData type) { - Debug.Assert(!GlobalizationMode.Invariant); + Debug.Assert(!GlobalizationMode.UseNls); - Debug.Assert(_sWindowsName != null, "[CultureData.GetLocaleInfo(LocaleNumberData)] Expected _sWindowsName to be populated already"); + Debug.Assert(_sWindowsName != null, "[CultureData.IcuGetLocaleInfo(LocaleNumberData)] Expected _sWindowsName to be populated already"); switch (type) { @@ -170,22 +169,23 @@ namespace System.Globalization if (!result) { // Failed, just use 0 - Debug.Fail("[CultureData.GetLocaleInfo(LocaleNumberData)] failed"); + Debug.Fail("[CultureData.IcuGetLocaleInfo(LocaleNumberData)] failed"); } return value; } - private int[] GetLocaleInfo(LocaleGroupingData type) + private int[] IcuGetLocaleInfo(LocaleGroupingData type) { - Debug.Assert(_sWindowsName != null, "[CultureData.GetLocaleInfo(LocaleGroupingData)] Expected _sWindowsName to be populated already"); + Debug.Assert(!GlobalizationMode.UseNls); + Debug.Assert(_sWindowsName != null, "[CultureData.IcuGetLocaleInfo(LocaleGroupingData)] Expected _sWindowsName to be populated already"); int primaryGroupingSize = 0; int secondaryGroupingSize = 0; bool result = Interop.Globalization.GetLocaleInfoGroupingSizes(_sWindowsName, (uint)type, ref primaryGroupingSize, ref secondaryGroupingSize); if (!result) { - Debug.Fail("[CultureData.GetLocaleInfo(LocaleGroupingData type)] failed"); + Debug.Fail("[CultureData.IcuGetLocaleInfo(LocaleGroupingData type)] failed"); } if (secondaryGroupingSize == 0) @@ -196,10 +196,11 @@ namespace System.Globalization return new int[] { primaryGroupingSize, secondaryGroupingSize }; } - private string GetTimeFormatString() => GetTimeFormatString(shortFormat: false); + private string IcuGetTimeFormatString() => IcuGetTimeFormatString(shortFormat: false); - private unsafe string GetTimeFormatString(bool shortFormat) + private unsafe string IcuGetTimeFormatString(bool shortFormat) { + Debug.Assert(!GlobalizationMode.UseNls); Debug.Assert(_sWindowsName != null, "[CultureData.GetTimeFormatString(bool shortFormat)] Expected _sWindowsName to be populated already"); char* buffer = stackalloc char[ICU_ULOC_KEYWORD_AND_VALUES_CAPACITY]; @@ -216,32 +217,32 @@ namespace System.Globalization return ConvertIcuTimeFormatString(span.Slice(0, span.IndexOf('\0'))); } - private int GetFirstDayOfWeek() => GetLocaleInfo(LocaleNumberData.FirstDayOfWeek); + private int IcuGetFirstDayOfWeek() => IcuGetLocaleInfo(LocaleNumberData.FirstDayOfWeek); - private string[] GetTimeFormats() + private string[] IcuGetTimeFormats() { - string format = GetTimeFormatString(false); + string format = IcuGetTimeFormatString(false); return new string[] { format }; } - private string[] GetShortTimeFormats() + private string[] IcuGetShortTimeFormats() { - string format = GetTimeFormatString(true); + string format = IcuGetTimeFormatString(true); return new string[] { format }; } - private static CultureData? GetCultureDataFromRegionName(string? regionName) + private static CultureData? IcuGetCultureDataFromRegionName(string? regionName) { // no support to lookup by region name, other than the hard-coded list in CultureData return null; } - private static string GetLanguageDisplayName(string cultureName) + private static string IcuGetLanguageDisplayName(string cultureName) { - return new CultureInfo(cultureName)._cultureData.GetLocaleInfo(cultureName, LocaleStringData.LocalizedDisplayName); + return new CultureInfo(cultureName)._cultureData.IcuGetLocaleInfo(cultureName, LocaleStringData.LocalizedDisplayName); } - private static string? GetRegionDisplayName() + private static string? IcuGetRegionDisplayName() { // use the fallback which is to return NativeName return null; @@ -303,65 +304,75 @@ namespace System.Globalization return result.Slice(0, resultPos).ToString(); } - private static string? LCIDToLocaleName(int culture) + private static string? IcuLCIDToLocaleName(int culture) { Debug.Assert(!GlobalizationMode.Invariant); + Debug.Assert(!GlobalizationMode.UseNls); - return LocaleData.LCIDToLocaleName(culture); + return IcuLocaleData.LCIDToLocaleName(culture); } - private static int LocaleNameToLCID(string cultureName) + private static int IcuLocaleNameToLCID(string cultureName) { Debug.Assert(!GlobalizationMode.Invariant); + Debug.Assert(!GlobalizationMode.UseNls); - int lcid = LocaleData.GetLocaleDataNumericPart(cultureName, LocaleDataParts.Lcid); + int lcid = IcuLocaleData.GetLocaleDataNumericPart(cultureName, IcuLocaleDataParts.Lcid); return lcid == -1 ? CultureInfo.LOCALE_CUSTOM_UNSPECIFIED : lcid; } - private static int GetAnsiCodePage(string cultureName) + private static int IcuGetAnsiCodePage(string cultureName) { - int ansiCodePage = LocaleData.GetLocaleDataNumericPart(cultureName, LocaleDataParts.AnsiCodePage); + Debug.Assert(!GlobalizationMode.UseNls); + int ansiCodePage = IcuLocaleData.GetLocaleDataNumericPart(cultureName, IcuLocaleDataParts.AnsiCodePage); return ansiCodePage == -1 ? CultureData.Invariant.ANSICodePage : ansiCodePage; } - private static int GetOemCodePage(string cultureName) + private static int IcuGetOemCodePage(string cultureName) { - int oemCodePage = LocaleData.GetLocaleDataNumericPart(cultureName, LocaleDataParts.OemCodePage); + Debug.Assert(!GlobalizationMode.UseNls); + int oemCodePage = IcuLocaleData.GetLocaleDataNumericPart(cultureName, IcuLocaleDataParts.OemCodePage); return oemCodePage == -1 ? CultureData.Invariant.OEMCodePage : oemCodePage; } - private static int GetMacCodePage(string cultureName) + private static int IcuGetMacCodePage(string cultureName) { - int macCodePage = LocaleData.GetLocaleDataNumericPart(cultureName, LocaleDataParts.MacCodePage); + Debug.Assert(!GlobalizationMode.UseNls); + int macCodePage = IcuLocaleData.GetLocaleDataNumericPart(cultureName, IcuLocaleDataParts.MacCodePage); return macCodePage == -1 ? CultureData.Invariant.MacCodePage : macCodePage; } - private static int GetEbcdicCodePage(string cultureName) + private static int IcuGetEbcdicCodePage(string cultureName) { - int ebcdicCodePage = LocaleData.GetLocaleDataNumericPart(cultureName, LocaleDataParts.EbcdicCodePage); + Debug.Assert(!GlobalizationMode.UseNls); + int ebcdicCodePage = IcuLocaleData.GetLocaleDataNumericPart(cultureName, IcuLocaleDataParts.EbcdicCodePage); return ebcdicCodePage == -1 ? CultureData.Invariant.EBCDICCodePage : ebcdicCodePage; } - private static int GetGeoId(string cultureName) + private static int IcuGetGeoId(string cultureName) { - int geoId = LocaleData.GetLocaleDataNumericPart(cultureName, LocaleDataParts.GeoId); + Debug.Assert(!GlobalizationMode.UseNls); + int geoId = IcuLocaleData.GetLocaleDataNumericPart(cultureName, IcuLocaleDataParts.GeoId); return geoId == -1 ? CultureData.Invariant.GeoId : geoId; } - private static int GetDigitSubstitution(string cultureName) + private static int IcuGetDigitSubstitution(string cultureName) { - int digitSubstitution = LocaleData.GetLocaleDataNumericPart(cultureName, LocaleDataParts.DigitSubstitution); + Debug.Assert(!GlobalizationMode.UseNls); + int digitSubstitution = IcuLocaleData.GetLocaleDataNumericPart(cultureName, IcuLocaleDataParts.DigitSubstitution); return digitSubstitution == -1 ? (int) DigitShapes.None : digitSubstitution; } - private static string GetThreeLetterWindowsLanguageName(string cultureName) + private static string IcuGetThreeLetterWindowsLanguageName(string cultureName) { - return LocaleData.GetThreeLetterWindowsLanguageName(cultureName) ?? "ZZZ" /* default lang name */; + Debug.Assert(!GlobalizationMode.UseNls); + return IcuLocaleData.GetThreeLetterWindowsLanguageName(cultureName) ?? "ZZZ" /* default lang name */; } - private static CultureInfo[] EnumCultures(CultureTypes types) + private static CultureInfo[] IcuEnumCultures(CultureTypes types) { Debug.Assert(!GlobalizationMode.Invariant); + Debug.Assert(!GlobalizationMode.UseNls); if ((types & (CultureTypes.NeutralCultures | CultureTypes.SpecificCultures)) == 0) { @@ -410,13 +421,10 @@ namespace System.Globalization return list.ToArray(); } - private static string GetConsoleFallbackName(string cultureName) + private static string IcuGetConsoleFallbackName(string cultureName) { - return LocaleData.GetConsoleUICulture(cultureName); + Debug.Assert(!GlobalizationMode.UseNls); + return IcuLocaleData.GetConsoleUICulture(cultureName); } - - internal bool IsWin32Installed => false; - - internal bool IsReplacementCulture => false; } } diff --git a/src/System.Private.CoreLib/shared/System/Globalization/CultureData.Windows.cs b/src/System.Private.CoreLib/shared/System/Globalization/CultureData.Nls.cs similarity index 84% rename from src/System.Private.CoreLib/shared/System/Globalization/CultureData.Windows.cs rename to src/System.Private.CoreLib/shared/System/Globalization/CultureData.Nls.cs index b8ae40837..49a2b1d06 100644 --- a/src/System.Private.CoreLib/shared/System/Globalization/CultureData.Windows.cs +++ b/src/System.Private.CoreLib/shared/System/Globalization/CultureData.Nls.cs @@ -7,6 +7,7 @@ using System.Diagnostics; using System.Diagnostics.CodeAnalysis; using System.Text; using Internal.Runtime.CompilerServices; +using System.Runtime.InteropServices; namespace System.Globalization { @@ -45,9 +46,10 @@ namespace System.Globalization /// For a neutral we just populate the neutral name, but we leave the windows name pointing to the /// windows locale that's going to provide data for us. /// - private unsafe bool InitCultureData() + private unsafe bool NlsInitCultureData() { Debug.Assert(!GlobalizationMode.Invariant); + Debug.Assert(GlobalizationMode.UseNls); int result; string realNameBuffer = _sRealName; @@ -178,23 +180,26 @@ namespace System.Globalization return Interop.Kernel32.GetLocaleInfoEx(lpLocaleName, lcType, lpLCData, cchData); } - private string GetLocaleInfo(LocaleStringData type) + private string NlsGetLocaleInfo(LocaleStringData type) { + Debug.Assert(GlobalizationMode.UseNls); Debug.Assert(_sWindowsName != null, "[CultureData.DoGetLocaleInfo] Expected _sWindowsName to be populated by already"); - return GetLocaleInfo(_sWindowsName, type); + return NlsGetLocaleInfo(_sWindowsName, type); } // For LOCALE_SPARENT we need the option of using the "real" name (forcing neutral names) instead of the // "windows" name, which can be specific for downlevel (< windows 7) os's. - private string GetLocaleInfo(string localeName, LocaleStringData type) + private string NlsGetLocaleInfo(string localeName, LocaleStringData type) { + Debug.Assert(GlobalizationMode.UseNls); uint lctype = (uint)type; return GetLocaleInfoFromLCType(localeName, lctype, UseUserOverride); } - private int GetLocaleInfo(LocaleNumberData type) + private int NlsGetLocaleInfo(LocaleNumberData type) { + Debug.Assert(GlobalizationMode.UseNls); uint lctype = (uint)type; // Fix lctype if we don't want overrides @@ -209,20 +214,23 @@ namespace System.Globalization return GetLocaleInfoExInt(_sWindowsName, lctype); } - private int[] GetLocaleInfo(LocaleGroupingData type) + private int[] NlsGetLocaleInfo(LocaleGroupingData type) { + Debug.Assert(GlobalizationMode.UseNls); Debug.Assert(_sWindowsName != null, "[CultureData.DoGetLocaleInfoInt] Expected _sWindowsName to be populated by already"); return ConvertWin32GroupString(GetLocaleInfoFromLCType(_sWindowsName, (uint)type, UseUserOverride)); } - private string? GetTimeFormatString() + private string? NlsGetTimeFormatString() { + Debug.Assert(GlobalizationMode.UseNls); Debug.Assert(_sWindowsName != null, "[CultureData.DoGetLocaleInfoInt] Expected _sWindowsName to be populated by already"); return ReescapeWin32String(GetLocaleInfoFromLCType(_sWindowsName, Interop.Kernel32.LOCALE_STIMEFORMAT, UseUserOverride)); } - private int GetFirstDayOfWeek() + private int NlsGetFirstDayOfWeek() { + Debug.Assert(GlobalizationMode.UseNls); Debug.Assert(_sWindowsName != null, "[CultureData.DoGetLocaleInfoInt] Expected _sWindowsName to be populated by already"); int result = GetLocaleInfoExInt(_sWindowsName, Interop.Kernel32.LOCALE_IFIRSTDAYOFWEEK | (!UseUserOverride ? Interop.Kernel32.LOCALE_NOUSEROVERRIDE : 0)); @@ -231,18 +239,20 @@ namespace System.Globalization return ConvertFirstDayOfWeekMonToSun(result); } - private string[]? GetTimeFormats() + private string[]? NlsGetTimeFormats() { // Note that this gets overrides for us all the time + Debug.Assert(GlobalizationMode.UseNls); Debug.Assert(_sWindowsName != null, "[CultureData.DoEnumTimeFormats] Expected _sWindowsName to be populated by already"); string[]? result = ReescapeWin32Strings(nativeEnumTimeFormats(_sWindowsName, 0, UseUserOverride)); return result; } - private string[]? GetShortTimeFormats() + private string[]? NlsGetShortTimeFormats() { // Note that this gets overrides for us all the time + Debug.Assert(GlobalizationMode.UseNls); Debug.Assert(_sWindowsName != null, "[CultureData.DoEnumShortTimeFormats] Expected _sWindowsName to be populated by already"); string[]? result = ReescapeWin32Strings(nativeEnumTimeFormats(_sWindowsName, Interop.Kernel32.TIME_NOSECONDS, UseUserOverride)); @@ -251,9 +261,10 @@ namespace System.Globalization // Enumerate all system cultures and then try to find out which culture has // region name match the requested region name - private static CultureData? GetCultureDataFromRegionName(string regionName) + private static CultureData? NlsGetCultureDataFromRegionName(string regionName) { Debug.Assert(!GlobalizationMode.Invariant); + Debug.Assert(GlobalizationMode.UseNls); Debug.Assert(regionName != null); EnumLocaleData context; @@ -274,31 +285,35 @@ namespace System.Globalization return null; } - private string GetLanguageDisplayName(string cultureName) + private string NlsGetLanguageDisplayName(string cultureName) { + Debug.Assert(GlobalizationMode.UseNls); + // Usually the UI culture shouldn't be different than what we got from WinRT except // if DefaultThreadCurrentUICulture was set CultureInfo? ci; if (CultureInfo.DefaultThreadCurrentUICulture != null && - ((ci = CultureInfo.GetUserDefaultCulture()) != null) && + ((ci = CultureInfo.NlsGetUserDefaultCulture()) != null) && !CultureInfo.DefaultThreadCurrentUICulture.Name.Equals(ci.Name)) { return NativeName; } else { - return GetLocaleInfo(cultureName, LocaleStringData.LocalizedDisplayName); + return NlsGetLocaleInfo(cultureName, LocaleStringData.LocalizedDisplayName); } } - private string GetRegionDisplayName() + private string NlsGetRegionDisplayName() { + Debug.Assert(GlobalizationMode.UseNls); + // If the current UI culture matching the OS UI language, we'll get the display name from the OS. // otherwise, we use the native name as we don't carry resources for the region display names anyway. if (CultureInfo.CurrentUICulture.Name.Equals(CultureInfo.UserDefaultUICulture.Name)) { - return GetLocaleInfo(LocaleStringData.LocalizedCountryName); + return NlsGetLocaleInfo(LocaleStringData.LocalizedCountryName); } return NativeCountryName; @@ -579,16 +594,17 @@ namespace System.Globalization return null; } - private static int LocaleNameToLCID(string cultureName) + private static int NlsLocaleNameToLCID(string cultureName) { Debug.Assert(!GlobalizationMode.Invariant); return Interop.Kernel32.LocaleNameToLCID(cultureName, Interop.Kernel32.LOCALE_ALLOW_NEUTRAL_NAMES); } - private static unsafe string? LCIDToLocaleName(int culture) + private static unsafe string? NlsLCIDToLocaleName(int culture) { Debug.Assert(!GlobalizationMode.Invariant); + Debug.Assert(GlobalizationMode.UseNls); char* pBuffer = stackalloc char[Interop.Kernel32.LOCALE_NAME_MAX_LENGTH + 1]; // +1 for the null termination int length = Interop.Kernel32.LCIDToLocaleName(culture, pBuffer, Interop.Kernel32.LOCALE_NAME_MAX_LENGTH + 1, Interop.Kernel32.LOCALE_ALLOW_NEUTRAL_NAMES); @@ -601,44 +617,52 @@ namespace System.Globalization return null; } - private int GetAnsiCodePage(string cultureName) + private int NlsGetAnsiCodePage(string cultureName) { - return GetLocaleInfo(LocaleNumberData.AnsiCodePage); + Debug.Assert(GlobalizationMode.UseNls); + return NlsGetLocaleInfo(LocaleNumberData.AnsiCodePage); } - private int GetOemCodePage(string cultureName) + private int NlsGetOemCodePage(string cultureName) { - return GetLocaleInfo(LocaleNumberData.OemCodePage); + Debug.Assert(GlobalizationMode.UseNls); + return NlsGetLocaleInfo(LocaleNumberData.OemCodePage); } - private int GetMacCodePage(string cultureName) + private int NlsGetMacCodePage(string cultureName) { - return GetLocaleInfo(LocaleNumberData.MacCodePage); + Debug.Assert(GlobalizationMode.UseNls); + return NlsGetLocaleInfo(LocaleNumberData.MacCodePage); } - private int GetEbcdicCodePage(string cultureName) + private int NlsGetEbcdicCodePage(string cultureName) { - return GetLocaleInfo(LocaleNumberData.EbcdicCodePage); + Debug.Assert(GlobalizationMode.UseNls); + return NlsGetLocaleInfo(LocaleNumberData.EbcdicCodePage); } - private int GetGeoId(string cultureName) + private int NlsGetGeoId(string cultureName) { - return GetLocaleInfo(LocaleNumberData.GeoId); + Debug.Assert(GlobalizationMode.UseNls); + return NlsGetLocaleInfo(LocaleNumberData.GeoId); } - private int GetDigitSubstitution(string cultureName) + private int NlsGetDigitSubstitution(string cultureName) { - return GetLocaleInfo(LocaleNumberData.DigitSubstitution); + Debug.Assert(GlobalizationMode.UseNls); + return NlsGetLocaleInfo(LocaleNumberData.DigitSubstitution); } - private string GetThreeLetterWindowsLanguageName(string cultureName) + private string NlsGetThreeLetterWindowsLanguageName(string cultureName) { - return GetLocaleInfo(cultureName, LocaleStringData.AbbreviatedWindowsLanguageName); + Debug.Assert(GlobalizationMode.UseNls); + return NlsGetLocaleInfo(cultureName, LocaleStringData.AbbreviatedWindowsLanguageName); } - private static CultureInfo[] EnumCultures(CultureTypes types) + private static CultureInfo[] NlsEnumCultures(CultureTypes types) { Debug.Assert(!GlobalizationMode.Invariant); + Debug.Assert(GlobalizationMode.UseNls); uint flags = 0; @@ -686,17 +710,17 @@ namespace System.Globalization return cultures; } - private string GetConsoleFallbackName(string cultureName) + private string NlsGetConsoleFallbackName(string cultureName) { - return GetLocaleInfo(cultureName, LocaleStringData.ConsoleFallbackName); + Debug.Assert(GlobalizationMode.UseNls); + return NlsGetLocaleInfo(cultureName, LocaleStringData.ConsoleFallbackName); } - internal bool IsWin32Installed => true; - - internal bool IsReplacementCulture + internal bool NlsIsReplacementCulture { get { + Debug.Assert(GlobalizationMode.UseNls); EnumData context = default; context.strings = new List(); @@ -714,5 +738,34 @@ namespace System.Globalization return false; } } + + internal static unsafe CultureData NlsGetCurrentRegionData() + { + Debug.Assert(GlobalizationMode.UseNls); + Span geoIso2Letters = stackalloc char[10]; + + int geoId = Interop.Kernel32.GetUserGeoID(Interop.Kernel32.GEOCLASS_NATION); + if (geoId != Interop.Kernel32.GEOID_NOT_AVAILABLE) + { + int geoIsoIdLength; + fixed (char* pGeoIsoId = geoIso2Letters) + { + geoIsoIdLength = Interop.Kernel32.GetGeoInfo(geoId, Interop.Kernel32.GEO_ISO2, pGeoIsoId, geoIso2Letters.Length, 0); + } + + if (geoIsoIdLength != 0) + { + geoIsoIdLength -= geoIso2Letters[geoIsoIdLength - 1] == 0 ? 1 : 0; // handle null termination and exclude it. + CultureData? cd = GetCultureDataForRegion(geoIso2Letters.Slice(0, geoIsoIdLength).ToString(), true); + if (cd != null) + { + return cd; + } + } + } + + // Fallback to current locale data. + return CultureInfo.CurrentCulture._cultureData; + } } } diff --git a/src/System.Private.CoreLib/shared/System/Globalization/CultureData.cs b/src/System.Private.CoreLib/shared/System/Globalization/CultureData.cs index f2d68e95b..011befa56 100644 --- a/src/System.Private.CoreLib/shared/System/Globalization/CultureData.cs +++ b/src/System.Private.CoreLib/shared/System/Globalization/CultureData.cs @@ -152,135 +152,262 @@ namespace System.Globalization /// private static Dictionary RegionNames => s_regionNames ??= - new Dictionary(211 /* prime */) + new Dictionary(257 /* prime */) { + { "001", "en-001" }, { "029", "en-029" }, + { "150", "en-150" }, + { "419", "es-419" }, + { "AD", "ca-AD" }, { "AE", "ar-AE" }, { "AF", "prs-AF" }, + { "AG", "en-AG" }, + { "AI", "en-AI" }, { "AL", "sq-AL" }, { "AM", "hy-AM" }, + { "AO", "pt-AO" }, + { "AQ", "en-A" }, { "AR", "es-AR" }, + { "AS", "en-AS" }, { "AT", "de-AT" }, { "AU", "en-AU" }, + { "AW", "nl-AW" }, + { "AX", "sv-AX" }, { "AZ", "az-Cyrl-AZ" }, { "BA", "bs-Latn-BA" }, + { "BB", "en-BB" }, { "BD", "bn-BD" }, { "BE", "nl-BE" }, + { "BF", "fr-BF" }, { "BG", "bg-BG" }, { "BH", "ar-BH" }, + { "BI", "rn-BI" }, + { "BJ", "fr-BJ" }, + { "BL", "fr-BL" }, + { "BM", "en-BM" }, { "BN", "ms-BN" }, { "BO", "es-BO" }, + { "BQ", "nl-BQ" }, { "BR", "pt-BR" }, + { "BS", "en-BS" }, + { "BT", "dz-BT" }, + { "BV", "nb-B" }, + { "BW", "en-BW" }, { "BY", "be-BY" }, { "BZ", "en-BZ" }, { "CA", "en-CA" }, + { "CC", "en-CC" }, + { "CD", "fr-CD" }, + { "CF", "sg-CF" }, + { "CG", "fr-CG" }, { "CH", "it-CH" }, + { "CI", "fr-CI" }, + { "CK", "en-CK" }, { "CL", "es-CL" }, + { "CM", "fr-C" }, { "CN", "zh-CN" }, { "CO", "es-CO" }, { "CR", "es-CR" }, { "CS", "sr-Cyrl-CS" }, + { "CU", "es-CU" }, + { "CV", "pt-CV" }, + { "CW", "nl-CW" }, + { "CX", "en-CX" }, + { "CY", "el-CY" }, { "CZ", "cs-CZ" }, { "DE", "de-DE" }, + { "DJ", "fr-DJ" }, { "DK", "da-DK" }, + { "DM", "en-DM" }, { "DO", "es-DO" }, { "DZ", "ar-DZ" }, { "EC", "es-EC" }, { "EE", "et-EE" }, { "EG", "ar-EG" }, + { "ER", "tig-ER" }, { "ES", "es-ES" }, { "ET", "am-ET" }, { "FI", "fi-FI" }, + { "FJ", "en-FJ" }, + { "FK", "en-FK" }, + { "FM", "en-FM" }, { "FO", "fo-FO" }, { "FR", "fr-FR" }, + { "GA", "fr-GA" }, { "GB", "en-GB" }, + { "GD", "en-GD" }, { "GE", "ka-GE" }, + { "GF", "fr-GF" }, + { "GG", "en-GG" }, + { "GH", "en-GH" }, + { "GI", "en-GI" }, { "GL", "kl-GL" }, + { "GM", "en-GM" }, + { "GN", "fr-GN" }, + { "GP", "fr-GP" }, + { "GQ", "es-GQ" }, { "GR", "el-GR" }, + { "GS", "en-G" }, { "GT", "es-GT" }, + { "GU", "en-GU" }, + { "GW", "pt-GW" }, + { "GY", "en-GY" }, { "HK", "zh-HK" }, + { "HM", "en-H" }, { "HN", "es-HN" }, { "HR", "hr-HR" }, + { "HT", "fr-HT" }, { "HU", "hu-HU" }, { "ID", "id-ID" }, { "IE", "en-IE" }, { "IL", "he-IL" }, + { "IM", "gv-IM" }, { "IN", "hi-IN" }, + { "IO", "en-IO" }, { "IQ", "ar-IQ" }, { "IR", "fa-IR" }, { "IS", "is-IS" }, { "IT", "it-IT" }, { "IV", "" }, + { "JE", "en-JE" }, { "JM", "en-JM" }, { "JO", "ar-JO" }, { "JP", "ja-JP" }, { "KE", "sw-KE" }, { "KG", "ky-KG" }, { "KH", "km-KH" }, + { "KI", "en-KI" }, + { "KM", "ar-KM" }, + { "KN", "en-KN" }, + { "KP", "ko-KP" }, { "KR", "ko-KR" }, { "KW", "ar-KW" }, + { "KY", "en-KY" }, { "KZ", "kk-KZ" }, { "LA", "lo-LA" }, { "LB", "ar-LB" }, + { "LC", "en-LC" }, { "LI", "de-LI" }, { "LK", "si-LK" }, + { "LR", "en-LR" }, + { "LS", "st-LS" }, { "LT", "lt-LT" }, { "LU", "lb-LU" }, { "LV", "lv-LV" }, { "LY", "ar-LY" }, { "MA", "ar-MA" }, { "MC", "fr-MC" }, + { "MD", "ro-MD" }, { "ME", "sr-Latn-ME" }, + { "MF", "fr-MF" }, + { "MG", "mg-MG" }, + { "MH", "en-MH" }, { "MK", "mk-MK" }, + { "ML", "fr-ML" }, + { "MM", "my-MM" }, { "MN", "mn-MN" }, { "MO", "zh-MO" }, + { "MP", "en-MP" }, + { "MQ", "fr-MQ" }, + { "MR", "ar-MR" }, + { "MS", "en-MS" }, { "MT", "mt-MT" }, + { "MU", "en-MU" }, { "MV", "dv-MV" }, + { "MW", "en-MW" }, { "MX", "es-MX" }, { "MY", "ms-MY" }, + { "MZ", "pt-MZ" }, + { "NA", "en-NA" }, + { "NC", "fr-NC" }, + { "NE", "fr-NE" }, + { "NF", "en-NF" }, { "NG", "ig-NG" }, { "NI", "es-NI" }, { "NL", "nl-NL" }, { "NO", "nn-NO" }, { "NP", "ne-NP" }, + { "NR", "en-NR" }, + { "NU", "en-NU" }, { "NZ", "en-NZ" }, { "OM", "ar-OM" }, { "PA", "es-PA" }, { "PE", "es-PE" }, + { "PF", "fr-PF" }, + { "PG", "en-PG" }, { "PH", "en-PH" }, { "PK", "ur-PK" }, { "PL", "pl-PL" }, + { "PM", "fr-PM" }, + { "PN", "en-PN" }, { "PR", "es-PR" }, + { "PS", "ar-PS" }, { "PT", "pt-PT" }, + { "PW", "en-PW" }, { "PY", "es-PY" }, { "QA", "ar-QA" }, + { "RE", "fr-RE" }, { "RO", "ro-RO" }, { "RS", "sr-Latn-RS" }, { "RU", "ru-RU" }, { "RW", "rw-RW" }, { "SA", "ar-SA" }, + { "SB", "en-SB" }, + { "SC", "fr-SC" }, + { "SD", "ar-SD" }, { "SE", "sv-SE" }, { "SG", "zh-SG" }, + { "SH", "en-SH" }, { "SI", "sl-SI" }, + { "SJ", "nb-SJ" }, { "SK", "sk-SK" }, + { "SL", "en-SL" }, + { "SM", "it-SM" }, { "SN", "wo-SN" }, + { "SO", "so-SO" }, + { "SR", "nl-SR" }, + { "SS", "en-SS" }, + { "ST", "pt-ST" }, { "SV", "es-SV" }, + { "SX", "nl-SX" }, { "SY", "ar-SY" }, + { "SZ", "ss-SZ" }, + { "TC", "en-TC" }, + { "TD", "fr-TD" }, + { "TF", "fr-T" }, + { "TG", "fr-TG" }, { "TH", "th-TH" }, { "TJ", "tg-Cyrl-TJ" }, + { "TK", "en-TK" }, + { "TL", "pt-TL" }, { "TM", "tk-TM" }, { "TN", "ar-TN" }, + { "TO", "to-TO" }, { "TR", "tr-TR" }, { "TT", "en-TT" }, + { "TV", "en-TV" }, { "TW", "zh-TW" }, + { "TZ", "sw-TZ" }, { "UA", "uk-UA" }, + { "UG", "sw-UG" }, + { "UM", "en-UM" }, { "US", "en-US" }, { "UY", "es-UY" }, { "UZ", "uz-Cyrl-UZ" }, + { "VA", "it-VA" }, + { "VC", "en-VC" }, { "VE", "es-VE" }, + { "VG", "en-VG" }, + { "VI", "en-VI" }, { "VN", "vi-VN" }, + { "VU", "fr-VU" }, + { "WF", "fr-WF" }, + { "WS", "en-WS" }, + { "XK", "sq-XK" }, { "YE", "ar-YE" }, + { "YT", "fr-YT" }, { "ZA", "af-ZA" }, + { "ZM", "en-ZM" }, { "ZW", "en-ZW" } }; @@ -337,8 +464,7 @@ namespace System.Globalization if (retVal == null || retVal.IsNeutralCulture) { // Not a valid mapping, try the hard coded table - string? name; - if (RegionNames.TryGetValue(cultureName, out name)) + if (RegionNames.TryGetValue(cultureName, out string? name)) { // Make sure we can get culture data for it retVal = GetCultureData(name, useUserOverride); @@ -348,7 +474,7 @@ namespace System.Globalization // If not found in the hard coded table we'll have to find a culture that works for us if (!GlobalizationMode.Invariant && (retVal == null || retVal.IsNeutralCulture)) { - retVal = GetCultureDataFromRegionName(cultureName); + retVal = GlobalizationMode.UseNls ? NlsGetCultureDataFromRegionName(cultureName) : IcuGetCultureDataFromRegionName(cultureName); } // If we found one we can use, then cache it for next time @@ -414,7 +540,7 @@ namespace System.Globalization } #pragma warning restore 618 - return EnumCultures(types); + return GlobalizationMode.UseNls ? NlsEnumCultures(types) : IcuEnumCultures(types); } private static CultureData CreateCultureWithInvariantData() @@ -676,7 +802,7 @@ namespace System.Globalization culture._sRealName = cultureName; // Ask native code if that one's real - if (!culture.InitCultureData() && !culture.InitCompatibilityCultureData()) + if (!culture.InitCultureDataCore() && !culture.InitCompatibilityCultureData()) { return null; } @@ -706,7 +832,7 @@ namespace System.Globalization } _sRealName = fallbackCultureName; - if (!InitCultureData()) + if (!InitCultureDataCore()) { return false; } @@ -718,6 +844,10 @@ namespace System.Globalization return true; } + private bool InitCultureDataCore() => GlobalizationMode.UseNls ? + NlsInitCultureData() : + IcuInitCultureData(); + /// We'd rather people use the named version since this doesn't allow custom locales internal static CultureData GetCultureData(int culture, bool bUseUserOverride) { @@ -737,7 +867,7 @@ namespace System.Globalization // Convert the lcid to a name, then use that // Note that this will return neutral names (unlike Vista native API) - localeName = LCIDToLocaleName(culture); + localeName = GlobalizationMode.UseNls ? NlsLCIDToLocaleName(culture) : IcuLCIDToLocaleName(culture); if (!string.IsNullOrEmpty(localeName)) { @@ -788,7 +918,7 @@ namespace System.Globalization // Parent name (which may be a custom locale/culture) // Ask using the real name, so that we get parents of neutrals - internal string ParentName => _sParent ??= GetLocaleInfo(_sRealName!, LocaleStringData.ParentName); + internal string ParentName => _sParent ??= GetLocaleInfoCore(_sRealName!, LocaleStringData.ParentName); // Localized pretty name for this locale (ie: Inglis (estados Unitos)) internal string DisplayName @@ -818,15 +948,15 @@ namespace System.Globalization if (Name.Equals(ZH_CHT, StringComparison.OrdinalIgnoreCase)) { - localizedDisplayName = GetLanguageDisplayName("zh-Hant"); + localizedDisplayName = GetLanguageDisplayNameCore("zh-Hant"); } else if (Name.Equals(ZH_CHS, StringComparison.OrdinalIgnoreCase)) { - localizedDisplayName = GetLanguageDisplayName("zh-Hans"); + localizedDisplayName = GetLanguageDisplayNameCore("zh-Hans"); } else { - localizedDisplayName = GetLanguageDisplayName(Name); + localizedDisplayName = GetLanguageDisplayNameCore(Name); } } catch @@ -857,7 +987,7 @@ namespace System.Globalization } else { - localizedDisplayName = GetLocaleInfo(LocaleStringData.LocalizedDisplayName); + localizedDisplayName = GetLocaleInfoCore(LocaleStringData.LocalizedDisplayName); } } } @@ -869,6 +999,10 @@ namespace System.Globalization } } + private string GetLanguageDisplayNameCore(string cultureName) => GlobalizationMode.UseNls ? + NlsGetLanguageDisplayName(cultureName) : + IcuGetLanguageDisplayName(cultureName); + /// /// English pretty name for this locale (ie: English (United States)) /// @@ -894,7 +1028,7 @@ namespace System.Globalization } else { - englishDisplayName = GetLocaleInfo(LocaleStringData.EnglishDisplayName); + englishDisplayName = GetLocaleInfoCore(LocaleStringData.EnglishDisplayName); // if it isn't found build one: if (string.IsNullOrEmpty(englishDisplayName)) @@ -953,7 +1087,7 @@ namespace System.Globalization } else { - nativeDisplayName = GetLocaleInfo(LocaleStringData.NativeDisplayName); + nativeDisplayName = GetLocaleInfoCore(LocaleStringData.NativeDisplayName); // if it isn't found build one: if (string.IsNullOrEmpty(nativeDisplayName)) @@ -986,17 +1120,19 @@ namespace System.Globalization /// /// iso 639 language name, ie: en /// - internal string TwoLetterISOLanguageName => _sISO639Language ??= GetLocaleInfo(LocaleStringData.Iso639LanguageTwoLetterName); + internal string TwoLetterISOLanguageName => _sISO639Language ??= GetLocaleInfoCore(LocaleStringData.Iso639LanguageTwoLetterName); /// /// iso 639 language name, ie: eng /// - internal string ThreeLetterISOLanguageName => _sISO639Language2 ??= GetLocaleInfo(LocaleStringData.Iso639LanguageThreeLetterName); + internal string ThreeLetterISOLanguageName => _sISO639Language2 ??= GetLocaleInfoCore(LocaleStringData.Iso639LanguageThreeLetterName); /// /// abbreviated windows language name (ie: enu) (non-standard, avoid this) /// - internal string ThreeLetterWindowsLanguageName => _sAbbrevLang ??= GetThreeLetterWindowsLanguageName(_sRealName!); + internal string ThreeLetterWindowsLanguageName => _sAbbrevLang ??= GlobalizationMode.UseNls ? + NlsGetThreeLetterWindowsLanguageName(_sRealName!) : + IcuGetThreeLetterWindowsLanguageName(_sRealName!); /// /// Localized name for this language (Windows Only) ie: Inglis @@ -1020,7 +1156,7 @@ namespace System.Globalization } else { - _sLocalizedLanguage = GetLocaleInfo(LocaleStringData.LocalizedLanguageName); + _sLocalizedLanguage = GetLocaleInfoCore(LocaleStringData.LocalizedLanguageName); } } @@ -1031,17 +1167,17 @@ namespace System.Globalization /// /// English name for this language (Windows Only) ie: German /// - private string EnglishLanguageName => _sEnglishLanguage ??= GetLocaleInfo(LocaleStringData.EnglishLanguageName); + private string EnglishLanguageName => _sEnglishLanguage ??= GetLocaleInfoCore(LocaleStringData.EnglishLanguageName); /// /// Native name of this language (Windows Only) ie: Deutsch /// - private string NativeLanguageName => _sNativeLanguage ??= GetLocaleInfo(LocaleStringData.NativeLanguageName); + private string NativeLanguageName => _sNativeLanguage ??= GetLocaleInfoCore(LocaleStringData.NativeLanguageName); /// /// region name (eg US) /// - internal string RegionName => _sRegionName ??= GetLocaleInfo(LocaleStringData.Iso3166CountryName); + internal string RegionName => _sRegionName ??= GetLocaleInfoCore(LocaleStringData.Iso3166CountryName); internal int GeoId { @@ -1049,7 +1185,7 @@ namespace System.Globalization { if (_iGeoId == undef) { - _iGeoId = GetGeoId(_sRealName!); + _iGeoId = GlobalizationMode.UseNls ? NlsGetGeoId(_sRealName!) : IcuGetGeoId(_sRealName!); } return _iGeoId; } @@ -1067,7 +1203,7 @@ namespace System.Globalization { try { - localizedCountry = GetRegionDisplayName(); + localizedCountry = GlobalizationMode.UseNls ? NlsGetRegionDisplayName() : IcuGetRegionDisplayName(); } catch { @@ -1085,22 +1221,22 @@ namespace System.Globalization /// /// english country name (RegionInfo) ie: Germany /// - internal string EnglishCountryName => _sEnglishCountry ??= GetLocaleInfo(LocaleStringData.EnglishCountryName); + internal string EnglishCountryName => _sEnglishCountry ??= GetLocaleInfoCore(LocaleStringData.EnglishCountryName); /// /// native country name (RegionInfo) ie: Deutschland /// - internal string NativeCountryName => _sNativeCountry ??= GetLocaleInfo(LocaleStringData.NativeCountryName); + internal string NativeCountryName => _sNativeCountry ??= GetLocaleInfoCore(LocaleStringData.NativeCountryName); /// /// ISO 3166 Country Name /// - internal string TwoLetterISOCountryName => _sISO3166CountryName ??= GetLocaleInfo(LocaleStringData.Iso3166CountryName); + internal string TwoLetterISOCountryName => _sISO3166CountryName ??= GetLocaleInfoCore(LocaleStringData.Iso3166CountryName); /// /// 3 letter ISO 3166 country code /// - internal string ThreeLetterISOCountryName => _sISO3166CountryName2 ??= GetLocaleInfo(LocaleStringData.Iso3166CountryName2); + internal string ThreeLetterISOCountryName => _sISO3166CountryName2 ??= GetLocaleInfoCore(LocaleStringData.Iso3166CountryName2); internal int KeyboardLayoutId { @@ -1125,27 +1261,29 @@ namespace System.Globalization /// /// Console fallback name (ie: locale to use for console apps for unicode-only locales) /// - internal string SCONSOLEFALLBACKNAME => _sConsoleFallbackName ??= GetConsoleFallbackName(_sRealName!); + internal string SCONSOLEFALLBACKNAME => _sConsoleFallbackName ??= GlobalizationMode.UseNls ? + NlsGetConsoleFallbackName(_sRealName!) : + IcuGetConsoleFallbackName(_sRealName!); /// /// (user can override) grouping of digits /// - internal int[] NumberGroupSizes => _waGrouping ??= GetLocaleInfo(LocaleGroupingData.Digit); + internal int[] NumberGroupSizes => _waGrouping ??= GetLocaleInfoCore(LocaleGroupingData.Digit); /// /// Not a Number /// - private string NaNSymbol => _sNaN ??= GetLocaleInfo(LocaleStringData.NaNSymbol); + private string NaNSymbol => _sNaN ??= GetLocaleInfoCore(LocaleStringData.NaNSymbol); /// /// + Infinity /// - private string PositiveInfinitySymbol => _sPositiveInfinity ??= GetLocaleInfo(LocaleStringData.PositiveInfinitySymbol); + private string PositiveInfinitySymbol => _sPositiveInfinity ??= GetLocaleInfoCore(LocaleStringData.PositiveInfinitySymbol); /// /// - Infinity /// - private string NegativeInfinitySymbol => _sNegativeInfinity ??= GetLocaleInfo(LocaleStringData.NegativeInfinitySymbol); + private string NegativeInfinitySymbol => _sNegativeInfinity ??= GetLocaleInfoCore(LocaleStringData.NegativeInfinitySymbol); /// /// Negative Percent (0-3) @@ -1157,7 +1295,7 @@ namespace System.Globalization if (_iNegativePercent == undef) { // Note that <= Windows Vista this is synthesized by native code - _iNegativePercent = GetLocaleInfo(LocaleNumberData.NegativePercentFormat); + _iNegativePercent = GetLocaleInfoCore(LocaleNumberData.NegativePercentFormat); } return _iNegativePercent; } @@ -1173,7 +1311,7 @@ namespace System.Globalization if (_iPositivePercent == undef) { // Note that <= Windows Vista this is synthesized by native code - _iPositivePercent = GetLocaleInfo(LocaleNumberData.PositivePercentFormat); + _iPositivePercent = GetLocaleInfoCore(LocaleNumberData.PositivePercentFormat); } return _iPositivePercent; } @@ -1182,37 +1320,37 @@ namespace System.Globalization /// /// Percent (%) symbol /// - private string PercentSymbol => _sPercent ??= GetLocaleInfo(LocaleStringData.PercentSymbol); + private string PercentSymbol => _sPercent ??= GetLocaleInfoCore(LocaleStringData.PercentSymbol); /// /// PerMille symbol /// - private string PerMilleSymbol => _sPerMille ??= GetLocaleInfo(LocaleStringData.PerMilleSymbol); + private string PerMilleSymbol => _sPerMille ??= GetLocaleInfoCore(LocaleStringData.PerMilleSymbol); /// /// (user can override) local monetary symbol, eg: $ /// - internal string CurrencySymbol => _sCurrency ??= GetLocaleInfo(LocaleStringData.MonetarySymbol); + internal string CurrencySymbol => _sCurrency ??= GetLocaleInfoCore(LocaleStringData.MonetarySymbol); /// /// international monetary symbol (RegionInfo), eg: USD /// - internal string ISOCurrencySymbol => _sIntlMonetarySymbol ??= GetLocaleInfo(LocaleStringData.Iso4217MonetarySymbol); + internal string ISOCurrencySymbol => _sIntlMonetarySymbol ??= GetLocaleInfoCore(LocaleStringData.Iso4217MonetarySymbol); /// /// English name for this currency (RegionInfo), eg: US Dollar /// - internal string CurrencyEnglishName => _sEnglishCurrency ??= GetLocaleInfo(LocaleStringData.CurrencyEnglishName); + internal string CurrencyEnglishName => _sEnglishCurrency ??= GetLocaleInfoCore(LocaleStringData.CurrencyEnglishName); /// /// Native name for this currency (RegionInfo), eg: Schweiz Frank /// - internal string CurrencyNativeName => _sNativeCurrency ??= GetLocaleInfo(LocaleStringData.CurrencyNativeName); + internal string CurrencyNativeName => _sNativeCurrency ??= GetLocaleInfoCore(LocaleStringData.CurrencyNativeName); /// /// (user can override) monetary grouping of digits /// - internal int[] CurrencyGroupSizes => _waMonetaryGrouping ??= GetLocaleInfo(LocaleGroupingData.Monetary); + internal int[] CurrencyGroupSizes => _waMonetaryGrouping ??= GetLocaleInfoCore(LocaleGroupingData.Monetary); /// /// (user can override) system of measurement 0=metric, 1=US (RegionInfo) @@ -1223,7 +1361,7 @@ namespace System.Globalization { if (_iMeasure == undef) { - _iMeasure = GetLocaleInfo(LocaleNumberData.MeasurementSystem); + _iMeasure = GetLocaleInfoCore(LocaleNumberData.MeasurementSystem); } return _iMeasure; } @@ -1232,17 +1370,17 @@ namespace System.Globalization /// /// (user can override) list Separator /// - internal string ListSeparator => _sListSeparator ??= GetLocaleInfo(LocaleStringData.ListSeparator); + internal string ListSeparator => _sListSeparator ??= GetLocaleInfoCore(LocaleStringData.ListSeparator); /// /// (user can override) AM designator /// - internal string AMDesignator => _sAM1159 ??= GetLocaleInfo(LocaleStringData.AMDesignator); + internal string AMDesignator => _sAM1159 ??= GetLocaleInfoCore(LocaleStringData.AMDesignator); /// /// (user can override) PM designator /// - internal string PMDesignator => _sPM2359 ??= GetLocaleInfo(LocaleStringData.PMDesignator); + internal string PMDesignator => _sPM2359 ??= GetLocaleInfoCore(LocaleStringData.PMDesignator); /// /// (user can override) time format @@ -1255,7 +1393,7 @@ namespace System.Globalization { Debug.Assert(!GlobalizationMode.Invariant); - string[]? longTimes = GetTimeFormats(); + string[]? longTimes = GlobalizationMode.UseNls ? NlsGetTimeFormats() : IcuGetTimeFormats(); if (longTimes == null || longTimes.Length == 0) { _saLongTimes = Invariant._saLongTimes!; @@ -1282,7 +1420,7 @@ namespace System.Globalization Debug.Assert(!GlobalizationMode.Invariant); // Try to get the short times from the OS/culture.dll - string[]? shortTimes = GetShortTimeFormats(); + string[]? shortTimes = GlobalizationMode.UseNls ? NlsGetShortTimeFormats() : IcuGetShortTimeFormats(); if (shortTimes == null || shortTimes.Length == 0) { @@ -1433,7 +1571,7 @@ namespace System.Globalization { if (_iFirstDayOfWeek == undef) { - _iFirstDayOfWeek = GetFirstDayOfWeek(); + _iFirstDayOfWeek = GlobalizationMode.UseNls ? NlsGetFirstDayOfWeek() : IcuGetFirstDayOfWeek(); } return _iFirstDayOfWeek; } @@ -1446,7 +1584,7 @@ namespace System.Globalization { if (_iFirstWeekOfYear == undef) { - _iFirstWeekOfYear = GetLocaleInfo(LocaleNumberData.FirstWeekOfYear); + _iFirstWeekOfYear = GetLocaleInfoCore(LocaleNumberData.FirstWeekOfYear); } return _iFirstWeekOfYear; } @@ -1539,7 +1677,10 @@ namespace System.Globalization // Default calendar should be first CalendarId[] calendars = new CalendarId[23]; Debug.Assert(_sWindowsName != null, "[CultureData.CalendarIds] Expected _sWindowsName to be populated by already"); - int count = CalendarData.GetCalendars(_sWindowsName, _bUseOverrides, calendars); + + int count = GlobalizationMode.UseNls + ? CalendarData.NlsGetCalendars(_sWindowsName, _bUseOverrides, calendars) + : CalendarData.IcuGetCalendars(_sWindowsName, _bUseOverrides, calendars); // See if we had a calendar to add. if (count == 0) @@ -1585,7 +1726,7 @@ namespace System.Globalization // Prior to Vista the enumeration didn't have default calendar first if (temp.Length > 1) { - CalendarId i = (CalendarId)GetLocaleInfo(LocaleNumberData.CalendarType); + CalendarId i = (CalendarId)GetLocaleInfoCore(LocaleNumberData.CalendarType); if (temp[1] == i) { temp[1] = temp[0]; @@ -1658,7 +1799,7 @@ namespace System.Globalization if (_iReadingLayout == undef) { Debug.Assert(_sRealName != null, "[CultureData.IsRightToLeft] Expected _sRealName to be populated by already"); - _iReadingLayout = GetLocaleInfo(LocaleNumberData.ReadingLayout); + _iReadingLayout = GetLocaleInfoCore(LocaleNumberData.ReadingLayout); } return _iReadingLayout; @@ -1709,7 +1850,7 @@ namespace System.Globalization { if (_iDefaultAnsiCodePage == undef) { - _iDefaultAnsiCodePage = GetAnsiCodePage(_sRealName!); + _iDefaultAnsiCodePage = GlobalizationMode.UseNls ? NlsGetAnsiCodePage(_sRealName!) : IcuGetAnsiCodePage(_sRealName!); } return _iDefaultAnsiCodePage; } @@ -1724,7 +1865,7 @@ namespace System.Globalization { if (_iDefaultOemCodePage == undef) { - _iDefaultOemCodePage = GetOemCodePage(_sRealName!); + _iDefaultOemCodePage = GlobalizationMode.UseNls ? NlsGetOemCodePage(_sRealName!) : IcuGetOemCodePage(_sRealName!); } return _iDefaultOemCodePage; } @@ -1739,7 +1880,7 @@ namespace System.Globalization { if (_iDefaultMacCodePage == undef) { - _iDefaultMacCodePage = GetMacCodePage(_sRealName!); + _iDefaultMacCodePage = GlobalizationMode.UseNls ? NlsGetMacCodePage(_sRealName!) : IcuGetMacCodePage(_sRealName!); } return _iDefaultMacCodePage; } @@ -1754,7 +1895,7 @@ namespace System.Globalization { if (_iDefaultEbcdicCodePage == undef) { - _iDefaultEbcdicCodePage = GetEbcdicCodePage(_sRealName!); + _iDefaultEbcdicCodePage = GlobalizationMode.UseNls ? NlsGetEbcdicCodePage(_sRealName!) : IcuGetEbcdicCodePage(_sRealName!); } return _iDefaultEbcdicCodePage; } @@ -1767,7 +1908,7 @@ namespace System.Globalization if (_iLanguage == 0) { Debug.Assert(_sRealName != null, "[CultureData.LCID] Expected this.sRealName to be populated already"); - _iLanguage = LocaleNameToLCID(_sRealName); + _iLanguage = GlobalizationMode.UseNls ? NlsLocaleNameToLCID(_sRealName) : IcuLocaleNameToLCID(_sRealName); } return _iLanguage; } @@ -1779,6 +1920,14 @@ namespace System.Globalization internal bool IsInvariantCulture => string.IsNullOrEmpty(Name); + internal bool IsWin32Installed => GlobalizationMode.UseNls; + + internal bool IsReplacementCulture => GlobalizationMode.UseNls ? NlsIsReplacementCulture : false; + + internal static unsafe CultureData GetCurrentRegionData() => GlobalizationMode.UseNls ? + NlsGetCurrentRegionData() : + CultureInfo.CurrentCulture._cultureData; + /// /// Get an instance of our default calendar /// @@ -1791,7 +1940,7 @@ namespace System.Globalization return CultureInfo.GetCalendarInstance(CalendarIds[0]); } - CalendarId defaultCalId = (CalendarId)GetLocaleInfo(LocaleNumberData.CalendarType); + CalendarId defaultCalId = (CalendarId)GetLocaleInfoCore(LocaleNumberData.CalendarType); if (defaultCalId == 0) { @@ -1832,7 +1981,7 @@ namespace System.Globalization { if (_sTimeSeparator == null) { - string? longTimeFormat = GetTimeFormatString(); + string? longTimeFormat = GlobalizationMode.UseNls ? NlsGetTimeFormatString() : IcuGetTimeFormatString(); if (string.IsNullOrEmpty(longTimeFormat)) { longTimeFormat = LongTimes[0]; @@ -2034,24 +2183,24 @@ namespace System.Globalization { Debug.Assert(_sWindowsName != null, "[CultureData.GetNFIValues] Expected _sWindowsName to be populated by already"); // String values - nfi._positiveSign = GetLocaleInfo(LocaleStringData.PositiveSign); - nfi._negativeSign = GetLocaleInfo(LocaleStringData.NegativeSign); + nfi._positiveSign = GetLocaleInfoCore(LocaleStringData.PositiveSign); + nfi._negativeSign = GetLocaleInfoCore(LocaleStringData.NegativeSign); - nfi._numberDecimalSeparator = GetLocaleInfo(LocaleStringData.DecimalSeparator); - nfi._numberGroupSeparator = GetLocaleInfo(LocaleStringData.ThousandSeparator); - nfi._currencyGroupSeparator = GetLocaleInfo(LocaleStringData.MonetaryThousandSeparator); - nfi._currencyDecimalSeparator = GetLocaleInfo(LocaleStringData.MonetaryDecimalSeparator); - nfi._currencySymbol = GetLocaleInfo(LocaleStringData.MonetarySymbol); + nfi._numberDecimalSeparator = GetLocaleInfoCore(LocaleStringData.DecimalSeparator); + nfi._numberGroupSeparator = GetLocaleInfoCore(LocaleStringData.ThousandSeparator); + nfi._currencyGroupSeparator = GetLocaleInfoCore(LocaleStringData.MonetaryThousandSeparator); + nfi._currencyDecimalSeparator = GetLocaleInfoCore(LocaleStringData.MonetaryDecimalSeparator); + nfi._currencySymbol = GetLocaleInfoCore(LocaleStringData.MonetarySymbol); // Numeric values - nfi._numberDecimalDigits = GetLocaleInfo(LocaleNumberData.FractionalDigitsCount); - nfi._currencyDecimalDigits = GetLocaleInfo(LocaleNumberData.MonetaryFractionalDigitsCount); - nfi._currencyPositivePattern = GetLocaleInfo(LocaleNumberData.PositiveMonetaryNumberFormat); - nfi._currencyNegativePattern = GetLocaleInfo(LocaleNumberData.NegativeMonetaryNumberFormat); - nfi._numberNegativePattern = GetLocaleInfo(LocaleNumberData.NegativeNumberFormat); + nfi._numberDecimalDigits = GetLocaleInfoCore(LocaleNumberData.FractionalDigitsCount); + nfi._currencyDecimalDigits = GetLocaleInfoCore(LocaleNumberData.MonetaryFractionalDigitsCount); + nfi._currencyPositivePattern = GetLocaleInfoCore(LocaleNumberData.PositiveMonetaryNumberFormat); + nfi._currencyNegativePattern = GetLocaleInfoCore(LocaleNumberData.NegativeMonetaryNumberFormat); + nfi._numberNegativePattern = GetLocaleInfoCore(LocaleNumberData.NegativeNumberFormat); // LOCALE_SNATIVEDIGITS (array of 10 single character strings). - string digits = GetLocaleInfo(LocaleStringData.Digits); + string digits = GetLocaleInfoCore(LocaleStringData.Digits); nfi._nativeDigits = new string[10]; for (int i = 0; i < nfi._nativeDigits.Length; i++) { @@ -2059,7 +2208,7 @@ namespace System.Globalization } Debug.Assert(_sRealName != null); - nfi._digitSubstitution = GetDigitSubstitution(_sRealName); + nfi._digitSubstitution = GlobalizationMode.UseNls ? NlsGetDigitSubstitution(_sRealName) : IcuGetDigitSubstitution(_sRealName); } // Gather additional data @@ -2104,6 +2253,22 @@ namespace System.Globalization /// internal static string AnsiToLower(string testString) => TextInfo.ToLowerAsciiInvariant(testString); + private int GetLocaleInfoCore(LocaleNumberData type) => GlobalizationMode.UseNls ? + NlsGetLocaleInfo(type) : + IcuGetLocaleInfo(type); + + private string GetLocaleInfoCore(LocaleStringData type) => GlobalizationMode.UseNls ? + NlsGetLocaleInfo(type) : + IcuGetLocaleInfo(type); + + private string GetLocaleInfoCore(string localeName, LocaleStringData type) => GlobalizationMode.UseNls ? + NlsGetLocaleInfo(localeName, type) : + IcuGetLocaleInfo(localeName, type); + + private int[] GetLocaleInfoCore(LocaleGroupingData type) => GlobalizationMode.UseNls ? + NlsGetLocaleInfo(type) : + IcuGetLocaleInfo(type); + /// /// The numeric values of the enum members match their Win32 counterparts. The CultureData Win32 PAL implementation /// takes a dependency on this fact, in order to prevent having to construct a mapping from internal values to LCTypes. diff --git a/src/System.Private.CoreLib/shared/System/Globalization/CultureInfo.Unix.cs b/src/System.Private.CoreLib/shared/System/Globalization/CultureInfo.Icu.cs similarity index 76% rename from src/System.Private.CoreLib/shared/System/Globalization/CultureInfo.Unix.cs rename to src/System.Private.CoreLib/shared/System/Globalization/CultureInfo.Icu.cs index da4c00af2..6fb99d3e6 100644 --- a/src/System.Private.CoreLib/shared/System/Globalization/CultureInfo.Unix.cs +++ b/src/System.Private.CoreLib/shared/System/Globalization/CultureInfo.Icu.cs @@ -8,8 +8,10 @@ namespace System.Globalization { public partial class CultureInfo : IFormatProvider { - internal static CultureInfo GetUserDefaultCulture() + internal static CultureInfo IcuGetUserDefaultCulture() { + Debug.Assert(!GlobalizationMode.UseNls); + if (GlobalizationMode.Invariant) return CultureInfo.InvariantCulture; @@ -28,8 +30,10 @@ namespace System.Globalization return cultureInfo; } - private static CultureInfo GetPredefinedCultureInfo(string name) + private static CultureInfo IcuGetPredefinedCultureInfo(string name) { + Debug.Assert(!GlobalizationMode.UseNls); + if (!Interop.Globalization.IsPredefinedLocale(name)) { throw new CultureNotFoundException(nameof(name), SR.Format(SR.Argument_InvalidPredefinedCultureName, name)); @@ -38,8 +42,10 @@ namespace System.Globalization return GetCultureInfo(name); } - private static CultureInfo GetUserDefaultUICulture() + private static CultureInfo IcuGetUserDefaultUICulture() { + Debug.Assert(!GlobalizationMode.UseNls); + return InitializeUserDefaultCulture(); } } diff --git a/src/System.Private.CoreLib/shared/System/Globalization/CultureInfo.Windows.cs b/src/System.Private.CoreLib/shared/System/Globalization/CultureInfo.Nls.cs similarity index 88% rename from src/System.Private.CoreLib/shared/System/Globalization/CultureInfo.Windows.cs rename to src/System.Private.CoreLib/shared/System/Globalization/CultureInfo.Nls.cs index dd4f34f58..6265fc8af 100644 --- a/src/System.Private.CoreLib/shared/System/Globalization/CultureInfo.Windows.cs +++ b/src/System.Private.CoreLib/shared/System/Globalization/CultureInfo.Nls.cs @@ -2,12 +2,16 @@ // 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.Diagnostics; + namespace System.Globalization { public partial class CultureInfo : IFormatProvider { - internal static CultureInfo GetUserDefaultCulture() + internal static CultureInfo NlsGetUserDefaultCulture() { + Debug.Assert(GlobalizationMode.UseNls); + if (GlobalizationMode.Invariant) return CultureInfo.InvariantCulture; @@ -26,8 +30,10 @@ namespace System.Globalization return GetCultureByName(strDefault); } - private static CultureInfo GetPredefinedCultureInfo(string name) + private static CultureInfo NlsGetPredefinedCultureInfo(string name) { + Debug.Assert(GlobalizationMode.UseNls); + CultureInfo culture = GetCultureInfo(name); string englishName = culture.EnglishName; @@ -44,8 +50,10 @@ namespace System.Globalization return culture; } - private static unsafe CultureInfo GetUserDefaultUICulture() + private static unsafe CultureInfo NlsGetUserDefaultUICulture() { + Debug.Assert(GlobalizationMode.UseNls); + if (GlobalizationMode.Invariant) return CultureInfo.InvariantCulture; diff --git a/src/System.Private.CoreLib/shared/System/Globalization/CultureInfo.cs b/src/System.Private.CoreLib/shared/System/Globalization/CultureInfo.cs index e85331686..f4daf5c08 100644 --- a/src/System.Private.CoreLib/shared/System/Globalization/CultureInfo.cs +++ b/src/System.Private.CoreLib/shared/System/Globalization/CultureInfo.cs @@ -819,6 +819,14 @@ namespace System.Globalization return new GregorianCalendar(); } + internal static CultureInfo GetUserDefaultCulture() => GlobalizationMode.UseNls ? + NlsGetUserDefaultCulture() : + IcuGetUserDefaultCulture(); + + private static CultureInfo GetUserDefaultUICulture() => GlobalizationMode.UseNls ? + NlsGetUserDefaultUICulture() : + IcuGetUserDefaultUICulture(); + /// /// Return/set the default calendar used by this culture. /// This value can be overridden by regional option if this is a current culture. @@ -1123,7 +1131,9 @@ namespace System.Globalization if (predefinedOnly) { - return GetPredefinedCultureInfo(name); + return GlobalizationMode.UseNls ? + NlsGetPredefinedCultureInfo(name) : + IcuGetPredefinedCultureInfo(name); } return GetCultureInfo(name); diff --git a/src/System.Private.CoreLib/shared/System/Globalization/DateTimeFormat.cs b/src/System.Private.CoreLib/shared/System/Globalization/DateTimeFormat.cs index d226c00e1..ae4878980 100644 --- a/src/System.Private.CoreLib/shared/System/Globalization/DateTimeFormat.cs +++ b/src/System.Private.CoreLib/shared/System/Globalization/DateTimeFormat.cs @@ -125,7 +125,7 @@ namespace System class DateTimeFormat { internal const int MaxSecondsFractionDigits = 7; - internal static readonly TimeSpan NullOffset = TimeSpan.MinValue; + internal const long NullOffset = long.MinValue; internal static char[] allStandardFormats = { @@ -778,7 +778,7 @@ namespace System private static void FormatCustomizedTimeZone(DateTime dateTime, TimeSpan offset, int tokenLen, bool timeOnly, StringBuilder result) { // See if the instance already has an offset - bool dateTimeFormat = (offset == NullOffset); + bool dateTimeFormat = (offset.Ticks == NullOffset); if (dateTimeFormat) { // No offset. The instance is a DateTime and the output should be the local time zone @@ -791,14 +791,14 @@ namespace System } else if (dateTime.Kind == DateTimeKind.Utc) { - offset = TimeSpan.Zero; + offset = default; // TimeSpan.Zero } else { offset = TimeZoneInfo.GetLocalUtcOffset(dateTime, TimeZoneInfoOptions.NoThrowOnInvalidTime); } } - if (offset >= TimeSpan.Zero) + if (offset.Ticks >= 0) { result.Append('+'); } @@ -833,7 +833,7 @@ namespace System // For DateTime it should round-trip the Kind value and preserve the time zone. // DateTimeOffset instance, it should do so by using the internal time zone. - if (offset == NullOffset) + if (offset.Ticks == NullOffset) { // source is a date time, so behavior depends on the kind. switch (dateTime.Kind) @@ -852,7 +852,7 @@ namespace System return; } } - if (offset >= TimeSpan.Zero) + if (offset.Ticks >= 0) { result.Append('+'); } @@ -940,7 +940,7 @@ namespace System // This method also convert the dateTime if necessary (e.g. when the format is in Universal time), // and change dtfi if necessary (e.g. when the format should use invariant culture). // - private static string ExpandPredefinedFormat(ReadOnlySpan format, ref DateTime dateTime, ref DateTimeFormatInfo dtfi, ref TimeSpan offset) + private static string ExpandPredefinedFormat(ReadOnlySpan format, ref DateTime dateTime, ref DateTimeFormatInfo dtfi, TimeSpan offset) { switch (format[0]) { @@ -951,7 +951,7 @@ namespace System case 'r': case 'R': // RFC 1123 Standard case 'u': // Universal time in sortable format. - if (offset != NullOffset) + if (offset.Ticks != NullOffset) { // Convert to UTC invariants mean this will be in range dateTime -= offset; @@ -962,7 +962,7 @@ namespace System dtfi = DateTimeFormatInfo.InvariantInfo; break; case 'U': // Universal time in culture dependent format. - if (offset != NullOffset) + if (offset.Ticks != NullOffset) { // This format is not supported by DateTimeOffset throw new FormatException(SR.Format_InvalidString); @@ -984,7 +984,7 @@ namespace System internal static string Format(DateTime dateTime, string? format, IFormatProvider? provider) { - return Format(dateTime, format, provider, NullOffset); + return Format(dateTime, format, provider, new TimeSpan(NullOffset)); } internal static string Format(DateTime dateTime, string? format, IFormatProvider? provider, TimeSpan offset) @@ -1019,7 +1019,7 @@ namespace System } internal static bool TryFormat(DateTime dateTime, Span destination, out int charsWritten, ReadOnlySpan format, IFormatProvider? provider) => - TryFormat(dateTime, destination, out charsWritten, format, provider, NullOffset); + TryFormat(dateTime, destination, out charsWritten, format, provider, new TimeSpan(NullOffset)); internal static bool TryFormat(DateTime dateTime, Span destination, out int charsWritten, ReadOnlySpan format, IFormatProvider? provider, TimeSpan offset) { @@ -1093,7 +1093,7 @@ namespace System break; } } - if (offset == NullOffset) + if (offset.Ticks == NullOffset) { // Default DateTime.ToString case. format = timeOnlySpecialCase ? "s" : "G"; @@ -1107,7 +1107,7 @@ namespace System if (format.Length == 1) { - format = ExpandPredefinedFormat(format, ref dateTime, ref dtfi, ref offset); + format = ExpandPredefinedFormat(format, ref dateTime, ref dtfi, offset); } return FormatCustomized(dateTime, format, dtfi, offset, result: null); @@ -1126,7 +1126,7 @@ namespace System int charsRequired = MinimumBytesNeeded; DateTimeKind kind = DateTimeKind.Local; - if (offset == NullOffset) + if (offset.Ticks == NullOffset) { kind = dateTime.Kind; if (kind == DateTimeKind.Local) @@ -1217,7 +1217,7 @@ namespace System return false; } - if (offset != NullOffset) + if (offset.Ticks != NullOffset) { // Convert to UTC invariants. dateTime -= offset; diff --git a/src/System.Private.CoreLib/shared/System/Globalization/DateTimeFormatInfo.cs b/src/System.Private.CoreLib/shared/System/Globalization/DateTimeFormatInfo.cs index fab4a23fe..722c58392 100644 --- a/src/System.Private.CoreLib/shared/System/Globalization/DateTimeFormatInfo.cs +++ b/src/System.Private.CoreLib/shared/System/Globalization/DateTimeFormatInfo.cs @@ -2379,8 +2379,7 @@ namespace System.Globalization ch = Culture.TextInfo.ToLower(ch); if (IsHebrewChar(ch) && TokenMask == TokenType.RegularTokenMask) { - bool badFormat; - if (TryParseHebrewNumber(ref str, out badFormat, out tokenValue)) + if (TryParseHebrewNumber(ref str, out bool badFormat, out tokenValue)) { if (badFormat) { diff --git a/src/System.Private.CoreLib/shared/System/Globalization/DateTimeFormatInfoScanner.cs b/src/System.Private.CoreLib/shared/System/Globalization/DateTimeFormatInfoScanner.cs index 1ecdc35ea..f1b382ea5 100644 --- a/src/System.Private.CoreLib/shared/System/Globalization/DateTimeFormatInfoScanner.cs +++ b/src/System.Private.CoreLib/shared/System/Globalization/DateTimeFormatInfoScanner.cs @@ -436,7 +436,7 @@ namespace System.Globalization _ymdFlags |= FoundDatePattern.FoundMonthPatternFlag; break; case 'y': - i = ScanRepeatChar(pattern, 'y', i, out chCount); + i = ScanRepeatChar(pattern, 'y', i, out _); _ymdFlags |= FoundDatePattern.FoundYearPatternFlag; break; case 'd': diff --git a/src/System.Private.CoreLib/shared/System/Globalization/DateTimeParse.cs b/src/System.Private.CoreLib/shared/System/Globalization/DateTimeParse.cs index 138b69746..a0bc369dc 100644 --- a/src/System.Private.CoreLib/shared/System/Globalization/DateTimeParse.cs +++ b/src/System.Private.CoreLib/shared/System/Globalization/DateTimeParse.cs @@ -604,15 +604,13 @@ new DS[] { DS.ERROR, DS.TX_NNN, DS.TX_NNN, DS.TX_NNN, DS.ERROR, DS.ERROR, // private static bool Lex(DS dps, ref __DTString str, ref DateTimeToken dtok, ref DateTimeRawInfo raw, ref DateTimeResult result, ref DateTimeFormatInfo dtfi, DateTimeStyles styles) { - TokenType tokenType; - int tokenValue; int indexBeforeSeparator; char charBeforeSeparator; TokenType sep; dtok.dtt = DTT.Unk; // Assume the token is unkown. - str.GetRegularToken(out tokenType, out tokenValue, dtfi); + str.GetRegularToken(out TokenType tokenType, out int tokenValue, dtfi); #if _LOGGING if (s_tracingEnabled) @@ -1553,8 +1551,7 @@ new DS[] { DS.ERROR, DS.TX_NNN, DS.TX_NNN, DS.TX_NNN, DS.ERROR, DS.ERROR, GetDefaultYear(ref result, ref styles); - int order; - if (!GetMonthDayOrder(dtfi.MonthDayPattern, out order)) + if (!GetMonthDayOrder(dtfi.MonthDayPattern, out int order)) { result.SetFailure(ParseFailureKind.FormatWithParameter, nameof(SR.Format_BadDatePattern), dtfi.MonthDayPattern); return false; @@ -1595,8 +1592,7 @@ new DS[] { DS.ERROR, DS.TX_NNN, DS.TX_NNN, DS.TX_NNN, DS.ERROR, DS.ERROR, int n2 = raw.GetNumber(1); int n3 = raw.GetNumber(2); - int order; - if (!GetYearMonthDayOrder(dtfi.ShortDatePattern, out order)) + if (!GetYearMonthDayOrder(dtfi.ShortDatePattern, out int order)) { result.SetFailure(ParseFailureKind.FormatWithParameter, nameof(SR.Format_BadDatePattern), dtfi.ShortDatePattern); return false; @@ -1660,16 +1656,14 @@ new DS[] { DS.ERROR, DS.TX_NNN, DS.TX_NNN, DS.TX_NNN, DS.ERROR, DS.ERROR, // In the first and last cases, it could be either or neither, but a day is a better default interpretation // than a 2 digit year. - int monthDayOrder; - if (!GetMonthDayOrder(dtfi.MonthDayPattern, out monthDayOrder)) + if (!GetMonthDayOrder(dtfi.MonthDayPattern, out int monthDayOrder)) { result.SetFailure(ParseFailureKind.FormatWithParameter, nameof(SR.Format_BadDatePattern), dtfi.MonthDayPattern); return false; } if (monthDayOrder == ORDER_DM) { - int yearMonthOrder; - if (!GetYearMonthOrder(dtfi.YearMonthPattern, out yearMonthOrder)) + if (!GetYearMonthOrder(dtfi.YearMonthPattern, out int yearMonthOrder)) { result.SetFailure(ParseFailureKind.FormatWithParameter, nameof(SR.Format_BadDatePattern), dtfi.YearMonthPattern); return false; @@ -1702,8 +1696,7 @@ new DS[] { DS.ERROR, DS.TX_NNN, DS.TX_NNN, DS.TX_NNN, DS.ERROR, DS.ERROR, private static bool GetHebrewDayOfNM(ref DateTimeResult result, ref DateTimeRawInfo raw, DateTimeFormatInfo dtfi) { - int monthDayOrder; - if (!GetMonthDayOrder(dtfi.MonthDayPattern, out monthDayOrder)) + if (!GetMonthDayOrder(dtfi.MonthDayPattern, out int monthDayOrder)) { result.SetFailure(ParseFailureKind.FormatWithParameter, nameof(SR.Format_BadDatePattern), dtfi.MonthDayPattern); return false; @@ -1742,16 +1735,14 @@ new DS[] { DS.ERROR, DS.TX_NNN, DS.TX_NNN, DS.TX_NNN, DS.ERROR, DS.ERROR, // In the first and last cases, it could be either or neither, but a day is a better default interpretation // than a 2 digit year. - int monthDayOrder; - if (!GetMonthDayOrder(dtfi.MonthDayPattern, out monthDayOrder)) + if (!GetMonthDayOrder(dtfi.MonthDayPattern, out int monthDayOrder)) { result.SetFailure(ParseFailureKind.FormatWithParameter, nameof(SR.Format_BadDatePattern), dtfi.MonthDayPattern); return false; } if (monthDayOrder == ORDER_MD) { - int yearMonthOrder; - if (!GetYearMonthOrder(dtfi.YearMonthPattern, out yearMonthOrder)) + if (!GetYearMonthOrder(dtfi.YearMonthPattern, out int yearMonthOrder)) { result.SetFailure(ParseFailureKind.FormatWithParameter, nameof(SR.Format_BadDatePattern), dtfi.YearMonthPattern); return false; @@ -1788,8 +1779,7 @@ new DS[] { DS.ERROR, DS.TX_NNN, DS.TX_NNN, DS.TX_NNN, DS.ERROR, DS.ERROR, int n1 = raw.GetNumber(0); int n2 = raw.GetNumber(1); - int order; - if (!GetYearMonthDayOrder(dtfi.ShortDatePattern, out order)) + if (!GetYearMonthDayOrder(dtfi.ShortDatePattern, out int order)) { result.SetFailure(ParseFailureKind.FormatWithParameter, nameof(SR.Format_BadDatePattern), dtfi.ShortDatePattern); return false; @@ -1860,8 +1850,7 @@ new DS[] { DS.ERROR, DS.TX_NNN, DS.TX_NNN, DS.TX_NNN, DS.ERROR, DS.ERROR, string pattern = dtfi.ShortDatePattern; // For compatibility, don't throw if we can't determine the order, but default to YMD instead - int order; - if (GetYearMonthDayOrder(pattern, out order) && order == ORDER_YDM) + if (GetYearMonthDayOrder(pattern, out int order) && order == ORDER_YDM) { if (SetDateYMD(ref result, raw.year, n2, n1)) { @@ -1893,8 +1882,7 @@ new DS[] { DS.ERROR, DS.TX_NNN, DS.TX_NNN, DS.TX_NNN, DS.ERROR, DS.ERROR, int n1 = raw.GetNumber(0); int n2 = raw.GetNumber(1); - int order; - if (!GetYearMonthDayOrder(dtfi.ShortDatePattern, out order)) + if (!GetYearMonthDayOrder(dtfi.ShortDatePattern, out int order)) { result.SetFailure(ParseFailureKind.FormatWithParameter, nameof(SR.Format_BadDatePattern), dtfi.ShortDatePattern); return false; @@ -2139,8 +2127,7 @@ new DS[] { DS.ERROR, DS.TX_NNN, DS.TX_NNN, DS.TX_NNN, DS.ERROR, DS.ERROR, { if (((result.flags & ParseFlags.HaveYear) == 0) && ((result.flags & ParseFlags.HaveDay) == 0)) { - int order; - if (!GetYearMonthDayOrder(dtfi.ShortDatePattern, out order)) + if (!GetYearMonthDayOrder(dtfi.ShortDatePattern, out int order)) { result.SetFailure(ParseFailureKind.FormatWithParameter, nameof(SR.Format_BadDatePattern), dtfi.ShortDatePattern); return false; @@ -2686,9 +2673,8 @@ new DS[] { DS.ERROR, DS.TX_NNN, DS.TX_NNN, DS.TX_NNN, DS.ERROR, DS.ERROR, return false; } - DateTime time; if (!result.calendar.TryToDateTime(result.Year, result.Month, result.Day, - result.Hour, result.Minute, result.Second, 0, result.era, out time)) + result.Hour, result.Minute, result.Second, 0, result.era, out DateTime time)) { result.SetFailure(ParseFailureKind.FormatBadDateTimeCalendar, nameof(SR.Format_BadDateTimeCalendar)); TPTraceExit("0100 (result.calendar.TryToDateTime)", dps); @@ -2962,12 +2948,11 @@ new DS[] { DS.ERROR, DS.TX_NNN, DS.TX_NNN, DS.TX_NNN, DS.ERROR, DS.ERROR, { } str.Index--; - int hour, minute; int second = 0; double partSecond = 0; str.SkipWhiteSpaces(); - if (!ParseDigits(ref str, 2, out hour)) + if (!ParseDigits(ref str, 2, out int hour)) { result.SetBadDateTimeFailure(); return false; @@ -2979,7 +2964,7 @@ new DS[] { DS.ERROR, DS.TX_NNN, DS.TX_NNN, DS.TX_NNN, DS.ERROR, DS.ERROR, return false; } str.SkipWhiteSpaces(); - if (!ParseDigits(ref str, 2, out minute)) + if (!ParseDigits(ref str, 2, out int minute)) { result.SetBadDateTimeFailure(); return false; @@ -3052,10 +3037,9 @@ new DS[] { DS.ERROR, DS.TX_NNN, DS.TX_NNN, DS.TX_NNN, DS.ERROR, DS.ERROR, } } - DateTime time; Calendar calendar = GregorianCalendar.GetDefaultInstance(); if (!calendar.TryToDateTime(raw.year, raw.GetNumber(0), raw.GetNumber(1), - hour, minute, second, 0, result.era, out time)) + hour, minute, second, 0, result.era, out DateTime time)) { result.SetFailure(ParseFailureKind.FormatBadDateTimeCalendar, nameof(SR.Format_BadDateTimeCalendar)); return false; diff --git a/src/System.Private.CoreLib/shared/System/Globalization/GregorianCalendarHelper.cs b/src/System.Private.CoreLib/shared/System/Globalization/GregorianCalendarHelper.cs index 589a8b662..2649eca9b 100644 --- a/src/System.Private.CoreLib/shared/System/Globalization/GregorianCalendarHelper.cs +++ b/src/System.Private.CoreLib/shared/System/Globalization/GregorianCalendarHelper.cs @@ -211,7 +211,7 @@ namespace System.Globalization // Returns a given date part of this DateTime. This method is used // to compute the year, day-of-year, month, or day part. - internal virtual int GetDatePart(long ticks, int part) + internal int GetDatePart(long ticks, int part) { CheckTicksRange(ticks); // n = number of days since 1/1/0001 @@ -624,7 +624,7 @@ namespace System.Globalization return new DateTime(ticks); } - public virtual int GetWeekOfYear(DateTime time, CalendarWeekRule rule, DayOfWeek firstDayOfWeek) + public int GetWeekOfYear(DateTime time, CalendarWeekRule rule, DayOfWeek firstDayOfWeek) { CheckTicksRange(time.Ticks); // Use GregorianCalendar to get around the problem that the implmentation in Calendar.GetWeekOfYear() diff --git a/src/System.Private.CoreLib/shared/System/Globalization/HebrewCalendar.cs b/src/System.Private.CoreLib/shared/System/Globalization/HebrewCalendar.cs index e2d8e7214..c5cf3dfd3 100644 --- a/src/System.Private.CoreLib/shared/System/Globalization/HebrewCalendar.cs +++ b/src/System.Private.CoreLib/shared/System/Globalization/HebrewCalendar.cs @@ -438,7 +438,6 @@ namespace System.Globalization internal virtual int GetDatePart(long ticks, int part) { // The Gregorian year, month, day value for ticks. - int gregorianYear, gregorianMonth, gregorianDay; int hebrewYearType; // lunar year type long AbsoluteDate; // absolute date - absolute date 1/1/1600 @@ -449,7 +448,7 @@ namespace System.Globalization DateTime time = new DateTime(ticks); // Save the Gregorian date values. - time.GetDate(out gregorianYear, out gregorianMonth, out gregorianDay); + time.GetDate(out int gregorianYear, out int gregorianMonth, out int gregorianDay); DateBuffer lunarDate = new DateBuffer(); // lunar month and day for Jan 1 diff --git a/src/System.Private.CoreLib/shared/System/Globalization/LocaleData.Unix.cs b/src/System.Private.CoreLib/shared/System/Globalization/IcuLocaleData.cs similarity index 99% rename from src/System.Private.CoreLib/shared/System/Globalization/LocaleData.Unix.cs rename to src/System.Private.CoreLib/shared/System/Globalization/IcuLocaleData.cs index 2af5eb9c2..3750e7551 100644 --- a/src/System.Private.CoreLib/shared/System/Globalization/LocaleData.Unix.cs +++ b/src/System.Private.CoreLib/shared/System/Globalization/IcuLocaleData.cs @@ -10,7 +10,7 @@ using System.Diagnostics; namespace System.Globalization { - internal enum LocaleDataParts + internal enum IcuLocaleDataParts { Lcid = 0, AnsiCodePage = 1, @@ -23,7 +23,7 @@ namespace System.Globalization ConsoleLocaleIndex = 8 } - internal static class LocaleData + internal static class IcuLocaleData { // this is done rather than using a large readonly array of strings to avoid // generating a large amount of code in the static constructor. @@ -4454,7 +4454,7 @@ namespace System.Globalization return null; } - internal static int GetLocaleDataNumericPart(string cultureName, LocaleDataParts part) + internal static int GetLocaleDataNumericPart(string cultureName, IcuLocaleDataParts part) { int index = SearchCultureName(cultureName); if (index < 0) @@ -4480,7 +4480,7 @@ namespace System.Globalization return c_threeLetterWindowsLanguageName.Substring(index * 3, 3); } - internal static string GetLocaleDataMappedCulture(string cultureName, LocaleDataParts part) + internal static string GetLocaleDataMappedCulture(string cultureName, IcuLocaleDataParts part) { int indexToIndicesTable = GetLocaleDataNumericPart(cultureName, part); if (indexToIndicesTable < 0) @@ -4496,12 +4496,12 @@ namespace System.Globalization internal static string GetSpecificCultureName(string cultureName) { - return GetLocaleDataMappedCulture(cultureName, LocaleDataParts.SpecificLocaleIndex); + return GetLocaleDataMappedCulture(cultureName, IcuLocaleDataParts.SpecificLocaleIndex); } internal static string GetConsoleUICulture(string cultureName) { - return GetLocaleDataMappedCulture(cultureName, LocaleDataParts.ConsoleLocaleIndex); + return GetLocaleDataMappedCulture(cultureName, IcuLocaleDataParts.ConsoleLocaleIndex); } // SearchCultureName will binary search c_localeNames using s_localeNamesIndices. diff --git a/src/System.Private.CoreLib/shared/System/Globalization/IdnMapping.Unix.cs b/src/System.Private.CoreLib/shared/System/Globalization/IdnMapping.Icu.cs similarity index 84% rename from src/System.Private.CoreLib/shared/System/Globalization/IdnMapping.Unix.cs rename to src/System.Private.CoreLib/shared/System/Globalization/IdnMapping.Icu.cs index 4c6ee2c40..82b97b27d 100644 --- a/src/System.Private.CoreLib/shared/System/Globalization/IdnMapping.Unix.cs +++ b/src/System.Private.CoreLib/shared/System/Globalization/IdnMapping.Icu.cs @@ -8,12 +8,13 @@ namespace System.Globalization { public sealed partial class IdnMapping { - private unsafe string GetAsciiCore(string unicodeString, char* unicode, int count) + private unsafe string IcuGetAsciiCore(string unicodeString, char* unicode, int count) { Debug.Assert(!GlobalizationMode.Invariant); + Debug.Assert(!GlobalizationMode.UseNls); Debug.Assert(unicodeString != null && unicodeString.Length >= count); - uint flags = Flags; + uint flags = IcuFlags; CheckInvalidIdnCharacters(unicode, count, flags, nameof(unicode)); const int StackallocThreshold = 512; @@ -51,33 +52,35 @@ namespace System.Globalization } } - private unsafe string GetUnicodeCore(string asciiString, char* ascii, int count) + private unsafe string IcuGetUnicodeCore(string asciiString, char* ascii, int count) { Debug.Assert(!GlobalizationMode.Invariant); + Debug.Assert(!GlobalizationMode.UseNls); Debug.Assert(asciiString != null && asciiString.Length >= count); - uint flags = Flags; + uint flags = IcuFlags; CheckInvalidIdnCharacters(ascii, count, flags, nameof(ascii)); const int StackAllocThreshold = 512; if (count < StackAllocThreshold) { char* output = stackalloc char[count]; - return GetUnicodeCore(asciiString, ascii, count, flags, output, count, reattempt: true); + return IcuGetUnicodeCore(asciiString, ascii, count, flags, output, count, reattempt: true); } else { char[] output = new char[count]; fixed (char* pOutput = &output[0]) { - return GetUnicodeCore(asciiString, ascii, count, flags, pOutput, count, reattempt: true); + return IcuGetUnicodeCore(asciiString, ascii, count, flags, pOutput, count, reattempt: true); } } } - private unsafe string GetUnicodeCore(string asciiString, char* ascii, int count, uint flags, char* output, int outputLength, bool reattempt) + private unsafe string IcuGetUnicodeCore(string asciiString, char* ascii, int count, uint flags, char* output, int outputLength, bool reattempt) { Debug.Assert(!GlobalizationMode.Invariant); + Debug.Assert(!GlobalizationMode.UseNls); Debug.Assert(asciiString != null && asciiString.Length >= count); int realLen = Interop.Globalization.ToUnicode(flags, ascii, count, output, outputLength); @@ -95,7 +98,7 @@ namespace System.Globalization char[] newOutput = new char[realLen]; fixed (char* pNewOutput = newOutput) { - return GetUnicodeCore(asciiString, ascii, count, flags, pNewOutput, realLen, reattempt: false); + return IcuGetUnicodeCore(asciiString, ascii, count, flags, pNewOutput, realLen, reattempt: false); } } @@ -106,7 +109,7 @@ namespace System.Globalization // ---- PAL layer ends here ---- // ----------------------------- - private uint Flags + private uint IcuFlags { get { diff --git a/src/System.Private.CoreLib/shared/System/Globalization/IdnMapping.Windows.cs b/src/System.Private.CoreLib/shared/System/Globalization/IdnMapping.Nls.cs similarity index 77% rename from src/System.Private.CoreLib/shared/System/Globalization/IdnMapping.Windows.cs rename to src/System.Private.CoreLib/shared/System/Globalization/IdnMapping.Nls.cs index 6a97c04eb..54ebee274 100644 --- a/src/System.Private.CoreLib/shared/System/Globalization/IdnMapping.Windows.cs +++ b/src/System.Private.CoreLib/shared/System/Globalization/IdnMapping.Nls.cs @@ -10,12 +10,13 @@ namespace System.Globalization { public sealed partial class IdnMapping { - private unsafe string GetAsciiCore(string unicodeString, char* unicode, int count) + private unsafe string NlsGetAsciiCore(string unicodeString, char* unicode, int count) { Debug.Assert(!GlobalizationMode.Invariant); + Debug.Assert(GlobalizationMode.UseNls); Debug.Assert(unicodeString != null && unicodeString.Length >= count); - uint flags = Flags; + uint flags = NlsFlags; // Determine the required length int length = Interop.Normaliz.IdnToAscii(flags, unicode, count, null, 0); @@ -29,21 +30,22 @@ namespace System.Globalization if (length < StackAllocThreshold) { char* output = stackalloc char[length]; - return GetAsciiCore(unicodeString, unicode, count, flags, output, length); + return NlsGetAsciiCore(unicodeString, unicode, count, flags, output, length); } else { char[] output = new char[length]; fixed (char* pOutput = &output[0]) { - return GetAsciiCore(unicodeString, unicode, count, flags, pOutput, length); + return NlsGetAsciiCore(unicodeString, unicode, count, flags, pOutput, length); } } } - private unsafe string GetAsciiCore(string unicodeString, char* unicode, int count, uint flags, char* output, int outputLength) + private unsafe string NlsGetAsciiCore(string unicodeString, char* unicode, int count, uint flags, char* output, int outputLength) { Debug.Assert(!GlobalizationMode.Invariant); + Debug.Assert(GlobalizationMode.UseNls); Debug.Assert(unicodeString != null && unicodeString.Length >= count); int length = Interop.Normaliz.IdnToAscii(flags, unicode, count, output, outputLength); @@ -55,12 +57,13 @@ namespace System.Globalization return GetStringForOutput(unicodeString, unicode, count, output, length); } - private unsafe string GetUnicodeCore(string asciiString, char* ascii, int count) + private unsafe string NlsGetUnicodeCore(string asciiString, char* ascii, int count) { Debug.Assert(!GlobalizationMode.Invariant); + Debug.Assert(GlobalizationMode.UseNls); Debug.Assert(asciiString != null && asciiString.Length >= count); - uint flags = Flags; + uint flags = NlsFlags; // Determine the required length int length = Interop.Normaliz.IdnToUnicode(flags, ascii, count, null, 0); @@ -74,21 +77,22 @@ namespace System.Globalization if (length < StackAllocThreshold) { char* output = stackalloc char[length]; - return GetUnicodeCore(asciiString, ascii, count, flags, output, length); + return NlsGetUnicodeCore(asciiString, ascii, count, flags, output, length); } else { char[] output = new char[length]; fixed (char* pOutput = &output[0]) { - return GetUnicodeCore(asciiString, ascii, count, flags, pOutput, length); + return NlsGetUnicodeCore(asciiString, ascii, count, flags, pOutput, length); } } } - private unsafe string GetUnicodeCore(string asciiString, char* ascii, int count, uint flags, char* output, int outputLength) + private unsafe string NlsGetUnicodeCore(string asciiString, char* ascii, int count, uint flags, char* output, int outputLength) { Debug.Assert(!GlobalizationMode.Invariant); + Debug.Assert(GlobalizationMode.UseNls); Debug.Assert(asciiString != null && asciiString.Length >= count); int length = Interop.Normaliz.IdnToUnicode(flags, ascii, count, output, outputLength); @@ -104,7 +108,7 @@ namespace System.Globalization // ---- PAL layer ends here ---- // ----------------------------- - private uint Flags + private uint NlsFlags { get { diff --git a/src/System.Private.CoreLib/shared/System/Globalization/IdnMapping.cs b/src/System.Private.CoreLib/shared/System/Globalization/IdnMapping.cs index 3ec32b27a..f309a4227 100644 --- a/src/System.Private.CoreLib/shared/System/Globalization/IdnMapping.cs +++ b/src/System.Private.CoreLib/shared/System/Globalization/IdnMapping.cs @@ -92,7 +92,9 @@ namespace System.Globalization { fixed (char* pUnicode = unicode) { - return GetAsciiCore(unicode, pUnicode + index, count); + return GlobalizationMode.UseNls ? + NlsGetAsciiCore(unicode, pUnicode + index, count) : + IcuGetAsciiCore(unicode, pUnicode + index, count); } } } @@ -134,7 +136,9 @@ namespace System.Globalization { fixed (char* pAscii = ascii) { - return GetUnicodeCore(ascii, pAscii + index, count); + return GlobalizationMode.UseNls ? + NlsGetUnicodeCore(ascii, pAscii + index, count) : + IcuGetUnicodeCore(ascii, pAscii + index, count); } } } diff --git a/src/System.Private.CoreLib/shared/System/Globalization/JapaneseCalendar.Unix.cs b/src/System.Private.CoreLib/shared/System/Globalization/JapaneseCalendar.Icu.cs similarity index 95% rename from src/System.Private.CoreLib/shared/System/Globalization/JapaneseCalendar.Unix.cs rename to src/System.Private.CoreLib/shared/System/Globalization/JapaneseCalendar.Icu.cs index 0bbebba77..3f9aac684 100644 --- a/src/System.Private.CoreLib/shared/System/Globalization/JapaneseCalendar.Unix.cs +++ b/src/System.Private.CoreLib/shared/System/Globalization/JapaneseCalendar.Icu.cs @@ -9,13 +9,15 @@ namespace System.Globalization { public partial class JapaneseCalendar : Calendar { - private static EraInfo[]? GetJapaneseEras() + private static EraInfo[]? IcuGetJapaneseEras() { if (GlobalizationMode.Invariant) { return null; } + Debug.Assert(!GlobalizationMode.UseNls); + string[]? eraNames; if (!CalendarData.EnumCalendarInfo("ja-JP", CalendarId.JAPAN, CalendarDataType.EraNames, out eraNames)) { @@ -74,7 +76,7 @@ namespace System.Globalization { Debug.Assert(!GlobalizationMode.Invariant); - dateTime = default(DateTime); + dateTime = default; int startYear; int startMonth; diff --git a/src/System.Private.CoreLib/shared/System/Globalization/JapaneseCalendar.Win32.cs b/src/System.Private.CoreLib/shared/System/Globalization/JapaneseCalendar.Nls.cs similarity index 90% rename from src/System.Private.CoreLib/shared/System/Globalization/JapaneseCalendar.Win32.cs rename to src/System.Private.CoreLib/shared/System/Globalization/JapaneseCalendar.Nls.cs index 866765c42..09a59adb0 100644 --- a/src/System.Private.CoreLib/shared/System/Globalization/JapaneseCalendar.Win32.cs +++ b/src/System.Private.CoreLib/shared/System/Globalization/JapaneseCalendar.Nls.cs @@ -2,12 +2,17 @@ // 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.Diagnostics; + +#if TARGET_WINDOWS using Internal.Win32; +#endif namespace System.Globalization { public partial class JapaneseCalendar : Calendar { +#if TARGET_WINDOWS private const string JapaneseErasHive = @"System\CurrentControlSet\Control\Nls\Calendars\Japanese\Eras"; // We know about 4 built-in eras, however users may add additional era(s) from the @@ -25,8 +30,10 @@ namespace System.Globalization // . is a delimiter, but the value of . doesn't matter. // '_' marks the space between the japanese era name, japanese abbreviated era name // english name, and abbreviated english names. - private static EraInfo[]? GetJapaneseEras() + private static EraInfo[]? NlsGetJapaneseEras() { + Debug.Assert(GlobalizationMode.UseNls); + // Look in the registry key and see if we can find any ranges int iFoundEras = 0; EraInfo[]? registryEraRanges = null; @@ -114,6 +121,17 @@ namespace System.Globalization // Return our ranges return registryEraRanges; } +#else + // no-op, in Unix we never call this function. + // the reason to have it is to simplify the build + // this way we avoid having to include RegistryKey + // and all it's windows PInvokes. + private static EraInfo[]? NlsGetJapaneseEras() + { + Debug.Fail("Should never be called non-Windows platforms."); + throw new PlatformNotSupportedException(); + } +#endif // // Compare two era ranges, eg just the ticks @@ -153,14 +171,11 @@ namespace System.Globalization // yyyy.mm.dd although the . can be any character if (value.Length != 10) return null; - int year; - int month; - int day; ReadOnlySpan valueSpan = value.AsSpan(); - if (!int.TryParse(valueSpan.Slice(0, 4), NumberStyles.None, NumberFormatInfo.InvariantInfo, out year) || - !int.TryParse(valueSpan.Slice(5, 2), NumberStyles.None, NumberFormatInfo.InvariantInfo, out month) || - !int.TryParse(valueSpan.Slice(8, 2), NumberStyles.None, NumberFormatInfo.InvariantInfo, out day)) + if (!int.TryParse(valueSpan.Slice(0, 4), NumberStyles.None, NumberFormatInfo.InvariantInfo, out int year) || + !int.TryParse(valueSpan.Slice(5, 2), NumberStyles.None, NumberFormatInfo.InvariantInfo, out int month) || + !int.TryParse(valueSpan.Slice(8, 2), NumberStyles.None, NumberFormatInfo.InvariantInfo, out int day)) { // Couldn't convert integer, fail return null; diff --git a/src/System.Private.CoreLib/shared/System/Globalization/JapaneseCalendar.cs b/src/System.Private.CoreLib/shared/System/Globalization/JapaneseCalendar.cs index 02b15af27..2ed5af5b8 100644 --- a/src/System.Private.CoreLib/shared/System/Globalization/JapaneseCalendar.cs +++ b/src/System.Private.CoreLib/shared/System/Globalization/JapaneseCalendar.cs @@ -69,7 +69,7 @@ namespace System.Globalization { // See if we need to build it return s_japaneseEraInfo ?? - (s_japaneseEraInfo = GetJapaneseEras()) ?? + (s_japaneseEraInfo = GlobalizationMode.UseNls ? NlsGetJapaneseEras() : IcuGetJapaneseEras()) ?? // See if we have to use the built-in eras (s_japaneseEraInfo = new EraInfo[] { diff --git a/src/System.Private.CoreLib/shared/System/Globalization/Normalization.Unix.cs b/src/System.Private.CoreLib/shared/System/Globalization/Normalization.Icu.cs similarity index 54% rename from src/System.Private.CoreLib/shared/System/Globalization/Normalization.Unix.cs rename to src/System.Private.CoreLib/shared/System/Globalization/Normalization.Icu.cs index 37c9024c3..a897fcf6f 100644 --- a/src/System.Private.CoreLib/shared/System/Globalization/Normalization.Unix.cs +++ b/src/System.Private.CoreLib/shared/System/Globalization/Normalization.Icu.cs @@ -2,25 +2,27 @@ // 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.Buffers; using System.Diagnostics; +using System.Runtime.InteropServices; using System.Text; namespace System.Globalization { internal static partial class Normalization { - internal static bool IsNormalized(string strInput, NormalizationForm normalizationForm) + private static unsafe bool IcuIsNormalized(string strInput, NormalizationForm normalizationForm) { - if (GlobalizationMode.Invariant) - { - // In Invariant mode we assume all characters are normalized. - // This is because we don't support any linguistic operation on the strings - return true; - } + Debug.Assert(!GlobalizationMode.Invariant); + Debug.Assert(!GlobalizationMode.UseNls); ValidateArguments(strInput, normalizationForm); - int ret = Interop.Globalization.IsNormalized(normalizationForm, strInput, strInput.Length); + int ret; + fixed (char* pInput = strInput) + { + ret = Interop.Globalization.IsNormalized(normalizationForm, pInput, strInput.Length); + } if (ret == -1) { @@ -30,37 +32,69 @@ namespace System.Globalization return ret == 1; } - internal static string Normalize(string strInput, NormalizationForm normalizationForm) + private static unsafe string IcuNormalize(string strInput, NormalizationForm normalizationForm) { - if (GlobalizationMode.Invariant) - { - // In Invariant mode we assume all characters are normalized. - // This is because we don't support any linguistic operation on the strings - return strInput; - } + Debug.Assert(!GlobalizationMode.Invariant); + Debug.Assert(!GlobalizationMode.UseNls); ValidateArguments(strInput, normalizationForm); - char[] buf = new char[strInput.Length]; - - for (int attempts = 2; attempts > 0; attempts--) + char[]? toReturn = null; + try { - int realLen = Interop.Globalization.NormalizeString(normalizationForm, strInput, strInput.Length, buf, buf.Length); + const int StackallocThreshold = 512; - if (realLen == -1) + Span buffer = strInput.Length <= StackallocThreshold + ? stackalloc char[StackallocThreshold] + : (toReturn = ArrayPool.Shared.Rent(strInput.Length)); + + for (int attempt = 0; attempt < 2; attempt++) { - throw new ArgumentException(SR.Argument_InvalidCharSequenceNoIndex, nameof(strInput)); + int realLen; + fixed (char* pInput = strInput) + fixed (char* pDest = &MemoryMarshal.GetReference(buffer)) + { + realLen = Interop.Globalization.NormalizeString(normalizationForm, pInput, strInput.Length, pDest, buffer.Length); + } + + if (realLen == -1) + { + throw new ArgumentException(SR.Argument_InvalidCharSequenceNoIndex, nameof(strInput)); + } + + if (realLen <= buffer.Length) + { + ReadOnlySpan result = buffer.Slice(0, realLen); + return result.SequenceEqual(strInput) + ? strInput + : new string(result); + } + + Debug.Assert(realLen > StackallocThreshold); + + if (attempt == 0) + { + if (toReturn != null) + { + // Clear toReturn first to ensure we don't return the same buffer twice + char[] temp = toReturn; + toReturn = null; + ArrayPool.Shared.Return(temp); + } + + buffer = toReturn = ArrayPool.Shared.Rent(realLen); + } } - if (realLen <= buf.Length) - { - return new string(buf, 0, realLen); - } - - buf = new char[realLen]; + throw new ArgumentException(SR.Argument_InvalidCharSequenceNoIndex, nameof(strInput)); + } + finally + { + if (toReturn != null) + { + ArrayPool.Shared.Return(toReturn); + } } - - throw new ArgumentException(SR.Argument_InvalidCharSequenceNoIndex, nameof(strInput)); } // ----------------------------- diff --git a/src/System.Private.CoreLib/shared/System/Globalization/Normalization.Nls.cs b/src/System.Private.CoreLib/shared/System/Globalization/Normalization.Nls.cs new file mode 100644 index 000000000..e6c413580 --- /dev/null +++ b/src/System.Private.CoreLib/shared/System/Globalization/Normalization.Nls.cs @@ -0,0 +1,144 @@ +// 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.Buffers; +using System.Diagnostics; +using System.Runtime.InteropServices; +using System.Text; + +namespace System.Globalization +{ + internal static partial class Normalization + { + private static unsafe bool NlsIsNormalized(string strInput, NormalizationForm normalizationForm) + { + Debug.Assert(!GlobalizationMode.Invariant); + Debug.Assert(GlobalizationMode.UseNls); + Debug.Assert(strInput != null); + + // The only way to know if IsNormalizedString failed is through checking the Win32 last error + // IsNormalizedString pinvoke has SetLastError attribute property which will set the last error + // to 0 (ERROR_SUCCESS) before executing the calls. + Interop.BOOL result; + fixed (char* pInput = strInput) + { + result = Interop.Normaliz.IsNormalizedString(normalizationForm, pInput, strInput.Length); + } + + int lastError = Marshal.GetLastWin32Error(); + switch (lastError) + { + case Interop.Errors.ERROR_SUCCESS: + break; + + case Interop.Errors.ERROR_INVALID_PARAMETER: + case Interop.Errors.ERROR_NO_UNICODE_TRANSLATION: + if (normalizationForm != NormalizationForm.FormC && + normalizationForm != NormalizationForm.FormD && + normalizationForm != NormalizationForm.FormKC && + normalizationForm != NormalizationForm.FormKD) + { + throw new ArgumentException(SR.Argument_InvalidNormalizationForm, nameof(normalizationForm)); + } + + throw new ArgumentException(SR.Argument_InvalidCharSequenceNoIndex, nameof(strInput)); + + case Interop.Errors.ERROR_NOT_ENOUGH_MEMORY: + throw new OutOfMemoryException(); + + default: + throw new InvalidOperationException(SR.Format(SR.UnknownError_Num, lastError)); + } + + return result != Interop.BOOL.FALSE; + } + + private static unsafe string NlsNormalize(string strInput, NormalizationForm normalizationForm) + { + Debug.Assert(!GlobalizationMode.Invariant); + Debug.Assert(GlobalizationMode.UseNls); + Debug.Assert(strInput != null); + + if (strInput.Length == 0) + { + return string.Empty; + } + + char[]? toReturn = null; + try + { + const int StackallocThreshold = 512; + + Span buffer = strInput.Length <= StackallocThreshold + ? stackalloc char[StackallocThreshold] + : (toReturn = ArrayPool.Shared.Rent(strInput.Length)); + + while (true) + { + // we depend on Win32 last error when calling NormalizeString + // NormalizeString pinvoke has SetLastError attribute property which will set the last error + // to 0 (ERROR_SUCCESS) before executing the calls. + int realLength; + fixed (char* pInput = strInput) + fixed (char* pDest = &MemoryMarshal.GetReference(buffer)) + { + realLength = Interop.Normaliz.NormalizeString(normalizationForm, pInput, strInput.Length, pDest, buffer.Length); + } + int lastError = Marshal.GetLastWin32Error(); + + switch (lastError) + { + case Interop.Errors.ERROR_SUCCESS: + ReadOnlySpan result = buffer.Slice(0, realLength); + return result.SequenceEqual(strInput) + ? strInput + : new string(result); + + // Do appropriate stuff for the individual errors: + case Interop.Errors.ERROR_INSUFFICIENT_BUFFER: + realLength = Math.Abs(realLength); + Debug.Assert(realLength > buffer.Length, "Buffer overflow should have iLength > cBuffer.Length"); + if (toReturn != null) + { + // Clear toReturn first to ensure we don't return the same buffer twice + char[] temp = toReturn; + toReturn = null; + ArrayPool.Shared.Return(temp); + } + Debug.Assert(realLength > StackallocThreshold); + buffer = toReturn = ArrayPool.Shared.Rent(realLength); + continue; + + case Interop.Errors.ERROR_INVALID_PARAMETER: + case Interop.Errors.ERROR_NO_UNICODE_TRANSLATION: + if (normalizationForm != NormalizationForm.FormC && + normalizationForm != NormalizationForm.FormD && + normalizationForm != NormalizationForm.FormKC && + normalizationForm != NormalizationForm.FormKD) + { + throw new ArgumentException(SR.Argument_InvalidNormalizationForm, nameof(normalizationForm)); + } + + // Illegal code point or order found. Ie: FFFE or D800 D800, etc. + throw new ArgumentException(SR.Argument_InvalidCharSequenceNoIndex, nameof(strInput)); + + case Interop.Errors.ERROR_NOT_ENOUGH_MEMORY: + throw new OutOfMemoryException(); + + default: + // We shouldn't get here... + throw new InvalidOperationException(SR.Format(SR.UnknownError_Num, lastError)); + } + } + } + finally + { + if (toReturn != null) + { + ArrayPool.Shared.Return(toReturn); + } + } + } + } +} diff --git a/src/System.Private.CoreLib/shared/System/Globalization/Normalization.Windows.cs b/src/System.Private.CoreLib/shared/System/Globalization/Normalization.Windows.cs deleted file mode 100644 index e96789d16..000000000 --- a/src/System.Private.CoreLib/shared/System/Globalization/Normalization.Windows.cs +++ /dev/null @@ -1,148 +0,0 @@ -// 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.Diagnostics; -using System.Runtime.InteropServices; -using System.Text; - -namespace System.Globalization -{ - internal static partial class Normalization - { - internal static bool IsNormalized(string strInput, NormalizationForm normalizationForm) - { - if (GlobalizationMode.Invariant) - { - // In Invariant mode we assume all characters are normalized. - // This is because we don't support any linguistic operation on the strings - return true; - } - - Debug.Assert(strInput != null); - - // The only way to know if IsNormalizedString failed is through checking the Win32 last error - // IsNormalizedString pinvoke has SetLastError attribute property which will set the last error - // to 0 (ERROR_SUCCESS) before executing the calls. - bool result = Interop.Normaliz.IsNormalizedString((int)normalizationForm, strInput, strInput.Length); - - int lastError = Marshal.GetLastWin32Error(); - switch (lastError) - { - case Interop.Errors.ERROR_SUCCESS: - break; - - case Interop.Errors.ERROR_INVALID_PARAMETER: - case Interop.Errors.ERROR_NO_UNICODE_TRANSLATION: - if (normalizationForm != NormalizationForm.FormC && - normalizationForm != NormalizationForm.FormD && - normalizationForm != NormalizationForm.FormKC && - normalizationForm != NormalizationForm.FormKD) - { - throw new ArgumentException(SR.Argument_InvalidNormalizationForm, nameof(normalizationForm)); - } - - throw new ArgumentException(SR.Argument_InvalidCharSequenceNoIndex, nameof(strInput)); - - case Interop.Errors.ERROR_NOT_ENOUGH_MEMORY: - throw new OutOfMemoryException(); - - default: - throw new InvalidOperationException(SR.Format(SR.UnknownError_Num, lastError)); - } - - return result; - } - - internal static string Normalize(string strInput, NormalizationForm normalizationForm) - { - if (GlobalizationMode.Invariant) - { - // In Invariant mode we assume all characters are normalized. - // This is because we don't support any linguistic operation on the strings - return strInput; - } - - Debug.Assert(strInput != null); - - // we depend on Win32 last error when calling NormalizeString - // NormalizeString pinvoke has SetLastError attribute property which will set the last error - // to 0 (ERROR_SUCCESS) before executing the calls. - - // Guess our buffer size first - int iLength = Interop.Normaliz.NormalizeString((int)normalizationForm, strInput, strInput.Length, null, 0); - - int lastError = Marshal.GetLastWin32Error(); - // Could have an error (actually it'd be quite hard to have an error here) - if ((lastError != Interop.Errors.ERROR_SUCCESS) || iLength < 0) - { - if (lastError == Interop.Errors.ERROR_INVALID_PARAMETER) - { - if (normalizationForm != NormalizationForm.FormC && - normalizationForm != NormalizationForm.FormD && - normalizationForm != NormalizationForm.FormKC && - normalizationForm != NormalizationForm.FormKD) - { - throw new ArgumentException(SR.Argument_InvalidNormalizationForm, nameof(normalizationForm)); - } - - throw new ArgumentException(SR.Argument_InvalidCharSequenceNoIndex, nameof(strInput)); - } - - // We shouldn't really be able to get here..., guessing length is - // a trivial math function... - // Can't really be Out of Memory, but just in case: - if (lastError == Interop.Errors.ERROR_NOT_ENOUGH_MEMORY) - throw new OutOfMemoryException(); - - // Who knows what happened? Not us! - throw new InvalidOperationException(SR.Format(SR.UnknownError_Num, lastError)); - } - - // Don't break for empty strings (only possible for D & KD and not really possible at that) - if (iLength == 0) return string.Empty; - - // Someplace to stick our buffer - char[] cBuffer; - - while (true) - { - // (re)allocation buffer and normalize string - cBuffer = new char[iLength]; - - // NormalizeString pinvoke has SetLastError attribute property which will set the last error - // to 0 (ERROR_SUCCESS) before executing the calls. - iLength = Interop.Normaliz.NormalizeString((int)normalizationForm, strInput, strInput.Length, cBuffer, cBuffer.Length); - lastError = Marshal.GetLastWin32Error(); - - if (lastError == Interop.Errors.ERROR_SUCCESS) - break; - - // Could have an error (actually it'd be quite hard to have an error here) - switch (lastError) - { - // Do appropriate stuff for the individual errors: - case Interop.Errors.ERROR_INSUFFICIENT_BUFFER: - iLength = Math.Abs(iLength); - Debug.Assert(iLength > cBuffer.Length, "Buffer overflow should have iLength > cBuffer.Length"); - continue; - - case Interop.Errors.ERROR_INVALID_PARAMETER: - case Interop.Errors.ERROR_NO_UNICODE_TRANSLATION: - // Illegal code point or order found. Ie: FFFE or D800 D800, etc. - throw new ArgumentException(SR.Argument_InvalidCharSequenceNoIndex, nameof(strInput)); - - case Interop.Errors.ERROR_NOT_ENOUGH_MEMORY: - throw new OutOfMemoryException(); - - default: - // We shouldn't get here... - throw new InvalidOperationException(SR.Format(SR.UnknownError_Num, lastError)); - } - } - - // Copy our buffer into our new string, which will be the appropriate size - return new string(cBuffer, 0, iLength); - } - } -} diff --git a/src/System.Private.CoreLib/shared/System/Globalization/Normalization.cs b/src/System.Private.CoreLib/shared/System/Globalization/Normalization.cs new file mode 100644 index 000000000..d71b3380a --- /dev/null +++ b/src/System.Private.CoreLib/shared/System/Globalization/Normalization.cs @@ -0,0 +1,40 @@ +// 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.Diagnostics; +using System.Text; + +namespace System.Globalization +{ + internal static partial class Normalization + { + internal static bool IsNormalized(string strInput, NormalizationForm normalizationForm) + { + if (GlobalizationMode.Invariant) + { + // In Invariant mode we assume all characters are normalized. + // This is because we don't support any linguistic operation on the strings + return true; + } + + return GlobalizationMode.UseNls ? + NlsIsNormalized(strInput, normalizationForm) : + IcuIsNormalized(strInput, normalizationForm); + } + + internal static string Normalize(string strInput, NormalizationForm normalizationForm) + { + if (GlobalizationMode.Invariant) + { + // In Invariant mode we assume all characters are normalized. + // This is because we don't support any linguistic operation on the strings + return strInput; + } + + return GlobalizationMode.UseNls ? + NlsNormalize(strInput, normalizationForm) : + IcuNormalize(strInput, normalizationForm); + } + } +} diff --git a/src/System.Private.CoreLib/shared/System/Globalization/RegionInfo.cs b/src/System.Private.CoreLib/shared/System/Globalization/RegionInfo.cs index ccaa806ad..47894cc4a 100644 --- a/src/System.Private.CoreLib/shared/System/Globalization/RegionInfo.cs +++ b/src/System.Private.CoreLib/shared/System/Globalization/RegionInfo.cs @@ -96,7 +96,7 @@ namespace System.Globalization RegionInfo? temp = s_currentRegionInfo; if (temp == null) { - temp = new RegionInfo(CultureInfo.CurrentCulture._cultureData); + temp = new RegionInfo(CultureData.GetCurrentRegionData()); // Need full name for custom cultures temp._name = temp._cultureData.RegionName; diff --git a/src/System.Private.CoreLib/shared/System/Globalization/SortKey.cs b/src/System.Private.CoreLib/shared/System/Globalization/SortKey.cs index a3690c1f3..f845908c7 100644 --- a/src/System.Private.CoreLib/shared/System/Globalization/SortKey.cs +++ b/src/System.Private.CoreLib/shared/System/Globalization/SortKey.cs @@ -11,7 +11,7 @@ namespace System.Globalization /// public sealed partial class SortKey { - private readonly string _localeName; + private readonly CompareInfo _compareInfo; private readonly CompareOptions _options; private readonly string _string; private readonly byte[] _keyData; @@ -20,10 +20,10 @@ namespace System.Globalization /// The following constructor is designed to be called from CompareInfo to get the /// the sort key of specific string for synthetic culture /// - internal SortKey(string localeName, string str, CompareOptions options, byte[] keyData) + internal SortKey(CompareInfo compareInfo, string str, CompareOptions options, byte[] keyData) { _keyData = keyData; - _localeName = localeName; + _compareInfo = compareInfo; _options = options; _string = str; } @@ -75,13 +75,12 @@ namespace System.Globalization public override int GetHashCode() { - // keep this in sync with CompareInfo.GetHashCodeOfString - return Marvin.ComputeHash32(_keyData, Marvin.DefaultSeed); + return _compareInfo.GetHashCode(_string, _options); } public override string ToString() { - return "SortKey - " + _localeName + ", " + _options + ", " + _string; + return "SortKey - " + _compareInfo.Name + ", " + _options + ", " + _string; } } } diff --git a/src/System.Private.CoreLib/shared/System/Globalization/TextInfo.Unix.cs b/src/System.Private.CoreLib/shared/System/Globalization/TextInfo.Icu.cs similarity index 87% rename from src/System.Private.CoreLib/shared/System/Globalization/TextInfo.Unix.cs rename to src/System.Private.CoreLib/shared/System/Globalization/TextInfo.Icu.cs index 02e7c5f50..d499c4085 100644 --- a/src/System.Private.CoreLib/shared/System/Globalization/TextInfo.Unix.cs +++ b/src/System.Private.CoreLib/shared/System/Globalization/TextInfo.Icu.cs @@ -3,9 +3,6 @@ // See the LICENSE file in the project root for more information. using System.Diagnostics; -using System.Runtime.InteropServices; -using System.Security; -using System.Text; namespace System.Globalization { @@ -13,8 +10,6 @@ namespace System.Globalization { private Tristate _needsTurkishCasing = Tristate.NotInitialized; - private void FinishInitialization() { } - // ----------------------------- // ---- PAL layer ends here ---- // ----------------------------- @@ -28,9 +23,10 @@ namespace System.Globalization private bool IsInvariant { get { return _cultureName.Length == 0; } } - internal unsafe void ChangeCase(char* src, int srcLen, char* dstBuffer, int dstBufferCapacity, bool bToUpper) + internal unsafe void IcuChangeCase(char* src, int srcLen, char* dstBuffer, int dstBufferCapacity, bool bToUpper) { Debug.Assert(!GlobalizationMode.Invariant); + Debug.Assert(!GlobalizationMode.UseNls); if (IsInvariant) { diff --git a/src/System.Private.CoreLib/shared/System/Globalization/TextInfo.Windows.cs b/src/System.Private.CoreLib/shared/System/Globalization/TextInfo.Nls.cs similarity index 88% rename from src/System.Private.CoreLib/shared/System/Globalization/TextInfo.Windows.cs rename to src/System.Private.CoreLib/shared/System/Globalization/TextInfo.Nls.cs index 948644769..b49552f20 100644 --- a/src/System.Private.CoreLib/shared/System/Globalization/TextInfo.Windows.cs +++ b/src/System.Private.CoreLib/shared/System/Globalization/TextInfo.Nls.cs @@ -8,14 +8,10 @@ namespace System.Globalization { public partial class TextInfo { - private unsafe void FinishInitialization() - { - _sortHandle = CompareInfo.GetSortHandle(_textInfoName); - } - - private unsafe void ChangeCase(char* pSource, int pSourceLen, char* pResult, int pResultLen, bool toUpper) + private unsafe void NlsChangeCase(char* pSource, int pSourceLen, char* pResult, int pResultLen, bool toUpper) { Debug.Assert(!GlobalizationMode.Invariant); + Debug.Assert(GlobalizationMode.UseNls); Debug.Assert(pSource != null); Debug.Assert(pResult != null); Debug.Assert(pSourceLen >= 0); diff --git a/src/System.Private.CoreLib/shared/System/Globalization/TextInfo.cs b/src/System.Private.CoreLib/shared/System/Globalization/TextInfo.cs index f8e2e0c45..eaa2042fd 100644 --- a/src/System.Private.CoreLib/shared/System/Globalization/TextInfo.cs +++ b/src/System.Private.CoreLib/shared/System/Globalization/TextInfo.cs @@ -54,7 +54,10 @@ namespace System.Globalization _cultureName = _cultureData.CultureName; _textInfoName = _cultureData.TextInfoName; - FinishInitialization(); + if (GlobalizationMode.UseNls) + { + _sortHandle = CompareInfo.NlsGetSortHandle(_textInfoName); + } } private TextInfo(CultureData cultureData, bool readOnly) @@ -148,7 +151,7 @@ namespace System.Globalization /// public char ToLower(char c) { - if (GlobalizationMode.Invariant || (IsAscii(c) && IsAsciiCasingSameAsInvariant)) + if (GlobalizationMode.Invariant || (UnicodeUtility.IsAsciiCodePoint(c) && IsAsciiCasingSameAsInvariant)) { return ToLowerAsciiInvariant(c); } @@ -156,6 +159,16 @@ namespace System.Globalization return ChangeCase(c, toUpper: false); } + internal static char ToLowerInvariant(char c) + { + if (GlobalizationMode.Invariant || UnicodeUtility.IsAsciiCodePoint(c)) + { + return ToLowerAsciiInvariant(c); + } + + return Invariant.ChangeCase(c, toUpper: false); + } + public string ToLower(string str) { if (str == null) @@ -176,7 +189,7 @@ namespace System.Globalization Debug.Assert(!GlobalizationMode.Invariant); char dst = default; - ChangeCase(&c, 1, &dst, 1, toUpper); + ChangeCaseCore(&c, 1, &dst, 1, toUpper); return dst; } @@ -301,7 +314,7 @@ namespace System.Globalization // has a case conversion that's different from the invariant culture, even for ASCII data (e.g., tr-TR converts // 'i' (U+0069) to Latin Capital Letter I With Dot Above (U+0130)). - ChangeCase(pSource + currIdx, charCount, pDestination + currIdx, charCount, toUpper); + ChangeCaseCore(pSource + currIdx, charCount, pDestination + currIdx, charCount, toUpper); } Return: @@ -406,7 +419,7 @@ namespace System.Globalization // and run the culture-aware logic over the remainder of the data fixed (char* pResult = result) { - ChangeCase(pSource + currIdx, source.Length - (int)currIdx, pResult + currIdx, result.Length - (int)currIdx, toUpper); + ChangeCaseCore(pSource + currIdx, source.Length - (int)currIdx, pResult + currIdx, result.Length - (int)currIdx, toUpper); } return result; } @@ -525,11 +538,13 @@ namespace System.Globalization } } + [MethodImpl(MethodImplOptions.AggressiveInlining)] private static char ToLowerAsciiInvariant(char c) { - if ((uint)(c - 'A') <= (uint)('Z' - 'A')) + if (UnicodeUtility.IsInRangeInclusive(c, 'A', 'Z')) { - c = (char)(c | 0x20); + // on x86, extending BYTE -> DWORD is more efficient than WORD -> DWORD + c = (char)(byte)(c | 0x20); } return c; } @@ -540,7 +555,7 @@ namespace System.Globalization /// public char ToUpper(char c) { - if (GlobalizationMode.Invariant || (IsAscii(c) && IsAsciiCasingSameAsInvariant)) + if (GlobalizationMode.Invariant || (UnicodeUtility.IsAsciiCodePoint(c) && IsAsciiCasingSameAsInvariant)) { return ToUpperAsciiInvariant(c); } @@ -548,6 +563,16 @@ namespace System.Globalization return ChangeCase(c, toUpper: true); } + internal static char ToUpperInvariant(char c) + { + if (GlobalizationMode.Invariant || UnicodeUtility.IsAsciiCodePoint(c)) + { + return ToUpperAsciiInvariant(c); + } + + return Invariant.ChangeCase(c, toUpper: true); + } + public string ToUpper(string str) { if (str == null) @@ -563,17 +588,16 @@ namespace System.Globalization return ChangeCaseCommon(str); } - internal static char ToUpperAsciiInvariant(char c) + [MethodImpl(MethodImplOptions.AggressiveInlining)] + private static char ToUpperAsciiInvariant(char c) { - if ((uint)(c - 'a') <= (uint)('z' - 'a')) + if (UnicodeUtility.IsInRangeInclusive(c, 'a', 'z')) { - c = (char)(c & ~0x20); + c = (char)(c & 0x5F); // = low 7 bits of ~0x20 } return c; } - private static bool IsAscii(char c) => c < 0x80; - private bool IsAsciiCasingSameAsInvariant { [MethodImpl(MethodImplOptions.AggressiveInlining)] @@ -646,8 +670,7 @@ namespace System.Globalization for (int i = 0; i < str.Length; i++) { - int charLen; - UnicodeCategory charType = CharUnicodeInfo.GetUnicodeCategoryInternal(str, i, out charLen); + UnicodeCategory charType = CharUnicodeInfo.GetUnicodeCategoryInternal(str, i, out int charLen); if (char.CheckLetter(charType)) { // Special case to check for Dutch specific titlecasing with "IJ" characters @@ -816,6 +839,18 @@ namespace System.Globalization return inputIndex; } + private unsafe void ChangeCaseCore(char* src, int srcLen, char* dstBuffer, int dstBufferCapacity, bool bToUpper) + { + if (GlobalizationMode.UseNls) + { + NlsChangeCase(src, srcLen, dstBuffer, dstBufferCapacity, bToUpper); + } + else + { + IcuChangeCase(src, srcLen, dstBuffer, dstBufferCapacity, bToUpper); + } + } + // Used in ToTitleCase(): // When we find a starting letter, the following array decides if a category should be // considered as word seprator or not. diff --git a/src/System.Private.CoreLib/shared/System/Globalization/TimeSpanParse.cs b/src/System.Private.CoreLib/shared/System/Globalization/TimeSpanParse.cs index 0a2df7734..0bc27f555 100644 --- a/src/System.Private.CoreLib/shared/System/Globalization/TimeSpanParse.cs +++ b/src/System.Private.CoreLib/shared/System/Globalization/TimeSpanParse.cs @@ -652,7 +652,7 @@ namespace System.Globalization return false; } - internal static TimeSpan ParseExactMultiple(ReadOnlySpan input, string[] formats, IFormatProvider? formatProvider, TimeSpanStyles styles) + internal static TimeSpan ParseExactMultiple(ReadOnlySpan input, string?[]? formats, IFormatProvider? formatProvider, TimeSpanStyles styles) { var parseResult = new TimeSpanResult(throwOnFailure: true, originalTimeSpanString: input); bool success = TryParseExactMultipleTimeSpan(input, formats, formatProvider, styles, ref parseResult); @@ -660,7 +660,7 @@ namespace System.Globalization return parseResult.parsedTimeSpan; } - internal static bool TryParseExactMultiple(ReadOnlySpan input, string[] formats, IFormatProvider? formatProvider, TimeSpanStyles styles, out TimeSpan result) + internal static bool TryParseExactMultiple(ReadOnlySpan input, string?[]? formats, IFormatProvider? formatProvider, TimeSpanStyles styles, out TimeSpan result) { var parseResult = new TimeSpanResult(throwOnFailure: false, originalTimeSpanString: input); @@ -792,9 +792,8 @@ namespace System.Globalization if (match) { - long ticks; - if (!TryTimeToTicks(positive, raw._numbers0, raw._numbers1, raw._numbers2, raw._numbers3, raw._numbers4, out ticks)) + if (!TryTimeToTicks(positive, raw._numbers0, raw._numbers1, raw._numbers2, raw._numbers3, raw._numbers4, out long ticks)) { return result.SetOverflowFailure(); } @@ -1117,10 +1116,9 @@ namespace System.Globalization if (match) { - long ticks; var zero = new TimeSpanToken(0); - if (!TryTimeToTicks(positive, zero, raw._numbers0, raw._numbers1, zero, zero, out ticks)) + if (!TryTimeToTicks(positive, zero, raw._numbers0, raw._numbers1, zero, zero, out long ticks)) { return result.SetOverflowFailure(); } @@ -1187,10 +1185,9 @@ namespace System.Globalization if (match) { - long ticks; var zero = new TimeSpanToken(0); - if (!TryTimeToTicks(positive, raw._numbers0, zero, zero, zero, zero, out ticks)) + if (!TryTimeToTicks(positive, raw._numbers0, zero, zero, zero, zero, out long ticks)) { return result.SetOverflowFailure(); } @@ -1520,8 +1517,7 @@ namespace System.Globalization } else { - int days; - if (!ParseInt((int)(0x7FFFFFFFFFFFFFFFL / TimeSpan.TicksPerDay), out days, ref result)) + if (!ParseInt((int)(0x7FFFFFFFFFFFFFFFL / TimeSpan.TicksPerDay), out int days, ref result)) { return false; } @@ -1531,8 +1527,7 @@ namespace System.Globalization if (_ch == '.') { NextChar(); - long remainingTime; - if (!ParseTime(out remainingTime, ref result)) + if (!ParseTime(out long remainingTime, ref result)) { return false; } @@ -1604,9 +1599,8 @@ namespace System.Globalization internal bool ParseTime(out long time, ref TimeSpanResult result) { time = 0; - int unit; - if (!ParseInt(23, out unit, ref result)) + if (!ParseInt(23, out int unit, ref result)) { return false; } @@ -1663,7 +1657,7 @@ namespace System.Globalization } /// Common private ParseExactMultiple method called by both ParseExactMultiple and TryParseExactMultiple. - private static bool TryParseExactMultipleTimeSpan(ReadOnlySpan input, string[] formats, IFormatProvider? formatProvider, TimeSpanStyles styles, ref TimeSpanResult result) + private static bool TryParseExactMultipleTimeSpan(ReadOnlySpan input, string?[]? formats, IFormatProvider? formatProvider, TimeSpanStyles styles, ref TimeSpanResult result) { if (formats == null) { @@ -1684,7 +1678,9 @@ namespace System.Globalization // one of the formats. for (int i = 0; i < formats.Length; i++) { - if (formats[i] == null || formats[i].Length == 0) + string? format = formats[i]; + + if (string.IsNullOrEmpty(format)) { return result.SetBadFormatSpecifierFailure(); } @@ -1692,7 +1688,7 @@ namespace System.Globalization // Create a new non-throwing result each time to ensure the runs are independent. TimeSpanResult innerResult = new TimeSpanResult(throwOnFailure: false, originalTimeSpanString: input); - if (TryParseExactTimeSpan(input, formats[i], formatProvider, styles, ref innerResult)) + if (TryParseExactTimeSpan(input, format, formatProvider, styles, ref innerResult)) { result.parsedTimeSpan = innerResult.parsedTimeSpan; return true; diff --git a/src/System.Private.CoreLib/shared/System/Guid.Unix.cs b/src/System.Private.CoreLib/shared/System/Guid.Unix.cs index 5a1364d03..3ee426d23 100644 --- a/src/System.Private.CoreLib/shared/System/Guid.Unix.cs +++ b/src/System.Private.CoreLib/shared/System/Guid.Unix.cs @@ -2,9 +2,6 @@ // 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.Diagnostics; -using System.Runtime.InteropServices; - namespace System { public partial struct Guid diff --git a/src/System.Private.CoreLib/shared/System/Guid.Windows.cs b/src/System.Private.CoreLib/shared/System/Guid.Windows.cs index 5947cea46..c166b1e64 100644 --- a/src/System.Private.CoreLib/shared/System/Guid.Windows.cs +++ b/src/System.Private.CoreLib/shared/System/Guid.Windows.cs @@ -11,8 +11,7 @@ namespace System // CoCreateGuid should never return Guid.Empty, since it attempts to maintain some // uniqueness guarantees. - Guid g; - int hr = Interop.Ole32.CoCreateGuid(out g); + int hr = Interop.Ole32.CoCreateGuid(out Guid g); // We don't expect that this will ever throw an error, none are even documented, and so we don't want to pull // in the HR to ComException mappings into the core library just for this so we will try a generic exception if // we ever hit this condition. diff --git a/src/System.Private.CoreLib/shared/System/Guid.cs b/src/System.Private.CoreLib/shared/System/Guid.cs index 3d68e4503..478384754 100644 --- a/src/System.Private.CoreLib/shared/System/Guid.cs +++ b/src/System.Private.CoreLib/shared/System/Guid.cs @@ -3,6 +3,7 @@ // See the LICENSE file in the project root for more information. using System.Diagnostics; +using System.Diagnostics.CodeAnalysis; using System.Globalization; using System.Runtime.CompilerServices; using System.Runtime.InteropServices; @@ -196,7 +197,7 @@ namespace System return result._parsedGuid; } - public static bool TryParse(string? input, out Guid result) + public static bool TryParse([NotNullWhen(true)] string? input, out Guid result) { if (input == null) { @@ -251,7 +252,7 @@ namespace System return result._parsedGuid; } - public static bool TryParseExact(string? input, string? format, out Guid result) + public static bool TryParseExact([NotNullWhen(true)] string? input, [NotNullWhen(true)] string? format, out Guid result) { if (input == null) { @@ -374,9 +375,8 @@ namespace System ref Guid g = ref result._parsedGuid; - uint uintTmp; if (TryParseHex(guidString.Slice(0, 8), out Unsafe.As(ref g._a)) && // _a - TryParseHex(guidString.Slice(9, 4), out uintTmp)) // _b + TryParseHex(guidString.Slice(9, 4), out uint uintTmp)) // _b { g._b = (short)uintTmp; @@ -424,9 +424,8 @@ namespace System ref Guid g = ref result._parsedGuid; - uint uintTmp; if (uint.TryParse(guidString.Slice(0, 8), NumberStyles.AllowHexSpecifier, null, out Unsafe.As(ref g._a)) && // _a - uint.TryParse(guidString.Slice(8, 8), NumberStyles.AllowHexSpecifier, null, out uintTmp)) // _b, _c + uint.TryParse(guidString.Slice(8, 8), NumberStyles.AllowHexSpecifier, null, out uint uintTmp)) // _b, _c { g._b = (short)(uintTmp >> 16); g._c = (short)uintTmp; @@ -600,8 +599,7 @@ namespace System } // Read in the number - uint byteVal; - if (!TryParseHex(guidString.Slice(numStart, numLen), out byteVal, ref overflow) || overflow || byteVal > byte.MaxValue) + if (!TryParseHex(guidString.Slice(numStart, numLen), out uint byteVal, ref overflow) || overflow || byteVal > byte.MaxValue) { // The previous implementation had some odd inconsistencies, which are carried forward here. // The byte values in the X format are treated as integers with regards to overflow, so @@ -635,8 +633,7 @@ namespace System private static bool TryParseHex(ReadOnlySpan guidString, out short result, ref bool overflow) { - uint tmp; - bool success = TryParseHex(guidString, out tmp, ref overflow); + bool success = TryParseHex(guidString, out uint tmp, ref overflow); result = (short)tmp; return success; } @@ -1028,8 +1025,7 @@ namespace System string guidString = string.FastAllocateString(guidSize); - int bytesWritten; - bool result = TryFormat(new Span(ref guidString.GetRawStringData(), guidString.Length), out bytesWritten, format); + bool result = TryFormat(new Span(ref guidString.GetRawStringData(), guidString.Length), out int bytesWritten, format); Debug.Assert(result && bytesWritten == guidString.Length, "Formatting guid should have succeeded."); return guidString; diff --git a/src/System.Private.CoreLib/shared/System/IO/BinaryReader.cs b/src/System.Private.CoreLib/shared/System/IO/BinaryReader.cs index cf8e49545..8b9a53f39 100644 --- a/src/System.Private.CoreLib/shared/System/IO/BinaryReader.cs +++ b/src/System.Private.CoreLib/shared/System/IO/BinaryReader.cs @@ -306,7 +306,10 @@ namespace System.IO return new string(_charBuffer, 0, charsRead); } - sb ??= StringBuilderCache.Acquire(stringLength); // Actual string length in chars may be smaller. + // Since we could be reading from an untrusted data source, limit the initial size of the + // StringBuilder instance we're about to get or create. It'll expand automatically as needed. + + sb ??= StringBuilderCache.Acquire(Math.Min(stringLength, StringBuilderCache.MaxBuilderSize)); // Actual string length in chars may be smaller. sb.Append(_charBuffer, 0, charsRead); currPos += n; } while (currPos < stringLength); @@ -584,28 +587,88 @@ namespace System.IO } while (bytesRead < numBytes); } - protected internal int Read7BitEncodedInt() + public int Read7BitEncodedInt() { - // Read out an Int32 7 bits at a time. The high bit - // of the byte when on means to continue reading more bytes. - int count = 0; - int shift = 0; - byte b; - do - { - // Check for a corrupted stream. Read a max of 5 bytes. - // In a future version, add a DataFormatException. - if (shift == 5 * 7) // 5 bytes max per Int32, shift += 7 - { - throw new FormatException(SR.Format_Bad7BitInt32); - } + // Unlike writing, we can't delegate to the 64-bit read on + // 64-bit platforms. The reason for this is that we want to + // stop consuming bytes if we encounter an integer overflow. + uint result = 0; + byte byteReadJustNow; + + // Read the integer 7 bits at a time. The high bit + // of the byte when on means to continue reading more bytes. + // + // There are two failure cases: we've read more than 5 bytes, + // or the fifth byte is about to cause integer overflow. + // This means that we can read the first 4 bytes without + // worrying about integer overflow. + + const int MaxBytesWithoutOverflow = 4; + for (int shift = 0; shift < MaxBytesWithoutOverflow * 7; shift += 7) + { // ReadByte handles end of stream cases for us. - b = ReadByte(); - count |= (b & 0x7F) << shift; - shift += 7; - } while ((b & 0x80) != 0); - return count; + byteReadJustNow = ReadByte(); + result |= (byteReadJustNow & 0x7Fu) << shift; + + if (byteReadJustNow <= 0x7Fu) + { + return (int)result; // early exit + } + } + + // Read the 5th byte. Since we already read 28 bits, + // the value of this byte must fit within 4 bits (32 - 28), + // and it must not have the high bit set. + + byteReadJustNow = ReadByte(); + if (byteReadJustNow > 0b_1111u) + { + throw new FormatException(SR.Format_Bad7BitInt); + } + + result |= (uint)byteReadJustNow << (MaxBytesWithoutOverflow * 7); + return (int)result; + } + + public long Read7BitEncodedInt64() + { + ulong result = 0; + byte byteReadJustNow; + + // Read the integer 7 bits at a time. The high bit + // of the byte when on means to continue reading more bytes. + // + // There are two failure cases: we've read more than 10 bytes, + // or the tenth byte is about to cause integer overflow. + // This means that we can read the first 9 bytes without + // worrying about integer overflow. + + const int MaxBytesWithoutOverflow = 9; + for (int shift = 0; shift < MaxBytesWithoutOverflow * 7; shift += 7) + { + // ReadByte handles end of stream cases for us. + byteReadJustNow = ReadByte(); + result |= (byteReadJustNow & 0x7Ful) << shift; + + if (byteReadJustNow <= 0x7Fu) + { + return (long)result; // early exit + } + } + + // Read the 10th byte. Since we already read 63 bits, + // the value of this byte must fit within 1 bit (64 - 63), + // and it must not have the high bit set. + + byteReadJustNow = ReadByte(); + if (byteReadJustNow > 0b_1u) + { + throw new FormatException(SR.Format_Bad7BitInt); + } + + result |= (ulong)byteReadJustNow << (MaxBytesWithoutOverflow * 7); + return (long)result; } } } diff --git a/src/System.Private.CoreLib/shared/System/IO/BinaryWriter.cs b/src/System.Private.CoreLib/shared/System/IO/BinaryWriter.cs index fde451656..80fd193b5 100644 --- a/src/System.Private.CoreLib/shared/System/IO/BinaryWriter.cs +++ b/src/System.Private.CoreLib/shared/System/IO/BinaryWriter.cs @@ -453,17 +453,42 @@ namespace System.IO } } - protected void Write7BitEncodedInt(int value) + public void Write7BitEncodedInt(int value) { - // Write out an int 7 bits at a time. The high bit of the byte, + uint uValue = (uint)value; + + // Write out an int 7 bits at a time. The high bit of the byte, // when on, tells reader to continue reading more bytes. - uint v = (uint)value; // support negative numbers - while (v >= 0x80) + // + // Using the constants 0x7F and ~0x7F below offers smaller + // codegen than using the constant 0x80. + + while (uValue > 0x7Fu) { - Write((byte)(v | 0x80)); - v >>= 7; + Write((byte)(uValue | ~0x7Fu)); + uValue >>= 7; } - Write((byte)v); + + Write((byte)uValue); + } + + public void Write7BitEncodedInt64(long value) + { + ulong uValue = (ulong)value; + + // Write out an int 7 bits at a time. The high bit of the byte, + // when on, tells reader to continue reading more bytes. + // + // Using the constants 0x7F and ~0x7F below offers smaller + // codegen than using the constant 0x80. + + while (uValue > 0x7Fu) + { + Write((byte)((uint)uValue | ~0x7Fu)); + uValue >>= 7; + } + + Write((byte)uValue); } } } diff --git a/src/System.Private.CoreLib/shared/System/IO/BufferedStream.cs b/src/System.Private.CoreLib/shared/System/IO/BufferedStream.cs index 61acd65b5..6ab6272fe 100644 --- a/src/System.Private.CoreLib/shared/System/IO/BufferedStream.cs +++ b/src/System.Private.CoreLib/shared/System/IO/BufferedStream.cs @@ -672,7 +672,7 @@ namespace System.IO cancellationToken, bytesFromBuffer, semaphoreLockTask).AsTask(); } - public override ValueTask ReadAsync(Memory buffer, CancellationToken cancellationToken = default(CancellationToken)) + public override ValueTask ReadAsync(Memory buffer, CancellationToken cancellationToken = default) { if (cancellationToken.IsCancellationRequested) { @@ -837,19 +837,6 @@ namespace System.IO return bytesToWrite; } - private void WriteToBuffer(byte[] array, ref int offset, ref int count, out Exception? error) - { - try - { - error = null; - WriteToBuffer(array, ref offset, ref count); - } - catch (Exception ex) - { - error = ex; - } - } - public override void Write(byte[] array, int offset, int count) { if (array == null) @@ -1074,7 +1061,7 @@ namespace System.IO return WriteAsync(new ReadOnlyMemory(buffer, offset, count), cancellationToken).AsTask(); } - public override ValueTask WriteAsync(ReadOnlyMemory buffer, CancellationToken cancellationToken = default(CancellationToken)) + public override ValueTask WriteAsync(ReadOnlyMemory buffer, CancellationToken cancellationToken = default) { // Fast path check for cancellation already requested if (cancellationToken.IsCancellationRequested) diff --git a/src/System.Private.CoreLib/shared/System/IO/DriveInfoInternal.Unix.cs b/src/System.Private.CoreLib/shared/System/IO/DriveInfoInternal.Unix.cs index 78ef95704..20e2cf9b9 100644 --- a/src/System.Private.CoreLib/shared/System/IO/DriveInfoInternal.Unix.cs +++ b/src/System.Private.CoreLib/shared/System/IO/DriveInfoInternal.Unix.cs @@ -2,9 +2,6 @@ // 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.Diagnostics; -using System.Text; - namespace System.IO { /// Contains internal volume helpers that are shared between many projects. diff --git a/src/System.Private.CoreLib/shared/System/IO/FileAttributes.cs b/src/System.Private.CoreLib/shared/System/IO/FileAttributes.cs index 90351282f..5f53a5d99 100644 --- a/src/System.Private.CoreLib/shared/System/IO/FileAttributes.cs +++ b/src/System.Private.CoreLib/shared/System/IO/FileAttributes.cs @@ -2,8 +2,6 @@ // 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; - namespace System.IO { [Flags] diff --git a/src/System.Private.CoreLib/shared/System/IO/FileStream.Linux.cs b/src/System.Private.CoreLib/shared/System/IO/FileStream.Linux.cs index 873c4eb55..6cc56e6ac 100644 --- a/src/System.Private.CoreLib/shared/System/IO/FileStream.Linux.cs +++ b/src/System.Private.CoreLib/shared/System/IO/FileStream.Linux.cs @@ -2,11 +2,6 @@ // The .NET Foundation licenses this file to you under the MIT license. // See the LICENSE file in the project root for more information. -using Microsoft.Win32.SafeHandles; -using System.Diagnostics; -using System.Threading; -using System.Threading.Tasks; - namespace System.IO { public partial class FileStream : Stream diff --git a/src/System.Private.CoreLib/shared/System/IO/FileStream.Unix.cs b/src/System.Private.CoreLib/shared/System/IO/FileStream.Unix.cs index 2a8e277c3..855397ce0 100644 --- a/src/System.Private.CoreLib/shared/System/IO/FileStream.Unix.cs +++ b/src/System.Private.CoreLib/shared/System/IO/FileStream.Unix.cs @@ -143,7 +143,7 @@ namespace System.IO private static Interop.Sys.OpenFlags PreOpenConfigurationFromOptions(FileMode mode, FileAccess access, FileShare share, FileOptions options) { // Translate FileMode. Most of the values map cleanly to one or more options for open. - Interop.Sys.OpenFlags flags = default(Interop.Sys.OpenFlags); + Interop.Sys.OpenFlags flags = default; switch (mode) { default: @@ -574,7 +574,7 @@ namespace System.IO try { Memory memory = thisRef._asyncState.Memory; - thisRef._asyncState.Memory = default(Memory); + thisRef._asyncState.Memory = default; return thisRef.ReadSpan(memory.Span); } finally { thisRef._asyncState.Release(); } @@ -733,7 +733,7 @@ namespace System.IO try { ReadOnlyMemory readOnlyMemory = thisRef._asyncState.ReadOnlyMemory; - thisRef._asyncState.ReadOnlyMemory = default(ReadOnlyMemory); + thisRef._asyncState.ReadOnlyMemory = default; thisRef.WriteSpan(readOnlyMemory.Span); } finally { thisRef._asyncState.Release(); } diff --git a/src/System.Private.CoreLib/shared/System/IO/FileStream.cs b/src/System.Private.CoreLib/shared/System/IO/FileStream.cs index 9221730c9..ee140ed65 100644 --- a/src/System.Private.CoreLib/shared/System/IO/FileStream.cs +++ b/src/System.Private.CoreLib/shared/System/IO/FileStream.cs @@ -426,7 +426,7 @@ namespace System.IO ValidateReadWriteArgs(array, offset, count); if (_useAsyncIO) { - WriteAsyncInternal(new ReadOnlyMemory(array, offset, count), CancellationToken.None).GetAwaiter().GetResult(); + WriteAsyncInternal(new ReadOnlyMemory(array, offset, count), CancellationToken.None).AsTask().GetAwaiter().GetResult(); } else { diff --git a/src/System.Private.CoreLib/shared/System/IO/Path.Unix.cs b/src/System.Private.CoreLib/shared/System/IO/Path.Unix.cs index 2b9b118b7..25cec9463 100644 --- a/src/System.Private.CoreLib/shared/System/IO/Path.Unix.cs +++ b/src/System.Private.CoreLib/shared/System/IO/Path.Unix.cs @@ -4,7 +4,6 @@ using System.Diagnostics; using System.Diagnostics.CodeAnalysis; -using System.Runtime.InteropServices; using System.Text; namespace System.IO @@ -137,7 +136,7 @@ namespace System.IO { get { - #if TARGET_OSX + #if TARGET_OSX || TARGET_IOS || TARGET_TVOS return false; #else return true; diff --git a/src/System.Private.CoreLib/shared/System/IO/Path.Windows.cs b/src/System.Private.CoreLib/shared/System/IO/Path.Windows.cs index b3ae4c54f..ce27a28f0 100644 --- a/src/System.Private.CoreLib/shared/System/IO/Path.Windows.cs +++ b/src/System.Private.CoreLib/shared/System/IO/Path.Windows.cs @@ -85,8 +85,7 @@ namespace System.IO return basePath; int length = path.Length; - string? combinedPath = null; - + string combinedPath; if (length >= 1 && PathInternal.IsDirectorySeparator(path[0])) { // Path is current drive rooted i.e. starts with \: diff --git a/src/System.Private.CoreLib/shared/System/IO/PathInternal.Unix.cs b/src/System.Private.CoreLib/shared/System/IO/PathInternal.Unix.cs index 4d652b641..77dab304e 100644 --- a/src/System.Private.CoreLib/shared/System/IO/PathInternal.Unix.cs +++ b/src/System.Private.CoreLib/shared/System/IO/PathInternal.Unix.cs @@ -5,7 +5,6 @@ #nullable enable using System.Diagnostics; using System.Text; -using System.Runtime.InteropServices; using System.Diagnostics.CodeAnalysis; namespace System.IO diff --git a/src/System.Private.CoreLib/shared/System/IO/UnmanagedMemoryStream.cs b/src/System.Private.CoreLib/shared/System/IO/UnmanagedMemoryStream.cs index ef5086482..ecdb45420 100644 --- a/src/System.Private.CoreLib/shared/System/IO/UnmanagedMemoryStream.cs +++ b/src/System.Private.CoreLib/shared/System/IO/UnmanagedMemoryStream.cs @@ -4,7 +4,6 @@ using System.Buffers; using System.Diagnostics; -using System.Runtime.CompilerServices; using System.Runtime.InteropServices; using System.Threading; using System.Threading.Tasks; @@ -128,7 +127,6 @@ namespace System.IO unsafe { byte* pointer = null; - RuntimeHelpers.PrepareConstrainedRegions(); try { buffer.AcquirePointer(ref pointer); @@ -260,7 +258,6 @@ namespace System.IO { byte* pointer = null; - RuntimeHelpers.PrepareConstrainedRegions(); try { _buffer.AcquirePointer(ref pointer); @@ -490,7 +487,6 @@ namespace System.IO { byte* pointer = null; - RuntimeHelpers.PrepareConstrainedRegions(); try { _buffer.AcquirePointer(ref pointer); @@ -606,7 +602,6 @@ namespace System.IO unsafe { byte* pointer = null; - RuntimeHelpers.PrepareConstrainedRegions(); try { _buffer.AcquirePointer(ref pointer); @@ -786,7 +781,6 @@ namespace System.IO } byte* pointer = null; - RuntimeHelpers.PrepareConstrainedRegions(); try { _buffer.AcquirePointer(ref pointer); @@ -920,7 +914,6 @@ namespace System.IO unsafe { byte* pointer = null; - RuntimeHelpers.PrepareConstrainedRegions(); try { _buffer.AcquirePointer(ref pointer); diff --git a/src/System.Private.CoreLib/shared/System/Index.cs b/src/System.Private.CoreLib/shared/System/Index.cs index 8f7c12eaa..1da3a691c 100644 --- a/src/System.Private.CoreLib/shared/System/Index.cs +++ b/src/System.Private.CoreLib/shared/System/Index.cs @@ -140,11 +140,15 @@ namespace System private string ToStringFromEnd() { +#if !NETSTANDARD2_0 Span span = stackalloc char[11]; // 1 for ^ and 10 for longest possible uint value bool formatted = ((uint)Value).TryFormat(span.Slice(1), out int charsWritten); Debug.Assert(formatted); span[0] = '^'; return new string(span.Slice(0, charsWritten + 1)); +#else + return '^' + Value.ToString(); +#endif } } } diff --git a/src/System.Private.CoreLib/shared/System/Int16.cs b/src/System.Private.CoreLib/shared/System/Int16.cs index 88bd953e8..379fa8999 100644 --- a/src/System.Private.CoreLib/shared/System/Int16.cs +++ b/src/System.Private.CoreLib/shared/System/Int16.cs @@ -2,6 +2,7 @@ // 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.Diagnostics.CodeAnalysis; using System.Globalization; using System.Runtime.CompilerServices; using System.Runtime.InteropServices; @@ -74,7 +75,7 @@ namespace System public string ToString(IFormatProvider? provider) { - return ToString(null, provider); + return Number.FormatInt32(m_value, 0, null, provider); } public string ToString(string? format) @@ -141,7 +142,7 @@ namespace System return (short)i; } - public static bool TryParse(string? s, out short result) + public static bool TryParse([NotNullWhen(true)] string? s, out short result) { if (s == null) { @@ -157,7 +158,7 @@ namespace System return TryParse(s, NumberStyles.Integer, NumberFormatInfo.CurrentInfo, out result); } - public static bool TryParse(string? s, NumberStyles style, IFormatProvider? provider, out short result) + public static bool TryParse([NotNullWhen(true)] string? s, NumberStyles style, IFormatProvider? provider, out short result) { NumberFormatInfo.ValidateParseStyleInteger(style); diff --git a/src/System.Private.CoreLib/shared/System/Int32.cs b/src/System.Private.CoreLib/shared/System/Int32.cs index 2e717736b..91e621888 100644 --- a/src/System.Private.CoreLib/shared/System/Int32.cs +++ b/src/System.Private.CoreLib/shared/System/Int32.cs @@ -2,6 +2,7 @@ // 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.Diagnostics.CodeAnalysis; using System.Globalization; using System.Runtime.CompilerServices; using System.Runtime.InteropServices; @@ -89,7 +90,7 @@ namespace System public string ToString(IFormatProvider? provider) { - return ToString(null, provider); + return Number.FormatInt32(m_value, 0, null, provider); } public string ToString(string? format, IFormatProvider? provider) @@ -145,7 +146,7 @@ namespace System // Parses an integer from a String. Returns false rather // than throwing exceptin if input is invalid // - public static bool TryParse(string? s, out int result) + public static bool TryParse([NotNullWhen(true)] string? s, out int result) { if (s == null) { @@ -164,7 +165,7 @@ namespace System // Parses an integer from a String in the given style. Returns false rather // than throwing exceptin if input is invalid // - public static bool TryParse(string? s, NumberStyles style, IFormatProvider? provider, out int result) + public static bool TryParse([NotNullWhen(true)] string? s, NumberStyles style, IFormatProvider? provider, out int result) { NumberFormatInfo.ValidateParseStyleInteger(style); diff --git a/src/System.Private.CoreLib/shared/System/Int64.cs b/src/System.Private.CoreLib/shared/System/Int64.cs index d4d22e070..b0374b96b 100644 --- a/src/System.Private.CoreLib/shared/System/Int64.cs +++ b/src/System.Private.CoreLib/shared/System/Int64.cs @@ -2,6 +2,7 @@ // 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.Diagnostics.CodeAnalysis; using System.Globalization; using System.Runtime.CompilerServices; using System.Runtime.InteropServices; @@ -135,7 +136,7 @@ namespace System return Number.ParseInt64(s, style, NumberFormatInfo.GetInstance(provider)); } - public static bool TryParse(string? s, out long result) + public static bool TryParse([NotNullWhen(true)] string? s, out long result) { if (s == null) { @@ -151,7 +152,7 @@ namespace System return Number.TryParseInt64IntegerStyle(s, NumberStyles.Integer, NumberFormatInfo.CurrentInfo, out result) == Number.ParsingStatus.OK; } - public static bool TryParse(string? s, NumberStyles style, IFormatProvider? provider, out long result) + public static bool TryParse([NotNullWhen(true)] string? s, NumberStyles style, IFormatProvider? provider, out long result) { NumberFormatInfo.ValidateParseStyleInteger(style); diff --git a/src/System.Private.CoreLib/shared/System/IntPtr.cs b/src/System.Private.CoreLib/shared/System/IntPtr.cs index e14dbc752..d82c18f1f 100644 --- a/src/System.Private.CoreLib/shared/System/IntPtr.cs +++ b/src/System.Private.CoreLib/shared/System/IntPtr.cs @@ -4,8 +4,10 @@ using System.Globalization; using System.Runtime.CompilerServices; +using System.Runtime.InteropServices; using System.Runtime.Serialization; using System.Runtime.Versioning; +using Internal.Runtime.CompilerServices; #pragma warning disable SA1121 // explicitly using type aliases instead of built-in types #if TARGET_64BIT @@ -17,8 +19,9 @@ using nint = System.Int32; namespace System { [Serializable] + [StructLayout(LayoutKind.Sequential)] [System.Runtime.CompilerServices.TypeForwardedFrom("mscorlib, Version=4.0.0.0, Culture=neutral, PublicKeyToken=b77a5c561934e089")] - public readonly struct IntPtr : IEquatable, ISerializable + public readonly struct IntPtr : IEquatable, IComparable, IComparable, IFormattable, ISerializable { // WARNING: We allow diagnostic tools to directly inspect this member (_value). // See https://github.com/dotnet/corert/blob/master/Documentation/design-docs/diagnostics/diagnostics-tools-contract.md for more details. @@ -74,9 +77,6 @@ namespace System obj is IntPtr other && _value == other._value; - unsafe bool IEquatable.Equals(IntPtr other) => - _value == other._value; - public override unsafe int GetHashCode() { #if TARGET_64BIT @@ -169,10 +169,61 @@ namespace System [NonVersionable] public unsafe void* ToPointer() => _value; - public override unsafe string ToString() => - ((nint)_value).ToString(CultureInfo.InvariantCulture); + public static IntPtr MaxValue + { + [NonVersionable] + get => (IntPtr)nint.MaxValue; + } - public unsafe string ToString(string format) => - ((nint)_value).ToString(format, CultureInfo.InvariantCulture); + public static IntPtr MinValue + { + [NonVersionable] + get => (IntPtr)nint.MinValue; + } + + // Don't just delegate to nint.CompareTo as it needs to throw when not IntPtr + public unsafe int CompareTo(object? value) + { + if (value is null) + { + return 1; + } + if (value is IntPtr o) + { + nint i = (nint)o; + if ((nint)_value < i) return -1; + if ((nint)_value > i) return 1; + return 0; + } + + throw new ArgumentException(SR.Arg_MustBeIntPtr); + } + + public unsafe int CompareTo(IntPtr value) => ((nint)_value).CompareTo((nint)value); + + [NonVersionable] + public unsafe bool Equals(IntPtr other) => (nint)_value == (nint)other; + + public unsafe override string ToString() => ((nint)_value).ToString(); + public unsafe string ToString(string? format) => ((nint)_value).ToString(format); + public unsafe string ToString(IFormatProvider? provider) => ((nint)_value).ToString(provider); + public unsafe string ToString(string? format, IFormatProvider? provider) => ((nint)_value).ToString(format, provider); + + public static IntPtr Parse(string s) => (IntPtr)nint.Parse(s); + public static IntPtr Parse(string s, NumberStyles style) => (IntPtr)nint.Parse(s, style); + public static IntPtr Parse(string s, IFormatProvider? provider) => (IntPtr)nint.Parse(s, provider); + public static IntPtr Parse(string s, NumberStyles style, IFormatProvider? provider) => (IntPtr)nint.Parse(s, style, provider); + + public static bool TryParse(string? s, out IntPtr result) + { + Unsafe.SkipInit(out result); + return nint.TryParse(s, out Unsafe.As(ref result)); + } + + public static bool TryParse(string? s, NumberStyles style, IFormatProvider? provider, out IntPtr result) + { + Unsafe.SkipInit(out result); + return nint.TryParse(s, style, provider, out Unsafe.As(ref result)); + } } } diff --git a/src/System.Private.CoreLib/shared/System/LocalAppContextSwitches.Common.cs b/src/System.Private.CoreLib/shared/System/LocalAppContextSwitches.Common.cs index eb657317e..074177172 100644 --- a/src/System.Private.CoreLib/shared/System/LocalAppContextSwitches.Common.cs +++ b/src/System.Private.CoreLib/shared/System/LocalAppContextSwitches.Common.cs @@ -23,9 +23,8 @@ namespace System private static bool GetCachedSwitchValueInternal(string switchName, ref int cachedSwitchValue) { - bool isSwitchEnabled; - bool hasSwitch = AppContext.TryGetSwitch(switchName, out isSwitchEnabled); + bool hasSwitch = AppContext.TryGetSwitch(switchName, out bool isSwitchEnabled); if (!hasSwitch) { isSwitchEnabled = GetSwitchDefaultValue(switchName); diff --git a/src/System.Private.CoreLib/shared/System/Math.cs b/src/System.Private.CoreLib/shared/System/Math.cs index 8432f458a..9e90ad9ca 100644 --- a/src/System.Private.CoreLib/shared/System/Math.cs +++ b/src/System.Private.CoreLib/shared/System/Math.cs @@ -539,6 +539,7 @@ namespace System return decimal.Max(val1, val2); } + [MethodImpl(MethodImplOptions.AggressiveInlining)] public static double Max(double val1, double val2) { // This matches the IEEE 754:2019 `maximum` function @@ -547,17 +548,17 @@ namespace System // otherwise returns the larger of the inputs. It // treats +0 as larger than -0 as per the specification. - if ((val1 > val2) || double.IsNaN(val1)) + if (val1 != val2) { + if (!double.IsNaN(val1)) + { + return val2 < val1 ? val1 : val2; + } + return val1; } - if (val1 == val2) - { - return double.IsNegative(val1) ? val2 : val1; - } - - return val2; + return double.IsNegative(val2) ? val1 : val2; } [NonVersionable] @@ -585,6 +586,7 @@ namespace System return (val1 >= val2) ? val1 : val2; } + [MethodImpl(MethodImplOptions.AggressiveInlining)] public static float Max(float val1, float val2) { // This matches the IEEE 754:2019 `maximum` function @@ -593,17 +595,17 @@ namespace System // otherwise returns the larger of the inputs. It // treats +0 as larger than -0 as per the specification. - if ((val1 > val2) || float.IsNaN(val1)) + if (val1 != val2) { + if (!float.IsNaN(val1)) + { + return val2 < val1 ? val1 : val2; + } + return val1; } - if (val1 == val2) - { - return float.IsNegative(val1) ? val2 : val1; - } - - return val2; + return float.IsNegative(val2) ? val1 : val2; } [CLSCompliant(false)] @@ -663,6 +665,7 @@ namespace System return decimal.Min(val1, val2); } + [MethodImpl(MethodImplOptions.AggressiveInlining)] public static double Min(double val1, double val2) { // This matches the IEEE 754:2019 `minimum` function @@ -671,17 +674,12 @@ namespace System // otherwise returns the larger of the inputs. It // treats +0 as larger than -0 as per the specification. - if ((val1 < val2) || double.IsNaN(val1)) + if (val1 != val2 && !double.IsNaN(val1)) { - return val1; + return val1 < val2 ? val1 : val2; } - if (val1 == val2) - { - return double.IsNegative(val1) ? val1 : val2; - } - - return val2; + return double.IsNegative(val1) ? val1 : val2; } [NonVersionable] @@ -709,6 +707,7 @@ namespace System return (val1 <= val2) ? val1 : val2; } + [MethodImpl(MethodImplOptions.AggressiveInlining)] public static float Min(float val1, float val2) { // This matches the IEEE 754:2019 `minimum` function @@ -717,17 +716,12 @@ namespace System // otherwise returns the larger of the inputs. It // treats +0 as larger than -0 as per the specification. - if ((val1 < val2) || float.IsNaN(val1)) + if (val1 != val2 && !float.IsNaN(val1)) { - return val1; + return val1 < val2 ? val1 : val2; } - if (val1 == val2) - { - return float.IsNegative(val1) ? val1 : val2; - } - - return val2; + return float.IsNegative(val1) ? val1 : val2; } [CLSCompliant(false)] diff --git a/src/System.Private.CoreLib/shared/System/MemoryExtensions.Globalization.cs b/src/System.Private.CoreLib/shared/System/MemoryExtensions.Globalization.cs index 604035e5e..4974928af 100644 --- a/src/System.Private.CoreLib/shared/System/MemoryExtensions.Globalization.cs +++ b/src/System.Private.CoreLib/shared/System/MemoryExtensions.Globalization.cs @@ -7,6 +7,7 @@ using System.Globalization; using System.Runtime.CompilerServices; using System.Runtime.InteropServices; using System.Text; +using Internal.Runtime.CompilerServices; namespace System { @@ -50,26 +51,20 @@ namespace System switch (comparisonType) { case StringComparison.CurrentCulture: - return CultureInfo.CurrentCulture.CompareInfo.CompareOptionNone(span, other) == 0; - case StringComparison.CurrentCultureIgnoreCase: - return CultureInfo.CurrentCulture.CompareInfo.CompareOptionIgnoreCase(span, other) == 0; + return CultureInfo.CurrentCulture.CompareInfo.Compare(span, other, string.GetCaseCompareOfComparisonCulture(comparisonType)) == 0; case StringComparison.InvariantCulture: - return CompareInfo.Invariant.CompareOptionNone(span, other) == 0; - case StringComparison.InvariantCultureIgnoreCase: - return CompareInfo.Invariant.CompareOptionIgnoreCase(span, other) == 0; + return CompareInfo.Invariant.Compare(span, other, string.GetCaseCompareOfComparisonCulture(comparisonType)) == 0; case StringComparison.Ordinal: return EqualsOrdinal(span, other); - case StringComparison.OrdinalIgnoreCase: + default: + Debug.Assert(comparisonType == StringComparison.OrdinalIgnoreCase); return EqualsOrdinalIgnoreCase(span, other); } - - Debug.Fail("StringComparison outside range"); - return false; } [MethodImpl(MethodImplOptions.AggressiveInlining)] @@ -106,28 +101,22 @@ namespace System switch (comparisonType) { case StringComparison.CurrentCulture: - return CultureInfo.CurrentCulture.CompareInfo.CompareOptionNone(span, other); - case StringComparison.CurrentCultureIgnoreCase: - return CultureInfo.CurrentCulture.CompareInfo.CompareOptionIgnoreCase(span, other); + return CultureInfo.CurrentCulture.CompareInfo.Compare(span, other, string.GetCaseCompareOfComparisonCulture(comparisonType)); case StringComparison.InvariantCulture: - return CompareInfo.Invariant.CompareOptionNone(span, other); - case StringComparison.InvariantCultureIgnoreCase: - return CompareInfo.Invariant.CompareOptionIgnoreCase(span, other); + return CompareInfo.Invariant.Compare(span, other, string.GetCaseCompareOfComparisonCulture(comparisonType)); case StringComparison.Ordinal: if (span.Length == 0 || other.Length == 0) return span.Length - other.Length; return string.CompareOrdinal(span, other); - case StringComparison.OrdinalIgnoreCase: + default: + Debug.Assert(comparisonType == StringComparison.OrdinalIgnoreCase); return CompareInfo.CompareOrdinalIgnoreCase(span, other); } - - Debug.Fail("StringComparison outside range"); - return 0; } /// @@ -140,16 +129,6 @@ namespace System { string.CheckStringComparison(comparisonType); - if (value.Length == 0) - { - return 0; - } - - if (span.Length == 0) - { - return -1; - } - if (comparisonType == StringComparison.Ordinal) { return SpanHelpers.IndexOf( @@ -159,11 +138,6 @@ namespace System value.Length); } - if (GlobalizationMode.Invariant) - { - return CompareInfo.InvariantIndexOf(span, value, string.GetCaseCompareOfComparisonCulture(comparisonType) != CompareOptions.None); - } - switch (comparisonType) { case StringComparison.CurrentCulture: @@ -176,7 +150,7 @@ namespace System default: Debug.Assert(comparisonType == StringComparison.OrdinalIgnoreCase); - return CompareInfo.Invariant.IndexOfOrdinalIgnoreCase(span, value); + return CompareInfo.IndexOfOrdinalIgnoreCase(span, value, fromBeginning: true); } } @@ -190,19 +164,13 @@ namespace System { string.CheckStringComparison(comparisonType); - if (value.Length == 0) + if (comparisonType == StringComparison.Ordinal) { - return span.Length > 0 ? span.Length - 1 : 0; - } - - if (span.Length == 0) - { - return -1; - } - - if (GlobalizationMode.Invariant) - { - return CompareInfo.InvariantIndexOf(span, value, string.GetCaseCompareOfComparisonCulture(comparisonType) != CompareOptions.None, fromBeginning: false); + return SpanHelpers.LastIndexOf( + ref MemoryMarshal.GetReference(span), + span.Length, + ref MemoryMarshal.GetReference(value), + value.Length); } switch (comparisonType) @@ -216,8 +184,8 @@ namespace System return CompareInfo.Invariant.LastIndexOf(span, value, string.GetCaseCompareOfComparisonCulture(comparisonType)); default: - Debug.Assert(comparisonType == StringComparison.Ordinal || comparisonType == StringComparison.OrdinalIgnoreCase); - return CompareInfo.Invariant.LastIndexOfOrdinal(span, value, string.GetCaseCompareOfComparisonCulture(comparisonType) != CompareOptions.None); + Debug.Assert(comparisonType == StringComparison.OrdinalIgnoreCase); + return CompareInfo.IndexOfOrdinalIgnoreCase(span, value, fromBeginning: false); } } @@ -335,29 +303,33 @@ namespace System { string.CheckStringComparison(comparisonType); - if (value.Length == 0) + switch (comparisonType) { - return true; - } + case StringComparison.CurrentCulture: + case StringComparison.CurrentCultureIgnoreCase: + return CultureInfo.CurrentCulture.CompareInfo.IsSuffix(span, value, string.GetCaseCompareOfComparisonCulture(comparisonType)); - if (comparisonType >= StringComparison.Ordinal || GlobalizationMode.Invariant) - { - if (string.GetCaseCompareOfComparisonCulture(comparisonType) == CompareOptions.None) + case StringComparison.InvariantCulture: + case StringComparison.InvariantCultureIgnoreCase: + return CompareInfo.Invariant.IsSuffix(span, value, string.GetCaseCompareOfComparisonCulture(comparisonType)); + + case StringComparison.Ordinal: return span.EndsWith(value); - return (span.Length >= value.Length) ? (CompareInfo.CompareOrdinalIgnoreCase(span.Slice(span.Length - value.Length), value) == 0) : false; + default: + Debug.Assert(comparisonType == StringComparison.OrdinalIgnoreCase); + return span.EndsWithOrdinalIgnoreCase(value); } - - if (span.Length == 0) - { - return false; - } - - return (comparisonType >= StringComparison.InvariantCulture) ? - CompareInfo.Invariant.IsSuffix(span, value, string.GetCaseCompareOfComparisonCulture(comparisonType)) : - CultureInfo.CurrentCulture.CompareInfo.IsSuffix(span, value, string.GetCaseCompareOfComparisonCulture(comparisonType)); } + [MethodImpl(MethodImplOptions.AggressiveInlining)] + internal static bool EndsWithOrdinalIgnoreCase(this ReadOnlySpan span, ReadOnlySpan value) + => value.Length <= span.Length + && CompareInfo.EqualsOrdinalIgnoreCase( + ref Unsafe.Add(ref MemoryMarshal.GetReference(span), span.Length - value.Length), + ref MemoryMarshal.GetReference(value), + value.Length); + /// /// Determines whether the beginning of the matches the specified when compared using the specified option. /// @@ -368,29 +340,30 @@ namespace System { string.CheckStringComparison(comparisonType); - if (value.Length == 0) + switch (comparisonType) { - return true; - } + case StringComparison.CurrentCulture: + case StringComparison.CurrentCultureIgnoreCase: + return CultureInfo.CurrentCulture.CompareInfo.IsPrefix(span, value, string.GetCaseCompareOfComparisonCulture(comparisonType)); - if (comparisonType >= StringComparison.Ordinal || GlobalizationMode.Invariant) - { - if (string.GetCaseCompareOfComparisonCulture(comparisonType) == CompareOptions.None) + case StringComparison.InvariantCulture: + case StringComparison.InvariantCultureIgnoreCase: + return CompareInfo.Invariant.IsPrefix(span, value, string.GetCaseCompareOfComparisonCulture(comparisonType)); + + case StringComparison.Ordinal: return span.StartsWith(value); - return (span.Length >= value.Length) ? (CompareInfo.CompareOrdinalIgnoreCase(span.Slice(0, value.Length), value) == 0) : false; + default: + Debug.Assert(comparisonType == StringComparison.OrdinalIgnoreCase); + return span.StartsWithOrdinalIgnoreCase(value); } - - if (span.Length == 0) - { - return false; - } - - return (comparisonType >= StringComparison.InvariantCulture) ? - CompareInfo.Invariant.IsPrefix(span, value, string.GetCaseCompareOfComparisonCulture(comparisonType)) : - CultureInfo.CurrentCulture.CompareInfo.IsPrefix(span, value, string.GetCaseCompareOfComparisonCulture(comparisonType)); } + [MethodImpl(MethodImplOptions.AggressiveInlining)] + internal static bool StartsWithOrdinalIgnoreCase(this ReadOnlySpan span, ReadOnlySpan value) + => value.Length <= span.Length + && CompareInfo.EqualsOrdinalIgnoreCase(ref MemoryMarshal.GetReference(span), ref MemoryMarshal.GetReference(value), value.Length); + /// /// Returns an enumeration of from the provided span. /// diff --git a/src/System.Private.CoreLib/shared/System/Number.Formatting.cs b/src/System.Private.CoreLib/shared/System/Number.Formatting.cs index 231704868..9cba193c2 100644 --- a/src/System.Private.CoreLib/shared/System/Number.Formatting.cs +++ b/src/System.Private.CoreLib/shared/System/Number.Formatting.cs @@ -277,7 +277,8 @@ namespace System "($#)", "-$#", "$-#", "$#-", "(#$)", "-#$", "#-$", "#$-", "-# $", "-$ #", "# $-", "$ #-", - "$ -#", "#- $", "($ #)", "(# $)" + "$ -#", "#- $", "($ #)", "(# $)", + "$- #" }; private static readonly string[] s_posPercentFormats = @@ -698,7 +699,7 @@ namespace System if (string.IsNullOrEmpty(format)) { return value >= 0 ? - UInt32ToDecStr((uint)value, digits: -1) : + UInt32ToDecStr((uint)value) : NegativeInt32ToDecStr(value, digits: -1, NumberFormatInfo.GetInstance(provider).NegativeSign); } @@ -800,7 +801,7 @@ namespace System // Fast path for default format if (string.IsNullOrEmpty(format)) { - return UInt32ToDecStr(value, digits: -1); + return UInt32ToDecStr(value); } return FormatUInt32Slow(value, format, provider); @@ -1068,7 +1069,7 @@ namespace System NumberFormatInfo info = NumberFormatInfo.GetInstance(provider); byte* pDigits = stackalloc byte[UInt64NumberBufferLength]; - NumberBuffer number = new NumberBuffer(NumberBufferKind.Integer, pDigits, UInt32NumberBufferLength); + NumberBuffer number = new NumberBuffer(NumberBufferKind.Integer, pDigits, UInt64NumberBufferLength); UInt64ToNumber(value, ref number); @@ -1122,7 +1123,7 @@ namespace System public static string Int32ToDecStr(int value) { return value >= 0 ? - UInt32ToDecStr((uint)value, -1) : + UInt32ToDecStr((uint)value) : NegativeInt32ToDecStr(value, -1, NumberFormatInfo.CurrentInfo.NegativeSign); } @@ -1267,9 +1268,9 @@ namespace System return bufferEnd; } - internal static unsafe string UInt32ToDecStr(uint value, int digits) + internal static unsafe string UInt32ToDecStr(uint value) { - int bufferLength = Math.Max(digits, FormattingHelpers.CountDigits(value)); + int bufferLength = FormattingHelpers.CountDigits(value); // For single-digit values that are very common, especially 0 and 1, just return cached strings. if (bufferLength == 1) @@ -1281,19 +1282,28 @@ namespace System fixed (char* buffer = result) { char* p = buffer + bufferLength; - if (digits <= 1) + do { - do - { - value = Math.DivRem(value, 10, out uint remainder); - *(--p) = (char)(remainder + '0'); - } - while (value != 0); - } - else - { - p = UInt32ToDecChars(p, value, digits); + value = Math.DivRem(value, 10, out uint remainder); + *(--p) = (char)(remainder + '0'); } + while (value != 0); + Debug.Assert(p == buffer); + } + return result; + } + + private static unsafe string UInt32ToDecStr(uint value, int digits) + { + if (digits <= 1) + return UInt32ToDecStr(value); + + int bufferLength = Math.Max(digits, FormattingHelpers.CountDigits(value)); + string result = string.FastAllocateString(bufferLength); + fixed (char* buffer = result) + { + char* p = buffer + bufferLength; + p = UInt32ToDecChars(p, value, digits); Debug.Assert(p == buffer); } return result; @@ -2169,7 +2179,7 @@ namespace System { if (groupDigits != null) { - Debug.Assert(sGroup != null, "Must be nulll when groupDigits != null"); + Debug.Assert(sGroup != null, "Must be null when groupDigits != null"); int groupSizeIndex = 0; // Index into the groupDigits array. int bufferSize = digPos; // The length of the result buffer string. int groupSize = 0; // The current group size. diff --git a/src/System.Private.CoreLib/shared/System/Numerics/BitOperations.cs b/src/System.Private.CoreLib/shared/System/Numerics/BitOperations.cs index 551065921..9844240e1 100644 --- a/src/System.Private.CoreLib/shared/System/Numerics/BitOperations.cs +++ b/src/System.Private.CoreLib/shared/System/Numerics/BitOperations.cs @@ -4,9 +4,12 @@ using System.Runtime.CompilerServices; using System.Runtime.InteropServices; +using System.Runtime.Intrinsics.Arm; using System.Runtime.Intrinsics.X86; +#if SYSTEM_PRIVATE_CORELIB using Internal.Runtime.CompilerServices; +#endif // Some routines inspired by the Stanford Bit Twiddling Hacks by Sean Eron Anderson: // http://graphics.stanford.edu/~seander/bithacks.html @@ -18,7 +21,12 @@ namespace System.Numerics /// The methods use hardware intrinsics when available on the underlying platform, /// otherwise they use optimized software fallbacks. /// - public static class BitOperations +#if SYSTEM_PRIVATE_CORELIB + public +#else + internal +#endif + static class BitOperations { // C# no-alloc optimization that directly wraps the data section of the dll (similar to string constants) // https://github.com/dotnet/roslyn/pull/24621 @@ -54,6 +62,11 @@ namespace System.Numerics return (int)Lzcnt.LeadingZeroCount(value); } + if (ArmBase.IsSupported) + { + return ArmBase.LeadingZeroCount(value); + } + // Unguarded fallback contract is 0->31 if (value == 0) { @@ -78,6 +91,11 @@ namespace System.Numerics return (int)Lzcnt.X64.LeadingZeroCount(value); } + if (ArmBase.Arm64.IsSupported) + { + return ArmBase.Arm64.LeadingZeroCount(value); + } + uint hi = (uint)(value >> 32); if (hi == 0) @@ -97,6 +115,12 @@ namespace System.Numerics [CLSCompliant(false)] public static int Log2(uint value) { + // Enforce conventional contract 0->0 (Log(0) is undefined) + if (value == 0) + { + return 0; + } + // value lzcnt actual expected // ..0000 32 0 0 (by convention, guard clause) // ..0001 31 31-31 0 @@ -106,16 +130,15 @@ namespace System.Numerics // 1000.. 0 31-0 31 if (Lzcnt.IsSupported) { - // Enforce conventional contract 0->0 (Log(0) is undefined) - if (value == 0) - { - return 0; - } - // LZCNT contract is 0->32 return 31 - (int)Lzcnt.LeadingZeroCount(value); } + if (ArmBase.IsSupported) + { + return 31 - ArmBase.LeadingZeroCount(value); + } + // Fallback contract is 0->0 return Log2SoftwareFallback(value); } @@ -129,18 +152,23 @@ namespace System.Numerics [CLSCompliant(false)] public static int Log2(ulong value) { + // Enforce conventional contract 0->0 (Log(0) is undefined) + if (value == 0) + { + return 0; + } + if (Lzcnt.X64.IsSupported) { - // Enforce conventional contract 0->0 (Log(0) is undefined) - if (value == 0) - { - return 0; - } - // LZCNT contract is 0->64 return 63 - (int)Lzcnt.X64.LeadingZeroCount(value); } + if (ArmBase.Arm64.IsSupported) + { + return 63 - ArmBase.Arm64.LeadingZeroCount(value); + } + uint hi = (uint)(value >> 32); if (hi == 0) @@ -268,6 +296,11 @@ namespace System.Numerics return (int)Bmi1.TrailingZeroCount(value); } + if (ArmBase.IsSupported) + { + return ArmBase.LeadingZeroCount(ArmBase.ReverseElementBits(value)); + } + // Unguarded fallback contract is 0->0 if (value == 0) { @@ -306,6 +339,10 @@ namespace System.Numerics return (int)Bmi1.X64.TrailingZeroCount(value); } + if (ArmBase.Arm64.IsSupported) + { + return ArmBase.Arm64.LeadingZeroCount(ArmBase.Arm64.ReverseElementBits(value)); + } uint lo = (uint)value; if (lo == 0) diff --git a/src/System.Private.CoreLib/shared/System/Numerics/Matrix4x4.cs b/src/System.Private.CoreLib/shared/System/Numerics/Matrix4x4.cs index e5cd43201..c49c02c18 100644 --- a/src/System.Private.CoreLib/shared/System/Numerics/Matrix4x4.cs +++ b/src/System.Private.CoreLib/shared/System/Numerics/Matrix4x4.cs @@ -899,7 +899,7 @@ namespace System.Numerics result.M21 = result.M23 = result.M24 = 0.0f; result.M31 = result.M32 = 0.0f; - var negFarRange = float.IsPositiveInfinity(farPlaneDistance) ? -1.0f : farPlaneDistance / (nearPlaneDistance - farPlaneDistance); + float negFarRange = float.IsPositiveInfinity(farPlaneDistance) ? -1.0f : farPlaneDistance / (nearPlaneDistance - farPlaneDistance); result.M33 = negFarRange; result.M34 = -1.0f; @@ -936,7 +936,7 @@ namespace System.Numerics result.M22 = 2.0f * nearPlaneDistance / height; result.M21 = result.M23 = result.M24 = 0.0f; - var negFarRange = float.IsPositiveInfinity(farPlaneDistance) ? -1.0f : farPlaneDistance / (nearPlaneDistance - farPlaneDistance); + float negFarRange = float.IsPositiveInfinity(farPlaneDistance) ? -1.0f : farPlaneDistance / (nearPlaneDistance - farPlaneDistance); result.M33 = negFarRange; result.M31 = result.M32 = 0.0f; result.M34 = -1.0f; @@ -978,7 +978,7 @@ namespace System.Numerics result.M31 = (left + right) / (right - left); result.M32 = (top + bottom) / (top - bottom); - var negFarRange = float.IsPositiveInfinity(farPlaneDistance) ? -1.0f : farPlaneDistance / (nearPlaneDistance - farPlaneDistance); + float negFarRange = float.IsPositiveInfinity(farPlaneDistance) ? -1.0f : farPlaneDistance / (nearPlaneDistance - farPlaneDistance); result.M33 = negFarRange; result.M34 = -1.0f; @@ -1761,15 +1761,15 @@ namespace System.Numerics { if (Sse.IsSupported) { - var row1 = Sse.LoadVector128(&matrix.M11); - var row2 = Sse.LoadVector128(&matrix.M21); - var row3 = Sse.LoadVector128(&matrix.M31); - var row4 = Sse.LoadVector128(&matrix.M41); + Vector128 row1 = Sse.LoadVector128(&matrix.M11); + Vector128 row2 = Sse.LoadVector128(&matrix.M21); + Vector128 row3 = Sse.LoadVector128(&matrix.M31); + Vector128 row4 = Sse.LoadVector128(&matrix.M41); - var l12 = Sse.UnpackLow(row1, row2); - var l34 = Sse.UnpackLow(row3, row4); - var h12 = Sse.UnpackHigh(row1, row2); - var h34 = Sse.UnpackHigh(row3, row4); + Vector128 l12 = Sse.UnpackLow(row1, row2); + Vector128 l34 = Sse.UnpackLow(row3, row4); + Vector128 h12 = Sse.UnpackHigh(row1, row2); + Vector128 h34 = Sse.UnpackHigh(row3, row4); Sse.Store(&matrix.M11, Sse.MoveLowToHigh(l12, l34)); Sse.Store(&matrix.M21, Sse.MoveHighToLow(l34, l12)); @@ -2016,7 +2016,7 @@ namespace System.Numerics { if (Sse.IsSupported) { - var row = Sse.LoadVector128(&value1.M11); + Vector128 row = Sse.LoadVector128(&value1.M11); Sse.Store(&value1.M11, Sse.Add(Sse.Add(Sse.Multiply(Sse.Shuffle(row, row, 0x00), Sse.LoadVector128(&value2.M11)), Sse.Multiply(Sse.Shuffle(row, row, 0x55), Sse.LoadVector128(&value2.M21))), diff --git a/src/System.Private.CoreLib/shared/System/Numerics/Plane.cs b/src/System.Private.CoreLib/shared/System/Numerics/Plane.cs index 7c4c376dd..955c2ae5b 100644 --- a/src/System.Private.CoreLib/shared/System/Numerics/Plane.cs +++ b/src/System.Private.CoreLib/shared/System/Numerics/Plane.cs @@ -162,8 +162,7 @@ namespace System.Numerics [MethodImpl(MethodImplOptions.AggressiveInlining)] public static Plane Transform(Plane plane, Matrix4x4 matrix) { - Matrix4x4 m; - Matrix4x4.Invert(matrix, out m); + Matrix4x4.Invert(matrix, out Matrix4x4 m); float x = plane.Normal.X, y = plane.Normal.Y, z = plane.Normal.Z, w = plane.D; diff --git a/src/System.Private.CoreLib/shared/System/Numerics/Vector.cs b/src/System.Private.CoreLib/shared/System/Numerics/Vector.cs index 0407fd492..f20b762af 100644 --- a/src/System.Private.CoreLib/shared/System/Numerics/Vector.cs +++ b/src/System.Private.CoreLib/shared/System/Numerics/Vector.cs @@ -3456,6 +3456,108 @@ namespace System.Numerics } } } + + [Intrinsic] + internal static unsafe Vector Ceiling(Vector value) + { + if (Vector.IsHardwareAccelerated) + { + if (typeof(T) == typeof(float)) + { + float* dataPtr = stackalloc float[Count]; + for (int g = 0; g < Count; g++) + { + dataPtr[g] = MathF.Ceiling((float)(object)value[g]); + } + return new Vector(dataPtr); + } + else if (typeof(T) == typeof(double)) + { + double* dataPtr = stackalloc double[Count]; + for (int g = 0; g < Count; g++) + { + dataPtr[g] = Math.Ceiling((double)(object)value[g]); + } + return new Vector(dataPtr); + } + else + { + throw new NotSupportedException(SR.Arg_TypeNotSupported); + } + } + else + { + if (typeof(T) == typeof(float)) + { + value.register.single_0 = MathF.Ceiling(value.register.single_0); + value.register.single_1 = MathF.Ceiling(value.register.single_1); + value.register.single_2 = MathF.Ceiling(value.register.single_2); + value.register.single_3 = MathF.Ceiling(value.register.single_3); + return value; + } + else if (typeof(T) == typeof(double)) + { + value.register.double_0 = Math.Ceiling(value.register.double_0); + value.register.double_1 = Math.Ceiling(value.register.double_1); + return value; + } + else + { + throw new NotSupportedException(SR.Arg_TypeNotSupported); + } + } + } + + [Intrinsic] + internal static unsafe Vector Floor(Vector value) + { + if (Vector.IsHardwareAccelerated) + { + if (typeof(T) == typeof(float)) + { + float* dataPtr = stackalloc float[Count]; + for (int g = 0; g < Count; g++) + { + dataPtr[g] = MathF.Floor((float)(object)value[g]); + } + return new Vector(dataPtr); + } + else if (typeof(T) == typeof(double)) + { + double* dataPtr = stackalloc double[Count]; + for (int g = 0; g < Count; g++) + { + dataPtr[g] = Math.Floor((double)(object)value[g]); + } + return new Vector(dataPtr); + } + else + { + throw new NotSupportedException(SR.Arg_TypeNotSupported); + } + } + else + { + if (typeof(T) == typeof(float)) + { + value.register.single_0 = MathF.Floor(value.register.single_0); + value.register.single_1 = MathF.Floor(value.register.single_1); + value.register.single_2 = MathF.Floor(value.register.single_2); + value.register.single_3 = MathF.Floor(value.register.single_3); + return value; + } + else if (typeof(T) == typeof(double)) + { + value.register.double_0 = Math.Floor(value.register.double_0); + value.register.double_1 = Math.Floor(value.register.double_1); + return value; + } + else + { + throw new NotSupportedException(SR.Arg_TypeNotSupported); + } + } + } #endregion Internal Math Methods #region Helper Methods diff --git a/src/System.Private.CoreLib/shared/System/Numerics/Vector.tt b/src/System.Private.CoreLib/shared/System/Numerics/Vector.tt index 93dd6d379..3c02ba2be 100644 --- a/src/System.Private.CoreLib/shared/System/Numerics/Vector.tt +++ b/src/System.Private.CoreLib/shared/System/Numerics/Vector.tt @@ -1405,6 +1405,128 @@ namespace System.Numerics } } } + + [Intrinsic] + internal static unsafe Vector Ceiling(Vector value) + { + if (Vector.IsHardwareAccelerated) + { + if (typeof(T) == typeof(float)) + { + float* dataPtr = stackalloc float[Count]; + for (int g = 0; g < Count; g++) + { + dataPtr[g] = MathF.Ceiling((float)(object)value[g]); + } + return new Vector(dataPtr); + } + else if (typeof(T) == typeof(double)) + { + double* dataPtr = stackalloc double[Count]; + for (int g = 0; g < Count; g++) + { + dataPtr[g] = Math.Ceiling((double)(object)value[g]); + } + return new Vector(dataPtr); + } + else + { + throw new NotSupportedException(SR.Arg_TypeNotSupported); + } + } + else + { + if (typeof(T) == typeof(float)) + { +<# + for (int g = 0; g < GetNumFields(typeof(float), totalSize); g++) + { +#> + value.<#=GetRegisterFieldName(typeof(float), g)#> = MathF.Ceiling(value.<#=GetRegisterFieldName(typeof(float), g)#>); +<# + } +#> + return value; + } + else if (typeof(T) == typeof(double)) + { +<# + for (int g = 0; g < GetNumFields(typeof(double), totalSize); g++) + { +#> + value.<#=GetRegisterFieldName(typeof(double), g)#> = Math.Ceiling(value.<#=GetRegisterFieldName(typeof(double), g)#>); +<# + } +#> + return value; + } + else + { + throw new NotSupportedException(SR.Arg_TypeNotSupported); + } + } + } + + [Intrinsic] + internal static unsafe Vector Floor(Vector value) + { + if (Vector.IsHardwareAccelerated) + { + if (typeof(T) == typeof(float)) + { + float* dataPtr = stackalloc float[Count]; + for (int g = 0; g < Count; g++) + { + dataPtr[g] = MathF.Floor((float)(object)value[g]); + } + return new Vector(dataPtr); + } + else if (typeof(T) == typeof(double)) + { + double* dataPtr = stackalloc double[Count]; + for (int g = 0; g < Count; g++) + { + dataPtr[g] = Math.Floor((double)(object)value[g]); + } + return new Vector(dataPtr); + } + else + { + throw new NotSupportedException(SR.Arg_TypeNotSupported); + } + } + else + { + if (typeof(T) == typeof(float)) + { +<# + for (int g = 0; g < GetNumFields(typeof(float), totalSize); g++) + { +#> + value.<#=GetRegisterFieldName(typeof(float), g)#> = MathF.Floor(value.<#=GetRegisterFieldName(typeof(float), g)#>); +<# + } +#> + return value; + } + else if (typeof(T) == typeof(double)) + { +<# + for (int g = 0; g < GetNumFields(typeof(double), totalSize); g++) + { +#> + value.<#=GetRegisterFieldName(typeof(double), g)#> = Math.Floor(value.<#=GetRegisterFieldName(typeof(double), g)#>); +<# + } +#> + return value; + } + else + { + throw new NotSupportedException(SR.Arg_TypeNotSupported); + } + } + } #endregion Internal Math Methods #region Helper Methods diff --git a/src/System.Private.CoreLib/shared/System/Numerics/Vector2.cs b/src/System.Private.CoreLib/shared/System/Numerics/Vector2.cs index 5e710842c..dc7496190 100644 --- a/src/System.Private.CoreLib/shared/System/Numerics/Vector2.cs +++ b/src/System.Private.CoreLib/shared/System/Numerics/Vector2.cs @@ -116,16 +116,8 @@ namespace System.Numerics [MethodImpl(MethodImplOptions.AggressiveInlining)] public readonly float Length() { - if (Vector.IsHardwareAccelerated) - { - float ls = Vector2.Dot(this, this); - return MathF.Sqrt(ls); - } - else - { - float ls = X * X + Y * Y; - return MathF.Sqrt(ls); - } + float ls = Vector2.Dot(this, this); + return MathF.Sqrt(ls); } /// @@ -135,14 +127,7 @@ namespace System.Numerics [MethodImpl(MethodImplOptions.AggressiveInlining)] public readonly float LengthSquared() { - if (Vector.IsHardwareAccelerated) - { - return Vector2.Dot(this, this); - } - else - { - return X * X + Y * Y; - } + return Vector2.Dot(this, this); } #endregion Public Instance Methods @@ -156,21 +141,9 @@ namespace System.Numerics [MethodImpl(MethodImplOptions.AggressiveInlining)] public static float Distance(Vector2 value1, Vector2 value2) { - if (Vector.IsHardwareAccelerated) - { - Vector2 difference = value1 - value2; - float ls = Vector2.Dot(difference, difference); - return MathF.Sqrt(ls); - } - else - { - float dx = value1.X - value2.X; - float dy = value1.Y - value2.Y; - - float ls = dx * dx + dy * dy; - - return MathF.Sqrt(ls); - } + Vector2 difference = value1 - value2; + float ls = Vector2.Dot(difference, difference); + return MathF.Sqrt(ls); } /// @@ -182,18 +155,8 @@ namespace System.Numerics [MethodImpl(MethodImplOptions.AggressiveInlining)] public static float DistanceSquared(Vector2 value1, Vector2 value2) { - if (Vector.IsHardwareAccelerated) - { - Vector2 difference = value1 - value2; - return Vector2.Dot(difference, difference); - } - else - { - float dx = value1.X - value2.X; - float dy = value1.Y - value2.Y; - - return dx * dx + dy * dy; - } + Vector2 difference = value1 - value2; + return Vector2.Dot(difference, difference); } /// @@ -204,20 +167,8 @@ namespace System.Numerics [MethodImpl(MethodImplOptions.AggressiveInlining)] public static Vector2 Normalize(Vector2 value) { - if (Vector.IsHardwareAccelerated) - { - float length = value.Length(); - return value / length; - } - else - { - float ls = value.X * value.X + value.Y * value.Y; - float invNorm = 1.0f / MathF.Sqrt(ls); - - return new Vector2( - value.X * invNorm, - value.Y * invNorm); - } + float length = value.Length(); + return value / length; } /// @@ -229,19 +180,8 @@ namespace System.Numerics [MethodImpl(MethodImplOptions.AggressiveInlining)] public static Vector2 Reflect(Vector2 vector, Vector2 normal) { - if (Vector.IsHardwareAccelerated) - { - float dot = Vector2.Dot(vector, normal); - return vector - (2 * dot * normal); - } - else - { - float dot = vector.X * normal.X + vector.Y * normal.Y; - - return new Vector2( - vector.X - 2.0f * dot * normal.X, - vector.Y - 2.0f * dot * normal.Y); - } + float dot = Vector2.Dot(vector, normal); + return vector - (2 * dot * normal); } /// @@ -253,17 +193,8 @@ namespace System.Numerics [MethodImpl(MethodImplOptions.AggressiveInlining)] public static Vector2 Clamp(Vector2 value1, Vector2 min, Vector2 max) { - // This compare order is very important!!! // We must follow HLSL behavior in the case user specified min value is bigger than max value. - float x = value1.X; - x = (min.X > x) ? min.X : x; // max(x, minx) - x = (max.X < x) ? max.X : x; // min(x, maxx) - - float y = value1.Y; - y = (min.Y > y) ? min.Y : y; // max(y, miny) - y = (max.Y < y) ? max.Y : y; // min(y, maxy) - - return new Vector2(x, y); + return Vector2.Min(Vector2.Max(value1, min), max); } /// diff --git a/src/System.Private.CoreLib/shared/System/Numerics/Vector3.cs b/src/System.Private.CoreLib/shared/System/Numerics/Vector3.cs index d69c196a9..af110ffcc 100644 --- a/src/System.Private.CoreLib/shared/System/Numerics/Vector3.cs +++ b/src/System.Private.CoreLib/shared/System/Numerics/Vector3.cs @@ -124,16 +124,8 @@ namespace System.Numerics [MethodImpl(MethodImplOptions.AggressiveInlining)] public readonly float Length() { - if (Vector.IsHardwareAccelerated) - { - float ls = Vector3.Dot(this, this); - return MathF.Sqrt(ls); - } - else - { - float ls = X * X + Y * Y + Z * Z; - return MathF.Sqrt(ls); - } + float ls = Vector3.Dot(this, this); + return MathF.Sqrt(ls); } /// @@ -143,14 +135,7 @@ namespace System.Numerics [MethodImpl(MethodImplOptions.AggressiveInlining)] public readonly float LengthSquared() { - if (Vector.IsHardwareAccelerated) - { - return Vector3.Dot(this, this); - } - else - { - return X * X + Y * Y + Z * Z; - } + return Vector3.Dot(this, this); } #endregion Public Instance Methods @@ -164,22 +149,9 @@ namespace System.Numerics [MethodImpl(MethodImplOptions.AggressiveInlining)] public static float Distance(Vector3 value1, Vector3 value2) { - if (Vector.IsHardwareAccelerated) - { - Vector3 difference = value1 - value2; - float ls = Vector3.Dot(difference, difference); - return MathF.Sqrt(ls); - } - else - { - float dx = value1.X - value2.X; - float dy = value1.Y - value2.Y; - float dz = value1.Z - value2.Z; - - float ls = dx * dx + dy * dy + dz * dz; - - return MathF.Sqrt(ls); - } + Vector3 difference = value1 - value2; + float ls = Vector3.Dot(difference, difference); + return MathF.Sqrt(ls); } /// @@ -191,19 +163,8 @@ namespace System.Numerics [MethodImpl(MethodImplOptions.AggressiveInlining)] public static float DistanceSquared(Vector3 value1, Vector3 value2) { - if (Vector.IsHardwareAccelerated) - { - Vector3 difference = value1 - value2; - return Vector3.Dot(difference, difference); - } - else - { - float dx = value1.X - value2.X; - float dy = value1.Y - value2.Y; - float dz = value1.Z - value2.Z; - - return dx * dx + dy * dy + dz * dz; - } + Vector3 difference = value1 - value2; + return Vector3.Dot(difference, difference); } /// @@ -214,17 +175,8 @@ namespace System.Numerics [MethodImpl(MethodImplOptions.AggressiveInlining)] public static Vector3 Normalize(Vector3 value) { - if (Vector.IsHardwareAccelerated) - { - float length = value.Length(); - return value / length; - } - else - { - float ls = value.X * value.X + value.Y * value.Y + value.Z * value.Z; - float length = MathF.Sqrt(ls); - return new Vector3(value.X / length, value.Y / length, value.Z / length); - } + float length = value.Length(); + return value / length; } /// @@ -251,20 +203,9 @@ namespace System.Numerics [MethodImpl(MethodImplOptions.AggressiveInlining)] public static Vector3 Reflect(Vector3 vector, Vector3 normal) { - if (Vector.IsHardwareAccelerated) - { - float dot = Vector3.Dot(vector, normal); - Vector3 temp = normal * dot * 2f; - return vector - temp; - } - else - { - float dot = vector.X * normal.X + vector.Y * normal.Y + vector.Z * normal.Z; - float tempX = normal.X * dot * 2f; - float tempY = normal.Y * dot * 2f; - float tempZ = normal.Z * dot * 2f; - return new Vector3(vector.X - tempX, vector.Y - tempY, vector.Z - tempZ); - } + float dot = Vector3.Dot(vector, normal); + Vector3 temp = normal * dot * 2f; + return vector - temp; } /// @@ -277,21 +218,8 @@ namespace System.Numerics [MethodImpl(MethodImplOptions.AggressiveInlining)] public static Vector3 Clamp(Vector3 value1, Vector3 min, Vector3 max) { - // This compare order is very important!!! // We must follow HLSL behavior in the case user specified min value is bigger than max value. - float x = value1.X; - x = (min.X > x) ? min.X : x; // max(x, minx) - x = (max.X < x) ? max.X : x; // min(x, maxx) - - float y = value1.Y; - y = (min.Y > y) ? min.Y : y; // max(y, miny) - y = (max.Y < y) ? max.Y : y; // min(y, maxy) - - float z = value1.Z; - z = (min.Z > z) ? min.Z : z; // max(z, minz) - z = (max.Z < z) ? max.Z : z; // min(z, maxz) - - return new Vector3(x, y, z); + return Vector3.Min(Vector3.Max(value1, min), max); } /// @@ -304,19 +232,9 @@ namespace System.Numerics [MethodImpl(MethodImplOptions.AggressiveInlining)] public static Vector3 Lerp(Vector3 value1, Vector3 value2, float amount) { - if (Vector.IsHardwareAccelerated) - { - Vector3 firstInfluence = value1 * (1f - amount); - Vector3 secondInfluence = value2 * amount; - return firstInfluence + secondInfluence; - } - else - { - return new Vector3( - value1.X + (value2.X - value1.X) * amount, - value1.Y + (value2.Y - value1.Y) * amount, - value1.Z + (value2.Z - value1.Z) * amount); - } + Vector3 firstInfluence = value1 * (1f - amount); + Vector3 secondInfluence = value2 * amount; + return firstInfluence + secondInfluence; } /// diff --git a/src/System.Private.CoreLib/shared/System/Numerics/Vector4.cs b/src/System.Private.CoreLib/shared/System/Numerics/Vector4.cs index 2a463dea4..30dd34323 100644 --- a/src/System.Private.CoreLib/shared/System/Numerics/Vector4.cs +++ b/src/System.Private.CoreLib/shared/System/Numerics/Vector4.cs @@ -130,17 +130,8 @@ namespace System.Numerics [MethodImpl(MethodImplOptions.AggressiveInlining)] public readonly float Length() { - if (Vector.IsHardwareAccelerated) - { - float ls = Vector4.Dot(this, this); - return MathF.Sqrt(ls); - } - else - { - float ls = X * X + Y * Y + Z * Z + W * W; - - return MathF.Sqrt(ls); - } + float ls = Vector4.Dot(this, this); + return MathF.Sqrt(ls); } /// @@ -150,14 +141,7 @@ namespace System.Numerics [MethodImpl(MethodImplOptions.AggressiveInlining)] public readonly float LengthSquared() { - if (Vector.IsHardwareAccelerated) - { - return Vector4.Dot(this, this); - } - else - { - return X * X + Y * Y + Z * Z + W * W; - } + return Vector4.Dot(this, this); } #endregion Public Instance Methods @@ -171,23 +155,9 @@ namespace System.Numerics [MethodImpl(MethodImplOptions.AggressiveInlining)] public static float Distance(Vector4 value1, Vector4 value2) { - if (Vector.IsHardwareAccelerated) - { - Vector4 difference = value1 - value2; - float ls = Vector4.Dot(difference, difference); - return MathF.Sqrt(ls); - } - else - { - float dx = value1.X - value2.X; - float dy = value1.Y - value2.Y; - float dz = value1.Z - value2.Z; - float dw = value1.W - value2.W; - - float ls = dx * dx + dy * dy + dz * dz + dw * dw; - - return MathF.Sqrt(ls); - } + Vector4 difference = value1 - value2; + float ls = Vector4.Dot(difference, difference); + return MathF.Sqrt(ls); } /// @@ -199,20 +169,8 @@ namespace System.Numerics [MethodImpl(MethodImplOptions.AggressiveInlining)] public static float DistanceSquared(Vector4 value1, Vector4 value2) { - if (Vector.IsHardwareAccelerated) - { - Vector4 difference = value1 - value2; - return Vector4.Dot(difference, difference); - } - else - { - float dx = value1.X - value2.X; - float dy = value1.Y - value2.Y; - float dz = value1.Z - value2.Z; - float dw = value1.W - value2.W; - - return dx * dx + dy * dy + dz * dz + dw * dw; - } + Vector4 difference = value1 - value2; + return Vector4.Dot(difference, difference); } /// @@ -223,22 +181,8 @@ namespace System.Numerics [MethodImpl(MethodImplOptions.AggressiveInlining)] public static Vector4 Normalize(Vector4 vector) { - if (Vector.IsHardwareAccelerated) - { - float length = vector.Length(); - return vector / length; - } - else - { - float ls = vector.X * vector.X + vector.Y * vector.Y + vector.Z * vector.Z + vector.W * vector.W; - float invNorm = 1.0f / MathF.Sqrt(ls); - - return new Vector4( - vector.X * invNorm, - vector.Y * invNorm, - vector.Z * invNorm, - vector.W * invNorm); - } + float length = vector.Length(); + return vector / length; } /// @@ -251,25 +195,8 @@ namespace System.Numerics [MethodImpl(MethodImplOptions.AggressiveInlining)] public static Vector4 Clamp(Vector4 value1, Vector4 min, Vector4 max) { - // This compare order is very important!!! // We must follow HLSL behavior in the case user specified min value is bigger than max value. - float x = value1.X; - x = (min.X > x) ? min.X : x; // max(x, minx) - x = (max.X < x) ? max.X : x; // min(x, maxx) - - float y = value1.Y; - y = (min.Y > y) ? min.Y : y; // max(y, miny) - y = (max.Y < y) ? max.Y : y; // min(y, maxy) - - float z = value1.Z; - z = (min.Z > z) ? min.Z : z; // max(z, minz) - z = (max.Z < z) ? max.Z : z; // min(z, maxz) - - float w = value1.W; - w = (min.W > w) ? min.W : w; // max(w, minw) - w = (max.W < w) ? max.W : w; // min(w, minw) - - return new Vector4(x, y, z, w); + return Vector4.Min(Vector4.Max(value1, min), max); } /// diff --git a/src/System.Private.CoreLib/shared/System/Numerics/Vector_Operations.cs b/src/System.Private.CoreLib/shared/System/Numerics/Vector_Operations.cs index 8d41edaf1..f16d1c4fc 100644 --- a/src/System.Private.CoreLib/shared/System/Numerics/Vector_Operations.cs +++ b/src/System.Private.CoreLib/shared/System/Numerics/Vector_Operations.cs @@ -626,6 +626,70 @@ namespace System.Numerics { return Vector.SquareRoot(value); } + + /// + /// Returns a new vector whose elements are the smallest integral values that are greater than or equal to the given vector's elements. + /// + /// The source vector. + /// + /// The vector whose elements are the smallest integral values that are greater than or equal to the given vector's elements. + /// If a value is equal to , or , that value is returned. + /// Note that this method returns a instead of an integral type. + /// + [Intrinsic] + [MethodImpl(MethodImplOptions.AggressiveInlining)] + public static Vector Ceiling(Vector value) + { + return Vector.Ceiling(value); + } + + /// + /// Returns a new vector whose elements are the smallest integral values that are greater than or equal to the given vector's elements. + /// + /// The source vector. + /// + /// The vector whose elements are the smallest integral values that are greater than or equal to the given vector's elements. + /// If a value is equal to , or , that value is returned. + /// Note that this method returns a instead of an integral type. + /// + [Intrinsic] + [MethodImpl(MethodImplOptions.AggressiveInlining)] + public static Vector Ceiling(Vector value) + { + return Vector.Ceiling(value); + } + + /// + /// Returns a new vector whose elements are the largest integral values that are less than or equal to the given vector's elements. + /// + /// The source vector. + /// + /// The vector whose elements are the largest integral values that are less than or equal to the given vector's elements. + /// If a value is equal to , or , that value is returned. + /// Note that this method returns a instead of an integral type. + /// + [Intrinsic] + [MethodImpl(MethodImplOptions.AggressiveInlining)] + public static Vector Floor(Vector value) + { + return Vector.Floor(value); + } + + /// + /// Returns a new vector whose elements are the largest integral values that are less than or equal to the given vector's elements. + /// + /// The source vector. + /// + /// The vector whose elements are the largest integral values that are less than or equal to the given vector's elements. + /// If a value is equal to , or , that value is returned. + /// Note that this method returns a instead of an integral type. + /// + [Intrinsic] + [MethodImpl(MethodImplOptions.AggressiveInlining)] + public static Vector Floor(Vector value) + { + return Vector.Floor(value); + } #endregion Vector Math Methods #region Named Arithmetic Operators diff --git a/src/System.Private.CoreLib/shared/System/ObsoleteAttribute.cs b/src/System.Private.CoreLib/shared/System/ObsoleteAttribute.cs index 94a26dd95..0bd3af61b 100644 --- a/src/System.Private.CoreLib/shared/System/ObsoleteAttribute.cs +++ b/src/System.Private.CoreLib/shared/System/ObsoleteAttribute.cs @@ -18,35 +18,39 @@ namespace System // Error indicates if the compiler should treat usage of such a method as an // error. (this would be used if the actual implementation of the obsolete // method's implementation had changed). + // DiagnosticId. Represents the ID the compiler will use when reporting a use of the API. + // UrlFormat.The URL that should be used by an IDE for navigating to corresponding documentation. Instead of taking the URL directly, + // the API takes a format string. This allows having a generic URL that includes the diagnostic ID. // [AttributeUsage(AttributeTargets.Class | AttributeTargets.Struct | AttributeTargets.Enum | AttributeTargets.Interface | AttributeTargets.Constructor | AttributeTargets.Method | AttributeTargets.Property | AttributeTargets.Field | AttributeTargets.Event | AttributeTargets.Delegate, Inherited = false)] public sealed class ObsoleteAttribute : Attribute { - private readonly string? _message; - private readonly bool _error; - public ObsoleteAttribute() { - _message = null; - _error = false; + Message = null; + IsError = false; } public ObsoleteAttribute(string? message) { - _message = message; - _error = false; + Message = message; + IsError = false; } public ObsoleteAttribute(string? message, bool error) { - _message = message; - _error = error; + Message = message; + IsError = error; } - public string? Message => _message; + public string? Message { get; } - public bool IsError => _error; + public bool IsError { get; } + + public string? DiagnosticId { get; set; } + + public string? UrlFormat { get; set; } } } diff --git a/src/System.Private.CoreLib/shared/System/PasteArguments.Unix.cs b/src/System.Private.CoreLib/shared/System/PasteArguments.Unix.cs index 1a4d92850..ccb810a6d 100644 --- a/src/System.Private.CoreLib/shared/System/PasteArguments.Unix.cs +++ b/src/System.Private.CoreLib/shared/System/PasteArguments.Unix.cs @@ -3,7 +3,6 @@ // See the LICENSE file in the project root for more information. using System.Collections.Generic; -using System.Runtime.CompilerServices; using System.Text; namespace System diff --git a/src/System.Private.CoreLib/shared/System/Range.cs b/src/System.Private.CoreLib/shared/System/Range.cs index a45eda37a..f2c549381 100644 --- a/src/System.Private.CoreLib/shared/System/Range.cs +++ b/src/System.Private.CoreLib/shared/System/Range.cs @@ -5,6 +5,10 @@ using System.Diagnostics; using System.Runtime.CompilerServices; +#if NETSTANDARD2_0 +using System.Numerics.Hashing; +#endif + namespace System { /// Represent a range has start and end indexes. @@ -47,14 +51,18 @@ namespace System /// Returns the hash code for this instance. public override int GetHashCode() { +#if !NETSTANDARD2_0 return HashCode.Combine(Start.GetHashCode(), End.GetHashCode()); +#else + return HashHelpers.Combine(Start.GetHashCode(), End.GetHashCode()); +#endif } /// Converts the value of the current Range object to its equivalent string representation. public override string ToString() { +#if !NETSTANDARD2_0 Span span = stackalloc char[2 + (2 * 11)]; // 2 for "..", then for each index 1 for '^' and 10 for longest possible uint - int charsWritten; int pos = 0; if (Start.IsFromEnd) @@ -62,7 +70,7 @@ namespace System span[0] = '^'; pos = 1; } - bool formatted = ((uint)Start.Value).TryFormat(span.Slice(pos), out charsWritten); + bool formatted = ((uint)Start.Value).TryFormat(span.Slice(pos), out int charsWritten); Debug.Assert(formatted); pos += charsWritten; @@ -78,6 +86,9 @@ namespace System pos += charsWritten; return new string(span.Slice(0, pos)); +#else + return Start.ToString() + ".." + End.ToString(); +#endif } /// Create a Range object starting from start index to the end of the collection. diff --git a/src/System.Private.CoreLib/shared/System/Reflection/Emit/TypeNameBuilder.cs b/src/System.Private.CoreLib/shared/System/Reflection/Emit/TypeNameBuilder.cs new file mode 100644 index 000000000..5f9bb76cb --- /dev/null +++ b/src/System.Private.CoreLib/shared/System/Reflection/Emit/TypeNameBuilder.cs @@ -0,0 +1,347 @@ +// 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. +// +// This TypeNameBuilder is ported from CoreCLR's original. +// It replaces the C++ bits of the implementation with a faithful C# port. + +using System.Collections.Generic; +using System.Collections; +using System.Runtime.CompilerServices; +using System.Runtime.InteropServices; +using System.Text; +using System.Diagnostics; + +namespace System.Reflection.Emit +{ + internal class TypeNameBuilder + { + private StringBuilder _str = new StringBuilder(); + private int _instNesting; + private bool _firstInstArg; + private bool _nestedName; + private bool _hasAssemblySpec; + private bool _useAngleBracketsForGenerics; + private List _stack = new List(); + private int _stackIdx; + + private TypeNameBuilder() + { + } + + private void OpenGenericArguments() + { + _instNesting++; + _firstInstArg = true; + + if (_useAngleBracketsForGenerics) + Append('<'); + else + Append('['); + } + + private void CloseGenericArguments() + { + Debug.Assert(_instNesting != 0); + + _instNesting--; + + if (_firstInstArg) + { + _str.Remove(_str.Length - 1, 1); + } + else + { + if (_useAngleBracketsForGenerics) + Append('>'); + else + Append(']'); + } + } + + private void OpenGenericArgument() + { + Debug.Assert(_instNesting != 0); + + _nestedName = false; + + if (!_firstInstArg) + Append(','); + + _firstInstArg = false; + + if (_useAngleBracketsForGenerics) + Append('<'); + else + Append('['); + + PushOpenGenericArgument(); + } + + private void CloseGenericArgument() + { + Debug.Assert(_instNesting != 0); + + if (_hasAssemblySpec) + { + if (_useAngleBracketsForGenerics) + Append('>'); + else + Append(']'); + } + + PopOpenGenericArgument(); + } + + private void AddName(string name) + { + Debug.Assert(name != null); + + if (_nestedName) + Append('+'); + + _nestedName = true; + + EscapeName(name); + } + + private void AddArray(int rank) + { + Debug.Assert(rank > 0); + + if (rank == 1) + { + Append("[*]"); + } + else if (rank > 64) + { + // Only taken in an error path, runtime will not load arrays of more than 32 dimensions + _str.Append('[').Append(rank).Append(']'); + } + else + { + Append('['); + for (int i = 1; i < rank; i++) + Append(','); + Append(']'); + } + } + + private void AddAssemblySpec(string assemblySpec) + { + if (assemblySpec != null && !assemblySpec.Equals("")) + { + Append(", "); + + if (_instNesting > 0) + { + EscapeEmbeddedAssemblyName(assemblySpec); + } + else + { + EscapeAssemblyName(assemblySpec); + } + + _hasAssemblySpec = true; + } + } + + public override string ToString() + { + Debug.Assert(_instNesting == 0); + + return _str.ToString(); + } + + private static bool ContainsReservedChar(string name) + { + foreach (char c in name) + { + if (c == '\0') + break; + if (IsTypeNameReservedChar(c)) + return true; + } + return false; + } + + private static bool IsTypeNameReservedChar(char ch) + { + switch (ch) + { + case ',': + case '[': + case ']': + case '&': + case '*': + case '+': + case '\\': + return true; + + default: + return false; + } + } + + private void EscapeName(string name) + { + if (ContainsReservedChar(name)) + { + foreach (char c in name) + { + if (c == '\0') + break; + if (IsTypeNameReservedChar(c)) + _str.Append('\\'); + _str.Append(c); + } + } + else + Append(name); + } + + private void EscapeAssemblyName(string name) + { + Append(name); + } + + private void EscapeEmbeddedAssemblyName(string name) + { + if (name.Contains(']')) + { + foreach (char c in name) + { + if (c == ']') + Append('\\'); + + Append(c); + } + } + else + { + Append(name); + } + } + + private void PushOpenGenericArgument() + { + _stack.Add(_str.Length); + _stackIdx++; + } + + private void PopOpenGenericArgument() + { + int index = _stack[--_stackIdx]; + _stack.RemoveAt(_stackIdx); + + if (!_hasAssemblySpec) + _str.Remove(index - 1, 1); + + _hasAssemblySpec = false; + } + + private void SetUseAngleBracketsForGenerics(bool value) + { + _useAngleBracketsForGenerics = value; + } + + private void Append(string pStr) + { + foreach (char c in pStr) + { + if (c == '\0') + break; + _str.Append(c); + } + } + + private void Append(char c) + { + _str.Append(c); + } + + internal enum Format + { + ToString, + FullName, + AssemblyQualifiedName, + } + + internal static string? ToString(Type type, Format format) + { + if (format == Format.FullName || format == Format.AssemblyQualifiedName) + { + if (!type.IsGenericTypeDefinition && type.ContainsGenericParameters) + return null; + } + + var tnb = new TypeNameBuilder(); + tnb.AddAssemblyQualifiedName(type, format); + return tnb.ToString(); + } + + private void AddElementType(Type type) + { + if (!type.HasElementType) + return; + + AddElementType(type.GetElementType()!); + + if (type.IsPointer) + Append('*'); + else if (type.IsByRef) + Append('&'); + else if (type.IsSZArray) + Append("[]"); + else if (type.IsArray) + AddArray(type.GetArrayRank()); + } + + private void AddAssemblyQualifiedName(Type type, Format format) + { + Type rootType = type; + + while (rootType.HasElementType) + rootType = rootType.GetElementType()!; + + // Append namespace + nesting + name + var nestings = new List(); + for (Type? t = rootType; t != null; t = t.IsGenericParameter ? null : t.DeclaringType) + nestings.Add(t); + + for (int i = nestings.Count - 1; i >= 0; i--) + { + Type enclosingType = nestings[i]; + string name = enclosingType.Name; + + if (i == nestings.Count - 1 && enclosingType.Namespace != null && enclosingType.Namespace.Length != 0) + name = enclosingType.Namespace + "." + name; + + AddName(name); + } + + // Append generic arguments + if (rootType.IsGenericType && (!rootType.IsGenericTypeDefinition || format == Format.ToString)) + { + Type[] genericArguments = rootType.GetGenericArguments(); + + OpenGenericArguments(); + for (int i = 0; i < genericArguments.Length; i++) + { + Format genericArgumentsFormat = format == Format.FullName ? Format.AssemblyQualifiedName : format; + + OpenGenericArgument(); + AddAssemblyQualifiedName(genericArguments[i], genericArgumentsFormat); + CloseGenericArgument(); + } + CloseGenericArguments(); + } + + // Append pointer, byRef and array qualifiers + AddElementType(type); + + if (format == Format.AssemblyQualifiedName) + AddAssemblySpec(type.Module.Assembly.FullName!); + } + } +} diff --git a/src/System.Private.CoreLib/shared/System/Reflection/ManifestResourceInfo.cs b/src/System.Private.CoreLib/shared/System/Reflection/ManifestResourceInfo.cs index 584e1361e..6d59256a6 100644 --- a/src/System.Private.CoreLib/shared/System/Reflection/ManifestResourceInfo.cs +++ b/src/System.Private.CoreLib/shared/System/Reflection/ManifestResourceInfo.cs @@ -6,8 +6,8 @@ namespace System.Reflection { public class ManifestResourceInfo { - public ManifestResourceInfo(Assembly containingAssembly, - string containingFileName, + public ManifestResourceInfo(Assembly? containingAssembly, + string? containingFileName, ResourceLocation resourceLocation) { ReferencedAssembly = containingAssembly; @@ -15,8 +15,8 @@ namespace System.Reflection ResourceLocation = resourceLocation; } - public virtual Assembly ReferencedAssembly { get; } - public virtual string FileName { get; } + public virtual Assembly? ReferencedAssembly { get; } + public virtual string? FileName { get; } public virtual ResourceLocation ResourceLocation { get; } } } diff --git a/src/System.Private.CoreLib/shared/System/Reflection/ParameterInfo.cs b/src/System.Private.CoreLib/shared/System/Reflection/ParameterInfo.cs index ef13b9031..9bea1e0f4 100644 --- a/src/System.Private.CoreLib/shared/System/Reflection/ParameterInfo.cs +++ b/src/System.Private.CoreLib/shared/System/Reflection/ParameterInfo.cs @@ -60,8 +60,7 @@ namespace System.Reflection if (MemberImpl == null) throw new SerializationException(SR.Serialization_InsufficientState); - ParameterInfo[]? args = null; - + ParameterInfo[] args; switch (MemberImpl.MemberType) { case MemberTypes.Constructor: diff --git a/src/System.Private.CoreLib/shared/System/Resources/FileBasedResourceGroveler.cs b/src/System.Private.CoreLib/shared/System/Resources/FileBasedResourceGroveler.cs index 27af1ffae..8df3c0c89 100644 --- a/src/System.Private.CoreLib/shared/System/Resources/FileBasedResourceGroveler.cs +++ b/src/System.Private.CoreLib/shared/System/Resources/FileBasedResourceGroveler.cs @@ -37,13 +37,12 @@ namespace System.Resources { Debug.Assert(culture != null, "culture shouldn't be null; check caller"); - string? fileName = null; ResourceSet? rs = null; // Don't use Assembly manifest, but grovel on disk for a file. // Create new ResourceSet, if a file exists on disk for it. string tempFileName = _mediator.GetResourceFileName(culture); - fileName = FindResourceFile(culture, tempFileName); + string? fileName = FindResourceFile(culture, tempFileName); if (fileName == null) { if (tryParents) diff --git a/src/System.Private.CoreLib/shared/System/Resources/ResourceManager.Uap.cs b/src/System.Private.CoreLib/shared/System/Resources/ResourceManager.Uap.cs index 2fa9e0dc6..2a8d73732 100644 --- a/src/System.Private.CoreLib/shared/System/Resources/ResourceManager.Uap.cs +++ b/src/System.Private.CoreLib/shared/System/Resources/ResourceManager.Uap.cs @@ -88,7 +88,7 @@ namespace System.Resources return false; // Check to see if the assembly is under PLATFORM_RESOURCE_ROOTS. If it is, then we should use satellite assembly lookup for it. - string? platformResourceRoots = (string?)AppContext.GetData("PLATFORM_RESOURCE_ROOTS"); + string? platformResourceRoots = AppContext.GetData("PLATFORM_RESOURCE_ROOTS") as string; if (!string.IsNullOrEmpty(platformResourceRoots)) { string resourceAssemblyPath = resourcesAssembly.Location; diff --git a/src/System.Private.CoreLib/shared/System/Resources/ResourceManager.cs b/src/System.Private.CoreLib/shared/System/Resources/ResourceManager.cs index 9fb40a69a..4ab1ecf19 100644 --- a/src/System.Private.CoreLib/shared/System/Resources/ResourceManager.cs +++ b/src/System.Private.CoreLib/shared/System/Resources/ResourceManager.cs @@ -501,8 +501,7 @@ namespace System.Resources lock (localResourceSets) { // If another thread added this culture, return that. - ResourceSet? lostRace; - if (localResourceSets.TryGetValue(cultureName, out lostRace)) + if (localResourceSets.TryGetValue(cultureName, out ResourceSet? lostRace)) { if (!object.ReferenceEquals(lostRace, rs)) { diff --git a/src/System.Private.CoreLib/shared/System/Resources/ResourceReader.cs b/src/System.Private.CoreLib/shared/System/Resources/ResourceReader.cs index 11abfc352..e601d637a 100644 --- a/src/System.Private.CoreLib/shared/System/Resources/ResourceReader.cs +++ b/src/System.Private.CoreLib/shared/System/Resources/ResourceReader.cs @@ -442,11 +442,11 @@ namespace System.Resources { throw new FormatException(SR.Format(SR.BadImageFormat_ResourcesDataInvalidOffset, dataPos)); } - ResourceTypeCode junk; + if (_version == 1) return LoadObjectV1(dataPos); else - return LoadObjectV2(dataPos, out junk); + return LoadObjectV2(dataPos, out _); } } @@ -1044,8 +1044,7 @@ namespace System.Resources lock (_reader._resCache) { key = _reader.AllocateStringForNameIndex(_currentName, out _dataPosition); // AllocateStringForNameIndex could lock on _reader - ResourceLocator locator; - if (_reader._resCache.TryGetValue(key, out locator)) + if (_reader._resCache.TryGetValue(key, out ResourceLocator locator)) { value = locator.Value; } diff --git a/src/System.Private.CoreLib/shared/System/Runtime/CompilerServices/SkipLocalsInitAttribute.cs b/src/System.Private.CoreLib/shared/System/Runtime/CompilerServices/SkipLocalsInitAttribute.cs index fef7f1174..349c12ace 100644 --- a/src/System.Private.CoreLib/shared/System/Runtime/CompilerServices/SkipLocalsInitAttribute.cs +++ b/src/System.Private.CoreLib/shared/System/Runtime/CompilerServices/SkipLocalsInitAttribute.cs @@ -21,6 +21,7 @@ namespace System.Runtime.CompilerServices [AttributeUsage(AttributeTargets.Module | AttributeTargets.Class | AttributeTargets.Struct + | AttributeTargets.Interface | AttributeTargets.Constructor | AttributeTargets.Method | AttributeTargets.Property @@ -31,4 +32,4 @@ namespace System.Runtime.CompilerServices { } } -} \ No newline at end of file +} diff --git a/src/System.Private.CoreLib/shared/System/Runtime/InteropServices/ComEventsHelpers.NoCom.cs b/src/System.Private.CoreLib/shared/System/Runtime/InteropServices/ComEventsHelpers.NoCom.cs index 7b29d6f9a..422698ce0 100644 --- a/src/System.Private.CoreLib/shared/System/Runtime/InteropServices/ComEventsHelpers.NoCom.cs +++ b/src/System.Private.CoreLib/shared/System/Runtime/InteropServices/ComEventsHelpers.NoCom.cs @@ -2,8 +2,6 @@ // 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.InteropServices.ComTypes; - namespace System.Runtime.InteropServices { public static class ComEventsHelper diff --git a/src/System.Private.CoreLib/shared/System/Runtime/InteropServices/ComWrappers.PlatformNotSupported.cs b/src/System.Private.CoreLib/shared/System/Runtime/InteropServices/ComWrappers.PlatformNotSupported.cs new file mode 100644 index 000000000..05764b08b --- /dev/null +++ b/src/System.Private.CoreLib/shared/System/Runtime/InteropServices/ComWrappers.PlatformNotSupported.cs @@ -0,0 +1,75 @@ +// 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.Collections; + +namespace System.Runtime.InteropServices +{ + [Flags] + public enum CreateComInterfaceFlags + { + None = 0, + CallerDefinedIUnknown = 1, + TrackerSupport = 2, + } + + [Flags] + public enum CreateObjectFlags + { + None = 0, + TrackerObject = 1, + UniqueInstance = 2, + } + + [CLSCompliant(false)] + public abstract class ComWrappers + { + public struct ComInterfaceEntry + { + public Guid IID; + public IntPtr Vtable; + } + + public struct ComInterfaceDispatch + { + public IntPtr Vtable; + + public static unsafe T GetInstance(ComInterfaceDispatch* dispatchPtr) where T : class + { + throw new PlatformNotSupportedException(); + } + } + + public IntPtr GetOrCreateComInterfaceForObject(object instance, CreateComInterfaceFlags flags) + { + throw new PlatformNotSupportedException(); + } + + protected abstract unsafe ComInterfaceEntry* ComputeVtables(object obj, CreateComInterfaceFlags flags, out int count); + + public object GetOrCreateObjectForComInstance(IntPtr externalComObject, CreateObjectFlags flags) + { + throw new PlatformNotSupportedException(); + } + + protected abstract object? CreateObject(IntPtr externalComObject, CreateObjectFlags flags); + + public object GetOrRegisterObjectForComInstance(IntPtr externalComObject, CreateObjectFlags flags, object wrapper) + { + throw new PlatformNotSupportedException(); + } + + protected abstract void ReleaseObjects(IEnumerable objects); + + public void RegisterAsGlobalInstance() + { + throw new PlatformNotSupportedException(); + } + + protected static void GetIUnknownImpl(out IntPtr fpQueryInterface, out IntPtr fpAddRef, out IntPtr fpRelease) + { + throw new PlatformNotSupportedException(); + } + } +} diff --git a/src/System.Private.CoreLib/shared/System/Runtime/InteropServices/GCHandle.cs b/src/System.Private.CoreLib/shared/System/Runtime/InteropServices/GCHandle.cs index e26c1190f..b7bd0361d 100644 --- a/src/System.Private.CoreLib/shared/System/Runtime/InteropServices/GCHandle.cs +++ b/src/System.Private.CoreLib/shared/System/Runtime/InteropServices/GCHandle.cs @@ -125,7 +125,7 @@ namespace System.Runtime.InteropServices // Get the address. - object target = InternalGet(GetHandleValue(handle)); + object? target = InternalGet(GetHandleValue(handle)); if (target is null) { return default; diff --git a/src/System.Private.CoreLib/shared/System/Runtime/InteropServices/Marshal.NoCom.cs b/src/System.Private.CoreLib/shared/System/Runtime/InteropServices/Marshal.NoCom.cs index b31013445..0f8a78eb9 100644 --- a/src/System.Private.CoreLib/shared/System/Runtime/InteropServices/Marshal.NoCom.cs +++ b/src/System.Private.CoreLib/shared/System/Runtime/InteropServices/Marshal.NoCom.cs @@ -91,6 +91,11 @@ namespace System.Runtime.InteropServices return (IntPtr)(-1); } + public static IntPtr GetIDispatchForObject(object o) + { + throw new PlatformNotSupportedException(SR.PlatformNotSupported_ComInterop); + } + public static IntPtr GetIUnknownForObject(object o) { throw new PlatformNotSupportedException(SR.PlatformNotSupported_ComInterop); @@ -147,7 +152,7 @@ namespace System.Runtime.InteropServices throw new PlatformNotSupportedException(SR.PlatformNotSupported_ComInterop); } - public static Type GetTypeFromCLSID(Guid clsid) + public static Type? GetTypeFromCLSID(Guid clsid) { throw new PlatformNotSupportedException(SR.PlatformNotSupported_ComInterop); } diff --git a/src/System.Private.CoreLib/shared/System/Runtime/InteropServices/Marshal.cs b/src/System.Private.CoreLib/shared/System/Runtime/InteropServices/Marshal.cs index d7fe3379e..227e84e71 100644 --- a/src/System.Private.CoreLib/shared/System/Runtime/InteropServices/Marshal.cs +++ b/src/System.Private.CoreLib/shared/System/Runtime/InteropServices/Marshal.cs @@ -873,6 +873,9 @@ namespace System.Runtime.InteropServices throw new ArgumentException(SR.Argument_NeedNonGenericType, nameof(t)); } + // COMPAT: This block of code isn't entirely correct. + // Users passing in typeof(MulticastDelegate) as 't' skip this check + // since Delegate is a base type of MulticastDelegate. Type? c = t.BaseType; if (c != typeof(Delegate) && c != typeof(MulticastDelegate)) { @@ -913,8 +916,6 @@ namespace System.Runtime.InteropServices return (dwLastError & 0x0000FFFF) | unchecked((int)0x80070000); } - public static IntPtr /* IDispatch */ GetIDispatchForObject(object o) => throw new PlatformNotSupportedException(); - public static unsafe void ZeroFreeBSTR(IntPtr s) { if (s == IntPtr.Zero) diff --git a/src/System.Private.CoreLib/shared/System/Runtime/InteropServices/NativeLibrary.cs b/src/System.Private.CoreLib/shared/System/Runtime/InteropServices/NativeLibrary.cs index 04ee346fc..bcff55343 100644 --- a/src/System.Private.CoreLib/shared/System/Runtime/InteropServices/NativeLibrary.cs +++ b/src/System.Private.CoreLib/shared/System/Runtime/InteropServices/NativeLibrary.cs @@ -68,10 +68,12 @@ namespace System.Runtime.InteropServices /// If DllImportSearchPath parameter is non-null, the flags in this enumeration are used. /// Otherwise, the flags specified by the DefaultDllImportSearchPaths attribute on the /// calling assembly (if any) are used. - /// This LoadLibrary() method does not invoke the managed call-backs for native library resolution: - /// * The per-assembly registered callback + /// This method follows the native library resolution for the AssemblyLoadContext of the + /// specified assembly. It will invoke the managed extension points: /// * AssemblyLoadContext.LoadUnmanagedDll() /// * AssemblyLoadContext.ResolvingUnmanagedDllEvent + /// It does not invoke extension points that are not tied to the AssemblyLoadContext: + /// * The per-assembly registered DllImportResolver callback /// /// The name of the native library to be loaded /// The assembly loading the native library @@ -79,7 +81,7 @@ namespace System.Runtime.InteropServices /// The handle for the loaded library /// If libraryPath or assembly is null /// If assembly is not a RuntimeAssembly - /// If the library can't be found. + /// If the library can't be found. /// If the library is not valid. public static IntPtr Load(string libraryName, Assembly assembly, DllImportSearchPath? searchPath) { @@ -90,7 +92,7 @@ namespace System.Runtime.InteropServices if (!assembly.IsRuntimeImplemented()) throw new ArgumentException(SR.Argument_MustBeRuntimeAssembly); - return LoadByName(libraryName, + return LoadLibraryByName(libraryName, assembly, searchPath, throwOnError: true); @@ -98,10 +100,21 @@ namespace System.Runtime.InteropServices /// /// NativeLibrary Loader: High-level API that doesn't throw. + /// Given a library name, this function searches specific paths based on the + /// runtime configuration, input parameters, and attributes of the calling assembly. + /// If DllImportSearchPath parameter is non-null, the flags in this enumeration are used. + /// Otherwise, the flags specified by the DefaultDllImportSearchPaths attribute on the + /// calling assembly (if any) are used. + /// This method follows the native library resolution for the AssemblyLoadContext of the + /// specified assembly. It will invoke the managed extension points: + /// * AssemblyLoadContext.LoadUnmanagedDll() + /// * AssemblyLoadContext.ResolvingUnmanagedDllEvent + /// It does not invoke extension points that are not tied to the AssemblyLoadContext: + /// * The per-assembly registered DllImportResolver callback /// /// The name of the native library to be loaded - /// The search path /// The assembly loading the native library + /// The search path /// The out-parameter for the loaded native library handle /// True on successful load, false otherwise /// If libraryPath or assembly is null @@ -115,7 +128,7 @@ namespace System.Runtime.InteropServices if (!assembly.IsRuntimeImplemented()) throw new ArgumentException(SR.Argument_MustBeRuntimeAssembly); - handle = LoadByName(libraryName, + handle = LoadLibraryByName(libraryName, assembly, searchPath, throwOnError: false); @@ -214,7 +227,7 @@ namespace System.Runtime.InteropServices } catch (ArgumentException) { - // ConditionalWealTable throws ArgumentException if the Key already exists + // ConditionalWeakTable throws ArgumentException if the Key already exists throw new InvalidOperationException(SR.InvalidOperation_CannotRegisterSecondResolver); } } diff --git a/src/System.Private.CoreLib/shared/System/Runtime/Intrinsics/Arm/AdvSimd.PlatformNotSupported.cs b/src/System.Private.CoreLib/shared/System/Runtime/Intrinsics/Arm/AdvSimd.PlatformNotSupported.cs index a51ae8b59..5c1d4391a 100644 --- a/src/System.Private.CoreLib/shared/System/Runtime/Intrinsics/Arm/AdvSimd.PlatformNotSupported.cs +++ b/src/System.Private.CoreLib/shared/System/Runtime/Intrinsics/Arm/AdvSimd.PlatformNotSupported.cs @@ -604,6 +604,18 @@ namespace System.Runtime.Intrinsics.Arm /// public static Vector128 Divide(Vector128 left, Vector128 right) { throw new PlatformNotSupportedException(); } + /// + /// float64x2_t vfmaq_f64 (float64x2_t a, float64x2_t b, float64x2_t c) + /// A64: FMLA Vd.2D, Vn.2D, Vm.2D + /// + public static Vector128 FusedMultiplyAdd(Vector128 acc, Vector128 left, Vector128 right) { throw new PlatformNotSupportedException(); } + + /// + /// float64x2_t vfmsq_f64 (float64x2_t a, float64x2_t b, float64x2_t c) + /// A64: FMLS Vd.2D, Vn.2D, Vm.2D + /// + public static Vector128 FusedMultiplySubtract(Vector128 acc, Vector128 left, Vector128 right) { throw new PlatformNotSupportedException(); } + /// /// float64x2_t vmaxq_f64 (float64x2_t a, float64x2_t b) /// A64: FMAX Vd.2D, Vn.2D, Vm.2D @@ -984,6 +996,36 @@ namespace System.Runtime.Intrinsics.Arm /// public static Vector128 Multiply(Vector128 left, Vector128 right) { throw new PlatformNotSupportedException(); } + /// + /// float32x2_t vmulx_f32 (float32x2_t a, float32x2_t b) + /// A64: FMULX Vd.2S, Vn.2S, Vm.2S + /// + public static Vector64 MultiplyExtended(Vector64 left, Vector64 right) { throw new PlatformNotSupportedException(); } + + /// + /// float64x2_t vmulxq_f64 (float64x2_t a, float64x2_t b) + /// A64: FMULX Vd.2D, Vn.2D, Vm.2D + /// + public static Vector128 MultiplyExtended(Vector128 left, Vector128 right) { throw new PlatformNotSupportedException(); } + + /// + /// float32x4_t vmulxq_f32 (float32x4_t a, float32x4_t b) + /// A64: FMULX Vd.4S, Vn.4S, Vm.4S + /// + public static Vector128 MultiplyExtended(Vector128 left, Vector128 right) { throw new PlatformNotSupportedException(); } + + /// + /// float64x1_t vmulx_f64 (float64x1_t a, float64x1_t b) + /// A64: FMULX Dd, Dn, Dm + /// + public static Vector64 MultiplyExtendedScalar(Vector64 left, Vector64 right) { throw new PlatformNotSupportedException(); } + + /// + /// float32_t vmulxs_f32 (float32_t a, float32_t b) + /// A64: FMULX Sd, Sn, Sm + /// + public static Vector64 MultiplyExtendedScalar(Vector64 left, Vector64 right) { throw new PlatformNotSupportedException(); } + /// /// float64x2_t vnegq_f64 (float64x2_t a) /// A64: FNEG Vd.2D, Vn.2D @@ -1002,6 +1044,90 @@ namespace System.Runtime.Intrinsics.Arm /// public static Vector64 NegateScalar(Vector64 value) { throw new PlatformNotSupportedException(); } + /// + /// float64x2_t vrecpeq_f64 (float64x2_t a) + /// A64: FRECPE Vd.2D, Vn.2D + /// + public static Vector128 ReciprocalEstimate(Vector128 value) { throw new PlatformNotSupportedException(); } + + /// + /// float64x1_t vrecpe_f64 (float64x1_t a) + /// A64: FRECPE Dd, Dn + /// + public static Vector64 ReciprocalEstimateScalar(Vector64 value) { throw new PlatformNotSupportedException(); } + + /// + /// float32_t vrecpes_f32 (float32_t a) + /// A64: FRECPE Sd, Sn + /// + public static Vector64 ReciprocalEstimateScalar(Vector64 value) { throw new PlatformNotSupportedException(); } + + /// + /// float64_t vrecpxd_f64 (float64_t a) + /// A64: FRECPX Dd, Dn + /// + public static Vector64 ReciprocalExponentScalar(Vector64 value) { throw new PlatformNotSupportedException(); } + + /// + /// float32_t vrecpxs_f32 (float32_t a) + /// A64: FRECPX Sd, Sn + /// + public static Vector64 ReciprocalExponentScalar(Vector64 value) { throw new PlatformNotSupportedException(); } + + /// + /// float64x2_t vrsqrteq_f64 (float64x2_t a) + /// A64: FRSQRTE Vd.2D, Vn.2D + /// + public static Vector128 ReciprocalSquareRootEstimate(Vector128 value) { throw new PlatformNotSupportedException(); } + + /// + /// float64x1_t vrsqrte_f64 (float64x1_t a) + /// A64: FRSQRTE Dd, Dn + /// + public static Vector64 ReciprocalSquareRootEstimateScalar(Vector64 value) { throw new PlatformNotSupportedException(); } + + /// + /// float32_t vrsqrtes_f32 (float32_t a) + /// A64: FRSQRTE Sd, Sn + /// + public static Vector64 ReciprocalSquareRootEstimateScalar(Vector64 value) { throw new PlatformNotSupportedException(); } + + /// + /// float64x2_t vrsqrtsq_f64 (float64x2_t a, float64x2_t b) + /// A64: FRSQRTS Vd.2D, Vn.2D, Vm.2D + /// + public static Vector128 ReciprocalSquareRootStep(Vector128 left, Vector128 right) { throw new PlatformNotSupportedException(); } + + /// + /// float64x1_t vrsqrts_f64 (float64x1_t a, float64x1_t b) + /// A64: FRSQRTS Dd, Dn, Dm + /// + public static Vector64 ReciprocalSquareRootStepScalar(Vector64 left, Vector64 right) { throw new PlatformNotSupportedException(); } + + /// + /// float32_t vrsqrtss_f32 (float32_t a, float32_t b) + /// A64: FRSQRTS Sd, Sn, Sm + /// + public static Vector64 ReciprocalSquareRootStepScalar(Vector64 left, Vector64 right) { throw new PlatformNotSupportedException(); } + + /// + /// float64x2_t vrecpsq_f64 (float64x2_t a, float64x2_t b) + /// A64: FRECPS Vd.2D, Vn.2D, Vm.2D + /// + public static Vector128 ReciprocalStep(Vector128 left, Vector128 right) { throw new PlatformNotSupportedException(); } + + /// + /// float64x1_t vrecps_f64 (float64x1_t a, float64x1_t b) + /// A64: FRECPS Dd, Dn, Dm + /// + public static Vector64 ReciprocalStepScalar(Vector64 left, Vector64 right) { throw new PlatformNotSupportedException(); } + + /// + /// float32_t vrecpss_f32 (float32_t a, float32_t b) + /// A64: FRECPS Sd, Sn, Sm + /// + public static Vector64 ReciprocalStepScalar(Vector64 left, Vector64 right) { throw new PlatformNotSupportedException(); } + /// /// float32x2_t vsqrt_f32 (float32x2_t a) /// A64: FSQRT Vd.2S, Vn.2S @@ -1020,18 +1146,6 @@ namespace System.Runtime.Intrinsics.Arm /// public static Vector128 Sqrt(Vector128 value) { throw new PlatformNotSupportedException(); } - /// - /// float64x2_t vfmaq_f64 (float64x2_t a, float64x2_t b, float64x2_t c) - /// A64: FMLA Vd.2D, Vn.2D, Vm.2D - /// - public static Vector128 FusedMultiplyAdd(Vector128 acc, Vector128 left, Vector128 right) { throw new PlatformNotSupportedException(); } - - /// - /// float64x2_t vfmsq_f64 (float64x2_t a, float64x2_t b, float64x2_t c) - /// A64: FMLS Vd.2D, Vn.2D, Vm.2D - /// - public static Vector128 FusedMultiplySubtract(Vector128 acc, Vector128 left, Vector128 right) { throw new PlatformNotSupportedException(); } - /// /// float64x2_t vsubq_f64 (float64x2_t a, float64x2_t b) /// A64: FSUB Vd.2D, Vn.2D, Vm.2D @@ -1900,6 +2014,90 @@ namespace System.Runtime.Intrinsics.Arm /// public static Vector128 AbsoluteDifference(Vector128 left, Vector128 right) { throw new PlatformNotSupportedException(); } + /// + /// uint8x8_t vaba_u8 (uint8x8_t a, uint8x8_t b, uint8x8_t c) + /// A32: VABA.U8 Dd, Dn, Dm + /// A64: UABA Vd.8B, Vn.8B, Vm.8B + /// + public static Vector64 AbsoluteDifferenceAdd(Vector64 addend, Vector64 left, Vector64 right) { throw new PlatformNotSupportedException(); } + + /// + /// int16x4_t vaba_s16 (int16x4_t a, int16x4_t b, int16x4_t c) + /// A32: VABA.S16 Dd, Dn, Dm + /// A64: SABA Vd.4H, Vn.4H, Vm.4H + /// + public static Vector64 AbsoluteDifferenceAdd(Vector64 addend, Vector64 left, Vector64 right) { throw new PlatformNotSupportedException(); } + + /// + /// int32x2_t vaba_s32 (int32x2_t a, int32x2_t b, int32x2_t c) + /// A32: VABA.S32 Dd, Dn, Dm + /// A64: SABA Vd.2S, Vn.2S, Vm.2S + /// + public static Vector64 AbsoluteDifferenceAdd(Vector64 addend, Vector64 left, Vector64 right) { throw new PlatformNotSupportedException(); } + + /// + /// int8x8_t vaba_s8 (int8x8_t a, int8x8_t b, int8x8_t c) + /// A32: VABA.S8 Dd, Dn, Dm + /// A64: SABA Vd.8B, Vn.8B, Vm.8B + /// + public static Vector64 AbsoluteDifferenceAdd(Vector64 addend, Vector64 left, Vector64 right) { throw new PlatformNotSupportedException(); } + + /// + /// uint16x4_t vaba_u16 (uint16x4_t a, uint16x4_t b, uint16x4_t c) + /// A32: VABA.U16 Dd, Dn, Dm + /// A64: UABA Vd.4H, Vn.4H, Vm.4H + /// + public static Vector64 AbsoluteDifferenceAdd(Vector64 addend, Vector64 left, Vector64 right) { throw new PlatformNotSupportedException(); } + + /// + /// uint32x2_t vaba_u32 (uint32x2_t a, uint32x2_t b, uint32x2_t c) + /// A32: VABA.U32 Dd, Dn, Dm + /// A64: UABA Vd.2S, Vn.2S, Vm.2S + /// + public static Vector64 AbsoluteDifferenceAdd(Vector64 addend, Vector64 left, Vector64 right) { throw new PlatformNotSupportedException(); } + + /// + /// uint8x16_t vabaq_u8 (uint8x16_t a, uint8x16_t b, uint8x16_t c) + /// A32: VABA.U8 Qd, Qn, Qm + /// A64: UABA Vd.16B, Vn.16B, Vm.16B + /// + public static Vector128 AbsoluteDifferenceAdd(Vector128 addend, Vector128 left, Vector128 right) { throw new PlatformNotSupportedException(); } + + /// + /// int16x8_t vabaq_s16 (int16x8_t a, int16x8_t b, int16x8_t c) + /// A32: VABA.S16 Qd, Qn, Qm + /// A64: SABA Vd.8H, Vn.8H, Vm.8H + /// + public static Vector128 AbsoluteDifferenceAdd(Vector128 addend, Vector128 left, Vector128 right) { throw new PlatformNotSupportedException(); } + + /// + /// int32x4_t vabaq_s32 (int32x4_t a, int32x4_t b, int32x4_t c) + /// A32: VABA.S32 Qd, Qn, Qm + /// A64: SABA Vd.4S, Vn.4S, Vm.4S + /// + public static Vector128 AbsoluteDifferenceAdd(Vector128 addend, Vector128 left, Vector128 right) { throw new PlatformNotSupportedException(); } + + /// + /// int8x16_t vabaq_s8 (int8x16_t a, int8x16_t b, int8x16_t c) + /// A32: VABA.S8 Qd, Qn, Qm + /// A64: SABA Vd.16B, Vn.16B, Vm.16B + /// + public static Vector128 AbsoluteDifferenceAdd(Vector128 addend, Vector128 left, Vector128 right) { throw new PlatformNotSupportedException(); } + + /// + /// uint16x8_t vabaq_u16 (uint16x8_t a, uint16x8_t b, uint16x8_t c) + /// A32: VABA.U16 Qd, Qn, Qm + /// A64: UABA Vd.8H, Vn.8H, Vm.8H + /// + public static Vector128 AbsoluteDifferenceAdd(Vector128 addend, Vector128 left, Vector128 right) { throw new PlatformNotSupportedException(); } + + /// + /// uint32x4_t vabaq_u32 (uint32x4_t a, uint32x4_t b, uint32x4_t c) + /// A32: VABA.U32 Qd, Qn, Qm + /// A64: UABA Vd.4S, Vn.4S, Vm.4S + /// + public static Vector128 AbsoluteDifferenceAdd(Vector128 addend, Vector128 left, Vector128 right) { throw new PlatformNotSupportedException(); } + /// /// uint8x8_t vadd_u8 (uint8x8_t a, uint8x8_t b) /// A32: VADD.I8 Dd, Dn, Dm @@ -3123,6 +3321,328 @@ namespace System.Runtime.Intrinsics.Arm /// public static Vector64 DivideScalar(Vector64 left, Vector64 right) { throw new PlatformNotSupportedException(); } + /// + /// uint8_t vget_lane_u8 (uint8x8_t v, const int lane) + /// A32: VMOV.U8 Rt, Dn[lane] + /// A64: UMOV Wd, Vn.B[lane] + /// + public static byte Extract(Vector64 vector, byte index) { throw new PlatformNotSupportedException(); } + + /// + /// int16_t vget_lane_s16 (int16x4_t v, const int lane) + /// A32: VMOV.S16 Rt, Dn[lane] + /// A64: SMOV Wd, Vn.H[lane] + /// + public static short Extract(Vector64 vector, byte index) { throw new PlatformNotSupportedException(); } + + /// + /// int32_t vget_lane_s32 (int32x2_t v, const int lane) + /// A32: VMOV.32 Rt, Dn[lane] + /// A64: SMOV Wd, Vn.S[lane] + /// + public static int Extract(Vector64 vector, byte index) { throw new PlatformNotSupportedException(); } + + /// + /// int8_t vget_lane_s8 (int8x8_t v, const int lane) + /// A32: VMOV.S8 Rt, Dn[lane] + /// A64: SMOV Wd, Vn.B[lane] + /// + public static sbyte Extract(Vector64 vector, byte index) { throw new PlatformNotSupportedException(); } + + /// + /// float32_t vget_lane_f32 (float32x2_t v, const int lane) + /// A32: VMOV.F32 Sd, Sm + /// A64: DUP Sd, Vn.S[lane] + /// + public static float Extract(Vector64 vector, byte index) { throw new PlatformNotSupportedException(); } + + /// + /// uint16_t vget_lane_u16 (uint16x4_t v, const int lane) + /// A32: VMOV.U16 Rt, Dn[lane] + /// A64: UMOV Wd, Vn.H[lane] + /// + public static ushort Extract(Vector64 vector, byte index) { throw new PlatformNotSupportedException(); } + + /// + /// uint32_t vget_lane_u32 (uint32x2_t v, const int lane) + /// A32: VMOV.32 Rt, Dn[lane] + /// A64: UMOV Wd, Vn.S[lane] + /// + public static uint Extract(Vector64 vector, byte index) { throw new PlatformNotSupportedException(); } + + /// + /// uint8_t vgetq_lane_u8 (uint8x16_t v, const int lane) + /// A32: VMOV.U8 Rt, Dn[lane] + /// A64: UMOV Wd, Vn.B[lane] + /// + public static byte Extract(Vector128 vector, byte index) { throw new PlatformNotSupportedException(); } + + /// + /// float64_t vgetq_lane_f64 (float64x2_t v, const int lane) + /// A32: VMOV.F64 Dd, Dm + /// A64: DUP Dd, Vn.D[lane] + /// + public static double Extract(Vector128 vector, byte index) { throw new PlatformNotSupportedException(); } + + /// + /// int16_t vgetq_lane_s16 (int16x8_t v, const int lane) + /// A32: VMOV.S16 Rt, Dn[lane] + /// A64: SMOV Wd, Vn.H[lane] + /// + public static short Extract(Vector128 vector, byte index) { throw new PlatformNotSupportedException(); } + + /// + /// int32_t vgetq_lane_s32 (int32x4_t v, const int lane) + /// A32: VMOV.32 Rt, Dn[lane] + /// A64: SMOV Wd, Vn.S[lane] + /// + public static int Extract(Vector128 vector, byte index) { throw new PlatformNotSupportedException(); } + + /// + /// int64_t vgetq_lane_s64 (int64x2_t v, const int lane) + /// A32: VMOV Rt, Rt2, Dm + /// A64: UMOV Xd, Vn.D[lane] + /// + public static long Extract(Vector128 vector, byte index) { throw new PlatformNotSupportedException(); } + + /// + /// int8_t vgetq_lane_s8 (int8x16_t v, const int lane) + /// A32: VMOV.S8 Rt, Dn[lane] + /// A64: SMOV Wd, Vn.B[lane] + /// + public static sbyte Extract(Vector128 vector, byte index) { throw new PlatformNotSupportedException(); } + + /// + /// float32_t vgetq_lane_f32 (float32x4_t v, const int lane) + /// A32: VMOV.F32 Sd, Sm + /// A64: DUP Sd, Vn.S[lane] + /// + public static float Extract(Vector128 vector, byte index) { throw new PlatformNotSupportedException(); } + + /// + /// uint16_t vgetq_lane_u16 (uint16x8_t v, const int lane) + /// A32: VMOV.U16 Rt, Dn[lane] + /// A64: UMOV Wd, Vn.H[lane] + /// + public static ushort Extract(Vector128 vector, byte index) { throw new PlatformNotSupportedException(); } + + /// + /// uint32_t vgetq_lane_u32 (uint32x4_t v, const int lane) + /// A32: VMOV.32 Rt, Dn[lane] + /// A64: UMOV Wd, Vn.S[lane] + /// + public static uint Extract(Vector128 vector, byte index) { throw new PlatformNotSupportedException(); } + + /// + /// uint64_t vgetq_lane_u64 (uint64x2_t v, const int lane) + /// A32: VMOV Rt, Rt2, Dm + /// A64: UMOV Xd, Vn.D[lane] + /// + public static ulong Extract(Vector128 vector, byte index) { throw new PlatformNotSupportedException(); } + + /// + /// int8x16_t vmovn_high_s16 (int8x8_t r, int16x8_t a) + /// A32: VMOVN.I16 Dd+1, Qm + /// A64: XTN2 Vd.16B, Vn.8H + /// + public static Vector128 ExtractAndNarrowHigh (Vector64 lower, Vector128 value) { throw new PlatformNotSupportedException(); } + + /// + /// int16x8_t vmovn_high_s32 (int16x4_t r, int32x4_t a) + /// A32: VMOVN.I32 Dd+1, Qm + /// A64: XTN2 Vd.8H, Vn.4S + /// + public static Vector128 ExtractAndNarrowHigh (Vector64 lower, Vector128 value) { throw new PlatformNotSupportedException(); } + + /// + /// int32x4_t vmovn_high_s64 (int32x2_t r, int64x2_t a) + /// A32: VMOVN.I64 Dd+1, Qm + /// A64: XTN2 Vd.4S, Vn.2D + /// + public static Vector128 ExtractAndNarrowHigh (Vector64 lower, Vector128 value) { throw new PlatformNotSupportedException(); } + + /// + /// uint8x16_t vmovn_high_u16 (uint8x8_t r, uint16x8_t a) + /// A32: VMOVN.I16 Dd+1, Qm + /// A64: XTN2 Vd.16B, Vn.8H + /// + public static Vector128 ExtractAndNarrowHigh (Vector64 lower, Vector128 value) { throw new PlatformNotSupportedException(); } + + /// + /// uint16x8_t vmovn_high_u32 (uint16x4_t r, uint32x4_t a) + /// A32: VMOVN.I32 Dd+1, Qm + /// A64: XTN2 Vd.8H, Vn.4S + /// + public static Vector128 ExtractAndNarrowHigh (Vector64 lower, Vector128 value) { throw new PlatformNotSupportedException(); } + + /// + /// uint32x4_t vmovn_high_u64 (uint32x2_t r, uint64x2_t a) + /// A32: VMOVN.I64 Dd+1, Qm + /// A64: XTN2 Vd.4S, Vn.2D + /// + public static Vector128 ExtractAndNarrowHigh (Vector64 lower, Vector128 value) { throw new PlatformNotSupportedException(); } + + /// + /// int8x8_t vmovn_s16 (int16x8_t a) + /// A32: VMOVN.I16 Dd, Qm + /// A64: XTN Vd.8B, Vn.8H + /// + public static Vector64 ExtractAndNarrowLow (Vector128 value) { throw new PlatformNotSupportedException(); } + + /// + /// int16x4_t vmovn_s32 (int32x4_t a) + /// A32: VMOVN.I32 Dd, Qm + /// A64: XTN Vd.4H, Vn.4S + /// + public static Vector64 ExtractAndNarrowLow (Vector128 value) { throw new PlatformNotSupportedException(); } + + /// + /// int32x2_t vmovn_s64 (int64x2_t a) + /// A32: VMOVN.I64 Dd, Qm + /// A64: XTN Vd.2S, Vn.2D + /// + public static Vector64 ExtractAndNarrowLow (Vector128 value) { throw new PlatformNotSupportedException(); } + + /// + /// uint8x8_t vmovn_u16 (uint16x8_t a) + /// A32: VMOVN.I16 Dd, Qm + /// A64: XTN Vd.8B, Vn.8H + /// + public static Vector64 ExtractAndNarrowLow (Vector128 value) { throw new PlatformNotSupportedException(); } + + /// + /// uint16x4_t vmovn_u32 (uint32x4_t a) + /// A32: VMOVN.I32 Dd, Qm + /// A64: XTN Vd.4H, Vn.4S + /// + public static Vector64 ExtractAndNarrowLow (Vector128 value) { throw new PlatformNotSupportedException(); } + + /// + /// uint32x2_t vmovn_u64 (uint64x2_t a) + /// A32: VMOVN.I64 Dd, Qm + /// A64: XTN Vd.2S, Vn.2D + /// + public static Vector64 ExtractAndNarrowLow (Vector128 value) { throw new PlatformNotSupportedException(); } + + /// + /// uint8x8_t vext_s8 (uint8x8_t a, uint8x8_t b, const int n) + /// A32: VEXT.8 Dd, Dn, Dm, #n + /// A64: EXT Vd.8B, Vn.8B, Vm.8B, #n + /// + public static Vector64 ExtractVector64(Vector64 upper, Vector64 lower, byte index) { throw new PlatformNotSupportedException(); } + + /// + /// int16x4_t vext_s16 (int16x4_t a, int16x4_t b, const int n) + /// A32: VEXT.8 Dd, Dn, Dm, #(n*2) + /// A64: EXT Vd.8B, Vn.8B, Vm.8B, #(n*2) + /// + public static Vector64 ExtractVector64(Vector64 upper, Vector64 lower, byte index) { throw new PlatformNotSupportedException(); } + + /// + /// int32x2_t vext_s32 (int32x2_t a, int32x2_t b, const int n) + /// A32: VEXT.8 Dd, Dn, Dm, #(n*4) + /// A64: EXT Vd.8B, Vn.8B, Vm.8B, #(n*4) + /// + public static Vector64 ExtractVector64(Vector64 upper, Vector64 lower, byte index) { throw new PlatformNotSupportedException(); } + + /// + /// int8x8_t vext_s8 (int8x8_t a, int8x8_t b, const int n) + /// A32: VEXT.8 Dd, Dn, Dm, #n + /// A64: EXT Vd.8B, Vn.8B, Vm.8B, #n + /// + public static Vector64 ExtractVector64(Vector64 upper, Vector64 lower, byte index) { throw new PlatformNotSupportedException(); } + + /// + /// float32x2_t vext_f32 (float32x2_t a, float32x2_t b, const int n) + /// A32: VEXT.8 Dd, Dn, Dm, #(n*4) + /// A64: EXT Vd.8B, Vn.8B, Vm.8B, #(n*4) + /// + public static Vector64 ExtractVector64(Vector64 upper, Vector64 lower, byte index) { throw new PlatformNotSupportedException(); } + + /// + /// uint16x4_t vext_s16 (uint16x4_t a, uint16x4_t b, const int n) + /// A32: VEXT.8 Dd, Dn, Dm, #(n*2) + /// A64: EXT Vd.8B, Vn.8B, Vm.8B, #(n*2) + /// + public static Vector64 ExtractVector64(Vector64 upper, Vector64 lower, byte index) { throw new PlatformNotSupportedException(); } + + /// + /// uint32x2_t vext_s32 (uint32x2_t a, uint32x2_t b, const int n) + /// A32: VEXT.8 Dd, Dn, Dm, #(n*4) + /// A64: EXT Vd.8B, Vn.8B, Vm.8B, #(n*4) + /// + public static Vector64 ExtractVector64(Vector64 upper, Vector64 lower, byte index) { throw new PlatformNotSupportedException(); } + + /// + /// uint8x16_t vextq_s8 (uint8x16_t a, uint8x16_t b, const int n) + /// A32: VEXT.8 Qd, Qn, Qm, #n + /// A64: EXT Vd.16B, Vn.16B, Vm.16B, #n + /// + public static Vector128 ExtractVector128(Vector128 upper, Vector128 lower, byte index) { throw new PlatformNotSupportedException(); } + + /// + /// float64x2_t vextq_f64 (float64x2_t a, float64x2_t b, const int n) + /// A32: VEXT.8 Qd, Qn, Qm, #(n*8) + /// A64: EXT Vd.16B, Vn.16B, Vm.16B, #(n*8) + /// + public static Vector128 ExtractVector128(Vector128 upper, Vector128 lower, byte index) { throw new PlatformNotSupportedException(); } + + /// + /// int16x8_t vextq_s16 (int16x8_t a, int16x8_t b, const int n) + /// A32: VEXT.8 Qd, Qn, Qm, #(n*2) + /// A64: EXT Vd.16B, Vn.16B, Vm.16B, #(n*2) + /// + public static Vector128 ExtractVector128(Vector128 upper, Vector128 lower, byte index) { throw new PlatformNotSupportedException(); } + + /// + /// int32x4_t vextq_s32 (int32x4_t a, int32x4_t b, const int n) + /// A32: VEXT.8 Qd, Qn, Qm, #(n*4) + /// A64: EXT Vd.16B, Vn.16B, Vm.16B, #(n*4) + /// + public static Vector128 ExtractVector128(Vector128 upper, Vector128 lower, byte index) { throw new PlatformNotSupportedException(); } + + /// + /// int64x2_t vextq_s64 (int64x2_t a, int64x2_t b, const int n) + /// A32: VEXT.8 Qd, Qn, Qm, #(n*8) + /// A64: EXT Vd.16B, Vn.16B, Vm.16B, #(n*8) + /// + public static Vector128 ExtractVector128(Vector128 upper, Vector128 lower, byte index) { throw new PlatformNotSupportedException(); } + + /// + /// int8x16_t vextq_s8 (int8x16_t a, int8x16_t b, const int n) + /// A32: VEXT.8 Qd, Qn, Qm, #n + /// A64: EXT Vd.16B, Vn.16B, Vm.16B, #n + /// + public static Vector128 ExtractVector128(Vector128 upper, Vector128 lower, byte index) { throw new PlatformNotSupportedException(); } + + /// + /// float32x4_t vextq_f32 (float32x4_t a, float32x4_t b, const int n) + /// A32: VEXT.8 Qd, Qn, Qm, #(n*4) + /// A64: EXT Vd.16B, Vn.16B, Vm.16B, #(n*4) + /// + public static Vector128 ExtractVector128(Vector128 upper, Vector128 lower, byte index) { throw new PlatformNotSupportedException(); } + + /// + /// uint16x8_t vextq_s16 (uint16x8_t a, uint16x8_t b, const int n) + /// A32: VEXT.8 Qd, Qn, Qm, #(n*2) + /// A64: EXT Vd.16B, Vn.16B, Vm.16B, #(n*2) + /// + public static Vector128 ExtractVector128(Vector128 upper, Vector128 lower, byte index) { throw new PlatformNotSupportedException(); } + + /// + /// uint32x4_t vextq_s32 (uint32x4_t a, uint32x4_t b, const int n) + /// A32: VEXT.8 Qd, Qn, Qm, #(n*4) + /// A64: EXT Vd.16B, Vn.16B, Vm.16B, #(n*4) + /// + public static Vector128 ExtractVector128(Vector128 upper, Vector128 lower, byte index) { throw new PlatformNotSupportedException(); } + + /// + /// uint64x2_t vextq_s64 (uint64x2_t a, uint64x2_t b, const int n) + /// A32: VEXT.8 Qd, Qn, Qm, #(n*8) + /// A64: EXT Vd.16B, Vn.16B, Vm.16B, #(n*8) + /// + public static Vector128 ExtractVector128(Vector128 upper, Vector128 lower, byte index) { throw new PlatformNotSupportedException(); } + /// /// float32x2_t vfma_f32 (float32x2_t a, float32x2_t b, float32x2_t c) /// A32: VFMA.F32 Dd, Dn, Dm @@ -3213,6 +3733,125 @@ namespace System.Runtime.Intrinsics.Arm /// public static Vector64 FusedMultiplySubtractNegatedScalar(Vector64 acc, Vector64 left, Vector64 right) { throw new PlatformNotSupportedException(); } + /// + /// uint8x8_t vset_lane_u8 (uint8_t a, uint8x8_t v, const int lane) + /// A32: VMOV.8 Dd[lane], Rt + /// A64: INS Vd.B[lane], Wn + /// + public static Vector64 Insert(Vector64 vector, byte index, byte data) { throw new PlatformNotSupportedException(); } + + /// + /// int16x4_t vset_lane_s16 (int16_t a, int16x4_t v, const int lane) + /// A32: VMOV.16 Dd[lane], Rt + /// A64: INS Vd.H[lane], Wn + /// + public static Vector64 Insert(Vector64 vector, byte index, short data) { throw new PlatformNotSupportedException(); } + + /// + /// int32x2_t vset_lane_s32 (int32_t a, int32x2_t v, const int lane) + /// A32: VMOV.32 Dd[lane], Rt + /// A64: INS Vd.S[lane], Wn + /// + public static Vector64 Insert(Vector64 vector, byte index, int data) { throw new PlatformNotSupportedException(); } + + /// + /// int8x8_t vset_lane_s8 (int8_t a, int8x8_t v, const int lane) + /// A32: VMOV.8 Dd[lane], Rt + /// A64: INS Vd.B[lane], Wn + /// + public static Vector64 Insert(Vector64 vector, byte index, sbyte data) { throw new PlatformNotSupportedException(); } + + /// + /// float32x2_t vset_lane_f32 (float32_t a, float32x2_t v, const int lane) + /// A32: VMOV.F32 Sd, Sm + /// A64: INS Vd.S[lane], Vn.S[0] + /// + public static Vector64 Insert(Vector64 vector, byte index, float data) { throw new PlatformNotSupportedException(); } + + /// + /// uint16x4_t vset_lane_u16 (uint16_t a, uint16x4_t v, const int lane) + /// A32: VMOV.16 Dd[lane], Rt + /// A64: INS Vd.H[lane], Wn + /// + public static Vector64 Insert(Vector64 vector, byte index, ushort data) { throw new PlatformNotSupportedException(); } + + /// + /// uint32x2_t vset_lane_u32 (uint32_t a, uint32x2_t v, const int lane) + /// A32: VMOV.32 Dd[lane], Rt + /// A64: INS Vd.S[lane], Wn + /// + public static Vector64 Insert(Vector64 vector, byte index, uint data) { throw new PlatformNotSupportedException(); } + + /// + /// uint8x16_t vsetq_lane_u8 (uint8_t a, uint8x16_t v, const int lane) + /// A32: VMOV.8 Dd[lane], Rt + /// A64: INS Vd.B[lane], Wn + /// + public static Vector128 Insert(Vector128 vector, byte index, byte data) { throw new PlatformNotSupportedException(); } + + /// + /// float64x2_t vsetq_lane_f64 (float64_t a, float64x2_t v, const int lane) + /// A32: VMOV.F64 Dd, Dm + /// A64: INS Vd.D[lane], Vn.D[0] + /// + public static Vector128 Insert(Vector128 vector, byte index, double data) { throw new PlatformNotSupportedException(); } + + /// + /// int16x8_t vsetq_lane_s16 (int16_t a, int16x8_t v, const int lane) + /// A32: VMOV.16 Dd[lane], Rt + /// A64: INS Vd.H[lane], Wn + /// + public static Vector128 Insert(Vector128 vector, byte index, short data) { throw new PlatformNotSupportedException(); } + + /// + /// int32x4_t vsetq_lane_s32 (int32_t a, int32x4_t v, const int lane) + /// A32: VMOV.32 Dd[lane], Rt + /// A64: INS Vd.S[lane], Wn + /// + public static Vector128 Insert(Vector128 vector, byte index, int data) { throw new PlatformNotSupportedException(); } + + /// + /// int64x2_t vsetq_lane_s64 (int64_t a, int64x2_t v, const int lane) + /// A32: VMOV.64 Dd, Rt, Rt2 + /// A64: INS Vd.D[lane], Xn + /// + public static Vector128 Insert(Vector128 vector, byte index, long data) { throw new PlatformNotSupportedException(); } + + /// + /// int8x16_t vsetq_lane_s8 (int8_t a, int8x16_t v, const int lane) + /// A32: VMOV.8 Dd[lane], Rt + /// A64: INS Vd.B[lane], Wn + /// + public static Vector128 Insert(Vector128 vector, byte index, sbyte data) { throw new PlatformNotSupportedException(); } + + /// + /// float32x4_t vsetq_lane_f32 (float32_t a, float32x4_t v, const int lane) + /// A32: VMOV.F32 Sd, Sm + /// A64: INS Vd.S[lane], Vn.S[0] + /// + public static Vector128 Insert(Vector128 vector, byte index, float data) { throw new PlatformNotSupportedException(); } + + /// + /// uint16x8_t vsetq_lane_u16 (uint16_t a, uint16x8_t v, const int lane) + /// A32: VMOV.16 Dd[lane], Rt + /// A64: INS Vd.H[lane], Wn + /// + public static Vector128 Insert(Vector128 vector, byte index, ushort data) { throw new PlatformNotSupportedException(); } + + /// + /// uint32x4_t vsetq_lane_u32 (uint32_t a, uint32x4_t v, const int lane) + /// A32: VMOV.32 Dd[lane], Rt + /// A64: INS Vd.S[lane], Wn + /// + public static Vector128 Insert(Vector128 vector, byte index, uint data) { throw new PlatformNotSupportedException(); } + + /// + /// uint64x2_t vsetq_lane_u64 (uint64_t a, uint64x2_t v, const int lane) + /// A32: VMOV.64 Dd, Rt, Rt2 + /// A64: INS Vd.D[lane], Xn + /// + public static Vector128 Insert(Vector128 vector, byte index, ulong data) { throw new PlatformNotSupportedException(); } + /// /// int16x4_t vcls_s16 (int16x4_t a) /// A32: VCLS.S16 Dd, Dm @@ -4613,6 +5252,34 @@ namespace System.Runtime.Intrinsics.Arm /// public static Vector128 OrNot(Vector128 left, Vector128 right) { throw new PlatformNotSupportedException(); } + /// + /// poly8x8_t vmul_p8 (poly8x8_t a, poly8x8_t b) + /// A32: VMUL.P8 Dd, Dn, Dm + /// A64: PMUL Vd.8B, Vn.8B, Vm.8B + /// + public static Vector64 PolynomialMultiply(Vector64 left, Vector64 right) { throw new PlatformNotSupportedException(); } + + /// + /// poly8x8_t vmul_p8 (poly8x8_t a, poly8x8_t b) + /// A32: VMUL.P8 Dd, Dn, Dm + /// A64: PMUL Vd.8B, Vn.8B, Vm.8B + /// + public static Vector64 PolynomialMultiply(Vector64 left, Vector64 right) { throw new PlatformNotSupportedException(); } + + /// + /// poly8x16_t vmulq_p8 (poly8x16_t a, poly8x16_t b) + /// A32: VMUL.P8 Qd, Qn, Qm + /// A64: PMUL Vd.16B, Vn.16B, Vm.16B + /// + public static Vector128 PolynomialMultiply(Vector128 left, Vector128 right) { throw new PlatformNotSupportedException(); } + + /// + /// poly8x16_t vmulq_p8 (poly8x16_t a, poly8x16_t b) + /// A32: VMUL.P8 Qd, Qn, Qm + /// A64: PMUL Vd.16B, Vn.16B, Vm.16B + /// + public static Vector128 PolynomialMultiply(Vector128 left, Vector128 right) { throw new PlatformNotSupportedException(); } + /// /// uint8x8_t vcnt_u8 (uint8x8_t a) /// A32: VCNT.I8 Dd, Dm @@ -4641,6 +5308,90 @@ namespace System.Runtime.Intrinsics.Arm /// public static Vector128 PopCount(Vector128 value) { throw new PlatformNotSupportedException(); } + /// + /// float32x2_t vrecpe_f32 (float32x2_t a) + /// A32: VRECPE.F32 Dd, Dm + /// A64: FRECPE Vd.2S, Vn.2S + /// + public static Vector64 ReciprocalEstimate(Vector64 value) { throw new PlatformNotSupportedException(); } + + /// + /// uint32x2_t vrecpe_u32 (uint32x2_t a) + /// A32: VRECPE.U32 Dd, Dm + /// A64: URECPE Vd.2S, Vn.2S + /// + public static Vector64 ReciprocalEstimate(Vector64 value) { throw new PlatformNotSupportedException(); } + + /// + /// float32x4_t vrecpeq_f32 (float32x4_t a) + /// A32: VRECPE.F32 Qd, Qm + /// A64: FRECPE Vd.4S, Vn.4S + /// + public static Vector128 ReciprocalEstimate(Vector128 value) { throw new PlatformNotSupportedException(); } + + /// + /// uint32x4_t vrecpeq_u32 (uint32x4_t a) + /// A32: VRECPE.U32 Qd, Qm + /// A64: URECPE Vd.4S, Vn.4S + /// + public static Vector128 ReciprocalEstimate(Vector128 value) { throw new PlatformNotSupportedException(); } + + /// + /// float32x2_t vrsqrte_f32 (float32x2_t a) + /// A32: VRSQRTE.F32 Dd, Dm + /// A64: FRSQRTE Vd.2S, Vn.2S + /// + public static Vector64 ReciprocalSquareRootEstimate(Vector64 value) { throw new PlatformNotSupportedException(); } + + /// + /// uint32x2_t vrsqrte_u32 (uint32x2_t a) + /// A32: VRSQRTE.U32 Dd, Dm + /// A64: URSQRTE Vd.2S, Vn.2S + /// + public static Vector64 ReciprocalSquareRootEstimate(Vector64 value) { throw new PlatformNotSupportedException(); } + + /// + /// float32x4_t vrsqrteq_f32 (float32x4_t a) + /// A32: VRSQRTE.F32 Qd, Qm + /// A64: FRSQRTE Vd.4S, Vn.4S + /// + public static Vector128 ReciprocalSquareRootEstimate(Vector128 value) { throw new PlatformNotSupportedException(); } + + /// + /// uint32x4_t vrsqrteq_u32 (uint32x4_t a) + /// A32: VRSQRTE.U32 Qd, Qm + /// A64: URSQRTE Vd.4S, Vn.4S + /// + public static Vector128 ReciprocalSquareRootEstimate(Vector128 value) { throw new PlatformNotSupportedException(); } + + /// + /// float32x2_t vrsqrts_f32 (float32x2_t a, float32x2_t b) + /// A32: VRSQRTS.F32 Dd, Dn, Dm + /// A64: FRSQRTS Vd.2S, Vn.2S, Vm.2S + /// + public static Vector64 ReciprocalSquareRootStep(Vector64 left, Vector64 right) { throw new PlatformNotSupportedException(); } + + /// + /// float32x4_t vrsqrtsq_f32 (float32x4_t a, float32x4_t b) + /// A32: VRSQRTS.F32 Qd, Qn, Qm + /// A64: FRSQRTS Vd.4S, Vn.4S, Vm.4S + /// + public static Vector128 ReciprocalSquareRootStep(Vector128 left, Vector128 right) { throw new PlatformNotSupportedException(); } + + /// + /// float32x2_t vrecps_f32 (float32x2_t a, float32x2_t b) + /// A32: VRECPS.F32 Dd, Dn, Dm + /// A64: FRECPS Vd.2S, Vn.2S, Vm.2S + /// + public static Vector64 ReciprocalStep(Vector64 left, Vector64 right) { throw new PlatformNotSupportedException(); } + + /// + /// float32x4_t vrecpsq_f32 (float32x4_t a, float32x4_t b) + /// A32: VRECPS.F32 Qd, Qn, Qm + /// A64: FRECPS Vd.4S, Vn.4S, Vm.4S + /// + public static Vector128 ReciprocalStep(Vector128 left, Vector128 right) { throw new PlatformNotSupportedException(); } + /// /// float64x1_t vsqrt_f64 (float64x1_t a) /// A32: VSQRT.F64 Dd, Dm @@ -4656,6 +5407,146 @@ namespace System.Runtime.Intrinsics.Arm /// public static Vector64 SqrtScalar(Vector64 value) { throw new PlatformNotSupportedException(); } + /// + /// void vst1_u8 (uint8_t * ptr, uint8x8_t val) + /// A32: VST1.8 { Dd }, [Rn] + /// A64: ST1 { Vt.8B }, [Xn] + /// + public static unsafe void Store(byte* address, Vector64 source) { throw new PlatformNotSupportedException(); } + + /// + /// void vst1_f64 (float64_t * ptr, float64x1_t val) + /// A32: VST1.64 { Dd }, [Rn] + /// A64: ST1 { Vt.1D }, [Xn] + /// + public static unsafe void Store(double* address, Vector64 source) { throw new PlatformNotSupportedException(); } + + /// + /// void vst1_s16 (int16_t * ptr, int16x4_t val) + /// A32: VST1.16 { Dd }, [Rn] + /// A64: ST1 {Vt.4H }, [Xn] + /// + public static unsafe void Store(short* address, Vector64 source) { throw new PlatformNotSupportedException(); } + + /// + /// void vst1_s32 (int32_t * ptr, int32x2_t val) + /// A32: VST1.32 { Dd }, [Rn] + /// A64: ST1 { Vt.2S }, [Xn] + /// + public static unsafe void Store(int* address, Vector64 source) { throw new PlatformNotSupportedException(); } + + /// + /// void vst1_s64 (int64_t * ptr, int64x1_t val) + /// A32: VST1.64 { Dd }, [Rn] + /// A64: ST1 { Vt.1D }, [Xn] + /// + public static unsafe void Store(long* address, Vector64 source) { throw new PlatformNotSupportedException(); } + + /// + /// void vst1_s8 (int8_t * ptr, int8x8_t val) + /// A32: VST1.8 { Dd }, [Rn] + /// A64: ST1 { Vt.8B }, [Xn] + /// + public static unsafe void Store(sbyte* address, Vector64 source) { throw new PlatformNotSupportedException(); } + + /// + /// void vst1_f32 (float32_t * ptr, float32x2_t val) + /// A32: VST1.32 { Dd }, [Rn] + /// A64: ST1 { Vt.2S }, [Xn] + /// + public static unsafe void Store(float* address, Vector64 source) { throw new PlatformNotSupportedException(); } + + /// + /// void vst1_u16 (uint16_t * ptr, uint16x4_t val) + /// A32: VST1.16 { Dd }, [Rn] + /// A64: ST1 { Vt.4H }, [Xn] + /// + public static unsafe void Store(ushort* address, Vector64 source) { throw new PlatformNotSupportedException(); } + + /// + /// void vst1_u32 (uint32_t * ptr, uint32x2_t val) + /// A32: VST1.32 { Dd }, [Rn] + /// A64: ST1 { Vt.2S }, [Xn] + /// + public static unsafe void Store(uint* address, Vector64 source) { throw new PlatformNotSupportedException(); } + + /// + /// void vst1_u64 (uint64_t * ptr, uint64x1_t val) + /// A32: VST1.64 { Dd }, [Rn] + /// A64: ST1 { Vt.1D }, [Xn] + /// + public static unsafe void Store(ulong* address, Vector64 source) { throw new PlatformNotSupportedException(); } + + /// + /// void vst1q_u8 (uint8_t * ptr, uint8x16_t val) + /// A32: VST1.8 { Dd, Dd+1 }, [Rn] + /// A64: ST1 { Vt.16B }, [Xn] + /// + public static unsafe void Store(byte* address, Vector128 source) { throw new PlatformNotSupportedException(); } + + /// + /// void vst1q_f64 (float64_t * ptr, float64x2_t val) + /// A32: VST1.64 { Dd, Dd+1 }, [Rn] + /// A64: ST1 { Vt.2D }, [Xn] + /// + public static unsafe void Store(double* address, Vector128 source) { throw new PlatformNotSupportedException(); } + + /// + /// void vst1q_s16 (int16_t * ptr, int16x8_t val) + /// A32: VST1.16 { Dd, Dd+1 }, [Rn] + /// A64: ST1 { Vt.8H }, [Xn] + /// + public static unsafe void Store(short* address, Vector128 source) { throw new PlatformNotSupportedException(); } + + /// + /// void vst1q_s32 (int32_t * ptr, int32x4_t val) + /// A32: VST1.32 { Dd, Dd+1 }, [Rn] + /// A64: ST1 { Vt.4S }, [Xn] + /// + public static unsafe void Store(int* address, Vector128 source) { throw new PlatformNotSupportedException(); } + + /// + /// void vst1q_s64 (int64_t * ptr, int64x2_t val) + /// A32: VST1.64 { Dd, Dd+1 }, [Rn] + /// A64: ST1 { Vt.2D }, [Xn] + /// + public static unsafe void Store(long* address, Vector128 source) { throw new PlatformNotSupportedException(); } + + /// + /// void vst1q_s8 (int8_t * ptr, int8x16_t val) + /// A32: VST1.8 { Dd, Dd+1 }, [Rn] + /// A64: ST1 { Vt.16B }, [Xn] + /// + public static unsafe void Store(sbyte* address, Vector128 source) { throw new PlatformNotSupportedException(); } + + /// + /// void vst1q_f32 (float32_t * ptr, float32x4_t val) + /// A32: VST1.32 { Dd, Dd+1 }, [Rn] + /// A64: ST1 { Vt.4S }, [Xn] + /// + public static unsafe void Store(float* address, Vector128 source) { throw new PlatformNotSupportedException(); } + + /// + /// void vst1q_u16 (uint16_t * ptr, uint16x8_t val) + /// A32: VST1.16 { Dd, Dd+1 }, [Rn] + /// A64: ST1 { Vt.8H }, [Xn] + /// + public static unsafe void Store(ushort* address, Vector128 source) { throw new PlatformNotSupportedException(); } + + /// + /// void vst1q_u32 (uint32_t * ptr, uint32x4_t val) + /// A32: VST1.32 { Dd, Dd+1 }, [Rn] + /// A64: ST1 { Vt.4S }, [Xn] + /// + public static unsafe void Store(uint* address, Vector128 source) { throw new PlatformNotSupportedException(); } + + /// + /// void vst1q_u64 (uint64_t * ptr, uint64x2_t val) + /// A32: VST1.64 { Dd, Dd+1 }, [Rn] + /// A64: ST1 { Vt.2D }, [Xn] + /// + public static unsafe void Store(ulong* address, Vector128 source) { throw new PlatformNotSupportedException(); } + /// /// uint8x8_t vsub_u8 (uint8x8_t a, uint8x8_t b) /// A32: VSUB.I8 Dd, Dn, Dm diff --git a/src/System.Private.CoreLib/shared/System/Runtime/Intrinsics/Arm/AdvSimd.cs b/src/System.Private.CoreLib/shared/System/Runtime/Intrinsics/Arm/AdvSimd.cs index 112dc1e56..df013f458 100644 --- a/src/System.Private.CoreLib/shared/System/Runtime/Intrinsics/Arm/AdvSimd.cs +++ b/src/System.Private.CoreLib/shared/System/Runtime/Intrinsics/Arm/AdvSimd.cs @@ -606,6 +606,18 @@ namespace System.Runtime.Intrinsics.Arm /// public static Vector128 Divide(Vector128 left, Vector128 right) => Divide(left, right); + /// + /// float64x2_t vfmaq_f64 (float64x2_t a, float64x2_t b, float64x2_t c) + /// A64: FMLA Vd.2D, Vn.2D, Vm.2D + /// + public static Vector128 FusedMultiplyAdd(Vector128 acc, Vector128 left, Vector128 right) => FusedMultiplyAdd(acc, left, right); + + /// + /// float64x2_t vfmsq_f64 (float64x2_t a, float64x2_t b, float64x2_t c) + /// A64: FMLS Vd.2D, Vn.2D, Vm.2D + /// + public static Vector128 FusedMultiplySubtract(Vector128 acc, Vector128 left, Vector128 right) => FusedMultiplySubtract(acc, left, right); + /// /// float64x2_t vmaxq_f64 (float64x2_t a, float64x2_t b) /// A64: FMAX Vd.2D, Vn.2D, Vm.2D @@ -986,6 +998,36 @@ namespace System.Runtime.Intrinsics.Arm /// public static Vector128 Multiply(Vector128 left, Vector128 right) => Multiply(left, right); + /// + /// float32x2_t vmulx_f32 (float32x2_t a, float32x2_t b) + /// A64: FMULX Vd.2S, Vn.2S, Vm.2S + /// + public static Vector64 MultiplyExtended(Vector64 left, Vector64 right) => MultiplyExtended(left, right); + + /// + /// float64x2_t vmulxq_f64 (float64x2_t a, float64x2_t b) + /// A64: FMULX Vd.2D, Vn.2D, Vm.2D + /// + public static Vector128 MultiplyExtended(Vector128 left, Vector128 right) => MultiplyExtended(left, right); + + /// + /// float32x4_t vmulxq_f32 (float32x4_t a, float32x4_t b) + /// A64: FMULX Vd.4S, Vn.4S, Vm.4S + /// + public static Vector128 MultiplyExtended(Vector128 left, Vector128 right) => MultiplyExtended(left, right); + + /// + /// float64x1_t vmulx_f64 (float64x1_t a, float64x1_t b) + /// A64: FMULX Dd, Dn, Dm + /// + public static Vector64 MultiplyExtendedScalar(Vector64 left, Vector64 right) => MultiplyExtendedScalar(left, right); + + /// + /// float32_t vmulxs_f32 (float32_t a, float32_t b) + /// A64: FMULX Sd, Sn, Sm + /// + public static Vector64 MultiplyExtendedScalar(Vector64 left, Vector64 right) => MultiplyExtendedScalar(left, right); + /// /// float64x2_t vnegq_f64 (float64x2_t a) /// A64: FNEG Vd.2D, Vn.2D @@ -1004,6 +1046,90 @@ namespace System.Runtime.Intrinsics.Arm /// public static Vector64 NegateScalar(Vector64 value) => NegateScalar(value); + /// + /// float64x2_t vrecpeq_f64 (float64x2_t a) + /// A64: FRECPE Vd.2D, Vn.2D + /// + public static Vector128 ReciprocalEstimate(Vector128 value) => ReciprocalEstimate(value); + + /// + /// float64x1_t vrecpe_f64 (float64x1_t a) + /// A64: FRECPE Dd, Dn + /// + public static Vector64 ReciprocalEstimateScalar(Vector64 value) => ReciprocalEstimateScalar(value); + + /// + /// float32_t vrecpes_f32 (float32_t a) + /// A64: FRECPE Sd, Sn + /// + public static Vector64 ReciprocalEstimateScalar(Vector64 value) => ReciprocalEstimateScalar(value); + + /// + /// float64_t vrecpxd_f64 (float64_t a) + /// A64: FRECPX Dd, Dn + /// + public static Vector64 ReciprocalExponentScalar(Vector64 value) => ReciprocalExponentScalar(value); + + /// + /// float32_t vrecpxs_f32 (float32_t a) + /// A64: FRECPX Sd, Sn + /// + public static Vector64 ReciprocalExponentScalar(Vector64 value) => ReciprocalExponentScalar(value); + + /// + /// float64x2_t vrsqrteq_f64 (float64x2_t a) + /// A64: FRSQRTE Vd.2D, Vn.2D + /// + public static Vector128 ReciprocalSquareRootEstimate(Vector128 value) => ReciprocalSquareRootEstimate(value); + + /// + /// float64x1_t vrsqrte_f64 (float64x1_t a) + /// A64: FRSQRTE Dd, Dn + /// + public static Vector64 ReciprocalSquareRootEstimateScalar(Vector64 value) => ReciprocalSquareRootEstimateScalar(value); + + /// + /// float32_t vrsqrtes_f32 (float32_t a) + /// A64: FRSQRTE Sd, Sn + /// + public static Vector64 ReciprocalSquareRootEstimateScalar(Vector64 value) => ReciprocalSquareRootEstimateScalar(value); + + /// + /// float64x2_t vrsqrtsq_f64 (float64x2_t a, float64x2_t b) + /// A64: FRSQRTS Vd.2D, Vn.2D, Vm.2D + /// + public static Vector128 ReciprocalSquareRootStep(Vector128 left, Vector128 right) => ReciprocalSquareRootStep(left, right); + + /// + /// float64x1_t vrsqrts_f64 (float64x1_t a, float64x1_t b) + /// A64: FRSQRTS Dd, Dn, Dm + /// + public static Vector64 ReciprocalSquareRootStepScalar(Vector64 left, Vector64 right) => ReciprocalSquareRootStepScalar(left, right); + + /// + /// float32_t vrsqrtss_f32 (float32_t a, float32_t b) + /// A64: FRSQRTS Sd, Sn, Sm + /// + public static Vector64 ReciprocalSquareRootStepScalar(Vector64 left, Vector64 right) => ReciprocalSquareRootStepScalar(left, right); + + /// + /// float64x2_t vrecpsq_f64 (float64x2_t a, float64x2_t b) + /// A64: FRECPS Vd.2D, Vn.2D, Vm.2D + /// + public static Vector128 ReciprocalStep(Vector128 left, Vector128 right) => ReciprocalStep(left, right); + + /// + /// float64x1_t vrecps_f64 (float64x1_t a, float64x1_t b) + /// A64: FRECPS Dd, Dn, Dm + /// + public static Vector64 ReciprocalStepScalar(Vector64 left, Vector64 right) => ReciprocalStepScalar(left, right); + + /// + /// float32_t vrecpss_f32 (float32_t a, float32_t b) + /// A64: FRECPS Sd, Sn, Sm + /// + public static Vector64 ReciprocalStepScalar(Vector64 left, Vector64 right) => ReciprocalStepScalar(left, right); + /// /// float32x2_t vsqrt_f32 (float32x2_t a) /// A64: FSQRT Vd.2S, Vn.2S @@ -1022,18 +1148,6 @@ namespace System.Runtime.Intrinsics.Arm /// public static Vector128 Sqrt(Vector128 value) => Sqrt(value); - /// - /// float64x2_t vfmaq_f64 (float64x2_t a, float64x2_t b, float64x2_t c) - /// A64: FMLA Vd.2D, Vn.2D, Vm.2D - /// - public static Vector128 FusedMultiplyAdd(Vector128 acc, Vector128 left, Vector128 right) => FusedMultiplyAdd(acc, left, right); - - /// - /// float64x2_t vfmsq_f64 (float64x2_t a, float64x2_t b, float64x2_t c) - /// A64: FMLS Vd.2D, Vn.2D, Vm.2D - /// - public static Vector128 FusedMultiplySubtract(Vector128 acc, Vector128 left, Vector128 right) => FusedMultiplySubtract(acc, left, right); - /// /// float64x2_t vsubq_f64 (float64x2_t a, float64x2_t b) /// A64: FSUB Vd.2D, Vn.2D, Vm.2D @@ -1902,6 +2016,90 @@ namespace System.Runtime.Intrinsics.Arm /// public static Vector128 AbsoluteDifference(Vector128 left, Vector128 right) => AbsoluteDifference(left, right); + /// + /// uint8x8_t vaba_u8 (uint8x8_t a, uint8x8_t b, uint8x8_t c) + /// A32: VABA.U8 Dd, Dn, Dm + /// A64: UABA Vd.8B, Vn.8B, Vm.8B + /// + public static Vector64 AbsoluteDifferenceAdd(Vector64 addend, Vector64 left, Vector64 right) => AbsoluteDifferenceAdd(addend, left, right); + + /// + /// int16x4_t vaba_s16 (int16x4_t a, int16x4_t b, int16x4_t c) + /// A32: VABA.S16 Dd, Dn, Dm + /// A64: SABA Vd.4H, Vn.4H, Vm.4H + /// + public static Vector64 AbsoluteDifferenceAdd(Vector64 addend, Vector64 left, Vector64 right) => AbsoluteDifferenceAdd(addend, left, right); + + /// + /// int32x2_t vaba_s32 (int32x2_t a, int32x2_t b, int32x2_t c) + /// A32: VABA.S32 Dd, Dn, Dm + /// A64: SABA Vd.2S, Vn.2S, Vm.2S + /// + public static Vector64 AbsoluteDifferenceAdd(Vector64 addend, Vector64 left, Vector64 right) => AbsoluteDifferenceAdd(addend, left, right); + + /// + /// int8x8_t vaba_s8 (int8x8_t a, int8x8_t b, int8x8_t c) + /// A32: VABA.S8 Dd, Dn, Dm + /// A64: SABA Vd.8B, Vn.8B, Vm.8B + /// + public static Vector64 AbsoluteDifferenceAdd(Vector64 addend, Vector64 left, Vector64 right) => AbsoluteDifferenceAdd(addend, left, right); + + /// + /// uint16x4_t vaba_u16 (uint16x4_t a, uint16x4_t b, uint16x4_t c) + /// A32: VABA.U16 Dd, Dn, Dm + /// A64: UABA Vd.4H, Vn.4H, Vm.4H + /// + public static Vector64 AbsoluteDifferenceAdd(Vector64 addend, Vector64 left, Vector64 right) => AbsoluteDifferenceAdd(addend, left, right); + + /// + /// uint32x2_t vaba_u32 (uint32x2_t a, uint32x2_t b, uint32x2_t c) + /// A32: VABA.U32 Dd, Dn, Dm + /// A64: UABA Vd.2S, Vn.2S, Vm.2S + /// + public static Vector64 AbsoluteDifferenceAdd(Vector64 addend, Vector64 left, Vector64 right) => AbsoluteDifferenceAdd(addend, left, right); + + /// + /// uint8x16_t vabaq_u8 (uint8x16_t a, uint8x16_t b, uint8x16_t c) + /// A32: VABA.U8 Qd, Qn, Qm + /// A64: UABA Vd.16B, Vn.16B, Vm.16B + /// + public static Vector128 AbsoluteDifferenceAdd(Vector128 addend, Vector128 left, Vector128 right) => AbsoluteDifferenceAdd(addend, left, right); + + /// + /// int16x8_t vabaq_s16 (int16x8_t a, int16x8_t b, int16x8_t c) + /// A32: VABA.S16 Qd, Qn, Qm + /// A64: SABA Vd.8H, Vn.8H, Vm.8H + /// + public static Vector128 AbsoluteDifferenceAdd(Vector128 addend, Vector128 left, Vector128 right) => AbsoluteDifferenceAdd(addend, left, right); + + /// + /// int32x4_t vabaq_s32 (int32x4_t a, int32x4_t b, int32x4_t c) + /// A32: VABA.S32 Qd, Qn, Qm + /// A64: SABA Vd.4S, Vn.4S, Vm.4S + /// + public static Vector128 AbsoluteDifferenceAdd(Vector128 addend, Vector128 left, Vector128 right) => AbsoluteDifferenceAdd(addend, left, right); + + /// + /// int8x16_t vabaq_s8 (int8x16_t a, int8x16_t b, int8x16_t c) + /// A32: VABA.S8 Qd, Qn, Qm + /// A64: SABA Vd.16B, Vn.16B, Vm.16B + /// + public static Vector128 AbsoluteDifferenceAdd(Vector128 addend, Vector128 left, Vector128 right) => AbsoluteDifferenceAdd(addend, left, right); + + /// + /// uint16x8_t vabaq_u16 (uint16x8_t a, uint16x8_t b, uint16x8_t c) + /// A32: VABA.U16 Qd, Qn, Qm + /// A64: UABA Vd.8H, Vn.8H, Vm.8H + /// + public static Vector128 AbsoluteDifferenceAdd(Vector128 addend, Vector128 left, Vector128 right) => AbsoluteDifferenceAdd(addend, left, right); + + /// + /// uint32x4_t vabaq_u32 (uint32x4_t a, uint32x4_t b, uint32x4_t c) + /// A32: VABA.U32 Qd, Qn, Qm + /// A64: UABA Vd.4S, Vn.4S, Vm.4S + /// + public static Vector128 AbsoluteDifferenceAdd(Vector128 addend, Vector128 left, Vector128 right) => AbsoluteDifferenceAdd(addend, left, right); + /// /// uint8x8_t vadd_u8 (uint8x8_t a, uint8x8_t b) /// A32: VADD.I8 Dd, Dn, Dm @@ -3125,6 +3323,328 @@ namespace System.Runtime.Intrinsics.Arm /// public static Vector64 DivideScalar(Vector64 left, Vector64 right) => DivideScalar(left, right); + /// + /// uint8_t vget_lane_u8 (uint8x8_t v, const int lane) + /// A32: VMOV.U8 Rt, Dn[lane] + /// A64: UMOV Wd, Vn.B[lane] + /// + public static byte Extract(Vector64 vector, byte index) => Extract(vector, index); + + /// + /// int16_t vget_lane_s16 (int16x4_t v, const int lane) + /// A32: VMOV.S16 Rt, Dn[lane] + /// A64: SMOV Wd, Vn.H[lane] + /// + public static short Extract(Vector64 vector, byte index) => Extract(vector, index); + + /// + /// int32_t vget_lane_s32 (int32x2_t v, const int lane) + /// A32: VMOV.32 Rt, Dn[lane] + /// A64: SMOV Wd, Vn.S[lane] + /// + public static int Extract(Vector64 vector, byte index) => Extract(vector, index); + + /// + /// int8_t vget_lane_s8 (int8x8_t v, const int lane) + /// A32: VMOV.S8 Rt, Dn[lane] + /// A64: SMOV Wd, Vn.B[lane] + /// + public static sbyte Extract(Vector64 vector, byte index) => Extract(vector, index); + + /// + /// float32_t vget_lane_f32 (float32x2_t v, const int lane) + /// A32: VMOV.F32 Sd, Sm + /// A64: DUP Sd, Vn.S[lane] + /// + public static float Extract(Vector64 vector, byte index) => Extract(vector, index); + + /// + /// uint16_t vget_lane_u16 (uint16x4_t v, const int lane) + /// A32: VMOV.U16 Rt, Dn[lane] + /// A64: UMOV Wd, Vn.H[lane] + /// + public static ushort Extract(Vector64 vector, byte index) => Extract(vector, index); + + /// + /// uint32_t vget_lane_u32 (uint32x2_t v, const int lane) + /// A32: VMOV.32 Rt, Dn[lane] + /// A64: UMOV Wd, Vn.S[lane] + /// + public static uint Extract(Vector64 vector, byte index) => Extract(vector, index); + + /// + /// uint8_t vgetq_lane_u8 (uint8x16_t v, const int lane) + /// A32: VMOV.U8 Rt, Dn[lane] + /// A64: UMOV Wd, Vn.B[lane] + /// + public static byte Extract(Vector128 vector, byte index) => Extract(vector, index); + + /// + /// float64_t vgetq_lane_f64 (float64x2_t v, const int lane) + /// A32: VMOV.F64 Dd, Dm + /// A64: DUP Dd, Vn.D[lane] + /// + public static double Extract(Vector128 vector, byte index) => Extract(vector, index); + + /// + /// int16_t vgetq_lane_s16 (int16x8_t v, const int lane) + /// A32: VMOV.S16 Rt, Dn[lane] + /// A64: SMOV Wd, Vn.H[lane] + /// + public static short Extract(Vector128 vector, byte index) => Extract(vector, index); + + /// + /// int32_t vgetq_lane_s32 (int32x4_t v, const int lane) + /// A32: VMOV.32 Rt, Dn[lane] + /// A64: SMOV Wd, Vn.S[lane] + /// + public static int Extract(Vector128 vector, byte index) => Extract(vector, index); + + /// + /// int64_t vgetq_lane_s64 (int64x2_t v, const int lane) + /// A32: VMOV Rt, Rt2, Dm + /// A64: UMOV Xd, Vn.D[lane] + /// + public static long Extract(Vector128 vector, byte index) => Extract(vector, index); + + /// + /// int8_t vgetq_lane_s8 (int8x16_t v, const int lane) + /// A32: VMOV.S8 Rt, Dn[lane] + /// A64: SMOV Wd, Vn.B[lane] + /// + public static sbyte Extract(Vector128 vector, byte index) => Extract(vector, index); + + /// + /// float32_t vgetq_lane_f32 (float32x4_t v, const int lane) + /// A32: VMOV.F32 Sd, Sm + /// A64: DUP Sd, Vn.S[lane] + /// + public static float Extract(Vector128 vector, byte index) => Extract(vector, index); + + /// + /// uint16_t vgetq_lane_u16 (uint16x8_t v, const int lane) + /// A32: VMOV.U16 Rt, Dn[lane] + /// A64: UMOV Wd, Vn.H[lane] + /// + public static ushort Extract(Vector128 vector, byte index) => Extract(vector, index); + + /// + /// uint32_t vgetq_lane_u32 (uint32x4_t v, const int lane) + /// A32: VMOV.32 Rt, Dn[lane] + /// A64: UMOV Wd, Vn.S[lane] + /// + public static uint Extract(Vector128 vector, byte index) => Extract(vector, index); + + /// + /// uint64_t vgetq_lane_u64 (uint64x2_t v, const int lane) + /// A32: VMOV Rt, Rt2, Dm + /// A64: UMOV Xd, Vn.D[lane] + /// + public static ulong Extract(Vector128 vector, byte index) => Extract(vector, index); + + /// + /// int8x16_t vmovn_high_s16 (int8x8_t r, int16x8_t a) + /// A32: VMOVN.I16 Dd+1, Qm + /// A64: XTN2 Vd.16B, Vn.8H + /// + public static Vector128 ExtractAndNarrowHigh (Vector64 lower, Vector128 value) => ExtractAndNarrowHigh (lower, value); + + /// + /// int16x8_t vmovn_high_s32 (int16x4_t r, int32x4_t a) + /// A32: VMOVN.I32 Dd+1, Qm + /// A64: XTN2 Vd.8H, Vn.4S + /// + public static Vector128 ExtractAndNarrowHigh (Vector64 lower, Vector128 value) => ExtractAndNarrowHigh (lower, value); + + /// + /// int32x4_t vmovn_high_s64 (int32x2_t r, int64x2_t a) + /// A32: VMOVN.I64 Dd+1, Qm + /// A64: XTN2 Vd.4S, Vn.2D + /// + public static Vector128 ExtractAndNarrowHigh (Vector64 lower, Vector128 value) => ExtractAndNarrowHigh (lower, value); + + /// + /// uint8x16_t vmovn_high_u16 (uint8x8_t r, uint16x8_t a) + /// A32: VMOVN.I16 Dd+1, Qm + /// A64: XTN2 Vd.16B, Vn.8H + /// + public static Vector128 ExtractAndNarrowHigh (Vector64 lower, Vector128 value) => ExtractAndNarrowHigh (lower, value); + + /// + /// uint16x8_t vmovn_high_u32 (uint16x4_t r, uint32x4_t a) + /// A32: VMOVN.I32 Dd+1, Qm + /// A64: XTN2 Vd.8H, Vn.4S + /// + public static Vector128 ExtractAndNarrowHigh (Vector64 lower, Vector128 value) => ExtractAndNarrowHigh (lower, value); + + /// + /// uint32x4_t vmovn_high_u64 (uint32x2_t r, uint64x2_t a) + /// A32: VMOVN.I64 Dd+1, Qm + /// A64: XTN2 Vd.4S, Vn.2D + /// + public static Vector128 ExtractAndNarrowHigh (Vector64 lower, Vector128 value) => ExtractAndNarrowHigh (lower, value); + + /// + /// int8x8_t vmovn_s16 (int16x8_t a) + /// A32: VMOVN.I16 Dd, Qm + /// A64: XTN Vd.8B, Vn.8H + /// + public static Vector64 ExtractAndNarrowLow (Vector128 value) => ExtractAndNarrowLow (value); + + /// + /// int16x4_t vmovn_s32 (int32x4_t a) + /// A32: VMOVN.I32 Dd, Qm + /// A64: XTN Vd.4H, Vn.4S + /// + public static Vector64 ExtractAndNarrowLow (Vector128 value) => ExtractAndNarrowLow (value); + + /// + /// int32x2_t vmovn_s64 (int64x2_t a) + /// A32: VMOVN.I64 Dd, Qm + /// A64: XTN Vd.2S, Vn.2D + /// + public static Vector64 ExtractAndNarrowLow (Vector128 value) => ExtractAndNarrowLow (value); + + /// + /// uint8x8_t vmovn_u16 (uint16x8_t a) + /// A32: VMOVN.I16 Dd, Qm + /// A64: XTN Vd.8B, Vn.8H + /// + public static Vector64 ExtractAndNarrowLow (Vector128 value) => ExtractAndNarrowLow (value); + + /// + /// uint16x4_t vmovn_u32 (uint32x4_t a) + /// A32: VMOVN.I32 Dd, Qm + /// A64: XTN Vd.4H, Vn.4S + /// + public static Vector64 ExtractAndNarrowLow (Vector128 value) => ExtractAndNarrowLow (value); + + /// + /// uint32x2_t vmovn_u64 (uint64x2_t a) + /// A32: VMOVN.I64 Dd, Qm + /// A64: XTN Vd.2S, Vn.2D + /// + public static Vector64 ExtractAndNarrowLow (Vector128 value) => ExtractAndNarrowLow (value); + + /// + /// uint8x8_t vext_s8 (uint8x8_t a, uint8x8_t b, const int n) + /// A32: VEXT.8 Dd, Dn, Dm, #n + /// A64: EXT Vd.8B, Vn.8B, Vm.8B, #n + /// + public static Vector64 ExtractVector64(Vector64 upper, Vector64 lower, byte index) => ExtractVector64(upper, lower, index); + + /// + /// int16x4_t vext_s16 (int16x4_t a, int16x4_t b, const int n) + /// A32: VEXT.8 Dd, Dn, Dm, #(n*2) + /// A64: EXT Vd.8B, Vn.8B, Vm.8B, #(n*2) + /// + public static Vector64 ExtractVector64(Vector64 upper, Vector64 lower, byte index) => ExtractVector64(upper, lower, index); + + /// + /// int32x2_t vext_s32 (int32x2_t a, int32x2_t b, const int n) + /// A32: VEXT.8 Dd, Dn, Dm, #(n*4) + /// A64: EXT Vd.8B, Vn.8B, Vm.8B, #(n*4) + /// + public static Vector64 ExtractVector64(Vector64 upper, Vector64 lower, byte index) => ExtractVector64(upper, lower, index); + + /// + /// int8x8_t vext_s8 (int8x8_t a, int8x8_t b, const int n) + /// A32: VEXT.8 Dd, Dn, Dm, #n + /// A64: EXT Vd.8B, Vn.8B, Vm.8B, #n + /// + public static Vector64 ExtractVector64(Vector64 upper, Vector64 lower, byte index) => ExtractVector64(upper, lower, index); + + /// + /// float32x2_t vext_f32 (float32x2_t a, float32x2_t b, const int n) + /// A32: VEXT.8 Dd, Dn, Dm, #(n*4) + /// A64: EXT Vd.8B, Vn.8B, Vm.8B, #(n*4) + /// + public static Vector64 ExtractVector64(Vector64 upper, Vector64 lower, byte index) => ExtractVector64(upper, lower, index); + + /// + /// uint16x4_t vext_s16 (uint16x4_t a, uint16x4_t b, const int n) + /// A32: VEXT.8 Dd, Dn, Dm, #(n*2) + /// A64: EXT Vd.8B, Vn.8B, Vm.8B, #(n*2) + /// + public static Vector64 ExtractVector64(Vector64 upper, Vector64 lower, byte index) => ExtractVector64(upper, lower, index); + + /// + /// uint32x2_t vext_s32 (uint32x2_t a, uint32x2_t b, const int n) + /// A32: VEXT.8 Dd, Dn, Dm, #(n*4) + /// A64: EXT Vd.8B, Vn.8B, Vm.8B, #(n*4) + /// + public static Vector64 ExtractVector64(Vector64 upper, Vector64 lower, byte index) => ExtractVector64(upper, lower, index); + + /// + /// uint8x16_t vextq_s8 (uint8x16_t a, uint8x16_t b, const int n) + /// A32: VEXT.8 Qd, Qn, Qm, #n + /// A64: EXT Vd.16B, Vn.16B, Vm.16B, #n + /// + public static Vector128 ExtractVector128(Vector128 upper, Vector128 lower, byte index) => ExtractVector128(upper, lower, index); + + /// + /// float64x2_t vextq_f64 (float64x2_t a, float64x2_t b, const int n) + /// A32: VEXT.8 Qd, Qn, Qm, #(n*8) + /// A64: EXT Vd.16B, Vn.16B, Vm.16B, #(n*8) + /// + public static Vector128 ExtractVector128(Vector128 upper, Vector128 lower, byte index) => ExtractVector128(upper, lower, index); + + /// + /// int16x8_t vextq_s16 (int16x8_t a, int16x8_t b, const int n) + /// A32: VEXT.8 Qd, Qn, Qm, #(n*2) + /// A64: EXT Vd.16B, Vn.16B, Vm.16B, #(n*2) + /// + public static Vector128 ExtractVector128(Vector128 upper, Vector128 lower, byte index) => ExtractVector128(upper, lower, index); + + /// + /// int32x4_t vextq_s32 (int32x4_t a, int32x4_t b, const int n) + /// A32: VEXT.8 Qd, Qn, Qm, #(n*4) + /// A64: EXT Vd.16B, Vn.16B, Vm.16B, #(n*4) + /// + public static Vector128 ExtractVector128(Vector128 upper, Vector128 lower, byte index) => ExtractVector128(upper, lower, index); + + /// + /// int64x2_t vextq_s64 (int64x2_t a, int64x2_t b, const int n) + /// A32: VEXT.8 Qd, Qn, Qm, #(n*8) + /// A64: EXT Vd.16B, Vn.16B, Vm.16B, #(n*8) + /// + public static Vector128 ExtractVector128(Vector128 upper, Vector128 lower, byte index) => ExtractVector128(upper, lower, index); + + /// + /// int8x16_t vextq_s8 (int8x16_t a, int8x16_t b, const int n) + /// A32: VEXT.8 Qd, Qn, Qm, #n + /// A64: EXT Vd.16B, Vn.16B, Vm.16B, #n + /// + public static Vector128 ExtractVector128(Vector128 upper, Vector128 lower, byte index) => ExtractVector128(upper, lower, index); + + /// + /// float32x4_t vextq_f32 (float32x4_t a, float32x4_t b, const int n) + /// A32: VEXT.8 Qd, Qn, Qm, #(n*4) + /// A64: EXT Vd.16B, Vn.16B, Vm.16B, #(n*4) + /// + public static Vector128 ExtractVector128(Vector128 upper, Vector128 lower, byte index) => ExtractVector128(upper, lower, index); + + /// + /// uint16x8_t vextq_s16 (uint16x8_t a, uint16x8_t b, const int n) + /// A32: VEXT.8 Qd, Qn, Qm, #(n*2) + /// A64: EXT Vd.16B, Vn.16B, Vm.16B, #(n*2) + /// + public static Vector128 ExtractVector128(Vector128 upper, Vector128 lower, byte index) => ExtractVector128(upper, lower, index); + + /// + /// uint32x4_t vextq_s32 (uint32x4_t a, uint32x4_t b, const int n) + /// A32: VEXT.8 Qd, Qn, Qm, #(n*4) + /// A64: EXT Vd.16B, Vn.16B, Vm.16B, #(n*4) + /// + public static Vector128 ExtractVector128(Vector128 upper, Vector128 lower, byte index) => ExtractVector128(upper, lower, index); + + /// + /// uint64x2_t vextq_s64 (uint64x2_t a, uint64x2_t b, const int n) + /// A32: VEXT.8 Qd, Qn, Qm, #(n*8) + /// A64: EXT Vd.16B, Vn.16B, Vm.16B, #(n*8) + /// + public static Vector128 ExtractVector128(Vector128 upper, Vector128 lower, byte index) => ExtractVector128(upper, lower, index); + /// /// float32x2_t vfma_f32 (float32x2_t a, float32x2_t b, float32x2_t c) /// A32: VFMA.F32 Dd, Dn, Dm @@ -3215,6 +3735,125 @@ namespace System.Runtime.Intrinsics.Arm /// public static Vector64 FusedMultiplySubtractNegatedScalar(Vector64 acc, Vector64 left, Vector64 right) => FusedMultiplySubtractNegatedScalar(acc, left, right); + /// + /// uint8x8_t vset_lane_u8 (uint8_t a, uint8x8_t v, const int lane) + /// A32: VMOV.8 Dd[lane], Rt + /// A64: INS Vd.B[lane], Wn + /// + public static Vector64 Insert(Vector64 vector, byte index, byte data) => Insert(vector, index, data); + + /// + /// int16x4_t vset_lane_s16 (int16_t a, int16x4_t v, const int lane) + /// A32: VMOV.16 Dd[lane], Rt + /// A64: INS Vd.H[lane], Wn + /// + public static Vector64 Insert(Vector64 vector, byte index, short data) => Insert(vector, index, data); + + /// + /// int32x2_t vset_lane_s32 (int32_t a, int32x2_t v, const int lane) + /// A32: VMOV.32 Dd[lane], Rt + /// A64: INS Vd.S[lane], Wn + /// + public static Vector64 Insert(Vector64 vector, byte index, int data) => Insert(vector, index, data); + + /// + /// int8x8_t vset_lane_s8 (int8_t a, int8x8_t v, const int lane) + /// A32: VMOV.8 Dd[lane], Rt + /// A64: INS Vd.B[lane], Wn + /// + public static Vector64 Insert(Vector64 vector, byte index, sbyte data) => Insert(vector, index, data); + + /// + /// float32x2_t vset_lane_f32 (float32_t a, float32x2_t v, const int lane) + /// A32: VMOV.F32 Sd, Sm + /// A64: INS Vd.S[lane], Vn.S[0] + /// + public static Vector64 Insert(Vector64 vector, byte index, float data) => Insert(vector, index, data); + + /// + /// uint16x4_t vset_lane_u16 (uint16_t a, uint16x4_t v, const int lane) + /// A32: VMOV.16 Dd[lane], Rt + /// A64: INS Vd.H[lane], Wn + /// + public static Vector64 Insert(Vector64 vector, byte index, ushort data) => Insert(vector, index, data); + + /// + /// uint32x2_t vset_lane_u32 (uint32_t a, uint32x2_t v, const int lane) + /// A32: VMOV.32 Dd[lane], Rt + /// A64: INS Vd.S[lane], Wn + /// + public static Vector64 Insert(Vector64 vector, byte index, uint data) => Insert(vector, index, data); + + /// + /// uint8x16_t vsetq_lane_u8 (uint8_t a, uint8x16_t v, const int lane) + /// A32: VMOV.8 Dd[lane], Rt + /// A64: INS Vd.B[lane], Wn + /// + public static Vector128 Insert(Vector128 vector, byte index, byte data) => Insert(vector, index, data); + + /// + /// float64x2_t vsetq_lane_f64 (float64_t a, float64x2_t v, const int lane) + /// A32: VMOV.F64 Dd, Dm + /// A64: INS Vd.D[lane], Vn.D[0] + /// + public static Vector128 Insert(Vector128 vector, byte index, double data) => Insert(vector, index, data); + + /// + /// int16x8_t vsetq_lane_s16 (int16_t a, int16x8_t v, const int lane) + /// A32: VMOV.16 Dd[lane], Rt + /// A64: INS Vd.H[lane], Wn + /// + public static Vector128 Insert(Vector128 vector, byte index, short data) => Insert(vector, index, data); + + /// + /// int32x4_t vsetq_lane_s32 (int32_t a, int32x4_t v, const int lane) + /// A32: VMOV.32 Dd[lane], Rt + /// A64: INS Vd.S[lane], Wn + /// + public static Vector128 Insert(Vector128 vector, byte index, int data) => Insert(vector, index, data); + + /// + /// int64x2_t vsetq_lane_s64 (int64_t a, int64x2_t v, const int lane) + /// A32: VMOV.64 Dd, Rt, Rt2 + /// A64: INS Vd.D[lane], Xn + /// + public static Vector128 Insert(Vector128 vector, byte index, long data) => Insert(vector, index, data); + + /// + /// int8x16_t vsetq_lane_s8 (int8_t a, int8x16_t v, const int lane) + /// A32: VMOV.8 Dd[lane], Rt + /// A64: INS Vd.B[lane], Wn + /// + public static Vector128 Insert(Vector128 vector, byte index, sbyte data) => Insert(vector, index, data); + + /// + /// float32x4_t vsetq_lane_f32 (float32_t a, float32x4_t v, const int lane) + /// A32: VMOV.F32 Sd, Sm + /// A64: INS Vd.S[lane], Vn.S[0] + /// + public static Vector128 Insert(Vector128 vector, byte index, float data) => Insert(vector, index, data); + + /// + /// uint16x8_t vsetq_lane_u16 (uint16_t a, uint16x8_t v, const int lane) + /// A32: VMOV.16 Dd[lane], Rt + /// A64: INS Vd.H[lane], Wn + /// + public static Vector128 Insert(Vector128 vector, byte index, ushort data) => Insert(vector, index, data); + + /// + /// uint32x4_t vsetq_lane_u32 (uint32_t a, uint32x4_t v, const int lane) + /// A32: VMOV.32 Dd[lane], Rt + /// A64: INS Vd.S[lane], Wn + /// + public static Vector128 Insert(Vector128 vector, byte index, uint data) => Insert(vector, index, data); + + /// + /// uint64x2_t vsetq_lane_u64 (uint64_t a, uint64x2_t v, const int lane) + /// A32: VMOV.64 Dd, Rt, Rt2 + /// A64: INS Vd.D[lane], Xn + /// + public static Vector128 Insert(Vector128 vector, byte index, ulong data) => Insert(vector, index, data); + /// /// int16x4_t vcls_s16 (int16x4_t a) /// A32: VCLS.S16 Dd, Dm @@ -4615,6 +5254,34 @@ namespace System.Runtime.Intrinsics.Arm /// public static Vector128 OrNot(Vector128 left, Vector128 right) => OrNot(left, right); + /// + /// poly8x8_t vmul_p8 (poly8x8_t a, poly8x8_t b) + /// A32: VMUL.P8 Dd, Dn, Dm + /// A64: PMUL Vd.8B, Vn.8B, Vm.8B + /// + public static Vector64 PolynomialMultiply(Vector64 left, Vector64 right) => PolynomialMultiply(left, right); + + /// + /// poly8x8_t vmul_p8 (poly8x8_t a, poly8x8_t b) + /// A32: VMUL.P8 Dd, Dn, Dm + /// A64: PMUL Vd.8B, Vn.8B, Vm.8B + /// + public static Vector64 PolynomialMultiply(Vector64 left, Vector64 right) => PolynomialMultiply(left, right); + + /// + /// poly8x16_t vmulq_p8 (poly8x16_t a, poly8x16_t b) + /// A32: VMUL.P8 Qd, Qn, Qm + /// A64: PMUL Vd.16B, Vn.16B, Vm.16B + /// + public static Vector128 PolynomialMultiply(Vector128 left, Vector128 right) => PolynomialMultiply(left, right); + + /// + /// poly8x16_t vmulq_p8 (poly8x16_t a, poly8x16_t b) + /// A32: VMUL.P8 Qd, Qn, Qm + /// A64: PMUL Vd.16B, Vn.16B, Vm.16B + /// + public static Vector128 PolynomialMultiply(Vector128 left, Vector128 right) => PolynomialMultiply(left, right); + /// /// uint8x8_t vcnt_u8 (uint8x8_t a) /// A32: VCNT.I8 Dd, Dm @@ -4643,6 +5310,90 @@ namespace System.Runtime.Intrinsics.Arm /// public static Vector128 PopCount(Vector128 value) => PopCount(value); + /// + /// float32x2_t vrecpe_f32 (float32x2_t a) + /// A32: VRECPE.F32 Dd, Dm + /// A64: FRECPE Vd.2S, Vn.2S + /// + public static Vector64 ReciprocalEstimate(Vector64 value) => ReciprocalEstimate(value); + + /// + /// uint32x2_t vrecpe_u32 (uint32x2_t a) + /// A32: VRECPE.U32 Dd, Dm + /// A64: URECPE Vd.2S, Vn.2S + /// + public static Vector64 ReciprocalEstimate(Vector64 value) => ReciprocalEstimate(value); + + /// + /// float32x4_t vrecpeq_f32 (float32x4_t a) + /// A32: VRECPE.F32 Qd, Qm + /// A64: FRECPE Vd.4S, Vn.4S + /// + public static Vector128 ReciprocalEstimate(Vector128 value) => ReciprocalEstimate(value); + + /// + /// uint32x4_t vrecpeq_u32 (uint32x4_t a) + /// A32: VRECPE.U32 Qd, Qm + /// A64: URECPE Vd.4S, Vn.4S + /// + public static Vector128 ReciprocalEstimate(Vector128 value) => ReciprocalEstimate(value); + + /// + /// float32x2_t vrsqrte_f32 (float32x2_t a) + /// A32: VRSQRTE.F32 Dd, Dm + /// A64: FRSQRTE Vd.2S, Vn.2S + /// + public static Vector64 ReciprocalSquareRootEstimate(Vector64 value) => ReciprocalSquareRootEstimate(value); + + /// + /// uint32x2_t vrsqrte_u32 (uint32x2_t a) + /// A32: VRSQRTE.U32 Dd, Dm + /// A64: URSQRTE Vd.2S, Vn.2S + /// + public static Vector64 ReciprocalSquareRootEstimate(Vector64 value) => ReciprocalSquareRootEstimate(value); + + /// + /// float32x4_t vrsqrteq_f32 (float32x4_t a) + /// A32: VRSQRTE.F32 Qd, Qm + /// A64: FRSQRTE Vd.4S, Vn.4S + /// + public static Vector128 ReciprocalSquareRootEstimate(Vector128 value) => ReciprocalSquareRootEstimate(value); + + /// + /// uint32x4_t vrsqrteq_u32 (uint32x4_t a) + /// A32: VRSQRTE.U32 Qd, Qm + /// A64: URSQRTE Vd.4S, Vn.4S + /// + public static Vector128 ReciprocalSquareRootEstimate(Vector128 value) => ReciprocalSquareRootEstimate(value); + + /// + /// float32x2_t vrsqrts_f32 (float32x2_t a, float32x2_t b) + /// A32: VRSQRTS.F32 Dd, Dn, Dm + /// A64: FRSQRTS Vd.2S, Vn.2S, Vm.2S + /// + public static Vector64 ReciprocalSquareRootStep(Vector64 left, Vector64 right) => ReciprocalSquareRootStep(left, right); + + /// + /// float32x4_t vrsqrtsq_f32 (float32x4_t a, float32x4_t b) + /// A32: VRSQRTS.F32 Qd, Qn, Qm + /// A64: FRSQRTS Vd.4S, Vn.4S, Vm.4S + /// + public static Vector128 ReciprocalSquareRootStep(Vector128 left, Vector128 right) => ReciprocalSquareRootStep(left, right); + + /// + /// float32x2_t vrecps_f32 (float32x2_t a, float32x2_t b) + /// A32: VRECPS.F32 Dd, Dn, Dm + /// A64: FRECPS Vd.2S, Vn.2S, Vm.2S + /// + public static Vector64 ReciprocalStep(Vector64 left, Vector64 right) => ReciprocalStep(left, right); + + /// + /// float32x4_t vrecpsq_f32 (float32x4_t a, float32x4_t b) + /// A32: VRECPS.F32 Qd, Qn, Qm + /// A64: FRECPS Vd.4S, Vn.4S, Vm.4S + /// + public static Vector128 ReciprocalStep(Vector128 left, Vector128 right) => ReciprocalStep(left, right); + /// /// float64x1_t vsqrt_f64 (float64x1_t a) /// A32: VSQRT.F64 Dd, Dm @@ -4658,6 +5409,146 @@ namespace System.Runtime.Intrinsics.Arm /// public static Vector64 SqrtScalar(Vector64 value) => SqrtScalar(value); + /// + /// void vst1_u8 (uint8_t * ptr, uint8x8_t val) + /// A32: VST1.8 { Dd }, [Rn] + /// A64: ST1 { Vt.8B }, [Xn] + /// + public static unsafe void Store(byte* address, Vector64 source) => Store(address, source); + + /// + /// void vst1_f64 (float64_t * ptr, float64x1_t val) + /// A32: VST1.64 { Dd }, [Rn] + /// A64: ST1 { Vt.1D }, [Xn] + /// + public static unsafe void Store(double* address, Vector64 source) => Store(address, source); + + /// + /// void vst1_s16 (int16_t * ptr, int16x4_t val) + /// A32: VST1.16 { Dd }, [Rn] + /// A64: ST1 {Vt.4H }, [Xn] + /// + public static unsafe void Store(short* address, Vector64 source) => Store(address, source); + + /// + /// void vst1_s32 (int32_t * ptr, int32x2_t val) + /// A32: VST1.32 { Dd }, [Rn] + /// A64: ST1 { Vt.2S }, [Xn] + /// + public static unsafe void Store(int* address, Vector64 source) => Store(address, source); + + /// + /// void vst1_s64 (int64_t * ptr, int64x1_t val) + /// A32: VST1.64 { Dd }, [Rn] + /// A64: ST1 { Vt.1D }, [Xn] + /// + public static unsafe void Store(long* address, Vector64 source) => Store(address, source); + + /// + /// void vst1_s8 (int8_t * ptr, int8x8_t val) + /// A32: VST1.8 { Dd }, [Rn] + /// A64: ST1 { Vt.8B }, [Xn] + /// + public static unsafe void Store(sbyte* address, Vector64 source) => Store(address, source); + + /// + /// void vst1_f32 (float32_t * ptr, float32x2_t val) + /// A32: VST1.32 { Dd }, [Rn] + /// A64: ST1 { Vt.2S }, [Xn] + /// + public static unsafe void Store(float* address, Vector64 source) => Store(address, source); + + /// + /// void vst1_u16 (uint16_t * ptr, uint16x4_t val) + /// A32: VST1.16 { Dd }, [Rn] + /// A64: ST1 { Vt.4H }, [Xn] + /// + public static unsafe void Store(ushort* address, Vector64 source) => Store(address, source); + + /// + /// void vst1_u32 (uint32_t * ptr, uint32x2_t val) + /// A32: VST1.32 { Dd }, [Rn] + /// A64: ST1 { Vt.2S }, [Xn] + /// + public static unsafe void Store(uint* address, Vector64 source) => Store(address, source); + + /// + /// void vst1_u64 (uint64_t * ptr, uint64x1_t val) + /// A32: VST1.64 { Dd }, [Rn] + /// A64: ST1 { Vt.1D }, [Xn] + /// + public static unsafe void Store(ulong* address, Vector64 source) => Store(address, source); + + /// + /// void vst1q_u8 (uint8_t * ptr, uint8x16_t val) + /// A32: VST1.8 { Dd, Dd+1 }, [Rn] + /// A64: ST1 { Vt.16B }, [Xn] + /// + public static unsafe void Store(byte* address, Vector128 source) => Store(address, source); + + /// + /// void vst1q_f64 (float64_t * ptr, float64x2_t val) + /// A32: VST1.64 { Dd, Dd+1 }, [Rn] + /// A64: ST1 { Vt.2D }, [Xn] + /// + public static unsafe void Store(double* address, Vector128 source) => Store(address, source); + + /// + /// void vst1q_s16 (int16_t * ptr, int16x8_t val) + /// A32: VST1.16 { Dd, Dd+1 }, [Rn] + /// A64: ST1 { Vt.8H }, [Xn] + /// + public static unsafe void Store(short* address, Vector128 source) => Store(address, source); + + /// + /// void vst1q_s32 (int32_t * ptr, int32x4_t val) + /// A32: VST1.32 { Dd, Dd+1 }, [Rn] + /// A64: ST1 { Vt.4S }, [Xn] + /// + public static unsafe void Store(int* address, Vector128 source) => Store(address, source); + + /// + /// void vst1q_s64 (int64_t * ptr, int64x2_t val) + /// A32: VST1.64 { Dd, Dd+1 }, [Rn] + /// A64: ST1 { Vt.2D }, [Xn] + /// + public static unsafe void Store(long* address, Vector128 source) => Store(address, source); + + /// + /// void vst1q_s8 (int8_t * ptr, int8x16_t val) + /// A32: VST1.8 { Dd, Dd+1 }, [Rn] + /// A64: ST1 { Vt.16B }, [Xn] + /// + public static unsafe void Store(sbyte* address, Vector128 source) => Store(address, source); + + /// + /// void vst1q_f32 (float32_t * ptr, float32x4_t val) + /// A32: VST1.32 { Dd, Dd+1 }, [Rn] + /// A64: ST1 { Vt.4S }, [Xn] + /// + public static unsafe void Store(float* address, Vector128 source) => Store(address, source); + + /// + /// void vst1q_u16 (uint16_t * ptr, uint16x8_t val) + /// A32: VST1.16 { Dd, Dd+1 }, [Rn] + /// A64: ST1 { Vt.8H }, [Xn] + /// + public static unsafe void Store(ushort* address, Vector128 source) => Store(address, source); + + /// + /// void vst1q_u32 (uint32_t * ptr, uint32x4_t val) + /// A32: VST1.32 { Dd, Dd+1 }, [Rn] + /// A64: ST1 { Vt.4S }, [Xn] + /// + public static unsafe void Store(uint* address, Vector128 source) => Store(address, source); + + /// + /// void vst1q_u64 (uint64_t * ptr, uint64x2_t val) + /// A32: VST1.64 { Dd, Dd+1 }, [Rn] + /// A64: ST1 { Vt.2D }, [Xn] + /// + public static unsafe void Store(ulong* address, Vector128 source) => Store(address, source); + /// /// uint8x8_t vsub_u8 (uint8x8_t a, uint8x8_t b) /// A32: VSUB.I8 Dd, Dn, Dm diff --git a/src/System.Private.CoreLib/shared/System/Runtime/Intrinsics/Arm/Sha1.PlatformNotSupported.cs b/src/System.Private.CoreLib/shared/System/Runtime/Intrinsics/Arm/Sha1.PlatformNotSupported.cs index 685000e40..d26f5f5de 100644 --- a/src/System.Private.CoreLib/shared/System/Runtime/Intrinsics/Arm/Sha1.PlatformNotSupported.cs +++ b/src/System.Private.CoreLib/shared/System/Runtime/Intrinsics/Arm/Sha1.PlatformNotSupported.cs @@ -22,28 +22,28 @@ namespace System.Runtime.Intrinsics.Arm /// A32: SHA1H.32 Qd, Qm /// A64: SHA1H Sd, Sn /// - public static uint FixedRotate(uint hash_e) { throw new PlatformNotSupportedException(); } + public static Vector64 FixedRotate(Vector64 hash_e) { throw new PlatformNotSupportedException(); } /// /// uint32x4_t vsha1cq_u32 (uint32x4_t hash_abcd, uint32_t hash_e, uint32x4_t wk) /// A32: SHA1C.32 Qd, Qn, Qm /// A64: SHA1C Qd, Sn, Vm.4S /// - public static Vector128 HashUpdateChoose(Vector128 hash_abcd, uint hash_e, Vector128 wk) { throw new PlatformNotSupportedException(); } + public static Vector128 HashUpdateChoose(Vector128 hash_abcd, Vector64 hash_e, Vector128 wk) { throw new PlatformNotSupportedException(); } /// /// uint32x4_t vsha1mq_u32 (uint32x4_t hash_abcd, uint32_t hash_e, uint32x4_t wk) /// A32: SHA1M.32 Qd, Qn, Qm /// A64: SHA1M Qd, Sn, Vm.4S /// - public static Vector128 HashUpdateMajority(Vector128 hash_abcd, uint hash_e, Vector128 wk) { throw new PlatformNotSupportedException(); } + public static Vector128 HashUpdateMajority(Vector128 hash_abcd, Vector64 hash_e, Vector128 wk) { throw new PlatformNotSupportedException(); } /// /// uint32x4_t vsha1pq_u32 (uint32x4_t hash_abcd, uint32_t hash_e, uint32x4_t wk) /// A32: SHA1P.32 Qd, Qn, Qm /// A64: SHA1P Qd, Sn, Vm.4S /// - public static Vector128 HashUpdateParity(Vector128 hash_abcd, uint hash_e, Vector128 wk) { throw new PlatformNotSupportedException(); } + public static Vector128 HashUpdateParity(Vector128 hash_abcd, Vector64 hash_e, Vector128 wk) { throw new PlatformNotSupportedException(); } /// /// uint32x4_t vsha1su0q_u32 (uint32x4_t w0_3, uint32x4_t w4_7, uint32x4_t w8_11) diff --git a/src/System.Private.CoreLib/shared/System/Runtime/Intrinsics/Arm/Sha1.cs b/src/System.Private.CoreLib/shared/System/Runtime/Intrinsics/Arm/Sha1.cs index d4d79a3cb..e2287c212 100644 --- a/src/System.Private.CoreLib/shared/System/Runtime/Intrinsics/Arm/Sha1.cs +++ b/src/System.Private.CoreLib/shared/System/Runtime/Intrinsics/Arm/Sha1.cs @@ -22,28 +22,28 @@ namespace System.Runtime.Intrinsics.Arm /// A32: SHA1H.32 Qd, Qm /// A64: SHA1H Sd, Sn /// - public static uint FixedRotate(uint hash_e) => FixedRotate(hash_e); + public static Vector64 FixedRotate(Vector64 hash_e) => FixedRotate(hash_e); /// /// uint32x4_t vsha1cq_u32 (uint32x4_t hash_abcd, uint32_t hash_e, uint32x4_t wk) /// A32: SHA1C.32 Qd, Qn, Qm /// A64: SHA1C Qd, Sn, Vm.4S /// - public static Vector128 HashUpdateChoose(Vector128 hash_abcd, uint hash_e, Vector128 wk) => HashUpdateChoose(hash_abcd, hash_e, wk); + public static Vector128 HashUpdateChoose(Vector128 hash_abcd, Vector64 hash_e, Vector128 wk) => HashUpdateChoose(hash_abcd, hash_e, wk); /// /// uint32x4_t vsha1mq_u32 (uint32x4_t hash_abcd, uint32_t hash_e, uint32x4_t wk) /// A32: SHA1M.32 Qd, Qn, Qm /// A64: SHA1M Qd, Sn, Vm.4S /// - public static Vector128 HashUpdateMajority(Vector128 hash_abcd, uint hash_e, Vector128 wk) => HashUpdateMajority(hash_abcd, hash_e, wk); + public static Vector128 HashUpdateMajority(Vector128 hash_abcd, Vector64 hash_e, Vector128 wk) => HashUpdateMajority(hash_abcd, hash_e, wk); /// /// uint32x4_t vsha1pq_u32 (uint32x4_t hash_abcd, uint32_t hash_e, uint32x4_t wk) /// A32: SHA1P.32 Qd, Qn, Qm /// A64: SHA1P Qd, Sn, Vm.4S /// - public static Vector128 HashUpdateParity(Vector128 hash_abcd, uint hash_e, Vector128 wk) => HashUpdateParity(hash_abcd, hash_e, wk); + public static Vector128 HashUpdateParity(Vector128 hash_abcd, Vector64 hash_e, Vector128 wk) => HashUpdateParity(hash_abcd, hash_e, wk); /// /// uint32x4_t vsha1su0q_u32 (uint32x4_t w0_3, uint32x4_t w4_7, uint32x4_t w8_11) diff --git a/src/System.Private.CoreLib/shared/System/Runtime/Intrinsics/Vector64.cs b/src/System.Private.CoreLib/shared/System/Runtime/Intrinsics/Vector64.cs index b1f164585..a4f3fae98 100644 --- a/src/System.Private.CoreLib/shared/System/Runtime/Intrinsics/Vector64.cs +++ b/src/System.Private.CoreLib/shared/System/Runtime/Intrinsics/Vector64.cs @@ -522,6 +522,7 @@ namespace System.Runtime.Intrinsics /// Creates a new instance with the first element initialized to the specified value and the remaining elements left uninitialized. /// The value that element 0 will be initialized to. /// A new instance with the first element initialized to and the remaining elements left uninitialized. + [Intrinsic] public static unsafe Vector64 CreateScalarUnsafe(byte value) { // This relies on us stripping the "init" flag from the ".locals" @@ -535,6 +536,7 @@ namespace System.Runtime.Intrinsics /// Creates a new instance with the first element initialized to the specified value and the remaining elements left uninitialized. /// The value that element 0 will be initialized to. /// A new instance with the first element initialized to and the remaining elements left uninitialized. + [Intrinsic] public static unsafe Vector64 CreateScalarUnsafe(short value) { // This relies on us stripping the "init" flag from the ".locals" @@ -548,6 +550,7 @@ namespace System.Runtime.Intrinsics /// Creates a new instance with the first element initialized to the specified value and the remaining elements left uninitialized. /// The value that element 0 will be initialized to. /// A new instance with the first element initialized to and the remaining elements left uninitialized. + [Intrinsic] public static unsafe Vector64 CreateScalarUnsafe(int value) { // This relies on us stripping the "init" flag from the ".locals" @@ -562,6 +565,7 @@ namespace System.Runtime.Intrinsics /// The value that element 0 will be initialized to. /// A new instance with the first element initialized to and the remaining elements left uninitialized. [CLSCompliant(false)] + [Intrinsic] public static unsafe Vector64 CreateScalarUnsafe(sbyte value) { // This relies on us stripping the "init" flag from the ".locals" @@ -575,6 +579,7 @@ namespace System.Runtime.Intrinsics /// Creates a new instance with the first element initialized to the specified value and the remaining elements left uninitialized. /// The value that element 0 will be initialized to. /// A new instance with the first element initialized to and the remaining elements left uninitialized. + [Intrinsic] public static unsafe Vector64 CreateScalarUnsafe(float value) { // This relies on us stripping the "init" flag from the ".locals" @@ -589,6 +594,7 @@ namespace System.Runtime.Intrinsics /// The value that element 0 will be initialized to. /// A new instance with the first element initialized to and the remaining elements left uninitialized. [CLSCompliant(false)] + [Intrinsic] public static unsafe Vector64 CreateScalarUnsafe(ushort value) { // This relies on us stripping the "init" flag from the ".locals" @@ -603,6 +609,7 @@ namespace System.Runtime.Intrinsics /// The value that element 0 will be initialized to. /// A new instance with the first element initialized to and the remaining elements left uninitialized. [CLSCompliant(false)] + [Intrinsic] public static unsafe Vector64 CreateScalarUnsafe(uint value) { // This relies on us stripping the "init" flag from the ".locals" diff --git a/src/System.Private.CoreLib/shared/System/Runtime/Intrinsics/X86/Avx.PlatformNotSupported.cs b/src/System.Private.CoreLib/shared/System/Runtime/Intrinsics/X86/Avx.PlatformNotSupported.cs index c855b8db6..dd8a009aa 100644 --- a/src/System.Private.CoreLib/shared/System/Runtime/Intrinsics/X86/Avx.PlatformNotSupported.cs +++ b/src/System.Private.CoreLib/shared/System/Runtime/Intrinsics/X86/Avx.PlatformNotSupported.cs @@ -144,6 +144,149 @@ namespace System.Runtime.Intrinsics.X86 /// public static Vector256 Compare(Vector256 left, Vector256 right, FloatComparisonMode mode) { throw new PlatformNotSupportedException(); } + /// + /// __m256 _mm256_cmpeq_ps (__m256 a, __m256 b) + /// CMPPS ymm, ymm/m256, imm8(0) + /// The above native signature does not exist. We provide this additional overload for completeness. + /// + public static Vector256 CompareEqual(Vector256 left, Vector256 right) { throw new PlatformNotSupportedException(); } + /// + /// __m256d _mm256_cmpeq_pd (__m256d a, __m256d b) + /// CMPPD ymm, ymm/m256, imm8(0) + /// The above native signature does not exist. We provide this additional overload for completeness. + /// + public static Vector256 CompareEqual(Vector256 left, Vector256 right) { throw new PlatformNotSupportedException(); } + + /// + /// __m256 _mm256_cmpgt_ps (__m256 a, __m256 b) + /// CMPPS ymm, ymm/m256, imm8(14) + /// The above native signature does not exist. We provide this additional overload for completeness. + /// + public static Vector256 CompareGreaterThan(Vector256 left, Vector256 right) { throw new PlatformNotSupportedException(); } + /// + /// __m256d _mm256_cmpgt_pd (__m256d a, __m256d b) + /// CMPPD ymm, ymm/m256, imm8(14) + /// The above native signature does not exist. We provide this additional overload for completeness. + /// + public static Vector256 CompareGreaterThan(Vector256 left, Vector256 right) { throw new PlatformNotSupportedException(); } + + /// + /// __m256 _mm256_cmpge_ps (__m256 a, __m256 b) + /// CMPPS ymm, ymm/m256, imm8(13) + /// The above native signature does not exist. We provide this additional overload for completeness. + /// + public static Vector256 CompareGreaterThanOrEqual(Vector256 left, Vector256 right) { throw new PlatformNotSupportedException(); } + /// + /// __m256d _mm256_cmpge_pd (__m256d a, __m256d b) + /// CMPPD ymm, ymm/m256, imm8(13) + /// The above native signature does not exist. We provide this additional overload for completeness. + /// + public static Vector256 CompareGreaterThanOrEqual(Vector256 left, Vector256 right) { throw new PlatformNotSupportedException(); } + + /// + /// __m256 _mm256_cmplt_ps (__m256 a, __m256 b) + /// CMPPS ymm, ymm/m256, imm8(1) + /// The above native signature does not exist. We provide this additional overload for completeness. + /// + public static Vector256 CompareLessThan(Vector256 left, Vector256 right) { throw new PlatformNotSupportedException(); } + /// + /// __m256d _mm256_cmplt_pd (__m256d a, __m256d b) + /// CMPPD ymm, ymm/m256, imm8(1) + /// The above native signature does not exist. We provide this additional overload for completeness. + /// + public static Vector256 CompareLessThan(Vector256 left, Vector256 right) { throw new PlatformNotSupportedException(); } + + /// + /// __m256 _mm256_cmple_ps (__m256 a, __m256 b) + /// CMPPS ymm, ymm/m256, imm8(2) + /// The above native signature does not exist. We provide this additional overload for completeness. + /// + public static Vector256 CompareLessThanOrEqual(Vector256 left, Vector256 right) { throw new PlatformNotSupportedException(); } + /// + /// __m256d _mm256_cmple_pd (__m256d a, __m256d b) + /// CMPPD ymm, ymm/m256, imm8(2) + /// The above native signature does not exist. We provide this additional overload for completeness. + /// + public static Vector256 CompareLessThanOrEqual(Vector256 left, Vector256 right) { throw new PlatformNotSupportedException(); } + + /// + /// __m256 _mm256_cmpneq_ps (__m256 a, __m256 b) + /// CMPPS ymm, ymm/m256, imm8(4) + /// The above native signature does not exist. We provide this additional overload for completeness. + /// + public static Vector256 CompareNotEqual(Vector256 left, Vector256 right) { throw new PlatformNotSupportedException(); } + /// + /// __m256d _mm256_cmpneq_pd (__m256d a, __m256d b) + /// CMPPD ymm, ymm/m256, imm8(4) + /// The above native signature does not exist. We provide this additional overload for completeness. + /// + public static Vector256 CompareNotEqual(Vector256 left, Vector256 right) { throw new PlatformNotSupportedException(); } + + /// + /// __m256 _mm256_cmpngt_ps (__m256 a, __m256 b) + /// CMPPS ymm, ymm/m256, imm8(10) + /// The above native signature does not exist. We provide this additional overload for completeness. + /// + public static Vector256 CompareNotGreaterThan(Vector256 left, Vector256 right) { throw new PlatformNotSupportedException(); } + /// + /// __m256d _mm256_cmpngt_pd (__m256d a, __m256d b) + /// CMPPD ymm, ymm/m256, imm8(10) + /// The above native signature does not exist. We provide this additional overload for completeness. + /// + public static Vector256 CompareNotGreaterThan(Vector256 left, Vector256 right) { throw new PlatformNotSupportedException(); } + + /// + /// __m256 _mm256_cmpnge_ps (__m256 a, __m256 b) + /// CMPPS ymm, ymm/m256, imm8(9) + /// The above native signature does not exist. We provide this additional overload for completeness. + /// + public static Vector256 CompareNotGreaterThanOrEqual(Vector256 left, Vector256 right) { throw new PlatformNotSupportedException(); } + /// + /// __m256d _mm256_cmpnge_pd (__m256d a, __m256d b) + /// CMPPD ymm, ymm/m256, imm8(9) + /// The above native signature does not exist. We provide this additional overload for completeness. + /// + public static Vector256 CompareNotGreaterThanOrEqual(Vector256 left, Vector256 right) { throw new PlatformNotSupportedException(); } + + /// + /// __m256 _mm256_cmpnlt_ps (__m256 a, __m256 b) + /// CMPPS ymm, ymm/m256, imm8(5) + /// The above native signature does not exist. We provide this additional overload for completeness. + /// + public static Vector256 CompareNotLessThan(Vector256 left, Vector256 right) { throw new PlatformNotSupportedException(); } + /// + /// __m256d _mm256_cmpnlt_pd (__m256d a, __m256d b) + /// CMPPD ymm, ymm/m256, imm8(5) + /// The above native signature does not exist. We provide this additional overload for completeness. + /// + public static Vector256 CompareNotLessThan(Vector256 left, Vector256 right) { throw new PlatformNotSupportedException(); } + + /// + /// __m256 _mm256_cmpnle_ps (__m256 a, __m256 b) + /// CMPPS ymm, ymm/m256, imm8(6) + /// The above native signature does not exist. We provide this additional overload for completeness. + /// + public static Vector256 CompareNotLessThanOrEqual(Vector256 left, Vector256 right) { throw new PlatformNotSupportedException(); } + /// + /// __m256d _mm256_cmpnle_pd (__m256d a, __m256d b) + /// CMPPD ymm, ymm/m256, imm8(6) + /// The above native signature does not exist. We provide this additional overload for completeness. + /// + public static Vector256 CompareNotLessThanOrEqual(Vector256 left, Vector256 right) { throw new PlatformNotSupportedException(); } + + /// + /// __m256 _mm256_cmpord_ps (__m256 a, __m256 b) + /// CMPPS ymm, ymm/m256, imm8(7) + /// The above native signature does not exist. We provide this additional overload for completeness. + /// + public static Vector256 CompareOrdered(Vector256 left, Vector256 right) { throw new PlatformNotSupportedException(); } + /// + /// __m256d _mm256_cmpord_pd (__m256d a, __m256d b) + /// CMPPD ymm, ymm/m256, imm8(7) + /// The above native signature does not exist. We provide this additional overload for completeness. + /// + public static Vector256 CompareOrdered(Vector256 left, Vector256 right) { throw new PlatformNotSupportedException(); } + /// /// __m128d _mm_cmp_sd (__m128d a, __m128d b, const int imm8) /// VCMPSS xmm, xmm, xmm/m32, imm8 @@ -155,6 +298,19 @@ namespace System.Runtime.Intrinsics.X86 /// public static Vector128 CompareScalar(Vector128 left, Vector128 right, FloatComparisonMode mode) { throw new PlatformNotSupportedException(); } + /// + /// __m256 _mm256_cmpunord_ps (__m256 a, __m256 b) + /// CMPPS ymm, ymm/m256, imm8(3) + /// The above native signature does not exist. We provide this additional overload for completeness. + /// + public static Vector256 CompareUnordered(Vector256 left, Vector256 right) { throw new PlatformNotSupportedException(); } + /// + /// __m256d _mm256_cmpunord_pd (__m256d a, __m256d b) + /// CMPPD ymm, ymm/m256, imm8(3) + /// The above native signature does not exist. We provide this additional overload for completeness. + /// + public static Vector256 CompareUnordered(Vector256 left, Vector256 right) { throw new PlatformNotSupportedException(); } + /// /// __m128i _mm256_cvtpd_epi32 (__m256d a) /// VCVTPD2DQ xmm, ymm/m256 diff --git a/src/System.Private.CoreLib/shared/System/Runtime/Intrinsics/X86/Avx.cs b/src/System.Private.CoreLib/shared/System/Runtime/Intrinsics/X86/Avx.cs index cf12b20bd..d76483eda 100644 --- a/src/System.Private.CoreLib/shared/System/Runtime/Intrinsics/X86/Avx.cs +++ b/src/System.Private.CoreLib/shared/System/Runtime/Intrinsics/X86/Avx.cs @@ -143,6 +143,149 @@ namespace System.Runtime.Intrinsics.X86 /// public static Vector256 Compare(Vector256 left, Vector256 right, FloatComparisonMode mode) => Compare(left, right, mode); + /// + /// __m256 _mm256_cmpeq_ps (__m256 a, __m256 b) + /// CMPPS ymm, ymm/m256, imm8(0) + /// The above native signature does not exist. We provide this additional overload for completeness. + /// + public static Vector256 CompareEqual(Vector256 left, Vector256 right) => Compare(left, right, FloatComparisonMode.OrderedEqualNonSignaling); + /// + /// __m256d _mm256_cmpeq_pd (__m256d a, __m256d b) + /// CMPPD ymm, ymm/m256, imm8(0) + /// The above native signature does not exist. We provide this additional overload for completeness. + /// + public static Vector256 CompareEqual(Vector256 left, Vector256 right) => Compare(left, right, FloatComparisonMode.OrderedEqualNonSignaling); + + /// + /// __m256 _mm256_cmpgt_ps (__m256 a, __m256 b) + /// CMPPS ymm, ymm/m256, imm8(14) + /// The above native signature does not exist. We provide this additional overload for completeness. + /// + public static Vector256 CompareGreaterThan(Vector256 left, Vector256 right) => Compare(left, right, FloatComparisonMode.OrderedGreaterThanSignaling); + /// + /// __m256d _mm256_cmpgt_pd (__m256d a, __m256d b) + /// CMPPD ymm, ymm/m256, imm8(14) + /// The above native signature does not exist. We provide this additional overload for completeness. + /// + public static Vector256 CompareGreaterThan(Vector256 left, Vector256 right) => Compare(left, right, FloatComparisonMode.OrderedGreaterThanSignaling); + + /// + /// __m256 _mm256_cmpge_ps (__m256 a, __m256 b) + /// CMPPS ymm, ymm/m256, imm8(13) + /// The above native signature does not exist. We provide this additional overload for completeness. + /// + public static Vector256 CompareGreaterThanOrEqual(Vector256 left, Vector256 right) => Compare(left, right, FloatComparisonMode.OrderedGreaterThanOrEqualSignaling); + /// + /// __m256d _mm256_cmpge_pd (__m256d a, __m256d b) + /// CMPPD ymm, ymm/m256, imm8(13) + /// The above native signature does not exist. We provide this additional overload for completeness. + /// + public static Vector256 CompareGreaterThanOrEqual(Vector256 left, Vector256 right) => Compare(left, right, FloatComparisonMode.OrderedGreaterThanOrEqualSignaling); + + /// + /// __m256 _mm256_cmplt_ps (__m256 a, __m256 b) + /// CMPPS ymm, ymm/m256, imm8(1) + /// The above native signature does not exist. We provide this additional overload for completeness. + /// + public static Vector256 CompareLessThan(Vector256 left, Vector256 right) => Compare(left, right, FloatComparisonMode.OrderedLessThanSignaling); + /// + /// __m256d _mm256_cmplt_pd (__m256d a, __m256d b) + /// CMPPD ymm, ymm/m256, imm8(1) + /// The above native signature does not exist. We provide this additional overload for completeness. + /// + public static Vector256 CompareLessThan(Vector256 left, Vector256 right) => Compare(left, right, FloatComparisonMode.OrderedLessThanSignaling); + + /// + /// __m256 _mm256_cmple_ps (__m256 a, __m256 b) + /// CMPPS ymm, ymm/m256, imm8(2) + /// The above native signature does not exist. We provide this additional overload for completeness. + /// + public static Vector256 CompareLessThanOrEqual(Vector256 left, Vector256 right) => Compare(left, right, FloatComparisonMode.OrderedLessThanOrEqualSignaling); + /// + /// __m256d _mm256_cmple_pd (__m256d a, __m256d b) + /// CMPPD ymm, ymm/m256, imm8(2) + /// The above native signature does not exist. We provide this additional overload for completeness. + /// + public static Vector256 CompareLessThanOrEqual(Vector256 left, Vector256 right) => Compare(left, right, FloatComparisonMode.OrderedLessThanOrEqualSignaling); + + /// + /// __m256 _mm256_cmpneq_ps (__m256 a, __m256 b) + /// CMPPS ymm, ymm/m256, imm8(4) + /// The above native signature does not exist. We provide this additional overload for completeness. + /// + public static Vector256 CompareNotEqual(Vector256 left, Vector256 right) => Compare(left, right, FloatComparisonMode.UnorderedNotEqualNonSignaling); + /// + /// __m256d _mm256_cmpneq_pd (__m256d a, __m256d b) + /// CMPPD ymm, ymm/m256, imm8(4) + /// The above native signature does not exist. We provide this additional overload for completeness. + /// + public static Vector256 CompareNotEqual(Vector256 left, Vector256 right) => Compare(left, right, FloatComparisonMode.UnorderedNotEqualNonSignaling); + + /// + /// __m256 _mm256_cmpngt_ps (__m256 a, __m256 b) + /// CMPPS ymm, ymm/m256, imm8(10) + /// The above native signature does not exist. We provide this additional overload for completeness. + /// + public static Vector256 CompareNotGreaterThan(Vector256 left, Vector256 right) => Compare(left, right, FloatComparisonMode.UnorderedNotGreaterThanSignaling); + /// + /// __m256d _mm256_cmpngt_pd (__m256d a, __m256d b) + /// CMPPD ymm, ymm/m256, imm8(10) + /// The above native signature does not exist. We provide this additional overload for completeness. + /// + public static Vector256 CompareNotGreaterThan(Vector256 left, Vector256 right) => Compare(left, right, FloatComparisonMode.UnorderedNotGreaterThanSignaling); + + /// + /// __m256 _mm256_cmpnge_ps (__m256 a, __m256 b) + /// CMPPS ymm, ymm/m256, imm8(9) + /// The above native signature does not exist. We provide this additional overload for completeness. + /// + public static Vector256 CompareNotGreaterThanOrEqual(Vector256 left, Vector256 right) => Compare(left, right, FloatComparisonMode.UnorderedNotGreaterThanOrEqualSignaling); + /// + /// __m256d _mm256_cmpnge_pd (__m256d a, __m256d b) + /// CMPPD ymm, ymm/m256, imm8(9) + /// The above native signature does not exist. We provide this additional overload for completeness. + /// + public static Vector256 CompareNotGreaterThanOrEqual(Vector256 left, Vector256 right) => Compare(left, right, FloatComparisonMode.UnorderedNotGreaterThanOrEqualSignaling); + + /// + /// __m256 _mm256_cmpnlt_ps (__m256 a, __m256 b) + /// CMPPS ymm, ymm/m256, imm8(5) + /// The above native signature does not exist. We provide this additional overload for completeness. + /// + public static Vector256 CompareNotLessThan(Vector256 left, Vector256 right) => Compare(left, right, FloatComparisonMode.UnorderedNotLessThanSignaling); + /// + /// __m256d _mm256_cmpnlt_pd (__m256d a, __m256d b) + /// CMPPD ymm, ymm/m256, imm8(5) + /// The above native signature does not exist. We provide this additional overload for completeness. + /// + public static Vector256 CompareNotLessThan(Vector256 left, Vector256 right) => Compare(left, right, FloatComparisonMode.UnorderedNotLessThanSignaling); + + /// + /// __m256 _mm256_cmpnle_ps (__m256 a, __m256 b) + /// CMPPS ymm, ymm/m256, imm8(6) + /// The above native signature does not exist. We provide this additional overload for completeness. + /// + public static Vector256 CompareNotLessThanOrEqual(Vector256 left, Vector256 right) => Compare(left, right, FloatComparisonMode.UnorderedNotLessThanOrEqualSignaling); + /// + /// __m256d _mm256_cmpnle_pd (__m256d a, __m256d b) + /// CMPPD ymm, ymm/m256, imm8(6) + /// The above native signature does not exist. We provide this additional overload for completeness. + /// + public static Vector256 CompareNotLessThanOrEqual(Vector256 left, Vector256 right) => Compare(left, right, FloatComparisonMode.UnorderedNotLessThanOrEqualSignaling); + + /// + /// __m256 _mm256_cmpord_ps (__m256 a, __m256 b) + /// CMPPS ymm, ymm/m256, imm8(7) + /// The above native signature does not exist. We provide this additional overload for completeness. + /// + public static Vector256 CompareOrdered(Vector256 left, Vector256 right) => Compare(left, right, FloatComparisonMode.OrderedNonSignaling); + /// + /// __m256d _mm256_cmpord_pd (__m256d a, __m256d b) + /// CMPPD ymm, ymm/m256, imm8(7) + /// The above native signature does not exist. We provide this additional overload for completeness. + /// + public static Vector256 CompareOrdered(Vector256 left, Vector256 right) => Compare(left, right, FloatComparisonMode.OrderedNonSignaling); + /// /// __m128d _mm_cmp_sd (__m128d a, __m128d b, const int imm8) /// VCMPSS xmm, xmm, xmm/m32, imm8 @@ -154,6 +297,19 @@ namespace System.Runtime.Intrinsics.X86 /// public static Vector128 CompareScalar(Vector128 left, Vector128 right, FloatComparisonMode mode) => CompareScalar(left, right, mode); + /// + /// __m256 _mm256_cmpunord_ps (__m256 a, __m256 b) + /// CMPPS ymm, ymm/m256, imm8(3) + /// The above native signature does not exist. We provide this additional overload for completeness. + /// + public static Vector256 CompareUnordered(Vector256 left, Vector256 right) => Compare(left, right, FloatComparisonMode.UnorderedNonSignaling); + /// + /// __m256d _mm256_cmpunord_pd (__m256d a, __m256d b) + /// CMPPD ymm, ymm/m256, imm8(3) + /// The above native signature does not exist. We provide this additional overload for completeness. + /// + public static Vector256 CompareUnordered(Vector256 left, Vector256 right) => Compare(left, right, FloatComparisonMode.UnorderedNonSignaling); + /// /// __m128i _mm256_cvtpd_epi32 (__m256d a) /// VCVTPD2DQ xmm, ymm/m256 diff --git a/src/System.Private.CoreLib/shared/System/Runtime/Intrinsics/X86/Sse.PlatformNotSupported.cs b/src/System.Private.CoreLib/shared/System/Runtime/Intrinsics/X86/Sse.PlatformNotSupported.cs index 23532b452..f3a4201f2 100644 --- a/src/System.Private.CoreLib/shared/System/Runtime/Intrinsics/X86/Sse.PlatformNotSupported.cs +++ b/src/System.Private.CoreLib/shared/System/Runtime/Intrinsics/X86/Sse.PlatformNotSupported.cs @@ -96,7 +96,7 @@ namespace System.Runtime.Intrinsics.X86 /// /// __m128 _mm_cmpgt_ps (__m128 a, __m128 b) - /// CMPPS xmm, xmm/m128, imm8(6) + /// CMPPS xmm, xmm/m128, imm8(1) with swapped operands /// public static Vector128 CompareGreaterThan(Vector128 left, Vector128 right) { throw new PlatformNotSupportedException(); } @@ -114,13 +114,13 @@ namespace System.Runtime.Intrinsics.X86 /// /// __m128 _mm_cmpgt_ss (__m128 a, __m128 b) - /// CMPSS xmm, xmm/m32, imm8(6) + /// CMPSS xmm, xmm/m32, imm8(1) with swapped operands /// public static Vector128 CompareScalarGreaterThan(Vector128 left, Vector128 right) { throw new PlatformNotSupportedException(); } /// /// __m128 _mm_cmpge_ps (__m128 a, __m128 b) - /// CMPPS xmm, xmm/m128, imm8(5) + /// CMPPS xmm, xmm/m128, imm8(2) with swapped operands /// public static Vector128 CompareGreaterThanOrEqual(Vector128 left, Vector128 right) { throw new PlatformNotSupportedException(); } @@ -138,7 +138,7 @@ namespace System.Runtime.Intrinsics.X86 /// /// __m128 _mm_cmpge_ss (__m128 a, __m128 b) - /// CMPPS xmm, xmm/m32, imm8(5) + /// CMPPS xmm, xmm/m32, imm8(2) with swapped operands /// public static Vector128 CompareScalarGreaterThanOrEqual(Vector128 left, Vector128 right) { throw new PlatformNotSupportedException(); } @@ -216,25 +216,25 @@ namespace System.Runtime.Intrinsics.X86 /// /// __m128 _mm_cmpngt_ps (__m128 a, __m128 b) - /// CMPPS xmm, xmm/m128, imm8(2) + /// CMPPS xmm, xmm/m128, imm8(5) with swapped operands /// public static Vector128 CompareNotGreaterThan(Vector128 left, Vector128 right) { throw new PlatformNotSupportedException(); } /// /// __m128 _mm_cmpngt_ss (__m128 a, __m128 b) - /// CMPSS xmm, xmm/m32, imm8(2) + /// CMPSS xmm, xmm/m32, imm8(5) with swapped operands /// public static Vector128 CompareScalarNotGreaterThan(Vector128 left, Vector128 right) { throw new PlatformNotSupportedException(); } /// /// __m128 _mm_cmpnge_ps (__m128 a, __m128 b) - /// CMPPS xmm, xmm/m128, imm8(1) + /// CMPPS xmm, xmm/m128, imm8(6) with swapped operands /// public static Vector128 CompareNotGreaterThanOrEqual(Vector128 left, Vector128 right) { throw new PlatformNotSupportedException(); } /// /// __m128 _mm_cmpnge_ss (__m128 a, __m128 b) - /// CMPSS xmm, xmm/m32, imm8(1) + /// CMPSS xmm, xmm/m32, imm8(6) with swapped operands /// public static Vector128 CompareScalarNotGreaterThanOrEqual(Vector128 left, Vector128 right) { throw new PlatformNotSupportedException(); } diff --git a/src/System.Private.CoreLib/shared/System/Runtime/Intrinsics/X86/Sse.cs b/src/System.Private.CoreLib/shared/System/Runtime/Intrinsics/X86/Sse.cs index f5cf132e4..b9e05621d 100644 --- a/src/System.Private.CoreLib/shared/System/Runtime/Intrinsics/X86/Sse.cs +++ b/src/System.Private.CoreLib/shared/System/Runtime/Intrinsics/X86/Sse.cs @@ -95,7 +95,7 @@ namespace System.Runtime.Intrinsics.X86 /// /// __m128 _mm_cmpgt_ps (__m128 a, __m128 b) - /// CMPPS xmm, xmm/m128, imm8(6) + /// CMPPS xmm, xmm/m128, imm8(1) with swapped operands /// public static Vector128 CompareGreaterThan(Vector128 left, Vector128 right) => CompareGreaterThan(left, right); @@ -113,13 +113,13 @@ namespace System.Runtime.Intrinsics.X86 /// /// __m128 _mm_cmpgt_ss (__m128 a, __m128 b) - /// CMPSS xmm, xmm/m32, imm8(6) + /// CMPSS xmm, xmm/m32, imm8(1) with swapped operands /// public static Vector128 CompareScalarGreaterThan(Vector128 left, Vector128 right) => CompareScalarGreaterThan(left, right); /// /// __m128 _mm_cmpge_ps (__m128 a, __m128 b) - /// CMPPS xmm, xmm/m128, imm8(5) + /// CMPPS xmm, xmm/m128, imm8(2) with swapped operands /// public static Vector128 CompareGreaterThanOrEqual(Vector128 left, Vector128 right) => CompareGreaterThanOrEqual(left, right); @@ -137,7 +137,7 @@ namespace System.Runtime.Intrinsics.X86 /// /// __m128 _mm_cmpge_ss (__m128 a, __m128 b) - /// CMPPS xmm, xmm/m32, imm8(5) + /// CMPPS xmm, xmm/m32, imm8(2) with swapped operands /// public static Vector128 CompareScalarGreaterThanOrEqual(Vector128 left, Vector128 right) => CompareScalarGreaterThanOrEqual(left, right); @@ -215,25 +215,25 @@ namespace System.Runtime.Intrinsics.X86 /// /// __m128 _mm_cmpngt_ps (__m128 a, __m128 b) - /// CMPPS xmm, xmm/m128, imm8(2) + /// CMPPS xmm, xmm/m128, imm8(5) with swapped operands /// public static Vector128 CompareNotGreaterThan(Vector128 left, Vector128 right) => CompareNotGreaterThan(left, right); /// /// __m128 _mm_cmpngt_ss (__m128 a, __m128 b) - /// CMPSS xmm, xmm/m32, imm8(2) + /// CMPSS xmm, xmm/m32, imm8(5) with swapped operands /// public static Vector128 CompareScalarNotGreaterThan(Vector128 left, Vector128 right) => CompareScalarNotGreaterThan(left, right); /// /// __m128 _mm_cmpnge_ps (__m128 a, __m128 b) - /// CMPPS xmm, xmm/m128, imm8(1) + /// CMPPS xmm, xmm/m128, imm8(6) with swapped operands /// public static Vector128 CompareNotGreaterThanOrEqual(Vector128 left, Vector128 right) => CompareNotGreaterThanOrEqual(left, right); /// /// __m128 _mm_cmpnge_ss (__m128 a, __m128 b) - /// CMPSS xmm, xmm/m32, imm8(1) + /// CMPSS xmm, xmm/m32, imm8(6) with swapped operands /// public static Vector128 CompareScalarNotGreaterThanOrEqual(Vector128 left, Vector128 right) => CompareScalarNotGreaterThanOrEqual(left, right); diff --git a/src/System.Private.CoreLib/shared/System/Runtime/Intrinsics/X86/Sse2.PlatformNotSupported.cs b/src/System.Private.CoreLib/shared/System/Runtime/Intrinsics/X86/Sse2.PlatformNotSupported.cs index df46013a2..93e0fa38a 100644 --- a/src/System.Private.CoreLib/shared/System/Runtime/Intrinsics/X86/Sse2.PlatformNotSupported.cs +++ b/src/System.Private.CoreLib/shared/System/Runtime/Intrinsics/X86/Sse2.PlatformNotSupported.cs @@ -333,7 +333,7 @@ namespace System.Runtime.Intrinsics.X86 public static Vector128 CompareGreaterThan(Vector128 left, Vector128 right) { throw new PlatformNotSupportedException(); } /// /// __m128d _mm_cmpgt_pd (__m128d a, __m128d b) - /// CMPPD xmm, xmm/m128, imm8(6) + /// CMPPD xmm, xmm/m128, imm8(1) with swapped operands /// public static Vector128 CompareGreaterThan(Vector128 left, Vector128 right) { throw new PlatformNotSupportedException(); } @@ -351,13 +351,13 @@ namespace System.Runtime.Intrinsics.X86 /// /// __m128d _mm_cmpgt_sd (__m128d a, __m128d b) - /// CMPSD xmm, xmm/m64, imm8(6) + /// CMPSD xmm, xmm/m64, imm8(1) with swapped operands /// public static Vector128 CompareScalarGreaterThan(Vector128 left, Vector128 right) { throw new PlatformNotSupportedException(); } /// /// __m128d _mm_cmpge_pd (__m128d a, __m128d b) - /// CMPPD xmm, xmm/m128, imm8(5) + /// CMPPD xmm, xmm/m128, imm8(2) with swapped operands /// public static Vector128 CompareGreaterThanOrEqual(Vector128 left, Vector128 right) { throw new PlatformNotSupportedException(); } @@ -375,7 +375,7 @@ namespace System.Runtime.Intrinsics.X86 /// /// __m128d _mm_cmpge_sd (__m128d a, __m128d b) - /// CMPSD xmm, xmm/m64, imm8(5) + /// CMPSD xmm, xmm/m64, imm8(2) with swapped operands /// public static Vector128 CompareScalarGreaterThanOrEqual(Vector128 left, Vector128 right) { throw new PlatformNotSupportedException(); } @@ -468,25 +468,25 @@ namespace System.Runtime.Intrinsics.X86 /// /// __m128d _mm_cmpngt_pd (__m128d a, __m128d b) - /// CMPPD xmm, xmm/m128, imm8(2) + /// CMPPD xmm, xmm/m128, imm8(5) with swapped operands /// public static Vector128 CompareNotGreaterThan(Vector128 left, Vector128 right) { throw new PlatformNotSupportedException(); } /// /// __m128d _mm_cmpngt_sd (__m128d a, __m128d b) - /// CMPSD xmm, xmm/m64, imm8(2) + /// CMPSD xmm, xmm/m64, imm8(5) with swapped operands /// public static Vector128 CompareScalarNotGreaterThan(Vector128 left, Vector128 right) { throw new PlatformNotSupportedException(); } /// /// __m128d _mm_cmpnge_pd (__m128d a, __m128d b) - /// CMPPD xmm, xmm/m128, imm8(1) + /// CMPPD xmm, xmm/m128, imm8(6) with swapped operands /// public static Vector128 CompareNotGreaterThanOrEqual(Vector128 left, Vector128 right) { throw new PlatformNotSupportedException(); } /// /// __m128d _mm_cmpnge_sd (__m128d a, __m128d b) - /// CMPSD xmm, xmm/m64, imm8(1) + /// CMPSD xmm, xmm/m64, imm8(6) with swapped operands /// public static Vector128 CompareScalarNotGreaterThanOrEqual(Vector128 left, Vector128 right) { throw new PlatformNotSupportedException(); } @@ -774,15 +774,13 @@ namespace System.Runtime.Intrinsics.X86 public static unsafe Vector128 LoadLow(Vector128 upper, double* address) { throw new PlatformNotSupportedException(); } /// - /// __m128i _mm_loadl_epi32 (__m128i const* mem_addr) - /// MOVD xmm, reg/m64 - /// The above native signature does not exist. We provide this additional overload for completeness. + /// __m128i _mm_loadu_si32 (void const* mem_addr) + /// MOVD xmm, reg/m32 /// public static unsafe Vector128 LoadScalarVector128(int* address) { throw new PlatformNotSupportedException(); } /// - /// __m128i _mm_loadl_epi32 (__m128i const* mem_addr) - /// MOVD xmm, reg/m64 - /// The above native signature does not exist. We provide this additional overload for completeness. + /// __m128i _mm_loadu_si32 (void const* mem_addr) + /// MOVD xmm, reg/m32 /// public static unsafe Vector128 LoadScalarVector128(uint* address) { throw new PlatformNotSupportedException(); } /// @@ -1295,11 +1293,21 @@ namespace System.Runtime.Intrinsics.X86 /// public static unsafe void StoreScalar(double* address, Vector128 source) { throw new PlatformNotSupportedException(); } /// + /// void _mm_storeu_si32 (void* mem_addr, __m128i a) + /// MOVD m32, xmm + /// + public static unsafe void StoreScalar(int* address, Vector128 source) { throw new PlatformNotSupportedException(); } + /// /// void _mm_storel_epi64 (__m128i* mem_addr, __m128i a) /// MOVQ m64, xmm /// public static unsafe void StoreScalar(long* address, Vector128 source) { throw new PlatformNotSupportedException(); } /// + /// void _mm_storeu_si32 (void* mem_addr, __m128i a) + /// MOVD m32, xmm + /// + public static unsafe void StoreScalar(uint* address, Vector128 source) { throw new PlatformNotSupportedException(); } + /// /// void _mm_storel_epi64 (__m128i* mem_addr, __m128i a) /// MOVQ m64, xmm /// diff --git a/src/System.Private.CoreLib/shared/System/Runtime/Intrinsics/X86/Sse2.cs b/src/System.Private.CoreLib/shared/System/Runtime/Intrinsics/X86/Sse2.cs index 464faffc7..343ca50d8 100644 --- a/src/System.Private.CoreLib/shared/System/Runtime/Intrinsics/X86/Sse2.cs +++ b/src/System.Private.CoreLib/shared/System/Runtime/Intrinsics/X86/Sse2.cs @@ -333,7 +333,7 @@ namespace System.Runtime.Intrinsics.X86 public static Vector128 CompareGreaterThan(Vector128 left, Vector128 right) => CompareGreaterThan(left, right); /// /// __m128d _mm_cmpgt_pd (__m128d a, __m128d b) - /// CMPPD xmm, xmm/m128, imm8(6) + /// CMPPD xmm, xmm/m128, imm8(1) with swapped operands /// public static Vector128 CompareGreaterThan(Vector128 left, Vector128 right) => CompareGreaterThan(left, right); @@ -351,13 +351,13 @@ namespace System.Runtime.Intrinsics.X86 /// /// __m128d _mm_cmpgt_sd (__m128d a, __m128d b) - /// CMPSD xmm, xmm/m64, imm8(6) + /// CMPSD xmm, xmm/m64, imm8(1) with swapped operands /// public static Vector128 CompareScalarGreaterThan(Vector128 left, Vector128 right) => CompareScalarGreaterThan(left, right); /// /// __m128d _mm_cmpge_pd (__m128d a, __m128d b) - /// CMPPD xmm, xmm/m128, imm8(5) + /// CMPPD xmm, xmm/m128, imm8(2) with swapped operands /// public static Vector128 CompareGreaterThanOrEqual(Vector128 left, Vector128 right) => CompareGreaterThanOrEqual(left, right); @@ -375,7 +375,7 @@ namespace System.Runtime.Intrinsics.X86 /// /// __m128d _mm_cmpge_sd (__m128d a, __m128d b) - /// CMPSD xmm, xmm/m64, imm8(5) + /// CMPSD xmm, xmm/m64, imm8(2) with swapped operands /// public static Vector128 CompareScalarGreaterThanOrEqual(Vector128 left, Vector128 right) => CompareScalarGreaterThanOrEqual(left, right); @@ -468,25 +468,25 @@ namespace System.Runtime.Intrinsics.X86 /// /// __m128d _mm_cmpngt_pd (__m128d a, __m128d b) - /// CMPPD xmm, xmm/m128, imm8(2) + /// CMPPD xmm, xmm/m128, imm8(5) with swapped operands /// public static Vector128 CompareNotGreaterThan(Vector128 left, Vector128 right) => CompareNotGreaterThan(left, right); /// /// __m128d _mm_cmpngt_sd (__m128d a, __m128d b) - /// CMPSD xmm, xmm/m64, imm8(2) + /// CMPSD xmm, xmm/m64, imm8(5) with swapped operands /// public static Vector128 CompareScalarNotGreaterThan(Vector128 left, Vector128 right) => CompareScalarNotGreaterThan(left, right); /// /// __m128d _mm_cmpnge_pd (__m128d a, __m128d b) - /// CMPPD xmm, xmm/m128, imm8(1) + /// CMPPD xmm, xmm/m128, imm8(6) with swapped operands /// public static Vector128 CompareNotGreaterThanOrEqual(Vector128 left, Vector128 right) => CompareNotGreaterThanOrEqual(left, right); /// /// __m128d _mm_cmpnge_sd (__m128d a, __m128d b) - /// CMPSD xmm, xmm/m64, imm8(1) + /// CMPSD xmm, xmm/m64, imm8(6) with swapped operands /// public static Vector128 CompareScalarNotGreaterThanOrEqual(Vector128 left, Vector128 right) => CompareScalarNotGreaterThanOrEqual(left, right); @@ -778,15 +778,13 @@ namespace System.Runtime.Intrinsics.X86 public static unsafe Vector128 LoadLow(Vector128 upper, double* address) => LoadLow(upper, address); /// - /// __m128i _mm_loadl_epi32 (__m128i const* mem_addr) + /// __m128i _mm_loadu_si32 (void const* mem_addr) /// MOVD xmm, reg/m32 - /// The above native signature does not exist. We provide this additional overload for completeness. /// public static unsafe Vector128 LoadScalarVector128(int* address) => LoadScalarVector128(address); /// - /// __m128i _mm_loadl_epi32 (__m128i const* mem_addr) + /// __m128i _mm_loadu_si32 (void const* mem_addr) /// MOVD xmm, reg/m32 - /// The above native signature does not exist. We provide this additional overload for completeness. /// public static unsafe Vector128 LoadScalarVector128(uint* address) => LoadScalarVector128(address); /// @@ -1299,11 +1297,21 @@ namespace System.Runtime.Intrinsics.X86 /// public static unsafe void StoreScalar(double* address, Vector128 source) => StoreScalar(address, source); /// + /// void _mm_storeu_si32 (void* mem_addr, __m128i a) + /// MOVD m32, xmm + /// + public static unsafe void StoreScalar(int* address, Vector128 source) => StoreScalar(address, source); + /// /// void _mm_storel_epi64 (__m128i* mem_addr, __m128i a) /// MOVQ m64, xmm /// public static unsafe void StoreScalar(long* address, Vector128 source) => StoreScalar(address, source); /// + /// void _mm_storeu_si32 (void* mem_addr, __m128i a) + /// MOVD m32, xmm + /// + public static unsafe void StoreScalar(uint* address, Vector128 source) => StoreScalar(address, source); + /// /// void _mm_storel_epi64 (__m128i* mem_addr, __m128i a) /// MOVQ m64, xmm /// diff --git a/src/System.Private.CoreLib/shared/System/Runtime/Loader/AssemblyDependencyResolver.cs b/src/System.Private.CoreLib/shared/System/Runtime/Loader/AssemblyDependencyResolver.cs deleted file mode 100644 index e9580d991..000000000 --- a/src/System.Private.CoreLib/shared/System/Runtime/Loader/AssemblyDependencyResolver.cs +++ /dev/null @@ -1,234 +0,0 @@ -// 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.Collections.Generic; -using System.IO; -using System.Reflection; -using System.Runtime.InteropServices; -using System.Text; -using Internal.IO; - -namespace System.Runtime.Loader -{ - public sealed class AssemblyDependencyResolver - { - /// - /// The name of the neutral culture (same value as in Variables::Init in CoreCLR) - /// - private const string NeutralCultureName = "neutral"; - - /// - /// The extension of resource assembly (same as in BindSatelliteResourceByResourceRoots in CoreCLR) - /// - private const string ResourceAssemblyExtension = ".dll"; - - private readonly Dictionary _assemblyPaths; - private readonly string[] _nativeSearchPaths; - private readonly string[] _resourceSearchPaths; - private readonly string[] _assemblyDirectorySearchPaths; - - public AssemblyDependencyResolver(string componentAssemblyPath) - { - if (componentAssemblyPath == null) - { - throw new ArgumentNullException(nameof(componentAssemblyPath)); - } - - string? assemblyPathsList = null; - string? nativeSearchPathsList = null; - string? resourceSearchPathsList = null; - int returnCode = 0; - - StringBuilder errorMessage = new StringBuilder(); - try - { - // Setup error writer for this thread. This makes the hostpolicy redirect all error output - // to the writer specified. Have to store the previous writer to set it back once this is done. - corehost_error_writer_fn errorWriter = new corehost_error_writer_fn(message => errorMessage.AppendLine(message)); - - IntPtr errorWriterPtr = Marshal.GetFunctionPointerForDelegate(errorWriter); - IntPtr previousErrorWriterPtr = corehost_set_error_writer(errorWriterPtr); - - try - { - // Call hostpolicy to do the actual work of finding .deps.json, parsing it and extracting - // information from it. - returnCode = corehost_resolve_component_dependencies( - componentAssemblyPath, - (assembly_paths, native_search_paths, resource_search_paths) => - { - assemblyPathsList = assembly_paths; - nativeSearchPathsList = native_search_paths; - resourceSearchPathsList = resource_search_paths; - }); - } - finally - { - // Reset the error write to the one used before - corehost_set_error_writer(previousErrorWriterPtr); - GC.KeepAlive(errorWriter); - } - } - catch (EntryPointNotFoundException entryPointNotFoundException) - { - throw new InvalidOperationException(SR.AssemblyDependencyResolver_FailedToLoadHostpolicy, entryPointNotFoundException); - } - catch (DllNotFoundException dllNotFoundException) - { - throw new InvalidOperationException(SR.AssemblyDependencyResolver_FailedToLoadHostpolicy, dllNotFoundException); - } - - if (returnCode != 0) - { - // Something went wrong - report a failure - throw new InvalidOperationException(SR.Format( - SR.AssemblyDependencyResolver_FailedToResolveDependencies, - componentAssemblyPath, - returnCode, - errorMessage)); - } - - string[] assemblyPaths = SplitPathsList(assemblyPathsList); - - // Assembly simple names are case insensitive per the runtime behavior - // (see SimpleNameToFileNameMapTraits for the TPA lookup hash). - _assemblyPaths = new Dictionary(StringComparer.OrdinalIgnoreCase); - foreach (string assemblyPath in assemblyPaths) - { - _assemblyPaths.Add(Path.GetFileNameWithoutExtension(assemblyPath), assemblyPath); - } - - _nativeSearchPaths = SplitPathsList(nativeSearchPathsList); - _resourceSearchPaths = SplitPathsList(resourceSearchPathsList); - - _assemblyDirectorySearchPaths = new string[1] { Path.GetDirectoryName(componentAssemblyPath)! }; - } - - public string? ResolveAssemblyToPath(AssemblyName assemblyName) - { - if (assemblyName == null) - { - throw new ArgumentNullException(nameof(assemblyName)); - } - - // Determine if the assembly name is for a satellite assembly or not - // This is the same logic as in AssemblyBinder::BindByTpaList in CoreCLR - // - If the culture name is non-empty and it's not 'neutral' - // - The culture name is the value of the AssemblyName.Culture.Name - // (CoreCLR gets this and stores it as the culture name in the internal assembly name) - // AssemblyName.CultureName is just a shortcut to AssemblyName.Culture.Name. - if (!string.IsNullOrEmpty(assemblyName.CultureName) && - !string.Equals(assemblyName.CultureName, NeutralCultureName, StringComparison.OrdinalIgnoreCase)) - { - // Load satellite assembly - // Search resource search paths by appending the culture name and the expected assembly file name. - // Copies the logic in BindSatelliteResourceByResourceRoots in CoreCLR. - // Note that the runtime will also probe APP_PATHS the same way, but that feature is effectively - // being deprecated, so we chose to not support the same behavior for components. - foreach (string searchPath in _resourceSearchPaths) - { - string assemblyPath = Path.Combine( - searchPath, - assemblyName.CultureName, - assemblyName.Name + ResourceAssemblyExtension); - if (File.Exists(assemblyPath)) - { - return assemblyPath; - } - } - } - else if (assemblyName.Name != null) - { - // Load code assembly - simply look it up in the dictionary by its simple name. - if (_assemblyPaths.TryGetValue(assemblyName.Name, out string? assemblyPath)) - { - // Only returnd the assembly if it exists on disk - this is to make the behavior of the API - // consistent. Resource and native resolutions will only return existing files - // so assembly resolution should do the same. - if (File.Exists(assemblyPath)) - { - return assemblyPath; - } - } - } - - return null; - } - - public string? ResolveUnmanagedDllToPath(string unmanagedDllName) - { - if (unmanagedDllName == null) - { - throw new ArgumentNullException(nameof(unmanagedDllName)); - } - - string[] searchPaths; - if (unmanagedDllName.Contains(Path.DirectorySeparatorChar)) - { - // Library names with absolute or relative path can't be resolved - // using the component .deps.json as that defines simple names. - // So instead use the component directory as the lookup path. - searchPaths = _assemblyDirectorySearchPaths; - } - else - { - searchPaths = _nativeSearchPaths; - } - - bool isRelativePath = !Path.IsPathFullyQualified(unmanagedDllName); - foreach (LibraryNameVariation libraryNameVariation in LibraryNameVariation.DetermineLibraryNameVariations(unmanagedDllName, isRelativePath)) - { - string libraryName = libraryNameVariation.Prefix + unmanagedDllName + libraryNameVariation.Suffix; - foreach (string searchPath in searchPaths) - { - string libraryPath = Path.Combine(searchPath, libraryName); - if (File.Exists(libraryPath)) - { - return libraryPath; - } - } - } - - return null; - } - - private static string[] SplitPathsList(string? pathsList) - { - if (pathsList == null) - { - return Array.Empty(); - } - else - { - return pathsList.Split(Path.PathSeparator, StringSplitOptions.RemoveEmptyEntries); - } - } - -#if TARGET_WINDOWS - private const CharSet HostpolicyCharSet = CharSet.Unicode; -#else - private const CharSet HostpolicyCharSet = CharSet.Ansi; -#endif - - [UnmanagedFunctionPointer(CallingConvention.Cdecl, CharSet = HostpolicyCharSet)] - internal delegate void corehost_resolve_component_dependencies_result_fn( - string assembly_paths, - string native_search_paths, - string resource_search_paths); - - [UnmanagedFunctionPointer(CallingConvention.Cdecl, CharSet = HostpolicyCharSet)] - internal delegate void corehost_error_writer_fn( - string message); - -#pragma warning disable BCL0015 // Disable Pinvoke analyzer errors. - [DllImport("hostpolicy", CallingConvention = CallingConvention.Cdecl, CharSet = HostpolicyCharSet)] - private static extern int corehost_resolve_component_dependencies( - string component_main_assembly_path, - corehost_resolve_component_dependencies_result_fn result); - - [DllImport("hostpolicy", CallingConvention = CallingConvention.Cdecl, CharSet = HostpolicyCharSet)] - private static extern IntPtr corehost_set_error_writer(IntPtr error_writer); -#pragma warning restore - } -} diff --git a/src/System.Private.CoreLib/shared/System/Runtime/Loader/AssemblyLoadContext.cs b/src/System.Private.CoreLib/shared/System/Runtime/Loader/AssemblyLoadContext.cs index 9629fa428..c958169fe 100644 --- a/src/System.Private.CoreLib/shared/System/Runtime/Loader/AssemblyLoadContext.cs +++ b/src/System.Private.CoreLib/shared/System/Runtime/Loader/AssemblyLoadContext.cs @@ -14,6 +14,7 @@ namespace System.Runtime.Loader { public partial class AssemblyLoadContext { + // Keep in sync with MonoManagedAssemblyLoadContextInternalState in object-internals.h private enum InternalState { /// @@ -34,6 +35,7 @@ namespace System.Runtime.Loader #region private data members // If you modify any of these fields, you must also update the // AssemblyLoadContextBaseObject structure in object.h + // and MonoManagedAssemblyLoadContext in object-internals.h // synchronization primitive to protect against usage of this instance while unloading private readonly object _unloadLock; @@ -364,7 +366,7 @@ namespace System.Runtime.Loader byte[]? arrSymbols = null; if (assemblySymbols != null) { - var iSymbolLength = (int)assemblySymbols.Length; + int iSymbolLength = (int)assemblySymbols.Length; arrSymbols = new byte[iSymbolLength]; assemblySymbols.Read(arrSymbols, 0, iSymbolLength); @@ -562,16 +564,6 @@ namespace System.Runtime.Loader return context.ResolveUsingLoad(assemblyName); } - // This method is invoked by the VM to resolve an assembly reference using the Resolving event - // after trying assembly resolution via Load override and TPA load context without success. - private static Assembly? ResolveUsingResolvingEvent(IntPtr gchManagedAssemblyLoadContext, AssemblyName assemblyName) - { - AssemblyLoadContext context = (AssemblyLoadContext)(GCHandle.FromIntPtr(gchManagedAssemblyLoadContext).Target)!; - - // Invoke the AssemblyResolve event callbacks if wired up - return context.ResolveUsingEvent(assemblyName); - } - // This method is invoked by the VM to resolve a satellite assembly reference // after trying assembly resolution via Load override without success. private static Assembly? ResolveSatelliteAssembly(IntPtr gchManagedAssemblyLoadContext, AssemblyName assemblyName) diff --git a/src/System.Private.CoreLib/shared/System/Runtime/Loader/LibraryNameVariation.Unix.cs b/src/System.Private.CoreLib/shared/System/Runtime/Loader/LibraryNameVariation.Unix.cs index c63ff94ef..5521481f9 100644 --- a/src/System.Private.CoreLib/shared/System/Runtime/Loader/LibraryNameVariation.Unix.cs +++ b/src/System.Private.CoreLib/shared/System/Runtime/Loader/LibraryNameVariation.Unix.cs @@ -10,7 +10,7 @@ namespace System.Runtime.Loader internal partial struct LibraryNameVariation { private const string LibraryNamePrefix = "lib"; -#if TARGET_OSX +#if TARGET_OSX || TARGET_IOS || TARGET_TVOS private const string LibraryNameSuffix = ".dylib"; #else private const string LibraryNameSuffix = ".so"; diff --git a/src/System.Private.CoreLib/shared/System/Runtime/MemoryFailPoint.cs b/src/System.Private.CoreLib/shared/System/Runtime/MemoryFailPoint.cs index 191e2fed5..d6c29347d 100644 --- a/src/System.Private.CoreLib/shared/System/Runtime/MemoryFailPoint.cs +++ b/src/System.Private.CoreLib/shared/System/Runtime/MemoryFailPoint.cs @@ -14,7 +14,6 @@ ===========================================================*/ using System.Threading; -using System.Runtime.CompilerServices; using System.Runtime.ConstrainedExecution; using System.Diagnostics; @@ -235,10 +234,6 @@ namespace System.Runtime if (!needPageFile) continue; - // Attempt to grow the OS's page file. Note that we ignore - // any allocation routines from the host intentionally. - RuntimeHelpers.PrepareConstrainedRegions(); - // This shouldn't overflow due to the if clauses above. UIntPtr numBytes = new UIntPtr(segmentSize); GrowPageFileIfNecessaryAndPossible(numBytes); @@ -286,8 +281,6 @@ namespace System.Runtime if (LastKnownFreeAddressSpace < 0) CheckForFreeAddressSpace(segmentSize, true); - RuntimeHelpers.PrepareConstrainedRegions(); - AddMemoryFailPointReservation((long)size); _mustSubtractReservation = true; } @@ -317,8 +310,6 @@ namespace System.Runtime // within the GC heap. if (_mustSubtractReservation) { - RuntimeHelpers.PrepareConstrainedRegions(); - AddMemoryFailPointReservation(-((long)_reservedMemory)); _mustSubtractReservation = false; } diff --git a/src/System.Private.CoreLib/shared/System/Runtime/ProfileOptimization.cs b/src/System.Private.CoreLib/shared/System/Runtime/ProfileOptimization.cs index 31b0f6594..a45ea4372 100644 --- a/src/System.Private.CoreLib/shared/System/Runtime/ProfileOptimization.cs +++ b/src/System.Private.CoreLib/shared/System/Runtime/ProfileOptimization.cs @@ -13,7 +13,7 @@ namespace System.Runtime AssemblyLoadContext.Default.SetProfileOptimizationRoot(directoryPath); } - public static void StartProfile(string profile) + public static void StartProfile(string? profile) { AssemblyLoadContext.Default.StartProfileOptimization(profile); } diff --git a/src/System.Private.CoreLib/shared/System/Runtime/Serialization/SerializationInfo.cs b/src/System.Private.CoreLib/shared/System/Runtime/Serialization/SerializationInfo.cs index 4dea67019..6f0c39112 100644 --- a/src/System.Private.CoreLib/shared/System/Runtime/Serialization/SerializationInfo.cs +++ b/src/System.Private.CoreLib/shared/System/Runtime/Serialization/SerializationInfo.cs @@ -92,8 +92,7 @@ namespace System.Runtime.Serialization if (cachedValue == 0) { - bool isEnabled = false; - if (AppContext.TryGetSwitch(SwitchPrefix + switchSuffix, out isEnabled) && isEnabled) + if (AppContext.TryGetSwitch(SwitchPrefix + switchSuffix, out bool isEnabled) && isEnabled) { cachedValue = 1; } @@ -438,8 +437,7 @@ namespace System.Runtime.Serialization { throw new ArgumentNullException(nameof(name)); } - int index; - if (_nameToIndex.TryGetValue(name, out index)) + if (_nameToIndex.TryGetValue(name, out int index)) { return index; } @@ -497,8 +495,7 @@ namespace System.Runtime.Serialization if (!type.IsRuntimeImplemented()) throw new ArgumentException(SR.Argument_MustBeRuntimeType); - Type foundType; - object? value = GetElement(name, out foundType); + object? value = GetElement(name, out Type foundType); if (ReferenceEquals(foundType, type) || type.IsAssignableFrom(foundType) || value == null) { @@ -514,8 +511,7 @@ namespace System.Runtime.Serialization Debug.Assert((object)type != null, "[SerializationInfo.GetValue]type ==null"); Debug.Assert(type.IsRuntimeImplemented(), "[SerializationInfo.GetValue]type is not a runtime type"); - Type? foundType; - object? value = GetElementNoThrow(name, out foundType); + object? value = GetElementNoThrow(name, out Type? foundType); if (value == null) return null; @@ -531,111 +527,96 @@ namespace System.Runtime.Serialization public bool GetBoolean(string name) { - Type foundType; - object? value = GetElement(name, out foundType); + object? value = GetElement(name, out Type foundType); return ReferenceEquals(foundType, typeof(bool)) ? (bool)value! : _converter.ToBoolean(value!); // if value is null To* method will either deal with it or throw } public char GetChar(string name) { - Type foundType; - object? value = GetElement(name, out foundType); + object? value = GetElement(name, out Type foundType); return ReferenceEquals(foundType, typeof(char)) ? (char)value! : _converter.ToChar(value!); } [CLSCompliant(false)] public sbyte GetSByte(string name) { - Type foundType; - object? value = GetElement(name, out foundType); + object? value = GetElement(name, out Type foundType); return ReferenceEquals(foundType, typeof(sbyte)) ? (sbyte)value! : _converter.ToSByte(value!); } public byte GetByte(string name) { - Type foundType; - object? value = GetElement(name, out foundType); + object? value = GetElement(name, out Type foundType); return ReferenceEquals(foundType, typeof(byte)) ? (byte)value! : _converter.ToByte(value!); } public short GetInt16(string name) { - Type foundType; - object? value = GetElement(name, out foundType); + object? value = GetElement(name, out Type foundType); return ReferenceEquals(foundType, typeof(short)) ? (short)value! : _converter.ToInt16(value!); } [CLSCompliant(false)] public ushort GetUInt16(string name) { - Type foundType; - object? value = GetElement(name, out foundType); + object? value = GetElement(name, out Type foundType); return ReferenceEquals(foundType, typeof(ushort)) ? (ushort)value! : _converter.ToUInt16(value!); } public int GetInt32(string name) { - Type foundType; - object? value = GetElement(name, out foundType); + object? value = GetElement(name, out Type foundType); return ReferenceEquals(foundType, typeof(int)) ? (int)value! : _converter.ToInt32(value!); } [CLSCompliant(false)] public uint GetUInt32(string name) { - Type foundType; - object? value = GetElement(name, out foundType); + object? value = GetElement(name, out Type foundType); return ReferenceEquals(foundType, typeof(uint)) ? (uint)value! : _converter.ToUInt32(value!); } public long GetInt64(string name) { - Type foundType; - object? value = GetElement(name, out foundType); + object? value = GetElement(name, out Type foundType); return ReferenceEquals(foundType, typeof(long)) ? (long)value! : _converter.ToInt64(value!); } [CLSCompliant(false)] public ulong GetUInt64(string name) { - Type foundType; - object? value = GetElement(name, out foundType); + object? value = GetElement(name, out Type foundType); return ReferenceEquals(foundType, typeof(ulong)) ? (ulong)value! : _converter.ToUInt64(value!); } public float GetSingle(string name) { - Type foundType; - object? value = GetElement(name, out foundType); + object? value = GetElement(name, out Type foundType); return ReferenceEquals(foundType, typeof(float)) ? (float)value! : _converter.ToSingle(value!); } public double GetDouble(string name) { - Type foundType; - object? value = GetElement(name, out foundType); + object? value = GetElement(name, out Type foundType); return ReferenceEquals(foundType, typeof(double)) ? (double)value! : _converter.ToDouble(value!); } public decimal GetDecimal(string name) { - Type foundType; - object? value = GetElement(name, out foundType); + object? value = GetElement(name, out Type foundType); return ReferenceEquals(foundType, typeof(decimal)) ? (decimal)value! : _converter.ToDecimal(value!); } public DateTime GetDateTime(string name) { - Type foundType; - object? value = GetElement(name, out foundType); + object? value = GetElement(name, out Type foundType); return ReferenceEquals(foundType, typeof(DateTime)) ? (DateTime)value! : _converter.ToDateTime(value!); } public string? GetString(string name) { - Type foundType; - object? value = GetElement(name, out foundType); + object? value = GetElement(name, out Type foundType); return ReferenceEquals(foundType, typeof(string)) || value == null ? (string?)value : _converter.ToString(value); } } diff --git a/src/System.Private.CoreLib/shared/System/SByte.cs b/src/System.Private.CoreLib/shared/System/SByte.cs index 56184571e..47d993e92 100644 --- a/src/System.Private.CoreLib/shared/System/SByte.cs +++ b/src/System.Private.CoreLib/shared/System/SByte.cs @@ -2,6 +2,7 @@ // 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.Diagnostics.CodeAnalysis; using System.Globalization; using System.Runtime.CompilerServices; using System.Runtime.InteropServices; @@ -84,7 +85,7 @@ namespace System public string ToString(IFormatProvider? provider) { - return ToString(null, provider); + return Number.FormatInt32(m_value, 0, null, provider); } public string ToString(string? format, IFormatProvider? provider) @@ -97,14 +98,12 @@ namespace System return Number.TryFormatInt32(m_value, 0x000000FF, format, provider, destination, out charsWritten); } - [CLSCompliant(false)] public static sbyte Parse(string s) { if (s == null) ThrowHelper.ThrowArgumentNullException(ExceptionArgument.s); return Parse((ReadOnlySpan)s, NumberStyles.Integer, NumberFormatInfo.CurrentInfo); } - [CLSCompliant(false)] public static sbyte Parse(string s, NumberStyles style) { NumberFormatInfo.ValidateParseStyleInteger(style); @@ -112,7 +111,6 @@ namespace System return Parse((ReadOnlySpan)s, style, NumberFormatInfo.CurrentInfo); } - [CLSCompliant(false)] public static sbyte Parse(string s, IFormatProvider? provider) { if (s == null) ThrowHelper.ThrowArgumentNullException(ExceptionArgument.s); @@ -123,7 +121,6 @@ namespace System // a NumberFormatInfo isn't specified, the current culture's // NumberFormatInfo is assumed. // - [CLSCompliant(false)] public static sbyte Parse(string s, NumberStyles style, IFormatProvider? provider) { NumberFormatInfo.ValidateParseStyleInteger(style); @@ -131,7 +128,6 @@ namespace System return Parse((ReadOnlySpan)s, style, NumberFormatInfo.GetInstance(provider)); } - [CLSCompliant(false)] public static sbyte Parse(ReadOnlySpan s, NumberStyles style = NumberStyles.Integer, IFormatProvider? provider = null) { NumberFormatInfo.ValidateParseStyleInteger(style); @@ -155,8 +151,7 @@ namespace System return (sbyte)i; } - [CLSCompliant(false)] - public static bool TryParse(string? s, out sbyte result) + public static bool TryParse([NotNullWhen(true)] string? s, out sbyte result) { if (s == null) { @@ -167,14 +162,12 @@ namespace System return TryParse((ReadOnlySpan)s, NumberStyles.Integer, NumberFormatInfo.CurrentInfo, out result); } - [CLSCompliant(false)] public static bool TryParse(ReadOnlySpan s, out sbyte result) { return TryParse(s, NumberStyles.Integer, NumberFormatInfo.CurrentInfo, out result); } - [CLSCompliant(false)] - public static bool TryParse(string? s, NumberStyles style, IFormatProvider? provider, out sbyte result) + public static bool TryParse([NotNullWhen(true)] string? s, NumberStyles style, IFormatProvider? provider, out sbyte result) { NumberFormatInfo.ValidateParseStyleInteger(style); @@ -187,7 +180,6 @@ namespace System return TryParse((ReadOnlySpan)s, style, NumberFormatInfo.GetInstance(provider), out result); } - [CLSCompliant(false)] public static bool TryParse(ReadOnlySpan s, NumberStyles style, IFormatProvider? provider, out sbyte result) { NumberFormatInfo.ValidateParseStyleInteger(style); diff --git a/src/System.Private.CoreLib/shared/System/Security/Permissions/CodeAccessSecurityAttribute.cs b/src/System.Private.CoreLib/shared/System/Security/Permissions/CodeAccessSecurityAttribute.cs index a816f1d01..1a27b3b39 100644 --- a/src/System.Private.CoreLib/shared/System/Security/Permissions/CodeAccessSecurityAttribute.cs +++ b/src/System.Private.CoreLib/shared/System/Security/Permissions/CodeAccessSecurityAttribute.cs @@ -7,6 +7,6 @@ namespace System.Security.Permissions [AttributeUsage((AttributeTargets)(109), AllowMultiple = true, Inherited = false)] public abstract partial class CodeAccessSecurityAttribute : SecurityAttribute { - protected CodeAccessSecurityAttribute(SecurityAction action) : base(default(SecurityAction)) { } + protected CodeAccessSecurityAttribute(SecurityAction action) : base(default) { } } } diff --git a/src/System.Private.CoreLib/shared/System/Security/Permissions/SecurityPermissionAttribute.cs b/src/System.Private.CoreLib/shared/System/Security/Permissions/SecurityPermissionAttribute.cs index e1e74c416..2ec3057bb 100644 --- a/src/System.Private.CoreLib/shared/System/Security/Permissions/SecurityPermissionAttribute.cs +++ b/src/System.Private.CoreLib/shared/System/Security/Permissions/SecurityPermissionAttribute.cs @@ -7,7 +7,7 @@ namespace System.Security.Permissions [AttributeUsage((AttributeTargets)(109), AllowMultiple = true, Inherited = false)] public sealed partial class SecurityPermissionAttribute : CodeAccessSecurityAttribute { - public SecurityPermissionAttribute(SecurityAction action) : base(default(SecurityAction)) { } + public SecurityPermissionAttribute(SecurityAction action) : base(default) { } public bool Assertion { get; set; } public bool BindingRedirects { get; set; } public bool ControlAppDomain { get; set; } diff --git a/src/System.Private.CoreLib/shared/System/Security/Principal/TokenImpersonationLevel.cs b/src/System.Private.CoreLib/shared/System/Security/Principal/TokenImpersonationLevel.cs index 406342ba2..25b0e977e 100644 --- a/src/System.Private.CoreLib/shared/System/Security/Principal/TokenImpersonationLevel.cs +++ b/src/System.Private.CoreLib/shared/System/Security/Principal/TokenImpersonationLevel.cs @@ -2,8 +2,6 @@ // 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; - namespace System.Security.Principal { public enum TokenImpersonationLevel diff --git a/src/System.Private.CoreLib/shared/System/Security/SecureString.Unix.cs b/src/System.Private.CoreLib/shared/System/Security/SecureString.Unix.cs index d3fbd9b2b..ca17a8987 100644 --- a/src/System.Private.CoreLib/shared/System/Security/SecureString.Unix.cs +++ b/src/System.Private.CoreLib/shared/System/Security/SecureString.Unix.cs @@ -2,11 +2,6 @@ // 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.Diagnostics; -using System.Runtime; -using System.Runtime.InteropServices; -using System.Text; - namespace System.Security { // SecureString attempts to provide a defense-in-depth solution. diff --git a/src/System.Private.CoreLib/shared/System/Single.cs b/src/System.Private.CoreLib/shared/System/Single.cs index 157d57466..3ad8a59ba 100644 --- a/src/System.Private.CoreLib/shared/System/Single.cs +++ b/src/System.Private.CoreLib/shared/System/Single.cs @@ -11,6 +11,7 @@ ** ===========================================================*/ +using System.Diagnostics.CodeAnalysis; using System.Globalization; using System.Runtime.CompilerServices; using System.Runtime.InteropServices; @@ -313,7 +314,7 @@ namespace System return Number.ParseSingle(s, style, NumberFormatInfo.GetInstance(provider)); } - public static bool TryParse(string? s, out float result) + public static bool TryParse([NotNullWhen(true)] string? s, out float result) { if (s == null) { @@ -329,7 +330,7 @@ namespace System return TryParse(s, NumberStyles.Float | NumberStyles.AllowThousands, NumberFormatInfo.CurrentInfo, out result); } - public static bool TryParse(string? s, NumberStyles style, IFormatProvider? provider, out float result) + public static bool TryParse([NotNullWhen(true)] string? s, NumberStyles style, IFormatProvider? provider, out float result) { NumberFormatInfo.ValidateParseStyleFloatingPoint(style); diff --git a/src/System.Private.CoreLib/shared/System/SpanHelpers.Byte.cs b/src/System.Private.CoreLib/shared/System/SpanHelpers.Byte.cs index 4d84fd385..a657cebe4 100644 --- a/src/System.Private.CoreLib/shared/System/SpanHelpers.Byte.cs +++ b/src/System.Private.CoreLib/shared/System/SpanHelpers.Byte.cs @@ -13,8 +13,10 @@ using Internal.Runtime.CompilerServices; #pragma warning disable SA1121 // explicitly using type aliases instead of built-in types #if TARGET_64BIT using nuint = System.UInt64; +using nint = System.Int64; #else using nuint = System.UInt32; +using nint = System.Int32; #endif // TARGET_64BIT namespace System @@ -430,7 +432,7 @@ namespace System Debug.Assert(valueLength >= 0); if (valueLength == 0) - return 0; // A zero-length sequence is always treated as "found" at the start of the search space. + return searchSpaceLength; // A zero-length sequence is always treated as "found" at the end of the search space. byte valueHead = value; ref byte valueTail = ref Unsafe.Add(ref value, 1); @@ -1309,85 +1311,210 @@ namespace System // Optimized byte-based SequenceEquals. The "length" parameter for this one is declared a nuint rather than int as we also use it for types other than byte // where the length can exceed 2Gb once scaled by sizeof(T). - [MethodImpl(MethodImplOptions.AggressiveOptimization)] - public static unsafe bool SequenceEqual(ref byte first, ref byte second, nuint length) + public static bool SequenceEqual(ref byte first, ref byte second, nuint length) { - IntPtr offset = (IntPtr)0; // Use IntPtr for arithmetic to avoid unnecessary 64->32->64 truncations - IntPtr lengthToExamine = (IntPtr)(void*)length; - - if ((byte*)lengthToExamine >= (byte*)sizeof(UIntPtr)) + bool result; + // Use nint for arithmetic to avoid unnecessary 64->32->64 truncations + if (length >= sizeof(nuint)) { - // Only check that the ref is the same if buffers are large, and hence - // its worth avoiding doing unnecessary comparisons - if (Unsafe.AreSame(ref first, ref second)) - goto Equal; + // Conditional jmp foward to favor shorter lengths. (See comment at "Equal:" label) + // The longer lengths can make back the time due to branch misprediction + // better than shorter lengths. + goto Longer; + } - if (Vector.IsHardwareAccelerated && (byte*)lengthToExamine >= (byte*)Vector.Count) +#if TARGET_64BIT + // On 32-bit, this will always be true since sizeof(nuint) == 4 + if (length < sizeof(uint)) +#endif + { + uint differentBits = 0; + nuint offset = (length & 2); + if (offset != 0) { - lengthToExamine -= Vector.Count; - while ((byte*)lengthToExamine > (byte*)offset) + differentBits = LoadUShort(ref first); + differentBits -= LoadUShort(ref second); + } + if ((length & 1) != 0) + { + differentBits |= (uint)Unsafe.AddByteOffset(ref first, offset) - (uint)Unsafe.AddByteOffset(ref second, offset); + } + result = (differentBits == 0); + goto Result; + } +#if TARGET_64BIT + else + { + nuint offset = length - sizeof(uint); + uint differentBits = LoadUInt(ref first) - LoadUInt(ref second); + differentBits |= LoadUInt(ref first, offset) - LoadUInt(ref second, offset); + result = (differentBits == 0); + goto Result; + } +#endif + Longer: + // Only check that the ref is the same if buffers are large, + // and hence its worth avoiding doing unnecessary comparisons + if (!Unsafe.AreSame(ref first, ref second)) + { + // C# compiler inverts this test, making the outer goto the conditional jmp. + goto Vector; + } + + // This becomes a conditional jmp foward to not favor it. + goto Equal; + + Result: + return result; + // When the sequence is equal; which is the longest execution, we want it to determine that + // as fast as possible so we do not want the early outs to be "predicted not taken" branches. + Equal: + return true; + + Vector: + if (Sse2.IsSupported) + { + if (Avx2.IsSupported && length >= (nuint)Vector256.Count) + { + Vector256 vecResult; + nuint offset = 0; + nuint lengthToExamine = length - (nuint)Vector256.Count; + // Unsigned, so it shouldn't have overflowed larger than length (rather than negative) + Debug.Assert(lengthToExamine < length); + if (lengthToExamine != 0) + { + do + { + vecResult = Avx2.CompareEqual(LoadVector256(ref first, offset), LoadVector256(ref second, offset)); + if (Avx2.MoveMask(vecResult) != -1) + { + goto NotEqual; + } + offset += (nuint)Vector256.Count; + } while (lengthToExamine > offset); + } + + // Do final compare as Vector256.Count from end rather than start + vecResult = Avx2.CompareEqual(LoadVector256(ref first, lengthToExamine), LoadVector256(ref second, lengthToExamine)); + if (Avx2.MoveMask(vecResult) == -1) + { + // C# compiler inverts this test, making the outer goto the conditional jmp. + goto Equal; + } + + // This becomes a conditional jmp foward to not favor it. + goto NotEqual; + } + // Use Vector128.Size as Vector128.Count doesn't inline at R2R time + // https://github.com/dotnet/runtime/issues/32714 + else if (length >= Vector128.Size) + { + Vector128 vecResult; + nuint offset = 0; + nuint lengthToExamine = length - Vector128.Size; + // Unsigned, so it shouldn't have overflowed larger than length (rather than negative) + Debug.Assert(lengthToExamine < length); + if (lengthToExamine != 0) + { + do + { + // We use instrincs directly as .Equals calls .AsByte() which doesn't inline at R2R time + // https://github.com/dotnet/runtime/issues/32714 + vecResult = Sse2.CompareEqual(LoadVector128(ref first, offset), LoadVector128(ref second, offset)); + if (Sse2.MoveMask(vecResult) != 0xFFFF) + { + goto NotEqual; + } + offset += Vector128.Size; + } while (lengthToExamine > offset); + } + + // Do final compare as Vector128.Count from end rather than start + vecResult = Sse2.CompareEqual(LoadVector128(ref first, lengthToExamine), LoadVector128(ref second, lengthToExamine)); + if (Sse2.MoveMask(vecResult) == 0xFFFF) + { + // C# compiler inverts this test, making the outer goto the conditional jmp. + goto Equal; + } + + // This becomes a conditional jmp foward to not favor it. + goto NotEqual; + } + } + else if (Vector.IsHardwareAccelerated && length >= (nuint)Vector.Count) + { + nuint offset = 0; + nuint lengthToExamine = length - (nuint)Vector.Count; + // Unsigned, so it shouldn't have overflowed larger than length (rather than negative) + Debug.Assert(lengthToExamine < length); + if (lengthToExamine > 0) + { + do { if (LoadVector(ref first, offset) != LoadVector(ref second, offset)) { goto NotEqual; } - offset += Vector.Count; - } - return LoadVector(ref first, lengthToExamine) == LoadVector(ref second, lengthToExamine); + offset += (nuint)Vector.Count; + } while (lengthToExamine > offset); } - Debug.Assert((byte*)lengthToExamine >= (byte*)sizeof(UIntPtr)); - - lengthToExamine -= sizeof(UIntPtr); - while ((byte*)lengthToExamine > (byte*)offset) + // Do final compare as Vector.Count from end rather than start + if (LoadVector(ref first, lengthToExamine) == LoadVector(ref second, lengthToExamine)) { - if (LoadUIntPtr(ref first, offset) != LoadUIntPtr(ref second, offset)) - { - goto NotEqual; - } - offset += sizeof(UIntPtr); + // C# compiler inverts this test, making the outer goto the conditional jmp. + goto Equal; } - return LoadUIntPtr(ref first, lengthToExamine) == LoadUIntPtr(ref second, lengthToExamine); + + // This becomes a conditional jmp foward to not favor it. + goto NotEqual; } - Debug.Assert((byte*)lengthToExamine < (byte*)sizeof(UIntPtr)); - - // On 32-bit, this will never be true since sizeof(UIntPtr) == 4 #if TARGET_64BIT - if ((byte*)lengthToExamine >= (byte*)sizeof(int)) + if (Sse2.IsSupported) { - if (LoadInt(ref first, offset) != LoadInt(ref second, offset)) - { - goto NotEqual; - } - offset += sizeof(int); - lengthToExamine -= sizeof(int); + Debug.Assert(length <= sizeof(nuint) * 2); + + nuint offset = length - sizeof(nuint); + nuint differentBits = LoadNUInt(ref first) - LoadNUInt(ref second); + differentBits |= LoadNUInt(ref first, offset) - LoadNUInt(ref second, offset); + result = (differentBits == 0); + goto Result; } + else #endif - - if ((byte*)lengthToExamine >= (byte*)sizeof(short)) { - if (LoadShort(ref first, offset) != LoadShort(ref second, offset)) + Debug.Assert(length >= sizeof(nuint)); { - goto NotEqual; - } - offset += sizeof(short); - lengthToExamine -= sizeof(short); - } + nuint offset = 0; + nuint lengthToExamine = length - sizeof(nuint); + // Unsigned, so it shouldn't have overflowed larger than length (rather than negative) + Debug.Assert(lengthToExamine < length); + if (lengthToExamine > 0) + { + do + { + // Compare unsigned so not do a sign extend mov on 64 bit + if (LoadNUInt(ref first, offset) != LoadNUInt(ref second, offset)) + { + goto NotEqual; + } + offset += sizeof(nuint); + } while (lengthToExamine > offset); + } - if (lengthToExamine != IntPtr.Zero) - { - Debug.Assert((int)lengthToExamine == 1); - - if (Unsafe.AddByteOffset(ref first, offset) != Unsafe.AddByteOffset(ref second, offset)) - { - goto NotEqual; + // Do final compare as sizeof(nuint) from end rather than start + result = (LoadNUInt(ref first, lengthToExamine) == LoadNUInt(ref second, lengthToExamine)); + goto Result; } } - Equal: - return true; - NotEqual: // Workaround for https://github.com/dotnet/runtime/issues/8795 + // As there are so many true/false exit points the Jit will coalesce them to one location. + // We want them at the end so the conditional early exit jmps are all jmp forwards so the + // branch predictor in a uninitialized state will not take them e.g. + // - loops are conditional jmps backwards and predicted + // - exceptions are conditional fowards jmps and not predicted + NotEqual: return false; } @@ -1644,27 +1771,55 @@ namespace System 0x01ul << 48) + 1; [MethodImpl(MethodImplOptions.AggressiveInlining)] - private static unsafe short LoadShort(ref byte start, IntPtr offset) - => Unsafe.ReadUnaligned(ref Unsafe.AddByteOffset(ref start, offset)); + private static ushort LoadUShort(ref byte start) + => Unsafe.ReadUnaligned(ref start); [MethodImpl(MethodImplOptions.AggressiveInlining)] - private static unsafe int LoadInt(ref byte start, IntPtr offset) - => Unsafe.ReadUnaligned(ref Unsafe.AddByteOffset(ref start, offset)); + private static ushort LoadUShort(ref byte start, nuint offset) + => Unsafe.ReadUnaligned(ref Unsafe.AddByteOffset(ref start, offset)); [MethodImpl(MethodImplOptions.AggressiveInlining)] - private static unsafe UIntPtr LoadUIntPtr(ref byte start, IntPtr offset) + private static uint LoadUInt(ref byte start) + => Unsafe.ReadUnaligned(ref start); + + [MethodImpl(MethodImplOptions.AggressiveInlining)] + private static uint LoadUInt(ref byte start, nuint offset) + => Unsafe.ReadUnaligned(ref Unsafe.AddByteOffset(ref start, offset)); + + [MethodImpl(MethodImplOptions.AggressiveInlining)] + private static nuint LoadNUInt(ref byte start) + => Unsafe.ReadUnaligned(ref start); + + [MethodImpl(MethodImplOptions.AggressiveInlining)] + private static nuint LoadNUInt(ref byte start, nuint offset) + => Unsafe.ReadUnaligned(ref Unsafe.AddByteOffset(ref start, offset)); + + [MethodImpl(MethodImplOptions.AggressiveInlining)] + private static UIntPtr LoadUIntPtr(ref byte start, IntPtr offset) => Unsafe.ReadUnaligned(ref Unsafe.AddByteOffset(ref start, offset)); [MethodImpl(MethodImplOptions.AggressiveInlining)] - private static unsafe Vector LoadVector(ref byte start, IntPtr offset) + private static Vector LoadVector(ref byte start, IntPtr offset) => Unsafe.ReadUnaligned>(ref Unsafe.AddByteOffset(ref start, offset)); [MethodImpl(MethodImplOptions.AggressiveInlining)] - private static unsafe Vector128 LoadVector128(ref byte start, IntPtr offset) + private static Vector LoadVector(ref byte start, nuint offset) + => Unsafe.ReadUnaligned>(ref Unsafe.AddByteOffset(ref start, offset)); + + [MethodImpl(MethodImplOptions.AggressiveInlining)] + private static Vector128 LoadVector128(ref byte start, IntPtr offset) => Unsafe.ReadUnaligned>(ref Unsafe.AddByteOffset(ref start, offset)); [MethodImpl(MethodImplOptions.AggressiveInlining)] - private static unsafe Vector256 LoadVector256(ref byte start, IntPtr offset) + private static Vector128 LoadVector128(ref byte start, nuint offset) + => Unsafe.ReadUnaligned>(ref Unsafe.AddByteOffset(ref start, offset)); + + [MethodImpl(MethodImplOptions.AggressiveInlining)] + private static Vector256 LoadVector256(ref byte start, IntPtr offset) + => Unsafe.ReadUnaligned>(ref Unsafe.AddByteOffset(ref start, offset)); + + [MethodImpl(MethodImplOptions.AggressiveInlining)] + private static Vector256 LoadVector256(ref byte start, nuint offset) => Unsafe.ReadUnaligned>(ref Unsafe.AddByteOffset(ref start, offset)); [MethodImpl(MethodImplOptions.AggressiveInlining)] diff --git a/src/System.Private.CoreLib/shared/System/SpanHelpers.T.cs b/src/System.Private.CoreLib/shared/System/SpanHelpers.T.cs index 978f3cebb..4177c45b1 100644 --- a/src/System.Private.CoreLib/shared/System/SpanHelpers.T.cs +++ b/src/System.Private.CoreLib/shared/System/SpanHelpers.T.cs @@ -3,7 +3,6 @@ // See the LICENSE file in the project root for more information. using System.Diagnostics; -using System.Runtime.CompilerServices; using Internal.Runtime.CompilerServices; @@ -442,7 +441,7 @@ namespace System Debug.Assert(valueLength >= 0); if (valueLength == 0) - return 0; // A zero-length sequence is always treated as "found" at the start of the search space. + return searchSpaceLength; // A zero-length sequence is always treated as "found" at the end of the search space. T valueHead = value; ref T valueTail = ref Unsafe.Add(ref value, 1); diff --git a/src/System.Private.CoreLib/shared/System/String.Comparison.cs b/src/System.Private.CoreLib/shared/System/String.Comparison.cs index b664044be..5ceed67a5 100644 --- a/src/System.Private.CoreLib/shared/System/String.Comparison.cs +++ b/src/System.Private.CoreLib/shared/System/String.Comparison.cs @@ -929,5 +929,16 @@ namespace System return (CompareOptions)((int)comparisonType & (int)CompareOptions.IgnoreCase); } + + private static CompareOptions GetCompareOptionsFromOrdinalStringComparison(StringComparison comparisonType) + { + Debug.Assert(comparisonType == StringComparison.Ordinal || comparisonType == StringComparison.OrdinalIgnoreCase); + + // StringComparison.Ordinal (0x04) --> CompareOptions.Ordinal (0x4000_0000) + // StringComparison.OrdinalIgnoreCase (0x05) -> CompareOptions.OrdinalIgnoreCase (0x1000_0000) + + int ct = (int)comparisonType; + return (CompareOptions)((ct & -ct) << 28); // neg and shl + } } } diff --git a/src/System.Private.CoreLib/shared/System/String.Manipulation.cs b/src/System.Private.CoreLib/shared/System/String.Manipulation.cs index a15d9b999..2fe2781e2 100644 --- a/src/System.Private.CoreLib/shared/System/String.Manipulation.cs +++ b/src/System.Private.CoreLib/shared/System/String.Manipulation.cs @@ -968,7 +968,7 @@ namespace System public string Replace(string oldValue, string? newValue, bool ignoreCase, CultureInfo? culture) { - return ReplaceCore(oldValue, newValue, culture, ignoreCase ? CompareOptions.IgnoreCase : CompareOptions.None); + return ReplaceCore(oldValue, newValue, culture?.CompareInfo, ignoreCase ? CompareOptions.IgnoreCase : CompareOptions.None); } public string Replace(string oldValue, string? newValue, StringComparison comparisonType) @@ -977,78 +977,92 @@ namespace System { case StringComparison.CurrentCulture: case StringComparison.CurrentCultureIgnoreCase: - return ReplaceCore(oldValue, newValue, CultureInfo.CurrentCulture, GetCaseCompareOfComparisonCulture(comparisonType)); + return ReplaceCore(oldValue, newValue, CultureInfo.CurrentCulture.CompareInfo, GetCaseCompareOfComparisonCulture(comparisonType)); case StringComparison.InvariantCulture: case StringComparison.InvariantCultureIgnoreCase: - return ReplaceCore(oldValue, newValue, CultureInfo.InvariantCulture, GetCaseCompareOfComparisonCulture(comparisonType)); + return ReplaceCore(oldValue, newValue, CompareInfo.Invariant, GetCaseCompareOfComparisonCulture(comparisonType)); case StringComparison.Ordinal: return Replace(oldValue, newValue); case StringComparison.OrdinalIgnoreCase: - return ReplaceCore(oldValue, newValue, CultureInfo.InvariantCulture, CompareOptions.OrdinalIgnoreCase); + return ReplaceCore(oldValue, newValue, CompareInfo.Invariant, CompareOptions.OrdinalIgnoreCase); default: throw new ArgumentException(SR.NotSupported_StringComparison, nameof(comparisonType)); } } - private unsafe string ReplaceCore(string oldValue, string? newValue, CultureInfo? culture, CompareOptions options) + private string ReplaceCore(string oldValue, string? newValue, CompareInfo? ci, CompareOptions options) { - if (oldValue == null) + if (oldValue is null) + { throw new ArgumentNullException(nameof(oldValue)); + } + if (oldValue.Length == 0) + { throw new ArgumentException(SR.Argument_StringZeroLength, nameof(oldValue)); + } // If they asked to replace oldValue with a null, replace all occurrences - // with the empty string. - newValue ??= string.Empty; + // with the empty string. AsSpan() will normalize appropriately. + // + // If inner ReplaceCore method returns null, it means no substitutions were + // performed, so as an optimization we'll return the original string. + + return ReplaceCore(this, oldValue.AsSpan(), newValue.AsSpan(), ci ?? CultureInfo.CurrentCulture.CompareInfo, options) + ?? this; + } + + private static unsafe string? ReplaceCore(ReadOnlySpan searchSpace, ReadOnlySpan oldValue, ReadOnlySpan newValue, CompareInfo compareInfo, CompareOptions options) + { + Debug.Assert(!oldValue.IsEmpty); + Debug.Assert(compareInfo != null); - CultureInfo referenceCulture = culture ?? CultureInfo.CurrentCulture; var result = new ValueStringBuilder(stackalloc char[256]); - result.EnsureCapacity(this.Length); - - int startIndex = 0; - int index = 0; + result.EnsureCapacity(searchSpace.Length); int matchLength = 0; - bool hasDoneAnyReplacements = false; - CompareInfo ci = referenceCulture.CompareInfo; - do + while (true) { - index = ci.IndexOf(this, oldValue, startIndex, this.Length - startIndex, options, &matchLength); + int index = compareInfo.IndexOf(searchSpace, oldValue, &matchLength, options, fromBeginning: true); // There's the possibility that 'oldValue' has zero collation weight (empty string equivalent). // If this is the case, we behave as if there are no more substitutions to be made. - if (index >= 0 && matchLength > 0) + if (index < 0 || matchLength == 0) { - // append the unmodified portion of string - result.Append(this.AsSpan(startIndex, index - startIndex)); - - // append the replacement - result.Append(newValue); - - startIndex = index + matchLength; - hasDoneAnyReplacements = true; + break; } - else if (!hasDoneAnyReplacements) - { - // small optimization, - // if we have not done any replacements, - // we will return the original string - result.Dispose(); - return this; - } - else - { - result.Append(this.AsSpan(startIndex, this.Length - startIndex)); - } - } while (index >= 0); + // append the unmodified portion of search space + result.Append(searchSpace.Slice(0, index)); + + // append the replacement + result.Append(newValue); + + searchSpace = searchSpace.Slice(index + matchLength); + hasDoneAnyReplacements = true; + } + + // Didn't find 'oldValue' in the remaining search space, or the match + // consisted only of zero collation weight characters. As an optimization, + // if we have not yet performed any replacements, we'll save the + // allocation. + + if (!hasDoneAnyReplacements) + { + result.Dispose(); + return null; + } + + // Append what remains of the search space, then allocate the new string. + + result.Append(searchSpace); return result.ToString(); } diff --git a/src/System.Private.CoreLib/shared/System/String.Searching.cs b/src/System.Private.CoreLib/shared/System/String.Searching.cs index e80cd4341..77162ee23 100644 --- a/src/System.Private.CoreLib/shared/System/String.Searching.cs +++ b/src/System.Private.CoreLib/shared/System/String.Searching.cs @@ -219,6 +219,85 @@ namespace System charMap[value & PROBABILISTICMAP_BLOCK_INDEX_MASK] |= 1u << (value >> PROBABILISTICMAP_BLOCK_INDEX_SHIFT); } + /* + * IndexOf, LastIndexOf, Contains, StartsWith, and EndsWith + * ======================================================== + * + * Given a search string 'searchString', a target string 'value' to locate within the search string, and a comparer + * 'comparer', the comparer will return a set S of tuples '(startPos, endPos)' for which the below expression + * returns true: + * + * >> bool result = searchString.Substring(startPos, endPos - startPos).Equals(value, comparer); + * + * If the set S is empty (i.e., there is no combination of values 'startPos' and 'endPos' which makes the + * above expression evaluate to true), then we say "'searchString' does not contain 'value'", and the expression + * "searchString.Contains(value, comparer)" should evaluate to false. If the set S is non-empty, then we say + * "'searchString' contains 'value'", and the expression "searchString.Contains(value, comparer)" should + * evaluate to true. + * + * Given a 'searchString', 'value', and 'comparer', the behavior of the IndexOf method is that it finds the + * smallest possible 'endPos' for which there exists any corresponding 'startPos' which makes the above + * expression evaluate to true, then it returns any 'startPos' within that subset. For example: + * + * let searchString = "hihi" (where = U+200D ZERO WIDTH JOINER, a weightless code point) + * let value = "hi" + * let comparer = a linguistic culture-invariant comparer (e.g., StringComparison.InvariantCulture) + * then S = { (0, 4), (1, 4), (2, 4), (4, 6) } + * so the expression "hihi".IndexOf("hi", comparer) can evaluate to any of { 0, 1, 2 }. + * + * n.b. ordinal comparers (e.g., StringComparison.Ordinal and StringComparison.OrdinalIgnoreCase) do not + * exhibit this ambiguity, as any given 'startPos' or 'endPos' will appear at most exactly once across + * all entries from set S. With the above example, S = { (2, 4), (4, 6) }, so IndexOf = 2 unambiguously. + * + * There exists a relationship between IndexOf and StartsWith. If there exists in set S any entry with + * the tuple values (startPos = 0, endPos = ), we say "'searchString' starts with 'value'", and + * the expression "searchString.StartsWith(value, comparer)" should evaluate to true. If there exists + * no such entry in set S, then we say "'searchString' does not start with 'value'", and the expression + * "searchString.StartsWith(value, comparer)" should evaluate to false. + * + * LastIndexOf and EndsWith have a similar relationship as IndexOf and StartsWith. The behavior of the + * LastIndexOf method is that it finds the largest possible 'endPos' for which there exists any corresponding + * 'startPos' which makes the expression evaluate to true, then it returns any 'startPos' within that + * subset. For example: + * + * let searchString = "hihi" (this is slightly modified from the earlier example) + * let value = "hi" + * let comparer = StringComparison.InvariantCulture + * then S = { (0, 2), (0, 3), (0, 4), (2, 6), (3, 6), (4, 6) } + * so the expression "hihi".LastIndexOf("hi", comparer) can evaluate to any of { 2, 3, 4 }. + * + * If there exists in set S any entry with the tuple values (startPos = , endPos = searchString.Length), + * we say "'searchString' ends with 'value'", and the expression "searchString.EndsWith(value, comparer)" + * should evaluate to true. If there exists no such entry in set S, then we say "'searchString' does not + * start with 'value'", and the expression "searchString.EndsWith(value, comparer)" should evaluate to false. + * + * There are overloads of IndexOf and LastIndexOf which take an offset and length in order to constrain the + * search space to a substring of the original search string. + * + * For LastIndexOf specifially, overloads which take a 'startIndex' and 'count' behave differently + * than their IndexOf counterparts. 'startIndex' is the index of the last char element that should + * be considered when performing the search. For example, if startIndex = 4, then the caller is + * indicating "when finding the match I want you to include the char element at index 4, but not + * any char elements past that point." + * + * idx = 0123456 ("abcdefg".Length = 7) + * So, if the search string is "abcdefg", startIndex = 5 and count = 3, then the search space will + * ~~~ be the substring "def", as highlighted to the left. + * Essentially: "the search space should be of length 3 chars and should end *just after* the char + * element at index 5." + * + * Since this behavior can introduce off-by-one errors in the boundary cases, we allow startIndex = -1 + * with a zero-length 'searchString' (treated as equivalent to startIndex = 0), and we allow + * startIndex = searchString.Length (treated as equivalent to startIndex = searchString.Length - 1). + * + * Note also that this behavior can introduce errors when dealing with UTF-16 surrogate pairs. + * If the search string is the 3 chars "[BMP][HI][LO]", startIndex = 1 and count = 2, then the + * ~~~~~~~~~ search space wil be the substring "[BMP][ HI]". + * This means that the char [HI] is incorrectly seen as a standalone high surrogate, which could + * lead to incorrect matching behavior, or it could cause LastIndexOf to incorrectly report that + * a zero-weight character could appear between the [HI] and [LO] chars. + */ + public int IndexOf(string value) { return IndexOf(value, StringComparison.CurrentCulture); @@ -231,16 +310,6 @@ namespace System public int IndexOf(string value, int startIndex, int count) { - if (startIndex < 0 || startIndex > this.Length) - { - throw new ArgumentOutOfRangeException(nameof(startIndex), SR.ArgumentOutOfRange_Index); - } - - if (count < 0 || count > this.Length - startIndex) - { - throw new ArgumentOutOfRangeException(nameof(count), SR.ArgumentOutOfRange_Count); - } - return IndexOf(value, startIndex, count, StringComparison.CurrentCulture); } @@ -256,26 +325,7 @@ namespace System public int IndexOf(string value, int startIndex, int count, StringComparison comparisonType) { - // Validate inputs - if (value == null) - throw new ArgumentNullException(nameof(value)); - - if (startIndex < 0 || startIndex > this.Length) - throw new ArgumentOutOfRangeException(nameof(startIndex), SR.ArgumentOutOfRange_Index); - - if (count < 0 || startIndex > this.Length - count) - throw new ArgumentOutOfRangeException(nameof(count), SR.ArgumentOutOfRange_Count); - - if (comparisonType == StringComparison.Ordinal) - { - int result = SpanHelpers.IndexOf( - ref Unsafe.Add(ref this._firstChar, startIndex), - count, - ref value._firstChar, - value.Length); - - return (result >= 0 ? startIndex : 0) + result; - } + // Parameter checking will be done by CompareInfo.IndexOf. switch (comparisonType) { @@ -287,11 +337,14 @@ namespace System case StringComparison.InvariantCultureIgnoreCase: return CompareInfo.Invariant.IndexOf(this, value, startIndex, count, GetCaseCompareOfComparisonCulture(comparisonType)); + case StringComparison.Ordinal: case StringComparison.OrdinalIgnoreCase: - return CompareInfo.IndexOfOrdinal(this, value, startIndex, count, GetCaseCompareOfComparisonCulture(comparisonType) != CompareOptions.None); + return CompareInfo.Invariant.IndexOf(this, value, startIndex, count, GetCompareOptionsFromOrdinalStringComparison(comparisonType)); default: - throw new ArgumentException(SR.NotSupported_StringComparison, nameof(comparisonType)); + throw (value is null) + ? new ArgumentNullException(nameof(value)) + : new ArgumentException(SR.NotSupported_StringComparison, nameof(comparisonType)); } } @@ -419,11 +472,6 @@ namespace System public int LastIndexOf(string value, int startIndex, int count) { - if (count < 0) - { - throw new ArgumentOutOfRangeException(nameof(count), SR.ArgumentOutOfRange_Count); - } - return LastIndexOf(value, startIndex, count, StringComparison.CurrentCulture); } @@ -439,32 +487,7 @@ namespace System public int LastIndexOf(string value, int startIndex, int count, StringComparison comparisonType) { - if (value == null) - throw new ArgumentNullException(nameof(value)); - - // Special case for 0 length input strings - if (this.Length == 0 && (startIndex == -1 || startIndex == 0)) - return (value.Length == 0) ? 0 : -1; - - // Now after handling empty strings, make sure we're not out of range - if (startIndex < 0 || startIndex > this.Length) - throw new ArgumentOutOfRangeException(nameof(startIndex), SR.ArgumentOutOfRange_Index); - - // Make sure that we allow startIndex == this.Length - if (startIndex == this.Length) - { - startIndex--; - if (count > 0) - count--; - } - - // 2nd half of this also catches when startIndex == MAXINT, so MAXINT - 0 + 1 == -1, which is < 0. - if (count < 0 || startIndex - count + 1 < 0) - throw new ArgumentOutOfRangeException(nameof(count), SR.ArgumentOutOfRange_Count); - - // If we are looking for nothing, just return startIndex - if (value.Length == 0) - return startIndex; + // Parameter checking will be done by CompareInfo.LastIndexOf. switch (comparisonType) { @@ -478,10 +501,12 @@ namespace System case StringComparison.Ordinal: case StringComparison.OrdinalIgnoreCase: - return CompareInfo.LastIndexOfOrdinal(this, value, startIndex, count, GetCaseCompareOfComparisonCulture(comparisonType) != CompareOptions.None); + return CompareInfo.Invariant.LastIndexOf(this, value, startIndex, count, GetCompareOptionsFromOrdinalStringComparison(comparisonType)); default: - throw new ArgumentException(SR.NotSupported_StringComparison, nameof(comparisonType)); + throw (value is null) + ? new ArgumentNullException(nameof(value)) + : new ArgumentException(SR.NotSupported_StringComparison, nameof(comparisonType)); } } diff --git a/src/System.Private.CoreLib/shared/System/String.cs b/src/System.Private.CoreLib/shared/System/String.cs index ec6fc18d8..00582d5eb 100644 --- a/src/System.Private.CoreLib/shared/System/String.cs +++ b/src/System.Private.CoreLib/shared/System/String.cs @@ -49,10 +49,11 @@ namespace System [PreserveDependency("Ctor(System.Char[])", "System.String")] public extern String(char[]? value); + private #if !CORECLR static #endif - private string Ctor(char[]? value) + string Ctor(char[]? value) { if (value == null || value.Length == 0) return Empty; @@ -71,10 +72,11 @@ namespace System [PreserveDependency("Ctor(System.Char[],System.Int32,System.Int32)", "System.String")] public extern String(char[] value, int startIndex, int length); + private #if !CORECLR static #endif - private string Ctor(char[] value, int startIndex, int length) + string Ctor(char[] value, int startIndex, int length) { if (value == null) throw new ArgumentNullException(nameof(value)); @@ -106,10 +108,11 @@ namespace System [PreserveDependency("Ctor(System.Char*)", "System.String")] public extern unsafe String(char* value); + private #if !CORECLR static #endif - private unsafe string Ctor(char* ptr) + unsafe string Ctor(char* ptr) { if (ptr == null) return Empty; @@ -133,10 +136,11 @@ namespace System [PreserveDependency("Ctor(System.Char*,System.Int32,System.Int32)", "System.String")] public extern unsafe String(char* value, int startIndex, int length); + private #if !CORECLR static #endif - private unsafe string Ctor(char* ptr, int startIndex, int length) + unsafe string Ctor(char* ptr, int startIndex, int length) { if (length < 0) throw new ArgumentOutOfRangeException(nameof(length), SR.ArgumentOutOfRange_NegativeLength); @@ -171,10 +175,11 @@ namespace System [PreserveDependency("Ctor(System.SByte*)", "System.String")] public extern unsafe String(sbyte* value); + private #if !CORECLR static #endif - private unsafe string Ctor(sbyte* value) + unsafe string Ctor(sbyte* value) { byte* pb = (byte*)value; if (pb == null) @@ -190,10 +195,11 @@ namespace System [PreserveDependency("Ctor(System.SByte*,System.Int32,System.Int32)", "System.String")] public extern unsafe String(sbyte* value, int startIndex, int length); + private #if !CORECLR static #endif - private unsafe string Ctor(sbyte* value, int startIndex, int length) + unsafe string Ctor(sbyte* value, int startIndex, int length) { if (startIndex < 0) throw new ArgumentOutOfRangeException(nameof(startIndex), SR.ArgumentOutOfRange_StartIndex); @@ -250,10 +256,11 @@ namespace System [PreserveDependency("Ctor(System.SByte*,System.Int32,System.Int32,System.Text.Encoding)", "System.String")] public extern unsafe String(sbyte* value, int startIndex, int length, Encoding enc); + private #if !CORECLR static #endif - private unsafe string Ctor(sbyte* value, int startIndex, int length, Encoding? enc) + unsafe string Ctor(sbyte* value, int startIndex, int length, Encoding? enc) { if (enc == null) return new string(value, startIndex, length); @@ -285,10 +292,11 @@ namespace System [PreserveDependency("Ctor(System.Char,System.Int32)", "System.String")] public extern String(char c, int count); + private #if !CORECLR static #endif - private string Ctor(char c, int count) + string Ctor(char c, int count) { if (count <= 0) { @@ -335,10 +343,11 @@ namespace System [PreserveDependency("Ctor(System.ReadOnlySpan`1)", "System.String")] public extern String(ReadOnlySpan value); + private #if !CORECLR static #endif - private unsafe string Ctor(ReadOnlySpan value) + unsafe string Ctor(ReadOnlySpan value) { if (value.Length == 0) return Empty; @@ -369,6 +378,28 @@ namespace System public static implicit operator ReadOnlySpan(string? value) => value != null ? new ReadOnlySpan(ref value.GetRawStringData(), value.Length) : default; + [MethodImpl(MethodImplOptions.AggressiveInlining)] + internal bool TryGetSpan(int startIndex, int count, out ReadOnlySpan slice) + { +#if TARGET_64BIT + // See comment in Span.Slice for how this works. + if ((ulong)(uint)startIndex + (ulong)(uint)count > (ulong)(uint)Length) + { + slice = default; + return false; + } +#else + if ((uint)startIndex > (uint)Length || (uint)count > (uint)(Length - startIndex)) + { + slice = default; + return false; + } +#endif + + slice = new ReadOnlySpan(ref Unsafe.Add(ref _firstChar, startIndex), count); + return true; + } + public object Clone() { return this; diff --git a/src/System.Private.CoreLib/shared/System/Text/ASCIIUtility.cs b/src/System.Private.CoreLib/shared/System/Text/ASCIIUtility.cs index b1f59d3b4..c0bdbf03f 100644 --- a/src/System.Private.CoreLib/shared/System/Text/ASCIIUtility.cs +++ b/src/System.Private.CoreLib/shared/System/Text/ASCIIUtility.cs @@ -7,9 +7,13 @@ using System.Numerics; using System.Runtime.CompilerServices; using System.Runtime.Intrinsics; using System.Runtime.Intrinsics.X86; + +#if SYSTEM_PRIVATE_CORELIB using Internal.Runtime.CompilerServices; +#endif #pragma warning disable SA1121 // explicitly using type aliases instead of built-in types +#if SYSTEM_PRIVATE_CORELIB #if TARGET_64BIT using nint = System.Int64; using nuint = System.UInt64; @@ -17,18 +21,22 @@ using nuint = System.UInt64; using nint = System.Int32; using nuint = System.UInt32; #endif // TARGET_64BIT +#else +using nint = System.Int64; // https://github.com/dotnet/runtime/issues/33575 - use long/ulong outside of corelib until the compiler supports it +using nuint = System.UInt64; +#endif namespace System.Text { internal static partial class ASCIIUtility { -#if DEBUG +#if DEBUG && SYSTEM_PRIVATE_CORELIB static ASCIIUtility() { Debug.Assert(sizeof(nint) == IntPtr.Size && nint.MinValue < 0, "nint is defined incorrectly."); Debug.Assert(sizeof(nuint) == IntPtr.Size && nuint.MinValue == 0, "nuint is defined incorrectly."); } -#endif // DEBUG +#endif // DEBUG && SYSTEM_PRIVATE_CORELIB [MethodImpl(MethodImplOptions.AggressiveInlining)] private static bool AllBytesInUInt64AreAscii(ulong value) diff --git a/src/System.Private.CoreLib/shared/System/Text/DecoderFallback.cs b/src/System.Private.CoreLib/shared/System/Text/DecoderFallback.cs index fda5edce1..2afc5bd27 100644 --- a/src/System.Private.CoreLib/shared/System/Text/DecoderFallback.cs +++ b/src/System.Private.CoreLib/shared/System/Text/DecoderFallback.cs @@ -242,9 +242,8 @@ namespace System.Text // as a surrogate pair. If that still fails, throw an exception since the fallback // mechanism is giving us a bad replacement character. - Rune rune; char ch = GetNextChar(); - if (!Rune.TryCreate(ch, out rune) && !Rune.TryCreate(ch, GetNextChar(), out rune)) + if (!Rune.TryCreate(ch, out Rune rune) && !Rune.TryCreate(ch, GetNextChar(), out rune)) { throw new ArgumentException(SR.Argument_InvalidCharSequenceNoIndex); } diff --git a/src/System.Private.CoreLib/shared/System/Text/EncoderNLS.cs b/src/System.Private.CoreLib/shared/System/Text/EncoderNLS.cs index 5135bc0be..bea5bf2ce 100644 --- a/src/System.Private.CoreLib/shared/System/Text/EncoderNLS.cs +++ b/src/System.Private.CoreLib/shared/System/Text/EncoderNLS.cs @@ -366,27 +366,33 @@ namespace System.Text secondChar = chars[0]; } + // We're about to consume the leftover char. Make a local copy of it and clear + // the backing field. We don't bother restoring its value if an exception occurs + // because exceptional code paths corrupt instance state anyway (e.g., by + // mutating the fallback buffer contents). + + char charLeftOver = _charLeftOver; + _charLeftOver = default; + // If we have to fallback the chars we're reading immediately below, populate the // fallback buffer with the invalid data. We'll just fall through to the "consume // fallback buffer" logic at the end of the method. - if (Rune.TryCreate(_charLeftOver, secondChar, out Rune rune)) + if (Rune.TryCreate(charLeftOver, secondChar, out Rune rune)) { charsConsumed = 1; // at the very least, we consumed 1 char from the input Debug.Assert(_encoding != null); switch (_encoding.EncodeRune(rune, bytes, out bytesWritten)) { case OperationStatus.Done: - _charLeftOver = default; // we just consumed this char return true; // that's all - we've handled the leftover data case OperationStatus.DestinationTooSmall: - _charLeftOver = default; // we just consumed this char _encoding.ThrowBytesOverflow(this, nothingEncoded: true); // will throw break; case OperationStatus.InvalidData: - FallbackBuffer.Fallback(_charLeftOver, secondChar, index: -1); // see comment in DrainLeftoverDataForGetByteCount + FallbackBuffer.Fallback(charLeftOver, secondChar, index: -1); // see comment in DrainLeftoverDataForGetByteCount break; default: @@ -396,7 +402,7 @@ namespace System.Text } else { - FallbackBuffer.Fallback(_charLeftOver, index: -1); // see comment in DrainLeftoverDataForGetByteCount + FallbackBuffer.Fallback(charLeftOver, index: -1); // see comment in DrainLeftoverDataForGetByteCount } } diff --git a/src/System.Private.CoreLib/shared/System/Text/Rune.cs b/src/System.Private.CoreLib/shared/System/Text/Rune.cs index fd3ac737e..b2cbe18b0 100644 --- a/src/System.Private.CoreLib/shared/System/Text/Rune.cs +++ b/src/System.Private.CoreLib/shared/System/Text/Rune.cs @@ -20,6 +20,13 @@ namespace System.Text [DebuggerDisplay("{DebuggerDisplay,nq}")] public readonly struct Rune : IComparable, IEquatable { + internal const int MaxUtf16CharsPerRune = 2; // supplementary plane code points are encoded as 2 UTF-16 code units + internal const int MaxUtf8BytesPerRune = 4; // supplementary plane code points are encoded as 4 UTF-8 code units + + private const char HighSurrogateStart = '\ud800'; + private const char LowSurrogateStart = '\udc00'; + private const int HighSurrogateRange = 0x3FF; + private const byte IsWhiteSpaceFlag = 0x80; private const byte IsLetterOrDigitFlag = 0x40; private const byte UnicodeCategoryMask = 0x1F; @@ -159,7 +166,15 @@ namespace System.Text /// /// The return value will be 1 or 2. /// - public int Utf16SequenceLength => UnicodeUtility.GetUtf16SequenceLength(_value); + public int Utf16SequenceLength + { + get + { + int codeUnitCount = UnicodeUtility.GetUtf16SequenceLength(_value); + Debug.Assert(codeUnitCount > 0 && codeUnitCount <= MaxUtf16CharsPerRune); + return codeUnitCount; + } + } /// /// Returns the length in code units of the @@ -168,20 +183,29 @@ namespace System.Text /// /// The return value will be 1 through 4, inclusive. /// - public int Utf8SequenceLength => UnicodeUtility.GetUtf8SequenceLength(_value); + public int Utf8SequenceLength + { + get + { + int codeUnitCount = UnicodeUtility.GetUtf8SequenceLength(_value); + Debug.Assert(codeUnitCount > 0 && codeUnitCount <= MaxUtf8BytesPerRune); + return codeUnitCount; + } + } /// /// Returns the Unicode scalar value as an integer. /// public int Value => (int)_value; +#if SYSTEM_PRIVATE_CORELIB private static Rune ChangeCaseCultureAware(Rune rune, TextInfo textInfo, bool toUpper) { Debug.Assert(!GlobalizationMode.Invariant, "This should've been checked by the caller."); Debug.Assert(textInfo != null, "This should've been checked by the caller."); - Span original = stackalloc char[2]; // worst case scenario = 2 code units (for a surrogate pair) - Span modified = stackalloc char[2]; // case change should preserve UTF-16 code unit count + Span original = stackalloc char[MaxUtf16CharsPerRune]; + Span modified = stackalloc char[MaxUtf16CharsPerRune]; int charCount = rune.EncodeToUtf16(original); original = original.Slice(0, charCount); @@ -209,6 +233,42 @@ namespace System.Text return UnsafeCreate(UnicodeUtility.GetScalarFromUtf16SurrogatePair(modified[0], modified[1])); } } +#else + private static Rune ChangeCaseCultureAware(Rune rune, CultureInfo culture, bool toUpper) + { + Debug.Assert(!GlobalizationMode.Invariant, "This should've been checked by the caller."); + Debug.Assert(culture != null, "This should've been checked by the caller."); + + Span original = stackalloc char[MaxUtf16CharsPerRune]; // worst case scenario = 2 code units (for a surrogate pair) + Span modified = stackalloc char[MaxUtf16CharsPerRune]; // case change should preserve UTF-16 code unit count + + int charCount = rune.EncodeToUtf16(original); + original = original.Slice(0, charCount); + modified = modified.Slice(0, charCount); + + if (toUpper) + { + MemoryExtensions.ToUpper(original, modified, culture); + } + else + { + MemoryExtensions.ToLower(original, modified, culture); + } + + // We use simple case folding rules, which disallows moving between the BMP and supplementary + // planes when performing a case conversion. The helper methods which reconstruct a Rune + // contain debug asserts for this condition. + + if (rune.IsBmp) + { + return UnsafeCreate(modified[0]); + } + else + { + return UnsafeCreate(UnicodeUtility.GetScalarFromUtf16SurrogatePair(modified[0], modified[1])); + } + } +#endif public int CompareTo(Rune other) => _value.CompareTo(other._value); @@ -827,6 +887,7 @@ namespace System.Text /// public override string ToString() { +#if SYSTEM_PRIVATE_CORELIB if (IsBmp) { return string.CreateFromChar((char)_value); @@ -836,6 +897,18 @@ namespace System.Text UnicodeUtility.GetUtf16SurrogatesFromSupplementaryPlaneScalar(_value, out char high, out char low); return string.CreateFromChar(high, low); } +#else + if (IsBmp) + { + return ((char)_value).ToString(); + } + else + { + Span buffer = stackalloc char[MaxUtf16CharsPerRune]; + UnicodeUtility.GetUtf16SurrogatesFromSupplementaryPlaneScalar(_value, out buffer[0], out buffer[1]); + return buffer.ToString(); + } +#endif } /// @@ -865,17 +938,17 @@ namespace System.Text // First, extend both to 32 bits, then calculate the offset of // each candidate surrogate char from the start of its range. - uint highSurrogateOffset = (uint)highSurrogate - CharUnicodeInfo.HIGH_SURROGATE_START; - uint lowSurrogateOffset = (uint)lowSurrogate - CharUnicodeInfo.LOW_SURROGATE_START; + uint highSurrogateOffset = (uint)highSurrogate - HighSurrogateStart; + uint lowSurrogateOffset = (uint)lowSurrogate - LowSurrogateStart; // This is a single comparison which allows us to check both for validity at once since // both the high surrogate range and the low surrogate range are the same length. // If the comparison fails, we call to a helper method to throw the correct exception message. - if ((highSurrogateOffset | lowSurrogateOffset) <= CharUnicodeInfo.HIGH_SURROGATE_RANGE) + if ((highSurrogateOffset | lowSurrogateOffset) <= HighSurrogateRange) { // The 0x40u << 10 below is to account for uuuuu = wwww + 1 in the surrogate encoding. - result = UnsafeCreate((highSurrogateOffset << 10) + ((uint)lowSurrogate - CharUnicodeInfo.LOW_SURROGATE_START) + (0x40u << 10)); + result = UnsafeCreate((highSurrogateOffset << 10) + ((uint)lowSurrogate - LowSurrogateStart) + (0x40u << 10)); return true; } else @@ -1070,7 +1143,15 @@ namespace System.Text else { // not an ASCII char; fall back to globalization table +#if SYSTEM_PRIVATE_CORELIB return CharUnicodeInfo.GetNumericValue(value.Value); +#else + if (value.IsBmp) + { + return CharUnicodeInfo.GetNumericValue((char)value._value); + } + return CharUnicodeInfo.GetNumericValue(value.ToString(), 0); +#endif } } @@ -1089,7 +1170,15 @@ namespace System.Text private static UnicodeCategory GetUnicodeCategoryNonAscii(Rune value) { Debug.Assert(!value.IsAscii, "Shouldn't use this non-optimized code path for ASCII characters."); +#if !NETSTANDARD2_0 return CharUnicodeInfo.GetUnicodeCategory(value.Value); +#else + if (value.IsBmp) + { + return CharUnicodeInfo.GetUnicodeCategory((char)value._value); + } + return CharUnicodeInfo.GetUnicodeCategory(value.ToString(), 0); +#endif } // Returns true iff this Unicode category represents a letter @@ -1240,7 +1329,12 @@ namespace System.Text // Only BMP code points can be white space, so only call into CharUnicodeInfo // if the incoming value is within the BMP. - return value.IsBmp && CharUnicodeInfo.GetIsWhiteSpace((char)value._value); + return value.IsBmp && +#if SYSTEM_PRIVATE_CORELIB + CharUnicodeInfo.GetIsWhiteSpace((char)value._value); +#else + char.IsWhiteSpace((char)value._value); +#endif } public static Rune ToLower(Rune value, CultureInfo culture) @@ -1259,7 +1353,11 @@ namespace System.Text return ToLowerInvariant(value); } - return ChangeCaseCultureAware(value, culture!.TextInfo, toUpper: false); +#if SYSTEM_PRIVATE_CORELIB + return ChangeCaseCultureAware(value, culture.TextInfo, toUpper: false); +#else + return ChangeCaseCultureAware(value, culture, toUpper: false); +#endif } public static Rune ToLowerInvariant(Rune value) @@ -1283,7 +1381,11 @@ namespace System.Text // Non-ASCII data requires going through the case folding tables. +#if SYSTEM_PRIVATE_CORELIB return ChangeCaseCultureAware(value, TextInfo.Invariant, toUpper: false); +#else + return ChangeCaseCultureAware(value, CultureInfo.InvariantCulture, toUpper: false); +#endif } public static Rune ToUpper(Rune value, CultureInfo culture) @@ -1302,7 +1404,11 @@ namespace System.Text return ToUpperInvariant(value); } - return ChangeCaseCultureAware(value, culture!.TextInfo, toUpper: true); +#if SYSTEM_PRIVATE_CORELIB + return ChangeCaseCultureAware(value, culture.TextInfo, toUpper: true); +#else + return ChangeCaseCultureAware(value, culture, toUpper: true); +#endif } public static Rune ToUpperInvariant(Rune value) @@ -1326,7 +1432,11 @@ namespace System.Text // Non-ASCII data requires going through the case folding tables. +#if SYSTEM_PRIVATE_CORELIB return ChangeCaseCultureAware(value, TextInfo.Invariant, toUpper: true); +#else + return ChangeCaseCultureAware(value, CultureInfo.InvariantCulture, toUpper: true); +#endif } } } diff --git a/src/System.Private.CoreLib/shared/System/Text/StringBuilder.cs b/src/System.Private.CoreLib/shared/System/Text/StringBuilder.cs index 338b29557..1b18fd5ec 100644 --- a/src/System.Private.CoreLib/shared/System/Text/StringBuilder.cs +++ b/src/System.Private.CoreLib/shared/System/Text/StringBuilder.cs @@ -1091,9 +1091,7 @@ namespace System.Text } Debug.Assert(insertingChars + this.Length < int.MaxValue); - StringBuilder chunk; - int indexInChunk; - MakeRoom(index, (int)insertingChars, out chunk, out indexInChunk, false); + MakeRoom(index, (int)insertingChars, out StringBuilder chunk, out int indexInChunk, false); unsafe { fixed (char* valuePtr = value) @@ -1140,9 +1138,7 @@ namespace System.Text if (length > 0) { - StringBuilder chunk; - int indexInChunk; - Remove(startIndex, length, out chunk, out indexInChunk); + Remove(startIndex, length, out _, out _); } return this; @@ -2140,9 +2136,7 @@ namespace System.Text if (valueCount > 0) { - StringBuilder chunk; - int indexInChunk; - MakeRoom(index, valueCount, out chunk, out indexInChunk, false); + MakeRoom(index, valueCount, out StringBuilder chunk, out int indexInChunk, false); ReplaceInPlaceAtChunk(ref chunk!, ref indexInChunk, value, valueCount); } } diff --git a/src/System.Private.CoreLib/shared/System/Text/Unicode/Utf16Utility.Validation.cs b/src/System.Private.CoreLib/shared/System/Text/Unicode/Utf16Utility.Validation.cs index be733006d..73bfa603f 100644 --- a/src/System.Private.CoreLib/shared/System/Text/Unicode/Utf16Utility.Validation.cs +++ b/src/System.Private.CoreLib/shared/System/Text/Unicode/Utf16Utility.Validation.cs @@ -3,12 +3,17 @@ // See the LICENSE file in the project root for more information. using System.Diagnostics; +using System.Runtime.CompilerServices; using System.Runtime.Intrinsics; using System.Runtime.Intrinsics.X86; using System.Numerics; + +#if SYSTEM_PRIVATE_CORELIB using Internal.Runtime.CompilerServices; +#endif #pragma warning disable SA1121 // explicitly using type aliases instead of built-in types +#if SYSTEM_PRIVATE_CORELIB #if TARGET_64BIT using nint = System.Int64; using nuint = System.UInt64; @@ -16,18 +21,22 @@ using nuint = System.UInt64; using nint = System.Int32; using nuint = System.UInt32; #endif // TARGET_64BIT +#else +using nint = System.Int64; // https://github.com/dotnet/runtime/issues/33575 - use long/ulong outside of corelib until the compiler supports it +using nuint = System.UInt64; +#endif namespace System.Text.Unicode { internal static unsafe partial class Utf16Utility { -#if DEBUG +#if DEBUG && SYSTEM_PRIVATE_CORELIB static Utf16Utility() { Debug.Assert(sizeof(nint) == IntPtr.Size && nint.MinValue < 0, "nint is defined incorrectly."); Debug.Assert(sizeof(nuint) == IntPtr.Size && nuint.MinValue == 0, "nuint is defined incorrectly."); } -#endif // DEBUG +#endif // DEBUG && SYSTEM_PRIVATE_CORELIB // Returns &inputBuffer[inputLength] if the input buffer is valid. /// diff --git a/src/System.Private.CoreLib/shared/System/Text/Unicode/Utf8.cs b/src/System.Private.CoreLib/shared/System/Text/Unicode/Utf8.cs index 1904df7db..7992cd52a 100644 --- a/src/System.Private.CoreLib/shared/System/Text/Unicode/Utf8.cs +++ b/src/System.Private.CoreLib/shared/System/Text/Unicode/Utf8.cs @@ -4,12 +4,21 @@ using System.Buffers; using System.Diagnostics; +using System.Runtime.CompilerServices; using System.Runtime.InteropServices; + +#if SYSTEM_PRIVATE_CORELIB using Internal.Runtime.CompilerServices; +#endif namespace System.Text.Unicode { - public static class Utf8 +#if SYSTEM_PRIVATE_CORELIB + public +#else + internal +#endif + static class Utf8 { /* * OperationStatus-based APIs for transcoding of chunked data. diff --git a/src/System.Private.CoreLib/shared/System/Text/Unicode/Utf8Utility.Helpers.cs b/src/System.Private.CoreLib/shared/System/Text/Unicode/Utf8Utility.Helpers.cs index 5cdf7574e..4021195ff 100644 --- a/src/System.Private.CoreLib/shared/System/Text/Unicode/Utf8Utility.Helpers.cs +++ b/src/System.Private.CoreLib/shared/System/Text/Unicode/Utf8Utility.Helpers.cs @@ -6,7 +6,10 @@ using System.Buffers.Binary; using System.Diagnostics; using System.Numerics; using System.Runtime.CompilerServices; + +#if SYSTEM_PRIVATE_CORELIB using Internal.Runtime.CompilerServices; +#endif namespace System.Text.Unicode { diff --git a/src/System.Private.CoreLib/shared/System/Text/Unicode/Utf8Utility.Transcoding.cs b/src/System.Private.CoreLib/shared/System/Text/Unicode/Utf8Utility.Transcoding.cs index b9d7fd305..64f76fec6 100644 --- a/src/System.Private.CoreLib/shared/System/Text/Unicode/Utf8Utility.Transcoding.cs +++ b/src/System.Private.CoreLib/shared/System/Text/Unicode/Utf8Utility.Transcoding.cs @@ -3,14 +3,18 @@ // See the LICENSE file in the project root for more information. using System.Buffers; -using System.Buffers.Binary; using System.Diagnostics; using System.Numerics; +using System.Runtime.CompilerServices; using System.Runtime.Intrinsics; using System.Runtime.Intrinsics.X86; + +#if SYSTEM_PRIVATE_CORELIB using Internal.Runtime.CompilerServices; +#endif #pragma warning disable SA1121 // explicitly using type aliases instead of built-in types +#if SYSTEM_PRIVATE_CORELIB #if TARGET_64BIT using nint = System.Int64; using nuint = System.UInt64; @@ -18,12 +22,16 @@ using nuint = System.UInt64; using nint = System.Int32; using nuint = System.UInt32; #endif // TARGET_64BIT +#else +using nint = System.Int64; // https://github.com/dotnet/runtime/issues/33575 - use long/ulong outside of corelib until the compiler supports it +using nuint = System.UInt64; +#endif namespace System.Text.Unicode { internal static unsafe partial class Utf8Utility { -#if DEBUG +#if DEBUG && SYSTEM_PRIVATE_CORELIB static Utf8Utility() { Debug.Assert(sizeof(nint) == IntPtr.Size && nint.MinValue < 0, "nint is defined incorrectly."); @@ -31,7 +39,7 @@ namespace System.Text.Unicode _ValidateAdditionalNIntDefinitions(); } -#endif // DEBUG +#endif // DEBUG && SYSTEM_PRIVATE_CORELIB // On method return, pInputBufferRemaining and pOutputBufferRemaining will both point to where // the next byte would have been consumed from / the next char would have been written to. diff --git a/src/System.Private.CoreLib/shared/System/Text/Unicode/Utf8Utility.Validation.cs b/src/System.Private.CoreLib/shared/System/Text/Unicode/Utf8Utility.Validation.cs index 9f721d540..8284828d5 100644 --- a/src/System.Private.CoreLib/shared/System/Text/Unicode/Utf8Utility.Validation.cs +++ b/src/System.Private.CoreLib/shared/System/Text/Unicode/Utf8Utility.Validation.cs @@ -4,10 +4,15 @@ using System.Diagnostics; using System.Numerics; +using System.Runtime.CompilerServices; using System.Runtime.Intrinsics.X86; + +#if SYSTEM_PRIVATE_CORELIB using Internal.Runtime.CompilerServices; +#endif #pragma warning disable SA1121 // explicitly using type aliases instead of built-in types +#if SYSTEM_PRIVATE_CORELIB #if TARGET_64BIT using nint = System.Int64; using nuint = System.UInt64; @@ -15,18 +20,22 @@ using nuint = System.UInt64; using nint = System.Int32; using nuint = System.UInt32; #endif // TARGET_64BIT +#else +using nint = System.Int64; // https://github.com/dotnet/runtime/issues/33575 - use long/ulong outside of corelib until the compiler supports it +using nuint = System.UInt64; +#endif namespace System.Text.Unicode { internal static unsafe partial class Utf8Utility { -#if DEBUG +#if DEBUG && SYSTEM_PRIVATE_CORELIB private static void _ValidateAdditionalNIntDefinitions() { Debug.Assert(sizeof(nint) == IntPtr.Size && nint.MinValue < 0, "nint is defined incorrectly."); Debug.Assert(sizeof(nuint) == IntPtr.Size && nuint.MinValue == 0, "nuint is defined incorrectly."); } -#endif // DEBUG +#endif // DEBUG && SYSTEM_PRIVATE_CORELIB // Returns &inputBuffer[inputLength] if the input buffer is valid. /// @@ -411,7 +420,7 @@ namespace System.Text.Unicode // in to the text. If this happens strip it off now before seeing if the next character // consists of three code units. - // Branchless: consume a 3-byte UTF-8 sequence and optionally an extra ASCII byte hanging off the end + // Branchless: consume a 3-byte UTF-8 sequence and optionally an extra ASCII byte from the end. nint asciiAdjustment; if (BitConverter.IsLittleEndian) diff --git a/src/System.Private.CoreLib/shared/System/Text/Unicode/Utf8Utility.WhiteSpace.cs b/src/System.Private.CoreLib/shared/System/Text/Unicode/Utf8Utility.WhiteSpace.CoreLib.cs similarity index 99% rename from src/System.Private.CoreLib/shared/System/Text/Unicode/Utf8Utility.WhiteSpace.cs rename to src/System.Private.CoreLib/shared/System/Text/Unicode/Utf8Utility.WhiteSpace.CoreLib.cs index 373f764ef..cf656bc1d 100644 --- a/src/System.Private.CoreLib/shared/System/Text/Unicode/Utf8Utility.WhiteSpace.cs +++ b/src/System.Private.CoreLib/shared/System/Text/Unicode/Utf8Utility.WhiteSpace.CoreLib.cs @@ -7,7 +7,6 @@ using Internal.Runtime.CompilerServices; #pragma warning disable SA1121 // explicitly using type aliases instead of built-in types #if TARGET_64BIT -using nint = System.Int64; using nuint = System.UInt64; #else using nint = System.Int32; diff --git a/src/System.Private.CoreLib/shared/System/Text/Unicode/Utf8Utility.WhiteSpace.NonCoreLib.cs b/src/System.Private.CoreLib/shared/System/Text/Unicode/Utf8Utility.WhiteSpace.NonCoreLib.cs new file mode 100644 index 000000000..214f01a66 --- /dev/null +++ b/src/System.Private.CoreLib/shared/System/Text/Unicode/Utf8Utility.WhiteSpace.NonCoreLib.cs @@ -0,0 +1,119 @@ +// 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.Text.Unicode +{ + internal static partial class Utf8Utility + { + /// + /// Returns the index in where the first non-whitespace character + /// appears, or the input length if the data contains only whitespace characters. + /// + public static int GetIndexOfFirstNonWhiteSpaceChar(ReadOnlySpan utf8Data) + { + // This method is optimized for the case where the input data is ASCII, and if the + // data does need to be trimmed it's likely that only a relatively small number of + // bytes will be trimmed. + + int i = 0; + int length = utf8Data.Length; + + while (i < length) + { + // Very quick check: see if the byte is in the range [ 21 .. 7F ]. + // If so, we can skip the more expensive logic later in this method. + + if ((sbyte)utf8Data[i] > (sbyte)0x20) + { + break; + } + + uint possibleAsciiByte = utf8Data[i]; + if (UnicodeUtility.IsAsciiCodePoint(possibleAsciiByte)) + { + // The simple comparison failed. Let's read the actual byte value, + // and if it's ASCII we can delegate to Rune's inlined method + // implementation. + + if (Rune.IsWhiteSpace(new Rune(possibleAsciiByte))) + { + i++; + continue; + } + } + else + { + // Not ASCII data. Go back to the slower "decode the entire scalar" + // code path, then compare it against our Unicode tables. + + Rune.DecodeFromUtf8(utf8Data.Slice(i), out Rune decodedRune, out int bytesConsumed); + if (Rune.IsWhiteSpace(decodedRune)) + { + i += bytesConsumed; + continue; + } + } + + break; // If we got here, we saw a non-whitespace subsequence. + } + + return i; + } + + /// + /// Returns the index in where the trailing whitespace sequence + /// begins, or 0 if the data contains only whitespace characters, or the span length if the + /// data does not end with any whitespace characters. + /// + public static int GetIndexOfTrailingWhiteSpaceSequence(ReadOnlySpan utf8Data) + { + // This method is optimized for the case where the input data is ASCII, and if the + // data does need to be trimmed it's likely that only a relatively small number of + // bytes will be trimmed. + + int length = utf8Data.Length; + + while (length > 0) + { + // Very quick check: see if the byte is in the range [ 21 .. 7F ]. + // If so, we can skip the more expensive logic later in this method. + + if ((sbyte)utf8Data[length - 1] > (sbyte)0x20) + { + break; + } + + uint possibleAsciiByte = utf8Data[length - 1]; + if (UnicodeUtility.IsAsciiCodePoint(possibleAsciiByte)) + { + // The simple comparison failed. Let's read the actual byte value, + // and if it's ASCII we can delegate to Rune's inlined method + // implementation. + + if (Rune.IsWhiteSpace(new Rune(possibleAsciiByte))) + { + length--; + continue; + } + } + else + { + // Not ASCII data. Go back to the slower "decode the entire scalar" + // code path, then compare it against our Unicode tables. + + Rune.DecodeLastFromUtf8(utf8Data.Slice(0, length), out Rune decodedRune, out int bytesConsumed); + if (Rune.IsWhiteSpace(decodedRune)) + { + length -= bytesConsumed; + continue; + } + } + + break; // If we got here, we saw a non-whitespace subsequence. + } + + return length; + } + } +} diff --git a/src/System.Private.CoreLib/shared/System/Text/Unicode/Utf8Utility.cs b/src/System.Private.CoreLib/shared/System/Text/Unicode/Utf8Utility.cs index bb6853b07..78de994a2 100644 --- a/src/System.Private.CoreLib/shared/System/Text/Unicode/Utf8Utility.cs +++ b/src/System.Private.CoreLib/shared/System/Text/Unicode/Utf8Utility.cs @@ -7,7 +7,10 @@ using System.Diagnostics; using System.IO; using System.Runtime.CompilerServices; using System.Runtime.InteropServices; + +#if SYSTEM_PRIVATE_CORELIB using Internal.Runtime.CompilerServices; +#endif namespace System.Text.Unicode { @@ -22,7 +25,11 @@ namespace System.Text.Unicode /// /// The UTF-8 representation of . /// +#if !NETSTANDARD2_0 private static ReadOnlySpan ReplacementCharSequence => new byte[] { 0xEF, 0xBF, 0xBD }; +#else + private static readonly byte[] ReplacementCharSequence = new byte[] { 0xEF, 0xBF, 0xBD }; +#endif /// /// Returns the byte index in where the first invalid UTF-8 sequence begins, @@ -83,6 +90,7 @@ namespace System.Text.Unicode // (The faster implementation is in the dev/utf8string_bak branch currently.) MemoryStream memStream = new MemoryStream(); +#if !NETSTANDARD2_0 memStream.Write(valueAsBytes.Slice(0, idxOfFirstInvalidData)); valueAsBytes = valueAsBytes.Slice(idxOfFirstInvalidData); @@ -101,6 +109,37 @@ namespace System.Text.Unicode valueAsBytes = valueAsBytes.Slice(bytesConsumed); } while (!valueAsBytes.IsEmpty); +#else + if (!MemoryMarshal.TryGetArray(value.AsMemoryBytes(), out ArraySegment valueArraySegment)) + { + Debug.Fail("Utf8String on netstandard should always be backed by an array."); + } + + memStream.Write(valueArraySegment.Array, valueArraySegment.Offset, idxOfFirstInvalidData); + + valueArraySegment = new ArraySegment( + valueArraySegment.Array, + idxOfFirstInvalidData, + valueArraySegment.Count - idxOfFirstInvalidData); + do + { + if (Rune.DecodeFromUtf8(valueArraySegment, out _, out int bytesConsumed) == OperationStatus.Done) + { + // Valid scalar value - copy data as-is to MemoryStream + memStream.Write(valueArraySegment.Array, valueArraySegment.Offset, bytesConsumed); + } + else + { + // Invalid scalar value - copy U+FFFD to MemoryStream + memStream.Write(ReplacementCharSequence, 0, ReplacementCharSequence.Length); + } + + valueArraySegment = new ArraySegment( + valueArraySegment.Array, + valueArraySegment.Offset + bytesConsumed, + valueArraySegment.Count - bytesConsumed); + } while (valueArraySegment.Count > 0); +#endif bool success = memStream.TryGetBuffer(out ArraySegment memStreamBuffer); Debug.Assert(success, "Couldn't get underlying MemoryStream buffer."); diff --git a/src/System.Private.CoreLib/shared/System/Threading/EventWaitHandle.cs b/src/System.Private.CoreLib/shared/System/Threading/EventWaitHandle.cs index 96c2ef89c..e3c0a66e3 100644 --- a/src/System.Private.CoreLib/shared/System/Threading/EventWaitHandle.cs +++ b/src/System.Private.CoreLib/shared/System/Threading/EventWaitHandle.cs @@ -30,8 +30,7 @@ namespace System.Threading public static EventWaitHandle OpenExisting(string name) { - EventWaitHandle? result; - switch (OpenExistingWorker(name, out result)) + switch (OpenExistingWorker(name, out EventWaitHandle? result)) { case OpenExistingResult.NameNotFound: throw new WaitHandleCannotBeOpenedException(); @@ -45,9 +44,7 @@ namespace System.Threading } } - public static bool TryOpenExisting(string name, [NotNullWhen(true)] out EventWaitHandle? result) - { - return OpenExistingWorker(name, out result) == OpenExistingResult.Success; - } + public static bool TryOpenExisting(string name, [NotNullWhen(true)] out EventWaitHandle? result) => + OpenExistingWorker(name, out result!) == OpenExistingResult.Success; } } diff --git a/src/System.Private.CoreLib/shared/System/Threading/Interlocked.cs b/src/System.Private.CoreLib/shared/System/Threading/Interlocked.cs index 16bb9bbf4..6c6f0d657 100644 --- a/src/System.Private.CoreLib/shared/System/Threading/Interlocked.cs +++ b/src/System.Private.CoreLib/shared/System/Threading/Interlocked.cs @@ -132,7 +132,7 @@ namespace System.Threading /// Bitwise "ands" two 32-bit signed integers and replaces the first integer with the result, as an atomic operation. /// A variable containing the first value to be combined. The result is stored in . /// The value to be combined with the integer at . - /// The new value stored at . + /// The original value in . /// The address of is a null pointer. [MethodImpl(MethodImplOptions.AggressiveInlining)] public static int And(ref int location1, int value) @@ -144,7 +144,7 @@ namespace System.Threading int oldValue = CompareExchange(ref location1, newValue, current); if (oldValue == current) { - return newValue; + return oldValue; } current = oldValue; } @@ -153,7 +153,7 @@ namespace System.Threading /// Bitwise "ands" two 32-bit unsigned integers and replaces the first integer with the result, as an atomic operation. /// A variable containing the first value to be combined. The result is stored in . /// The value to be combined with the integer at . - /// The new value stored at . + /// The original value in . /// The address of is a null pointer. [MethodImpl(MethodImplOptions.AggressiveInlining)] [CLSCompliant(false)] @@ -163,7 +163,7 @@ namespace System.Threading /// Bitwise "ands" two 64-bit signed integers and replaces the first integer with the result, as an atomic operation. /// A variable containing the first value to be combined. The result is stored in . /// The value to be combined with the integer at . - /// The new value stored at . + /// The original value in . /// The address of is a null pointer. [MethodImpl(MethodImplOptions.AggressiveInlining)] public static long And(ref long location1, long value) @@ -175,7 +175,7 @@ namespace System.Threading long oldValue = CompareExchange(ref location1, newValue, current); if (oldValue == current) { - return newValue; + return oldValue; } current = oldValue; } @@ -184,7 +184,7 @@ namespace System.Threading /// Bitwise "ands" two 64-bit unsigned integers and replaces the first integer with the result, as an atomic operation. /// A variable containing the first value to be combined. The result is stored in . /// The value to be combined with the integer at . - /// The new value stored at . + /// The original value in . /// The address of is a null pointer. [MethodImpl(MethodImplOptions.AggressiveInlining)] [CLSCompliant(false)] @@ -196,7 +196,7 @@ namespace System.Threading /// Bitwise "ors" two 32-bit signed integers and replaces the first integer with the result, as an atomic operation. /// A variable containing the first value to be combined. The result is stored in . /// The value to be combined with the integer at . - /// The new value stored at . + /// The original value in . /// The address of is a null pointer. [MethodImpl(MethodImplOptions.AggressiveInlining)] public static int Or(ref int location1, int value) @@ -208,7 +208,7 @@ namespace System.Threading int oldValue = CompareExchange(ref location1, newValue, current); if (oldValue == current) { - return newValue; + return oldValue; } current = oldValue; } @@ -217,7 +217,7 @@ namespace System.Threading /// Bitwise "ors" two 32-bit unsigned integers and replaces the first integer with the result, as an atomic operation. /// A variable containing the first value to be combined. The result is stored in . /// The value to be combined with the integer at . - /// The new value stored at . + /// The original value in . /// The address of is a null pointer. [MethodImpl(MethodImplOptions.AggressiveInlining)] [CLSCompliant(false)] @@ -227,7 +227,7 @@ namespace System.Threading /// Bitwise "ors" two 64-bit signed integers and replaces the first integer with the result, as an atomic operation. /// A variable containing the first value to be combined. The result is stored in . /// The value to be combined with the integer at . - /// The new value stored at . + /// The original value in . /// The address of is a null pointer. [MethodImpl(MethodImplOptions.AggressiveInlining)] public static long Or(ref long location1, long value) @@ -239,7 +239,7 @@ namespace System.Threading long oldValue = CompareExchange(ref location1, newValue, current); if (oldValue == current) { - return newValue; + return oldValue; } current = oldValue; } @@ -248,7 +248,7 @@ namespace System.Threading /// Bitwise "ors" two 64-bit unsigned integers and replaces the first integer with the result, as an atomic operation. /// A variable containing the first value to be combined. The result is stored in . /// The value to be combined with the integer at . - /// The new value stored at . + /// The original value in . /// The address of is a null pointer. [MethodImpl(MethodImplOptions.AggressiveInlining)] [CLSCompliant(false)] diff --git a/src/System.Private.CoreLib/shared/System/Threading/LowLevelLifoSemaphore.Windows.cs b/src/System.Private.CoreLib/shared/System/Threading/LowLevelLifoSemaphore.Windows.cs index 34d2895dd..fe0c5adec 100644 --- a/src/System.Private.CoreLib/shared/System/Threading/LowLevelLifoSemaphore.Windows.cs +++ b/src/System.Private.CoreLib/shared/System/Threading/LowLevelLifoSemaphore.Windows.cs @@ -27,7 +27,7 @@ namespace System.Threading Interop.Kernel32.CreateIoCompletionPort(new IntPtr(-1), IntPtr.Zero, UIntPtr.Zero, maximumSignalCount); if (_completionPort == IntPtr.Zero) { - var error = Marshal.GetLastWin32Error(); + int error = Marshal.GetLastWin32Error(); var exception = new OutOfMemoryException(); exception.HResult = error; throw exception; @@ -46,7 +46,7 @@ namespace System.Threading { Debug.Assert(timeoutMs >= -1); - bool success = Interop.Kernel32.GetQueuedCompletionStatus(_completionPort, out var numberOfBytes, out var completionKey, out var pointerToOverlapped, timeoutMs); + bool success = Interop.Kernel32.GetQueuedCompletionStatus(_completionPort, out int numberOfBytes, out UIntPtr completionKey, out IntPtr pointerToOverlapped, timeoutMs); Debug.Assert(success || (Marshal.GetLastWin32Error() == WaitHandle.WaitTimeout)); return success; } @@ -57,9 +57,9 @@ namespace System.Threading for (int i = 0; i < count; i++) { - if(!Interop.Kernel32.PostQueuedCompletionStatus(_completionPort, 1, UIntPtr.Zero, IntPtr.Zero)) + if (!Interop.Kernel32.PostQueuedCompletionStatus(_completionPort, 1, UIntPtr.Zero, IntPtr.Zero)) { - var lastError = Marshal.GetLastWin32Error(); + int lastError = Marshal.GetLastWin32Error(); var exception = new OutOfMemoryException(); exception.HResult = lastError; throw exception; diff --git a/src/System.Private.CoreLib/shared/System/Threading/LowLevelLifoSemaphore.cs b/src/System.Private.CoreLib/shared/System/Threading/LowLevelLifoSemaphore.cs index 4e812549e..3cf328d2a 100644 --- a/src/System.Private.CoreLib/shared/System/Threading/LowLevelLifoSemaphore.cs +++ b/src/System.Private.CoreLib/shared/System/Threading/LowLevelLifoSemaphore.cs @@ -15,8 +15,8 @@ namespace System.Threading { private CacheLineSeparatedCounts _separated; - private int _maximumSignalCount; - private int _spinCount; + private readonly int _maximumSignalCount; + private readonly int _spinCount; private const int SpinSleep0Threshold = 10; @@ -27,7 +27,7 @@ namespace System.Threading Debug.Assert(maximumSignalCount > 0); Debug.Assert(spinCount >= 0); - _separated = new CacheLineSeparatedCounts(); + _separated = default; _separated._counts._signalCount = (uint)initialSignalCount; _maximumSignalCount = maximumSignalCount; _spinCount = spinCount; @@ -204,7 +204,7 @@ namespace System.Threading { // Unregister the waiter. The wait subsystem used above guarantees that a thread that wakes due to a timeout does // not observe a signal to the object being waited upon. - Counts toSubtract = new Counts(); + Counts toSubtract = default; toSubtract._waiterCount++; Counts newCounts = _separated._counts.Subtract(toSubtract); Debug.Assert(newCounts._waiterCount != ushort.MaxValue); // Check for underflow @@ -287,9 +287,9 @@ namespace System.Threading [StructLayout(LayoutKind.Sequential)] private struct CacheLineSeparatedCounts { - private Internal.PaddingFor32 _pad1; + private readonly Internal.PaddingFor32 _pad1; public Counts _counts; - private Internal.PaddingFor32 _pad2; + private readonly Internal.PaddingFor32 _pad2; } } } diff --git a/src/System.Private.CoreLib/shared/System/Threading/Mutex.cs b/src/System.Private.CoreLib/shared/System/Threading/Mutex.cs index 1effbc63b..2f4756dbb 100644 --- a/src/System.Private.CoreLib/shared/System/Threading/Mutex.cs +++ b/src/System.Private.CoreLib/shared/System/Threading/Mutex.cs @@ -57,6 +57,6 @@ namespace System.Threading } public static bool TryOpenExisting(string name, [NotNullWhen(true)] out Mutex? result) => - OpenExistingWorker(name, out result) == OpenExistingResult.Success; + OpenExistingWorker(name, out result!) == OpenExistingResult.Success; } } diff --git a/src/System.Private.CoreLib/shared/System/Threading/PortableThreadPool.CpuUtilizationReader.Windows.cs b/src/System.Private.CoreLib/shared/System/Threading/PortableThreadPool.CpuUtilizationReader.Windows.cs index ee7899795..50c841fe9 100644 --- a/src/System.Private.CoreLib/shared/System/Threading/PortableThreadPool.CpuUtilizationReader.Windows.cs +++ b/src/System.Private.CoreLib/shared/System/Threading/PortableThreadPool.CpuUtilizationReader.Windows.cs @@ -19,7 +19,7 @@ namespace System.Threading { get { - if (!Interop.Kernel32.GetSystemTimes(out var idleTime, out var kernelTime, out var userTime)) + if (!Interop.Kernel32.GetSystemTimes(out long idleTime, out long kernelTime, out long userTime)) { return 0; } diff --git a/src/System.Private.CoreLib/shared/System/Threading/PortableThreadPool.GateThread.cs b/src/System.Private.CoreLib/shared/System/Threading/PortableThreadPool.GateThread.cs index a6124b4e1..96dfdebec 100644 --- a/src/System.Private.CoreLib/shared/System/Threading/PortableThreadPool.GateThread.cs +++ b/src/System.Private.CoreLib/shared/System/Threading/PortableThreadPool.GateThread.cs @@ -16,17 +16,15 @@ namespace System.Threading private static int s_runningState; - private static AutoResetEvent s_runGateThreadEvent = new AutoResetEvent(true); + private static readonly AutoResetEvent s_runGateThreadEvent = new AutoResetEvent(initialState: true); - private static LowLevelLock s_createdLock = new LowLevelLock(); - - private static CpuUtilizationReader s_cpu = new CpuUtilizationReader(); + private static CpuUtilizationReader s_cpu; private const int MaxRuns = 2; // TODO: CoreCLR: Worker Tracking in CoreCLR? (Config name: ThreadPool_EnableWorkerTracking) private static void GateThreadStart() { - var initialCpuRead = s_cpu.CurrentUtilization; // The first reading is over a time range other than what we are focusing on, so we do not use the read. + _ = s_cpu.CurrentUtilization; // The first reading is over a time range other than what we are focusing on, so we do not use the read. AppContext.TryGetSwitch("System.Threading.ThreadPool.DisableStarvationDetection", out bool disableStarvationDetection); AppContext.TryGetSwitch("System.Threading.ThreadPool.DebugBreakOnWorkerStarvation", out bool debuggerBreakOnWorkStarvation); @@ -87,7 +85,7 @@ namespace System.Threading int minimumDelay; - if(ThreadPoolInstance._cpuUtilization < CpuUtilizationLow) + if (ThreadPoolInstance._cpuUtilization < CpuUtilizationLow) { minimumDelay = GateThreadDelayMs; } diff --git a/src/System.Private.CoreLib/shared/System/Threading/PortableThreadPool.HillClimbing.Complex.cs b/src/System.Private.CoreLib/shared/System/Threading/PortableThreadPool.HillClimbing.Complex.cs index 7093ba3ad..b3cd2da17 100644 --- a/src/System.Private.CoreLib/shared/System/Threading/PortableThreadPool.HillClimbing.Complex.cs +++ b/src/System.Private.CoreLib/shared/System/Threading/PortableThreadPool.HillClimbing.Complex.cs @@ -19,15 +19,15 @@ namespace System.Threading public double Imaginary { get; } public double Real { get; } - public static Complex operator*(double scalar, Complex complex) => new Complex(scalar * complex.Real, scalar * complex.Imaginary); + public static Complex operator *(double scalar, Complex complex) => new Complex(scalar * complex.Real, scalar * complex.Imaginary); - public static Complex operator*(Complex complex, double scalar) => scalar * complex; + public static Complex operator *(Complex complex, double scalar) => scalar * complex; - public static Complex operator/(Complex complex, double scalar) => new Complex(complex.Real / scalar, complex.Imaginary / scalar); + public static Complex operator /(Complex complex, double scalar) => new Complex(complex.Real / scalar, complex.Imaginary / scalar); - public static Complex operator-(Complex lhs, Complex rhs) => new Complex(lhs.Real - rhs.Real, lhs.Imaginary - rhs.Imaginary); + public static Complex operator -(Complex lhs, Complex rhs) => new Complex(lhs.Real - rhs.Real, lhs.Imaginary - rhs.Imaginary); - public static Complex operator/(Complex lhs, Complex rhs) + public static Complex operator /(Complex lhs, Complex rhs) { double denom = rhs.Real * rhs.Real + rhs.Imaginary * rhs.Imaginary; return new Complex((lhs.Real * rhs.Real + lhs.Imaginary * rhs.Imaginary) / denom, (-lhs.Real * rhs.Imaginary + lhs.Imaginary * rhs.Real) / denom); diff --git a/src/System.Private.CoreLib/shared/System/Threading/PortableThreadPool.HillClimbing.cs b/src/System.Private.CoreLib/shared/System/Threading/PortableThreadPool.HillClimbing.cs index d32a227d4..0fa48e9d8 100644 --- a/src/System.Private.CoreLib/shared/System/Threading/PortableThreadPool.HillClimbing.cs +++ b/src/System.Private.CoreLib/shared/System/Threading/PortableThreadPool.HillClimbing.cs @@ -3,7 +3,6 @@ // See the LICENSE file in the project root for more information. using System.Diagnostics; -using System.Globalization; namespace System.Threading { @@ -83,13 +82,13 @@ namespace System.Threading private double _completionsSinceLastChange; private int _accumulatedCompletionCount; private double _accumulatedSampleDurationSeconds; - private double[] _samples; - private double[] _threadCounts; + private readonly double[] _samples; + private readonly double[] _threadCounts; private int _currentSampleMs; - private Random _randomIntervalGenerator = new Random(); + private readonly Random _randomIntervalGenerator = new Random(); - private LogEntry[] _log = new LogEntry[LogCapacity]; + private readonly LogEntry[] _log = new LogEntry[LogCapacity]; private int _logStart = 0; private int _logSize = 0; @@ -186,11 +185,8 @@ namespace System.Threading // Add the current thread count and throughput sample to our history // double throughput = numCompletions / sampleDurationSeconds; - PortableThreadPoolEventSource log = PortableThreadPoolEventSource.Log; - if (log.IsEnabled()) - { - log.WorkerThreadAdjustmentSample(throughput); - } + + PortableThreadPoolEventSource.Log.WorkerThreadAdjustmentSample(throughput); int sampleIndex = (int)(_totalSamples % _samplesToMeasure); _samples[sampleIndex] = throughput; @@ -200,10 +196,10 @@ namespace System.Threading // // Set up defaults for our metrics // - Complex threadWaveComponent = default(Complex); - Complex throughputWaveComponent = default(Complex); + Complex threadWaveComponent = default; + Complex throughputWaveComponent = default; double throughputErrorEstimate = 0; - Complex ratio = default(Complex); + Complex ratio = default; double confidence = 0; StateOrTransition state = StateOrTransition.Warmup; @@ -360,11 +356,8 @@ namespace System.Threading // Record these numbers for posterity // - if (log.IsEnabled()) - { - log.WorkerThreadAdjustmentStats(sampleDurationSeconds, throughput, threadWaveComponent.Real, throughputWaveComponent.Real, + PortableThreadPoolEventSource.Log.WorkerThreadAdjustmentStats(sampleDurationSeconds, throughput, threadWaveComponent.Real, throughputWaveComponent.Real, throughputErrorEstimate, _averageThroughputNoise, ratio.Real, confidence, _currentControlSetting, (ushort)newThreadWaveMagnitude); - } // @@ -405,7 +398,7 @@ namespace System.Threading // Use the _log array as a circular array for log entries int index = (_logStart + _logSize) % LogCapacity; - if(_logSize == LogCapacity) + if (_logSize == LogCapacity) { _logStart = (_logStart + 1) % LogCapacity; _logSize--; // hide this slot while we update it @@ -421,16 +414,12 @@ namespace System.Threading _logSize++; - PortableThreadPoolEventSource log = PortableThreadPoolEventSource.Log; - if (log.IsEnabled()) - { - log.WorkerThreadAdjustmentAdjustment(throughput, newThreadCount, (int)stateOrTransition); - } + PortableThreadPoolEventSource.Log.WorkerThreadAdjustmentAdjustment(throughput, newThreadCount, (int)stateOrTransition); } public void ForceChange(int newThreadCount, StateOrTransition state) { - if(_lastThreadCount != newThreadCount) + if (_lastThreadCount != newThreadCount) { _currentControlSetting += newThreadCount - _lastThreadCount; ChangeThreadCount(newThreadCount, state); @@ -452,7 +441,7 @@ namespace System.Threading double cos = Math.Cos(w); double coeff = 2 * cos; double q0 = 0, q1 = 0, q2 = 0; - for(int i = 0; i < numSamples; ++i) + for (int i = 0; i < numSamples; ++i) { q0 = coeff * q1 - q2 + samples[(_totalSamples - numSamples + i) % _samplesToMeasure]; q2 = q1; diff --git a/src/System.Private.CoreLib/shared/System/Threading/PortableThreadPool.ThreadCounts.cs b/src/System.Private.CoreLib/shared/System/Threading/PortableThreadPool.ThreadCounts.cs index 3fc6cf9fd..411cdbeb4 100644 --- a/src/System.Private.CoreLib/shared/System/Threading/PortableThreadPool.ThreadCounts.cs +++ b/src/System.Private.CoreLib/shared/System/Threading/PortableThreadPool.ThreadCounts.cs @@ -13,7 +13,7 @@ namespace System.Threading /// Tracks information on the number of threads we want/have in different states in our thread pool. /// [StructLayout(LayoutKind.Explicit)] - struct ThreadCounts + private struct ThreadCounts { /// /// Max possible thread pool threads we want to have. diff --git a/src/System.Private.CoreLib/shared/System/Threading/PortableThreadPool.WaitThread.cs b/src/System.Private.CoreLib/shared/System/Threading/PortableThreadPool.WaitThread.cs index d34576bcd..5d1558e3f 100644 --- a/src/System.Private.CoreLib/shared/System/Threading/PortableThreadPool.WaitThread.cs +++ b/src/System.Private.CoreLib/shared/System/Threading/PortableThreadPool.WaitThread.cs @@ -3,7 +3,6 @@ // See the LICENSE file in the project root for more information. using System.Diagnostics; -using System.Runtime.InteropServices; namespace System.Threading { @@ -12,10 +11,9 @@ namespace System.Threading /// /// A linked list of s. /// - private WaitThreadNode _waitThreadsHead; - private WaitThreadNode _waitThreadsTail; + private WaitThreadNode? _waitThreadsHead; - private LowLevelLock _waitThreadLock = new LowLevelLock(); + private readonly LowLevelLock _waitThreadLock = new LowLevelLock(); /// /// Register a wait handle on a . @@ -28,7 +26,7 @@ namespace System.Threading { if (_waitThreadsHead == null) // Lazily create the first wait thread. { - _waitThreadsTail = _waitThreadsHead = new WaitThreadNode + _waitThreadsHead = new WaitThreadNode { Thread = new WaitThread() }; @@ -36,10 +34,10 @@ namespace System.Threading // Register the wait handle on the first wait thread that is not at capacity. WaitThreadNode prev; - WaitThreadNode current = _waitThreadsHead; + WaitThreadNode? current = _waitThreadsHead; do { - if (current.Thread.RegisterWaitHandle(handle)) + if (current.Thread!.RegisterWaitHandle(handle)) { return; } @@ -48,7 +46,7 @@ namespace System.Threading } while (current != null); // If all wait threads are full, create a new one. - prev.Next = _waitThreadsTail = new WaitThreadNode + prev.Next = new WaitThreadNode { Thread = new WaitThread() }; @@ -90,14 +88,14 @@ namespace System.Threading /// The wait thread to remove from the list. private void RemoveWaitThread(WaitThread thread) { - if (_waitThreadsHead.Thread == thread) + if (_waitThreadsHead!.Thread == thread) { _waitThreadsHead = _waitThreadsHead.Next; return; } WaitThreadNode prev; - WaitThreadNode current = _waitThreadsHead; + WaitThreadNode? current = _waitThreadsHead; do { @@ -115,8 +113,8 @@ namespace System.Threading private class WaitThreadNode { - public WaitThread Thread { get; set; } - public WaitThreadNode Next { get; set; } + public WaitThread? Thread { get; set; } + public WaitThreadNode? Next { get; set; } } /// @@ -158,7 +156,7 @@ namespace System.Threading /// /// A list of removals of wait handles that are waiting for the wait thread to process. /// - private readonly RegisteredWaitHandle[] _pendingRemoves = new RegisteredWaitHandle[WaitHandle.MaxWaitHandles - 1]; + private readonly RegisteredWaitHandle?[] _pendingRemoves = new RegisteredWaitHandle[WaitHandle.MaxWaitHandles - 1]; /// /// The number of pending removals. /// @@ -230,7 +228,7 @@ namespace System.Threading continue; } - RegisteredWaitHandle signaledHandle = signaledHandleIndex != WaitHandle.WaitTimeout ? _registeredWaits[signaledHandleIndex - 1] : null; + RegisteredWaitHandle? signaledHandle = signaledHandleIndex != WaitHandle.WaitTimeout ? _registeredWaits[signaledHandleIndex - 1] : null; if (signaledHandle != null) { @@ -238,7 +236,7 @@ namespace System.Threading } else { - if(numUserWaits == 0) + if (numUserWaits == 0) { if (ThreadPoolInstance.TryRemoveWaitThread(this)) { @@ -292,8 +290,8 @@ namespace System.Threading _registeredWaits[j].OnRemoveWait(); _registeredWaits[j] = _registeredWaits[_numUserWaits - 1]; _waitHandles[j + 1] = _waitHandles[_numUserWaits]; - _registeredWaits[_numUserWaits - 1] = null; - _waitHandles[_numUserWaits] = null; + _registeredWaits[_numUserWaits - 1] = null!; + _waitHandles[_numUserWaits] = null!; --_numUserWaits; _pendingRemoves[i] = null; break; diff --git a/src/System.Private.CoreLib/shared/System/Threading/PortableThreadPool.WorkerThread.cs b/src/System.Private.CoreLib/shared/System/Threading/PortableThreadPool.WorkerThread.cs index 26232d04a..b120265a0 100644 --- a/src/System.Private.CoreLib/shared/System/Threading/PortableThreadPool.WorkerThread.cs +++ b/src/System.Private.CoreLib/shared/System/Threading/PortableThreadPool.WorkerThread.cs @@ -2,8 +2,6 @@ // 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.Globalization; - namespace System.Threading { internal partial class PortableThreadPool @@ -16,7 +14,7 @@ namespace System.Threading /// /// Semaphore for controlling how many threads are currently working. /// - private static LowLevelLifoSemaphore s_semaphore = new LowLevelLifoSemaphore(0, MaxPossibleThreadCount, SemaphoreSpinCount); + private static readonly LowLevelLifoSemaphore s_semaphore = new LowLevelLifoSemaphore(0, MaxPossibleThreadCount, SemaphoreSpinCount); /// /// Maximum number of spins a thread pool worker thread performs before waiting for work @@ -28,11 +26,7 @@ namespace System.Threading private static void WorkerThreadStart() { - PortableThreadPoolEventSource log = PortableThreadPoolEventSource.Log; - if (log.IsEnabled()) - { - log.WorkerThreadStart(ThreadCounts.VolatileReadCounts(ref ThreadPoolInstance._separated.counts).numExistingThreads); - } + PortableThreadPoolEventSource.Log.WorkerThreadStart(ThreadCounts.VolatileReadCounts(ref ThreadPoolInstance._separated.counts).numExistingThreads); while (true) { @@ -77,11 +71,7 @@ namespace System.Threading if (oldCounts == counts) { HillClimbing.ThreadPoolHillClimber.ForceChange(newCounts.numThreadsGoal, HillClimbing.StateOrTransition.ThreadTimedOut); - - if (log.IsEnabled()) - { - log.WorkerThreadStop(newCounts.numExistingThreads); - } + PortableThreadPoolEventSource.Log.WorkerThreadStop(newCounts.numExistingThreads); return; } } @@ -99,11 +89,7 @@ namespace System.Threading /// If this thread was woken up before it timed out. private static bool WaitForRequest() { - PortableThreadPoolEventSource log = PortableThreadPoolEventSource.Log; - if (log.IsEnabled()) - { - log.WorkerThreadWait(ThreadCounts.VolatileReadCounts(ref ThreadPoolInstance._separated.counts).numExistingThreads); - } + PortableThreadPoolEventSource.Log.WorkerThreadWait(ThreadCounts.VolatileReadCounts(ref ThreadPoolInstance._separated.counts).numExistingThreads); return s_semaphore.Wait(ThreadPoolThreadTimeoutMs); } @@ -185,7 +171,7 @@ namespace System.Threading newCounts.numExistingThreads -= (short)toCreate; ThreadCounts oldCounts = ThreadCounts.CompareExchangeCounts(ref ThreadPoolInstance._separated.counts, newCounts, counts); - if(oldCounts == counts) + if (oldCounts == counts) { break; } diff --git a/src/System.Private.CoreLib/shared/System/Threading/PortableThreadPool.cs b/src/System.Private.CoreLib/shared/System/Threading/PortableThreadPool.cs index 3da645357..25f434938 100644 --- a/src/System.Private.CoreLib/shared/System/Threading/PortableThreadPool.cs +++ b/src/System.Private.CoreLib/shared/System/Threading/PortableThreadPool.cs @@ -62,7 +62,7 @@ namespace System.Threading private readonly ThreadInt64PersistentCounter _completionCounter = new ThreadInt64PersistentCounter(); private int _threadAdjustmentIntervalMs; - private LowLevelLock _hillClimbingThreadAdjustmentLock = new LowLevelLock(); + private readonly LowLevelLock _hillClimbingThreadAdjustmentLock = new LowLevelLock(); private volatile int _numRequestedWorkers = 0; @@ -232,13 +232,13 @@ namespace System.Threading double elapsedSeconds = (double)(endTime - startTime) / freq; - if(elapsedSeconds * 1000 >= _threadAdjustmentIntervalMs / 2) + if (elapsedSeconds * 1000 >= _threadAdjustmentIntervalMs / 2) { ThreadCounts currentCounts = ThreadCounts.VolatileReadCounts(ref _separated.counts); int newMax; (newMax, _threadAdjustmentIntervalMs) = HillClimbing.ThreadPoolHillClimber.Update(currentCounts.numThreadsGoal, elapsedSeconds, numCompletions); - while(newMax != currentCounts.numThreadsGoal) + while (newMax != currentCounts.numThreadsGoal) { ThreadCounts newCounts = currentCounts; newCounts.numThreadsGoal = (short)newMax; @@ -260,7 +260,7 @@ namespace System.Threading } else { - if(oldCounts.numThreadsGoal > currentCounts.numThreadsGoal && oldCounts.numThreadsGoal >= newMax) + if (oldCounts.numThreadsGoal > currentCounts.numThreadsGoal && oldCounts.numThreadsGoal >= newMax) { // someone (probably the gate thread) increased the thread count more than // we are about to do. Don't interfere. @@ -283,7 +283,7 @@ namespace System.Threading int priorTime = Volatile.Read(ref _separated.priorCompletedWorkRequestsTime); int requiredInterval = _separated.nextCompletedWorkRequestsTime - priorTime; int elapsedInterval = Environment.TickCount - priorTime; - if(elapsedInterval >= requiredInterval) + if (elapsedInterval >= requiredInterval) { // Avoid trying to adjust the thread count goal if there are already more threads than the thread count goal. // In that situation, hill climbing must have previously decided to decrease the thread count goal, so let's diff --git a/src/System.Private.CoreLib/shared/System/Threading/PortableThreadPoolEventSource.cs b/src/System.Private.CoreLib/shared/System/Threading/PortableThreadPoolEventSource.cs index 97fad8277..f5eb61986 100644 --- a/src/System.Private.CoreLib/shared/System/Threading/PortableThreadPoolEventSource.cs +++ b/src/System.Private.CoreLib/shared/System/Threading/PortableThreadPoolEventSource.cs @@ -68,7 +68,7 @@ namespace System.Threading } } - [Event(5, Level = EventLevel.Informational, Message = WorkerThreadAdjustmentSampleMessage, Opcode = Opcodes.AdjustmentOpcode, Version = 0, Task = Tasks.WorkerThreadAdjustmentTask, Keywords = Keywords.ThreadingKeyword)] + [Event(5, Level = EventLevel.Informational, Message = WorkerThreadAdjustmentAdjustmentEventMessage, Opcode = Opcodes.AdjustmentOpcode, Version = 0, Task = Tasks.WorkerThreadAdjustmentTask, Keywords = Keywords.ThreadingKeyword)] public unsafe void WorkerThreadAdjustmentAdjustment(double averageThroughput, int newWorkerThreadCount, int stateOrTransition) { if (IsEnabled()) @@ -84,7 +84,7 @@ namespace System.Threading } } - [Event(6, Level = EventLevel.Verbose, Message = WorkerThreadAdjustmentSampleMessage, Opcode = Opcodes.StatsOpcode, Version = 0, Task = Tasks.WorkerThreadAdjustmentTask, Keywords = Keywords.ThreadingKeyword)] + [Event(6, Level = EventLevel.Verbose, Message = WorkerThreadAdjustmentStatsEventMessage, Opcode = Opcodes.StatsOpcode, Version = 0, Task = Tasks.WorkerThreadAdjustmentTask, Keywords = Keywords.ThreadingKeyword)] [CLSCompliant(false)] public unsafe void WorkerThreadAdjustmentStats(double duration, double throughput, double threadWave, double throughputWave, double throughputErrorEstimate, double averageThroughputNoise, double ratio, double confidence, double currentControlSetting, ushort newThreadWaveMagnitude) diff --git a/src/System.Private.CoreLib/shared/System/Threading/ReaderWriterLockSlim.cs b/src/System.Private.CoreLib/shared/System/Threading/ReaderWriterLockSlim.cs index 928f4c62c..ae9da9001 100644 --- a/src/System.Private.CoreLib/shared/System/Threading/ReaderWriterLockSlim.cs +++ b/src/System.Private.CoreLib/shared/System/Threading/ReaderWriterLockSlim.cs @@ -58,7 +58,7 @@ namespace System.Threading // Lock specification for _spinLock: This lock protects exactly the local fields associated with this // instance of ReaderWriterLockSlim. It does NOT protect the memory associated with - // the events that hang off this lock (eg writeEvent, readEvent upgradeEvent). + // the events that are raised by this lock (eg writeEvent, readEvent upgradeEvent). private SpinLock _spinLock; // These variables allow use to avoid Setting events (which is expensive) if we don't have to. diff --git a/src/System.Private.CoreLib/shared/System/Threading/Semaphore.Windows.cs b/src/System.Private.CoreLib/shared/System/Threading/Semaphore.Windows.cs index 9c518df95..605c088af 100644 --- a/src/System.Private.CoreLib/shared/System/Threading/Semaphore.Windows.cs +++ b/src/System.Private.CoreLib/shared/System/Threading/Semaphore.Windows.cs @@ -78,8 +78,7 @@ namespace System.Threading private int ReleaseCore(int releaseCount) { - int previousCount; - if (!Interop.Kernel32.ReleaseSemaphore(SafeWaitHandle!, releaseCount, out previousCount)) + if (!Interop.Kernel32.ReleaseSemaphore(SafeWaitHandle!, releaseCount, out int previousCount)) throw new SemaphoreFullException(); return previousCount; diff --git a/src/System.Private.CoreLib/shared/System/Threading/Semaphore.cs b/src/System.Private.CoreLib/shared/System/Threading/Semaphore.cs index 94ed61502..5a6a58620 100644 --- a/src/System.Private.CoreLib/shared/System/Threading/Semaphore.cs +++ b/src/System.Private.CoreLib/shared/System/Threading/Semaphore.cs @@ -35,8 +35,7 @@ namespace System.Threading public static Semaphore OpenExisting(string name) { - Semaphore? result; - switch (OpenExistingWorker(name, out result)) + switch (OpenExistingWorker(name, out Semaphore? result)) { case OpenExistingResult.NameNotFound: throw new WaitHandleCannotBeOpenedException(); @@ -51,7 +50,7 @@ namespace System.Threading } public static bool TryOpenExisting(string name, [NotNullWhen(true)] out Semaphore? result) => - OpenExistingWorker(name, out result) == OpenExistingResult.Success; + OpenExistingWorker(name, out result!) == OpenExistingResult.Success; public int Release() => ReleaseCore(1); diff --git a/src/System.Private.CoreLib/shared/System/Threading/SemaphoreSlim.cs b/src/System.Private.CoreLib/shared/System/Threading/SemaphoreSlim.cs index 0fd065d3f..5459bee1f 100644 --- a/src/System.Private.CoreLib/shared/System/Threading/SemaphoreSlim.cs +++ b/src/System.Private.CoreLib/shared/System/Threading/SemaphoreSlim.cs @@ -718,7 +718,7 @@ namespace System.Threading // cancel, and we chain the caller's supplied token into it. using (var cts = CancellationTokenSource.CreateLinkedTokenSource(cancellationToken)) { - if (asyncWaiter == await TaskFactory.CommonCWAnyLogic(new Task[] { asyncWaiter, Task.Delay(millisecondsTimeout, cts.Token) }).ConfigureAwait(false)) + if (asyncWaiter == await Task.WhenAny(asyncWaiter, Task.Delay(millisecondsTimeout, cts.Token)).ConfigureAwait(false)) { cts.Cancel(); // ensure that the Task.Delay task is cleaned up return true; // successfully acquired @@ -728,10 +728,10 @@ namespace System.Threading else // millisecondsTimeout == Timeout.Infinite { // Wait until either the task is completed or cancellation is requested. - var cancellationTask = new Task(); + var cancellationTask = new Task(null, TaskCreationOptions.RunContinuationsAsynchronously, promiseStyle: true); using (cancellationToken.UnsafeRegister(s => ((Task)s!).TrySetResult(), cancellationTask)) { - if (asyncWaiter == await TaskFactory.CommonCWAnyLogic(new Task[] { asyncWaiter, cancellationTask }).ConfigureAwait(false)) + if (asyncWaiter == await Task.WhenAny(asyncWaiter, cancellationTask).ConfigureAwait(false)) { return true; // successfully acquired } diff --git a/src/System.Private.CoreLib/shared/System/Threading/Tasks/ConcurrentExclusiveSchedulerPair.cs b/src/System.Private.CoreLib/shared/System/Threading/Tasks/ConcurrentExclusiveSchedulerPair.cs index 04992d550..f8880590c 100644 --- a/src/System.Private.CoreLib/shared/System/Threading/Tasks/ConcurrentExclusiveSchedulerPair.cs +++ b/src/System.Private.CoreLib/shared/System/Threading/Tasks/ConcurrentExclusiveSchedulerPair.cs @@ -366,8 +366,7 @@ namespace System.Threading.Tasks for (int i = 0; i < m_maxItemsPerTask; i++) { // Get the next available exclusive task. If we can't find one, bail. - Task? exclusiveTask; - if (!m_exclusiveTaskScheduler.m_tasks.TryDequeue(out exclusiveTask)) break; + if (!m_exclusiveTaskScheduler.m_tasks.TryDequeue(out Task? exclusiveTask)) break; // Execute the task. If the scheduler was previously faulted, // this task could have been faulted when it was queued; ignore such tasks. @@ -414,8 +413,7 @@ namespace System.Threading.Tasks for (int i = 0; i < m_maxItemsPerTask; i++) { // Get the next available concurrent task. If we can't find one, bail. - Task? concurrentTask; - if (!m_concurrentTaskScheduler.m_tasks.TryDequeue(out concurrentTask)) break; + if (!m_concurrentTaskScheduler.m_tasks.TryDequeue(out Task? concurrentTask)) break; // Execute the task. If the scheduler was previously faulted, // this task could have been faulted when it was queued; ignore such tasks. diff --git a/src/System.Private.CoreLib/shared/System/Threading/Tasks/Future.cs b/src/System.Private.CoreLib/shared/System/Threading/Tasks/Future.cs index ad362be2d..fbfc7d338 100644 --- a/src/System.Private.CoreLib/shared/System/Threading/Tasks/Future.cs +++ b/src/System.Private.CoreLib/shared/System/Threading/Tasks/Future.cs @@ -699,12 +699,10 @@ namespace System.Threading.Tasks ThrowHelper.ThrowArgumentNullException(ExceptionArgument.scheduler); } - TaskCreationOptions creationOptions; - InternalTaskOptions internalOptions; CreationOptionsFromContinuationOptions( continuationOptions, - out creationOptions, - out internalOptions); + out TaskCreationOptions creationOptions, + out InternalTaskOptions internalOptions); Task continuationTask = new ContinuationTaskFromResultTask( this, continuationAction, null, @@ -892,12 +890,10 @@ namespace System.Threading.Tasks ThrowHelper.ThrowArgumentNullException(ExceptionArgument.scheduler); } - TaskCreationOptions creationOptions; - InternalTaskOptions internalOptions; CreationOptionsFromContinuationOptions( continuationOptions, - out creationOptions, - out internalOptions); + out TaskCreationOptions creationOptions, + out InternalTaskOptions internalOptions); Task continuationTask = new ContinuationTaskFromResultTask( this, continuationAction, state, @@ -1108,12 +1104,10 @@ namespace System.Threading.Tasks ThrowHelper.ThrowArgumentNullException(ExceptionArgument.scheduler); } - TaskCreationOptions creationOptions; - InternalTaskOptions internalOptions; CreationOptionsFromContinuationOptions( continuationOptions, - out creationOptions, - out internalOptions); + out TaskCreationOptions creationOptions, + out InternalTaskOptions internalOptions); Task continuationFuture = new ContinuationResultTaskFromResultTask( this, continuationFunction, null, @@ -1331,12 +1325,10 @@ namespace System.Threading.Tasks ThrowHelper.ThrowArgumentNullException(ExceptionArgument.scheduler); } - TaskCreationOptions creationOptions; - InternalTaskOptions internalOptions; CreationOptionsFromContinuationOptions( continuationOptions, - out creationOptions, - out internalOptions); + out TaskCreationOptions creationOptions, + out InternalTaskOptions internalOptions); Task continuationFuture = new ContinuationResultTaskFromResultTask( this, continuationFunction, state, diff --git a/src/System.Private.CoreLib/shared/System/Threading/Tasks/FutureFactory.cs b/src/System.Private.CoreLib/shared/System/Threading/Tasks/FutureFactory.cs index d66db7b73..f3da02daa 100644 --- a/src/System.Private.CoreLib/shared/System/Threading/Tasks/FutureFactory.cs +++ b/src/System.Private.CoreLib/shared/System/Threading/Tasks/FutureFactory.cs @@ -1321,8 +1321,7 @@ namespace System.Threading.Tasks // Used by ContinueWhenAll/Any to bail out early on a pre-canceled token. private static Task CreateCanceledTask(TaskContinuationOptions continuationOptions, CancellationToken ct) { - TaskCreationOptions tco; - Task.CreationOptionsFromContinuationOptions(continuationOptions, out tco, out _); + Task.CreationOptionsFromContinuationOptions(continuationOptions, out TaskCreationOptions tco, out _); return new Task(true, default, tco, ct); } diff --git a/src/System.Private.CoreLib/shared/System/Threading/Tasks/Task.cs b/src/System.Private.CoreLib/shared/System/Threading/Tasks/Task.cs index 38960e6f6..229de2dfa 100644 --- a/src/System.Private.CoreLib/shared/System/Threading/Tasks/Task.cs +++ b/src/System.Private.CoreLib/shared/System/Threading/Tasks/Task.cs @@ -3546,9 +3546,7 @@ namespace System.Threading.Tasks ThrowHelper.ThrowArgumentNullException(ExceptionArgument.scheduler); } - TaskCreationOptions creationOptions; - InternalTaskOptions internalOptions; - CreationOptionsFromContinuationOptions(continuationOptions, out creationOptions, out internalOptions); + CreationOptionsFromContinuationOptions(continuationOptions, out TaskCreationOptions creationOptions, out InternalTaskOptions internalOptions); Task continuationTask = new ContinuationTaskFromTask( this, continuationAction, null, @@ -3736,9 +3734,7 @@ namespace System.Threading.Tasks ThrowHelper.ThrowArgumentNullException(ExceptionArgument.scheduler); } - TaskCreationOptions creationOptions; - InternalTaskOptions internalOptions; - CreationOptionsFromContinuationOptions(continuationOptions, out creationOptions, out internalOptions); + CreationOptionsFromContinuationOptions(continuationOptions, out TaskCreationOptions creationOptions, out InternalTaskOptions internalOptions); Task continuationTask = new ContinuationTaskFromTask( this, continuationAction, state, @@ -3938,9 +3934,7 @@ namespace System.Threading.Tasks ThrowHelper.ThrowArgumentNullException(ExceptionArgument.scheduler); } - TaskCreationOptions creationOptions; - InternalTaskOptions internalOptions; - CreationOptionsFromContinuationOptions(continuationOptions, out creationOptions, out internalOptions); + CreationOptionsFromContinuationOptions(continuationOptions, out TaskCreationOptions creationOptions, out InternalTaskOptions internalOptions); Task continuationTask = new ContinuationResultTaskFromTask( this, continuationFunction, null, @@ -4144,9 +4138,7 @@ namespace System.Threading.Tasks ThrowHelper.ThrowArgumentNullException(ExceptionArgument.scheduler); } - TaskCreationOptions creationOptions; - InternalTaskOptions internalOptions; - CreationOptionsFromContinuationOptions(continuationOptions, out creationOptions, out internalOptions); + CreationOptionsFromContinuationOptions(continuationOptions, out TaskCreationOptions creationOptions, out InternalTaskOptions internalOptions); Task continuationTask = new ContinuationResultTaskFromTask( this, continuationFunction, state, @@ -4303,14 +4295,7 @@ namespace System.Threading.Tasks // Adds a lightweight completion action to a task. This is similar to a continuation // task except that it is stored as an action, and thus does not require the allocation/ // execution resources of a continuation task. - // - // Used internally by ContinueWhenAll() and ContinueWhenAny(). - internal void AddCompletionAction(ITaskCompletionAction action) - { - AddCompletionAction(action, addBeforeOthers: false); - } - - internal void AddCompletionAction(ITaskCompletionAction action, bool addBeforeOthers) + internal void AddCompletionAction(ITaskCompletionAction action, bool addBeforeOthers = false) { if (!AddTaskContinuation(action, addBeforeOthers)) action.Invoke(this); // run the action directly if we failed to queue the continuation (i.e., the task completed) @@ -5964,7 +5949,16 @@ namespace System.Threading.Tasks /// public static Task WhenAny(params Task[] tasks) { - if (tasks == null) ThrowHelper.ThrowArgumentNullException(ExceptionArgument.tasks); + if (tasks == null) + { + ThrowHelper.ThrowArgumentNullException(ExceptionArgument.tasks); + } + + if (tasks.Length == 2) + { + return WhenAny(tasks[0], tasks[1]); + } + if (tasks.Length == 0) { ThrowHelper.ThrowArgumentException(ExceptionResource.Task_MultiTaskContinuation_EmptyTaskList, ExceptionArgument.tasks); @@ -5985,6 +5979,104 @@ namespace System.Threading.Tasks return TaskFactory.CommonCWAnyLogic(tasksCopy); } + // TODO https://github.com/dotnet/runtime/issues/23021: Make this public. + /// Creates a task that will complete when either of the supplied tasks have completed. + /// The first task to wait on for completion. + /// The second task to wait on for completion. + /// A task that represents the completion of one of the supplied tasks. The return Task's Result is the task that completed. + /// + /// The returned task will complete when any of the supplied tasks has completed. The returned task will always end in the RanToCompletion state + /// with its Result set to the first task to complete. This is true even if the first task to complete ended in the Canceled or Faulted state. + /// + /// + /// The or argument was null. + /// + internal static Task WhenAny(Task task1, Task task2) => + (task1 is null) || (task2 is null) ? throw new ArgumentNullException(task1 is null ? nameof(task1) : nameof(task2)) : + task1.IsCompleted ? FromResult(task1) : + task2.IsCompleted ? FromResult(task2) : + new TwoTaskWhenAnyPromise(task1, task2); + + /// A promise type used by WhenAny to wait on exactly two tasks. + /// Specifies the type of the task. + /// + /// This has essentially the same logic as , but optimized + /// for two tasks rather than any number. Exactly two tasks has shown to be the most common use-case by far. + /// + private sealed class TwoTaskWhenAnyPromise : Task, ITaskCompletionAction where TTask : Task + { + private TTask? _task1, _task2; + + /// Instantiate the promise and register it with both tasks as a completion action. + public TwoTaskWhenAnyPromise(TTask task1, TTask task2) + { + Debug.Assert(task1 != null && task2 != null); + _task1 = task1; + _task2 = task2; + + if (AsyncCausalityTracer.LoggingOn) + { + AsyncCausalityTracer.TraceOperationCreation(this, "Task.WhenAny"); + } + + if (s_asyncDebuggingEnabled) + { + AddToActiveTasks(this); + } + + task1.AddCompletionAction(this); + + task2.AddCompletionAction(this); + if (task1.IsCompleted) + { + // If task1 has already completed, Invoke may have tried to remove the continuation from + // each task before task2 added the continuation, in which case it's now referencing the + // already completed continuation. To deal with that race condition, explicitly check + // and remove the continuation here. + task2.RemoveContinuation(this); + } + } + + /// Completes this task when one of the constituent tasks completes. + public void Invoke(Task completingTask) + { + Task? task1; + if ((task1 = Interlocked.Exchange(ref _task1, null)) != null) + { + Task? task2 = _task2; + _task2 = null; + + Debug.Assert(task1 != null && task2 != null); + Debug.Assert(task1.IsCompleted || task2.IsCompleted); + + if (AsyncCausalityTracer.LoggingOn) + { + AsyncCausalityTracer.TraceOperationRelation(this, CausalityRelation.Choice); + AsyncCausalityTracer.TraceOperationCompletion(this, AsyncCausalityStatus.Completed); + } + + if (s_asyncDebuggingEnabled) + { + RemoveFromActiveTasks(this); + } + + if (!task1.IsCompleted) + { + task1.RemoveContinuation(this); + } + else + { + task2.RemoveContinuation(this); + } + + bool success = TrySetResult((TTask)completingTask); + Debug.Assert(success, "Only one task should have gotten to this point, and thus this must be successful."); + } + } + + public bool InvokeMayRunArbitraryCode => true; + } + /// /// Creates a task that will complete when any of the supplied tasks have completed. /// @@ -6043,14 +6135,37 @@ namespace System.Threading.Tasks // return (Task>) WhenAny( (Task[]) tasks); // but classes are not covariant to enable casting Task to Task>. + if (tasks != null && tasks.Length == 2) + { + return WhenAny(tasks[0], tasks[1]); + } + // Call WhenAny(Task[]) for basic functionality - Task intermediate = WhenAny((Task[])tasks); + Task intermediate = WhenAny((Task[])tasks!); // Return a continuation task with the correct result type return intermediate.ContinueWith(Task.TaskWhenAnyCast.Value, default, TaskContinuationOptions.ExecuteSynchronously | TaskContinuationOptions.DenyChildAttach, TaskScheduler.Default); } + // TODO https://github.com/dotnet/runtime/issues/23021: Make this public. + /// Creates a task that will complete when either of the supplied tasks have completed. + /// The first task to wait on for completion. + /// The second task to wait on for completion. + /// A task that represents the completion of one of the supplied tasks. The return Task's Result is the task that completed. + /// + /// The returned task will complete when any of the supplied tasks has completed. The returned task will always end in the RanToCompletion state + /// with its Result set to the first task to complete. This is true even if the first task to complete ended in the Canceled or Faulted state. + /// + /// + /// The or argument was null. + /// + internal static Task> WhenAny(Task task1, Task task2) => + (task1 is null) || (task2 is null) ? throw new ArgumentNullException(task1 is null ? nameof(task1) : nameof(task2)) : + task1.IsCompleted ? FromResult(task1) : + task2.IsCompleted ? FromResult(task2) : + new TwoTaskWhenAnyPromise>(task1, task2); + /// /// Creates a task that will complete when any of the supplied tasks have completed. /// diff --git a/src/System.Private.CoreLib/shared/System/Threading/Tasks/TaskContinuation.cs b/src/System.Private.CoreLib/shared/System/Threading/Tasks/TaskContinuation.cs index c7ebe5386..e2cf8a469 100644 --- a/src/System.Private.CoreLib/shared/System/Threading/Tasks/TaskContinuation.cs +++ b/src/System.Private.CoreLib/shared/System/Threading/Tasks/TaskContinuation.cs @@ -422,9 +422,8 @@ namespace System.Threading.Tasks { return () => { - Guid savedActivityId; Guid activityId = TplEventSource.CreateGuidForTaskID(continuationId); - System.Diagnostics.Tracing.EventSource.SetCurrentThreadActivityId(activityId, out savedActivityId); + System.Diagnostics.Tracing.EventSource.SetCurrentThreadActivityId(activityId, out Guid savedActivityId); try { action(); } finally { System.Diagnostics.Tracing.EventSource.SetCurrentThreadActivityId(savedActivityId); } }; diff --git a/src/System.Private.CoreLib/shared/System/Threading/Thread.Unix.cs b/src/System.Private.CoreLib/shared/System/Threading/Thread.Unix.cs index 902fcf265..35379f1f1 100644 --- a/src/System.Private.CoreLib/shared/System/Threading/Thread.Unix.cs +++ b/src/System.Private.CoreLib/shared/System/Threading/Thread.Unix.cs @@ -2,8 +2,6 @@ // 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 diff --git a/src/System.Private.CoreLib/shared/System/Threading/Thread.cs b/src/System.Private.CoreLib/shared/System/Threading/Thread.cs index 95f7bb702..8bdf89070 100644 --- a/src/System.Private.CoreLib/shared/System/Threading/Thread.cs +++ b/src/System.Private.CoreLib/shared/System/Threading/Thread.cs @@ -347,8 +347,7 @@ namespace System.Threading Dictionary nameToSlotMap = EnsureNameToSlotMap(); lock (nameToSlotMap) { - LocalDataStoreSlot? slot; - if (!nameToSlotMap.TryGetValue(name, out slot)) + if (!nameToSlotMap.TryGetValue(name, out LocalDataStoreSlot? slot)) { slot = AllocateSlot(); nameToSlotMap[name] = slot; diff --git a/src/System.Private.CoreLib/shared/System/Threading/ThreadInt64PersistentCounter.cs b/src/System.Private.CoreLib/shared/System/Threading/ThreadInt64PersistentCounter.cs index 440d38f9e..532962091 100644 --- a/src/System.Private.CoreLib/shared/System/Threading/ThreadInt64PersistentCounter.cs +++ b/src/System.Private.CoreLib/shared/System/Threading/ThreadInt64PersistentCounter.cs @@ -21,7 +21,7 @@ namespace System.Threading [MethodImpl(MethodImplOptions.AggressiveInlining)] public void Increment() { - ThreadLocalNode node = _threadLocalNode.Value; + ThreadLocalNode? node = _threadLocalNode.Value; if (node != null) { node.Increment(); diff --git a/src/System.Private.CoreLib/shared/System/Threading/ThreadPool.Portable.cs b/src/System.Private.CoreLib/shared/System/Threading/ThreadPool.Portable.cs index e63b7e50a..ed0bf45ed 100644 --- a/src/System.Private.CoreLib/shared/System/Threading/ThreadPool.Portable.cs +++ b/src/System.Private.CoreLib/shared/System/Threading/ThreadPool.Portable.cs @@ -3,7 +3,6 @@ // See the LICENSE file in the project root for more information. using System.Diagnostics; -using System.Runtime.InteropServices; using Microsoft.Win32.SafeHandles; namespace System.Threading @@ -29,23 +28,17 @@ namespace System.Threading ~RegisteredWaitHandle() { - if(WaitThread != null) + if (WaitThread != null) { Unregister(null); } } - private static AutoResetEvent s_cachedEvent; + private static AutoResetEvent? s_cachedEvent; - private static AutoResetEvent RentEvent() - { - AutoResetEvent resetEvent = Interlocked.Exchange(ref s_cachedEvent, (AutoResetEvent)null); - if (resetEvent == null) - { - resetEvent = new AutoResetEvent(false); - } - return resetEvent; - } + private static AutoResetEvent RentEvent() => + Interlocked.Exchange(ref s_cachedEvent, null) ?? + new AutoResetEvent(false); private static void ReturnEvent(AutoResetEvent resetEvent) { @@ -60,7 +53,6 @@ namespace System.Threading /// internal _ThreadPoolWaitOrTimerCallback Callback { get; } - /// /// The that was registered. /// @@ -88,7 +80,7 @@ namespace System.Threading /// /// The the user passed in via . /// - private SafeWaitHandle UserUnregisterWaitHandle { get; set; } + private SafeWaitHandle? UserUnregisterWaitHandle { get; set; } private IntPtr UserUnregisterWaitHandleValue { get; set; } @@ -97,14 +89,14 @@ namespace System.Threading /// /// The this was registered on. /// - internal PortableThreadPool.WaitThread WaitThread { get; set; } + internal PortableThreadPool.WaitThread? WaitThread { get; set; } /// /// The number of callbacks that are currently queued on the Thread Pool or executing. /// private int _numRequestedCallbacks; - private LowLevelLock _callbackLock = new LowLevelLock(); + private readonly LowLevelLock _callbackLock = new LowLevelLock(); /// /// Notes if we need to signal the user's unregister event after all callbacks complete. @@ -115,9 +107,9 @@ namespace System.Threading private bool _unregistered; - private AutoResetEvent _callbacksComplete; + private AutoResetEvent? _callbacksComplete; - private AutoResetEvent _removed; + private AutoResetEvent? _removed; /// /// Unregisters this wait handle registration from the wait threads. @@ -128,7 +120,7 @@ namespace System.Threading /// This method will only return true on the first call. /// Passing in a wait handle with a value of -1 will result in a blocking wait, where Unregister will not return until the full unregistration is completed. /// - public bool Unregister(WaitHandle waitObject) + public bool Unregister(WaitHandle? waitObject) { GC.SuppressFinalize(this); _callbackLock.Acquire(); @@ -189,7 +181,7 @@ namespace System.Threading _callbackLock.Release(); } - WaitThread.UnregisterWait(this); + WaitThread!.UnregisterWait(this); return true; } @@ -199,13 +191,13 @@ namespace System.Threading private void SignalUserWaitHandle() { _callbackLock.VerifyIsLocked(); - SafeWaitHandle handle = UserUnregisterWaitHandle; + SafeWaitHandle? handle = UserUnregisterWaitHandle; IntPtr handleValue = UserUnregisterWaitHandleValue; try { if (handleValue != IntPtr.Zero && handleValue != (IntPtr)(-1)) { - Debug.Assert(handleValue == handle.DangerousGetHandle()); + Debug.Assert(handleValue == handle!.DangerousGetHandle()); EventWaitHandle.Set(handle); } } @@ -307,7 +299,7 @@ namespace System.Threading Debug.Assert(IsBlocking); Debug.Assert(_unregisterCalled); // Should only be called when the wait is unregistered by the user. - _callbacksComplete.WaitOne(); + _callbacksComplete!.WaitOne(); ReturnEvent(_callbacksComplete); _callbacksComplete = null; } @@ -317,7 +309,7 @@ namespace System.Threading Debug.Assert(!IsBlocking); Debug.Assert(_unregisterCalled); // Should only be called when the wait is unregistered by the user. - _removed.WaitOne(); + _removed!.WaitOne(); ReturnEvent(_removed); _removed = null; } @@ -408,7 +400,7 @@ namespace System.Threading private static RegisteredWaitHandle RegisterWaitForSingleObject( WaitHandle waitObject, WaitOrTimerCallback callBack, - Object state, + object? state, uint millisecondsTimeOutInterval, bool executeOnlyOnce, bool flowExecutionContext) diff --git a/src/System.Private.CoreLib/shared/System/Threading/ThreadPoolBoundHandle.PlatformNotSupported.cs b/src/System.Private.CoreLib/shared/System/Threading/ThreadPoolBoundHandle.PlatformNotSupported.cs index e97b1e9e8..2da941252 100644 --- a/src/System.Private.CoreLib/shared/System/Threading/ThreadPoolBoundHandle.PlatformNotSupported.cs +++ b/src/System.Private.CoreLib/shared/System/Threading/ThreadPoolBoundHandle.PlatformNotSupported.cs @@ -2,17 +2,13 @@ // The .NET Foundation licenses this file to you under the MIT license. // See the LICENSE file in the project root for more information. -using Microsoft.Win32.SafeHandles; -using System.Diagnostics; using System.Runtime.InteropServices; -using System.Threading; -using System.IO; namespace System.Threading { public sealed class ThreadPoolBoundHandle : IDisposable { - public SafeHandle Handle => null; + public SafeHandle Handle => null!; private ThreadPoolBoundHandle() { @@ -30,7 +26,7 @@ namespace System.Threading } [CLSCompliant(false)] - public unsafe NativeOverlapped* AllocateNativeOverlapped(IOCompletionCallback callback, object state, object pinData) + public unsafe NativeOverlapped* AllocateNativeOverlapped(IOCompletionCallback callback, object? state, object? pinData) { if (callback == null) throw new ArgumentNullException(nameof(callback)); @@ -57,7 +53,7 @@ namespace System.Threading } [CLSCompliant(false)] - public static unsafe object GetNativeOverlappedState(NativeOverlapped* overlapped) + public static unsafe object? GetNativeOverlappedState(NativeOverlapped* overlapped) { if (overlapped == null) throw new ArgumentNullException(nameof(overlapped)); diff --git a/src/System.Private.CoreLib/shared/System/ThrowHelper.cs b/src/System.Private.CoreLib/shared/System/ThrowHelper.cs index 8ddc596a9..30a11b61a 100644 --- a/src/System.Private.CoreLib/shared/System/ThrowHelper.cs +++ b/src/System.Private.CoreLib/shared/System/ThrowHelper.cs @@ -96,6 +96,12 @@ namespace System ExceptionResource.ArgumentOutOfRange_Index); } + [DoesNotReturn] + internal static void ThrowArgumentException_BadComparer(object? comparer) + { + throw new ArgumentException(SR.Format(SR.Arg_BogusIComparer, comparer)); + } + [DoesNotReturn] internal static void ThrowIndexArgumentOutOfRange_NeedNonNegNumException() { @@ -688,6 +694,12 @@ namespace System return "codePoint"; case ExceptionArgument.str: return "str"; + case ExceptionArgument.options: + return "options"; + case ExceptionArgument.prefix: + return "prefix"; + case ExceptionArgument.suffix: + return "suffix"; default: Debug.Fail("The enum value is not defined, please check the ExceptionArgument Enum."); return ""; @@ -840,6 +852,8 @@ namespace System return SR.Arg_TypeNotSupported; case ExceptionResource.Argument_SpansMustHaveSameLength: return SR.Argument_SpansMustHaveSameLength; + case ExceptionResource.Argument_InvalidFlag: + return SR.Argument_InvalidFlag; default: Debug.Fail("The enum value is not defined, please check the ExceptionResource Enum."); return ""; @@ -939,6 +953,9 @@ namespace System year, codePoint, str, + options, + prefix, + suffix, } // @@ -1011,5 +1028,6 @@ namespace System Rank_MultiDimNotSupported, Arg_TypeNotSupported, Argument_SpansMustHaveSameLength, + Argument_InvalidFlag, } } diff --git a/src/System.Private.CoreLib/shared/System/TimeSpan.cs b/src/System.Private.CoreLib/shared/System/TimeSpan.cs index 5cbd47387..4b341799d 100644 --- a/src/System.Private.CoreLib/shared/System/TimeSpan.cs +++ b/src/System.Private.CoreLib/shared/System/TimeSpan.cs @@ -2,6 +2,7 @@ // 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.Diagnostics.CodeAnalysis; using System.Globalization; using System.Runtime.CompilerServices; @@ -200,8 +201,15 @@ namespace System if (double.IsNaN(value)) throw new ArgumentException(SR.Arg_CannotBeNaN); double ticks = value * scale; - if ((ticks > long.MaxValue) || (ticks < long.MinValue)) + return IntervalFromDoubleTicks(ticks); + } + + private static TimeSpan IntervalFromDoubleTicks(double ticks) + { + if ((ticks > long.MaxValue) || (ticks < long.MinValue) || double.IsNaN(ticks)) throw new OverflowException(SR.Overflow_TimeSpanTooLong); + if (ticks == long.MaxValue) + return TimeSpan.MaxValue; return new TimeSpan((long)ticks); } @@ -317,7 +325,7 @@ namespace System ValidateStyles(styles, nameof(styles)); return TimeSpanParse.ParseExactMultiple(input, formats, formatProvider, styles); } - public static bool TryParse(string? s, out TimeSpan result) + public static bool TryParse([NotNullWhen(true)] string? s, out TimeSpan result) { if (s == null) { @@ -331,7 +339,7 @@ namespace System return TimeSpanParse.TryParse(s, null, out result); } - public static bool TryParse(string? input, IFormatProvider? formatProvider, out TimeSpan result) + public static bool TryParse([NotNullWhen(true)] string? input, IFormatProvider? formatProvider, out TimeSpan result) { if (input == null) { @@ -344,7 +352,7 @@ namespace System { return TimeSpanParse.TryParse(input, formatProvider, out result); } - public static bool TryParseExact(string? input, string format, IFormatProvider? formatProvider, out TimeSpan result) + public static bool TryParseExact([NotNullWhen(true)] string? input, [NotNullWhen(true)] string? format, IFormatProvider? formatProvider, out TimeSpan result) { if (input == null || format == null) { @@ -358,7 +366,7 @@ namespace System { return TimeSpanParse.TryParseExact(input, format, formatProvider, TimeSpanStyles.None, out result); } - public static bool TryParseExact(string? input, string[] formats, IFormatProvider? formatProvider, out TimeSpan result) + public static bool TryParseExact([NotNullWhen(true)] string? input, [NotNullWhen(true)] string?[]? formats, IFormatProvider? formatProvider, out TimeSpan result) { if (input == null) { @@ -367,12 +375,12 @@ namespace System } return TimeSpanParse.TryParseExactMultiple(input, formats, formatProvider, TimeSpanStyles.None, out result); } - public static bool TryParseExact(ReadOnlySpan input, string[] formats, IFormatProvider? formatProvider, out TimeSpan result) + public static bool TryParseExact(ReadOnlySpan input, [NotNullWhen(true)] string?[]? formats, IFormatProvider? formatProvider, out TimeSpan result) { return TimeSpanParse.TryParseExactMultiple(input, formats, formatProvider, TimeSpanStyles.None, out result); } - public static bool TryParseExact(string? input, string format, IFormatProvider? formatProvider, TimeSpanStyles styles, out TimeSpan result) + public static bool TryParseExact([NotNullWhen(true)] string? input, [NotNullWhen(true)] string? format, IFormatProvider? formatProvider, TimeSpanStyles styles, out TimeSpan result) { ValidateStyles(styles, nameof(styles)); if (input == null || format == null) @@ -389,7 +397,7 @@ namespace System ValidateStyles(styles, nameof(styles)); return TimeSpanParse.TryParseExact(input, format, formatProvider, styles, out result); } - public static bool TryParseExact(string? input, string[] formats, IFormatProvider? formatProvider, TimeSpanStyles styles, out TimeSpan result) + public static bool TryParseExact([NotNullWhen(true)] string? input, [NotNullWhen(true)] string?[]? formats, IFormatProvider? formatProvider, TimeSpanStyles styles, out TimeSpan result) { ValidateStyles(styles, nameof(styles)); if (input == null) @@ -400,7 +408,7 @@ namespace System return TimeSpanParse.TryParseExactMultiple(input, formats, formatProvider, styles, out result); } - public static bool TryParseExact(ReadOnlySpan input, string[] formats, IFormatProvider? formatProvider, TimeSpanStyles styles, out TimeSpan result) + public static bool TryParseExact(ReadOnlySpan input, [NotNullWhen(true)] string?[]? formats, IFormatProvider? formatProvider, TimeSpanStyles styles, out TimeSpan result) { ValidateStyles(styles, nameof(styles)); return TimeSpanParse.TryParseExactMultiple(input, formats, formatProvider, styles, out result); @@ -447,12 +455,7 @@ namespace System // Rounding to the nearest tick is as close to the result we would have with unlimited // precision as possible, and so likely to have the least potential to surprise. double ticks = Math.Round(timeSpan.Ticks * factor); - if (ticks > long.MaxValue || ticks < long.MinValue) - { - throw new OverflowException(SR.Overflow_TimeSpanTooLong); - } - - return FromTicks((long)ticks); + return IntervalFromDoubleTicks(ticks); } public static TimeSpan operator *(double factor, TimeSpan timeSpan) => timeSpan * factor; @@ -465,12 +468,7 @@ namespace System } double ticks = Math.Round(timeSpan.Ticks / divisor); - if (ticks > long.MaxValue || ticks < long.MinValue || double.IsNaN(ticks)) - { - throw new OverflowException(SR.Overflow_TimeSpanTooLong); - } - - return FromTicks((long)ticks); + return IntervalFromDoubleTicks(ticks); } // Using floating-point arithmetic directly means that infinities can be returned, which is reasonable diff --git a/src/System.Private.CoreLib/shared/System/TimeZoneInfo.StringSerializer.cs b/src/System.Private.CoreLib/shared/System/TimeZoneInfo.StringSerializer.cs index feea5de3f..f40a2faec 100644 --- a/src/System.Private.CoreLib/shared/System/TimeZoneInfo.StringSerializer.cs +++ b/src/System.Private.CoreLib/shared/System/TimeZoneInfo.StringSerializer.cs @@ -332,8 +332,7 @@ namespace System private DateTime GetNextDateTimeValue(string format) { string token = GetNextStringValue(); - DateTime time; - if (!DateTime.TryParseExact(token, format, DateTimeFormatInfo.InvariantInfo, DateTimeStyles.None, out time)) + if (!DateTime.TryParseExact(token, format, DateTimeFormatInfo.InvariantInfo, DateTimeStyles.None, out DateTime time)) { throw new SerializationException(SR.Serialization_InvalidData); } @@ -362,8 +361,7 @@ namespace System private int GetNextInt32Value() { string token = GetNextStringValue(); - int value; - if (!int.TryParse(token, NumberStyles.AllowLeadingSign /* "[sign]digits" */, CultureInfo.InvariantCulture, out value)) + if (!int.TryParse(token, NumberStyles.AllowLeadingSign /* "[sign]digits" */, CultureInfo.InvariantCulture, out int value)) { throw new SerializationException(SR.Serialization_InvalidData); } diff --git a/src/System.Private.CoreLib/shared/System/TimeZoneInfo.Unix.cs b/src/System.Private.CoreLib/shared/System/TimeZoneInfo.Unix.cs index 3a5ecca20..ec137cdd8 100644 --- a/src/System.Private.CoreLib/shared/System/TimeZoneInfo.Unix.cs +++ b/src/System.Private.CoreLib/shared/System/TimeZoneInfo.Unix.cs @@ -11,8 +11,6 @@ using System.IO; using System.Text; using System.Threading; using System.Security; -using System.Runtime.CompilerServices; -using System.Runtime.InteropServices; using Internal.IO; @@ -24,6 +22,7 @@ namespace System private const string ZoneTabFileName = "zone.tab"; private const string TimeZoneEnvironmentVariable = "TZ"; private const string TimeZoneDirectoryEnvironmentVariable = "TZDIR"; + private const string FallbackCultureName = "en-US"; private TimeZoneInfo(byte[] data, string id, bool dstDisabled) { @@ -80,9 +79,10 @@ namespace System } _displayName = _standardDisplayName; - GetDisplayName(Interop.Globalization.TimeZoneDisplayNameType.Generic, ref _displayName); - GetDisplayName(Interop.Globalization.TimeZoneDisplayNameType.Standard, ref _standardDisplayName); - GetDisplayName(Interop.Globalization.TimeZoneDisplayNameType.DaylightSavings, ref _daylightDisplayName); + string uiCulture = CultureInfo.CurrentUICulture.Name.Length == 0 ? FallbackCultureName : CultureInfo.CurrentUICulture.Name; // ICU doesn't work nicely with Invariant + GetDisplayName(Interop.Globalization.TimeZoneDisplayNameType.Generic, uiCulture, ref _displayName); + GetDisplayName(Interop.Globalization.TimeZoneDisplayNameType.Standard, uiCulture, ref _standardDisplayName); + GetDisplayName(Interop.Globalization.TimeZoneDisplayNameType.DaylightSavings, uiCulture, ref _daylightDisplayName); if (_standardDisplayName == _displayName) { @@ -108,7 +108,7 @@ namespace System ValidateTimeZoneInfo(_id, _baseUtcOffset, _adjustmentRules, out _supportsDaylightSavingTime); } - private unsafe void GetDisplayName(Interop.Globalization.TimeZoneDisplayNameType nameType, ref string? displayName) + private unsafe void GetDisplayName(Interop.Globalization.TimeZoneDisplayNameType nameType, string uiCulture, ref string? displayName) { if (GlobalizationMode.Invariant) { @@ -125,11 +125,28 @@ namespace System return Interop.Globalization.GetTimeZoneDisplayName(locale, id, type, bufferPtr, buffer.Length); } }, - CultureInfo.CurrentUICulture.Name, + uiCulture, _id, nameType, out timeZoneDisplayName); + if (!result && uiCulture != FallbackCultureName) + { + // Try to fallback using FallbackCultureName just in case we can make it work. + result = Interop.CallStringMethod( + (buffer, locale, id, type) => + { + fixed (char* bufferPtr = buffer) + { + return Interop.Globalization.GetTimeZoneDisplayName(locale, id, type, bufferPtr, buffer.Length); + } + }, + FallbackCultureName, + _id, + nameType, + out timeZoneDisplayName); + } + // If there is an unknown error, don't set the displayName field. // It will be set to the abbreviation that was read out of the tzfile. if (result) @@ -156,20 +173,20 @@ namespace System for (int i = 0; i < _adjustmentRules.Length; i++) { - var rule = _adjustmentRules[i]; - var start = rule.DateStart.Kind == DateTimeKind.Utc ? + AdjustmentRule? rule = _adjustmentRules[i]; + DateTime start = rule.DateStart.Kind == DateTimeKind.Utc ? // At the daylight start we didn't start the daylight saving yet then we convert to Local time // by adding the _baseUtcOffset to the UTC time new DateTime(rule.DateStart.Ticks + _baseUtcOffset.Ticks, DateTimeKind.Unspecified) : rule.DateStart; - var end = rule.DateEnd.Kind == DateTimeKind.Utc ? + DateTime end = rule.DateEnd.Kind == DateTimeKind.Utc ? // At the daylight saving end, the UTC time is mapped to local time which is already shifted by the daylight delta // we calculate the local time by adding _baseUtcOffset + DaylightDelta to the UTC time new DateTime(rule.DateEnd.Ticks + _baseUtcOffset.Ticks + rule.DaylightDelta.Ticks, DateTimeKind.Unspecified) : rule.DateEnd; - var startTransition = TimeZoneInfo.TransitionTime.CreateFixedDateRule(new DateTime(1, 1, 1, start.Hour, start.Minute, start.Second), start.Month, start.Day); - var endTransition = TimeZoneInfo.TransitionTime.CreateFixedDateRule(new DateTime(1, 1, 1, end.Hour, end.Minute, end.Second), end.Month, end.Day); + TransitionTime startTransition = TimeZoneInfo.TransitionTime.CreateFixedDateRule(new DateTime(1, 1, 1, start.Hour, start.Minute, start.Second), start.Month, start.Day); + TransitionTime endTransition = TimeZoneInfo.TransitionTime.CreateFixedDateRule(new DateTime(1, 1, 1, end.Hour, end.Minute, end.Second), end.Month, end.Day); rules[i] = TimeZoneInfo.AdjustmentRule.CreateAdjustmentRule(start.Date, end.Date, rule.DaylightDelta, startTransition, endTransition); } @@ -919,8 +936,8 @@ namespace System DateTime.MinValue, endTransitionDate.AddTicks(-1), daylightDelta, - default(TransitionTime), - default(TransitionTime), + default, + default, baseUtcDelta, noDaylightTransitions: true); @@ -955,7 +972,7 @@ namespace System } else { - dstStart = default(TransitionTime); + dstStart = default; } AdjustmentRule r = AdjustmentRule.CreateAdjustmentRule( @@ -963,7 +980,7 @@ namespace System endTransitionDate.AddTicks(-1), daylightDelta, dstStart, - default(TransitionTime), + default, baseUtcDelta, noDaylightTransitions: true); @@ -1125,8 +1142,8 @@ namespace System startTransitionDate, DateTime.MaxValue, TimeSpan.Zero, - default(TransitionTime), - default(TransitionTime), + default, + default, baseOffset, noDaylightTransitions: true); } @@ -1340,7 +1357,7 @@ namespace System month = 0; week = 0; - dayOfWeek = default(DayOfWeek); + dayOfWeek = default; return false; } diff --git a/src/System.Private.CoreLib/shared/System/TimeZoneInfo.Win32.cs b/src/System.Private.CoreLib/shared/System/TimeZoneInfo.Win32.cs index 71eced847..afd503453 100644 --- a/src/System.Private.CoreLib/shared/System/TimeZoneInfo.Win32.cs +++ b/src/System.Private.CoreLib/shared/System/TimeZoneInfo.Win32.cs @@ -41,8 +41,7 @@ namespace System private static TimeZoneInfo GetCurrentOneYearLocal() { // load the data from the OS - TIME_ZONE_INFORMATION timeZoneInformation; - uint result = Interop.Kernel32.GetTimeZoneInformation(out timeZoneInformation); + uint result = Interop.Kernel32.GetTimeZoneInformation(out TIME_ZONE_INFORMATION timeZoneInformation); return result == Interop.Kernel32.TIME_ZONE_ID_INVALID ? CreateCustomTimeZone(LocalId, TimeSpan.Zero, LocalId, LocalId) : GetLocalTimeZoneFromWin32Data(timeZoneInformation, dstDisabled: false); @@ -173,14 +172,12 @@ namespace System // // Create an AdjustmentRule with TransitionTime objects // - TransitionTime daylightTransitionStart; - if (!TransitionTimeFromTimeZoneInformation(timeZoneInformation, out daylightTransitionStart, readStartDate: true)) + if (!TransitionTimeFromTimeZoneInformation(timeZoneInformation, out TransitionTime daylightTransitionStart, readStartDate: true)) { return null; } - TransitionTime daylightTransitionEnd; - if (!TransitionTimeFromTimeZoneInformation(timeZoneInformation, out daylightTransitionEnd, readStartDate: false)) + if (!TransitionTimeFromTimeZoneInformation(timeZoneInformation, out TransitionTime daylightTransitionEnd, readStartDate: false)) { return null; } @@ -242,9 +239,8 @@ namespace System // Try using the "kernel32!GetDynamicTimeZoneInformation" API to get the "id" // - TIME_DYNAMIC_ZONE_INFORMATION dynamicTimeZoneInformation; // call kernel32!GetDynamicTimeZoneInformation... - uint result = Interop.Kernel32.GetDynamicTimeZoneInformation(out dynamicTimeZoneInformation); + uint result = Interop.Kernel32.GetDynamicTimeZoneInformation(out TIME_DYNAMIC_ZONE_INFORMATION dynamicTimeZoneInformation); if (result == Interop.Kernel32.TIME_ZONE_ID_INVALID) { // return a dummy entry @@ -569,9 +565,8 @@ namespace System } // read the first year entry - REG_TZI_FORMAT dtzi; - if (!TryGetTimeZoneEntryFromRegistry(dynamicKey, first.ToString(CultureInfo.InvariantCulture), out dtzi)) + if (!TryGetTimeZoneEntryFromRegistry(dynamicKey, first.ToString(CultureInfo.InvariantCulture), out REG_TZI_FORMAT dtzi)) { return false; } @@ -697,8 +692,7 @@ namespace System return false; } - REG_TZI_FORMAT registryTimeZoneInfo; - if (!TryGetTimeZoneEntryFromRegistry(key, TimeZoneInfoValue, out registryTimeZoneInfo)) + if (!TryGetTimeZoneEntryFromRegistry(key, TimeZoneInfoValue, out REG_TZI_FORMAT registryTimeZoneInfo)) { return false; } @@ -765,7 +759,6 @@ namespace System } string filePath; - int resourceId; // get the path to Windows\System32 string system32 = Environment.SystemDirectory; @@ -783,7 +776,7 @@ namespace System return string.Empty; } - if (!int.TryParse(resources[1], NumberStyles.Integer, CultureInfo.InvariantCulture, out resourceId)) + if (!int.TryParse(resources[1], NumberStyles.Integer, CultureInfo.InvariantCulture, out int resourceId)) { return string.Empty; } @@ -939,16 +932,14 @@ namespace System return TimeZoneInfoResult.TimeZoneNotFoundException; } - REG_TZI_FORMAT defaultTimeZoneInformation; - if (!TryGetTimeZoneEntryFromRegistry(key, TimeZoneInfoValue, out defaultTimeZoneInformation)) + if (!TryGetTimeZoneEntryFromRegistry(key, TimeZoneInfoValue, out REG_TZI_FORMAT defaultTimeZoneInformation)) { // the registry value could not be cast to a byte array value = null; return TimeZoneInfoResult.InvalidTimeZoneException; } - AdjustmentRule[]? adjustmentRules; - if (!TryCreateAdjustmentRules(id, defaultTimeZoneInformation, out adjustmentRules, out e, defaultTimeZoneInformation.Bias)) + if (!TryCreateAdjustmentRules(id, defaultTimeZoneInformation, out AdjustmentRule[]? adjustmentRules, out e, defaultTimeZoneInformation.Bias)) { value = null; return TimeZoneInfoResult.InvalidTimeZoneException; diff --git a/src/System.Private.CoreLib/shared/System/TimeZoneInfo.cs b/src/System.Private.CoreLib/shared/System/TimeZoneInfo.cs index af68566a1..73aaa54b1 100644 --- a/src/System.Private.CoreLib/shared/System/TimeZoneInfo.cs +++ b/src/System.Private.CoreLib/shared/System/TimeZoneInfo.cs @@ -158,8 +158,7 @@ namespace System DateTime adjustedTime = ConvertTime(dateTimeOffset, this).DateTime; bool isAmbiguous = false; - int? ruleIndex; - AdjustmentRule? rule = GetAdjustmentRuleForAmbiguousOffsets(adjustedTime, out ruleIndex); + AdjustmentRule? rule = GetAdjustmentRuleForAmbiguousOffsets(adjustedTime, out int? ruleIndex); if (rule != null && rule.HasDaylightSaving) { DaylightTimeStruct daylightTime = GetDaylightTime(adjustedTime.Year, rule, ruleIndex); @@ -218,8 +217,7 @@ namespace System } bool isAmbiguous = false; - int? ruleIndex; - AdjustmentRule? rule = GetAdjustmentRuleForAmbiguousOffsets(adjustedTime, out ruleIndex); + AdjustmentRule? rule = GetAdjustmentRuleForAmbiguousOffsets(adjustedTime, out int? ruleIndex); if (rule != null && rule.HasDaylightSaving) { DaylightTimeStruct daylightTime = GetDaylightTime(adjustedTime.Year, rule, ruleIndex); @@ -406,8 +404,7 @@ namespace System dateTime.Kind == DateTimeKind.Utc ? ConvertTime(dateTime, s_utcTimeZone, this, flags, cachedData) : dateTime; - int? ruleIndex; - AdjustmentRule? rule = GetAdjustmentRuleForTime(adjustedTime, out ruleIndex); + AdjustmentRule? rule = GetAdjustmentRuleForTime(adjustedTime, out int? ruleIndex); if (rule != null && rule.HasDaylightSaving) { DaylightTimeStruct daylightTime = GetDaylightTime(adjustedTime.Year, rule, ruleIndex); @@ -421,8 +418,7 @@ namespace System /// public bool IsDaylightSavingTime(DateTimeOffset dateTimeOffset) { - bool isDaylightSavingTime; - GetUtcOffsetFromUtc(dateTimeOffset.UtcDateTime, this, out isDaylightSavingTime); + GetUtcOffsetFromUtc(dateTimeOffset.UtcDateTime, this, out bool isDaylightSavingTime); return isDaylightSavingTime; } @@ -479,8 +475,7 @@ namespace System // passing in a UTC dateTime to a non-UTC TimeZoneInfo instance is a // special Loss-Less case. // - bool isDaylightSavings; - GetUtcOffsetFromUtc(dateTime, this, out isDaylightSavings); + GetUtcOffsetFromUtc(dateTime, this, out bool isDaylightSavings); return isDaylightSavings; } } @@ -492,8 +487,7 @@ namespace System // // handle the normal cases... // - int? ruleIndex; - AdjustmentRule? rule = GetAdjustmentRuleForTime(adjustedTime, out ruleIndex); + AdjustmentRule? rule = GetAdjustmentRuleForTime(adjustedTime, out int? ruleIndex); if (rule != null && rule.HasDaylightSaving) { DaylightTimeStruct daylightTime = GetDaylightTime(adjustedTime.Year, rule, ruleIndex); @@ -516,8 +510,7 @@ namespace System (dateTime.Kind == DateTimeKind.Local && s_cachedData.GetCorrespondingKind(this) == DateTimeKind.Local)) { // only check Unspecified and (Local when this TimeZoneInfo instance is Local) - int? ruleIndex; - AdjustmentRule? rule = GetAdjustmentRuleForTime(dateTime, out ruleIndex); + AdjustmentRule? rule = GetAdjustmentRuleForTime(dateTime, out int? ruleIndex); if (rule != null && rule.HasDaylightSaving) { @@ -660,8 +653,7 @@ namespace System // performance for the normal case at the expense of the 'ArgumentException' // case and Loss-less Local special cases. // - int? sourceRuleIndex; - AdjustmentRule? sourceRule = sourceTimeZone.GetAdjustmentRuleForTime(dateTime, out sourceRuleIndex); + AdjustmentRule? sourceRule = sourceTimeZone.GetAdjustmentRuleForTime(dateTime, out int? sourceRuleIndex); TimeSpan sourceOffset = sourceTimeZone.BaseUtcOffset; if (sourceRule != null) @@ -696,8 +688,7 @@ namespace System long utcTicks = dateTime.Ticks - sourceOffset.Ticks; // handle the normal case by converting from 'source' to UTC and then to 'target' - bool isAmbiguousLocalDst; - DateTime targetConverted = ConvertUtcToTimeZone(utcTicks, destinationTimeZone, out isAmbiguousLocalDst); + DateTime targetConverted = ConvertUtcToTimeZone(utcTicks, destinationTimeZone, out bool isAmbiguousLocalDst); if (targetKind == DateTimeKind.Local) { @@ -912,8 +903,7 @@ namespace System AdjustmentRule[]? adjustmentRules, bool disableDaylightSavingTime) { - bool adjustmentRulesSupportDst; - ValidateTimeZoneInfo(id, baseUtcOffset, adjustmentRules, out adjustmentRulesSupportDst); + ValidateTimeZoneInfo(id, baseUtcOffset, adjustmentRules, out bool adjustmentRulesSupportDst); _id = id; _baseUtcOffset = baseUtcOffset; @@ -995,8 +985,7 @@ namespace System { try { - bool adjustmentRulesSupportDst; - ValidateTimeZoneInfo(_id, _baseUtcOffset, _adjustmentRules, out adjustmentRulesSupportDst); + ValidateTimeZoneInfo(_id, _baseUtcOffset, _adjustmentRules, out bool adjustmentRulesSupportDst); if (adjustmentRulesSupportDst != _supportsDaylightSavingTime) { @@ -1364,10 +1353,9 @@ namespace System DateTime startTime; if (rule.IsStartDateMarkerForBeginningOfYear() && daylightTime.Start.Year > DateTime.MinValue.Year) { - int? previousYearRuleIndex; AdjustmentRule? previousYearRule = zone.GetAdjustmentRuleForTime( new DateTime(daylightTime.Start.Year - 1, 12, 31), - out previousYearRuleIndex); + out int? previousYearRuleIndex); if (previousYearRule != null && previousYearRule.IsEndDateMarkerForEndOfYear()) { DaylightTimeStruct previousDaylightTime = zone.GetDaylightTime( @@ -1391,10 +1379,9 @@ namespace System DateTime endTime; if (rule.IsEndDateMarkerForEndOfYear() && daylightTime.End.Year < DateTime.MaxValue.Year) { - int? nextYearRuleIndex; AdjustmentRule? nextYearRule = zone.GetAdjustmentRuleForTime( new DateTime(daylightTime.End.Year + 1, 1, 1), - out nextYearRuleIndex); + out int? nextYearRuleIndex); if (nextYearRule != null && nextYearRule.IsStartDateMarkerForBeginningOfYear()) { if (nextYearRule.IsEndDateMarkerForEndOfYear()) @@ -1664,8 +1651,7 @@ namespace System private static TimeSpan GetUtcOffset(DateTime time, TimeZoneInfo zone) { TimeSpan baseOffset = zone.BaseUtcOffset; - int? ruleIndex; - AdjustmentRule? rule = zone.GetAdjustmentRuleForTime(time, out ruleIndex); + AdjustmentRule? rule = zone.GetAdjustmentRuleForTime(time, out int? ruleIndex); if (rule != null) { @@ -1874,9 +1860,8 @@ namespace System private static TimeZoneInfoResult TryGetTimeZoneFromLocalMachine(string id, bool dstDisabled, out TimeZoneInfo? value, out Exception? e, CachedData cachedData) { TimeZoneInfoResult result; - TimeZoneInfo? match; - result = TryGetTimeZoneFromLocalMachine(id, out match, out e); + result = TryGetTimeZoneFromLocalMachine(id, out TimeZoneInfo? match, out e); if (result == TimeZoneInfoResult.Success) { diff --git a/src/System.Private.CoreLib/shared/System/Type.Enum.cs b/src/System.Private.CoreLib/shared/System/Type.Enum.cs index ee9e158ee..59f244f6c 100644 --- a/src/System.Private.CoreLib/shared/System/Type.Enum.cs +++ b/src/System.Private.CoreLib/shared/System/Type.Enum.cs @@ -94,9 +94,7 @@ namespace System if (!IsEnum) throw new ArgumentException(SR.Arg_MustBeEnum, "enumType"); - string[] names; - Array values; - GetEnumData(out names, out values); + GetEnumData(out string[] names, out Array values); return names; } diff --git a/src/System.Private.CoreLib/shared/System/Type.Helpers.cs b/src/System.Private.CoreLib/shared/System/Type.Helpers.cs index a1308fe15..f407ebccd 100644 --- a/src/System.Private.CoreLib/shared/System/Type.Helpers.cs +++ b/src/System.Private.CoreLib/shared/System/Type.Helpers.cs @@ -406,7 +406,7 @@ namespace System case MemberTypes.Constructor: case MemberTypes.Method: { - MethodAttributes criteria = 0; + MethodAttributes criteria; try { int i = (int)filterCriteria; @@ -440,7 +440,7 @@ namespace System } case MemberTypes.Field: { - FieldAttributes criteria = 0; + FieldAttributes criteria; try { int i = (int)filterCriteria; diff --git a/src/System.Private.CoreLib/shared/System/UInt16.cs b/src/System.Private.CoreLib/shared/System/UInt16.cs index c0b2900f8..b33ea2336 100644 --- a/src/System.Private.CoreLib/shared/System/UInt16.cs +++ b/src/System.Private.CoreLib/shared/System/UInt16.cs @@ -2,6 +2,7 @@ // 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.Diagnostics.CodeAnalysis; using System.Globalization; using System.Runtime.CompilerServices; using System.Runtime.InteropServices; @@ -68,12 +69,12 @@ namespace System // Converts the current value to a String in base-10 with no extra padding. public override string ToString() { - return Number.UInt32ToDecStr(m_value, -1); + return Number.UInt32ToDecStr(m_value); } public string ToString(IFormatProvider? provider) { - return Number.FormatUInt32(m_value, null, provider); + return Number.UInt32ToDecStr(m_value); } public string ToString(string? format) @@ -91,14 +92,12 @@ namespace System return Number.TryFormatUInt32(m_value, format, provider, destination, out charsWritten); } - [CLSCompliant(false)] public static ushort Parse(string s) { if (s == null) ThrowHelper.ThrowArgumentNullException(ExceptionArgument.s); return Parse((ReadOnlySpan)s, NumberStyles.Integer, NumberFormatInfo.CurrentInfo); } - [CLSCompliant(false)] public static ushort Parse(string s, NumberStyles style) { NumberFormatInfo.ValidateParseStyleInteger(style); @@ -106,14 +105,12 @@ namespace System return Parse((ReadOnlySpan)s, style, NumberFormatInfo.CurrentInfo); } - [CLSCompliant(false)] public static ushort Parse(string s, IFormatProvider? provider) { if (s == null) ThrowHelper.ThrowArgumentNullException(ExceptionArgument.s); return Parse((ReadOnlySpan)s, NumberStyles.Integer, NumberFormatInfo.GetInstance(provider)); } - [CLSCompliant(false)] public static ushort Parse(string s, NumberStyles style, IFormatProvider? provider) { NumberFormatInfo.ValidateParseStyleInteger(style); @@ -121,7 +118,6 @@ namespace System return Parse((ReadOnlySpan)s, style, NumberFormatInfo.GetInstance(provider)); } - [CLSCompliant(false)] public static ushort Parse(ReadOnlySpan s, NumberStyles style = NumberStyles.Integer, IFormatProvider? provider = null) { NumberFormatInfo.ValidateParseStyleInteger(style); @@ -140,8 +136,7 @@ namespace System return (ushort)i; } - [CLSCompliant(false)] - public static bool TryParse(string? s, out ushort result) + public static bool TryParse([NotNullWhen(true)] string? s, out ushort result) { if (s == null) { @@ -152,14 +147,12 @@ namespace System return TryParse((ReadOnlySpan)s, NumberStyles.Integer, NumberFormatInfo.CurrentInfo, out result); } - [CLSCompliant(false)] public static bool TryParse(ReadOnlySpan s, out ushort result) { return TryParse(s, NumberStyles.Integer, NumberFormatInfo.CurrentInfo, out result); } - [CLSCompliant(false)] - public static bool TryParse(string? s, NumberStyles style, IFormatProvider? provider, out ushort result) + public static bool TryParse([NotNullWhen(true)] string? s, NumberStyles style, IFormatProvider? provider, out ushort result) { NumberFormatInfo.ValidateParseStyleInteger(style); @@ -172,7 +165,6 @@ namespace System return TryParse((ReadOnlySpan)s, style, NumberFormatInfo.GetInstance(provider), out result); } - [CLSCompliant(false)] public static bool TryParse(ReadOnlySpan s, NumberStyles style, IFormatProvider? provider, out ushort result) { NumberFormatInfo.ValidateParseStyleInteger(style); diff --git a/src/System.Private.CoreLib/shared/System/UInt32.cs b/src/System.Private.CoreLib/shared/System/UInt32.cs index f4ef1c6ec..10247a8e9 100644 --- a/src/System.Private.CoreLib/shared/System/UInt32.cs +++ b/src/System.Private.CoreLib/shared/System/UInt32.cs @@ -2,6 +2,7 @@ // 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.Diagnostics.CodeAnalysis; using System.Globalization; using System.Runtime.CompilerServices; using System.Runtime.InteropServices; @@ -78,12 +79,12 @@ namespace System // The base 10 representation of the number with no extra padding. public override string ToString() { - return Number.UInt32ToDecStr(m_value, -1); + return Number.UInt32ToDecStr(m_value); } public string ToString(IFormatProvider? provider) { - return Number.FormatUInt32(m_value, null, provider); + return Number.UInt32ToDecStr(m_value); } public string ToString(string? format) @@ -101,14 +102,12 @@ namespace System return Number.TryFormatUInt32(m_value, format, provider, destination, out charsWritten); } - [CLSCompliant(false)] public static uint Parse(string s) { if (s == null) ThrowHelper.ThrowArgumentNullException(ExceptionArgument.s); return Number.ParseUInt32(s, NumberStyles.Integer, NumberFormatInfo.CurrentInfo); } - [CLSCompliant(false)] public static uint Parse(string s, NumberStyles style) { NumberFormatInfo.ValidateParseStyleInteger(style); @@ -116,14 +115,12 @@ namespace System return Number.ParseUInt32(s, style, NumberFormatInfo.CurrentInfo); } - [CLSCompliant(false)] public static uint Parse(string s, IFormatProvider? provider) { if (s == null) ThrowHelper.ThrowArgumentNullException(ExceptionArgument.s); return Number.ParseUInt32(s, NumberStyles.Integer, NumberFormatInfo.GetInstance(provider)); } - [CLSCompliant(false)] public static uint Parse(string s, NumberStyles style, IFormatProvider? provider) { NumberFormatInfo.ValidateParseStyleInteger(style); @@ -131,15 +128,13 @@ namespace System return Number.ParseUInt32(s, style, NumberFormatInfo.GetInstance(provider)); } - [CLSCompliant(false)] public static uint Parse(ReadOnlySpan s, NumberStyles style = NumberStyles.Integer, IFormatProvider? provider = null) { NumberFormatInfo.ValidateParseStyleInteger(style); return Number.ParseUInt32(s, style, NumberFormatInfo.GetInstance(provider)); } - [CLSCompliant(false)] - public static bool TryParse(string? s, out uint result) + public static bool TryParse([NotNullWhen(true)] string? s, out uint result) { if (s == null) { @@ -150,14 +145,12 @@ namespace System return Number.TryParseUInt32IntegerStyle(s, NumberStyles.Integer, NumberFormatInfo.CurrentInfo, out result) == Number.ParsingStatus.OK; } - [CLSCompliant(false)] public static bool TryParse(ReadOnlySpan s, out uint result) { return Number.TryParseUInt32IntegerStyle(s, NumberStyles.Integer, NumberFormatInfo.CurrentInfo, out result) == Number.ParsingStatus.OK; } - [CLSCompliant(false)] - public static bool TryParse(string? s, NumberStyles style, IFormatProvider? provider, out uint result) + public static bool TryParse([NotNullWhen(true)] string? s, NumberStyles style, IFormatProvider? provider, out uint result) { NumberFormatInfo.ValidateParseStyleInteger(style); @@ -170,7 +163,6 @@ namespace System return Number.TryParseUInt32(s, style, NumberFormatInfo.GetInstance(provider), out result) == Number.ParsingStatus.OK; } - [CLSCompliant(false)] public static bool TryParse(ReadOnlySpan s, NumberStyles style, IFormatProvider? provider, out uint result) { NumberFormatInfo.ValidateParseStyleInteger(style); diff --git a/src/System.Private.CoreLib/shared/System/UInt64.cs b/src/System.Private.CoreLib/shared/System/UInt64.cs index 927d807b3..a86a97793 100644 --- a/src/System.Private.CoreLib/shared/System/UInt64.cs +++ b/src/System.Private.CoreLib/shared/System/UInt64.cs @@ -2,6 +2,7 @@ // 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.Diagnostics.CodeAnalysis; using System.Globalization; using System.Runtime.CompilerServices; using System.Runtime.InteropServices; @@ -82,7 +83,7 @@ namespace System public string ToString(IFormatProvider? provider) { - return Number.FormatUInt64(m_value, null, provider); + return Number.UInt64ToDecStr(m_value, -1); } public string ToString(string? format) @@ -100,14 +101,12 @@ namespace System return Number.TryFormatUInt64(m_value, format, provider, destination, out charsWritten); } - [CLSCompliant(false)] public static ulong Parse(string s) { if (s == null) ThrowHelper.ThrowArgumentNullException(ExceptionArgument.s); return Number.ParseUInt64(s, NumberStyles.Integer, NumberFormatInfo.CurrentInfo); } - [CLSCompliant(false)] public static ulong Parse(string s, NumberStyles style) { NumberFormatInfo.ValidateParseStyleInteger(style); @@ -115,14 +114,12 @@ namespace System return Number.ParseUInt64(s, style, NumberFormatInfo.CurrentInfo); } - [CLSCompliant(false)] public static ulong Parse(string s, IFormatProvider? provider) { if (s == null) ThrowHelper.ThrowArgumentNullException(ExceptionArgument.s); return Number.ParseUInt64(s, NumberStyles.Integer, NumberFormatInfo.GetInstance(provider)); } - [CLSCompliant(false)] public static ulong Parse(string s, NumberStyles style, IFormatProvider? provider) { NumberFormatInfo.ValidateParseStyleInteger(style); @@ -130,15 +127,13 @@ namespace System return Number.ParseUInt64(s, style, NumberFormatInfo.GetInstance(provider)); } - [CLSCompliant(false)] public static ulong Parse(ReadOnlySpan s, NumberStyles style = NumberStyles.Integer, IFormatProvider? provider = null) { NumberFormatInfo.ValidateParseStyleInteger(style); return Number.ParseUInt64(s, style, NumberFormatInfo.GetInstance(provider)); } - [CLSCompliant(false)] - public static bool TryParse(string? s, out ulong result) + public static bool TryParse([NotNullWhen(true)] string? s, out ulong result) { if (s == null) { @@ -149,14 +144,12 @@ namespace System return Number.TryParseUInt64IntegerStyle(s, NumberStyles.Integer, NumberFormatInfo.CurrentInfo, out result) == Number.ParsingStatus.OK; } - [CLSCompliant(false)] public static bool TryParse(ReadOnlySpan s, out ulong result) { return Number.TryParseUInt64IntegerStyle(s, NumberStyles.Integer, NumberFormatInfo.CurrentInfo, out result) == Number.ParsingStatus.OK; } - [CLSCompliant(false)] - public static bool TryParse(string? s, NumberStyles style, IFormatProvider? provider, out ulong result) + public static bool TryParse([NotNullWhen(true)] string? s, NumberStyles style, IFormatProvider? provider, out ulong result) { NumberFormatInfo.ValidateParseStyleInteger(style); @@ -169,7 +162,6 @@ namespace System return Number.TryParseUInt64(s, style, NumberFormatInfo.GetInstance(provider), out result) == Number.ParsingStatus.OK; } - [CLSCompliant(false)] public static bool TryParse(ReadOnlySpan s, NumberStyles style, IFormatProvider? provider, out ulong result) { NumberFormatInfo.ValidateParseStyleInteger(style); diff --git a/src/System.Private.CoreLib/shared/System/UIntPtr.cs b/src/System.Private.CoreLib/shared/System/UIntPtr.cs index 217e1566c..99eb0cf75 100644 --- a/src/System.Private.CoreLib/shared/System/UIntPtr.cs +++ b/src/System.Private.CoreLib/shared/System/UIntPtr.cs @@ -4,8 +4,10 @@ using System.Globalization; using System.Runtime.CompilerServices; +using System.Runtime.InteropServices; using System.Runtime.Serialization; using System.Runtime.Versioning; +using Internal.Runtime.CompilerServices; #pragma warning disable SA1121 // explicitly using type aliases instead of built-in types #if TARGET_64BIT @@ -18,8 +20,9 @@ namespace System { [Serializable] [CLSCompliant(false)] + [StructLayout(LayoutKind.Sequential)] [System.Runtime.CompilerServices.TypeForwardedFrom("mscorlib, Version=4.0.0.0, Culture=neutral, PublicKeyToken=b77a5c561934e089")] - public readonly struct UIntPtr : IEquatable, ISerializable + public readonly struct UIntPtr : IEquatable, IComparable, IComparable, IFormattable, ISerializable { private readonly unsafe void* _value; // Do not rename (binary serialization) @@ -75,9 +78,6 @@ namespace System return false; } - unsafe bool IEquatable.Equals(UIntPtr other) => - _value == other._value; - public override unsafe int GetHashCode() { #if TARGET_64BIT @@ -162,7 +162,60 @@ namespace System [NonVersionable] public unsafe void* ToPointer() => _value; - public override unsafe string ToString() => - ((nuint)_value).ToString(CultureInfo.InvariantCulture); + public static UIntPtr MaxValue + { + [NonVersionable] + get => (UIntPtr)nuint.MaxValue; + } + + public static UIntPtr MinValue + { + [NonVersionable] + get => (UIntPtr)nuint.MinValue; + } + + public unsafe int CompareTo(object? value) + { + if (value is null) + { + return 1; + } + if (value is UIntPtr o) + { + nuint i = (nuint)o; + if ((nuint)_value < i) return -1; + if ((nuint)_value > i) return 1; + return 0; + } + + throw new ArgumentException(SR.Arg_MustBeUIntPtr); + } + + public unsafe int CompareTo(UIntPtr value) => ((nuint)_value).CompareTo((nuint)value); + + [NonVersionable] + public unsafe bool Equals(UIntPtr other) => (nuint)_value == (nuint)other; + + public unsafe override string ToString() => ((nuint)_value).ToString(); + public unsafe string ToString(string? format) => ((nuint)_value).ToString(format); + public unsafe string ToString(IFormatProvider? provider) => ((nuint)_value).ToString(provider); + public unsafe string ToString(string? format, IFormatProvider? provider) => ((nuint)_value).ToString(format, provider); + + public static UIntPtr Parse(string s) => (UIntPtr)nuint.Parse(s); + public static UIntPtr Parse(string s, NumberStyles style) => (UIntPtr)nuint.Parse(s, style); + public static UIntPtr Parse(string s, IFormatProvider? provider) => (UIntPtr)nuint.Parse(s, provider); + public static UIntPtr Parse(string s, NumberStyles style, IFormatProvider? provider) => (UIntPtr)nuint.Parse(s, style, provider); + + public static bool TryParse(string? s, out UIntPtr result) + { + Unsafe.SkipInit(out result); + return nuint.TryParse(s, out Unsafe.As(ref result)); + } + + public static bool TryParse(string? s, NumberStyles style, IFormatProvider? provider, out UIntPtr result) + { + Unsafe.SkipInit(out result); + return nuint.TryParse(s, style, provider, out Unsafe.As(ref result)); + } } } diff --git a/src/System.Private.CoreLib/shared/System/Version.cs b/src/System.Private.CoreLib/shared/System/Version.cs index 978e805cb..8a354d40e 100644 --- a/src/System.Private.CoreLib/shared/System/Version.cs +++ b/src/System.Private.CoreLib/shared/System/Version.cs @@ -293,7 +293,7 @@ namespace System public static Version Parse(ReadOnlySpan input) => ParseVersion(input, throwOnFailure: true)!; - public static bool TryParse(string? input, [NotNullWhen(true)] out Version? result) + public static bool TryParse([NotNullWhen(true)] string? input, [NotNullWhen(true)] out Version? result) { if (input == null) { diff --git a/src/System.Private.CoreLib/src/Interop/Unix/Interop.Libraries.cs b/src/System.Private.CoreLib/src/Interop/Unix/Interop.Libraries.cs index 7b0a290bd..0bc915371 100644 --- a/src/System.Private.CoreLib/src/Interop/Unix/Interop.Libraries.cs +++ b/src/System.Private.CoreLib/src/Interop/Unix/Interop.Libraries.cs @@ -6,6 +6,6 @@ internal static partial class Interop { internal static partial class Libraries { - internal const string CoreLibNative = "System.Private.CoreLib.Native"; + internal const string CoreLibNative = "libSystem.Private.CoreLib.Native"; } } diff --git a/src/System.Private.CoreLib/src/Resources/Strings.resx b/src/System.Private.CoreLib/src/Resources/Strings.resx index 9559d7593..f0e00329a 100644 --- a/src/System.Private.CoreLib/src/Resources/Strings.resx +++ b/src/System.Private.CoreLib/src/Resources/Strings.resx @@ -345,6 +345,9 @@ Object must be of type Int64. + + Object must be of type IntPtr. + Object must be an array of primitives. @@ -381,6 +384,9 @@ Object must be of type UInt64. + + Object must be of type UIntPtr. + Object must be of type Version. @@ -2278,8 +2284,8 @@ Corrupt .resources file. Invalid offset into data section is - - Too many bytes in what should have been a 7 bit encoded Int32. + + Too many bytes in what should have been a 7-bit encoded integer. Corrupt .resources file. The specified type doesn't exist. diff --git a/src/System.Private.CoreLib/src/System/Globalization/GlobalizationMode.Unix.cs b/src/System.Private.CoreLib/src/System/Globalization/GlobalizationMode.Unix.cs index 5a6b74e5d..97f1de8f7 100644 --- a/src/System.Private.CoreLib/src/System/Globalization/GlobalizationMode.Unix.cs +++ b/src/System.Private.CoreLib/src/System/Globalization/GlobalizationMode.Unix.cs @@ -27,5 +27,7 @@ namespace System.Globalization } return invariantEnabled; } + + internal static bool UseNls => false; } } diff --git a/src/System.Private.CoreLib/src/System/Globalization/GlobalizationMode.Windows.cs b/src/System.Private.CoreLib/src/System/Globalization/GlobalizationMode.Windows.cs index 7c6bf0161..1dd331194 100644 --- a/src/System.Private.CoreLib/src/System/Globalization/GlobalizationMode.Windows.cs +++ b/src/System.Private.CoreLib/src/System/Globalization/GlobalizationMode.Windows.cs @@ -12,5 +12,8 @@ namespace System.Globalization // return CLRConfig.GetBoolValue(c_InvariantModeConfigSwitch); return false; } + + // CORERT-TODO: Enable Icu on Windows + internal static bool UseNls => true; } } diff --git a/src/System.Private.CoreLib/src/System/Runtime/InteropServices/Marshal.Com.cs b/src/System.Private.CoreLib/src/System/Runtime/InteropServices/Marshal.Com.cs index c9a237d64..c05d4b850 100644 --- a/src/System.Private.CoreLib/src/System/Runtime/InteropServices/Marshal.Com.cs +++ b/src/System.Private.CoreLib/src/System/Runtime/InteropServices/Marshal.Com.cs @@ -95,6 +95,11 @@ namespace System.Runtime.InteropServices return (IntPtr)(-1); } + public static IntPtr GetIDispatchForObject(object o) + { + throw new PlatformNotSupportedException(SR.PlatformNotSupported_ComInterop); + } + public static IntPtr GetIUnknownForObject(object o) { throw new PlatformNotSupportedException(SR.PlatformNotSupported_ComInterop); @@ -151,7 +156,7 @@ namespace System.Runtime.InteropServices throw new PlatformNotSupportedException(SR.PlatformNotSupported_ComInterop); } - public static Type GetTypeFromCLSID(Guid clsid) + public static Type? GetTypeFromCLSID(Guid clsid) { throw new PlatformNotSupportedException(SR.PlatformNotSupported_ComInterop); } diff --git a/src/System.Private.CoreLib/src/System/Runtime/InteropServices/NativeLibrary.CoreRT.cs b/src/System.Private.CoreLib/src/System/Runtime/InteropServices/NativeLibrary.CoreRT.cs index 7c84f9cea..9cb70d3f8 100644 --- a/src/System.Private.CoreLib/src/System/Runtime/InteropServices/NativeLibrary.CoreRT.cs +++ b/src/System.Private.CoreLib/src/System/Runtime/InteropServices/NativeLibrary.CoreRT.cs @@ -13,7 +13,7 @@ namespace System.Runtime.InteropServices { public static partial class NativeLibrary { - internal static IntPtr LoadByName(string libraryName, Assembly assembly, DllImportSearchPath? searchPath, bool throwOnError) + internal static IntPtr LoadLibraryByName(string libraryName, Assembly assembly, DllImportSearchPath? searchPath, bool throwOnError) { // First checks if a default dllImportSearchPathFlags was passed in, if so, use that value. // Otherwise checks if the assembly has the DefaultDllImportSearchPathsAttribute attribute. diff --git a/tests/TopN.CoreFX.Windows.issues.json b/tests/TopN.CoreFX.Windows.issues.json index a47d4729a..d08700eb5 100644 --- a/tests/TopN.CoreFX.Windows.issues.json +++ b/tests/TopN.CoreFX.Windows.issues.json @@ -2271,6 +2271,10 @@ { "name": "System.Tests.StringTests.ToUpperNullCulture", "reason": "outdated" + }, + { + "name": "System.Tests.StringTests.LastIndexOf_EmptyString", + "reason": "outdated" } ] }