|
using BenchmarkDotNet.Attributes; |
|
using System; |
|
using System.Linq; |
|
using System.Numerics; |
|
using System.Runtime.CompilerServices; |
|
using System.Runtime.InteropServices; |
|
|
|
namespace DotNetBenchmarks; |
|
|
|
[Config(typeof(BaseConfig))] |
|
public class GetFirstPositiveBenchmarks |
|
{ |
|
List<int>? list; |
|
|
|
[Params(1000)] |
|
public int Count { get; set; } |
|
|
|
[GlobalSetup] |
|
public void GlobalSetup() |
|
{ |
|
list = Enumerable.Range(-Count + 5, Count).ToList(); |
|
} |
|
|
|
[Benchmark(Baseline = true)] |
|
public void Enumerable_FirstOrDefault() |
|
=> GetFirstPositive(list!.AsEnumerable()); |
|
|
|
[Benchmark] |
|
public void Enumerable_Foreach() |
|
=> GetFirstPositive2(list!.AsEnumerable()); |
|
|
|
[Benchmark] |
|
public void List_Find() |
|
=> GetFirstPositive(list!); |
|
|
|
[Benchmark] |
|
public void List_ForEach() |
|
=> GetFirstPositive2(list!); |
|
|
|
static int GetFirstPositive(IEnumerable<int> source) |
|
=> source.FirstOrDefault(i => i > 0); |
|
|
|
static int GetFirstPositive2(IEnumerable<int> source) |
|
{ |
|
foreach (var item in source) |
|
{ |
|
if (item > 0) |
|
return item; |
|
} |
|
return default; |
|
} |
|
|
|
static int GetFirstPositive(List<int> source) |
|
=> source.Find(i => i > 0); |
|
|
|
static int GetFirstPositive2(List<int> source) |
|
=> GetFirstPositive(CollectionsMarshal.AsSpan(source)); |
|
|
|
static int GetFirstPositive(ReadOnlySpan<int> source) |
|
{ |
|
var indexSource = nint.Zero; |
|
|
|
if (Vector.IsHardwareAccelerated) |
|
{ |
|
var vectors = MemoryMarshal.Cast<int, Vector<int>>(source); |
|
ref var vectorsRef = ref MemoryMarshal.GetReference(vectors); |
|
var zeroVector = Vector<int>.Zero; |
|
|
|
var indexVector = nint.Zero; |
|
for (; indexVector < vectors.Length; indexVector++) |
|
{ |
|
ref var currentVector = ref Unsafe.Add(ref vectorsRef, indexVector); |
|
if (Vector.GreaterThanAny(currentVector, zeroVector)) |
|
{ |
|
for (var index = 0; index < Vector<int>.Count; index++) |
|
{ |
|
if (currentVector.GetElement(index) > 0) |
|
return currentVector.GetElement(index); |
|
} |
|
} |
|
} |
|
|
|
indexSource = indexVector * Vector<int>.Count; |
|
} |
|
|
|
ref var sourceRef = ref MemoryMarshal.GetReference(source); |
|
for (; indexSource < source.Length; indexSource++) |
|
{ |
|
if (Unsafe.Add(ref sourceRef, indexSource) > 0) |
|
return Unsafe.Add(ref sourceRef, indexSource); |
|
} |
|
|
|
return default; |
|
} |
|
|
|
} |