Last active
August 21, 2020 18:48
-
-
Save badamczewski/e0cd62c25b20311104a666cde4c61a53 to your computer and use it in GitHub Desktop.
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
| Method | Mean | Error | StdDev | Ratio | RatioSD | | |
|------------------------------------- |----------:|----------:|----------:|------:|--------:| | |
| SkipLinq | 47.386 ns | 0.4797 ns | 0.4487 ns | 1.00 | 0.00 | | |
| SkipHyperLinq | 31.090 ns | 0.3779 ns | 0.3350 ns | 0.66 | 0.01 | | |
| SkipLinq_Custom_List | 73.336 ns | 1.3644 ns | 1.2095 ns | 1.55 | 0.03 | | |
| SkipLinq_Custom_List_2 | 71.604 ns | 1.3169 ns | 1.4090 ns | 1.51 | 0.03 | | |
| SkipLinq_Custom_Enumerable | 48.463 ns | 0.7997 ns | 0.7089 ns | 1.02 | 0.02 | | |
| SkipLinq_Custom_Enumerable_AsClass | 40.907 ns | 0.3217 ns | 0.2687 ns | 0.86 | 0.01 | | |
| SkipLinq_Custom_Enumerable_DF_NoVirt | 2.329 ns | 0.0407 ns | 0.0340 ns | 0.05 | 0.00 | | |
CODE: | |
public class Benchmark | |
{ | |
private List<int> list; | |
[GlobalSetup] | |
public void Global() | |
{ | |
list = Enumerable.Range(0, 15).ToList(); | |
} | |
[Benchmark(Baseline = true)] | |
public int SkipLinq() | |
{ | |
return LinqPerf_6.SkipLinq(list, 9); | |
} | |
[Benchmark] | |
public int SkipHyperLinq() | |
{ | |
return list.Skip(9).FirstOrDefault(); | |
} | |
[Benchmark] | |
public int SkipLinq_Custom_List() | |
{ | |
return LinqPerf_6.SkipLinq_Custom_List(list, 9); | |
} | |
[Benchmark] | |
public int SkipLinq_Custom_List_2() | |
{ | |
return LinqPerf_6.SkipLinq_Custom_List_2(list, 9); | |
} | |
[Benchmark] | |
public int SkipLinq_Custom_Enumerable() | |
{ | |
return LinqPerf_6.SkipLinq_Custom_Enumerable(list, 9); | |
} | |
[Benchmark] | |
public int SkipLinq_Custom_Enumerable_AsClass() | |
{ | |
return LinqPerf_6.SkipLinq_Custom_Enumerable_AsClass(list, 9); | |
} | |
[Benchmark] | |
public int SkipLinq_Custom_Enumerable_DF_NoVirt() | |
{ | |
return LinqPerf_6.SkipLinq_Custom_Enumerable_DF_NoVirt(list, 9); | |
} | |
} |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
public readonly struct SkipEnumerable<TSource> : IEnumerable<TSource> | |
{ | |
public readonly int skip; | |
public readonly List<TSource> source; | |
public SkipEnumerable(List<TSource> source, int skip) | |
{ | |
this.skip = skip; | |
this.source = source; | |
} | |
public SkipEnumerable(SkipEnumerable<TSource> source, int skip) | |
{ | |
this.skip = source.skip + skip; | |
this.source = source.source; | |
} | |
[MethodImpl(MethodImplOptions.AggressiveInlining)] | |
public Enumerator GetEnumerator() | |
{ | |
return new Enumerator(in this); | |
} | |
IEnumerator IEnumerable.GetEnumerator() | |
{ | |
return new Enumerator(in this); | |
} | |
IEnumerator<TSource> IEnumerable<TSource>.GetEnumerator() | |
{ | |
return new Enumerator(in this); | |
} | |
public struct Enumerator : IEnumerator<TSource> | |
{ | |
readonly List<TSource> source; | |
public int index; | |
public Enumerator(in SkipEnumerable<TSource> skip) | |
{ | |
index = -1; | |
this.source = skip.source; | |
this.index += skip.skip; | |
} | |
public TSource Current | |
{ | |
[MethodImpl(MethodImplOptions.AggressiveInlining)] | |
get => source[index]; | |
} | |
object IEnumerator.Current => throw new NotImplementedException(); | |
public void Dispose() | |
{ | |
} | |
[MethodImpl(MethodImplOptions.AggressiveInlining)] | |
public bool MoveNext() | |
{ | |
if (++index < source.Count) | |
{ | |
return true; | |
} | |
return false; | |
} | |
public void Reset() | |
{ | |
} | |
} | |
} | |
public class SkipEnumerableClass<TSource> : IEnumerable<TSource> | |
{ | |
public readonly int skip; | |
public readonly List<TSource> source; | |
public SkipEnumerableClass(List<TSource> source, int skip) | |
{ | |
this.skip = skip; | |
this.source = source; | |
} | |
[MethodImpl(MethodImplOptions.AggressiveInlining)] | |
public Enumerator GetEnumerator() | |
{ | |
return new Enumerator(this); | |
} | |
IEnumerator IEnumerable.GetEnumerator() | |
{ | |
return new Enumerator(this); | |
} | |
IEnumerator<TSource> IEnumerable<TSource>.GetEnumerator() | |
{ | |
return new Enumerator(this); | |
} | |
public class Enumerator : IEnumerator<TSource> | |
{ | |
readonly List<TSource> source; | |
public int index; | |
public Enumerator(in SkipEnumerableClass<TSource> skip) | |
{ | |
index = -1; | |
this.source = skip.source; | |
this.index += skip.skip; | |
} | |
public TSource Current | |
{ | |
[MethodImpl(MethodImplOptions.AggressiveInlining)] | |
get => source[index]; | |
} | |
object IEnumerator.Current => throw new NotImplementedException(); | |
public void Dispose() | |
{ | |
} | |
[MethodImpl(MethodImplOptions.AggressiveInlining)] | |
public bool MoveNext() | |
{ | |
if (++index < source.Count) | |
{ | |
return true; | |
} | |
return false; | |
} | |
public void Reset() | |
{ | |
} | |
} | |
} | |
public static class SuperLinq | |
{ | |
public static IEnumerable<TSource> SkipLinq_Custom_Enumerable<TSource>(this List<TSource> source, int count) | |
{ | |
return new SkipEnumerable<TSource>(source, count); | |
} | |
public static IEnumerable<TSource> SkipLinq_Custom_Enumerable_AsClass<TSource>(this List<TSource> source, int count) | |
{ | |
return new SkipEnumerableClass<TSource>(source, count); | |
} | |
public static SkipEnumerable<TSource> SkipLinq_Custom_Enumerable_DF_NoVirt<TSource>(this List<TSource> source, int count) | |
{ | |
return new SkipEnumerable<TSource>(source, count); | |
} | |
public static SkipEnumerable<TSource> SkipLinq_Custom_Enumerable_DF_NoVirt<TSource>(this SkipEnumerable<TSource> source, int count) | |
{ | |
return new SkipEnumerable<TSource>(source, count); | |
} | |
public static IEnumerable<TSource> SkipLinq_Custom_List<TSource>(this IEnumerable<TSource> source, int count) | |
{ | |
if (source is IList<TSource>) | |
{ | |
IList<TSource> list = (IList<TSource>)source; | |
for (int i = count; i < list.Count; i++) | |
{ | |
yield return list[i]; | |
} | |
} | |
else | |
{ | |
using (IEnumerator<TSource> e = source.GetEnumerator()) | |
{ | |
while (count > 0 && e.MoveNext()) count--; | |
if (count <= 0) | |
{ | |
while (e.MoveNext()) yield return e.Current; | |
} | |
} | |
} | |
} | |
public static IEnumerable<TSource> SkipLinq_Custom_List_2<TSource>(this List<TSource> source, int count) | |
{ | |
if (source == null) throw new ArgumentNullException(); | |
using (var e = source.GetEnumerator()) | |
{ | |
var list = source; | |
for (int i = count; i < list.Count; i++) | |
{ | |
e.MoveNext(); | |
yield return list[i]; | |
} | |
} | |
} | |
public static IEnumerable<TSource> Where_Custom<TSource>(this List<TSource> source, Func<TSource, bool> predicate) | |
{ | |
List<TSource> result = new List<TSource>(); | |
foreach (var item in source) | |
{ | |
if (predicate(item)) | |
result.Add(item); | |
} | |
return result; | |
} | |
public static IEnumerable<TSource> WhereLinq_Custom_WhereEnumerable<TSource>(this List<TSource> source, Func<TSource, bool> predicate) | |
{ | |
if (source == null || predicate == null) throw new ArgumentNullException(); | |
return new WhereCustomEnumerable<TSource>(source, predicate); | |
} | |
public static WhereCustomEnumerable<TSource> | |
WhereLinq_Custom_WhereEnumerable_Better<TSource> | |
(this List<TSource> source, Func<TSource, bool> predicate) | |
{ | |
if (source == null || predicate == null) throw new ArgumentNullException(); | |
var where = new WhereCustomEnumerable<TSource>(source, predicate); | |
return where; | |
} | |
public static TSource FirstOrDefault<TSource>( | |
this RefList<TSource> source, Func<TSource, bool> predicate) | |
{ | |
foreach (var item in source) | |
{ | |
if (predicate(item)) | |
return item; | |
} | |
return default(TSource); | |
} | |
public static List<TSource> ToList_Custom<TSource>(this WhereCustomEnumerable<TSource> where) | |
{ | |
if (where.source == null) throw new ArgumentNullException(); | |
var list = new List<TSource>(where.source.Count); | |
foreach (var e in where) | |
{ | |
list.Add(e); | |
} | |
return list; | |
} | |
public static TSource FirstOrDefault_Custom<TSource>(this IEnumerable<TSource> source, Func<TSource, bool> predicate) | |
{ | |
if (source is List<TSource>) | |
{ | |
List<TSource> list = (List<TSource>)source; | |
foreach (var item in list) | |
{ | |
if (predicate(item)) return item; | |
} | |
return default(TSource); | |
} | |
foreach (var item in source) | |
{ | |
if (predicate(item)) return item; | |
} | |
return default(TSource); | |
} | |
public static TSource FirstOrDefault_Custom<TSource>(this SkipEnumerable<TSource> source) | |
{ | |
if (source.source == null) throw new ArgumentNullException(); | |
if (source.source.Count > 0) | |
{ | |
using (var e = source.GetEnumerator()) | |
{ | |
e.MoveNext(); | |
return e.Current; | |
} | |
} | |
return default(TSource); | |
} | |
public static TSource FirstOrDefault_Custom2<TSource>(this IEnumerable<TSource> source) | |
{ | |
if (source == null) throw new ArgumentNullException(); | |
using (var e = source.GetEnumerator()) | |
{ | |
e.MoveNext(); | |
return e.Current; | |
} | |
throw new ArgumentException(); | |
} | |
//public static TSource Last<TSource>(this IEnumerable<TSource> source) | |
//{ | |
// if (source is IList<TSource> listSource) | |
// { | |
// return listSource[listSource.Count - 1]; | |
// } | |
// TSource last = default(TSource); | |
// foreach (var item in source) | |
// { | |
// last = item; | |
// } | |
// return last; | |
//} | |
//public static TSource Last<TSource>(this IList<TSource> source) | |
//{ | |
// return source[source.Count - 1]; | |
//} | |
//public static TSource Last_Custom<TSource>(this IEnumerable<TSource> source) | |
//{ | |
// if (source is IList<TSource> listSource) | |
// { | |
// return listSource[listSource.Count - 1]; | |
// } | |
//} | |
} | |
public readonly struct WhereCustomEnumerable<TSource> : IEnumerable<TSource> | |
{ | |
public readonly Func<TSource, bool> predicate; | |
public readonly List<TSource> source; | |
public WhereCustomEnumerable(List<TSource> source, Func<TSource, bool> predicate) | |
{ | |
this.predicate = predicate; | |
this.source = source; | |
} | |
[MethodImpl(MethodImplOptions.AggressiveInlining)] | |
public Enumerator GetEnumerator() | |
{ | |
return new Enumerator(in this); | |
} | |
IEnumerator IEnumerable.GetEnumerator() | |
{ | |
return new Enumerator(in this); | |
} | |
IEnumerator<TSource> IEnumerable<TSource>.GetEnumerator() | |
{ | |
return new Enumerator(in this); | |
} | |
public struct Enumerator : IEnumerator<TSource> | |
{ | |
readonly List<TSource> source; | |
readonly Func<TSource, bool> predicate; | |
private int index; | |
public Enumerator(in WhereCustomEnumerable<TSource> where) | |
{ | |
index = -1; | |
this.source = where.source; | |
this.predicate = where.predicate; | |
} | |
public TSource Current | |
{ | |
[MethodImpl(MethodImplOptions.AggressiveInlining)] | |
get => source[index]; | |
} | |
object IEnumerator.Current => throw new NotImplementedException(); | |
public void Dispose() | |
{ | |
} | |
[MethodImpl(MethodImplOptions.AggressiveInlining)] | |
public bool MoveNext() | |
{ | |
while (++index < source.Count) | |
{ | |
if (predicate(source[index])) | |
return true; | |
} | |
return false; | |
} | |
public void Reset() | |
{ | |
} | |
} | |
} |
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment