From 1f593d39c47fab0510dd015d0886f9ad0f831575 Mon Sep 17 00:00:00 2001 From: yesmey Date: Sun, 27 Mar 2022 22:51:06 +0200 Subject: [PATCH] Allow List to be unrolled/vectorized in IEnumerable SequenceEqual --- src/libraries/System.Linq/src/System/Linq/Enumerable.cs | 8 +++++--- .../System.Linq/src/System/Linq/SequenceEqual.cs | 4 ++-- 2 files changed, 7 insertions(+), 5 deletions(-) diff --git a/src/libraries/System.Linq/src/System/Linq/Enumerable.cs b/src/libraries/System.Linq/src/System/Linq/Enumerable.cs index 6e3b2d772609dd..368794f747e7ea 100644 --- a/src/libraries/System.Linq/src/System/Linq/Enumerable.cs +++ b/src/libraries/System.Linq/src/System/Linq/Enumerable.cs @@ -2,6 +2,7 @@ // The .NET Foundation licenses this file to you under the MIT license. using System.Collections.Generic; +using System.Diagnostics; using System.Runtime.CompilerServices; using System.Runtime.InteropServices; @@ -14,12 +15,13 @@ public static partial class Enumerable /// Validates that source is not null and then tries to extract a span from the source. [MethodImpl(MethodImplOptions.AggressiveInlining)] // fast type checks that don't add a lot of overhead private static bool TryGetSpan(this IEnumerable source, out ReadOnlySpan span) + { // This constraint isn't required, but the overheads involved here can be more substantial when TSource - // is a reference type and generic implementations are shared. So for now we're protecting ourselves + // is a reference type and generic implementations are shared. So for now we're protecting ourselves // and forcing a conscious choice to remove this in the future, at which point it should be paired with // sufficient performance testing. - where TSource : struct - { + Debug.Assert(typeof(TSource).IsValueType); + if (source is null) { ThrowHelper.ThrowArgumentNullException(ExceptionArgument.source); diff --git a/src/libraries/System.Linq/src/System/Linq/SequenceEqual.cs b/src/libraries/System.Linq/src/System/Linq/SequenceEqual.cs index d1d6dc1586b0f5..5badacd1118c7d 100644 --- a/src/libraries/System.Linq/src/System/Linq/SequenceEqual.cs +++ b/src/libraries/System.Linq/src/System/Linq/SequenceEqual.cs @@ -24,9 +24,9 @@ public static bool SequenceEqual(this IEnumerable first, IEnum if (first is ICollection firstCol && second is ICollection secondCol) { - if (first is TSource[] firstArray && second is TSource[] secondArray) + if (typeof(TSource).IsValueType && first.TryGetSpan(out ReadOnlySpan firstSpan) && second.TryGetSpan(out ReadOnlySpan secondSpan)) { - return ((ReadOnlySpan)firstArray).SequenceEqual(secondArray, comparer); + return firstSpan.SequenceEqual(secondSpan, comparer); } if (firstCol.Count != secondCol.Count)