|
using BenchmarkDotNet.Attributes; |
|
using BenchmarkDotNet.Configs; |
|
using System; |
|
using System.Collections; |
|
using System.Collections.Generic; |
|
|
|
namespace Benchmarks |
|
{ |
|
[GroupBenchmarksBy(BenchmarkLogicalGroupRule.ByCategory)] |
|
[CategoriesColumn] |
|
[MemoryDiagnoser] |
|
[MarkdownExporterAttribute.GitHub] |
|
public class ValueEnumerableBenchmarks |
|
{ |
|
RangeEnumerable source; |
|
|
|
[Params(0, 1_000, 100_000)] |
|
public int Count { get; set; } |
|
|
|
[GlobalSetup] |
|
public void GlobalSetup() |
|
{ |
|
source = new RangeEnumerable(Count); |
|
} |
|
|
|
[BenchmarkCategory("Count")] |
|
[Benchmark(Baseline = true)] |
|
public int Enumerator() => |
|
CountEnumerable<RangeEnumerable, RangeEnumerable.Enumerator, int>(source); |
|
|
|
[BenchmarkCategory("Count_Predicate")] |
|
[Benchmark(Baseline = true)] |
|
public int Enumerator_Predicate() => |
|
CountEnumerable<RangeEnumerable, RangeEnumerable.Enumerator, int>(source, _ => true); |
|
|
|
[BenchmarkCategory("Count")] |
|
[Benchmark] |
|
public int MyEnumerator() => |
|
CountMyEnumerable<RangeEnumerable, RangeEnumerable.MyEnumerator, int>(source); |
|
|
|
[BenchmarkCategory("Count_Predicate")] |
|
[Benchmark] |
|
public int MyEnumerator_Predicate() => |
|
CountMyEnumerable<RangeEnumerable, RangeEnumerable.MyEnumerator, int>(source, _ => true); |
|
|
|
[BenchmarkCategory("Count")] |
|
[Benchmark] |
|
public int BenValueEnumerator() => |
|
CountBenValueEnumerable<RangeEnumerable, RangeEnumerable.BenValueEnumerator, int>(source); |
|
|
|
[BenchmarkCategory("Count_Predicate")] |
|
[Benchmark] |
|
public int BenValueEnumerator_Predicate() => |
|
CountBenValueEnumerable<RangeEnumerable, RangeEnumerable.BenValueEnumerator, int>(source, _ => true); |
|
|
|
[BenchmarkCategory("Count")] |
|
[Benchmark] |
|
public int MyValueEnumerator() => |
|
CountMyValueEnumerable<RangeEnumerable, RangeEnumerable.MyValueEnumerator, int>(source); |
|
|
|
[BenchmarkCategory("Count_Predicate")] |
|
[Benchmark] |
|
public int MyValueEnumerator_Predicate() => |
|
CountMyValueEnumerable<RangeEnumerable, RangeEnumerable.MyValueEnumerator, int>(source, _ => true); |
|
|
|
static int CountEnumerable<TEnumerable, TEnumerator, TSource>(TEnumerable source) |
|
where TEnumerable : IEnumerable<TSource> |
|
where TEnumerator: IEnumerator<TSource> |
|
{ |
|
var count = 0; |
|
using(var enumerator = (TEnumerator)source.GetEnumerator()) |
|
{ |
|
while (enumerator.MoveNext()) |
|
count++; |
|
} |
|
return count; |
|
} |
|
|
|
static int CountEnumerable<TEnumerable, TEnumerator, TSource>(TEnumerable source, Func<TSource, bool> predicate) |
|
where TEnumerable : IEnumerable<TSource> |
|
where TEnumerator: IEnumerator<TSource> |
|
{ |
|
var count = 0; |
|
using(var enumerator = (TEnumerator)source.GetEnumerator()) |
|
{ |
|
while (enumerator.MoveNext()) |
|
{ |
|
if (predicate(enumerator.Current)) |
|
count++; |
|
} |
|
} |
|
return count; |
|
} |
|
|
|
static int CountMyEnumerable<TEnumerable, TEnumerator, TSource>(TEnumerable source) |
|
where TEnumerable : IMyEnumerable<TSource> |
|
where TEnumerator: IMyEnumerator<TSource> |
|
{ |
|
var count = 0; |
|
using(var enumerator = (TEnumerator)source.GetEnumerator()) |
|
{ |
|
while (enumerator.MoveNext()) |
|
count++; |
|
} |
|
return count; |
|
} |
|
|
|
static int CountMyEnumerable<TEnumerable, TEnumerator, TSource>(TEnumerable source, Func<TSource, bool> predicate) |
|
where TEnumerable : IMyEnumerable<TSource> |
|
where TEnumerator: IMyEnumerator<TSource> |
|
{ |
|
var count = 0; |
|
using(var enumerator = (TEnumerator)source.GetEnumerator()) |
|
{ |
|
while (enumerator.MoveNext()) |
|
{ |
|
if (predicate(enumerator.Current)) |
|
count++; |
|
} |
|
} |
|
return count; |
|
} |
|
|
|
static int CountBenValueEnumerable<TEnumerable, TEnumerator, TSource>(TEnumerable source) |
|
where TEnumerable : IBenValueEnumerable<TSource, TEnumerator> |
|
where TEnumerator : struct, IBenValueEnumerator<TSource> |
|
{ |
|
var count = 0; |
|
using (var enumerator = source.GetValueEnumerator()) |
|
{ |
|
while (enumerator.TryMoveNext()) |
|
count++; |
|
} |
|
return count; |
|
} |
|
|
|
static int CountBenValueEnumerable<TEnumerable, TEnumerator, TSource>(TEnumerable source, Func<TSource, bool> predicate) |
|
where TEnumerable : IBenValueEnumerable<TSource, TEnumerator> |
|
where TEnumerator : struct, IBenValueEnumerator<TSource> |
|
{ |
|
var count = 0; |
|
using (var enumerator = source.GetValueEnumerator()) |
|
{ |
|
var current = enumerator.TryGetNext(out var success); |
|
while (success) |
|
{ |
|
if (predicate(current)) |
|
count++; |
|
|
|
current = enumerator.TryGetNext(out success); |
|
} |
|
} |
|
return count; |
|
} |
|
|
|
static int CountMyValueEnumerable<TEnumerable, TEnumerator, TSource>(TEnumerable source) |
|
where TEnumerable : IMyValueEnumerable<TEnumerator, TSource> |
|
where TEnumerator : struct, IMyValueEnumerator<TSource> |
|
{ |
|
var count = 0; |
|
using(var enumerator = source.GetValueEnumerator()) |
|
{ |
|
while (enumerator.TryMoveNext()) |
|
count++; |
|
} |
|
return count; |
|
} |
|
|
|
static int CountMyValueEnumerable<TEnumerable, TEnumerator, TSource>(TEnumerable source, Func<TSource, bool> predicate) |
|
where TEnumerable : IMyValueEnumerable<TEnumerator, TSource> |
|
where TEnumerator : struct, IMyValueEnumerator<TSource> |
|
{ |
|
var count = 0; |
|
using(var enumerator = source.GetValueEnumerator()) |
|
{ |
|
while (enumerator.TryMoveNext(out var current)) |
|
{ |
|
if (predicate(current)) |
|
count++; |
|
} |
|
} |
|
return count; |
|
} |
|
|
|
public interface IMyEnumerator<T> : IDisposable |
|
{ |
|
T Current { get; } |
|
bool MoveNext(); |
|
} |
|
|
|
public interface IMyEnumerable<T> |
|
{ |
|
IMyEnumerator<T> GetEnumerator(); |
|
} |
|
|
|
public interface IBenValueEnumerator : IDisposable |
|
{ |
|
bool TryMoveNext(); |
|
} |
|
|
|
public interface IBenValueEnumerator<T> : IBenValueEnumerator |
|
{ |
|
T TryGetNext(out bool success); |
|
} |
|
|
|
public interface IBenValueEnumerable<TEnumerator> |
|
where TEnumerator : struct, IBenValueEnumerator |
|
{ |
|
TEnumerator GetValueEnumerator(); |
|
} |
|
|
|
public interface IBenValueEnumerable<T, TEnumerator> |
|
where TEnumerator : struct, IBenValueEnumerator<T> |
|
{ |
|
TEnumerator GetValueEnumerator(); |
|
} |
|
|
|
public interface IMyValueEnumerator<T> : IDisposable |
|
{ |
|
bool TryMoveNext(); |
|
bool TryMoveNext(out T current); |
|
} |
|
|
|
public interface IMyValueEnumerable<TEnumerator, T> |
|
where TEnumerator : struct, IMyValueEnumerator<T> |
|
{ |
|
TEnumerator GetValueEnumerator(); |
|
} |
|
|
|
public readonly struct RangeEnumerable |
|
: IEnumerable<int> |
|
, IMyEnumerable<int> |
|
, IBenValueEnumerable<int, RangeEnumerable.BenValueEnumerator> |
|
, IMyValueEnumerable<RangeEnumerable.MyValueEnumerator, int> |
|
{ |
|
readonly int count; |
|
|
|
internal RangeEnumerable(int count) |
|
{ |
|
this.count = count; |
|
} |
|
|
|
public Enumerator GetEnumerator() => new Enumerator(count); |
|
IEnumerator<int> IEnumerable<int>.GetEnumerator() => new Enumerator(count); |
|
IEnumerator IEnumerable.GetEnumerator() => new Enumerator(count); |
|
|
|
public MyEnumerator GetMyEnumerator() => new MyEnumerator(count); |
|
IMyEnumerator<int> IMyEnumerable<int>.GetEnumerator() => new MyEnumerator(count); |
|
|
|
public BenValueEnumerator GetBenValueEnumerator() => new BenValueEnumerator(count); |
|
BenValueEnumerator IBenValueEnumerable<int, RangeEnumerable.BenValueEnumerator>.GetValueEnumerator() => new BenValueEnumerator(count); |
|
|
|
public MyValueEnumerator GetMyValueEnumerator() => new MyValueEnumerator(count); |
|
MyValueEnumerator IMyValueEnumerable<RangeEnumerable.MyValueEnumerator, int>.GetValueEnumerator() => new MyValueEnumerator(count); |
|
|
|
public struct Enumerator : IEnumerator<int> |
|
{ |
|
readonly int count; |
|
int current; |
|
|
|
internal Enumerator(int count) |
|
{ |
|
this.count = count; |
|
current = -1; |
|
} |
|
|
|
public int Current => current; |
|
object IEnumerator.Current => current; |
|
|
|
public bool MoveNext() => ++current < count; |
|
|
|
public void Reset() => throw new NotSupportedException(); |
|
|
|
public void Dispose() { } |
|
} |
|
|
|
public struct MyEnumerator : IMyEnumerator<int> |
|
{ |
|
readonly int count; |
|
int current; |
|
|
|
internal MyEnumerator(int count) |
|
{ |
|
this.count = count; |
|
current = -1; |
|
} |
|
|
|
public int Current => current; |
|
|
|
public bool MoveNext() => ++current < count; |
|
|
|
public void Dispose() { } |
|
} |
|
|
|
public struct BenValueEnumerator : IBenValueEnumerator<int> |
|
{ |
|
readonly int count; |
|
int current; |
|
|
|
internal BenValueEnumerator(int count) |
|
{ |
|
this.count = count; |
|
current = -1; |
|
} |
|
|
|
public int TryGetNext(out bool success) |
|
{ |
|
success = ++current < count; |
|
if (success) |
|
return current; |
|
|
|
return default; |
|
} |
|
|
|
public bool TryMoveNext() => ++current < count; |
|
|
|
public void Dispose() { } |
|
} |
|
|
|
public struct MyValueEnumerator : IMyValueEnumerator<int> |
|
{ |
|
readonly int count; |
|
int current; |
|
|
|
internal MyValueEnumerator(int count) |
|
{ |
|
this.count = count; |
|
current = -1; |
|
} |
|
|
|
public bool TryMoveNext(out int current) |
|
{ |
|
if (++this.current < count) |
|
{ |
|
current = this.current; |
|
return true; |
|
} |
|
|
|
current = default; |
|
return false; |
|
} |
|
|
|
public bool TryMoveNext() => ++current < count; |
|
|
|
public void Dispose() { } |
|
} |
|
} |
|
} |
|
} |