Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

[iOS][non-icu] HybridGlobalization implement GetSortKey on hybrid mode #95260

Merged
merged 13 commits into from
Dec 6, 2023
2 changes: 1 addition & 1 deletion docs/design/features/globalization-hybrid-mode.md
Original file line number Diff line number Diff line change
Expand Up @@ -463,7 +463,7 @@ Affected public APIs:
- CompareInfo.GetSortKeyLength
- CompareInfo.GetHashCode

Apple Native API does not have an equivalent, so they throw `PlatformNotSupportedException`.
Implemeneted using [stringByFoldingWithOptions:locale:](https://developer.apple.com/documentation/foundation/nsstring/1413779-stringbyfoldingwithoptions)


## Case change
Expand Down
3 changes: 3 additions & 0 deletions src/libraries/Common/src/Interop/Interop.Collation.iOS.cs
Original file line number Diff line number Diff line change
Expand Up @@ -29,5 +29,8 @@ internal static partial class Globalization
[LibraryImport(Libraries.GlobalizationNative, EntryPoint = "GlobalizationNative_StartsWithNative", StringMarshalling = StringMarshalling.Utf16)]
[MethodImpl(MethodImplOptions.NoInlining)]
internal static unsafe partial int StartsWithNative(string localeName, int lNameLen, char* target, int cwTargetLength, char* source, int cwSourceLength, CompareOptions options);

[LibraryImport(Libraries.GlobalizationNative, EntryPoint = "GlobalizationNative_GetSortKeyNative", StringMarshalling = StringMarshalling.Utf16)]
internal static unsafe partial int GetSortKeyNative(string localeName, int lNameLen, char* str, int strLength, byte* sortKey, int sortKeyLength, CompareOptions options);
}
}
26 changes: 16 additions & 10 deletions src/libraries/Common/tests/Tests/System/StringTests.cs
Original file line number Diff line number Diff line change
Expand Up @@ -1009,6 +1009,7 @@ public static void MakeSureNoCompareToChecksGoOutOfRange_StringComparison()
}

[Fact]
[ActiveIssue("https://github.com/dotnet/runtime/issues/95338", typeof(PlatformDetection), nameof(PlatformDetection.IsHybridGlobalizationOnOSX))]
public static void CompareToNoMatch_StringComparison()
{
for (int length = 1; length < 150; length++)
Expand Down Expand Up @@ -1283,6 +1284,7 @@ public static void ContainsMatchDifferentSpans_StringComparison()
}

[Fact]
[ActiveIssue("https://github.com/dotnet/runtime/issues/95338", typeof(PlatformDetection), nameof(PlatformDetection.IsHybridGlobalizationOnOSX))]
public static void ContainsNoMatch_StringComparison()
{
for (int length = 1; length < 150; length++)
Expand Down Expand Up @@ -1660,7 +1662,7 @@ public static IEnumerable<object[]> EndsWith_StringComparison_TestData()
yield return new object[] { "", "", StringComparison.CurrentCulture, true };
yield return new object[] { "", "a", StringComparison.CurrentCulture, false };

if (PlatformDetection.IsNotInvariantGlobalization)
if (PlatformDetection.IsNotInvariantGlobalization && PlatformDetection.IsNotHybridGlobalizationOnOSX)
yield return new object[] { "Hello", "llo" + SoftHyphen, StringComparison.CurrentCulture, true };

// CurrentCultureIgnoreCase
Expand All @@ -1672,7 +1674,7 @@ public static IEnumerable<object[]> EndsWith_StringComparison_TestData()
yield return new object[] { "", "", StringComparison.CurrentCultureIgnoreCase, true };
yield return new object[] { "", "a", StringComparison.CurrentCultureIgnoreCase, false };

if (PlatformDetection.IsNotInvariantGlobalization)
if (PlatformDetection.IsNotInvariantGlobalization && PlatformDetection.IsNotHybridGlobalizationOnOSX)
yield return new object[] { "Hello", "llo" + SoftHyphen, StringComparison.CurrentCultureIgnoreCase, true };

// InvariantCulture
Expand All @@ -1685,7 +1687,7 @@ public static IEnumerable<object[]> EndsWith_StringComparison_TestData()
yield return new object[] { "", "", StringComparison.InvariantCulture, true };
yield return new object[] { "", "a", StringComparison.InvariantCulture, false };

if (PlatformDetection.IsNotInvariantGlobalization)
if (PlatformDetection.IsNotInvariantGlobalization && PlatformDetection.IsNotHybridGlobalizationOnOSX)
yield return new object[] { "Hello", "llo" + SoftHyphen, StringComparison.InvariantCulture, true };

// InvariantCultureIgnoreCase
Expand All @@ -1697,7 +1699,7 @@ public static IEnumerable<object[]> EndsWith_StringComparison_TestData()
yield return new object[] { "", "", StringComparison.InvariantCultureIgnoreCase, true };
yield return new object[] { "", "a", StringComparison.InvariantCultureIgnoreCase, false };

if (PlatformDetection.IsNotInvariantGlobalization)
if (PlatformDetection.IsNotInvariantGlobalization && PlatformDetection.IsNotHybridGlobalizationOnOSX)
yield return new object[] { "Hello", "llo" + SoftHyphen, StringComparison.InvariantCultureIgnoreCase, true };

// Ordinal
Expand Down Expand Up @@ -2109,6 +2111,7 @@ public static void EndsWithMatchDifferentSpans_StringComparison()
}

