// See the LICENSE file in the project root for more information.
using System.Buffers;
+using System.Collections.Generic;
using System.Diagnostics;
using System.Runtime.CompilerServices;
using System.Runtime.InteropServices;
using System.Security;
+using System.Threading;
using Internal.Runtime.CompilerServices;
public partial class CompareInfo
{
[NonSerialized]
+ private IntPtr _sortHandle;
+
+ [NonSerialized]
private bool _isAsciiEqualityOrdinal;
+ // in most scenarios there is a limited number of cultures with limited number of sort options
+ // so caching the sort handles and not freeing them is OK, see https://github.com/dotnet/coreclr/pull/25117 for more
+ [NonSerialized]
+ private static Dictionary<string, IntPtr> s_sortNameToSortHandleCache;
+
private void InitSort(CultureInfo culture)
{
_sortName = culture.SortName;
}
else
{
- Interop.Globalization.ResultCode resultCode = Interop.Globalization.GetSortHandle(GetNullTerminatedUtf8String(_sortName), out _sortHandle);
- if (resultCode != Interop.Globalization.ResultCode.Success)
- {
- Interop.Globalization.CloseSortHandle(_sortHandle);
+ _isAsciiEqualityOrdinal = (_sortName == "en-US" || _sortName == "");
- if (resultCode == Interop.Globalization.ResultCode.OutOfMemory)
- throw new OutOfMemoryException();
+ lock (_lock)
+ {
+ if (s_sortNameToSortHandleCache == null)
+ {
+ s_sortNameToSortHandleCache = new Dictionary<string, IntPtr>();
+ }
- throw new ExternalException(SR.Arg_ExternalException);
+ if (!s_sortNameToSortHandleCache.TryGetValue(_sortName, out _sortHandle))
+ {
+ s_sortNameToSortHandleCache.Add(_sortName, (_sortHandle = GetSortHandle(_sortName)));
+ }
}
- _isAsciiEqualityOrdinal = (_sortName == "en-US" || _sortName == "");
+ }
+ }
+
+ private static IntPtr GetSortHandle(string sortName)
+ {
+ var resultCode = Interop.Globalization.GetSortHandle(GetNullTerminatedUtf8String(sortName), out IntPtr sortHandle);
+ if (resultCode == Interop.Globalization.ResultCode.Success)
+ {
+ return sortHandle;
+ }
+ else
+ {
+ Interop.Globalization.CloseSortHandle(sortHandle);
+
+ if (resultCode == Interop.Globalization.ResultCode.OutOfMemory)
+ throw new OutOfMemoryException();
+
+ throw new ExternalException(SR.Arg_ExternalException);
}
}
~(CompareOptions.IgnoreCase | CompareOptions.IgnoreSymbols | CompareOptions.IgnoreNonSpace |
CompareOptions.IgnoreWidth | CompareOptions.IgnoreKanaType | CompareOptions.StringSort);
+ [NonSerialized]
+ private static readonly object _lock = new object(); // must be initialized before Invariant field
+
// Cache the invariant CompareInfo
internal static readonly CompareInfo Invariant = CultureInfo.InvariantCulture.CompareInfo;
private int culture; // Do not rename (binary serialization). The fields sole purpose is to support Desktop serialization.
- [NonSerialized]
- private IntPtr _sortHandle;
-
internal CompareInfo(CultureInfo culture)
{
m_name = culture._name;