Skip to content
This repository has been archived by the owner on Jan 23, 2023. It is now read-only.
/ corefx Public archive

Commit

Permalink
Expose and test MemoryExtensions.Sort
Browse files Browse the repository at this point in the history
  • Loading branch information
stephentoub committed Nov 8, 2019
1 parent dce83cb commit a7fbb94
Show file tree
Hide file tree
Showing 3 changed files with 155 additions and 0 deletions.
6 changes: 6 additions & 0 deletions src/System.Memory/ref/System.Memory.cs
Original file line number Diff line number Diff line change
Expand Up @@ -163,6 +163,12 @@ public static bool SequenceEqual<T>(this System.Span<T> span, System.ReadOnlySpa
#nullable disable
where T : System.IEquatable<T> { throw null; }
#nullable restore
public static void Sort<T>(this System.Span<T> span) { }
public static void Sort<T, TComparer>(this System.Span<T> span, TComparer comparer) where TComparer : System.Collections.Generic.IComparer<T>? { }
public static void Sort<T>(this System.Span<T> span, System.Comparison<T> comparison) { }
public static void Sort<TKey, TValue>(this System.Span<TKey> keys, System.Span<TValue> items) { }
public static void Sort<TKey, TValue, TComparer>(this System.Span<TKey> keys, System.Span<TValue> items, TComparer comparer) where TComparer : System.Collections.Generic.IComparer<TKey>? { }
public static void Sort<TKey, TValue>(this System.Span<TKey> keys, System.Span<TValue> items, System.Comparison<TKey> comparison) { }
public static bool StartsWith(this System.ReadOnlySpan<char> span, System.ReadOnlySpan<char> value, System.StringComparison comparisonType) { throw null; }
public static bool StartsWith<T>(this System.ReadOnlySpan<T> span, System.ReadOnlySpan<T> value)
#nullable disable
Expand Down
148 changes: 148 additions & 0 deletions src/System.Memory/tests/Span/Sort.cs
Original file line number Diff line number Diff line change
@@ -0,0 +1,148 @@
// Licensed to the .NET Foundation under one or more agreements.
// The .NET Foundation licenses this file to you under the MIT license.
// See the LICENSE file in the project root for more information.

using System.Collections.Generic;
using System.Linq;
using Xunit;

namespace System.SpanTests
{
public static partial class SpanTests
{
[Fact]
public static void Sort_InvalidArguments_Throws()
{
AssertExtensions.Throws<ArgumentNullException>("comparison", () => MemoryExtensions.Sort(Span<byte>.Empty, (Comparison<byte>)null));
AssertExtensions.Throws<ArgumentNullException>("comparison", () => MemoryExtensions.Sort(Span<byte>.Empty, Span<byte>.Empty, (Comparison<byte>)null));

Assert.Throws<ArgumentException>(() => MemoryExtensions.Sort((Span<byte>)new byte[1], (Span<byte>)new byte[2]));
Assert.Throws<ArgumentException>(() => MemoryExtensions.Sort((Span<byte>)new byte[2], (Span<byte>)new byte[1]));
Assert.Throws<ArgumentException>(() => MemoryExtensions.Sort((Span<byte>)new byte[1], (Span<byte>)new byte[2], Comparer<byte>.Default.Compare));
Assert.Throws<ArgumentException>(() => MemoryExtensions.Sort((Span<byte>)new byte[2], (Span<byte>)new byte[1], Comparer<byte>.Default.Compare));
Assert.Throws<ArgumentException>(() => MemoryExtensions.Sort((Span<byte>)new byte[1], (Span<byte>)new byte[2], Comparer<byte>.Default));
Assert.Throws<ArgumentException>(() => MemoryExtensions.Sort((Span<byte>)new byte[2], (Span<byte>)new byte[1], Comparer<byte>.Default));

Assert.Throws<InvalidOperationException>(() => MemoryExtensions.Sort((Span<NotImcomparable>)new NotImcomparable[10]));
Assert.Throws<InvalidOperationException>(() => MemoryExtensions.Sort((Span<NotImcomparable>)new NotImcomparable[10], (Span<byte>)new byte[10]));
}

private struct NotImcomparable { }

[Theory]
[InlineData(0)]
[InlineData(1)]
[InlineData(2)]
[InlineData(3)]
[InlineData(4)]
[InlineData(5)]
public static void Sort_CovariantArraysAllowed(int overload)
{
Span<object> actual = Enumerable.Range(0, 10).Select(i => (object)i.ToString()).Reverse().ToArray();

object[] expected = actual.ToArray();
Array.Sort(expected);

switch (overload)
{
case 0:
MemoryExtensions.Sort(actual);
break;
case 1:
MemoryExtensions.Sort(actual, StringComparer.CurrentCulture.Compare);
break;
case 2:
MemoryExtensions.Sort(actual, (IComparer<object>)null);
break;
case 3:
MemoryExtensions.Sort(actual, new byte[actual.Length].AsSpan());
break;
case 4:
MemoryExtensions.Sort(actual, new byte[actual.Length].AsSpan(), StringComparer.CurrentCulture.Compare);
break;
case 5:
MemoryExtensions.Sort(actual, new byte[actual.Length].AsSpan(), (IComparer<object>)null);
break;
}

Assert.Equal(expected, actual.ToArray());
}

[Theory]
[MemberData(nameof(Sort_MemberData))]
public static void Sort<T>(T[] origKeys, IComparer<T> comparer)
{
T[] expectedKeys = origKeys.ToArray();
Array.Sort(expectedKeys, comparer);

byte[] origValues = new byte[origKeys.Length];
new Random(42).NextBytes(origValues);
byte[] expectedValues = origValues.ToArray();
Array.Sort(origKeys.ToArray(), expectedValues, comparer);

Span<T> keys;
Span<byte> values;

if (comparer == null)
{
keys = origKeys.ToArray();
MemoryExtensions.Sort(keys);
Assert.Equal(expectedKeys, keys.ToArray());
}

keys = origKeys.ToArray();
MemoryExtensions.Sort(keys, comparer);
Assert.Equal(expectedKeys, keys.ToArray());

keys = origKeys.ToArray();
MemoryExtensions.Sort(keys, comparer != null ? (Comparison<T>)comparer.Compare : Comparer<T>.Default.Compare);
Assert.Equal(expectedKeys, keys.ToArray());

if (comparer == null)
{
keys = origKeys.ToArray();
values = origValues.ToArray();
MemoryExtensions.Sort(keys, values);
Assert.Equal(expectedKeys, keys.ToArray());
Assert.Equal(expectedValues, values.ToArray());
}

keys = origKeys.ToArray();
values = origValues.ToArray();
MemoryExtensions.Sort(keys, values, comparer);
Assert.Equal(expectedKeys, keys.ToArray());
Assert.Equal(expectedValues, values.ToArray());

keys = origKeys.ToArray();
values = origValues.ToArray();
MemoryExtensions.Sort(keys, values, comparer != null ? (Comparison<T>)comparer.Compare : Comparer<T>.Default.Compare);
Assert.Equal(expectedKeys, keys.ToArray());
Assert.Equal(expectedValues, values.ToArray());
}

public static IEnumerable<object[]> Sort_MemberData()
{
var rand = new Random(42);
foreach (int length in new[] { 0, 1, 2, 3, 10 })
{
yield return new object[] { CreateArray(i => i.ToString()), null };
yield return new object[] { CreateArray(i => (byte)i), null };
yield return new object[] { CreateArray(i => (sbyte)i), null };
yield return new object[] { CreateArray(i => (ushort)i), null };
yield return new object[] { CreateArray(i => (short)i), null };
yield return new object[] { CreateArray(i => (uint)i), null };
yield return new object[] { CreateArray(i => i), null };
yield return new object[] { CreateArray(i => (ulong)i), null };
yield return new object[] { CreateArray(i => (long)i), null };
yield return new object[] { CreateArray(i => (char)i), null };
yield return new object[] { CreateArray(i => i % 2 == 0), null };
yield return new object[] { CreateArray(i => (float)i), null };
yield return new object[] { CreateArray(i => (double)i), null };
yield return new object[] { CreateArray(i => (IntPtr)i), Comparer<IntPtr>.Create((i, j) => i.ToInt64().CompareTo(j.ToInt64())) };
yield return new object[] { CreateArray(i => (UIntPtr)i), Comparer<UIntPtr>.Create((i, j) => i.ToUInt64().CompareTo(j.ToUInt64())) };

T[] CreateArray<T>(Func<int, T> getValue) => Enumerable.Range(0, length).Select(_ => getValue(rand.Next())).ToArray();
}
}
}
}
1 change: 1 addition & 0 deletions src/System.Memory/tests/System.Memory.Tests.csproj
Original file line number Diff line number Diff line change
Expand Up @@ -100,6 +100,7 @@
<Compile Include="Span\SequenceEqual.long.cs" />
<Compile Include="Span\SequenceEqual.T.cs" />
<Compile Include="Span\Slice.cs" />
<Compile Include="Span\Sort.cs" />
<Compile Include="Span\StartsWith.byte.cs" />
<Compile Include="Span\StartsWith.char.cs" />
<Compile Include="Span\StartsWith.long.cs" />
Expand Down

0 comments on commit a7fbb94

Please sign in to comment.