From 4919275003a2f3742b2b80bcddac5dcb0a2b7833 Mon Sep 17 00:00:00 2001 From: Stephen Toub Date: Thu, 16 Jun 2022 10:56:55 -0400 Subject: [PATCH] Use Roslyn support for RuntimeHelpers.CreateSpan The optimization that previously extended only to byte/sbyte/bool now also supports char/ushort/short/uint/int/ulong/long/float/double. --- .../src/System/Data/Filter/Operators.cs | 50 +++++++------- .../src/System/Data/SQLTypes/SQLDateTime.cs | 21 +++--- .../src/System/Data/SQLTypes/SQLDecimal.cs | 62 ++++++++--------- .../Diagnostics/FileVersionInfo.Windows.cs | 24 +++---- .../src/System/Drawing/KnownColorTable.cs | 15 +++-- .../DeflateManaged/InflaterManaged.cs | 10 +-- .../Http/SocketsHttpHandler/Http2Stream.cs | 4 +- .../Net/Http/SocketsHttpHandler/MultiProxy.cs | 11 ++-- .../src/System/Net/HttpListenerResponse.cs | 17 ++--- .../Managed/HttpListenerRequest.Managed.cs | 4 +- .../src/System/Net/Cookie.cs | 13 ++-- .../Utf8Formatter/Utf8Formatter.Date.L.cs | 4 +- .../Utf8Formatter/Utf8Formatter.Date.R.cs | 4 +- .../Text/Utf8Formatter/Utf8Formatter.Date.cs | 8 +-- .../Utf8Parser/Utf8Parser.Date.Helpers.cs | 6 +- .../src/System/Convert.cs | 22 +++---- .../src/System/DateTime.Windows.cs | 2 +- .../src/System/DateTime.cs | 28 ++++---- .../src/System/Decimal.DecCalc.cs | 54 +++++++-------- .../CalendricalCalculationsHelper.cs | 39 +++++------ .../System/Globalization/DateTimeFormat.cs | 6 +- .../Globalization/DateTimeFormatInfo.cs | 8 +-- .../src/System/Globalization/DateTimeParse.cs | 18 +++-- .../EastAsianLunisolarCalendar.cs | 11 ++-- .../System/Globalization/GregorianCalendar.cs | 10 +-- .../Globalization/GregorianCalendarHelper.cs | 16 +---- .../src/System/Globalization/HijriCalendar.cs | 8 +-- .../Globalization/IcuLocaleData.generator.cs | 24 +++---- .../src/System/Globalization/IdnMapping.cs | 8 +-- .../System/Globalization/JulianCalendar.cs | 20 ++---- .../System/Globalization/PersianCalendar.cs | 10 +-- .../FileSystemEnumerableFactory.cs | 13 ++-- .../System/IO/Enumeration/FileSystemName.cs | 20 ++---- .../System.Private.CoreLib/src/System/Math.cs | 4 +- .../src/System/MathF.cs | 4 +- .../src/System/Number.BigInteger.cs | 32 ++++----- .../src/System/Number.Grisu3.cs | 30 ++++----- .../Number.NumberToFloatingPointBits.cs | 6 +- .../System/Reflection/AssemblyNameParser.cs | 3 +- .../src/System/Security/SecurityElement.cs | 36 +++------- .../Text/EncoderLatin1BestFitFallback.Data.cs | 2 +- .../Text/EncoderLatin1BestFitFallback.cs | 15 ++--- .../src/System/Text/EncodingData.cs | 66 +++++++++---------- .../src/System/Text/EncodingTable.cs | 42 ++++++------ .../src/System/TimeZoneInfo.Unix.cs | 2 +- .../Runtime/Serialization/Json/JsonGlobals.cs | 1 - .../Json/JsonObjectDataContract.cs | 2 +- .../Runtime/Serialization/ObjectToIdCache.cs | 30 +++++---- .../src/System/Xml/UniqueId.cs | 4 +- .../src/System/DomainNameHelper.cs | 5 +- .../System.Private.Uri/src/System/Uri.cs | 13 ++-- .../src/System/Xml/Linq/XNodeReader.cs | 4 +- .../src/System/Xml/XPath/XNodeNavigator.cs | 4 +- .../src/System/Xml/Schema/XsdBuilder.cs | 6 +- .../src/System/Xml/Schema/XsdDateTime.cs | 24 +++---- .../src/System/Xml/XPath/XPathNavigator.cs | 10 +-- .../System/Xml/Xsl/Runtime/NumberFormatter.cs | 12 ++-- .../src/System/Xml/Xsl/XPathConvert.cs | 2 +- .../src/System/Numerics/BigNumber.cs | 6 +- .../SHAHashProvider.Browser.Managed.cs | 6 +- .../X509Certificates/X500NameEncoder.cs | 18 ++--- .../RegexCaseEquivalences.Data.cs | 21 +++++- .../RegexCaseEquivalences.cs | 15 +++-- .../tools/DataTable.cs | 35 ++++++++-- 64 files changed, 501 insertions(+), 529 deletions(-) diff --git a/src/libraries/System.Data.Common/src/System/Data/Filter/Operators.cs b/src/libraries/System.Data.Common/src/System/Data/Filter/Operators.cs index 75e35ce37734f..9a5b62b516894 100644 --- a/src/libraries/System.Data.Common/src/System/Data/Filter/Operators.cs +++ b/src/libraries/System.Data.Common/src/System/Data/Filter/Operators.cs @@ -119,34 +119,32 @@ internal static bool IsRelational(int op) /// Mapping from Operator to priorities /// CONSIDER: fast, but hard to maintain /// - - private static readonly int[] s_priority = new int[] { - priStart, // Noop - priNeg, priNeg, priNot, // Unary -, +, Not - priBetweenAnd, priBetweenInLike, priBetweenInLike, - priRelOp, priRelOp, priRelOp, priRelOp, priRelOp, priRelOp, - priIs, - priBetweenInLike, // Like - - priPlusMinus, priPlusMinus, // +, - - priMulDiv, priMulDiv, priIDiv, priMod, // *, /, \, Mod - priExp, // ** - - priAnd, priOr, priXor, priNot, - priAnd, priOr, - - priParen, priProc, priDot, priDot, // Proc, Iff, Qula, Dot.. - - priMax, priMax, priMax, priMax, priMax, priMax, priMax, - priMax, priMax, priMax, priMax, - priMax, - }; - internal static int Priority(int op) { - if ((uint)op >= (uint)s_priority.Length) - return priMax; - return s_priority[op]; + ReadOnlySpan priority = new int[] + { + priStart, // Noop + priNeg, priNeg, priNot, // Unary -, +, Not + priBetweenAnd, priBetweenInLike, priBetweenInLike, + priRelOp, priRelOp, priRelOp, priRelOp, priRelOp, priRelOp, + priIs, + priBetweenInLike, // Like + + priPlusMinus, priPlusMinus, // +, - + priMulDiv, priMulDiv, priIDiv, priMod, // *, /, \, Mod + priExp, // ** + + priAnd, priOr, priXor, priNot, + priAnd, priOr, + + priParen, priProc, priDot, priDot, // Proc, Iff, Qula, Dot.. + + priMax, priMax, priMax, priMax, priMax, priMax, priMax, + priMax, priMax, priMax, priMax, + priMax, + }; + + return (uint)op < (uint)priority.Length ? priority[op] : priMax; } /// diff --git a/src/libraries/System.Data.Common/src/System/Data/SQLTypes/SQLDateTime.cs b/src/libraries/System.Data.Common/src/System/Data/SQLTypes/SQLDateTime.cs index 2b246f2d40c76..2cb46b3f36af3 100644 --- a/src/libraries/System.Data.Common/src/System/Data/SQLTypes/SQLDateTime.cs +++ b/src/libraries/System.Data.Common/src/System/Data/SQLTypes/SQLDateTime.cs @@ -36,8 +36,6 @@ public struct SqlDateTime : INullable, IComparable, IXmlSerializable, IEquatable public static readonly int SQLTicksPerHour = SQLTicksPerMinute * 60; private static readonly int s_SQLTicksPerDay = SQLTicksPerHour * 24; - private const long s_ticksPerSecond = TimeSpan.TicksPerMillisecond * 1000; - private static readonly DateTime s_SQLBaseDate = new DateTime(1900, 1, 1); private static readonly long s_SQLBaseDateTicks = s_SQLBaseDate.Ticks; @@ -51,17 +49,14 @@ public struct SqlDateTime : INullable, IComparable, IXmlSerializable, IEquatable private const int s_dayBase = 693595; // Jan 1 1900 is this many days from Jan 1 0001 - - private static readonly int[] s_daysToMonth365 = new int[] { + private static ReadOnlySpan DaysToMonth365 => new int[] { 0, 31, 59, 90, 120, 151, 181, 212, 243, 273, 304, 334, 365}; - private static readonly int[] s_daysToMonth366 = new int[] { + private static ReadOnlySpan DaysToMonth366 => new int[] { 0, 31, 60, 91, 121, 152, 182, 213, 244, 274, 305, 335, 366}; - private static readonly DateTime s_minDateTime = new DateTime(1753, 1, 1); - private static readonly DateTime s_maxDateTime = DateTime.MaxValue; - private static readonly TimeSpan s_minTimeSpan = s_minDateTime.Subtract(s_SQLBaseDate); - private static readonly TimeSpan s_maxTimeSpan = s_maxDateTime.Subtract(s_SQLBaseDate); - private const string s_ISO8601_DateTimeFormat = "yyyy-MM-ddTHH:mm:ss.fff"; + private static readonly TimeSpan s_minTimeSpan = new DateTime(1753, 1, 1).Subtract(s_SQLBaseDate); + private static readonly TimeSpan s_maxTimeSpan = DateTime.MaxValue.Subtract(s_SQLBaseDate); + private const string ISO8601_DateTimeFormat = "yyyy-MM-ddTHH:mm:ss.fff"; // These formats are valid styles in SQL Server (style 9, 12, 13, 14) // but couldn't be recognized by the default parse. Needs to call @@ -105,7 +100,9 @@ public SqlDateTime(int year, int month, int day, int hour, int minute, int secon { if (year >= s_minYear && year <= s_maxYear && month >= 1 && month <= 12) { - int[] days = IsLeapYear(year) ? s_daysToMonth366 : s_daysToMonth365; + ReadOnlySpan days = IsLeapYear(year) ? + DaysToMonth366 : + DaysToMonth365; if (day >= 1 && day <= days[month] - days[month - 1]) { int y = year - 1; @@ -670,7 +667,7 @@ void IXmlSerializable.WriteXml(XmlWriter writer) } else { - writer.WriteString(XmlConvert.ToString(Value, s_ISO8601_DateTimeFormat)); + writer.WriteString(XmlConvert.ToString(Value, ISO8601_DateTimeFormat)); } } diff --git a/src/libraries/System.Data.Common/src/System/Data/SQLTypes/SQLDecimal.cs b/src/libraries/System.Data.Common/src/System/Data/SQLTypes/SQLDecimal.cs index db617033a8f76..9d7af7bb1440a 100644 --- a/src/libraries/System.Data.Common/src/System/Data/SQLTypes/SQLDecimal.cs +++ b/src/libraries/System.Data.Common/src/System/Data/SQLTypes/SQLDecimal.cs @@ -71,7 +71,7 @@ public struct SqlDecimal : INullable, IComparable, IXmlSerializable, IEquatable< private const byte s_cNumeDivScaleMin = 6; // Minimum result scale of numeric division // Array of multipliers for lAdjust and Ceiling/Floor. - private static readonly uint[] s_rgulShiftBase = new uint[9] { + private static ReadOnlySpan RgulShiftBase => new uint[9] { 10, 10 * 10, 10 * 10 * 10, @@ -130,7 +130,7 @@ public static void CreateDecimalHelperTable() #endregion #region DecimalHelperTable - private static readonly uint[] s_decimalHelpersLo = { + private static ReadOnlySpan DecimalHelpersLo => new uint[] { 0x0000000a, // precision:2, value:10 0x00000064, // precision:3, value:100 0x000003e8, // precision:4, value:1000 @@ -171,7 +171,7 @@ public static void CreateDecimalHelperTable() 0x00000000, // precision:38+1, value:99999999999999999999999999999999999999+1 }; - private static readonly uint[] s_decimalHelpersMid = { + private static ReadOnlySpan DecimalHelpersMid => new uint[] { 0x00000000, // precision:2, value:10 0x00000000, // precision:3, value:100 0x00000000, // precision:4, value:1000 @@ -212,7 +212,7 @@ public static void CreateDecimalHelperTable() 0x098a2240, // precision:38+1, value:99999999999999999999999999999999999999+1 }; - private static readonly uint[] s_decimalHelpersHi = { + private static ReadOnlySpan DecimalHelpersHi => new uint[] { 0x00000000, // precision:2, value:10 0x00000000, // precision:3, value:100 0x00000000, // precision:4, value:1000 @@ -253,7 +253,7 @@ public static void CreateDecimalHelperTable() 0x5a86c47a, // precision:38+1, value:99999999999999999999999999999999999999+1 }; - private static readonly uint[] s_decimalHelpersHiHi = { + private static ReadOnlySpan DecimalHelpersHiHi => new uint[] { 0x00000000, // precision:2, value:10 0x00000000, // precision:3, value:100 0x00000000, // precision:4, value:1000 @@ -313,31 +313,31 @@ private byte CalculatePrecision() { int tableIndex; byte precision; - uint[] decimalHelpers; + ReadOnlySpan decimalHelpers; uint decimalPart; if (_data4 != 0) { tableIndex = HelperTableStartIndexHiHi; - decimalHelpers = s_decimalHelpersHiHi; + decimalHelpers = DecimalHelpersHiHi; decimalPart = _data4; } else if (_data3 != 0) { tableIndex = HelperTableStartIndexHi; - decimalHelpers = s_decimalHelpersHi; + decimalHelpers = DecimalHelpersHi; decimalPart = _data3; } else if (_data2 != 0) { tableIndex = HelperTableStartIndexMid; - decimalHelpers = s_decimalHelpersMid; + decimalHelpers = DecimalHelpersMid; decimalPart = _data2; } else { tableIndex = HelperTableStartIndexLo; - decimalHelpers = s_decimalHelpersLo; + decimalHelpers = DecimalHelpersLo; decimalPart = _data1; } @@ -429,25 +429,25 @@ private bool VerifyPrecision(byte precision) Debug.Assert(precision <= MaxPrecision, "Precision > MaxPrecision"); int tableIndex = checked((precision - 1)); - if (_data4 < s_decimalHelpersHiHi[tableIndex]) + if (_data4 < DecimalHelpersHiHi[tableIndex]) { return true; } - else if (_data4 == s_decimalHelpersHiHi[tableIndex]) + else if (_data4 == DecimalHelpersHiHi[tableIndex]) { - if (_data3 < s_decimalHelpersHi[tableIndex]) + if (_data3 < DecimalHelpersHi[tableIndex]) { return true; } - else if (_data3 == s_decimalHelpersHi[tableIndex]) + else if (_data3 == DecimalHelpersHi[tableIndex]) { - if (_data2 < s_decimalHelpersMid[tableIndex]) + if (_data2 < DecimalHelpersMid[tableIndex]) { return true; } - else if (_data2 == s_decimalHelpersMid[tableIndex]) + else if (_data2 == DecimalHelpersMid[tableIndex]) { - if (_data1 < s_decimalHelpersLo[tableIndex]) + if (_data1 < DecimalHelpersLo[tableIndex]) { return true; } @@ -756,9 +756,9 @@ public SqlDecimal(double dVal) : this(false) { ulLenDelta = (ulLen >= 9) ? 9 : ulLen; - dFrac *= s_rgulShiftBase[(int)ulLenDelta - 1]; + dFrac *= RgulShiftBase[(int)ulLenDelta - 1]; ulLen -= ulLenDelta; - MultByULong(s_rgulShiftBase[(int)ulLenDelta - 1]); + MultByULong(RgulShiftBase[(int)ulLenDelta - 1]); AddULong((uint)dFrac); dFrac -= Math.Floor(dFrac); } @@ -1525,12 +1525,12 @@ public static explicit operator decimal(SqlDecimal x) { if (lScaleAdjust <= -9) { - ulShiftBase = s_rgulShiftBase[8]; + ulShiftBase = RgulShiftBase[8]; lScaleAdjust += 9; } else { - ulShiftBase = s_rgulShiftBase[-lScaleAdjust - 1]; + ulShiftBase = RgulShiftBase[-lScaleAdjust - 1]; lScaleAdjust = 0; } MpDiv1(rgulRes, ref culRes, ulShiftBase, out ulRem); @@ -2287,12 +2287,12 @@ internal void AdjustScale(int digits, bool fRound) //if lAdjust>=9, downshift by 10^9 each time, otherwise by the full amount if (lAdjust >= 9) { - ulShiftBase = s_rgulShiftBase[8]; + ulShiftBase = RgulShiftBase[8]; lAdjust -= 9; } else { - ulShiftBase = s_rgulShiftBase[lAdjust - 1]; + ulShiftBase = RgulShiftBase[lAdjust - 1]; lAdjust = 0; } MultByULong(ulShiftBase); @@ -2304,12 +2304,12 @@ internal void AdjustScale(int digits, bool fRound) { if (lAdjust <= -9) { - ulShiftBase = s_rgulShiftBase[8]; + ulShiftBase = RgulShiftBase[8]; lAdjust += 9; } else { - ulShiftBase = s_rgulShiftBase[-lAdjust - 1]; + ulShiftBase = RgulShiftBase[-lAdjust - 1]; lAdjust = 0; } ulRem = DivByULong(ulShiftBase); @@ -3034,12 +3034,12 @@ private void MakeInteger(out bool fFraction) { if (iAdjust >= 9) { - ulRem = DivByULong(s_rgulShiftBase[8]); + ulRem = DivByULong(RgulShiftBase[8]); iAdjust -= 9; } else { - ulRem = DivByULong(s_rgulShiftBase[iAdjust - 1]); + ulRem = DivByULong(RgulShiftBase[iAdjust - 1]); iAdjust = 0; } @@ -3172,14 +3172,14 @@ private static SqlDecimal Round(SqlDecimal n, int lPosition, bool fTruncate) { if (lAdjust >= 9) { - ulRem = n.DivByULong(s_rgulShiftBase[8]); - ulLastDivBase = s_rgulShiftBase[8]; + ulRem = n.DivByULong(RgulShiftBase[8]); + ulLastDivBase = RgulShiftBase[8]; lAdjust -= 9; } else { - ulRem = n.DivByULong(s_rgulShiftBase[lAdjust - 1]); - ulLastDivBase = s_rgulShiftBase[lAdjust - 1]; + ulRem = n.DivByULong(RgulShiftBase[lAdjust - 1]); + ulLastDivBase = RgulShiftBase[lAdjust - 1]; lAdjust = 0; } } diff --git a/src/libraries/System.Diagnostics.FileVersionInfo/src/System/Diagnostics/FileVersionInfo.Windows.cs b/src/libraries/System.Diagnostics.FileVersionInfo/src/System/Diagnostics/FileVersionInfo.Windows.cs index fa5234bde62de..c9efe822c1cff 100644 --- a/src/libraries/System.Diagnostics.FileVersionInfo/src/System/Diagnostics/FileVersionInfo.Windows.cs +++ b/src/libraries/System.Diagnostics.FileVersionInfo/src/System/Diagnostics/FileVersionInfo.Windows.cs @@ -32,11 +32,22 @@ private unsafe FileVersionInfo(string fileName) uint langid = GetVarEntry(memIntPtr); if (!GetVersionInfoForCodePage(memIntPtr, ConvertTo8DigitHex(langid))) { + // Some dlls might not contain correct codepage information, + // in which case the lookup will fail. Explorer will take + // a few shots in dark. We'll simulate similar behavior by + // falling back to the following lang-codepages: + ReadOnlySpan fallbackLanguageCodePages = new uint[] + { + 0x040904B0, // US English + CP_UNICODE + 0x040904E4, // US English + CP_USASCII + 0x04090000 // US English + unknown codepage + }; + // Some DLLs might not contain correct codepage information. In these cases we will fail during lookup. // Explorer will take a few shots in dark by trying several specific lang-codepages // (Explorer also randomly guesses 041D04B0=Swedish+CP_UNICODE and 040704B0=German+CP_UNICODE sometimes). // We will try to simulate similar behavior here. - foreach (uint id in s_fallbackLanguageCodePages) + foreach (uint id in fallbackLanguageCodePages) { if (id != langid) { @@ -52,17 +63,6 @@ private unsafe FileVersionInfo(string fileName) } } - // Some dlls might not contain correct codepage information, - // in which case the lookup will fail. Explorer will take - // a few shots in dark. We'll simulate similar behavior by - // falling back to the following lang-codepages: - private static readonly uint[] s_fallbackLanguageCodePages = new uint[] - { - 0x040904B0, // US English + CP_UNICODE - 0x040904E4, // US English + CP_USASCII - 0x04090000 // US English + unknown codepage - }; - private static string ConvertTo8DigitHex(uint value) { return value.ToString("X8"); diff --git a/src/libraries/System.Drawing.Primitives/src/System/Drawing/KnownColorTable.cs b/src/libraries/System.Drawing.Primitives/src/System/Drawing/KnownColorTable.cs index 281f246d13ade..3ec5d7ab825cb 100644 --- a/src/libraries/System.Drawing.Primitives/src/System/Drawing/KnownColorTable.cs +++ b/src/libraries/System.Drawing.Primitives/src/System/Drawing/KnownColorTable.cs @@ -12,7 +12,7 @@ internal static class KnownColorTable public const byte KnownColorKindUnknown = 2; // All known color values (in order of definition in the KnownColor enum). - public static readonly uint[] s_colorValueTable = new uint[] + public static ReadOnlySpan ColorValueTable => new uint[] { // "not a known color" 0, @@ -466,11 +466,12 @@ internal static class KnownColorTable internal static Color ArgbToKnownColor(uint argb) { Debug.Assert((argb & Color.ARGBAlphaMask) == Color.ARGBAlphaMask); - Debug.Assert(s_colorValueTable.Length == ColorKindTable.Length); + Debug.Assert(ColorValueTable.Length == ColorKindTable.Length); - for (int index = 1; index < s_colorValueTable.Length; ++index) + ReadOnlySpan colorValueTable = ColorValueTable; + for (int index = 1; index < colorValueTable.Length; ++index) { - if (ColorKindTable[index] == KnownColorKindWeb && s_colorValueTable[index] == argb) + if (ColorKindTable[index] == KnownColorKindWeb && colorValueTable[index] == argb) { return Color.FromKnownColor((KnownColor)index); } @@ -486,7 +487,7 @@ public static uint KnownColorToArgb(KnownColor color) return ColorKindTable[(int)color] == KnownColorKindSystem ? GetSystemColorArgb(color) - : s_colorValueTable[(int)color]; + : ColorValueTable[(int)color]; } #if FEATURE_WINDOWS_SYSTEM_COLORS @@ -494,14 +495,14 @@ public static uint GetSystemColorArgb(KnownColor color) { Debug.Assert(Color.IsKnownColorSystem(color)); - return ColorTranslator.COLORREFToARGB(Interop.User32.GetSysColor((byte)s_colorValueTable[(int)color])); + return ColorTranslator.COLORREFToARGB(Interop.User32.GetSysColor((byte)ColorValueTable[(int)color])); } #else public static uint GetSystemColorArgb(KnownColor color) { Debug.Assert(Color.IsKnownColorSystem(color)); - return s_colorValueTable[(int)color]; + return ColorValueTable[(int)color]; } #endif } diff --git a/src/libraries/System.IO.Compression/src/System/IO/Compression/DeflateManaged/InflaterManaged.cs b/src/libraries/System.IO.Compression/src/System/IO/Compression/DeflateManaged/InflaterManaged.cs index 4dce72fb505a8..8ebc9b97f1bcd 100644 --- a/src/libraries/System.IO.Compression/src/System/IO/Compression/DeflateManaged/InflaterManaged.cs +++ b/src/libraries/System.IO.Compression/src/System/IO/Compression/DeflateManaged/InflaterManaged.cs @@ -18,7 +18,7 @@ internal sealed class InflaterManaged // The base length for length code 257 - 285. // The formula to get the real length for a length code is lengthBase[code - 257] + (value stored in extraBits) - private static readonly int[] s_lengthBase = + private static ReadOnlySpan LengthBase => new int[] { 3, 4, 5, 6, 7, 8, 9, 10, 11, 13, 15, 17, 19, 23, 27, 31, 35, 43, 51, 59, 67, 83, 99, 115, 131, 163, 195, 227, 3 @@ -26,7 +26,7 @@ internal sealed class InflaterManaged // The base distance for distance code 0 - 31 // The real distance for a distance code is distanceBasePosition[code] + (value stored in extraBits) - private static readonly int[] s_distanceBasePosition = + private static ReadOnlySpan DistanceBasePosition => new int[] { 1, 2, 3, 4, 5, 7, 9, 13, 17, 25, 33, 49, 65, 97, 129, 193, 257, 385, 513, 769, 1025, 1537, 2049, 3073, 4097, 6145, 8193, 12289, 16385, 24577, 32769, 49153 @@ -410,11 +410,11 @@ private bool DecodeBlock(out bool end_of_block_code_seen) return false; } - if (_length < 0 || _length >= s_lengthBase.Length) + if (_length < 0 || _length >= LengthBase.Length) { throw new InvalidDataException(SR.GenericInvalidData); } - _length = s_lengthBase[_length] + bits; + _length = LengthBase[_length] + bits; } _state = InflaterState.HaveFullLength; goto case InflaterState.HaveFullLength; @@ -456,7 +456,7 @@ private bool DecodeBlock(out bool end_of_block_code_seen) { return false; } - offset = s_distanceBasePosition[_distanceCode] + bits; + offset = DistanceBasePosition[_distanceCode] + bits; } else { diff --git a/src/libraries/System.Net.Http/src/System/Net/Http/SocketsHttpHandler/Http2Stream.cs b/src/libraries/System.Net.Http/src/System/Net/Http/SocketsHttpHandler/Http2Stream.cs index b3f82779a715d..828449b9b71e4 100644 --- a/src/libraries/System.Net.Http/src/System/Net/Http/SocketsHttpHandler/Http2Stream.cs +++ b/src/libraries/System.Net.Http/src/System/Net/Http/SocketsHttpHandler/Http2Stream.cs @@ -478,7 +478,7 @@ public void OnWindowUpdate(int amount) private const int FirstHPackNormalHeaderId = 15; private const int LastHPackNormalHeaderId = 61; - private static readonly int[] s_hpackStaticStatusCodeTable = new int[LastHPackStatusPseudoHeaderId - FirstHPackStatusPseudoHeaderId + 1] { 200, 204, 206, 304, 400, 404, 500 }; + private static ReadOnlySpan HpackStaticStatusCodeTable => new int[LastHPackStatusPseudoHeaderId - FirstHPackStatusPseudoHeaderId + 1] { 200, 204, 206, 304, 400, 404, 500 }; private static readonly (HeaderDescriptor descriptor, byte[] value)[] s_hpackStaticHeaderTable = new (HeaderDescriptor, byte[])[LastHPackNormalHeaderId - FirstHPackNormalHeaderId + 1] { @@ -542,7 +542,7 @@ void IHttpStreamHeadersHandler.OnStaticIndexedHeader(int index) } else if (index <= LastHPackStatusPseudoHeaderId) { - int statusCode = s_hpackStaticStatusCodeTable[index - FirstHPackStatusPseudoHeaderId]; + int statusCode = HpackStaticStatusCodeTable[index - FirstHPackStatusPseudoHeaderId]; OnStatus(statusCode); } diff --git a/src/libraries/System.Net.Http/src/System/Net/Http/SocketsHttpHandler/MultiProxy.cs b/src/libraries/System.Net.Http/src/System/Net/Http/SocketsHttpHandler/MultiProxy.cs index 087d104153b10..553f76d5557c6 100644 --- a/src/libraries/System.Net.Http/src/System/Net/Http/SocketsHttpHandler/MultiProxy.cs +++ b/src/libraries/System.Net.Http/src/System/Net/Http/SocketsHttpHandler/MultiProxy.cs @@ -11,7 +11,6 @@ namespace System.Net.Http /// internal struct MultiProxy { - private static readonly char[] s_proxyDelimiters = { ';', ' ', '\n', '\r', '\t' }; private readonly FailedProxyCache? _failedProxyCache; private readonly Uri[]? _uris; private readonly string? _proxyConfig; @@ -19,8 +18,6 @@ internal struct MultiProxy private int _currentIndex; private Uri? _currentUri; - public static MultiProxy Empty => new MultiProxy(null, Array.Empty()); - private MultiProxy(FailedProxyCache? failedProxyCache, Uri[] uris) { _failedProxyCache = failedProxyCache; @@ -41,6 +38,10 @@ private MultiProxy(FailedProxyCache failedProxyCache, string proxyConfig, bool s _currentUri = null; } + public static MultiProxy Empty => new MultiProxy(null, Array.Empty()); + + private static ReadOnlySpan ProxyDelimiters => new char[] { ';', ' ', '\n', '\r', '\t' }; + /// /// Parses a WinHTTP proxy config into a MultiProxy instance. /// @@ -206,7 +207,7 @@ private static bool TryParseProxyConfigPart(ReadOnlySpan proxyString, bool { // Skip any delimiters. int iter = 0; - while (iter < proxyString.Length && Array.IndexOf(s_proxyDelimiters, proxyString[iter]) >= 0) + while (iter < proxyString.Length && ProxyDelimiters.Contains(proxyString[iter])) { ++iter; } @@ -245,7 +246,7 @@ private static bool TryParseProxyConfigPart(ReadOnlySpan proxyString, bool } // Find the next delimiter, or end of string. - iter = proxyString.IndexOfAny(s_proxyDelimiters); + iter = proxyString.IndexOfAny(ProxyDelimiters); if (iter < 0) { iter = proxyString.Length; diff --git a/src/libraries/System.Net.HttpListener/src/System/Net/HttpListenerResponse.cs b/src/libraries/System.Net.HttpListener/src/System/Net/HttpListenerResponse.cs index bb52043594685..40c9e8b71a7df 100644 --- a/src/libraries/System.Net.HttpListener/src/System/Net/HttpListenerResponse.cs +++ b/src/libraries/System.Net.HttpListener/src/System/Net/HttpListenerResponse.cs @@ -79,20 +79,11 @@ public bool SendChunked set => EntitySendFormat = value ? EntitySendFormat.Chunked : EntitySendFormat.ContentLength; } - // We MUST NOT send message-body when we send responses with these Status codes - private static readonly int[] s_noResponseBody = { 100, 101, 204, 205, 304 }; - private static bool CanSendResponseBody(int responseCode) - { - for (int i = 0; i < s_noResponseBody.Length; i++) - { - if (responseCode == s_noResponseBody[i]) - { - return false; - } - } - return true; - } + + private static bool CanSendResponseBody(int responseCode) => + // We MUST NOT send message-body when we send responses with these Status codes + responseCode is not (100 or 101 or 204 or 205 or 304); public long ContentLength64 { diff --git a/src/libraries/System.Net.HttpListener/src/System/Net/Managed/HttpListenerRequest.Managed.cs b/src/libraries/System.Net.HttpListener/src/System/Net/Managed/HttpListenerRequest.Managed.cs index e42cfb07a05f6..448ce0c767f42 100644 --- a/src/libraries/System.Net.HttpListener/src/System/Net/Managed/HttpListenerRequest.Managed.cs +++ b/src/libraries/System.Net.HttpListener/src/System/Net/Managed/HttpListenerRequest.Managed.cs @@ -73,11 +73,9 @@ internal HttpListenerRequest(HttpListenerContext context) _version = HttpVersion.Version10; } - private static readonly char[] s_separators = new char[] { ' ' }; - internal void SetRequestLine(string req) { - string[] parts = req.Split(s_separators, 3); + string[] parts = req.Split(' ', 3); if (parts.Length != 3) { _context.ErrorMessage = "Invalid request line (parts)."; diff --git a/src/libraries/System.Net.Primitives/src/System/Net/Cookie.cs b/src/libraries/System.Net.Primitives/src/System/Net/Cookie.cs index bca1fb1341c71..5d3a770107a48 100644 --- a/src/libraries/System.Net.Primitives/src/System/Net/Cookie.cs +++ b/src/libraries/System.Net.Primitives/src/System/Net/Cookie.cs @@ -41,8 +41,7 @@ public sealed class Cookie internal static readonly char[] PortSplitDelimiters = new char[] { ' ', ',', '\"' }; // Space (' ') should be reserved as well per RFCs, but major web browsers support it and some web sites use it - so we support it too - internal static readonly char[] ReservedToName = new char[] { '\t', '\r', '\n', '=', ';', ',' }; - internal static readonly char[] ReservedToValue = new char[] { ';', ',' }; + internal static ReadOnlySpan ReservedToName => new char[] { '\t', '\r', '\n', '=', ';', ',' }; private string m_comment = string.Empty; // Do not rename (binary serialization) private Uri? m_commentUri; // Do not rename (binary serialization) @@ -239,7 +238,7 @@ internal bool InternalSetName(string? value) || value.StartsWith('$') || value.StartsWith(' ') || value.EndsWith(' ') - || value.IndexOfAny(ReservedToName) >= 0) + || value.AsSpan().IndexOfAny(ReservedToName) >= 0) { m_name = string.Empty; return false; @@ -347,7 +346,7 @@ internal bool VerifySetDefaults(CookieVariant variant, Uri uri, bool isLocalDoma m_name.StartsWith('$') || m_name.StartsWith(' ') || m_name.EndsWith(' ') || - m_name.IndexOfAny(ReservedToName) >= 0) + m_name.AsSpan().IndexOfAny(ReservedToName) >= 0) { if (shouldThrow) { @@ -358,7 +357,7 @@ internal bool VerifySetDefaults(CookieVariant variant, Uri uri, bool isLocalDoma // Check the value if (m_value == null || - (!(m_value.Length > 2 && m_value.StartsWith('\"') && m_value.EndsWith('\"')) && m_value.IndexOfAny(ReservedToValue) >= 0)) + (!(m_value.Length > 2 && m_value.StartsWith('\"') && m_value.EndsWith('\"')) && m_value.AsSpan().IndexOfAny(';', ',') >= 0)) { if (shouldThrow) { @@ -369,7 +368,7 @@ internal bool VerifySetDefaults(CookieVariant variant, Uri uri, bool isLocalDoma // Check Comment syntax if (Comment != null && !(Comment.Length > 2 && Comment.StartsWith('\"') && Comment.EndsWith('\"')) - && (Comment.IndexOfAny(ReservedToValue) >= 0)) + && (Comment.AsSpan().IndexOfAny(';', ',') >= 0)) { if (shouldThrow) { @@ -380,7 +379,7 @@ internal bool VerifySetDefaults(CookieVariant variant, Uri uri, bool isLocalDoma // Check Path syntax if (Path != null && !(Path.Length > 2 && Path.StartsWith('\"') && Path.EndsWith('\"')) - && (Path.IndexOfAny(ReservedToValue) >= 0)) + && (Path.AsSpan().IndexOfAny(';', ',') != -1)) { if (shouldThrow) { diff --git a/src/libraries/System.Private.CoreLib/src/System/Buffers/Text/Utf8Formatter/Utf8Formatter.Date.L.cs b/src/libraries/System.Private.CoreLib/src/System/Buffers/Text/Utf8Formatter/Utf8Formatter.Date.L.cs index 6d4dc6143dc5c..69574bf0d39c4 100644 --- a/src/libraries/System.Private.CoreLib/src/System/Buffers/Text/Utf8Formatter/Utf8Formatter.Date.L.cs +++ b/src/libraries/System.Private.CoreLib/src/System/Buffers/Text/Utf8Formatter/Utf8Formatter.Date.L.cs @@ -22,7 +22,7 @@ private static bool TryFormatDateTimeL(DateTime value, Span destination, o value.GetDate(out int year, out int month, out int day); value.GetTime(out int hour, out int minute, out int second); - uint dayAbbrev = s_dayAbbreviationsLowercase[(int)value.DayOfWeek]; + uint dayAbbrev = DayAbbreviationsLowercase[(int)value.DayOfWeek]; destination[0] = (byte)dayAbbrev; dayAbbrev >>= 8; @@ -35,7 +35,7 @@ private static bool TryFormatDateTimeL(DateTime value, Span destination, o FormattingHelpers.WriteTwoDecimalDigits((uint)day, destination, 5); destination[7] = Utf8Constants.Space; - uint monthAbbrev = s_monthAbbreviationsLowercase[month - 1]; + uint monthAbbrev = MonthAbbreviationsLowercase[month - 1]; destination[8] = (byte)monthAbbrev; monthAbbrev >>= 8; destination[9] = (byte)monthAbbrev; diff --git a/src/libraries/System.Private.CoreLib/src/System/Buffers/Text/Utf8Formatter/Utf8Formatter.Date.R.cs b/src/libraries/System.Private.CoreLib/src/System/Buffers/Text/Utf8Formatter/Utf8Formatter.Date.R.cs index d80b27cd26c8b..df19850ec6b3b 100644 --- a/src/libraries/System.Private.CoreLib/src/System/Buffers/Text/Utf8Formatter/Utf8Formatter.Date.R.cs +++ b/src/libraries/System.Private.CoreLib/src/System/Buffers/Text/Utf8Formatter/Utf8Formatter.Date.R.cs @@ -22,7 +22,7 @@ private static bool TryFormatDateTimeR(DateTime value, Span destination, o value.GetDate(out int year, out int month, out int day); value.GetTime(out int hour, out int minute, out int second); - uint dayAbbrev = s_dayAbbreviations[(int)value.DayOfWeek]; + uint dayAbbrev = DayAbbreviations[(int)value.DayOfWeek]; destination[0] = (byte)dayAbbrev; dayAbbrev >>= 8; @@ -35,7 +35,7 @@ private static bool TryFormatDateTimeR(DateTime value, Span destination, o FormattingHelpers.WriteTwoDecimalDigits((uint)day, destination, 5); destination[7] = Utf8Constants.Space; - uint monthAbbrev = s_monthAbbreviations[month - 1]; + uint monthAbbrev = MonthAbbreviations[month - 1]; destination[8] = (byte)monthAbbrev; monthAbbrev >>= 8; destination[9] = (byte)monthAbbrev; diff --git a/src/libraries/System.Private.CoreLib/src/System/Buffers/Text/Utf8Formatter/Utf8Formatter.Date.cs b/src/libraries/System.Private.CoreLib/src/System/Buffers/Text/Utf8Formatter/Utf8Formatter.Date.cs index f5c877d63fc77..f3db0b459fca8 100644 --- a/src/libraries/System.Private.CoreLib/src/System/Buffers/Text/Utf8Formatter/Utf8Formatter.Date.cs +++ b/src/libraries/System.Private.CoreLib/src/System/Buffers/Text/Utf8Formatter/Utf8Formatter.Date.cs @@ -18,7 +18,7 @@ public static partial class Utf8Formatter // The three-letter abbreviation is packed into a 24-bit unsigned integer // where the least significant byte represents the first letter. - private static readonly uint[] s_dayAbbreviations = new uint[] + private static ReadOnlySpan DayAbbreviations => new uint[] { 'S' + ('u' << 8) + ('n' << 16), 'M' + ('o' << 8) + ('n' << 16), @@ -29,7 +29,7 @@ public static partial class Utf8Formatter 'S' + ('a' << 8) + ('t' << 16), }; - private static readonly uint[] s_dayAbbreviationsLowercase = new uint[] + private static ReadOnlySpan DayAbbreviationsLowercase => new uint[] { 's' + ('u' << 8) + ('n' << 16), 'm' + ('o' << 8) + ('n' << 16), @@ -40,7 +40,7 @@ public static partial class Utf8Formatter 's' + ('a' << 8) + ('t' << 16) }; - private static readonly uint[] s_monthAbbreviations = new uint[] + private static ReadOnlySpan MonthAbbreviations => new uint[] { 'J' + ('a' << 8) + ('n' << 16), 'F' + ('e' << 8) + ('b' << 16), @@ -56,7 +56,7 @@ public static partial class Utf8Formatter 'D' + ('e' << 8) + ('c' << 16), }; - private static readonly uint[] s_monthAbbreviationsLowercase = new uint[] + private static ReadOnlySpan MonthAbbreviationsLowercase => new uint[] { 'j' + ('a' << 8) + ('n' << 16), 'f' + ('e' << 8) + ('b' << 16), diff --git a/src/libraries/System.Private.CoreLib/src/System/Buffers/Text/Utf8Parser/Utf8Parser.Date.Helpers.cs b/src/libraries/System.Private.CoreLib/src/System/Buffers/Text/Utf8Parser/Utf8Parser.Date.Helpers.cs index 8dcea70dbf14e..763aa4d9711ae 100644 --- a/src/libraries/System.Private.CoreLib/src/System/Buffers/Text/Utf8Parser/Utf8Parser.Date.Helpers.cs +++ b/src/libraries/System.Private.CoreLib/src/System/Buffers/Text/Utf8Parser/Utf8Parser.Date.Helpers.cs @@ -2,6 +2,7 @@ // The .NET Foundation licenses this file to you under the MIT license. using System.Diagnostics; +using System.Globalization; namespace System.Buffers.Text { @@ -144,7 +145,7 @@ private static bool TryCreateDateTime(int year, int month, int day, int hour, in Debug.Assert(fraction >= 0 && fraction <= Utf8Constants.MaxDateTimeFraction); // All of our callers to date parse the fraction from fixed 7-digit fields so this value is trusted. - int[] days = DateTime.IsLeapYear(year) ? s_daysToMonth366 : s_daysToMonth365; + ReadOnlySpan days = DateTime.IsLeapYear(year) ? GregorianCalendar.DaysToMonth366 : GregorianCalendar.DaysToMonth365; int yearMinusOne = year - 1; int totalDays = (yearMinusOne * 365) + (yearMinusOne / 4) - (yearMinusOne / 100) + (yearMinusOne / 400) + days[month - 1] + day - 1; long ticks = totalDays * TimeSpan.TicksPerDay; @@ -154,8 +155,5 @@ private static bool TryCreateDateTime(int year, int month, int day, int hour, in value = new DateTime(ticks: ticks, kind: kind); return true; } - - private static readonly int[] s_daysToMonth365 = { 0, 31, 59, 90, 120, 151, 181, 212, 243, 273, 304, 334, 365 }; - private static readonly int[] s_daysToMonth366 = { 0, 31, 60, 91, 121, 152, 182, 213, 244, 274, 305, 335, 366 }; } } diff --git a/src/libraries/System.Private.CoreLib/src/System/Convert.cs b/src/libraries/System.Private.CoreLib/src/System/Convert.cs index 5a55edfba1a6e..3ac15ce1d6312 100644 --- a/src/libraries/System.Private.CoreLib/src/System/Convert.cs +++ b/src/libraries/System.Private.CoreLib/src/System/Convert.cs @@ -101,13 +101,13 @@ public static partial class Convert // Need to special case Enum because typecode will be underlying type, e.g. Int32 private static readonly Type EnumType = typeof(Enum); - internal static readonly char[] base64Table = { 'A', 'B', 'C', 'D', 'E', 'F', 'G', 'H', 'I', 'J', 'K', 'L', 'M', 'N', 'O', - 'P', 'Q', 'R', 'S', 'T', 'U', 'V', 'W', 'X', 'Y', 'Z', 'a', 'b', 'c', 'd', - 'e', 'f', 'g', 'h', 'i', 'j', 'k', 'l', 'm', 'n', 'o', 'p', 'q', 'r', 's', - 't', 'u', 'v', 'w', 'x', 'y', 'z', '0', '1', '2', '3', '4', '5', '6', '7', - '8', '9', '+', '/', '=' }; + internal static ReadOnlySpan Base64Table => new char[] { 'A', 'B', 'C', 'D', 'E', 'F', 'G', 'H', 'I', 'J', 'K', 'L', 'M', 'N', 'O', + 'P', 'Q', 'R', 'S', 'T', 'U', 'V', 'W', 'X', 'Y', 'Z', 'a', 'b', 'c', 'd', + 'e', 'f', 'g', 'h', 'i', 'j', 'k', 'l', 'm', 'n', 'o', 'p', 'q', 'r', 's', + 't', 'u', 'v', 'w', 'x', 'y', 'z', '0', '1', '2', '3', '4', '5', '6', '7', + '8', '9', '+', '/', '=' }; - private const int base64LineBreakPosition = 76; + private const int Base64LineBreakPosition = 76; #if DEBUG static Convert() @@ -2473,14 +2473,14 @@ private static unsafe int ConvertToBase64Array(char* outChars, byte* inData, int // Convert three bytes at a time to base64 notation. This will consume 4 chars. int i; - // get a pointer to the base64Table to avoid unnecessary range checking - fixed (char* base64 = &base64Table[0]) + // get a pointer to the Base64Table to avoid unnecessary range checking + fixed (char* base64 = &Base64Table[0]) { for (i = offset; i < calcLength; i += 3) { if (insertLineBreaks) { - if (charcount == base64LineBreakPosition) + if (charcount == Base64LineBreakPosition) { outChars[j++] = '\r'; outChars[j++] = '\n'; @@ -2498,7 +2498,7 @@ private static unsafe int ConvertToBase64Array(char* outChars, byte* inData, int // Where we left off before i = calcLength; - if (insertLineBreaks && (lengthmod3 != 0) && (charcount == base64LineBreakPosition)) + if (insertLineBreaks && (lengthmod3 != 0) && (charcount == Base64LineBreakPosition)) { outChars[j++] = '\r'; outChars[j++] = '\n'; @@ -2536,7 +2536,7 @@ private static int ToBase64_CalculateAndValidateOutputLength(int inputLength, bo if (insertLineBreaks) { - (uint newLines, uint remainder) = Math.DivRem(outlen, base64LineBreakPosition); + (uint newLines, uint remainder) = Math.DivRem(outlen, Base64LineBreakPosition); if (remainder == 0) { --newLines; diff --git a/src/libraries/System.Private.CoreLib/src/System/DateTime.Windows.cs b/src/libraries/System.Private.CoreLib/src/System/DateTime.Windows.cs index 5ec5c7d0548a4..083d3fbf209b3 100644 --- a/src/libraries/System.Private.CoreLib/src/System/DateTime.Windows.cs +++ b/src/libraries/System.Private.CoreLib/src/System/DateTime.Windows.cs @@ -109,7 +109,7 @@ private static unsafe ulong ToFileTimeLeapSecondsAware(long ticks) private static DateTime CreateDateTimeFromSystemTime(in Interop.Kernel32.SYSTEMTIME time, ulong hundredNanoSecond) { uint year = time.Year; - uint[] days = IsLeapYear((int)year) ? s_daysToMonth366 : s_daysToMonth365; + ReadOnlySpan days = IsLeapYear((int)year) ? DaysToMonth366 : DaysToMonth365; int month = time.Month - 1; uint n = DaysToYear(year) + days[month] + time.Day - 1; ulong ticks = n * (ulong)TicksPerDay; diff --git a/src/libraries/System.Private.CoreLib/src/System/DateTime.cs b/src/libraries/System.Private.CoreLib/src/System/DateTime.cs index efe43d734a377..bcf19218c514a 100644 --- a/src/libraries/System.Private.CoreLib/src/System/DateTime.cs +++ b/src/libraries/System.Private.CoreLib/src/System/DateTime.cs @@ -109,10 +109,8 @@ public readonly partial struct DateTime private const int DatePartMonth = 2; private const int DatePartDay = 3; - private static readonly uint[] s_daysToMonth365 = { - 0, 31, 59, 90, 120, 151, 181, 212, 243, 273, 304, 334, 365 }; - private static readonly uint[] s_daysToMonth366 = { - 0, 31, 60, 91, 121, 152, 182, 213, 244, 274, 305, 335, 366 }; + private static ReadOnlySpan DaysToMonth365 => new uint[] { 0, 31, 59, 90, 120, 151, 181, 212, 243, 273, 304, 334, 365 }; + private static ReadOnlySpan DaysToMonth366 => new uint[] { 0, 31, 60, 91, 121, 152, 182, 213, 244, 274, 305, 335, 366 }; private static ReadOnlySpan DaysInMonth365 => new byte[] { 31, 28, 31, 30, 31, 30, 31, 31, 30, 31, 30, 31 }; private static ReadOnlySpan DaysInMonth366 => new byte[] { 31, 29, 31, 30, 31, 30, 31, 31, 30, 31, 30, 31 }; @@ -954,7 +952,7 @@ public DateTime AddMonths(int months) y += q; m -= q * 12; if (y < 1 || y > 9999) ThrowDateArithmetic(2); - uint[] daysTo = IsLeapYear(y) ? s_daysToMonth366 : s_daysToMonth365; + ReadOnlySpan daysTo = IsLeapYear(y) ? DaysToMonth366 : DaysToMonth365; uint daysToMonth = daysTo[m - 1]; int days = (int)(daysTo[m] - daysToMonth); if (d > days) d = days; @@ -1019,12 +1017,12 @@ public DateTime AddYears(int value) int m = month - 1, d = day - 1; if (IsLeapYear(y)) { - n += s_daysToMonth366[m]; + n += DaysToMonth366[m]; } else { if (d == 28 && m == 1) d--; - n += s_daysToMonth365[m]; + n += DaysToMonth365[m]; } n += (uint)d; return new DateTime(n * (ulong)TicksPerDay + UTicks % TicksPerDay | InternalKind); @@ -1074,7 +1072,7 @@ private static ulong DateToTicks(int year, int month, int day) ThrowHelper.ThrowArgumentOutOfRange_BadYearMonthDay(); } - uint[] days = IsLeapYear(year) ? s_daysToMonth366 : s_daysToMonth365; + ReadOnlySpan days = IsLeapYear(year) ? DaysToMonth366 : DaysToMonth365; if ((uint)day > days[month] - days[month - 1]) { ThrowHelper.ThrowArgumentOutOfRange_BadYearMonthDay(); @@ -1384,16 +1382,16 @@ private int GetDatePart(int part) if (part == DatePartDayOfYear) return (int)n + 1; // Leap year calculation looks different from IsLeapYear since y1, y4, // and y100 are relative to year 1, not year 0 - uint[] days = y1 == 3 && (y4 != 24 || y100 == 3) ? s_daysToMonth366 : s_daysToMonth365; + ReadOnlySpan days = y1 == 3 && (y4 != 24 || y100 == 3) ? DaysToMonth366 : DaysToMonth365; // All months have less than 32 days, so n >> 5 is a good conservative // estimate for the month uint m = (n >> 5) + 1; // m = 1-based month number - while (n >= days[m]) m++; + while (n >= days[(int)m]) m++; // If month was requested, return it if (part == DatePartMonth) return (int)m; // Return 1-based day-of-month - return (int)(n - days[m - 1] + 1); + return (int)(n - days[(int)(m - 1)] + 1); } // Exactly the same as GetDatePart, except computing all of @@ -1428,15 +1426,15 @@ internal void GetDate(out int year, out int month, out int day) // dayOfYear = n + 1; // Leap year calculation looks different from IsLeapYear since y1, y4, // and y100 are relative to year 1, not year 0 - uint[] days = y1 == 3 && (y4 != 24 || y100 == 3) ? s_daysToMonth366 : s_daysToMonth365; + ReadOnlySpan days = y1 == 3 && (y4 != 24 || y100 == 3) ? DaysToMonth366 : DaysToMonth365; // All months have less than 32 days, so n >> 5 is a good conservative // estimate for the month uint m = (n >> 5) + 1; // m = 1-based month number - while (n >= days[m]) m++; + while (n >= days[(int)m]) m++; // compute month and day month = (int)m; - day = (int)(n - days[m - 1] + 1); + day = (int)(n - days[(int)(m - 1)] + 1); } [MethodImpl(MethodImplOptions.AggressiveInlining)] @@ -1993,7 +1991,7 @@ internal static bool TryCreate(int year, int month, int day, int hour, int minut return false; } - uint[] days = IsLeapYear(year) ? s_daysToMonth366 : s_daysToMonth365; + ReadOnlySpan days = IsLeapYear(year) ? DaysToMonth366 : DaysToMonth365; if ((uint)day > days[month] - days[month - 1]) { return false; diff --git a/src/libraries/System.Private.CoreLib/src/System/Decimal.DecCalc.cs b/src/libraries/System.Private.CoreLib/src/System/Decimal.DecCalc.cs index 1a5834c08d42f..03d4943b493c4 100644 --- a/src/libraries/System.Private.CoreLib/src/System/Decimal.DecCalc.cs +++ b/src/libraries/System.Private.CoreLib/src/System/Decimal.DecCalc.cs @@ -101,7 +101,7 @@ private ulong Low64 private const int MaxInt64Scale = 19; // Fast access for 10^n where n is 0-9 - private static readonly uint[] s_powers10 = new uint[] { + private static ReadOnlySpan UInt32Powers10 => new uint[] { 1, 10, 100, @@ -115,7 +115,7 @@ private ulong Low64 }; // Fast access for 10^n where n is 1-19 - private static readonly ulong[] s_ulongPowers10 = new ulong[] { + private static ReadOnlySpan UInt64Powers10 => new ulong[] { 10, 100, 1000, @@ -137,7 +137,7 @@ private ulong Low64 10000000000000000000, }; - private static readonly double[] s_doublePowers10 = new double[] { + private static ReadOnlySpan DoublePowers10 => new double[] { 1, 1e1, 1e2, 1e3, 1e4, 1e5, 1e6, 1e7, 1e8, 1e9, 1e10, 1e11, 1e12, 1e13, 1e14, 1e15, 1e16, 1e17, 1e18, 1e19, 1e20, 1e21, 1e22, 1e23, 1e24, 1e25, 1e26, 1e27, 1e28, 1e29, @@ -931,7 +931,7 @@ internal static unsafe void DecAddSub(ref DecCalc d1, ref DecCalc d2, bool sign) { if (scale <= MaxInt32Scale) { - low64 = UInt32x32To64((uint)low64, s_powers10[scale]); + low64 = UInt32x32To64((uint)low64, UInt32Powers10[scale]); goto AlignedAdd; } scale -= MaxInt32Scale; @@ -943,7 +943,7 @@ internal static unsafe void DecAddSub(ref DecCalc d1, ref DecCalc d2, bool sign) { power = TenToPowerNine; if (scale < MaxInt32Scale) - power = s_powers10[scale]; + power = UInt32Powers10[scale]; tmpLow = UInt32x32To64((uint)low64, power); tmp64 = UInt32x32To64((uint)(low64 >> 32), power) + (tmpLow >> 32); low64 = (uint)tmpLow + (tmp64 << 32); @@ -959,7 +959,7 @@ internal static unsafe void DecAddSub(ref DecCalc d1, ref DecCalc d2, bool sign) // power = TenToPowerNine; if (scale < MaxInt32Scale) - power = s_powers10[scale]; + power = UInt32Powers10[scale]; tmpLow = UInt32x32To64((uint)low64, power); tmp64 = UInt32x32To64((uint)(low64 >> 32), power) + (tmpLow >> 32); low64 = (uint)tmpLow + (tmp64 << 32); @@ -990,7 +990,7 @@ internal static unsafe void DecAddSub(ref DecCalc d1, ref DecCalc d2, bool sign) { power = TenToPowerNine; if (scale < MaxInt32Scale) - power = s_powers10[scale]; + power = UInt32Powers10[scale]; tmp64 = 0; uint* rgulNum = (uint*)&bufNum; for (uint cur = 0; ;) @@ -1198,7 +1198,7 @@ internal static long VarCyFromDec(ref DecCalc pdecIn) { if (pdecIn.High != 0) goto ThrowOverflow; - uint pwr = s_powers10[-scale]; + uint pwr = UInt32Powers10[-scale]; ulong high = UInt32x32To64(pwr, pdecIn.Mid); if (high > uint.MaxValue) goto ThrowOverflow; @@ -1286,7 +1286,7 @@ private static int VarDecCmpSub(in decimal d1, in decimal d2) // Scaling loop, up to 10^9 at a time. do { - uint power = scale >= MaxInt32Scale ? TenToPowerNine : s_powers10[scale]; + uint power = scale >= MaxInt32Scale ? TenToPowerNine : UInt32Powers10[scale]; ulong tmpLow = UInt32x32To64((uint)low64, power); ulong tmp = UInt32x32To64((uint)(low64 >> 32), power) + (tmpLow >> 32); low64 = (uint)tmpLow + (tmp << 32); @@ -1345,7 +1345,7 @@ internal static unsafe void VarDecMul(ref DecCalc d1, ref DecCalc d2) goto ReturnZero; scale -= DEC_SCALE_MAX + 1; - ulong power = s_ulongPowers10[scale]; + ulong power = UInt64Powers10[scale]; // TODO: https://github.com/dotnet/runtime/issues/5213 tmp = low64 / power; @@ -1562,12 +1562,12 @@ internal static void VarDecFromR4(float input, out DecCalc result) if (power > DEC_SCALE_MAX) power = DEC_SCALE_MAX; - dbl *= s_doublePowers10[power]; + dbl *= DoublePowers10[power]; } else { if (power != -1 || dbl >= 1E7) - dbl /= s_doublePowers10[-power]; + dbl /= DoublePowers10[-power]; else power = 0; // didn't scale it } @@ -1604,7 +1604,7 @@ internal static void VarDecFromR4(float input, out DecCalc result) power = -power; if (power < 10) { - result.Low64 = UInt32x32To64(mant, s_powers10[power]); + result.Low64 = UInt32x32To64(mant, UInt32Powers10[power]); } else { @@ -1612,12 +1612,12 @@ internal static void VarDecFromR4(float input, out DecCalc result) // if (power > 18) { - ulong low64 = UInt32x32To64(mant, s_powers10[power - 18]); + ulong low64 = UInt32x32To64(mant, UInt32Powers10[power - 18]); UInt64x64To128(low64, TenToPowerEighteen, ref result); } else { - ulong low64 = UInt32x32To64(mant, s_powers10[power - 9]); + ulong low64 = UInt32x32To64(mant, UInt32Powers10[power - 9]); ulong hi64 = UInt32x32To64(TenToPowerNine, (uint)(low64 >> 32)); low64 = UInt32x32To64(TenToPowerNine, (uint)low64); result.Low = (uint)low64; @@ -1729,12 +1729,12 @@ internal static void VarDecFromR8(double input, out DecCalc result) if (power > DEC_SCALE_MAX) power = DEC_SCALE_MAX; - dbl *= s_doublePowers10[power]; + dbl *= DoublePowers10[power]; } else { if (power != -1 || dbl >= 1E15) - dbl /= s_doublePowers10[-power]; + dbl /= DoublePowers10[-power]; else power = 0; // didn't scale it } @@ -1771,7 +1771,7 @@ internal static void VarDecFromR8(double input, out DecCalc result) power = -power; if (power < 10) { - uint pow10 = s_powers10[power]; + uint pow10 = UInt32Powers10[power]; ulong low64 = UInt32x32To64((uint)mant, pow10); ulong hi64 = UInt32x32To64((uint)(mant >> 32), pow10); result.Low = (uint)low64; @@ -1785,7 +1785,7 @@ internal static void VarDecFromR8(double input, out DecCalc result) // Have a big power of 10. // Debug.Assert(power <= 14); - UInt64x64To128(mant, s_ulongPowers10[power - 1], ref result); + UInt64x64To128(mant, UInt64Powers10[power - 1], ref result); } } else @@ -1873,7 +1873,7 @@ internal static double VarR8FromDec(in decimal value) const double ds2to64 = 1.8446744073709552e+019; double dbl = ((double)value.Low64 + - (double)value.High * ds2to64) / s_doublePowers10[value.Scale]; + (double)value.High * ds2to64) / DoublePowers10[value.Scale]; if (decimal.IsNegative(value)) dbl = -dbl; @@ -1971,7 +1971,7 @@ internal static unsafe void VarDecDiv(ref DecCalc d1, ref DecCalc d2) } HaveScale: - power = s_powers10[curScale]; + power = UInt32Powers10[curScale]; scale += curScale; if (IncreaseScale(ref bufQuo, power) != 0) @@ -2053,7 +2053,7 @@ internal static unsafe void VarDecDiv(ref DecCalc d1, ref DecCalc d2) } HaveScale64: - power = s_powers10[curScale]; + power = UInt32Powers10[curScale]; scale += curScale; if (IncreaseScale(ref bufQuo, power) != 0) @@ -2124,7 +2124,7 @@ internal static unsafe void VarDecDiv(ref DecCalc d1, ref DecCalc d2) } HaveScale96: - power = s_powers10[curScale]; + power = UInt32Powers10[curScale]; scale += curScale; if (IncreaseScale(ref bufQuo, power) != 0) @@ -2209,7 +2209,7 @@ internal static void VarDecMod(ref DecCalc d1, ref DecCalc d2) // Divisor scale can always be increased to dividend scale for remainder calculation. do { - uint power = scale >= MaxInt32Scale ? TenToPowerNine : s_powers10[scale]; + uint power = scale >= MaxInt32Scale ? TenToPowerNine : UInt32Powers10[scale]; ulong tmp = UInt32x32To64(d2.Low, power); d2.Low = (uint)tmp; tmp >>= 32; @@ -2235,7 +2235,7 @@ internal static void VarDecMod(ref DecCalc d1, ref DecCalc d2) int iCurScale = SearchScale(ref bufQuo, DEC_SCALE_MAX + scale); if (iCurScale == 0) break; - uint power = iCurScale >= MaxInt32Scale ? TenToPowerNine : s_powers10[iCurScale]; + uint power = iCurScale >= MaxInt32Scale ? TenToPowerNine : UInt32Powers10[iCurScale]; scale += iCurScale; ulong tmp = UInt32x32To64(bufQuo.U0, power); bufQuo.U0 = (uint)tmp; @@ -2296,7 +2296,7 @@ private static unsafe void VarDecModFull(ref DecCalc d1, ref DecCalc d2, int sca uint high = 3; while (scale < 0) { - uint power = scale <= -MaxInt32Scale ? TenToPowerNine : s_powers10[-scale]; + uint power = scale <= -MaxInt32Scale ? TenToPowerNine : UInt32Powers10[-scale]; uint* buf = (uint*)&b; ulong tmp64 = UInt32x32To64(b.Buf24.U0, power); b.Buf24.U0 = (uint)tmp64; @@ -2409,7 +2409,7 @@ internal static void InternalRound(ref DecCalc d, uint scale, MidpointRounding m } { - power = s_powers10[scale]; + power = UInt32Powers10[(int)scale]; // TODO: https://github.com/dotnet/runtime/issues/5213 uint n = d.uhi; if (n == 0) diff --git a/src/libraries/System.Private.CoreLib/src/System/Globalization/CalendricalCalculationsHelper.cs b/src/libraries/System.Private.CoreLib/src/System/Globalization/CalendricalCalculationsHelper.cs index e344048af72df..ce960764e6d82 100644 --- a/src/libraries/System.Private.CoreLib/src/System/Globalization/CalendricalCalculationsHelper.cs +++ b/src/libraries/System.Private.CoreLib/src/System/Globalization/CalendricalCalculationsHelper.cs @@ -24,16 +24,17 @@ internal static class CalendricalCalculationsHelper private static readonly long s_startOf1810 = GetNumberOfDays(new DateTime(1810, 1, 1)); private static readonly long s_startOf1900Century = GetNumberOfDays(new DateTime(1900, 1, 1)); - private static readonly double[] s_coefficients1900to1987 = new double[] { -0.00002, 0.000297, 0.025184, -0.181133, 0.553040, -0.861938, 0.677066, -0.212591 }; - private static readonly double[] s_coefficients1800to1899 = new double[] { -0.000009, 0.003844, 0.083563, 0.865736, 4.867575, 15.845535, 31.332267, 38.291999, 28.316289, 11.636204, 2.043794 }; - private static readonly double[] s_coefficients1700to1799 = new double[] { 8.118780842, -0.005092142, 0.003336121, -0.0000266484 }; - private static readonly double[] s_coefficients1620to1699 = new double[] { 196.58333, -4.0675, 0.0219167 }; - private static readonly double[] s_lambdaCoefficients = new double[] { 280.46645, 36000.76983, 0.0003032 }; - private static readonly double[] s_anomalyCoefficients = new double[] { 357.52910, 35999.05030, -0.0001559, -0.00000048 }; - private static readonly double[] s_eccentricityCoefficients = new double[] { 0.016708617, -0.000042037, -0.0000001236 }; + private static ReadOnlySpan Coefficients1900to1987 => new double[] { -0.00002, 0.000297, 0.025184, -0.181133, 0.553040, -0.861938, 0.677066, -0.212591 }; + private static ReadOnlySpan Coefficients1800to1899 => new double[] { -0.000009, 0.003844, 0.083563, 0.865736, 4.867575, 15.845535, 31.332267, 38.291999, 28.316289, 11.636204, 2.043794 }; + private static ReadOnlySpan Coefficients1700to1799 => new double[] { 8.118780842, -0.005092142, 0.003336121, -0.0000266484 }; + private static ReadOnlySpan Coefficients1620to1699 => new double[] { 196.58333, -4.0675, 0.0219167 }; + private static ReadOnlySpan LambdaCoefficients => new double[] { 280.46645, 36000.76983, 0.0003032 }; + private static ReadOnlySpan AnomalyCoefficients => new double[] { 357.52910, 35999.05030, -0.0001559, -0.00000048 }; + private static ReadOnlySpan EccentricityCoefficients => new double[] { 0.016708617, -0.000042037, -0.0000001236 }; + private static ReadOnlySpan CoefficientsA => new double[] { 124.90, -1934.134, 0.002063 }; + private static ReadOnlySpan CoefficientsB => new double[] { 201.11, 72001.5377, 0.00057 }; + private static readonly double[] s_coefficients = new double[] { Angle(23, 26, 21.448), Angle(0, 0, -46.8150), Angle(0, 0, -0.00059), Angle(0, 0, 0.001813) }; - private static readonly double[] s_coefficientsA = new double[] { 124.90, -1934.134, 0.002063 }; - private static readonly double[] s_coefficientsB = new double[] { 201.11, 72001.5377, 0.00057 }; private static double RadiansFromDegrees(double degree) { @@ -129,7 +130,7 @@ public static double AsDayFraction(double longitude) return longitude / FullCircleOfArc; } - private static double PolynomialSum(double[] coefficients, double indeterminate) + private static double PolynomialSum(ReadOnlySpan coefficients, double indeterminate) { double sum = coefficients[0]; double indeterminateRaised = 1; @@ -168,28 +169,28 @@ private static double EphemerisCorrection1900to1987(int gregorianYear) { Debug.Assert(1900 <= gregorianYear && gregorianYear <= 1987); double centuriesFrom1900 = CenturiesFrom1900(gregorianYear); - return PolynomialSum(s_coefficients1900to1987, centuriesFrom1900); + return PolynomialSum(Coefficients1900to1987, centuriesFrom1900); } private static double EphemerisCorrection1800to1899(int gregorianYear) { Debug.Assert(1800 <= gregorianYear && gregorianYear <= 1899); double centuriesFrom1900 = CenturiesFrom1900(gregorianYear); - return PolynomialSum(s_coefficients1800to1899, centuriesFrom1900); + return PolynomialSum(Coefficients1800to1899, centuriesFrom1900); } private static double EphemerisCorrection1700to1799(int gregorianYear) { Debug.Assert(1700 <= gregorianYear && gregorianYear <= 1799); double yearsSince1700 = gregorianYear - 1700; - return PolynomialSum(s_coefficients1700to1799, yearsSince1700) / SecondsPerDay; + return PolynomialSum(Coefficients1700to1799, yearsSince1700) / SecondsPerDay; } private static double EphemerisCorrection1620to1699(int gregorianYear) { Debug.Assert(1620 <= gregorianYear && gregorianYear <= 1699); double yearsSince1600 = gregorianYear - 1600; - return PolynomialSum(s_coefficients1620to1699, yearsSince1600) / SecondsPerDay; + return PolynomialSum(Coefficients1620to1699, yearsSince1600) / SecondsPerDay; } // ephemeris-correction: correction to account for the slowing down of the rotation of the earth @@ -233,9 +234,9 @@ public static double JulianCenturies(double moment) private static double EquationOfTime(double time) { double julianCenturies = JulianCenturies(time); - double lambda = PolynomialSum(s_lambdaCoefficients, julianCenturies); - double anomaly = PolynomialSum(s_anomalyCoefficients, julianCenturies); - double eccentricity = PolynomialSum(s_eccentricityCoefficients, julianCenturies); + double lambda = PolynomialSum(LambdaCoefficients, julianCenturies); + double anomaly = PolynomialSum(AnomalyCoefficients, julianCenturies); + double eccentricity = PolynomialSum(EccentricityCoefficients, julianCenturies); double epsilon = Obliquity(julianCenturies); double tanHalfEpsilon = TanOfDegree(epsilon / 2); @@ -345,8 +346,8 @@ private static double Aberration(double julianCenturies) private static double Nutation(double julianCenturies) { - double a = PolynomialSum(s_coefficientsA, julianCenturies); - double b = PolynomialSum(s_coefficientsB, julianCenturies); + double a = PolynomialSum(CoefficientsA, julianCenturies); + double b = PolynomialSum(CoefficientsB, julianCenturies); return (-0.004778 * SinOfDegree(a)) - (0.0003667 * SinOfDegree(b)); } diff --git a/src/libraries/System.Private.CoreLib/src/System/Globalization/DateTimeFormat.cs b/src/libraries/System.Private.CoreLib/src/System/Globalization/DateTimeFormat.cs index bb5917a06fd13..f3b4ea2c75b0d 100644 --- a/src/libraries/System.Private.CoreLib/src/System/Globalization/DateTimeFormat.cs +++ b/src/libraries/System.Private.CoreLib/src/System/Globalization/DateTimeFormat.cs @@ -120,13 +120,12 @@ based on ISO 8601. */ // This class contains only static members and does not require the serializable attribute. - internal static - class DateTimeFormat + internal static class DateTimeFormat { internal const int MaxSecondsFractionDigits = 7; internal const long NullOffset = long.MinValue; - internal static char[] allStandardFormats = + internal static ReadOnlySpan AllStandardFormats => new char[] { 'd', 'D', 'f', 'F', 'g', 'G', 'm', 'M', 'o', 'O', 'r', 'R', @@ -1562,6 +1561,7 @@ internal static string[] GetAllDateTimes(DateTime dateTime, DateTimeFormatInfo d { List results = new List(DEFAULT_ALL_DATETIMES_SIZE); + ReadOnlySpan allStandardFormats = AllStandardFormats; for (int i = 0; i < allStandardFormats.Length; i++) { string[] strings = GetAllDateTimes(dateTime, allStandardFormats[i], dtfi); diff --git a/src/libraries/System.Private.CoreLib/src/System/Globalization/DateTimeFormatInfo.cs b/src/libraries/System.Private.CoreLib/src/System/Globalization/DateTimeFormatInfo.cs index 4a70413b14607..26a182843ac8b 100644 --- a/src/libraries/System.Private.CoreLib/src/System/Globalization/DateTimeFormatInfo.cs +++ b/src/libraries/System.Private.CoreLib/src/System/Globalization/DateTimeFormatInfo.cs @@ -1266,14 +1266,14 @@ public string[] GetAllDateTimePatterns() { List results = new List(DEFAULT_ALL_DATETIMES_SIZE); - for (int i = 0; i < DateTimeFormat.allStandardFormats.Length; i++) + foreach (char standardFormat in DateTimeFormat.AllStandardFormats) { - string[] strings = GetAllDateTimePatterns(DateTimeFormat.allStandardFormats[i]); - for (int j = 0; j < strings.Length; j++) + foreach (string pattern in GetAllDateTimePatterns(standardFormat)) { - results.Add(strings[j]); + results.Add(pattern); } } + return results.ToArray(); } diff --git a/src/libraries/System.Private.CoreLib/src/System/Globalization/DateTimeParse.cs b/src/libraries/System.Private.CoreLib/src/System/Globalization/DateTimeParse.cs index 13aae15d40ce6..c676df5c7a249 100644 --- a/src/libraries/System.Private.CoreLib/src/System/Globalization/DateTimeParse.cs +++ b/src/libraries/System.Private.CoreLib/src/System/Globalization/DateTimeParse.cs @@ -5438,8 +5438,6 @@ internal bool MatchSpecifiedWord(string target) => Index + target.Length <= Length && m_info.Compare(Value.Slice(Index, target.Length), target, CompareOptions.IgnoreCase) == 0; - private static readonly char[] WhiteSpaceChecks = new char[] { ' ', '\u00A0' }; - internal bool MatchSpecifiedWords(string target, bool checkWordBoundary, ref int matchLength) { int valueRemaining = Value.Length - Index; @@ -5450,12 +5448,14 @@ internal bool MatchSpecifiedWords(string target, bool checkWordBoundary, ref int // Check word by word int targetPosition = 0; // Where we are in the target string int thisPosition = Index; // Where we are in this string - int wsIndex = target.IndexOfAny(WhiteSpaceChecks, targetPosition); + int wsIndex = target.AsSpan(targetPosition).IndexOfAny(' ', '\u00A0'); if (wsIndex < 0) { return false; } - do + wsIndex += targetPosition; + + while (true) { int segmentLength = wsIndex - targetPosition; if (thisPosition >= Value.Length - segmentLength) @@ -5491,7 +5491,15 @@ internal bool MatchSpecifiedWords(string target, bool checkWordBoundary, ref int thisPosition++; matchLength++; } - } while ((wsIndex = target.IndexOfAny(WhiteSpaceChecks, targetPosition)) >= 0); + + wsIndex = target.AsSpan(targetPosition).IndexOfAny(' ', '\u00A0'); + if (wsIndex < 0) + { + break; + } + wsIndex += targetPosition; + } + // now check the last segment; if (targetPosition < target.Length) { diff --git a/src/libraries/System.Private.CoreLib/src/System/Globalization/EastAsianLunisolarCalendar.cs b/src/libraries/System.Private.CoreLib/src/System/Globalization/EastAsianLunisolarCalendar.cs index 73322a6570a72..35c2d09c3d4dd 100644 --- a/src/libraries/System.Private.CoreLib/src/System/Globalization/EastAsianLunisolarCalendar.cs +++ b/src/libraries/System.Private.CoreLib/src/System/Globalization/EastAsianLunisolarCalendar.cs @@ -11,9 +11,8 @@ public abstract class EastAsianLunisolarCalendar : Calendar private const int nDaysPerMonth = 3; // # of days so far in the solar year - private static readonly int[] s_daysToMonth365 = { 0, 31, 59, 90, 120, 151, 181, 212, 243, 273, 304, 334 }; - - private static readonly int[] s_daysToMonth366 = { 0, 31, 60, 91, 121, 152, 182, 213, 244, 274, 305, 335 }; + private static ReadOnlySpan DaysToMonth365 => new int[] { 0, 31, 59, 90, 120, 151, 181, 212, 243, 273, 304, 334 }; + private static ReadOnlySpan DaysToMonth366 => new int[] { 0, 31, 60, 91, 121, 152, 182, 213, 244, 274, 305, 335 }; public override CalendarAlgorithmType AlgorithmType => CalendarAlgorithmType.LunisolarCalendar; @@ -273,7 +272,7 @@ private void GregorianToLunar(int solarYear, int solarMonth, int solarDate, out int jan1Date; // Calculate the day number in the solar year. - int solarDay = isLeapYear ? s_daysToMonth366[solarMonth - 1] : s_daysToMonth365[solarMonth - 1]; + int solarDay = isLeapYear ? DaysToMonth366[solarMonth - 1] : DaysToMonth365[solarMonth - 1]; solarDay += solarDate; // Calculate the day number in the lunar year. @@ -314,7 +313,7 @@ private void GregorianToLunar(int solarYear, int solarMonth, int solarDate, out // part of the lunar year. since this part is always in Jan or Feb, // we don't need to handle Leap Year (LY only affects March // and later). - lunarDay -= s_daysToMonth365[jan1Month - 1]; + lunarDay -= DaysToMonth365[jan1Month - 1]; lunarDay -= (jan1Date - 1); // convert the lunar day into a lunar month/date @@ -362,7 +361,7 @@ private bool LunarToGregorian(int lunarYear, int lunarMonth, int lunarDate, out // calc the solar day of year of 1 Lunar day bool isLeapYear = GregorianIsLeapYear(lunarYear); - int[] days = isLeapYear ? s_daysToMonth366 : s_daysToMonth365; + ReadOnlySpan days = isLeapYear ? DaysToMonth366 : DaysToMonth365; solarDay = jan1Date; diff --git a/src/libraries/System.Private.CoreLib/src/System/Globalization/GregorianCalendar.cs b/src/libraries/System.Private.CoreLib/src/System/Globalization/GregorianCalendar.cs index e883c8e3772ad..51c506e0d4b27 100644 --- a/src/libraries/System.Private.CoreLib/src/System/Globalization/GregorianCalendar.cs +++ b/src/libraries/System.Private.CoreLib/src/System/Globalization/GregorianCalendar.cs @@ -22,9 +22,9 @@ public class GregorianCalendar : Calendar private GregorianCalendarTypes _type; - private static readonly int[] DaysToMonth365 = { 0, 31, 59, 90, 120, 151, 181, 212, 243, 273, 304, 334, 365 }; + internal static ReadOnlySpan DaysToMonth365 => new int[] { 0, 31, 59, 90, 120, 151, 181, 212, 243, 273, 304, 334, 365 }; - private static readonly int[] DaysToMonth366 = { 0, 31, 60, 91, 121, 152, 182, 213, 244, 274, 305, 335, 366 }; + internal static ReadOnlySpan DaysToMonth366 => new int[] { 0, 31, 60, 91, 121, 152, 182, 213, 244, 274, 305, 335, 366 }; private static volatile Calendar? s_defaultInstance; @@ -96,7 +96,7 @@ internal static long GetAbsoluteDate(int year, int month, int day) { if (year >= 1 && year <= MaxYear && month >= 1 && month <= 12) { - int[] days = (year % 4 == 0 && (year % 100 != 0 || year % 400 == 0)) ? DaysToMonth366 : DaysToMonth365; + ReadOnlySpan days = (year % 4 == 0 && (year % 100 != 0 || year % 400 == 0)) ? DaysToMonth366 : DaysToMonth365; if (day >= 1 && (day <= days[month] - days[month - 1])) { int y = year - 1; @@ -157,7 +157,7 @@ public override DateTime AddMonths(DateTime time, int months) y += (i - 11) / 12; } - int[] daysArray = (y % 4 == 0 && (y % 100 != 0 || y % 400 == 0)) ? DaysToMonth366 : DaysToMonth365; + ReadOnlySpan daysArray = (y % 4 == 0 && (y % 100 != 0 || y % 400 == 0)) ? DaysToMonth366 : DaysToMonth365; int days = (daysArray[m] - daysArray[m - 1]); if (d > days) @@ -278,7 +278,7 @@ internal override bool IsValidDay(int year, int month, int day, int era) return false; } - int[] days = (year % 4 == 0 && (year % 100 != 0 || year % 400 == 0)) ? DaysToMonth366 : DaysToMonth365; + ReadOnlySpan days = (year % 4 == 0 && (year % 100 != 0 || year % 400 == 0)) ? DaysToMonth366 : DaysToMonth365; return day <= (days[month] - days[month - 1]); } diff --git a/src/libraries/System.Private.CoreLib/src/System/Globalization/GregorianCalendarHelper.cs b/src/libraries/System.Private.CoreLib/src/System/Globalization/GregorianCalendarHelper.cs index a79e625497a9f..4fdac70d510e7 100644 --- a/src/libraries/System.Private.CoreLib/src/System/Globalization/GregorianCalendarHelper.cs +++ b/src/libraries/System.Private.CoreLib/src/System/Globalization/GregorianCalendarHelper.cs @@ -53,16 +53,6 @@ internal sealed class GregorianCalendarHelper // internal int MaxYear => m_maxYear; - internal static readonly int[] DaysToMonth365 = - { - 0, 31, 59, 90, 120, 151, 181, 212, 243, 273, 304, 334, 365 - }; - - internal static readonly int[] DaysToMonth366 = - { - 0, 31, 60, 91, 121, 152, 182, 213, 244, 274, 305, 335, 366 - }; - private readonly int m_maxYear; private readonly int m_minYear; private readonly Calendar m_Cal; @@ -197,7 +187,7 @@ internal static long GetAbsoluteDate(int year, int month, int day) { if (year >= 1 && year <= 9999 && month >= 1 && month <= 12) { - int[] days = (year % 4 == 0 && (year % 100 != 0 || year % 400 == 0)) ? DaysToMonth366 : DaysToMonth365; + ReadOnlySpan days = (year % 4 == 0 && (year % 100 != 0 || year % 400 == 0)) ? GregorianCalendar.DaysToMonth366 : GregorianCalendar.DaysToMonth365; if (day >= 1 && (day <= days[month] - days[month - 1])) { int y = year - 1; @@ -271,7 +261,7 @@ public DateTime AddMonths(DateTime time, int months) m = 12 + (i + 1) % 12; y += (i - 11) / 12; } - int[] daysArray = (y % 4 == 0 && (y % 100 != 0 || y % 400 == 0)) ? DaysToMonth366 : DaysToMonth365; + ReadOnlySpan daysArray = (y % 4 == 0 && (y % 100 != 0 || y % 400 == 0)) ? GregorianCalendar.DaysToMonth366 : GregorianCalendar.DaysToMonth365; int days = (daysArray[m] - daysArray[m - 1]); if (d > days) @@ -338,7 +328,7 @@ public int GetDaysInMonth(int year, int month, int era) { ThrowHelper.ThrowArgumentOutOfRange_Month(month); } - int[] days = ((year % 4 == 0 && (year % 100 != 0 || year % 400 == 0)) ? DaysToMonth366 : DaysToMonth365); + ReadOnlySpan days = ((year % 4 == 0 && (year % 100 != 0 || year % 400 == 0)) ? GregorianCalendar.DaysToMonth366 : GregorianCalendar.DaysToMonth365); return days[month] - days[month - 1]; } diff --git a/src/libraries/System.Private.CoreLib/src/System/Globalization/HijriCalendar.cs b/src/libraries/System.Private.CoreLib/src/System/Globalization/HijriCalendar.cs index fa1f63490195d..316efb150dec5 100644 --- a/src/libraries/System.Private.CoreLib/src/System/Globalization/HijriCalendar.cs +++ b/src/libraries/System.Private.CoreLib/src/System/Globalization/HijriCalendar.cs @@ -48,7 +48,7 @@ public partial class HijriCalendar : Calendar private const int MinAdvancedHijri = -2; private const int MaxAdvancedHijri = 2; - private static readonly int[] s_hijriMonthDays = { 0, 30, 59, 89, 118, 148, 177, 207, 236, 266, 295, 325, 355 }; + private static ReadOnlySpan HijriMonthDays => new int[] { 0, 30, 59, 89, 118, 148, 177, 207, 236, 266, 295, 325, 355 }; private int _hijriAdvance = int.MinValue; @@ -80,7 +80,7 @@ public HijriCalendar() private long GetAbsoluteDateHijri(int y, int m, int d) { - return (long)(DaysUpToHijriYear(y) + s_hijriMonthDays[m - 1] + d - 1 - HijriAdjustment); + return (long)(DaysUpToHijriYear(y) + HijriMonthDays[m - 1] + d - 1 - HijriAdjustment); } private long DaysUpToHijriYear(int HijriYear) @@ -241,7 +241,7 @@ internal virtual int GetDatePart(long ticks, int part) return (int)numDays; } - while ((hijriMonth <= 12) && (numDays > s_hijriMonthDays[hijriMonth - 1])) + while ((hijriMonth <= 12) && (numDays > HijriMonthDays[hijriMonth - 1])) { hijriMonth++; } @@ -253,7 +253,7 @@ internal virtual int GetDatePart(long ticks, int part) } // Calculate the Hijri Day. - int hijriDay = (int)(numDays - s_hijriMonthDays[hijriMonth - 1]); + int hijriDay = (int)(numDays - HijriMonthDays[hijriMonth - 1]); if (part == DatePartDay) { diff --git a/src/libraries/System.Private.CoreLib/src/System/Globalization/IcuLocaleData.generator.cs b/src/libraries/System.Private.CoreLib/src/System/Globalization/IcuLocaleData.generator.cs index 4ca862777f193..b7c4d1b0cf27f 100644 --- a/src/libraries/System.Private.CoreLib/src/System/Globalization/IcuLocaleData.generator.cs +++ b/src/libraries/System.Private.CoreLib/src/System/Globalization/IcuLocaleData.generator.cs @@ -24,10 +24,10 @@ internal static partial class IcuLocaleData internal const int DoubleCommaSep = 4 << 4; private const int CulturesCount = 864; - // s_nameIndexToNumericData is mapping from index in s_localeNamesIndices to locale data. + // NameIndexToNumericData is mapping from index in s_localeNamesIndices to locale data. // each row in the table will have the following data: // Lcid, Ansi codepage, Oem codepage, MAC codepage, EBCDIC codepage, Geo Id, Digit Substitution | ListSeparator, specific locale index, Console locale index - private static readonly int[] s_nameIndexToNumericData = new int[CulturesCount * NUMERIC_LOCALE_DATA_COUNT_PER_ROW] + private static ReadOnlySpan NameIndexToNumericData => new int[CulturesCount * NUMERIC_LOCALE_DATA_COUNT_PER_ROW] { // Lcid, Ansi CP, Oem CP, MAC CP, EBCDIC CP, Geo Id, digit substitution | ListSeparator, Specific culture index, Console locale index // index - locale name 0x1000 , 0x0 , 0x1 , 0x2 , 0x1f4 , 0x49 , 1 | SemicolonSep , 3 , 240 , // 0 - aa @@ -1327,20 +1327,20 @@ static void GenerateData(string[] cultures, (string lcid, string culture)[] lcid Console.WriteLine("private static ReadOnlySpan LcidToCultureNameIndices => new byte[CulturesCount * NumericLocaleDataBytesPerRow]"); Console.WriteLine("{"); - for (int i = 0; i < s_nameIndexToNumericData.Length; i += NUMERIC_LOCALE_DATA_COUNT_PER_ROW) + for (int i = 0; i < NameIndexToNumericData.Length; i += NUMERIC_LOCALE_DATA_COUNT_PER_ROW) { - uint Lcid = (uint)s_nameIndexToNumericData[i]; - uint AnsiCP = (uint)s_nameIndexToNumericData[i + 1]; - uint OemCP = (uint)s_nameIndexToNumericData[i + 2]; - uint MacCP = (uint)s_nameIndexToNumericData[i + 3]; - uint EBCDIC = (uint)s_nameIndexToNumericData[i + 4]; - uint GeoId = (uint)s_nameIndexToNumericData[i + 5]; - uint DigitList = (uint)s_nameIndexToNumericData[i + 6]; + uint Lcid = (uint)NameIndexToNumericData[i]; + uint AnsiCP = (uint)NameIndexToNumericData[i + 1]; + uint OemCP = (uint)NameIndexToNumericData[i + 2]; + uint MacCP = (uint)NameIndexToNumericData[i + 3]; + uint EBCDIC = (uint)NameIndexToNumericData[i + 4]; + uint GeoId = (uint)NameIndexToNumericData[i + 5]; + uint DigitList = (uint)NameIndexToNumericData[i + 6]; - int index = s_nameIndexToNumericData[i + 7]; + int index = NameIndexToNumericData[i + 7]; Debug.Assert(index == -1 || index < 0xfff); uint SpecificCultureIndex = index == -1 ? 0xfff: (uint)index; - index = s_nameIndexToNumericData[i + 8]; + index = NameIndexToNumericData[i + 8]; Debug.Assert(index == -1 || index < 0xfff); uint ConsoleLocaleIndex = index == -1 ? 0xfff : (uint)index; diff --git a/src/libraries/System.Private.CoreLib/src/System/Globalization/IdnMapping.cs b/src/libraries/System.Private.CoreLib/src/System/Globalization/IdnMapping.cs index be74bb7a1dfdc..5f3c0d59f11e6 100644 --- a/src/libraries/System.Private.CoreLib/src/System/Globalization/IdnMapping.cs +++ b/src/libraries/System.Private.CoreLib/src/System/Globalization/IdnMapping.cs @@ -184,7 +184,7 @@ private static unsafe string GetStringForOutput(string originalString, char* inp private const int c_damp = 700; // Legal "dot" separators (i.e: . in www.microsoft.com) - private static readonly char[] s_dotSeparators = { '.', '\u3002', '\uFF0E', '\uFF61' }; + private static ReadOnlySpan DotSeparators => new char[] { '.', '\u3002', '\uFF0E', '\uFF61' }; private string GetAsciiInvariant(string unicode, int index, int count) { @@ -322,10 +322,8 @@ private static string PunycodeEncode(string unicode) while (iNextDot < unicode.Length) { // Find end of this segment - iNextDot = unicode.IndexOfAny(s_dotSeparators, iAfterLastDot); - Debug.Assert(iNextDot <= unicode.Length, "[IdnMapping.punycode_encode]IndexOfAny is broken"); - if (iNextDot < 0) - iNextDot = unicode.Length; + iNextDot = unicode.AsSpan(iAfterLastDot).IndexOfAny(DotSeparators); + iNextDot = iNextDot < 0 ? unicode.Length : iNextDot + iAfterLastDot; // Only allowed to have empty . section at end (www.microsoft.com.) if (iNextDot == iAfterLastDot) diff --git a/src/libraries/System.Private.CoreLib/src/System/Globalization/JulianCalendar.cs b/src/libraries/System.Private.CoreLib/src/System/Globalization/JulianCalendar.cs index bd213f17fe1f0..d6b1c013329d7 100644 --- a/src/libraries/System.Private.CoreLib/src/System/Globalization/JulianCalendar.cs +++ b/src/libraries/System.Private.CoreLib/src/System/Globalization/JulianCalendar.cs @@ -31,16 +31,6 @@ public class JulianCalendar : Calendar // Number of days in 4 years private const int JulianDaysPer4Years = JulianDaysPerYear * 4 + 1; - private static readonly int[] s_daysToMonth365 = - { - 0, 31, 59, 90, 120, 151, 181, 212, 243, 273, 304, 334, 365 - }; - - private static readonly int[] s_daysToMonth366 = - { - 0, 31, 60, 91, 121, 152, 182, 213, 244, 274, 305, 335, 366 - }; - // Gregorian Calendar 9999/12/31 = Julian Calendar 9999/10/19 // keep it as variable field for serialization compat. internal int MaxYear = 9999; @@ -106,7 +96,7 @@ internal static void CheckDayRange(int year, int month, int day) } bool isLeapYear = (year % 4) == 0; - int[] days = isLeapYear ? s_daysToMonth366 : s_daysToMonth365; + ReadOnlySpan days = isLeapYear ? GregorianCalendar.DaysToMonth366 : GregorianCalendar.DaysToMonth365; int monthDays = days[month] - days[month - 1]; if (day < 1 || day > monthDays) { @@ -153,7 +143,7 @@ internal static int GetDatePart(long ticks, int part) // Leap year calculation looks different from IsLeapYear since y1, y4, // and y100 are relative to year 1, not year 0 bool leapYear = (y1 == 3); - int[] days = leapYear ? s_daysToMonth366 : s_daysToMonth365; + ReadOnlySpan days = leapYear ? GregorianCalendar.DaysToMonth366 : GregorianCalendar.DaysToMonth365; // All months have less than 32 days, so n >> 5 is a good conservative // estimate for the month int m = (n >> 5) + 1; @@ -178,7 +168,7 @@ internal static int GetDatePart(long ticks, int part) /// internal static long DateToTicks(int year, int month, int day) { - int[] days = (year % 4 == 0) ? s_daysToMonth366 : s_daysToMonth365; + ReadOnlySpan days = (year % 4 == 0) ? GregorianCalendar.DaysToMonth366 : GregorianCalendar.DaysToMonth365; int y = year - 1; int n = y * 365 + y / 4 + days[month - 1] + day - 1; // Gregorian 1/1/0001 is Julian 1/3/0001. n * TicksPerDay is the ticks in JulianCalendar. @@ -212,7 +202,7 @@ public override DateTime AddMonths(DateTime time, int months) y += (i - 11) / 12; } - int[] daysArray = (y % 4 == 0 && (y % 100 != 0 || y % 400 == 0)) ? s_daysToMonth366 : s_daysToMonth365; + ReadOnlySpan daysArray = (y % 4 == 0 && (y % 100 != 0 || y % 400 == 0)) ? GregorianCalendar.DaysToMonth366 : GregorianCalendar.DaysToMonth365; int days = daysArray[m] - daysArray[m - 1]; if (d > days) { @@ -245,7 +235,7 @@ public override int GetDaysInMonth(int year, int month, int era) { CheckYearEraRange(year, era); CheckMonthRange(month); - int[] days = (year % 4 == 0) ? s_daysToMonth366 : s_daysToMonth365; + ReadOnlySpan days = (year % 4 == 0) ? GregorianCalendar.DaysToMonth366 : GregorianCalendar.DaysToMonth365; return days[month] - days[month - 1]; } diff --git a/src/libraries/System.Private.CoreLib/src/System/Globalization/PersianCalendar.cs b/src/libraries/System.Private.CoreLib/src/System/Globalization/PersianCalendar.cs index a1d507dc2a323..f766b0ff553a3 100644 --- a/src/libraries/System.Private.CoreLib/src/System/Globalization/PersianCalendar.cs +++ b/src/libraries/System.Private.CoreLib/src/System/Globalization/PersianCalendar.cs @@ -30,7 +30,7 @@ public class PersianCalendar : Calendar private const int DatePartDay = 3; private const int MonthsPerYear = 12; - private static readonly int[] s_daysToMonth = { 0, 31, 62, 93, 124, 155, 186, 216, 246, 276, 306, 336, 366 }; + private static ReadOnlySpan DaysToMonth => new int[] { 0, 31, 62, 93, 124, 155, 186, 216, 246, 276, 306, 336, 366 }; private const int MaxCalendarYear = 9378; private const int MaxCalendarMonth = 10; @@ -125,7 +125,7 @@ private static int MonthFromOrdinalDay(int ordinalDay) { Debug.Assert(ordinalDay <= 366); int index = 0; - while (ordinalDay > s_daysToMonth[index]) + while (ordinalDay > DaysToMonth[index]) { index++; } @@ -138,7 +138,7 @@ private static int DaysInPreviousMonths(int month) Debug.Assert(1 <= month && month <= 12); // months are one based but for calculations use 0 based --month; - return s_daysToMonth[month]; + return DaysToMonth[month]; } internal int GetDatePart(long ticks, int part) @@ -276,7 +276,7 @@ public override int GetDaysInMonth(int year, int month, int era) return MaxCalendarDay; } - int daysInMonth = s_daysToMonth[month] - s_daysToMonth[month - 1]; + int daysInMonth = DaysToMonth[month] - DaysToMonth[month - 1]; if ((month == MonthsPerYear) && !IsLeapYear(year)) { Debug.Assert(daysInMonth == 30); @@ -291,7 +291,7 @@ public override int GetDaysInYear(int year, int era) CheckYearRange(year, era); if (year == MaxCalendarYear) { - return s_daysToMonth[MaxCalendarMonth - 1] + MaxCalendarDay; + return DaysToMonth[MaxCalendarMonth - 1] + MaxCalendarDay; } return IsLeapYear(year, CurrentEra) ? 366 : 365; diff --git a/src/libraries/System.Private.CoreLib/src/System/IO/Enumeration/FileSystemEnumerableFactory.cs b/src/libraries/System.Private.CoreLib/src/System/IO/Enumeration/FileSystemEnumerableFactory.cs index 33b8c92a32ff3..aadb3f3ba9e47 100644 --- a/src/libraries/System.Private.CoreLib/src/System/IO/Enumeration/FileSystemEnumerableFactory.cs +++ b/src/libraries/System.Private.CoreLib/src/System/IO/Enumeration/FileSystemEnumerableFactory.cs @@ -9,12 +9,6 @@ namespace System.IO.Enumeration { internal static class FileSystemEnumerableFactory { - // These all have special meaning in DOS name matching. '\' is the escaping character (which conveniently - // is the directory separator and cannot be part of any path segment in Windows). The other three are the - // special case wildcards that we'll convert some * and ? into. They're also valid as filenames on Unix, - // which is not true in Windows and as such we'll escape any that occur on the input string. - private static readonly char[] s_unixEscapeChars = { '\\', '"', '<', '>' }; - /// /// Validates the directory and expression strings to check that they have no invalid characters, any special DOS wildcard characters in Win32 in the expression get replaced with their proper escaped representation, and if the expression string begins with a directory name, the directory name is moved and appended at the end of the directory string. /// @@ -76,7 +70,12 @@ internal static bool NormalizeInputs(ref string directory, ref string expression } else { - if (Path.DirectorySeparatorChar != '\\' && expression.IndexOfAny(s_unixEscapeChars) >= 0) + // These all have special meaning in DOS name matching. '\' is the escaping character (which conveniently + // is the directory separator and cannot be part of any path segment in Windows). The other three are the + // special case wildcards that we'll convert some * and ? into. They're also valid as filenames on Unix, + // which is not true in Windows and as such we'll escape any that occur on the input string. + if (Path.DirectorySeparatorChar != '\\' && + expression.AsSpan().IndexOfAny((ReadOnlySpan)new char[] { '\\', '"', '<', '>' }) >= 0) { // Backslash isn't the default separator, need to escape (e.g. Unix) expression = expression.Replace("\\", "\\\\"); diff --git a/src/libraries/System.Private.CoreLib/src/System/IO/Enumeration/FileSystemName.cs b/src/libraries/System.Private.CoreLib/src/System/IO/Enumeration/FileSystemName.cs index 7ac46feb9ab9d..3bdb7d1a7e9f7 100644 --- a/src/libraries/System.Private.CoreLib/src/System/IO/Enumeration/FileSystemName.cs +++ b/src/libraries/System.Private.CoreLib/src/System/IO/Enumeration/FileSystemName.cs @@ -9,18 +9,6 @@ namespace System.IO.Enumeration /// Provides methods for matching file system names. public static class FileSystemName { - // [MS - FSA] 2.1.4.4 Algorithm for Determining if a FileName Is in an Expression - // https://msdn.microsoft.com/en-us/library/ff469270.aspx - private static readonly char[] s_wildcardChars = - { - '\"', '<', '>', '*', '?' - }; - - private static readonly char[] s_simpleWildcardChars = - { - '*', '?' - }; - /// Translates the given Win32 expression. Change '*' and '?' to '<', '>' and '"' to match Win32 behavior. /// The expression to translate. /// A string with the translated Win32 expression. @@ -161,7 +149,13 @@ private static bool MatchPattern(ReadOnlySpan expression, ReadOnlySpan expressionEnd = expression.Slice(1); - if (expressionEnd.IndexOfAny(useExtendedWildcards ? s_wildcardChars : s_simpleWildcardChars) < 0) + + // [MS - FSA] 2.1.4.4 Algorithm for Determining if a FileName Is in an Expression + // https://msdn.microsoft.com/en-us/library/ff469270.aspx + bool hasWildcards = (useExtendedWildcards ? + expressionEnd.IndexOfAny((ReadOnlySpan)new char[] { '\"', '<', '>', '*', '?' }) : + expressionEnd.IndexOfAny('*', '?')) >= 0; + if (!hasWildcards) { // Handle the special case of a single starting *, which essentially means "ends with" diff --git a/src/libraries/System.Private.CoreLib/src/System/Math.cs b/src/libraries/System.Private.CoreLib/src/System/Math.cs index c8abd2bc39c68..79ff858afb588 100644 --- a/src/libraries/System.Private.CoreLib/src/System/Math.cs +++ b/src/libraries/System.Private.CoreLib/src/System/Math.cs @@ -38,7 +38,7 @@ public static partial class Math private const double doubleRoundLimit = 1e16d; // This table is required for the Round function which can specify the number of digits to round to - private static readonly double[] roundPower10Double = new double[] { + private static ReadOnlySpan RoundPower10Double => new double[] { 1E0, 1E1, 1E2, 1E3, 1E4, 1E5, 1E6, 1E7, 1E8, 1E9, 1E10, 1E11, 1E12, 1E13, 1E14, 1E15 }; @@ -1342,7 +1342,7 @@ public static unsafe double Round(double value, int digits, MidpointRounding mod if (Abs(value) < doubleRoundLimit) { - double power10 = roundPower10Double[digits]; + double power10 = RoundPower10Double[digits]; value *= power10; diff --git a/src/libraries/System.Private.CoreLib/src/System/MathF.cs b/src/libraries/System.Private.CoreLib/src/System/MathF.cs index 6b86c780a5c46..0e783e3ff12b2 100644 --- a/src/libraries/System.Private.CoreLib/src/System/MathF.cs +++ b/src/libraries/System.Private.CoreLib/src/System/MathF.cs @@ -31,7 +31,7 @@ public static partial class MathF private const int maxRoundingDigits = 6; // This table is required for the Round function which can specify the number of digits to round to - private static readonly float[] roundPower10Single = new float[] { + private static ReadOnlySpan RoundPower10Single => new float[] { 1e0f, 1e1f, 1e2f, 1e3f, 1e4f, 1e5f, 1e6f }; @@ -458,7 +458,7 @@ public static unsafe float Round(float x, int digits, MidpointRounding mode) if (Abs(x) < singleRoundLimit) { - float power10 = roundPower10Single[digits]; + float power10 = RoundPower10Single[digits]; x *= power10; diff --git a/src/libraries/System.Private.CoreLib/src/System/Number.BigInteger.cs b/src/libraries/System.Private.CoreLib/src/System/Number.BigInteger.cs index c19e7d036b04b..e7f1948afe401 100644 --- a/src/libraries/System.Private.CoreLib/src/System/Number.BigInteger.cs +++ b/src/libraries/System.Private.CoreLib/src/System/Number.BigInteger.cs @@ -33,7 +33,7 @@ internal unsafe ref struct BigInteger private const int BitsPerBlock = sizeof(int) * 8; private const int MaxBlockCount = (MaxBits + (BitsPerBlock - 1)) / BitsPerBlock; - private static readonly uint[] s_Pow10UInt32Table = new uint[] + private static ReadOnlySpan Pow10UInt32Table => new uint[] { 1, // 10^0 10, // 10^1 @@ -48,7 +48,7 @@ internal unsafe ref struct BigInteger 1000000000 // 10^9 }; - private static readonly int[] s_Pow10BigNumTableIndices = new int[] + private static ReadOnlySpan Pow10BigNumTableIndices => new int[] { 0, // 10^8 2, // 10^16 @@ -60,7 +60,7 @@ internal unsafe ref struct BigInteger 116, // 10^1024 }; - private static readonly uint[] s_Pow10BigNumTable = new uint[] + private static ReadOnlySpan Pow10BigNumTable => new uint[] { // 10^8 1, // _length @@ -826,37 +826,37 @@ public static void Pow2(uint exponent, out BigInteger result) public static void Pow10(uint exponent, out BigInteger result) { - // We leverage two arrays - s_Pow10UInt32Table and s_Pow10BigNumTable to speed up the Pow10 calculation. + // We leverage two arrays - Pow10UInt32Table and Pow10BigNumTable to speed up the Pow10 calculation. // - // s_Pow10UInt32Table stores the results of 10^0 to 10^7. - // s_Pow10BigNumTable stores the results of 10^8, 10^16, 10^32, 10^64, 10^128, 10^256, and 10^512 + // Pow10UInt32Table stores the results of 10^0 to 10^7. + // Pow10BigNumTable stores the results of 10^8, 10^16, 10^32, 10^64, 10^128, 10^256, and 10^512 // // For example, let's say exp = 0b111111. We can split the exp to two parts, one is small exp, // which 10^smallExp can be represented as uint, another part is 10^bigExp, which must be represented as BigNum. // So the result should be 10^smallExp * 10^bigExp. // - // Calculating 10^smallExp is simple, we just lookup the 10^smallExp from s_Pow10UInt32Table. + // Calculating 10^smallExp is simple, we just lookup the 10^smallExp from Pow10UInt32Table. // But here's a bad news: although uint can represent 10^9, exp 9's binary representation is 1001. // That means 10^(1011), 10^(1101), 10^(1111) all cannot be stored as uint, we cannot easily say something like: - // "Any bits <= 3 is small exp, any bits > 3 is big exp". So instead of involving 10^8, 10^9 to s_Pow10UInt32Table, - // consider 10^8 and 10^9 as a bigNum, so they fall into s_Pow10BigNumTable. Now we can have a simple rule: + // "Any bits <= 3 is small exp, any bits > 3 is big exp". So instead of involving 10^8, 10^9 to Pow10UInt32Table, + // consider 10^8 and 10^9 as a bigNum, so they fall into Pow10BigNumTable. Now we can have a simple rule: // "Any bits <= 3 is small exp, any bits > 3 is big exp". // // For 0b111111, we first calculate 10^(smallExp), which is 10^(7), now we can shift right 3 bits, prepare to calculate the bigExp part, // the exp now becomes 0b000111. // - // Apparently the lowest bit of bigExp should represent 10^8 because we have already shifted 3 bits for smallExp, so s_Pow10BigNumTable[0] = 10^8. + // Apparently the lowest bit of bigExp should represent 10^8 because we have already shifted 3 bits for smallExp, so Pow10BigNumTable[0] = 10^8. // Now let's shift exp right 1 bit, the lowest bit should represent 10^(8 * 2) = 10^16, and so on... // - // That's why we just need the values of s_Pow10BigNumTable be power of 2. + // That's why we just need the values of Pow10BigNumTable be power of 2. // // More details of this implementation can be found at: https://github.com/dotnet/coreclr/pull/12894#discussion_r128890596 - // Validate that `s_Pow10BigNumTable` has exactly enough trailing elements to fill a BigInteger (which contains MaxBlockCount + 1 elements) + // Validate that `Pow10BigNumTable` has exactly enough trailing elements to fill a BigInteger (which contains MaxBlockCount + 1 elements) // We validate here, since this is the only current consumer of the array - Debug.Assert((s_Pow10BigNumTableIndices[^1] + MaxBlockCount + 2) == s_Pow10BigNumTable.Length); + Debug.Assert((Pow10BigNumTableIndices[^1] + MaxBlockCount + 2) == Pow10BigNumTable.Length); - SetUInt32(out BigInteger temp1, s_Pow10UInt32Table[exponent & 0x7]); + SetUInt32(out BigInteger temp1, Pow10UInt32Table[(int)(exponent & 0x7)]); ref BigInteger lhs = ref temp1; SetZero(out BigInteger temp2); @@ -871,7 +871,7 @@ public static void Pow10(uint exponent, out BigInteger result) if ((exponent & 1) != 0) { // Multiply into the next temporary - fixed (uint* pBigNumEntry = &s_Pow10BigNumTable[s_Pow10BigNumTableIndices[index]]) + fixed (uint* pBigNumEntry = &Pow10BigNumTable[Pow10BigNumTableIndices[(int)index]]) { ref BigInteger rhs = ref *(BigInteger*)(pBigNumEntry); Multiply(ref lhs, ref rhs, out product); @@ -1078,7 +1078,7 @@ public void MultiplyPow10(uint exponent) { if (exponent <= 9) { - Multiply(s_Pow10UInt32Table[exponent]); + Multiply(Pow10UInt32Table[(int)exponent]); } else if (!IsZero()) { diff --git a/src/libraries/System.Private.CoreLib/src/System/Number.Grisu3.cs b/src/libraries/System.Private.CoreLib/src/System/Number.Grisu3.cs index b1217121ef6b5..f18f202837640 100644 --- a/src/libraries/System.Private.CoreLib/src/System/Number.Grisu3.cs +++ b/src/libraries/System.Private.CoreLib/src/System/Number.Grisu3.cs @@ -34,7 +34,7 @@ internal static class Grisu3 private const int MaximalTargetExponent = -32; private const int MinimalTargetExponent = -60; - private static readonly short[] s_CachedPowersBinaryExponent = new short[] + private static ReadOnlySpan CachedPowersBinaryExponent => new short[] { -1220, -1193, @@ -125,7 +125,7 @@ internal static class Grisu3 1066, }; - private static readonly short[] s_CachedPowersDecimalExponent = new short[] + private static ReadOnlySpan CachedPowersDecimalExponent => new short[] { CachedPowersMinDecimalExponent, -340, @@ -216,7 +216,7 @@ internal static class Grisu3 CachedPowersPowerMaxDecimalExponent, }; - private static readonly ulong[] s_CachedPowersSignificand = new ulong[] + private static ReadOnlySpan CachedPowersSignificand => new ulong[] { 0xFA8FD5A0081C0288, 0xBAAEE17FA23EBF76, @@ -307,7 +307,7 @@ internal static class Grisu3 0xAF87023B9BF0EE6B, }; - private static readonly uint[] s_SmallPowersOfTen = new uint[] + private static ReadOnlySpan SmallPowersOfTen => new uint[] { 1, // 10^0 10, // 10^1 @@ -540,15 +540,15 @@ private static uint BiggestPowerTen(uint number, int numberBits, out int exponen // 1233/4096 is approximately 1/log2(10) int exponentGuess = ((numberBits + 1) * 1233) >> 12; - Debug.Assert((uint)(exponentGuess) < s_SmallPowersOfTen.Length); + Debug.Assert((uint)(exponentGuess) < SmallPowersOfTen.Length); - uint power = s_SmallPowersOfTen[exponentGuess]; + uint power = SmallPowersOfTen[exponentGuess]; // We don't have any guarantees that 2^numberBits <= number if (number < power) { exponentGuess--; - power = s_SmallPowersOfTen[exponentGuess]; + power = SmallPowersOfTen[exponentGuess]; } exponentPlusOne = exponentGuess + 1; @@ -606,7 +606,7 @@ private static bool TryDigitGenCounted(in DiyFp w, int requestedDigits, Span= 11, integrals is not able to exhaust the count by itself since 10^(11 -1) > uint.MaxValue >= integrals. // If integrals < 10^(requestedDigits - 1), integrals cannot exhaust the count. // Otherwise, integrals might be able to exhaust the count and we need to execute the rest of the code. - if ((fractionals == 0) && ((requestedDigits >= 11) || (integrals < s_SmallPowersOfTen[requestedDigits - 1]))) + if ((fractionals == 0) && ((requestedDigits >= 11) || (integrals < SmallPowersOfTen[requestedDigits - 1]))) { Debug.Assert(buffer[0] == '\0'); length = 0; @@ -884,19 +884,19 @@ private static bool TryDigitGenShortest(in DiyFp low, in DiyFp w, in DiyFp high, // Returns a cached power-of-ten with a binary exponent in the range [minExponent; maxExponent] (boundaries included). private static DiyFp GetCachedPowerForBinaryExponentRange(int minExponent, int maxExponent, out int decimalExponent) { - Debug.Assert(s_CachedPowersSignificand.Length == s_CachedPowersBinaryExponent.Length); - Debug.Assert(s_CachedPowersSignificand.Length == s_CachedPowersDecimalExponent.Length); + Debug.Assert(CachedPowersSignificand.Length == CachedPowersBinaryExponent.Length); + Debug.Assert(CachedPowersSignificand.Length == CachedPowersDecimalExponent.Length); double k = Math.Ceiling((minExponent + DiyFp.SignificandSize - 1) * D1Log210); int index = ((CachedPowersOffset + (int)(k) - 1) / CachedPowersDecimalExponentDistance) + 1; - Debug.Assert((uint)(index) < s_CachedPowersSignificand.Length); + Debug.Assert((uint)(index) < CachedPowersSignificand.Length); - Debug.Assert(minExponent <= s_CachedPowersBinaryExponent[index]); - Debug.Assert(s_CachedPowersBinaryExponent[index] <= maxExponent); + Debug.Assert(minExponent <= CachedPowersBinaryExponent[index]); + Debug.Assert(CachedPowersBinaryExponent[index] <= maxExponent); - decimalExponent = s_CachedPowersDecimalExponent[index]; - return new DiyFp(s_CachedPowersSignificand[index], s_CachedPowersBinaryExponent[index]); + decimalExponent = CachedPowersDecimalExponent[index]; + return new DiyFp(CachedPowersSignificand[index], CachedPowersBinaryExponent[index]); } // Rounds the buffer upwards if the result is closer to v by possibly adding 1 to the buffer. diff --git a/src/libraries/System.Private.CoreLib/src/System/Number.NumberToFloatingPointBits.cs b/src/libraries/System.Private.CoreLib/src/System/Number.NumberToFloatingPointBits.cs index e88014c3a9518..65adf4a034cd1 100644 --- a/src/libraries/System.Private.CoreLib/src/System/Number.NumberToFloatingPointBits.cs +++ b/src/libraries/System.Private.CoreLib/src/System/Number.NumberToFloatingPointBits.cs @@ -140,7 +140,7 @@ public FloatingPointInfo(ushort denormalMantissaBits, ushort exponentBits, int m /// Normalized 128 bits values for powers of 5^q for q in range [-342, 308] /// stored as 2 64-bits integers for convenience /// - private static readonly ulong[] s_Pow5128Table = { + private static ReadOnlySpan Pow5128Table => new ulong[] { 0xeef453d6923bd65a, 0x113faa2906a13b3f, 0x9558b4661b6565f8, 0x4ac7ca59a424c507, 0xbaaee17fa23ebf76, 0x5d79bcf00d2df649, @@ -1647,13 +1647,13 @@ private static (ulong high, ulong low) ComputeProductApproximation(int bitPrecis int index = 2 * (int)(q - -342); // For small values of q, e.g., q in [0,27], the answer is always exact because // Math.BigMul gives the exact answer. - ulong high = Math.BigMul(w, s_Pow5128Table[index], out ulong low); + ulong high = Math.BigMul(w, Pow5128Table[index], out ulong low); ulong precisionMask = (bitPrecision < 64) ? (0xFFFFFFFFFFFFFFFFUL >> bitPrecision) : 0xFFFFFFFFFFFFFFFFUL; if ((high & precisionMask) == precisionMask) { // could further guard with (lower + w < lower) // regarding the second product, we only need secondproduct.high, but our expectation is that the compiler will optimize this extra work away if needed. - ulong high2 = Math.BigMul(w, s_Pow5128Table[index + 1], out ulong _); + ulong high2 = Math.BigMul(w, Pow5128Table[index + 1], out ulong _); low += high2; if (high2 > low) { diff --git a/src/libraries/System.Private.CoreLib/src/System/Reflection/AssemblyNameParser.cs b/src/libraries/System.Private.CoreLib/src/System/Reflection/AssemblyNameParser.cs index e245714e12017..ab6dce32c2b95 100644 --- a/src/libraries/System.Private.CoreLib/src/System/Reflection/AssemblyNameParser.cs +++ b/src/libraries/System.Private.CoreLib/src/System/Reflection/AssemblyNameParser.cs @@ -51,7 +51,6 @@ private enum AttributeKind ContentType = 32 } - private static readonly char[] s_illegalCharactersInSimpleName = { '/', '\\', ':' }; private ReadOnlySpan _input; private int _index; @@ -90,7 +89,7 @@ private AssemblyNameParts Parse() if (token != Token.String) ThrowInvalidAssemblyName(); - if (name == string.Empty || name.IndexOfAny(s_illegalCharactersInSimpleName) != -1) + if (string.IsNullOrEmpty(name) || name.AsSpan().IndexOfAny('/', '\\', ':') != -1) ThrowInvalidAssemblyName(); Version? version = null; diff --git a/src/libraries/System.Private.CoreLib/src/System/Security/SecurityElement.cs b/src/libraries/System.Private.CoreLib/src/System/Security/SecurityElement.cs index 67f4184a75724..6dad5d3ffa570 100644 --- a/src/libraries/System.Private.CoreLib/src/System/Security/SecurityElement.cs +++ b/src/libraries/System.Private.CoreLib/src/System/Security/SecurityElement.cs @@ -18,7 +18,7 @@ public sealed class SecurityElement private const int AttributesTypical = 4 * 2; // 4 attributes, times 2 strings per attribute private const int ChildrenTypical = 1; - private static readonly char[] s_escapeChars = new char[] { '<', '>', '\"', '\'', '&' }; + private static ReadOnlySpan EscapeChars => new char[] { '<', '>', '\"', '\'', '&' }; private static readonly string[] s_escapeStringPairs = new string[] { // these must be all once character escape sequences or a new escaping algorithm is needed @@ -326,36 +326,16 @@ private static string GetEscapeSequence(char c) StringBuilder? sb = null; - int strLen = str.Length; - int index; // Pointer into the string that indicates the location of the current '&' character - int newIndex = 0; // Pointer into the string that indicates the start index of the "remaining" string (that still needs to be processed). - - while (true) + ReadOnlySpan span = str; + int pos; + while ((pos = span.IndexOfAny(EscapeChars)) >= 0) { - index = str.IndexOfAny(s_escapeChars, newIndex); - - if (index < 0) - { - if (sb == null) - return str; - else - { - sb.Append(str, newIndex, strLen - newIndex); - return sb.ToString(); - } - } - else - { - sb ??= new StringBuilder(); - - sb.Append(str, newIndex, index - newIndex); - sb.Append(GetEscapeSequence(str[index])); - - newIndex = (index + 1); - } + sb ??= new StringBuilder(); + sb.Append(span.Slice(0, pos)).Append(GetEscapeSequence(span[pos])); + span = span.Slice(pos + 1); } - // no normal exit is possible + return sb == null ? str : sb.Append(span).ToString(); } private static string GetUnescapeSequence(string str, int index, out int newIndex) diff --git a/src/libraries/System.Private.CoreLib/src/System/Text/EncoderLatin1BestFitFallback.Data.cs b/src/libraries/System.Private.CoreLib/src/System/Text/EncoderLatin1BestFitFallback.Data.cs index c110074189c19..fe856d6148225 100644 --- a/src/libraries/System.Private.CoreLib/src/System/Text/EncoderLatin1BestFitFallback.Data.cs +++ b/src/libraries/System.Private.CoreLib/src/System/Text/EncoderLatin1BestFitFallback.Data.cs @@ -6,7 +6,7 @@ namespace System.Text internal sealed partial class EncoderLatin1BestFitFallbackBuffer { // Best fit for ASCII, and since it works for ASCII, we use it for latin1 as well. - private static readonly char[] s_arrayCharBestFit = + private static ReadOnlySpan ArrayCharBestFit => new char[] { // The first many are in case you wanted to use this for ASCIIEncoding, which we don't need to do any more. // (char)0x00a0, (char)0x0020, // No-Break Space -> Space diff --git a/src/libraries/System.Private.CoreLib/src/System/Text/EncoderLatin1BestFitFallback.cs b/src/libraries/System.Private.CoreLib/src/System/Text/EncoderLatin1BestFitFallback.cs index 8fb9515001842..d9ceb1178643e 100644 --- a/src/libraries/System.Private.CoreLib/src/System/Text/EncoderLatin1BestFitFallback.cs +++ b/src/libraries/System.Private.CoreLib/src/System/Text/EncoderLatin1BestFitFallback.cs @@ -123,8 +123,7 @@ private static char TryBestFit(char cUnknown) { // Need to figure out our best fit character, low is beginning of array, high is 1 AFTER end of array int lowBound = 0; - Debug.Assert(s_arrayCharBestFit != null); - int highBound = s_arrayCharBestFit.Length; + int highBound = ArrayCharBestFit.Length; int index; // Binary search the array @@ -136,13 +135,13 @@ private static char TryBestFit(char cUnknown) // Also note that index can never == highBound (because diff is rounded down) index = ((iDiff / 2) + lowBound) & 0xFFFE; - char cTest = s_arrayCharBestFit[index]; + char cTest = ArrayCharBestFit[index]; if (cTest == cUnknown) { // We found it - Debug.Assert(index + 1 < s_arrayCharBestFit.Length, + Debug.Assert(index + 1 < ArrayCharBestFit.Length, "[EncoderLatin1BestFitFallbackBuffer.TryBestFit]Expected replacement character at end of array"); - return s_arrayCharBestFit[index + 1]; + return ArrayCharBestFit[index + 1]; } else if (cTest < cUnknown) { @@ -158,12 +157,12 @@ private static char TryBestFit(char cUnknown) for (index = lowBound; index < highBound; index += 2) { - if (s_arrayCharBestFit[index] == cUnknown) + if (ArrayCharBestFit[index] == cUnknown) { // We found it - Debug.Assert(index + 1 < s_arrayCharBestFit.Length, + Debug.Assert(index + 1 < ArrayCharBestFit.Length, "[EncoderLatin1BestFitFallbackBuffer.TryBestFit]Expected replacement character at end of array"); - return s_arrayCharBestFit[index + 1]; + return ArrayCharBestFit[index + 1]; } } diff --git a/src/libraries/System.Private.CoreLib/src/System/Text/EncodingData.cs b/src/libraries/System.Private.CoreLib/src/System/Text/EncodingData.cs index 992891ff08836..2b621d6bce9fe 100644 --- a/src/libraries/System.Private.CoreLib/src/System/Text/EncodingData.cs +++ b/src/libraries/System.Private.CoreLib/src/System/Text/EncodingData.cs @@ -9,14 +9,14 @@ namespace System.Text internal static partial class EncodingTable { // - // s_encodingNames is the concatenation of all supported IANA names for each codepage. + // EncodingNames is the concatenation of all supported IANA names for each codepage. // This is done rather than using a large readonly array of strings to avoid // generating a large amount of code in the static constructor. - // Using indices from s_encodingNamesIndices, we binary search this string when mapping + // Using indices from EncodingNamesIndices, we binary search this string when mapping // an encoding name to a codepage. Note that these names are all lowercase and are // sorted alphabetically. // - private const string s_encodingNames = + private const string EncodingNames = "ansi_x3.4-1968" + // 20127 "ansi_x3.4-1986" + // 20127 "ascii" + // 20127 @@ -61,11 +61,11 @@ internal static partial class EncodingTable "x-unicode-2-0-utf-8"; // 65001 // - // s_encodingNameIndices contains the start index of every encoding name in the string - // s_encodingNames. We infer the length of each string by looking at the start index + // EncodingNameIndices contains the start index of every encoding name in the string + // EncodingNames. We infer the length of each string by looking at the start index // of the next string. // - private static readonly int[] s_encodingNameIndices = new int[] + private static ReadOnlySpan EncodingNameIndices => new int[] { 0, // ansi_x3.4-1968 (20127) 14, // ansi_x3.4-1986 (20127) @@ -113,13 +113,13 @@ internal static partial class EncodingTable }; // - // s_codePagesByName contains the list of supported codepages which match the encoding - // names listed in s_encodingNames. The way mapping works is we binary search - // s_encodingNames using s_encodingNamesIndices until we find a match for a given name. - // The index of the entry in s_encodingNamesIndices will be the index of codepage in - // s_codePagesByName. + // CodePagesByName contains the list of supported codepages which match the encoding + // names listed in EncodingNames. The way mapping works is we binary search + // EncodingNames using EncodingNamesIndices until we find a match for a given name. + // The index of the entry in EncodingNamesIndices will be the index of codepage in + // CodePagesByName. // - private static readonly ushort[] s_codePagesByName = new ushort[] + private static ReadOnlySpan CodePagesByName => new ushort[] { 20127, // ansi_x3.4-1968 20127, // ansi_x3.4-1986 @@ -168,14 +168,14 @@ internal static partial class EncodingTable // // When retrieving the value for System.Text.Encoding.WebName or // System.Text.Encoding.EncodingName given System.Text.Encoding.CodePage, - // we perform a linear search on s_mappedCodePages to find the index of the + // we perform a linear search on MappedCodePages to find the index of the // given codepage. This is used to index WebNameIndices to get the start // index of the web name in the string WebNames, and to index - // s_englishNameIndices to get the start of the English name in - // s_englishNames. In addition, this arrays indices correspond to the indices - // into s_uiFamilyCodePages and s_flags. + // EnglishNameIndices to get the start of the English name in + // EnglishNames. In addition, this arrays indices correspond to the indices + // into UiFamilyCodePages and Flags. // - private static readonly ushort[] s_mappedCodePages = new ushort[] + private static ReadOnlySpan MappedCodePages => new ushort[] { 1200, // utf-16 1201, // utf-16be @@ -188,9 +188,9 @@ internal static partial class EncodingTable }; // - // s_uiFamilyCodePages is indexed by the corresponding index in s_mappedCodePages. + // UiFamilyCodePages is indexed by the corresponding index in MappedCodePages. // - private static readonly int[] s_uiFamilyCodePages = new int[] + private static ReadOnlySpan UiFamilyCodePages => new int[] { 1200, 1200, @@ -203,13 +203,13 @@ internal static partial class EncodingTable }; // - // s_webNames is a concatenation of the default encoding names + // WebNames is a concatenation of the default encoding names // for each code page. It is used in retrieving the value for // System.Text.Encoding.WebName given System.Text.Encoding.CodePage. // This is done rather than using a large readonly array of strings to avoid // generating a large amount of code in the static constructor. // - private const string s_webNames = + private const string WebNames = "utf-16" + // 1200 "utf-16BE" + // 1201 "utf-32" + // 12000 @@ -220,11 +220,11 @@ internal static partial class EncodingTable "utf-8"; // 65001 // - // s_webNameIndices contains the start index of each code page's default - // web name in the string s_webNames. It is indexed by an index into - // s_mappedCodePages. + // WebNameIndices contains the start index of each code page's default + // web name in the string WebNames. It is indexed by an index into + // MappedCodePages. // - private static readonly int[] s_webNameIndices = new int[] + private static ReadOnlySpan WebNameIndices => new int[] { 0, // utf-16 (1200) 6, // utf-16be (1201) @@ -238,13 +238,13 @@ internal static partial class EncodingTable }; // - // s_englishNames is the concatenation of the English names for each codepage. + // EnglishNames is the concatenation of the English names for each codepage. // It is used in retrieving the value for System.Text.Encoding.EncodingName // given System.Text.Encoding.CodePage. // This is done rather than using a large readonly array of strings to avoid // generating a large amount of code in the static constructor. // - private const string s_englishNames = + private const string EnglishNames = "Unicode" + // 1200 "Unicode (Big-Endian)" + // 1201 "Unicode (UTF-32)" + // 12000 @@ -255,11 +255,11 @@ internal static partial class EncodingTable "Unicode (UTF-8)"; // 65001 // - // s_englishNameIndices contains the start index of each code page's English - // name in the string s_englishNames. It is indexed by an index into - // s_mappedCodePages. + // EnglishNameIndices contains the start index of each code page's English + // name in the string EnglishNames. It is indexed by an index into + // MappedCodePages. // - private static readonly int[] s_englishNameIndices = new int[] + private static ReadOnlySpan EnglishNameIndices => new int[] { 0, // Unicode (1200) 7, // Unicode (Big-Endian) (1201) @@ -278,8 +278,8 @@ internal static partial class EncodingTable private const uint MIMECONTF_SAVABLE_MAILNEWS = Encoding.MIMECONTF_SAVABLE_MAILNEWS; private const uint MIMECONTF_SAVABLE_BROWSER = Encoding.MIMECONTF_SAVABLE_BROWSER; - // s_flags is indexed by the corresponding index in s_mappedCodePages. - private static readonly uint[] s_flags = new uint[] + // Flags is indexed by the corresponding index in MappedCodePages. + private static ReadOnlySpan Flags => new uint[] { MIMECONTF_SAVABLE_BROWSER, 0, diff --git a/src/libraries/System.Private.CoreLib/src/System/Text/EncodingTable.cs b/src/libraries/System.Private.CoreLib/src/System/Text/EncodingTable.cs index ded8d29edc76c..e404065b099bb 100644 --- a/src/libraries/System.Private.CoreLib/src/System/Text/EncodingTable.cs +++ b/src/libraries/System.Private.CoreLib/src/System/Text/EncodingTable.cs @@ -50,12 +50,12 @@ internal static int GetCodePageFromName(string name) private static int InternalGetCodePageFromName(string name) { int left = 0; - int right = s_encodingNameIndices.Length - 2; + int right = EncodingNameIndices.Length - 2; int index; int result; - Debug.Assert(s_encodingNameIndices.Length == s_codePagesByName.Length + 1); - Debug.Assert(s_encodingNameIndices[^1] == s_encodingNames.Length); + Debug.Assert(EncodingNameIndices.Length == CodePagesByName.Length + 1); + Debug.Assert(EncodingNameIndices[^1] == EncodingNames.Length); ReadOnlySpan invariantName = name.ToLowerInvariant().AsSpan(); @@ -65,13 +65,13 @@ private static int InternalGetCodePageFromName(string name) { index = ((right - left) / 2) + left; - Debug.Assert(index < s_encodingNameIndices.Length - 1); - result = string.CompareOrdinal(invariantName, s_encodingNames.AsSpan(s_encodingNameIndices[index], s_encodingNameIndices[index + 1] - s_encodingNameIndices[index])); + Debug.Assert(index < EncodingNameIndices.Length - 1); + result = string.CompareOrdinal(invariantName, EncodingNames.AsSpan(EncodingNameIndices[index], EncodingNameIndices[index + 1] - EncodingNameIndices[index])); if (result == 0) { // We found the item, return the associated codePage. - return s_codePagesByName[index]; + return CodePagesByName[index]; } else if (result < 0) { @@ -88,10 +88,10 @@ private static int InternalGetCodePageFromName(string name) // Walk the remaining elements (it'll be 3 or fewer). for (; left <= right; left++) { - Debug.Assert(left < s_encodingNameIndices.Length - 1); - if (string.CompareOrdinal(invariantName, s_encodingNames.AsSpan(s_encodingNameIndices[left], s_encodingNameIndices[left + 1] - s_encodingNameIndices[left])) == 0) + Debug.Assert(left < EncodingNameIndices.Length - 1); + if (string.CompareOrdinal(invariantName, EncodingNames.AsSpan(EncodingNameIndices[left], EncodingNameIndices[left + 1] - EncodingNameIndices[left])) == 0) { - return s_codePagesByName[left]; + return CodePagesByName[left]; } } @@ -107,10 +107,10 @@ internal static EncodingInfo[] GetEncodings() // If UTF-7 encoding is not enabled, we adjust the return array length by -1 // to account for the skipped EncodingInfo element. - ushort[] mappedCodePages = s_mappedCodePages; + ReadOnlySpan mappedCodePages = MappedCodePages; EncodingInfo[] arrayEncodingInfo = new EncodingInfo[(LocalAppContextSwitches.EnableUnsafeUTF7Encoding) ? mappedCodePages.Length : (mappedCodePages.Length - 1)]; - string webNames = s_webNames; - int[] webNameIndices = s_webNameIndices; + string webNames = WebNames; + ReadOnlySpan webNameIndices = WebNameIndices; int arrayEncodingInfoIdx = 0; for (int i = 0; i < mappedCodePages.Length; i++) @@ -135,9 +135,9 @@ internal static EncodingInfo[] GetEncodings() internal static EncodingInfo[] GetEncodings(Dictionary encodingInfoList) { Debug.Assert(encodingInfoList != null); - ushort[] mappedCodePages = s_mappedCodePages; - string webNames = s_webNames; - int[] webNameIndices = s_webNameIndices; + ReadOnlySpan mappedCodePages = MappedCodePages; + string webNames = WebNames; + ReadOnlySpan webNameIndices = WebNameIndices; for (int i = 0; i < mappedCodePages.Length; i++) { @@ -177,10 +177,10 @@ internal static EncodingInfo[] GetEncodings(Dictionary encodi { if (s_codePageToCodePageData == null) { - Interlocked.CompareExchange(ref s_codePageToCodePageData, new CodePageDataItem[s_mappedCodePages.Length], null); + Interlocked.CompareExchange(ref s_codePageToCodePageData, new CodePageDataItem[MappedCodePages.Length], null); } - // Keep in sync with s_mappedCodePages + // Keep in sync with MappedCodePages int index; switch (codePage) { @@ -224,13 +224,13 @@ internal static EncodingInfo[] GetEncodings(Dictionary encodi private static CodePageDataItem InternalGetCodePageDataItem(int codePage, int index) { - int uiFamilyCodePage = s_uiFamilyCodePages[index]; - string webName = s_webNames[s_webNameIndices[index]..s_webNameIndices[index + 1]]; + int uiFamilyCodePage = UiFamilyCodePages[index]; + string webName = WebNames[WebNameIndices[index]..WebNameIndices[index + 1]]; // All supported code pages have identical header names, and body names. string headerName = webName; string bodyName = webName; string displayName = GetDisplayName(codePage, index); - uint flags = s_flags[index]; + uint flags = Flags[index]; return new CodePageDataItem(uiFamilyCodePage, webName, headerName, bodyName, displayName, flags); } @@ -239,7 +239,7 @@ private static string GetDisplayName(int codePage, int englishNameIndex) { string? displayName = SR.GetResourceString("Globalization_cp_" + codePage.ToString()); if (string.IsNullOrEmpty(displayName)) - displayName = s_englishNames[s_englishNameIndices[englishNameIndex]..s_englishNameIndices[englishNameIndex + 1]]; + displayName = EnglishNames[EnglishNameIndices[englishNameIndex]..EnglishNameIndices[englishNameIndex + 1]]; return displayName; } diff --git a/src/libraries/System.Private.CoreLib/src/System/TimeZoneInfo.Unix.cs b/src/libraries/System.Private.CoreLib/src/System/TimeZoneInfo.Unix.cs index 80159dca5af52..d759df64ad65a 100644 --- a/src/libraries/System.Private.CoreLib/src/System/TimeZoneInfo.Unix.cs +++ b/src/libraries/System.Private.CoreLib/src/System/TimeZoneInfo.Unix.cs @@ -912,7 +912,7 @@ private static void TZif_ParseJulianDay(ReadOnlySpan date, out int month, index++; } while ((uint)index < (uint)date.Length && char.IsAsciiDigit(date[index])); - int[] days = GregorianCalendarHelper.DaysToMonth365; + ReadOnlySpan days = GregorianCalendar.DaysToMonth365; if (julianDay == 0 || julianDay > days[days.Length - 1]) { diff --git a/src/libraries/System.Private.DataContractSerialization/src/System/Runtime/Serialization/Json/JsonGlobals.cs b/src/libraries/System.Private.DataContractSerialization/src/System/Runtime/Serialization/Json/JsonGlobals.cs index b4a99668d1357..34c6ea80c4772 100644 --- a/src/libraries/System.Private.DataContractSerialization/src/System/Runtime/Serialization/Json/JsonGlobals.cs +++ b/src/libraries/System.Private.DataContractSerialization/src/System/Runtime/Serialization/Json/JsonGlobals.cs @@ -24,7 +24,6 @@ internal static class JsonGlobals public static readonly UTF8Encoding ValidatingUTF8 = new UTF8Encoding(false, true); public const string PositiveInf = "INF"; public const string NegativeInf = "-INF"; - public static readonly char[] FloatingPointCharacters = new char[] { '.', 'e', 'E' }; public const string typeString = "type"; public const string nullString = "null"; public const string arrayString = "array"; diff --git a/src/libraries/System.Private.DataContractSerialization/src/System/Runtime/Serialization/Json/JsonObjectDataContract.cs b/src/libraries/System.Private.DataContractSerialization/src/System/Runtime/Serialization/Json/JsonObjectDataContract.cs index c6e4945072ef8..078c4c5179339 100644 --- a/src/libraries/System.Private.DataContractSerialization/src/System/Runtime/Serialization/Json/JsonObjectDataContract.cs +++ b/src/libraries/System.Private.DataContractSerialization/src/System/Runtime/Serialization/Json/JsonObjectDataContract.cs @@ -66,7 +66,7 @@ internal static object ParseJsonNumber(string value, out TypeCode objectTypeCode throw new XmlException(SR.Format(SR.XmlInvalidConversion, value, Globals.TypeOfInt)); } - if (value.IndexOfAny(JsonGlobals.FloatingPointCharacters) == -1) + if (value.AsSpan().IndexOfAny('.', 'e', 'E') < 0) { int intValue; if (int.TryParse(value, NumberStyles.Float, NumberFormatInfo.InvariantInfo, out intValue)) diff --git a/src/libraries/System.Private.DataContractSerialization/src/System/Runtime/Serialization/ObjectToIdCache.cs b/src/libraries/System.Private.DataContractSerialization/src/System/Runtime/Serialization/ObjectToIdCache.cs index b1cb4458d86b9..9bc1ae31a159a 100644 --- a/src/libraries/System.Private.DataContractSerialization/src/System/Runtime/Serialization/ObjectToIdCache.cs +++ b/src/libraries/System.Private.DataContractSerialization/src/System/Runtime/Serialization/ObjectToIdCache.cs @@ -161,24 +161,26 @@ private void Rehash() private static int GetPrime(int min) { - for (int i = 0; i < primes.Length; i++) + ReadOnlySpan primes = new int[] { - int prime = primes[i]; - if (prime >= min) return prime; + 3, 7, 17, 37, 89, 197, 431, 919, 1931, 4049, 8419, 17519, 36353, + 75431, 156437, 324449, 672827, 1395263, 2893249, 5999471, + 11998949, 23997907, 47995853, 95991737, 191983481, 383966977, 767933981, 1535867969, + 2146435069, 0x7FFFFFC7 + // 0x7FFFFFC7 == Array.MaxLength is not prime, but it is the largest possible array size. + // There's nowhere to go from here. Using a const rather than the MaxLength property + // so that the array contains only const values. + }; + + foreach (int prime in primes) + { + if (prime >= min) + { + return prime; + } } return min; } - - internal static readonly int[] primes = - { - 3, 7, 17, 37, 89, 197, 431, 919, 1931, 4049, 8419, 17519, 36353, - 75431, 156437, 324449, 672827, 1395263, 2893249, 5999471, - 11998949, 23997907, 47995853, 95991737, 191983481, 383966977, 767933981, 1535867969, - 2146435069, 0x7FFFFFC7 - // 0x7FFFFFC7 == Array.MaxLength is not prime, but it is the largest possible array size. - // There's nowhere to go from here. Using a const rather than the MaxLength property - // so that the array contains only const values. - }; } } diff --git a/src/libraries/System.Private.DataContractSerialization/src/System/Xml/UniqueId.cs b/src/libraries/System.Private.DataContractSerialization/src/System/Xml/UniqueId.cs index 4bc3d0702bd85..dbda45dc02d7a 100644 --- a/src/libraries/System.Private.DataContractSerialization/src/System/Xml/UniqueId.cs +++ b/src/libraries/System.Private.DataContractSerialization/src/System/Xml/UniqueId.cs @@ -13,7 +13,7 @@ public class UniqueId private const int guidLength = 16; private const int uuidLength = 45; - private static readonly short[] s_char2val = new short[256] + private static ReadOnlySpan Char2val => new short[256] { /* 0-15 */ 0x100, 0x100, 0x100, 0x100, 0x100, 0x100, 0x100, 0x100, 0x100, 0x100, 0x100, 0x100, 0x100, 0x100, 0x100, 0x100, @@ -162,7 +162,7 @@ private unsafe void UnsafeParse(char* chars, int charCount) int i = 0; int j = 0; - fixed (short* ps = &s_char2val[0]) + fixed (short* ps = &Char2val[0]) { short* _char2val = ps; diff --git a/src/libraries/System.Private.Uri/src/System/DomainNameHelper.cs b/src/libraries/System.Private.Uri/src/System/DomainNameHelper.cs index 6c93827e75fbb..a9c458c0e592a 100644 --- a/src/libraries/System.Private.Uri/src/System/DomainNameHelper.cs +++ b/src/libraries/System.Private.Uri/src/System/DomainNameHelper.cs @@ -389,11 +389,10 @@ private static bool IsValidDomainLabelCharacter(char character, ref bool notCano // This means that a host containing Unicode characters can be normalized to contain // URI reserved characters, changing the meaning of a URI only when certain properties // such as IdnHost are accessed. To be safe, disallow control characters in normalized hosts. - private static readonly char[] s_UnsafeForNormalizedHost = { '\\', '/', '?', '@', '#', ':', '[', ']' }; - internal static bool ContainsCharactersUnsafeForNormalizedHost(string host) { - return host.IndexOfAny(s_UnsafeForNormalizedHost) != -1; + ReadOnlySpan unsafeForNormalizedHost = new char[] { '\\', '/', '?', '@', '#', ':', '[', ']' }; + return host.AsSpan().IndexOfAny(unsafeForNormalizedHost) >= 0; } } } diff --git a/src/libraries/System.Private.Uri/src/System/Uri.cs b/src/libraries/System.Private.Uri/src/System/Uri.cs index de7eebd7d39bc..4ba5ab0c427f1 100644 --- a/src/libraries/System.Private.Uri/src/System/Uri.cs +++ b/src/libraries/System.Private.Uri/src/System/Uri.cs @@ -1806,16 +1806,13 @@ public Uri MakeRelativeUri(Uri uri) // // Returns true if a colon is found in the first path segment, false otherwise // - - // Check for anything that may terminate the first regular path segment - // or an illegal colon - private static readonly char[] s_pathDelims = { ':', '\\', '/', '?', '#' }; - private static bool CheckForColonInFirstPathSegment(string uriString) { - int index = uriString.IndexOfAny(s_pathDelims); - - return (index >= 0 && uriString[index] == ':'); + // Check for anything that may terminate the first regular path segment + // or an illegal colon + ReadOnlySpan PathDelims = new char[] { ':', '\\', '/', '?', '#' }; + int index = uriString.AsSpan().IndexOfAny(PathDelims); + return (uint)index < (uint)uriString.Length && uriString[index] == ':'; } internal static string InternalEscapeString(string rawString) => diff --git a/src/libraries/System.Private.Xml.Linq/src/System/Xml/Linq/XNodeReader.cs b/src/libraries/System.Private.Xml.Linq/src/System/Xml/Linq/XNodeReader.cs index 930dd7092a2f5..9fb478ae40413 100644 --- a/src/libraries/System.Private.Xml.Linq/src/System/Xml/Linq/XNodeReader.cs +++ b/src/libraries/System.Private.Xml.Linq/src/System/Xml/Linq/XNodeReader.cs @@ -7,8 +7,6 @@ namespace System.Xml.Linq { internal sealed class XNodeReader : XmlReader, IXmlLineInfo { - private static readonly char[] s_WhitespaceChars = new char[] { ' ', '\t', '\n', '\r' }; - // The reader position is encoded by the tuple (source, parent). // Lazy text uses (instance, parent element). Attribute value // uses (instance, parent attribute). End element uses (instance, @@ -430,7 +428,7 @@ public override XmlSpace XmlSpace XAttribute? a = e.Attribute(name); if (a != null) { - switch (a.Value.Trim(s_WhitespaceChars)) + switch (a.Value.AsSpan().Trim((ReadOnlySpan)new char[] { ' ', '\t', '\n', '\r' })) { case "preserve": return XmlSpace.Preserve; diff --git a/src/libraries/System.Private.Xml.Linq/src/System/Xml/XPath/XNodeNavigator.cs b/src/libraries/System.Private.Xml.Linq/src/System/Xml/XPath/XNodeNavigator.cs index ea7d1f28ddfa4..b6a6f83a75bb1 100644 --- a/src/libraries/System.Private.Xml.Linq/src/System/Xml/XPath/XNodeNavigator.cs +++ b/src/libraries/System.Private.Xml.Linq/src/System/Xml/XPath/XNodeNavigator.cs @@ -16,7 +16,7 @@ internal sealed class XNodeNavigator : XPathNavigator, IXmlLineInfo (1 << (int)XmlNodeType.Element) | (1 << (int)XmlNodeType.ProcessingInstruction) | (1 << (int)XmlNodeType.Comment); - private static readonly int[] s_ElementContentMasks = { + private static ReadOnlySpan ElementContentMasks => new int[] { 0, // Root (1 << (int)XmlNodeType.Element), // Element 0, // Attribute @@ -765,7 +765,7 @@ private static bool IsXmlNamespaceDeclaration(XAttribute a) private static int GetElementContentMask(XPathNodeType type) { - return s_ElementContentMasks[(int)type]; + return ElementContentMasks[(int)type]; } private static XAttribute? GetFirstNamespaceDeclarationGlobal(XElement e) diff --git a/src/libraries/System.Private.Xml/src/System/Xml/Schema/XsdBuilder.cs b/src/libraries/System.Private.Xml/src/System/Xml/Schema/XsdBuilder.cs index 7d148ecfabcc8..f237a4608c779 100644 --- a/src/libraries/System.Private.Xml/src/System/Xml/Schema/XsdBuilder.cs +++ b/src/libraries/System.Private.Xml/src/System/Xml/Schema/XsdBuilder.cs @@ -598,7 +598,7 @@ public BuilderNamespaceManager(XmlNamespaceManager nsMgr, XmlReader reader) // // for 'block' and 'final' attribute values // - private static readonly int[] s_derivationMethodValues = { + private static ReadOnlySpan DerivationMethodValues => new int[] { (int)XmlSchemaDerivationMethod.Substitution, (int)XmlSchemaDerivationMethod.Extension, (int)XmlSchemaDerivationMethod.Restriction, @@ -2525,12 +2525,12 @@ private int ParseBlockFinalEnum(string value, string attributeName) { if (stringValues[i] == s_derivationMethodStrings[j]) { - if ((r & s_derivationMethodValues[j]) != 0 && (r & s_derivationMethodValues[j]) != s_derivationMethodValues[j]) + if ((r & DerivationMethodValues[j]) != 0 && (r & DerivationMethodValues[j]) != DerivationMethodValues[j]) { SendValidationEvent(SR.Sch_InvalidXsdAttributeValue, attributeName, value, null); return 0; } - r |= s_derivationMethodValues[j]; + r |= DerivationMethodValues[j]; matched = true; break; } diff --git a/src/libraries/System.Private.Xml/src/System/Xml/Schema/XsdDateTime.cs b/src/libraries/System.Private.Xml/src/System/Xml/Schema/XsdDateTime.cs index 05adf65c48717..34f1b7cae8af7 100644 --- a/src/libraries/System.Private.Xml/src/System/Xml/Schema/XsdDateTime.cs +++ b/src/libraries/System.Private.Xml/src/System/Xml/Schema/XsdDateTime.cs @@ -81,8 +81,8 @@ private enum XsdDateTimeKind private const int ZoneHourShift = 8; // Maximum number of fraction digits; - private const short maxFractionDigits = 7; - private const int ticksToFractionDivisor = 10000000; + private const short MaxFractionDigits = 7; + private const int TicksToFractionDivisor = 10000000; private static readonly int s_lzyyyy = "yyyy".Length; private static readonly int s_lzyyyy_ = "yyyy-".Length; @@ -126,9 +126,9 @@ private enum XsdDateTimeKind // Number of days in 400 years private const int DaysPer400Years = DaysPer100Years * 4 + 1; // 146097 - private static readonly int[] DaysToMonth365 = { + private static ReadOnlySpan DaysToMonth365 => new int[] { 0, 31, 59, 90, 120, 151, 181, 212, 243, 273, 304, 334, 365}; - private static readonly int[] DaysToMonth366 = { + private static ReadOnlySpan DaysToMonth366 => new int[] { 0, 31, 60, 91, 121, 152, 182, 213, 244, 274, 305, 335, 366}; /// @@ -328,7 +328,7 @@ public int Second /// public int Fraction { - get { return (int)(_dt.Ticks % ticksToFractionDivisor); } + get { return (int)(_dt.Ticks % TicksToFractionDivisor); } } /// @@ -591,7 +591,7 @@ private void GetYearMonthDay(out int year, out int month, out int day) // Leap year calculation looks different from IsLeapYear since y1, y4, // and y100 are relative to year 1, not year 0 bool leapYear = y1 == 3 && (y4 != 24 || y100 == 3); - int[] days = leapYear ? DaysToMonth366 : DaysToMonth365; + ReadOnlySpan days = leapYear ? DaysToMonth366 : DaysToMonth365; // All months have less than 32 days, so n >> 5 is a good conservative // estimate for the month month = (n >> 5) + 1; @@ -614,7 +614,7 @@ private void PrintTime(ref ValueStringBuilder vsb) int fraction = Fraction; if (fraction != 0) { - int fractionDigits = maxFractionDigits; + int fractionDigits = MaxFractionDigits; while (fraction % 10 == 0) { fractionDigits--; @@ -909,7 +909,7 @@ private bool ParseTimeAndWhitespace(int start) return false; } - private static readonly int[] s_power10 = new int[maxFractionDigits] { -1, 10, 100, 1000, 10000, 100000, 1000000 }; + private static ReadOnlySpan Power10 => new int[MaxFractionDigits] { -1, 10, 100, 1000, 10000, 100000, 1000000 }; private bool ParseTime(ref int start) { if ( @@ -935,11 +935,11 @@ private bool ParseTime(ref int start) { // d < 0 || 9 < d break; } - if (fractionDigits < maxFractionDigits) + if (fractionDigits < MaxFractionDigits) { this.fraction = (this.fraction * 10) + d; } - else if (fractionDigits == maxFractionDigits) + else if (fractionDigits == MaxFractionDigits) { if (5 < d) { @@ -956,13 +956,13 @@ private bool ParseTime(ref int start) } fractionDigits++; } - if (fractionDigits < maxFractionDigits) + if (fractionDigits < MaxFractionDigits) { if (fractionDigits == 0) { return false; // cannot end with . } - fraction *= s_power10[maxFractionDigits - fractionDigits]; + fraction *= Power10[MaxFractionDigits - fractionDigits]; } else { diff --git a/src/libraries/System.Private.Xml/src/System/Xml/XPath/XPathNavigator.cs b/src/libraries/System.Private.Xml/src/System/Xml/XPath/XPathNavigator.cs index b0cac8d88790e..19d6fc794be5b 100644 --- a/src/libraries/System.Private.Xml/src/System/Xml/XPath/XPathNavigator.cs +++ b/src/libraries/System.Private.Xml/src/System/Xml/XPath/XPathNavigator.cs @@ -1730,7 +1730,7 @@ internal uint IndexInParent } } - internal static readonly char[] NodeTypeLetter = new char[] { + internal static ReadOnlySpan NodeTypeLetter => new char[] { 'R', // Root 'E', // Element 'A', // Attribute @@ -1743,7 +1743,7 @@ internal uint IndexInParent 'X', // All }; - internal static readonly char[] UniqueIdTbl = new char[] { + internal static ReadOnlySpan UniqueIdTbl => new char[] { 'A', 'B', 'C', 'D', 'E', 'F', 'G', 'H', 'I', 'J', 'K', 'L', 'M', 'N', 'O', 'P', 'Q', 'R', 'S', 'T', 'U', 'V', 'W', 'X', 'Y', 'Z', '1', '2', '3', '4', @@ -1776,14 +1776,14 @@ internal virtual string UniqueId } if (idx <= 0x1f) { - sb.Append(UniqueIdTbl[idx]); + sb.Append(UniqueIdTbl[(int)idx]); } else { sb.Append('0'); do { - sb.Append(UniqueIdTbl[idx & 0x1f]); + sb.Append(UniqueIdTbl[(int)(idx & 0x1f)]); idx >>= 5; } while (idx != 0); sb.Append('0'); @@ -1900,7 +1900,7 @@ internal static XmlNamespaceManager GetNamespaces(IXmlNamespaceResolver resolver internal const int AllMask = 0x7FFFFFFF; internal const int NoAttrNmspMask = AllMask & ~(1 << (int)XPathNodeType.Attribute) & ~(1 << (int)XPathNodeType.Namespace); internal const int TextMask = (1 << (int)XPathNodeType.Text) | (1 << (int)XPathNodeType.SignificantWhitespace) | (1 << (int)XPathNodeType.Whitespace); - internal static readonly int[] ContentKindMasks = { + internal static ReadOnlySpan ContentKindMasks => new int[] { (1 << (int) XPathNodeType.Root), // Root (1 << (int) XPathNodeType.Element), // Element 0, // Attribute (not content) diff --git a/src/libraries/System.Private.Xml/src/System/Xml/Xsl/Runtime/NumberFormatter.cs b/src/libraries/System.Private.Xml/src/System/Xml/Xsl/Runtime/NumberFormatter.cs index d749d8ec9feac..8079d606ffe69 100644 --- a/src/libraries/System.Private.Xml/src/System/Xml/Xsl/Runtime/NumberFormatter.cs +++ b/src/libraries/System.Private.Xml/src/System/Xml/Xsl/Runtime/NumberFormatter.cs @@ -99,9 +99,6 @@ public static void ConvertToAlphabetic(StringBuilder sb, double val, char firstC private const string RomanDigitsUC = "IIVIXXLXCCDCM"; private const string RomanDigitsLC = "iivixxlxccdcm"; - // RomanDigit = { I IV V IX X XL L XC C CD D CM M } - private static readonly int[] s_romanDigitValue = { 1, 4, 5, 9, 10, 40, 50, 90, 100, 400, 500, 900, 1000 }; - public static void ConvertToRoman(StringBuilder sb, double val, bool upperCase) { Debug.Assert(1 <= val && val <= MaxRomanValue); @@ -109,11 +106,14 @@ public static void ConvertToRoman(StringBuilder sb, double val, bool upperCase) int number = (int)val; string digits = upperCase ? RomanDigitsUC : RomanDigitsLC; - for (int idx = s_romanDigitValue.Length; idx-- != 0;) + // RomanDigit = { I IV V IX X XL L XC C CD D CM M } + ReadOnlySpan RomanDigitValue = new int[] { 1, 4, 5, 9, 10, 40, 50, 90, 100, 400, 500, 900, 1000 }; + + for (int idx = RomanDigitValue.Length; idx-- != 0;) { - while (number >= s_romanDigitValue[idx]) + while (number >= RomanDigitValue[idx]) { - number -= s_romanDigitValue[idx]; + number -= RomanDigitValue[idx]; sb.Append(digits, idx, 1 + (idx & 1)); } } diff --git a/src/libraries/System.Private.Xml/src/System/Xml/Xsl/XPathConvert.cs b/src/libraries/System.Private.Xml/src/System/Xml/Xsl/XPathConvert.cs index abce1eebfb2bf..b7fa436504725 100644 --- a/src/libraries/System.Private.Xml/src/System/Xml/Xsl/XPathConvert.cs +++ b/src/libraries/System.Private.Xml/src/System/Xml/Xsl/XPathConvert.cs @@ -89,7 +89,7 @@ public static double Pred(double x) // Small powers of ten. These are all the powers of ten that have an exact // representation in IEEE double precision format. - public static readonly double[] C10toN = { + public static ReadOnlySpan C10toN => new double[] { 1e00, 1e01, 1e02, 1e03, 1e04, 1e05, 1e06, 1e07, 1e08, 1e09, 1e10, 1e11, 1e12, 1e13, 1e14, 1e15, 1e16, 1e17, 1e18, 1e19, 1e20, 1e21, 1e22, diff --git a/src/libraries/System.Runtime.Numerics/src/System/Numerics/BigNumber.cs b/src/libraries/System.Runtime.Numerics/src/System/Numerics/BigNumber.cs index 51643f6b4e4df..d834253d30352 100644 --- a/src/libraries/System.Runtime.Numerics/src/System/Numerics/BigNumber.cs +++ b/src/libraries/System.Runtime.Numerics/src/System/Numerics/BigNumber.cs @@ -287,7 +287,7 @@ internal static class BigNumber | NumberStyles.AllowThousands | NumberStyles.AllowExponent | NumberStyles.AllowCurrencySymbol | NumberStyles.AllowHexSpecifier); - private static readonly uint[] s_uint32PowersOfTen = { 1, 10, 100, 1000, 10000, 100000, 1000000, 10000000, 100000000, 1000000000 }; + private static ReadOnlySpan UInt32PowersOfTen => new uint[] { 1, 10, 100, 1000, 10000, 100000, 1000000, 10000000, 100000000, 1000000000 }; private struct BigNumberBuffer { @@ -553,7 +553,7 @@ bool Naive(ref BigNumberBuffer number, out BigInteger result) if (partialDigitCount > 0) { - MultiplyAdd(ref currentBuffer, s_uint32PowersOfTen[partialDigitCount], partialValue); + MultiplyAdd(ref currentBuffer, UInt32PowersOfTen[partialDigitCount], partialValue); } result = NumberBufferToBigInteger(currentBuffer, number.sign); @@ -791,7 +791,7 @@ BigInteger NumberBufferToBigInteger(Span currentBuffer, bool signa) if (trailingZeroCount > 0) { - MultiplyAdd(ref currentBuffer, s_uint32PowersOfTen[trailingZeroCount], 0); + MultiplyAdd(ref currentBuffer, UInt32PowersOfTen[trailingZeroCount], 0); } int sign; diff --git a/src/libraries/System.Security.Cryptography/src/System/Security/Cryptography/SHAHashProvider.Browser.Managed.cs b/src/libraries/System.Security.Cryptography/src/System/Security/Cryptography/SHAHashProvider.Browser.Managed.cs index cfa39e599f7d5..ca61f24b0f7f6 100644 --- a/src/libraries/System.Security.Cryptography/src/System/Security/Cryptography/SHAHashProvider.Browser.Managed.cs +++ b/src/libraries/System.Security.Cryptography/src/System/Security/Cryptography/SHAHashProvider.Browser.Managed.cs @@ -244,7 +244,7 @@ public override byte[] HashFinal() return hash; } - private static readonly uint[] _K = { + private static ReadOnlySpan _K => new uint[] { 0x428a2f98, 0x71374491, 0xb5c0fbcf, 0xe9b5dba5, 0x3956c25b, 0x59f111f1, 0x923f82a4, 0xab1c5ed5, 0xd807aa98, 0x12835b01, 0x243185be, 0x550c7dc3, @@ -522,7 +522,7 @@ public override byte[] HashFinal() return hash; } - private static readonly ulong[] _K = { + private static ReadOnlySpan _K => new ulong[] { 0x428a2f98d728ae22, 0x7137449123ef65cd, 0xb5c0fbcfec4d3b2f, 0xe9b5dba58189dbbc, 0x3956c25bf348b538, 0x59f111f1b605d019, 0x923f82a4af194f9b, 0xab1c5ed5da6d8118, 0xd807aa98a3030242, 0x12835b0145706fbe, 0x243185be4ee4b28c, 0x550c7dc3d5ffb4e2, @@ -810,7 +810,7 @@ public override byte[] HashFinal() return hash; } - private static readonly ulong[] _K = { + private static ReadOnlySpan _K => new ulong[] { 0x428a2f98d728ae22, 0x7137449123ef65cd, 0xb5c0fbcfec4d3b2f, 0xe9b5dba58189dbbc, 0x3956c25bf348b538, 0x59f111f1b605d019, 0x923f82a4af194f9b, 0xab1c5ed5da6d8118, 0xd807aa98a3030242, 0x12835b0145706fbe, 0x243185be4ee4b28c, 0x550c7dc3d5ffb4e2, diff --git a/src/libraries/System.Security.Cryptography/src/System/Security/Cryptography/X509Certificates/X500NameEncoder.cs b/src/libraries/System.Security.Cryptography/src/System/Security/Cryptography/X509Certificates/X500NameEncoder.cs index 7b90d14424e38..c8176a7947f21 100644 --- a/src/libraries/System.Security.Cryptography/src/System/Security/Cryptography/X509Certificates/X500NameEncoder.cs +++ b/src/libraries/System.Security.Cryptography/src/System/Security/Cryptography/X509Certificates/X500NameEncoder.cs @@ -12,7 +12,7 @@ internal static partial class X500NameEncoder { private const string OidTagPrefix = "OID."; - private static readonly char[] s_quoteNeedingChars = + private static ReadOnlySpan QuoteNeedingChars => new char[] { ',', '+', @@ -131,22 +131,18 @@ internal static byte[] X500DistinguishedNameEncode( return writer.Encode(); } - private static bool NeedsQuoting(string rdnValue) + private static bool NeedsQuoting(ReadOnlySpan rdnValue) { - if (string.IsNullOrEmpty(rdnValue)) + if (rdnValue.IsEmpty || + IsQuotableWhitespace(rdnValue[0]) || + IsQuotableWhitespace(rdnValue[^1])) { return true; } - if (IsQuotableWhitespace(rdnValue[0]) || - IsQuotableWhitespace(rdnValue[rdnValue.Length - 1])) - { - return true; - } - - int index = rdnValue.IndexOfAny(s_quoteNeedingChars); + int index = rdnValue.IndexOfAny(QuoteNeedingChars); - return index != -1; + return index >= 0; } private static bool IsQuotableWhitespace(char c) diff --git a/src/libraries/System.Text.RegularExpressions/src/System/Text/RegularExpressions/RegexCaseEquivalences.Data.cs b/src/libraries/System.Text.RegularExpressions/src/System/Text/RegularExpressions/RegexCaseEquivalences.Data.cs index 888d23f524a52..8d1bf2bb443cb 100644 --- a/src/libraries/System.Text.RegularExpressions/src/System/Text/RegularExpressions/RegexCaseEquivalences.Data.cs +++ b/src/libraries/System.Text.RegularExpressions/src/System/Text/RegularExpressions/RegexCaseEquivalences.Data.cs @@ -9,7 +9,12 @@ internal static partial class RegexCaseEquivalences // PLEASE DON'T MODIFY BY HAND // IF YOU NEED TO UPDATE UNICODE VERSION FOLLOW THE GUIDE AT src/libraries/System.Private.CoreLib/Tools/GenUnicodeProp/Updating-Unicode-Versions.md - private static char[] EquivalenceCasingValues { get; } = new char[2336] +#if REGEXGENERATOR + private static ReadOnlySpan EquivalenceCasingValues => s_equivalentCasingValues; + private static readonly char[] s_equivalentCasingValues = new char[2336] +#else + private static ReadOnlySpan EquivalenceCasingValues => new char[2336] +#endif { '\u0041', '\u0061', '\u0042', '\u0062', '\u0043', '\u0063', '\u0044', '\u0064', '\u0045', '\u0065', '\u0046', '\u0066', '\u0047', '\u0067', '\u0048', '\u0068', '\u0049', '\u0069', '\u004A', '\u006A', '\u004B', '\u006B', '\u212A', '\u004C', '\u006C', '\u004D', '\u006D', '\u004E', '\u006E', '\u004F', '\u006F', '\u0050', @@ -159,7 +164,12 @@ internal static partial class RegexCaseEquivalences '\uFF33', '\uFF53', '\uFF34', '\uFF54', '\uFF35', '\uFF55', '\uFF36', '\uFF56', '\uFF37', '\uFF57', '\uFF38', '\uFF58', '\uFF39', '\uFF59', '\uFF3A', '\uFF5A' }; - private static ushort[] EquivalenceFirstLevelLookup { get; } = new ushort[64] +#if REGEXGENERATOR + private static ReadOnlySpan EquivalenceFirstLevelLookup => s_equivalenceFirstLevelLookup; + private static readonly ushort[] s_equivalenceFirstLevelLookup = new ushort[64] +#else + private static ReadOnlySpan EquivalenceFirstLevelLookup => new ushort[64] +#endif { 0x0000, 0x0400, 0xffff, 0xffff, 0x0800, 0xffff, 0xffff, 0x0c00, 0x1000, 0x1400, 0xffff, 0x1800, 0xffff, 0xffff, 0xffff, 0xffff, 0xffff, 0xffff, 0xffff, 0xffff, 0xffff, 0xffff, 0xffff, 0xffff, 0xffff, 0xffff, 0xffff, 0xffff, 0xffff, 0xffff, 0xffff, 0xffff, @@ -167,7 +177,12 @@ internal static partial class RegexCaseEquivalences 0xffff, 0xffff, 0xffff, 0xffff, 0xffff, 0xffff, 0xffff, 0xffff, 0xffff, 0xffff, 0xffff, 0xffff, 0xffff, 0xffff, 0xffff, 0x2400 }; - private static ushort[] EquivalenceCasingMap { get; } = new ushort[10240] +#if REGEXGENERATOR + private static ReadOnlySpan EquivalenceCasingMap => s_equivalenceCasingMap; + private static readonly ushort[] s_equivalenceCasingMap = new ushort[10240] +#else + private static ReadOnlySpan EquivalenceCasingMap => new ushort[10240] +#endif { 0xffff, 0xffff, 0xffff, 0xffff, 0xffff, 0xffff, 0xffff, 0xffff, 0xffff, 0xffff, 0xffff, 0xffff, 0xffff, 0xffff, 0xffff, 0xffff, 0xffff, 0xffff, 0xffff, 0xffff, 0xffff, 0xffff, 0xffff, 0xffff, 0xffff, 0xffff, 0xffff, 0xffff, 0xffff, 0xffff, 0xffff, 0xffff, diff --git a/src/libraries/System.Text.RegularExpressions/src/System/Text/RegularExpressions/RegexCaseEquivalences.cs b/src/libraries/System.Text.RegularExpressions/src/System/Text/RegularExpressions/RegexCaseEquivalences.cs index 7c65c63e90dfb..e6e9bf011f05c 100644 --- a/src/libraries/System.Text.RegularExpressions/src/System/Text/RegularExpressions/RegexCaseEquivalences.cs +++ b/src/libraries/System.Text.RegularExpressions/src/System/Text/RegularExpressions/RegexCaseEquivalences.cs @@ -16,7 +16,12 @@ internal static partial class RegexCaseEquivalences { public const int CharactersPerRange = 1024; +#if REGEXGENERATOR + private static ReadOnlySpan SpecialCasingSetBehaviors => s_specialCasingSetBehaviors; private static readonly char[] s_specialCasingSetBehaviors = new char[5] +#else + private static ReadOnlySpan SpecialCasingSetBehaviors => new char[5] +#endif { 'I', 'i', '\u0130', 'I', '\u0131' }; @@ -45,14 +50,14 @@ public static bool TryFindCaseEquivalencesForCharWithIBehavior(char c, CultureIn equivalences = c switch { // Invariant mappings - 'i' or 'I' when mappingBehavior is RegexCaseBehavior.Invariant => s_specialCasingSetBehaviors.AsSpan(0, 2), // 'I' and 'i' + 'i' or 'I' when mappingBehavior is RegexCaseBehavior.Invariant => SpecialCasingSetBehaviors.Slice(0, 2), // 'I' and 'i' // Non-Turkish mappings - 'i' or 'I' or '\u0130' when mappingBehavior is RegexCaseBehavior.NonTurkish => s_specialCasingSetBehaviors.AsSpan(0, 3), // 'I', 'i', and '\u0130' + 'i' or 'I' or '\u0130' when mappingBehavior is RegexCaseBehavior.NonTurkish => SpecialCasingSetBehaviors.Slice(0, 3), // 'I', 'i', and '\u0130' // Turkish mappings - 'I' or '\u0131' when mappingBehavior is RegexCaseBehavior.Turkish => s_specialCasingSetBehaviors.AsSpan(3, 2), // 'I' and '\u0131' - 'i' or '\u0130' when mappingBehavior is RegexCaseBehavior.Turkish => s_specialCasingSetBehaviors.AsSpan(1, 2), // 'i' and '\u0130' + 'I' or '\u0131' when mappingBehavior is RegexCaseBehavior.Turkish => SpecialCasingSetBehaviors.Slice(3, 2), // 'I' and '\u0131' + 'i' or '\u0130' when mappingBehavior is RegexCaseBehavior.Turkish => SpecialCasingSetBehaviors.Slice(1, 2), // 'i' and '\u0130' // Default _ => default @@ -158,7 +163,7 @@ private static bool TryFindCaseEquivalencesForChar(char c, out ReadOnlySpan> 13) & 0b111); ushort index3 = (ushort)(mappingValue & 0x1FFF); - equivalences = EquivalenceCasingValues.AsSpan(index3, count); + equivalences = EquivalenceCasingValues.Slice(index3, count); return true; } diff --git a/src/libraries/System.Text.RegularExpressions/tools/DataTable.cs b/src/libraries/System.Text.RegularExpressions/tools/DataTable.cs index 7185e4a62e7e6..d5ec2b5448da8 100644 --- a/src/libraries/System.Text.RegularExpressions/tools/DataTable.cs +++ b/src/libraries/System.Text.RegularExpressions/tools/DataTable.cs @@ -110,8 +110,15 @@ void EmitFileHeadersAndUsings(StreamWriter writer) void EmitFirstLevelLookupTable(StreamWriter writer) { - var firstLevelLookupTable = FlattenFirstLevelLookupTable(); - writer.Write(" private static ushort[] EquivalenceFirstLevelLookup { get; } = new ushort[" + firstLevelLookupTable.Count + "]\n {\n"); + List firstLevelLookupTable = FlattenFirstLevelLookupTable(); + + writer.Write($"#if REGEXGENERATOR"); + writer.Write($" private static ReadOnlySpan EquivalenceFirstLevelLookup => s_equivalenceFirstLevelLookup;"); + writer.Write($" private static readonly ushort[] s_equivalenceFirstLevelLookup = new ushort[{firstLevelLookupTable.Count}]"); + writer.Write($"#else"); + writer.Write($" private static ReadOnlySpan EquivalenceFirstLevelLookup => new ushort[{firstLevelLookupTable.Count}]"); + writer.Write($"#endif"); + writer.Write(" {"); writer.Write(" 0x{0:x4}", firstLevelLookupTable[0]); for (var i = 1; i < firstLevelLookupTable.Count; i++) @@ -146,8 +153,15 @@ List FlattenFirstLevelLookupTable() void EmitMapArray(StreamWriter writer) { - var flattenedMap = FlattenMapDictionary(); - writer.Write(" private static ushort[] EquivalenceCasingMap { get; } = new ushort[" + flattenedMap.Count + "]\n {\n"); + List flattenedMap = FlattenMapDictionary(); + + writer.Write($"#if REGEXGENERATOR"); + writer.Write($" private static ReadOnlySpan EquivalenceCasingMap => s_equivalenceCasingMap;"); + writer.Write($" private static readonly ushort[] s_equivalenceCasingMap = new ushort[{flattenedMap.Count}]"); + writer.Write($"#else"); + writer.Write($" private static ReadOnlySpan EquivalenceCasingMap => new ushort[{flattenedMap.Count}]"); + writer.Write($"#endif"); + writer.Write(" {"); writer.Write(" 0x{0:x4}", flattenedMap[0]); for (var i = 1; i < flattenedMap.Count; i++) @@ -189,8 +203,17 @@ List FlattenMapDictionary() void EmitValuesArray(StreamWriter writer) { - var flattenedValues = FlattenValuesDictionary(); - writer.Write(" private static char[] EquivalenceCasingValues { get; } = new char[" + flattenedValues.Count + "]\n {\n"); + List flattenedValues = FlattenValuesDictionary(); + + writer.Write($"#if REGEXGENERATOR"); + writer.Write($" private static ReadOnlySpan EquivalenceCasingValues => s_equivalenceCasingValues;"); + writer.Write($" private static readonly char[] s_equivalenceCasingValues = new char[{flattenedValues.Count}]"); + writer.Write($"#else"); + writer.Write($" private static ReadOnlySpan EquivalenceCasingValues => new char[{flattenedValues.Count}]"); + writer.Write($"#endif"); + writer.Write(" {"); + + writer.Write(" private static ReadOnlySpan EquivalenceCasingValues => new char[" + flattenedValues.Count + "]\n {\n"); writer.Write(" \'\\u{0:X4}\'", flattenedValues[0]); for (var i = 1; i < flattenedValues.Count; i++)