From 38cf93013c1dd1efc7137a6f4930cab7cc653411 Mon Sep 17 00:00:00 2001 From: Jan Kotas Date: Thu, 18 Jan 2018 18:57:14 -0800 Subject: [PATCH] Cache Invariant CompareInfo (#15902) The Invariant CompareInfo is used in number of places. It is fetched via virtual method on CultureInfo. Caching it avoids the virtual method calls and extra indirections. --- .../shared/System/Globalization/CompareInfo.cs | 3 +++ .../System/Globalization/DateTimeFormatInfo.cs | 2 +- .../shared/System/Globalization/TextInfo.cs | 22 -------------------- src/mscorlib/shared/System/String.Searching.cs | 24 +++++++++++----------- .../src/System/Globalization/CultureInfo.cs | 15 +++++--------- .../Resources/ManifestBasedResourceGroveler.cs | 3 +-- src/mscorlib/src/System/String.Comparison.cs | 24 +++++++++++----------- 7 files changed, 34 insertions(+), 59 deletions(-) diff --git a/src/mscorlib/shared/System/Globalization/CompareInfo.cs b/src/mscorlib/shared/System/Globalization/CompareInfo.cs index e088a82..aa7e908 100644 --- a/src/mscorlib/shared/System/Globalization/CompareInfo.cs +++ b/src/mscorlib/shared/System/Globalization/CompareInfo.cs @@ -57,6 +57,9 @@ namespace System.Globalization ~(CompareOptions.IgnoreCase | CompareOptions.IgnoreSymbols | CompareOptions.IgnoreNonSpace | CompareOptions.IgnoreWidth | CompareOptions.IgnoreKanaType | CompareOptions.StringSort); + // Cache the invariant CompareInfo + internal static readonly CompareInfo Invariant = CultureInfo.InvariantCulture.CompareInfo; + // // CompareInfos have an interesting identity. They are attached to the locale that created them, // ie: en-US would have an en-US sort. For haw-US (custom), then we serialize it as haw-US. diff --git a/src/mscorlib/shared/System/Globalization/DateTimeFormatInfo.cs b/src/mscorlib/shared/System/Globalization/DateTimeFormatInfo.cs index b6a4621..c8f5ee4 100644 --- a/src/mscorlib/shared/System/Globalization/DateTimeFormatInfo.cs +++ b/src/mscorlib/shared/System/Globalization/DateTimeFormatInfo.cs @@ -593,7 +593,7 @@ namespace System.Globalization { // this comparison should use the InvariantCulture. The English name could have linguistically // interesting characters. - if (CultureInfo.InvariantCulture.CompareInfo.Compare(eraName, m_abbrevEnglishEraNames[i], CompareOptions.IgnoreCase) == 0) + if (CompareInfo.Invariant.Compare(eraName, m_abbrevEnglishEraNames[i], CompareOptions.IgnoreCase) == 0) { return (i + 1); } diff --git a/src/mscorlib/shared/System/Globalization/TextInfo.cs b/src/mscorlib/shared/System/Globalization/TextInfo.cs index 59a3188..d9d6f3b 100644 --- a/src/mscorlib/shared/System/Globalization/TextInfo.cs +++ b/src/mscorlib/shared/System/Globalization/TextInfo.cs @@ -91,28 +91,6 @@ namespace System.Globalization return Invariant.GetCaseInsensitiveHashCode(s); } - // Currently we don't have native functions to do this, so we do it the hard way - internal static int IndexOfStringOrdinalIgnoreCase(string source, string value, int startIndex, int count) - { - if (count > source.Length || count < 0 || startIndex < 0 || startIndex > source.Length - count) - { - return -1; - } - - return CultureInfo.InvariantCulture.CompareInfo.IndexOfOrdinal(source, value, startIndex, count, ignoreCase: true); - } - - // Currently we don't have native functions to do this, so we do it the hard way - internal static int LastIndexOfStringOrdinalIgnoreCase(string source, string value, int startIndex, int count) - { - if (count > source.Length || count < 0 || startIndex < 0 || startIndex > source.Length - 1 || (startIndex - count + 1 < 0)) - { - return -1; - } - - return CultureInfo.InvariantCulture.CompareInfo.LastIndexOfOrdinal(source, value, startIndex, count, ignoreCase: true); - } - public virtual int ANSICodePage => _cultureData.IDEFAULTANSICODEPAGE; public virtual int OEMCodePage => _cultureData.IDEFAULTOEMCODEPAGE; diff --git a/src/mscorlib/shared/System/String.Searching.cs b/src/mscorlib/shared/System/String.Searching.cs index 5aa002b..b0ba92b 100644 --- a/src/mscorlib/shared/System/String.Searching.cs +++ b/src/mscorlib/shared/System/String.Searching.cs @@ -53,16 +53,16 @@ namespace System return CultureInfo.CurrentCulture.CompareInfo.IndexOf(this, value, CompareOptions.IgnoreCase); case StringComparison.InvariantCulture: - return CultureInfo.InvariantCulture.CompareInfo.IndexOf(this, value, CompareOptions.None); + return CompareInfo.Invariant.IndexOf(this, value, CompareOptions.None); case StringComparison.InvariantCultureIgnoreCase: - return CultureInfo.InvariantCulture.CompareInfo.IndexOf(this, value, CompareOptions.IgnoreCase); + return CompareInfo.Invariant.IndexOf(this, value, CompareOptions.IgnoreCase); case StringComparison.Ordinal: - return CultureInfo.InvariantCulture.CompareInfo.IndexOf(this, value, CompareOptions.Ordinal); + return CompareInfo.Invariant.IndexOf(this, value, CompareOptions.Ordinal); case StringComparison.OrdinalIgnoreCase: - return CultureInfo.InvariantCulture.CompareInfo.IndexOf(this, value, CompareOptions.OrdinalIgnoreCase); + return CompareInfo.Invariant.IndexOf(this, value, CompareOptions.OrdinalIgnoreCase); default: throw new ArgumentException(SR.NotSupported_StringComparison, nameof(comparisonType)); @@ -361,16 +361,16 @@ namespace System return CultureInfo.CurrentCulture.CompareInfo.IndexOf(this, value, startIndex, count, CompareOptions.IgnoreCase); case StringComparison.InvariantCulture: - return CultureInfo.InvariantCulture.CompareInfo.IndexOf(this, value, startIndex, count, CompareOptions.None); + return CompareInfo.Invariant.IndexOf(this, value, startIndex, count, CompareOptions.None); case StringComparison.InvariantCultureIgnoreCase: - return CultureInfo.InvariantCulture.CompareInfo.IndexOf(this, value, startIndex, count, CompareOptions.IgnoreCase); + return CompareInfo.Invariant.IndexOf(this, value, startIndex, count, CompareOptions.IgnoreCase); case StringComparison.Ordinal: - return CultureInfo.InvariantCulture.CompareInfo.IndexOf(this, value, startIndex, count, CompareOptions.Ordinal); + return CompareInfo.Invariant.IndexOfOrdinal(this, value, startIndex, count, ignoreCase: false); case StringComparison.OrdinalIgnoreCase: - return TextInfo.IndexOfStringOrdinalIgnoreCase(this, value, startIndex, count); + return CompareInfo.Invariant.IndexOfOrdinal(this, value, startIndex, count, ignoreCase: true); default: throw new ArgumentException(SR.NotSupported_StringComparison, nameof(comparisonType)); @@ -589,16 +589,16 @@ namespace System return CultureInfo.CurrentCulture.CompareInfo.LastIndexOf(this, value, startIndex, count, CompareOptions.IgnoreCase); case StringComparison.InvariantCulture: - return CultureInfo.InvariantCulture.CompareInfo.LastIndexOf(this, value, startIndex, count, CompareOptions.None); + return CompareInfo.Invariant.LastIndexOf(this, value, startIndex, count, CompareOptions.None); case StringComparison.InvariantCultureIgnoreCase: - return CultureInfo.InvariantCulture.CompareInfo.LastIndexOf(this, value, startIndex, count, CompareOptions.IgnoreCase); + return CompareInfo.Invariant.LastIndexOf(this, value, startIndex, count, CompareOptions.IgnoreCase); case StringComparison.Ordinal: - return CultureInfo.InvariantCulture.CompareInfo.LastIndexOf(this, value, startIndex, count, CompareOptions.Ordinal); + return CompareInfo.Invariant.LastIndexOfOrdinal(this, value, startIndex, count, ignoreCase: false); case StringComparison.OrdinalIgnoreCase: - return TextInfo.LastIndexOfStringOrdinalIgnoreCase(this, value, startIndex, count); + return CompareInfo.Invariant.LastIndexOfOrdinal(this, value, startIndex, count, ignoreCase: true); default: throw new ArgumentException(SR.NotSupported_StringComparison, nameof(comparisonType)); diff --git a/src/mscorlib/src/System/Globalization/CultureInfo.cs b/src/mscorlib/src/System/Globalization/CultureInfo.cs index bb6e8f9..2c93277 100644 --- a/src/mscorlib/src/System/Globalization/CultureInfo.cs +++ b/src/mscorlib/src/System/Globalization/CultureInfo.cs @@ -113,7 +113,7 @@ namespace System.Globalization // Get in touch with the diagnostics team if you have questions. //The Invariant culture; - private static volatile CultureInfo s_InvariantCultureInfo; + private static readonly CultureInfo s_InvariantCultureInfo = new CultureInfo(CultureData.Invariant, isReadOnly: true); //These are defaults that we use if a thread has not opted into having an explicit culture private static volatile CultureInfo s_DefaultThreadCurrentUICulture; @@ -156,13 +156,6 @@ namespace System.Globalization private static readonly bool init = Init(); private static bool Init() { - if (s_InvariantCultureInfo == null) - { - CultureInfo temp = new CultureInfo("", false); - temp._isReadOnly = true; - s_InvariantCultureInfo = temp; - } - s_userDefaultCulture = GetUserDefaultCulture(); s_userDefaultUICulture = GetUserDefaultUILanguage(); return true; @@ -192,12 +185,13 @@ namespace System.Globalization InitializeFromName(name, useUserOverride); } - private CultureInfo(CultureData cultureData) + private CultureInfo(CultureData cultureData, bool isReadOnly = false) { Debug.Assert(cultureData != null); _cultureData = cultureData; _name = cultureData.CultureName; _isInherited = false; + _isReadOnly = isReadOnly; } private static CultureInfo CreateCultureInfoNoThrow(string name, bool useUserOverride) @@ -508,6 +502,7 @@ namespace System.Globalization { get { + Debug.Assert(s_InvariantCultureInfo != null); return (s_InvariantCultureInfo); } } @@ -1055,7 +1050,7 @@ namespace System.Globalization if (temp == null) { temp = CreateSpecificCulture(_cultureData.SCONSOLEFALLBACKNAME); - _isReadOnly = true; + temp._isReadOnly = true; _consoleFallbackCulture = temp; } return (temp); diff --git a/src/mscorlib/src/System/Resources/ManifestBasedResourceGroveler.cs b/src/mscorlib/src/System/Resources/ManifestBasedResourceGroveler.cs index 0986616..6f3d064 100644 --- a/src/mscorlib/src/System/Resources/ManifestBasedResourceGroveler.cs +++ b/src/mscorlib/src/System/Resources/ManifestBasedResourceGroveler.cs @@ -357,11 +357,10 @@ namespace System.Resources sb.Append(name); String givenName = sb.ToString(); - CompareInfo comparer = CultureInfo.InvariantCulture.CompareInfo; String canonicalName = null; foreach (String existingName in satellite.GetManifestResourceNames()) { - if (comparer.Compare(existingName, givenName, CompareOptions.IgnoreCase) == 0) + if (String.Equals(existingName, givenName, StringComparison.InvariantCultureIgnoreCase)) { if (canonicalName == null) { diff --git a/src/mscorlib/src/System/String.Comparison.cs b/src/mscorlib/src/System/String.Comparison.cs index 2da93d8..f51fda7 100644 --- a/src/mscorlib/src/System/String.Comparison.cs +++ b/src/mscorlib/src/System/String.Comparison.cs @@ -395,10 +395,10 @@ namespace System return CultureInfo.CurrentCulture.CompareInfo.Compare(strA, strB, CompareOptions.IgnoreCase); case StringComparison.InvariantCulture: - return CultureInfo.InvariantCulture.CompareInfo.Compare(strA, strB, CompareOptions.None); + return CompareInfo.Invariant.Compare(strA, strB, CompareOptions.None); case StringComparison.InvariantCultureIgnoreCase: - return CultureInfo.InvariantCulture.CompareInfo.Compare(strA, strB, CompareOptions.IgnoreCase); + return CompareInfo.Invariant.Compare(strA, strB, CompareOptions.IgnoreCase); case StringComparison.Ordinal: // Most common case: first character is different. @@ -592,10 +592,10 @@ namespace System return CultureInfo.CurrentCulture.CompareInfo.Compare(strA, indexA, lengthA, strB, indexB, lengthB, CompareOptions.IgnoreCase); case StringComparison.InvariantCulture: - return CultureInfo.InvariantCulture.CompareInfo.Compare(strA, indexA, lengthA, strB, indexB, lengthB, CompareOptions.None); + return CompareInfo.Invariant.Compare(strA, indexA, lengthA, strB, indexB, lengthB, CompareOptions.None); case StringComparison.InvariantCultureIgnoreCase: - return CultureInfo.InvariantCulture.CompareInfo.Compare(strA, indexA, lengthA, strB, indexB, lengthB, CompareOptions.IgnoreCase); + return CompareInfo.Invariant.Compare(strA, indexA, lengthA, strB, indexB, lengthB, CompareOptions.IgnoreCase); case StringComparison.Ordinal: return CompareOrdinalHelper(strA, indexA, lengthA, strB, indexB, lengthB); @@ -771,10 +771,10 @@ namespace System return CultureInfo.CurrentCulture.CompareInfo.IsSuffix(this, value, CompareOptions.IgnoreCase); case StringComparison.InvariantCulture: - return CultureInfo.InvariantCulture.CompareInfo.IsSuffix(this, value, CompareOptions.None); + return CompareInfo.Invariant.IsSuffix(this, value, CompareOptions.None); case StringComparison.InvariantCultureIgnoreCase: - return CultureInfo.InvariantCulture.CompareInfo.IsSuffix(this, value, CompareOptions.IgnoreCase); + return CompareInfo.Invariant.IsSuffix(this, value, CompareOptions.IgnoreCase); case StringComparison.Ordinal: return this.Length < value.Length ? false : (CompareOrdinalHelper(this, this.Length - value.Length, value.Length, value, 0, value.Length) == 0); @@ -867,10 +867,10 @@ namespace System return (CultureInfo.CurrentCulture.CompareInfo.Compare(this, value, CompareOptions.IgnoreCase) == 0); case StringComparison.InvariantCulture: - return (CultureInfo.InvariantCulture.CompareInfo.Compare(this, value, CompareOptions.None) == 0); + return (CompareInfo.Invariant.Compare(this, value, CompareOptions.None) == 0); case StringComparison.InvariantCultureIgnoreCase: - return (CultureInfo.InvariantCulture.CompareInfo.Compare(this, value, CompareOptions.IgnoreCase) == 0); + return (CompareInfo.Invariant.Compare(this, value, CompareOptions.IgnoreCase) == 0); case StringComparison.Ordinal: if (this.Length != value.Length) @@ -935,10 +935,10 @@ namespace System return (CultureInfo.CurrentCulture.CompareInfo.Compare(a, b, CompareOptions.IgnoreCase) == 0); case StringComparison.InvariantCulture: - return (CultureInfo.InvariantCulture.CompareInfo.Compare(a, b, CompareOptions.None) == 0); + return (CompareInfo.Invariant.Compare(a, b, CompareOptions.None) == 0); case StringComparison.InvariantCultureIgnoreCase: - return (CultureInfo.InvariantCulture.CompareInfo.Compare(a, b, CompareOptions.IgnoreCase) == 0); + return (CompareInfo.Invariant.Compare(a, b, CompareOptions.IgnoreCase) == 0); case StringComparison.Ordinal: if (a.Length != b.Length) @@ -1090,10 +1090,10 @@ namespace System return CultureInfo.CurrentCulture.CompareInfo.IsPrefix(this, value, CompareOptions.IgnoreCase); case StringComparison.InvariantCulture: - return CultureInfo.InvariantCulture.CompareInfo.IsPrefix(this, value, CompareOptions.None); + return CompareInfo.Invariant.IsPrefix(this, value, CompareOptions.None); case StringComparison.InvariantCultureIgnoreCase: - return CultureInfo.InvariantCulture.CompareInfo.IsPrefix(this, value, CompareOptions.IgnoreCase); + return CompareInfo.Invariant.IsPrefix(this, value, CompareOptions.IgnoreCase); case StringComparison.Ordinal: if (this.Length < value.Length || _firstChar != value._firstChar) -- 2.7.4