Imported Upstream version 5.10.0.47

Former-commit-id: d0813289fa2d35e1f8ed77530acb4fb1df441bc0
This commit is contained in:
Xamarin Public Jenkins (auto-signing)
2018-01-24 17:04:36 +00:00
parent 88ff76fe28
commit e46a49ecf1
5927 changed files with 226314 additions and 129848 deletions

View File

@@ -522,69 +522,74 @@ namespace System.Linq
internal TElement ElementAt(TElement[] elements, int count, int idx) =>
elements[QuickSelect(ComputeMap(elements, count), count - 1, idx)];
private int CompareKeys(int index1, int index2) => index1 == index2 ? 0 : CompareAnyKeys(index1, index2);
private void QuickSort(int[] map, int left, int right)
{
do
{
int i = left;
int j = right;
int x = map[i + ((j - i) >> 1)];
do
{
while (i < map.Length && CompareKeys(x, map[i]) > 0)
{
i++;
}
while (j >= 0 && CompareKeys(x, map[j]) < 0)
{
j--;
}
if (i > j)
{
break;
}
if (i < j)
{
int temp = map[i];
map[i] = map[j];
map[j] = temp;
}
i++;
j--;
}
while (i <= j);
if (j - left <= right - i)
{
if (left < j)
{
QuickSort(map, left, j);
}
left = i;
}
else
{
if (i < right)
{
QuickSort(map, i, right);
}
right = j;
}
}
while (left < right);
}
protected abstract void QuickSort(int[] map, int left, int right);
// Sorts the k elements between minIdx and maxIdx without sorting all elements
// Time complexity: O(n + k log k) best and average case. O(n^2) worse case.
private void PartialQuickSort(int[] map, int left, int right, int minIdx, int maxIdx)
protected abstract void PartialQuickSort(int[] map, int left, int right, int minIdx, int maxIdx);
// Finds the element that would be at idx if the collection was sorted.
// Time complexity: O(n) best and average case. O(n^2) worse case.
protected abstract int QuickSelect(int[] map, int right, int idx);
}
internal sealed class EnumerableSorter<TElement, TKey> : EnumerableSorter<TElement>
{
private readonly Func<TElement, TKey> _keySelector;
private readonly IComparer<TKey> _comparer;
private readonly bool _descending;
private readonly EnumerableSorter<TElement> _next;
private TKey[] _keys;
internal EnumerableSorter(Func<TElement, TKey> keySelector, IComparer<TKey> comparer, bool descending, EnumerableSorter<TElement> next)
{
_keySelector = keySelector;
_comparer = comparer;
_descending = descending;
_next = next;
}
internal override void ComputeKeys(TElement[] elements, int count)
{
_keys = new TKey[count];
for (int i = 0; i < count; i++)
{
_keys[i] = _keySelector(elements[i]);
}
_next?.ComputeKeys(elements, count);
}
internal override int CompareAnyKeys(int index1, int index2)
{
int c = _comparer.Compare(_keys[index1], _keys[index2]);
if (c == 0)
{
if (_next == null)
{
return index1 - index2; // ensure stability of sort
}
return _next.CompareAnyKeys(index1, index2);
}
// -c will result in a negative value for int.MinValue (-int.MinValue == int.MinValue).
// Flipping keys earlier is more likely to trigger something strange in a comparer,
// particularly as it comes to the sort being stable.
return (_descending != (c > 0)) ? 1 : -1;
}
private int CompareKeys(int index1, int index2) => index1 == index2 ? 0 : CompareAnyKeys(index1, index2);
protected override void QuickSort(int[] keys, int lo, int hi) =>
Array.Sort(keys, lo, hi - lo + 1, Comparer<int>.Create(CompareAnyKeys)); // TODO #24115: Remove Create call when delegate-based overload is available
// Sorts the k elements between minIdx and maxIdx without sorting all elements
// Time complexity: O(n + k log k) best and average case. O(n^2) worse case.
protected override void PartialQuickSort(int[] map, int left, int right, int minIdx, int maxIdx)
{
do
{
@@ -653,7 +658,7 @@ namespace System.Linq
// Finds the element that would be at idx if the collection was sorted.
// Time complexity: O(n) best and average case. O(n^2) worse case.
private int QuickSelect(int[] map, int right, int idx)
protected override int QuickSelect(int[] map, int right, int idx)
{
int left = 0;
do
@@ -723,51 +728,4 @@ namespace System.Linq
return map[idx];
}
}
internal sealed class EnumerableSorter<TElement, TKey> : EnumerableSorter<TElement>
{
private readonly Func<TElement, TKey> _keySelector;
private readonly IComparer<TKey> _comparer;
private readonly bool _descending;
private readonly EnumerableSorter<TElement> _next;
private TKey[] _keys;
internal EnumerableSorter(Func<TElement, TKey> keySelector, IComparer<TKey> comparer, bool descending, EnumerableSorter<TElement> next)
{
_keySelector = keySelector;
_comparer = comparer;
_descending = descending;
_next = next;
}
internal override void ComputeKeys(TElement[] elements, int count)
{
_keys = new TKey[count];
for (int i = 0; i < count; i++)
{
_keys[i] = _keySelector(elements[i]);
}
_next?.ComputeKeys(elements, count);
}
internal override int CompareAnyKeys(int index1, int index2)
{
int c = _comparer.Compare(_keys[index1], _keys[index2]);
if (c == 0)
{
if (_next == null)
{
return index1 - index2;
}
return _next.CompareAnyKeys(index1, index2);
}
// -c will result in a negative value for int.MinValue (-int.MinValue == int.MinValue).
// Flipping keys earlier is more likely to trigger something strange in a comparer,
// particularly as it comes to the sort being stable.
return (_descending != (c > 0)) ? 1 : -1;
}
}
}

View File

@@ -28,9 +28,26 @@ namespace System.Linq
throw Error.ArgumentNull(nameof(second));
}
if (first is ICollection<TSource> firstCol && second is ICollection<TSource> secondCol && firstCol.Count != secondCol.Count)
if (first is ICollection<TSource> firstCol && second is ICollection<TSource> secondCol)
{
return false;
if (firstCol.Count != secondCol.Count)
{
return false;
}
if (firstCol is IList<TSource> firstList && secondCol is IList<TSource> secondList)
{
int count = firstCol.Count;
for (int i = 0; i < count; i++)
{
if (!comparer.Equals(firstList[i], secondList[i]))
{
return false;
}
}
return true;
}
}
using (IEnumerator<TSource> e1 = first.GetEnumerator())

View File

@@ -116,10 +116,18 @@ namespace System.Linq
Debug.Assert(source != null);
Debug.Assert(count > 0);
var queue = new Queue<TSource>();
Queue<TSource> queue;
using (IEnumerator<TSource> e = source.GetEnumerator())
{
if (!e.MoveNext())
{
yield break;
}
queue = new Queue<TSource>();
queue.Enqueue(e.Current);
while (e.MoveNext())
{
if (queue.Count < count)

View File

@@ -421,5 +421,123 @@ namespace System.Linq.Tests
Assert.Equal(0xf00, en.Current);
}
}
[Theory]
[MemberData(nameof(GetToArrayDataSources))]
public void CollectionInterleavedWithLazyEnumerables_ToArray(IEnumerable<int>[] arrays)
{
// See https://github.com/dotnet/corefx/issues/23680
IEnumerable<int> concats = arrays[0];
for (int i = 1; i < arrays.Length; i++)
{
concats = concats.Concat(arrays[i]);
}
int[] results = concats.ToArray();
for (int i = 0; i < results.Length; i++)
{
Assert.Equal(i, results[i]);
}
}
private static IEnumerable<object[]> GetToArrayDataSources()
{
// Marker at the end
yield return new object[]
{
new IEnumerable<int>[]
{
new TestEnumerable<int>(new int[] { 0 }),
new TestEnumerable<int>(new int[] { 1 }),
new TestEnumerable<int>(new int[] { 2 }),
new int[] { 3 },
}
};
// Marker at beginning
yield return new object[]
{
new IEnumerable<int>[]
{
new int[] { 0 },
new TestEnumerable<int>(new int[] { 1 }),
new TestEnumerable<int>(new int[] { 2 }),
new TestEnumerable<int>(new int[] { 3 }),
}
};
// Marker in middle
yield return new object[]
{
new IEnumerable<int>[]
{
new TestEnumerable<int>(new int[] { 0 }),
new int[] { 1 },
new TestEnumerable<int>(new int[] { 2 }),
}
};
// Non-marker in middle
yield return new object[]
{
new IEnumerable<int>[]
{
new int[] { 0 },
new TestEnumerable<int>(new int[] { 1 }),
new int[] { 2 },
}
};
// Big arrays (marker in middle)
yield return new object[]
{
new IEnumerable<int>[]
{
new TestEnumerable<int>(Enumerable.Range(0, 100).ToArray()),
Enumerable.Range(100, 100).ToArray(),
new TestEnumerable<int>(Enumerable.Range(200, 100).ToArray()),
}
};
// Big arrays (non-marker in middle)
yield return new object[]
{
new IEnumerable<int>[]
{
Enumerable.Range(0, 100).ToArray(),
new TestEnumerable<int>(Enumerable.Range(100, 100).ToArray()),
Enumerable.Range(200, 100).ToArray(),
}
};
// Interleaved (first marker)
yield return new object[]
{
new IEnumerable<int>[]
{
new int[] { 0 },
new TestEnumerable<int>(new int[] { 1 }),
new int[] { 2 },
new TestEnumerable<int>(new int[] { 3 }),
new int[] { 4 },
}
};
// Interleaved (first non-marker)
yield return new object[]
{
new IEnumerable<int>[]
{
new TestEnumerable<int>(new int[] { 0 }),
new int[] { 1 },
new TestEnumerable<int>(new int[] { 2 }),
new int[] { 3 },
new TestEnumerable<int>(new int[] { 4 }),
}
};
}
}
}

View File

@@ -184,5 +184,50 @@ namespace System.Linq.Tests
Func<DateTime, int> keySelector = null;
AssertExtensions.Throws<ArgumentNullException>("keySelector", () => Enumerable.Empty<DateTime>().OrderByDescending(keySelector));
}
[Fact]
public void SortsLargeAscendingEnumerableCorrectly()
{
const int Items = 1_000_000;
IEnumerable<int> expected = NumberRangeGuaranteedNotCollectionType(0, Items);
IEnumerable<int> unordered = expected.Select(i => i);
IOrderedEnumerable<int> ordered = unordered.OrderByDescending(i => -i);
Assert.Equal(expected, ordered);
}
[Fact]
public void SortsLargeDescendingEnumerableCorrectly()
{
const int Items = 1_000_000;
IEnumerable<int> expected = NumberRangeGuaranteedNotCollectionType(0, Items);
IEnumerable<int> unordered = expected.Select(i => Items - i - 1);
IOrderedEnumerable<int> ordered = unordered.OrderByDescending(i => -i);
Assert.Equal(expected, ordered);
}
[Theory]
[InlineData(0)]
[InlineData(1)]
[InlineData(2)]
[InlineData(3)]
[InlineData(8)]
[InlineData(16)]
[InlineData(1024)]
[InlineData(4096)]
[InlineData(1_000_000)]
public void SortsRandomizedEnumerableCorrectly(int items)
{
var r = new Random(42);
int[] randomized = Enumerable.Range(0, items).Select(i => r.Next()).ToArray();
int[] ordered = ForceNotCollection(randomized).OrderByDescending(i => -i).ToArray();
Array.Sort(randomized, (a, b) => a - b);
Assert.Equal(randomized, ordered);
}
}
}

View File

@@ -377,5 +377,50 @@ namespace System.Linq.Tests
Enumerable.Range(0, 100).Select(i => i.ToString()).OrderBy(i => i.Length).ThenBy(i => i).ToArray();
Assert.Equal(expected, ordered);
}
[Fact]
public void SortsLargeAscendingEnumerableCorrectly()
{
const int Items = 1_000_000;
IEnumerable<int> expected = NumberRangeGuaranteedNotCollectionType(0, Items);
IEnumerable<int> unordered = expected.Select(i => i);
IOrderedEnumerable<int> ordered = unordered.OrderBy(i => i);
Assert.Equal(expected, ordered);
}
[Fact]
public void SortsLargeDescendingEnumerableCorrectly()
{
const int Items = 1_000_000;
IEnumerable<int> expected = NumberRangeGuaranteedNotCollectionType(0, Items);
IEnumerable<int> unordered = expected.Select(i => Items - i - 1);
IOrderedEnumerable<int> ordered = unordered.OrderBy(i => i);
Assert.Equal(expected, ordered);
}
[Theory]
[InlineData(0)]
[InlineData(1)]
[InlineData(2)]
[InlineData(3)]
[InlineData(8)]
[InlineData(16)]
[InlineData(1024)]
[InlineData(4096)]
[InlineData(1_000_000)]
public void SortsRandomizedEnumerableCorrectly(int items)
{
var r = new Random(42);
int[] randomized = Enumerable.Range(0, items).Select(i => r.Next()).ToArray();
int[] ordered = ForceNotCollection(randomized).OrderBy(i => i).ToArray();
Array.Sort(randomized);
Assert.Equal(randomized, ordered);
}
}
}

View File

@@ -0,0 +1,8 @@
<?xml version="1.0" encoding="utf-8"?>
<Project ToolsVersion="14.0" DefaultTargets="Build" xmlns="http://schemas.microsoft.com/developer/msbuild/2003">
<PropertyGroup>
<BuildConfigurations>
netcoreapp;
</BuildConfigurations>
</PropertyGroup>
</Project>

View File

@@ -477,5 +477,116 @@ namespace System.Linq.Tests
IEnumerable<int> iterator = counts.SelectMany(c => Enumerable.Range(1, c));
Assert.Throws<OverflowException>(() => iterator.Count());
}
[Theory]
[MemberData(nameof(GetToArrayDataSources))]
public void CollectionInterleavedWithLazyEnumerables_ToArray(IEnumerable<int>[] arrays)
{
// See https://github.com/dotnet/corefx/issues/23680
int[] results = arrays.SelectMany(ar => ar).ToArray();
for (int i = 0; i < results.Length; i++)
{
Assert.Equal(i, results[i]);
}
}
private static IEnumerable<object[]> GetToArrayDataSources()
{
// Marker at the end
yield return new object[]
{
new IEnumerable<int>[]
{
new TestEnumerable<int>(new int[] { 0 }),
new TestEnumerable<int>(new int[] { 1 }),
new TestEnumerable<int>(new int[] { 2 }),
new int[] { 3 },
}
};
// Marker at beginning
yield return new object[]
{
new IEnumerable<int>[]
{
new int[] { 0 },
new TestEnumerable<int>(new int[] { 1 }),
new TestEnumerable<int>(new int[] { 2 }),
new TestEnumerable<int>(new int[] { 3 }),
}
};
// Marker in middle
yield return new object[]
{
new IEnumerable<int>[]
{
new TestEnumerable<int>(new int[] { 0 }),
new int[] { 1 },
new TestEnumerable<int>(new int[] { 2 }),
}
};
// Non-marker in middle
yield return new object[]
{
new IEnumerable<int>[]
{
new int[] { 0 },
new TestEnumerable<int>(new int[] { 1 }),
new int[] { 2 },
}
};
// Big arrays (marker in middle)
yield return new object[]
{
new IEnumerable<int>[]
{
new TestEnumerable<int>(Enumerable.Range(0, 100).ToArray()),
Enumerable.Range(100, 100).ToArray(),
new TestEnumerable<int>(Enumerable.Range(200, 100).ToArray()),
}
};
// Big arrays (non-marker in middle)
yield return new object[]
{
new IEnumerable<int>[]
{
Enumerable.Range(0, 100).ToArray(),
new TestEnumerable<int>(Enumerable.Range(100, 100).ToArray()),
Enumerable.Range(200, 100).ToArray(),
}
};
// Interleaved (first marker)
yield return new object[]
{
new IEnumerable<int>[]
{
new int[] { 0 },
new TestEnumerable<int>(new int[] { 1 }),
new int[] { 2 },
new TestEnumerable<int>(new int[] { 3 }),
new int[] { 4 },
}
};
// Interleaved (first non-marker)
yield return new object[]
{
new IEnumerable<int>[]
{
new TestEnumerable<int>(new int[] { 0 }),
new int[] { 1 },
new TestEnumerable<int>(new int[] { 2 }),
new int[] { 3 },
new TestEnumerable<int>(new int[] { 4 }),
}
};
}
}
}