[Fact]
[ActiveIssue("https://github.com/dotnet/runtime/issues/95338", typeof(PlatformDetection), nameof(PlatformDetection.IsHybridGlobalizationOnOSX))]
public static void EndsWithNoMatch_StringComparison()
{
for (int length = 1; length < 150; length++)
Expand Down Expand Up @@ -3194,7 +3197,7 @@ public static void IndexOf_TurkishI_EnglishUSCulture()
}
}

[ConditionalFact(typeof(PlatformDetection), nameof(PlatformDetection.IsNotInvariantGlobalization))]
[ConditionalFact(typeof(PlatformDetection), nameof(PlatformDetection.IsNotInvariantGlobalization), nameof(PlatformDetection.IsNotHybridGlobalizationOnOSX))]
[ActiveIssue("https://github.com/dotnet/runtime/issues/60568", TestPlatforms.Android | TestPlatforms.LinuxBionic)]
public static void IndexOf_HungarianDoubleCompression_HungarianCulture()
{
Expand Down Expand Up @@ -4849,7 +4852,7 @@ public static IEnumerable<object[]> StartsWith_StringComparison_TestData()
yield return new object[] { "", "", StringComparison.CurrentCulture, true };
yield return new object[] { "", "hello", StringComparison.CurrentCulture, false };

if (PlatformDetection.IsNotInvariantGlobalization)
if (PlatformDetection.IsNotInvariantGlobalization && PlatformDetection.IsNotHybridGlobalizationOnOSX)
yield return new object[] { "Hello", SoftHyphen + "Hel", StringComparison.CurrentCulture, true };

// CurrentCultureIgnoreCase
Expand All @@ -4861,7 +4864,7 @@ public static IEnumerable<object[]> StartsWith_StringComparison_TestData()
yield return new object[] { "", "", StringComparison.CurrentCultureIgnoreCase, true };
yield return new object[] { "", "hello", StringComparison.CurrentCultureIgnoreCase, false };

if (PlatformDetection.IsNotInvariantGlobalization)
if (PlatformDetection.IsNotInvariantGlobalization && PlatformDetection.IsNotHybridGlobalizationOnOSX)
yield return new object[] { "Hello", SoftHyphen + "Hel", StringComparison.CurrentCultureIgnoreCase, true };

// InvariantCulture
Expand All @@ -4873,7 +4876,7 @@ public static IEnumerable<object[]> StartsWith_StringComparison_TestData()
yield return new object[] { "", "", StringComparison.InvariantCulture, true };
yield return new object[] { "", "hello", StringComparison.InvariantCulture, false };

if (PlatformDetection.IsNotInvariantGlobalization)
if (PlatformDetection.IsNotInvariantGlobalization && PlatformDetection.IsNotHybridGlobalizationOnOSX)
yield return new object[] { "Hello", SoftHyphen + "Hel", StringComparison.InvariantCulture, true };

// InvariantCultureIgnoreCase
Expand All @@ -4885,7 +4888,7 @@ public static IEnumerable<object[]> StartsWith_StringComparison_TestData()
yield return new object[] { "", "", StringComparison.InvariantCultureIgnoreCase, true };
yield return new object[] { "", "hello", StringComparison.InvariantCultureIgnoreCase, false };

if (PlatformDetection.IsNotInvariantGlobalization)
if (PlatformDetection.IsNotInvariantGlobalization && PlatformDetection.IsNotHybridGlobalizationOnOSX)
yield return new object[] { "Hello", SoftHyphen + "Hel", StringComparison.InvariantCultureIgnoreCase, true };

// Ordinal
Expand Down Expand Up @@ -5342,6 +5345,7 @@ private static IEnumerable<object[]> ToLower_Culture_TestData()
}

[ConditionalFact(typeof(PlatformDetection), nameof(PlatformDetection.IsNotInvariantGlobalization))]
[ActiveIssue("https://github.com/dotnet/runtime/issues/95338", typeof(PlatformDetection), nameof(PlatformDetection.IsHybridGlobalizationOnOSX))]
public static void Test_ToLower_Culture()
{
foreach (object[] testdata in ToLower_Culture_TestData())
Expand Down Expand Up @@ -5857,6 +5861,7 @@ public static IEnumerable<object[]> ToUpper_Culture_TestData()
}

