-
Notifications
You must be signed in to change notification settings - Fork 4.9k
[WIP] Add Sort(...) extension methods for Span<T> #26859
Changes from all commits
92702fe
0c99da2
48f655d
57eb72f
2b8b08f
4272823
25fc3c6
22d819b
ba1da6a
ec77c64
4f500a3
4f2f822
758762b
fcb63b5
eff4ab4
0d99df1
03b1bef
84691a2
c8dff35
5352890
c109f6a
48be72d
7468485
78aa18c
07b0105
04c5c0b
ced09bd
4259560
9527a49
146029f
e44b8b6
596df18
File filter
Filter by extension
Conversations
Jump to
Diff view
Diff view
There are no files selected for viewing
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,125 @@ | ||
// 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.Diagnostics; | ||
using System.Runtime.CompilerServices; | ||
|
||
#if !netstandard | ||
using Internal.Runtime.CompilerServices; | ||
#endif | ||
|
||
namespace System | ||
{ | ||
internal static partial class SpanSortHelpersCommon | ||
{ | ||
// This is the threshold where Introspective sort switches to Insertion sort. | ||
// Empirically, 16 seems to speed up most cases without slowing down others, at least for integers. | ||
// Large value types may benefit from a smaller number. | ||
internal const int IntrosortSizeThreshold = 16; | ||
|
||
internal static int FloorLog2PlusOne(int n) | ||
{ | ||
Debug.Assert(n >= 2); | ||
int result = 2; | ||
n >>= 2; | ||
while (n > 0) | ||
{ | ||
++result; | ||
n >>= 1; | ||
} | ||
return result; | ||
} | ||
|
||
[MethodImpl(MethodImplOptions.AggressiveInlining)] | ||
internal static void Swap<T>(ref T items, int i, int j) | ||
{ | ||
Debug.Assert(i != j); | ||
Swap(ref Unsafe.Add(ref items, i), ref Unsafe.Add(ref items, j)); | ||
} | ||
|
||
[MethodImpl(MethodImplOptions.AggressiveInlining)] | ||
internal static void Swap<T>(ref T a, ref T b) | ||
{ | ||
T temp = a; | ||
a = b; | ||
b = temp; | ||
} | ||
|
||
// This started out with just LessThan. | ||
// However, due to bogus comparers, comparables etc. | ||
// we need to preserve semantics completely to get same result. | ||
internal interface IDirectComparer<in T> | ||
{ | ||
bool GreaterThan(T x, T y); | ||
bool LessThan(T x, T y); | ||
} | ||
|
||
// | ||
// Type specific DirectComparer(s) to ensure optimal code-gen | ||
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. Are these type-specific structs really necessary for optimal code-gen? cc @AndyAyersMS There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. @nietras can you compare perf with and without these extra comparers, and if it's quite different, show the key bits of generated code? Also there still seems to be a healthy dose of Also (not necessarily critiquing this change, just wondering aloud) it seems like the same algorithmic patterns are duplicated across different comparison contexts, and I wonder if there is some way to avoid this, or whether we are missing language features and/or concepts that would allow there to be one master version that gets appropriately specialized and optimized, or whether this is just how things are done for now. I know we haven't put the effort into optimizing general comparers the way we have for equality comparers -- maybe we should? There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. @AndyAyersMS perf is significantly lower if using So yes, these are necessary, and I would really like for perf to be good on existing runtimes. |
||
// | ||
internal struct SByteDirectComparer : IDirectComparer<sbyte> | ||
{ | ||
public bool GreaterThan(sbyte x, sbyte y) => x > y; | ||
public bool LessThan(sbyte x, sbyte y) => x < y; | ||
} | ||
internal struct ByteDirectComparer : IDirectComparer<byte> | ||
{ | ||
public bool GreaterThan(byte x, byte y) => x > y; | ||
public bool LessThan(byte x, byte y) => x < y; | ||
} | ||
internal struct Int16DirectComparer : IDirectComparer<short> | ||
{ | ||
public bool GreaterThan(short x, short y) => x > y; | ||
public bool LessThan(short x, short y) => x < y; | ||
} | ||
internal struct UInt16DirectComparer : IDirectComparer<ushort> | ||
{ | ||
public bool GreaterThan(ushort x, ushort y) => x > y; | ||
public bool LessThan(ushort x, ushort y) => x < y; | ||
} | ||
internal struct Int32DirectComparer : IDirectComparer<int> | ||
{ | ||
public bool GreaterThan(int x, int y) => x > y; | ||
public bool LessThan(int x, int y) => x < y; | ||
} | ||
internal struct UInt32DirectComparer : IDirectComparer<uint> | ||
{ | ||
public bool GreaterThan(uint x, uint y) => x > y; | ||
public bool LessThan(uint x, uint y) => x < y; | ||
} | ||
internal struct Int64DirectComparer : IDirectComparer<long> | ||
{ | ||
public bool GreaterThan(long x, long y) => x > y; | ||
public bool LessThan(long x, long y) => x < y; | ||
} | ||
internal struct UInt64DirectComparer : IDirectComparer<ulong> | ||
{ | ||
public bool GreaterThan(ulong x, ulong y) => x > y; | ||
public bool LessThan(ulong x, ulong y) => x < y; | ||
} | ||
internal struct SingleDirectComparer : IDirectComparer<float> | ||
{ | ||
public bool GreaterThan(float x, float y) => x > y; | ||
public bool LessThan(float x, float y) => x < y; | ||
} | ||
internal struct DoubleDirectComparer : IDirectComparer<double> | ||
{ | ||
public bool GreaterThan(double x, double y) => x > y; | ||
public bool LessThan(double x, double y) => x < y; | ||
} | ||
|
||
internal interface IIsNaN<T> | ||
{ | ||
bool IsNaN(T value); | ||
} | ||
internal struct SingleIsNaN : IIsNaN<float> | ||
{ | ||
public bool IsNaN(float value) => float.IsNaN(value); | ||
} | ||
internal struct DoubleIsNaN : IIsNaN<double> | ||
{ | ||
public bool IsNaN(double value) => double.IsNaN(value); | ||
} | ||
} | ||
} |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
nice: new line.
Generate the reference using our tool.
Run
msbuild /t:GenerateReferenceSource
from the S.Memory source directory.cc @weshaggard if you have any questions.