View File

@@ -77,9 +77,6 @@
<Compile Include="UnionTests.cs" />
<Compile Include="WhereTests.cs" />
<Compile Include="ZipTests.cs" />
<Compile Include="$(CommonTestPath)\System\PlatformDetection.cs">
<Link>Common\System\PlatformDetection.cs</Link>
</Compile>
<Compile Include="$(CommonTestPath)\System\Linq\SkipTakeData.cs">
<Link>Common\System\Linq\SkipTakeData.cs</Link>
</Compile>

View File

@@ -165,5 +165,71 @@ And Immortality.".Split(new[] { ' ', '\n', '\r', '—' }, StringSplitOptions.Rem
Func<DateTime, int> keySelector = null;
AssertExtensions.Throws<ArgumentNullException>("keySelector", () => Enumerable.Empty<DateTime>().OrderBy(e => e).ThenByDescending(keySelector, null));
}
[Theory]
[InlineData(1)]
[InlineData(2)]
[InlineData(3)]
public void SortsLargeAscendingEnumerableCorrectly(int thenBys)
{
const int Items = 100_000;
IEnumerable<int> expected = NumberRangeGuaranteedNotCollectionType(0, Items);
IEnumerable<int> unordered = expected.Select(i => i);
IOrderedEnumerable<int> ordered = unordered.OrderBy(_ => 0);
switch (thenBys)
{
case 1: ordered = ordered.ThenByDescending(i => -i); break;
case 2: ordered = ordered.ThenByDescending(i => 0).ThenByDescending(i => -i); break;
case 3: ordered = ordered.ThenByDescending(i => 0).ThenByDescending(i => 0).ThenByDescending(i => -i); break;
}
Assert.Equal(expected, ordered);
}
[Theory]
[InlineData(1)]
[InlineData(2)]
[InlineData(3)]
public void SortsLargeDescendingEnumerableCorrectly(int thenBys)
{
const int Items = 100_000;
IEnumerable<int> expected = NumberRangeGuaranteedNotCollectionType(0, Items);
IEnumerable<int> unordered = expected.Select(i => Items - i - 1);
IOrderedEnumerable<int> ordered = unordered.OrderBy(_ => 0);
switch (thenBys)
{
case 1: ordered = ordered.ThenByDescending(i => -i); break;
case 2: ordered = ordered.ThenByDescending(i => 0).ThenByDescending(i => -i); break;
case 3: ordered = ordered.ThenByDescending(i => 0).ThenByDescending(i => 0).ThenByDescending(i => -i); break;
}
Assert.Equal(expected, ordered);
}
[Theory]
[InlineData(1)]
[InlineData(2)]
[InlineData(3)]
public void SortsLargeRandomizedEnumerableCorrectly(int thenBys)
{
const int Items = 100_000;
var r = new Random(42);
int[] randomized = Enumerable.Range(0, Items).Select(i => r.Next()).ToArray();
IOrderedEnumerable<int> orderedEnumerable = randomized.OrderBy(_ => 0);
switch (thenBys)
{
case 1: orderedEnumerable = orderedEnumerable.ThenByDescending(i => -i); break;
case 2: orderedEnumerable = orderedEnumerable.ThenByDescending(i => 0).ThenByDescending(i => -i); break;
case 3: orderedEnumerable = orderedEnumerable.ThenByDescending(i => 0).ThenByDescending(i => 0).ThenByDescending(i => -i); break;
}
int[] ordered = orderedEnumerable.ToArray();
Array.Sort(randomized, (a, b) => a - b);
Assert.Equal(randomized, orderedEnumerable);
}
}
}