[ConditionalTheory(typeof(PlatformDetection), nameof(PlatformDetection.IsNotInvariantGlobalization))]
[ActiveIssue("https://github.com/dotnet/runtime/issues/95338", typeof(PlatformDetection), nameof(PlatformDetection.IsHybridGlobalizationOnOSX))]
[MemberData(nameof(ToUpper_Culture_TestData))]
public static void Test_ToUpper_Culture(string actual, string expected, CultureInfo culture)
{
Expand Down Expand Up @@ -5955,7 +5960,7 @@ public static IEnumerable<object[]> ToUpper_TurkishI_InvariantCulture_MemberData
new KeyValuePair<char, char>('\u0130', '\u0130'),
new KeyValuePair<char, char>('\u0131', '\u0131'));

[ConditionalTheory(typeof(PlatformDetection), nameof(PlatformDetection.IsNotInvariantGlobalization))]
[ConditionalTheory(typeof(PlatformDetection), nameof(PlatformDetection.IsNotInvariantGlobalization), nameof(PlatformDetection.IsNotHybridGlobalizationOnOSX))]
[MemberData(nameof(ToUpper_TurkishI_InvariantCulture_MemberData))]
public static void ToUpper_TurkishI_InvariantCulture(string s, string expected)
{
Expand Down Expand Up @@ -7225,6 +7230,7 @@ public static void StartsWithMatchDifferentSpans_StringComparison()
}

