Skip to content

Commit 342bc7e

Browse files
authored
Use existing Range vectorized fill in Enumerable.OrderBy (#99538)
We already have a method that vectorizes the fill in Enumerable.Range. We can use the same helper in OrderBy when filling the integer map used to enable stability.
1 parent 19d7768 commit 342bc7e

File tree

3 files changed

+40
-42
lines changed

3 files changed

+40
-42
lines changed

src/libraries/System.Linq/src/System/Linq/OrderedEnumerable.cs

Lines changed: 2 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -339,12 +339,9 @@ private abstract class EnumerableSorter<TElement>
339339
private int[] ComputeMap(TElement[] elements, int count)
340340
{
341341
ComputeKeys(elements, count);
342-
int[] map = new int[count];
343-
for (int i = 0; i < map.Length; i++)
344-
{
345-
map[i] = i;
346-
}
347342

343+
int[] map = new int[count];
344+
FillIncrementing(map, 0);
348345
return map;
349346
}
350347

src/libraries/System.Linq/src/System/Linq/Range.SpeedOpt.cs

Lines changed: 3 additions & 37 deletions
Original file line numberDiff line numberDiff line change
@@ -2,9 +2,6 @@
22
// The .NET Foundation licenses this file to you under the MIT license.
33

44
using System.Collections.Generic;
5-
using System.Numerics;
6-
using System.Runtime.CompilerServices;
7-
using System.Runtime.InteropServices;
85

96
namespace System.Linq
107
{
@@ -21,51 +18,20 @@ public override int[] ToArray()
2118
{
2219
int start = _start;
2320
int[] array = new int[_end - start];
24-
Fill(array, start);
21+
FillIncrementing(array, start);
2522
return array;
2623
}
2724

2825
public override List<int> ToList()
2926
{
3027
(int start, int end) = (_start, _end);
3128
List<int> list = new List<int>(end - start);
32-
Fill(SetCountAndGetSpan(list, end - start), start);
29+
FillIncrementing(SetCountAndGetSpan(list, end - start), start);
3330
return list;
3431
}
3532

3633
public void CopyTo(int[] array, int arrayIndex) =>
37-
Fill(array.AsSpan(arrayIndex, _end - _start), _start);
38-
39-
private static void Fill(Span<int> destination, int value)
40-
{
41-
ref int pos = ref MemoryMarshal.GetReference(destination);
42-
ref int end = ref Unsafe.Add(ref pos, destination.Length);
43-
44-
if (Vector.IsHardwareAccelerated &&
45-
destination.Length >= Vector<int>.Count)
46-
{
47-
Vector<int> init = Vector<int>.Indices;
48-
Vector<int> current = new Vector<int>(value) + init;
49-
Vector<int> increment = new Vector<int>(Vector<int>.Count);
50-
51-
ref int oneVectorFromEnd = ref Unsafe.Subtract(ref end, Vector<int>.Count);
52-
do
53-
{
54-
current.StoreUnsafe(ref pos);
55-
current += increment;
56-
pos = ref Unsafe.Add(ref pos, Vector<int>.Count);
57-
}
58-
while (!Unsafe.IsAddressGreaterThan(ref pos, ref oneVectorFromEnd));
59-
60-
value = current[0];
61-
}
62-
63-
while (Unsafe.IsAddressLessThan(ref pos, ref end))
64-
{
65-
pos = value++;
66-
pos = ref Unsafe.Add(ref pos, 1);
67-
}
68-
}
34+
FillIncrementing(array.AsSpan(arrayIndex, _end - _start), _start);
6935

7036
public override int GetCount(bool onlyIfCheap) => _end - _start;
7137

src/libraries/System.Linq/src/System/Linq/Range.cs

Lines changed: 35 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -3,6 +3,9 @@
33

44
using System.Collections.Generic;
55
using System.Diagnostics;
6+
using System.Numerics;
7+
using System.Runtime.CompilerServices;
8+
using System.Runtime.InteropServices;
69

710
namespace System.Linq
811
{
@@ -71,5 +74,37 @@ public override void Dispose()
7174
_state = -1; // Don't reset current
7275
}
7376
}
77+
78+
/// <summary>Fills the <paramref name="destination"/> with incrementing numbers, starting from <paramref name="value"/>.</summary>
79+
private static void FillIncrementing(Span<int> destination, int value)
80+
{
81+
ref int pos = ref MemoryMarshal.GetReference(destination);
82+
ref int end = ref Unsafe.Add(ref pos, destination.Length);
83+
84+
if (Vector.IsHardwareAccelerated &&
85+
destination.Length >= Vector<int>.Count)
86+
{
87+
Vector<int> init = Vector<int>.Indices;
88+
Vector<int> current = new Vector<int>(value) + init;
89+
Vector<int> increment = new Vector<int>(Vector<int>.Count);
90+
91+
ref int oneVectorFromEnd = ref Unsafe.Subtract(ref end, Vector<int>.Count);
92+
do
93+
{
94+
current.StoreUnsafe(ref pos);
95+
current += increment;
96+
pos = ref Unsafe.Add(ref pos, Vector<int>.Count);
97+
}
98+
while (!Unsafe.IsAddressGreaterThan(ref pos, ref oneVectorFromEnd));
99+
100+
value = current[0];
101+
}
102+
103+
while (Unsafe.IsAddressLessThan(ref pos, ref end))
104+
{
105+
pos = value++;
106+
pos = ref Unsafe.Add(ref pos, 1);
107+
}
108+
}
74109
}
75110
}

0 commit comments

Comments
 (0)