View File

@@ -8,7 +8,7 @@ using Xunit;
namespace System.Linq.Tests
{
public class ThenByTests
public class ThenByTests : EnumerableTests
{
[Fact]
public void SameResultsRepeatCallsIntQuery()
@@ -170,5 +170,71 @@ And Immortality.".Split(new[] { ' ', '\n', '\r', '—' }, StringSplitOptions.Rem
Func<DateTime, int> keySelector = null;
AssertExtensions.Throws<ArgumentNullException>("keySelector", () => Enumerable.Empty<DateTime>().OrderBy(e => e).ThenBy(keySelector, null));
}
[Theory]
[InlineData(1)]
[InlineData(2)]
[InlineData(3)]
public void SortsLargeAscendingEnumerableCorrectly(int thenBys)
{
const int Items = 100_000;
IEnumerable<int> expected = NumberRangeGuaranteedNotCollectionType(0, Items);
IEnumerable<int> unordered = expected.Select(i => i);
IOrderedEnumerable<int> ordered = unordered.OrderBy(_ => 0);
switch (thenBys)
{
case 1: ordered = ordered.ThenBy(i => i); break;
case 2: ordered = ordered.ThenBy(i => 0).ThenBy(i => i); break;
case 3: ordered = ordered.ThenBy(i => 0).ThenBy(i => 0).ThenBy(i => i); break;
}
Assert.Equal(expected, ordered);
}
[Theory]
[InlineData(1)]
[InlineData(2)]
[InlineData(3)]
public void SortsLargeDescendingEnumerableCorrectly(int thenBys)
{
const int Items = 100_000;
IEnumerable<int> expected = NumberRangeGuaranteedNotCollectionType(0, Items);
IEnumerable<int> unordered = expected.Select(i => Items - i - 1);
IOrderedEnumerable<int> ordered = unordered.OrderBy(_ => 0);
switch (thenBys)
{
case 1: ordered = ordered.ThenBy(i => i); break;
case 2: ordered = ordered.ThenBy(i => 0).ThenBy(i => i); break;
case 3: ordered = ordered.ThenBy(i => 0).ThenBy(i => 0).ThenBy(i => i); break;
}
Assert.Equal(expected, ordered);
}
[Theory]
[InlineData(1)]
[InlineData(2)]
[InlineData(3)]
public void SortsLargeRandomizedEnumerableCorrectly(int thenBys)
{
const int Items = 100_000;
var r = new Random(42);
int[] randomized = Enumerable.Range(0, Items).Select(i => r.Next()).ToArray();
IOrderedEnumerable<int> orderedEnumerable = randomized.OrderBy(_ => 0);
switch (thenBys)
{
case 1: orderedEnumerable = orderedEnumerable.ThenBy(i => i); break;
case 2: orderedEnumerable = orderedEnumerable.ThenBy(i => 0).ThenBy(i => i); break;
case 3: orderedEnumerable = orderedEnumerable.ThenBy(i => 0).ThenBy(i => 0).ThenBy(i => i); break;
}
int[] ordered = orderedEnumerable.ToArray();
Array.Sort(randomized, (a, b) => a - b);
Assert.Equal(randomized, orderedEnumerable);
}
}
}