[Fact]
[ActiveIssue("https://github.com/dotnet/runtime/issues/95338", typeof(PlatformDetection), nameof(PlatformDetection.IsHybridGlobalizationOnOSX))]
public static void StartsWithNoMatch_StringComparison()
{
for (int length = 1; length < 150; length++)
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -700,14 +700,36 @@ private unsafe SortKey IcuCreateSortKey(string source, CompareOptions options)
byte[] keyData;
fixed (char* pSource = source)
{
int sortKeyLength = Interop.Globalization.GetSortKey(_sortHandle, pSource, source.Length, null, 0, options);
int sortKeyLength;
#if TARGET_MACCATALYST || TARGET_IOS || TARGET_TVOS
if (GlobalizationMode.Hybrid)
{
sortKeyLength = Interop.Globalization.GetSortKeyNative(m_name, m_name.Length, pSource, source.Length, null, 0, options);
}
else
#endif
{
sortKeyLength = Interop.Globalization.GetSortKey(_sortHandle, pSource, source.Length, null, 0, options);
}
keyData = new byte[sortKeyLength];

fixed (byte* pSortKey = keyData)
{
if (Interop.Globalization.GetSortKey(_sortHandle, pSource, source.Length, pSortKey, sortKeyLength, options) != sortKeyLength)
#if TARGET_MACCATALYST || TARGET_IOS || TARGET_TVOS
if (GlobalizationMode.Hybrid)
{
throw new ArgumentException(SR.Arg_ExternalException);
if (Interop.Globalization.GetSortKeyNative(m_name, m_name.Length, pSource, source.Length, pSortKey, sortKeyLength, options) != sortKeyLength)
{
throw new ArgumentException(SR.Arg_ExternalException);
}
}
else
#endif
{
if (Interop.Globalization.GetSortKey(_sortHandle, pSource, source.Length, pSortKey, sortKeyLength, options) != sortKeyLength)
{
throw new ArgumentException(SR.Arg_ExternalException);
}
}
}
}
Expand All @@ -728,7 +750,16 @@ private unsafe int IcuGetSortKey(ReadOnlySpan<char> source, Span<byte> destinati
fixed (char* pSource = &MemoryMarshal.GetReference(source))
fixed (byte* pDest = &MemoryMarshal.GetReference(destination))
{
actualSortKeyLength = Interop.Globalization.GetSortKey(_sortHandle, pSource, source.Length, pDest, destination.Length, options);
#if TARGET_MACCATALYST || TARGET_IOS || TARGET_TVOS
if (GlobalizationMode.Hybrid)
{
actualSortKeyLength = Interop.Globalization.GetSortKeyNative(m_name, m_name.Length, pSource, source.Length, pDest, destination.Length, options);
}
else
#endif
{
actualSortKeyLength = Interop.Globalization.GetSortKey(_sortHandle, pSource, source.Length, pDest, destination.Length, options);
}
}

// The check below also handles errors due to negative values / overflow being returned.
Expand Down Expand Up @@ -758,7 +789,16 @@ private unsafe int IcuGetSortKeyLength(ReadOnlySpan<char> source, CompareOptions

fixed (char* pSource = &MemoryMarshal.GetReference(source))
{
return Interop.Globalization.GetSortKey(_sortHandle, pSource, source.Length, null, 0, options);
#if TARGET_MACCATALYST || TARGET_IOS || TARGET_TVOS
if (GlobalizationMode.Hybrid)
{
return Interop.Globalization.GetSortKeyNative(m_name, m_name.Length, pSource, source.Length, null, 0, options);
}
else
#endif
{
return Interop.Globalization.GetSortKey(_sortHandle, pSource, source.Length, null, 0, options);
}
}
}

Expand Down Expand Up @@ -809,7 +849,16 @@ private unsafe int IcuGetHashCodeOfString(ReadOnlySpan<char> source, CompareOpti
{
fixed (byte* pSortKey = &MemoryMarshal.GetReference(sortKey))
{
sortKeyLength = Interop.Globalization.GetSortKey(_sortHandle, pSource, source.Length, pSortKey, sortKey.Length, options);
#if TARGET_MACCATALYST || TARGET_IOS || TARGET_TVOS
if (GlobalizationMode.Hybrid)
{
sortKeyLength = Interop.Globalization.GetSortKeyNative(m_name, m_name.Length, pSource, source.Length, pSortKey, sortKey.Length, options);
}
else
#endif
{
sortKeyLength = Interop.Globalization.GetSortKey(_sortHandle, pSource, source.Length, pSortKey, sortKey.Length, options);
}
}

if (sortKeyLength > sortKey.Length) // slow path for big strings
Expand All @@ -823,7 +872,16 @@ private unsafe int IcuGetHashCodeOfString(ReadOnlySpan<char> source, CompareOpti

fixed (byte* pSortKey = &MemoryMarshal.GetReference(sortKey))
{
sortKeyLength = Interop.Globalization.GetSortKey(_sortHandle, pSource, source.Length, pSortKey, sortKey.Length, options);
#if TARGET_MACCATALYST || TARGET_IOS || TARGET_TVOS
if (GlobalizationMode.Hybrid)
{
sortKeyLength = Interop.Globalization.GetSortKeyNative(m_name, m_name.Length, pSource, source.Length, pSortKey, sortKey.Length, options);
}
else
#endif
mkhamoyan marked this conversation as resolved.
Show resolved Hide resolved
{
sortKeyLength = Interop.Globalization.GetSortKey(_sortHandle, pSource, source.Length, pSortKey, sortKey.Length, options);
}
}
}
}
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -1450,7 +1450,7 @@ public SortKey GetSortKey(string source)
private SortKey CreateSortKeyCore(string source, CompareOptions options) =>
GlobalizationMode.UseNls ?
NlsCreateSortKey(source, options) :
#if TARGET_BROWSER || TARGET_MACCATALYST || TARGET_IOS || TARGET_TVOS
#if TARGET_BROWSER
GlobalizationMode.Hybrid ?
throw new PlatformNotSupportedException(GetPNSEText("SortKey")) :
#endif
Expand Down Expand Up @@ -1493,7 +1493,7 @@ public int GetSortKey(ReadOnlySpan<char> source, Span<byte> destination, Compare
private int GetSortKeyCore(ReadOnlySpan<char> source, Span<byte> destination, CompareOptions options) =>
GlobalizationMode.UseNls ?
NlsGetSortKey(source, destination, options) :
#if TARGET_BROWSER || TARGET_MACCATALYST || TARGET_IOS || TARGET_TVOS
#if TARGET_BROWSER
GlobalizationMode.Hybrid ?
throw new PlatformNotSupportedException(GetPNSEText("SortKey")) :
#endif
Expand Down Expand Up @@ -1530,7 +1530,7 @@ public int GetSortKeyLength(ReadOnlySpan<char> source, CompareOptions options =
private int GetSortKeyLengthCore(ReadOnlySpan<char> source, CompareOptions options) =>
GlobalizationMode.UseNls ?
NlsGetSortKeyLength(source, options) :
#if TARGET_BROWSER || TARGET_MACCATALYST || TARGET_IOS || TARGET_TVOS
#if TARGET_BROWSER
GlobalizationMode.Hybrid ?
throw new PlatformNotSupportedException(GetPNSEText("SortKey")) :
#endif
Expand Down Expand Up @@ -1607,7 +1607,7 @@ public int GetHashCode(ReadOnlySpan<char> source, CompareOptions options)
private unsafe int GetHashCodeOfStringCore(ReadOnlySpan<char> source, CompareOptions options) =>
GlobalizationMode.UseNls ?
NlsGetHashCodeOfString(source, options) :
#if TARGET_BROWSER || TARGET_MACCATALYST || TARGET_IOS || TARGET_TVOS
#if TARGET_BROWSER
GlobalizationMode.Hybrid ?
throw new PlatformNotSupportedException(GetPNSEText("HashCode")) :
#endif
Expand Down
Loading
Loading