Skip to content

Commit

Permalink
Do not allow composition of WhereRef
Browse files Browse the repository at this point in the history
  • Loading branch information
aalmada committed Jul 9, 2020
1 parent 5679981 commit 43d48a2
Show file tree
Hide file tree
Showing 10 changed files with 342 additions and 723 deletions.
112 changes: 35 additions & 77 deletions NetFabric.Hyperlinq/Filtering/WhereRef/WhereRef.ArraySegment.cs
Original file line number Diff line number Diff line change
@@ -1,7 +1,5 @@
using System;
using System.Collections;
using System.Collections.Generic;
using System.Diagnostics.CodeAnalysis;
using System.Runtime.CompilerServices;

namespace NetFabric.Hyperlinq
Expand All @@ -12,8 +10,8 @@ public static partial class ArrayExtensions
public static WhereRefEnumerable<TSource> WhereRef<TSource>(this in ArraySegment<TSource> source, Predicate<TSource> predicate)
=> new WhereRefEnumerable<TSource>(source, predicate);

public readonly partial struct WhereRefEnumerable<TSource>
: IValueEnumerable<TSource, WhereRefEnumerable<TSource>.DisposableEnumerator>
[GeneratorIgnore]
public readonly struct WhereRefEnumerable<TSource>
{
readonly ArraySegment<TSource> source;
readonly Predicate<TSource> predicate;
Expand All @@ -22,14 +20,8 @@ internal WhereRefEnumerable(in ArraySegment<TSource> source, Predicate<TSource>
=> (this.source, this.predicate) = (source, predicate);

[MethodImpl(MethodImplOptions.AggressiveInlining)]
public readonly Enumerator GetEnumerator()
public readonly Enumerator GetEnumerator()
=> new Enumerator(in this);
readonly DisposableEnumerator IValueEnumerable<TSource, WhereRefEnumerable<TSource>.DisposableEnumerator>.GetEnumerator()
=> new DisposableEnumerator(in this);
readonly IEnumerator<TSource> IEnumerable<TSource>.GetEnumerator()
=> new DisposableEnumerator(in this);
readonly IEnumerator IEnumerable.GetEnumerator()
=> new DisposableEnumerator(in this);

public struct Enumerator
{
Expand All @@ -43,7 +35,7 @@ internal Enumerator(in WhereRefEnumerable<TSource> enumerable)
source = enumerable.source.Array;
predicate = enumerable.predicate;
end = enumerable.source.Offset + enumerable.source.Count;
index = -1;
index = enumerable.source.Offset - 1;
}

public readonly ref TSource Current
Expand All @@ -60,84 +52,50 @@ public bool MoveNext()
}
}

public struct DisposableEnumerator
: IEnumerator<TSource>
public bool SequenceEqual(IEnumerable<TSource> other, IEqualityComparer<TSource>? comparer = null)
{
readonly TSource[] source;
readonly Predicate<TSource> predicate;
readonly int end;
int index;

internal DisposableEnumerator(in WhereRefEnumerable<TSource> enumerable)
if (Utils.UseDefault(comparer))
{
source = enumerable.source.Array;
predicate = enumerable.predicate;
end = enumerable.source.Offset + enumerable.source.Count;
index = enumerable.source.Offset - 1;
}
var enumerator = GetEnumerator();
using var otherEnumerator = other.GetEnumerator();
while (true)
{
var thisEnded = !enumerator.MoveNext();
var otherEnded = !otherEnumerator.MoveNext();

public readonly ref TSource Current
=> ref source[index];
readonly TSource IEnumerator<TSource>.Current
=> source[index];
readonly object? IEnumerator.Current
=> source[index];
if (thisEnded != otherEnded)
return false;

public bool MoveNext()
{
while (++index < end)
{
if (predicate(source[index]))
if (thisEnded)
return true;

if (!EqualityComparer<TSource>.Default.Equals(enumerator.Current, otherEnumerator.Current))
return false;
}
return false;
}
else
{
comparer ??= EqualityComparer<TSource>.Default;

[ExcludeFromCodeCoverage]
public readonly void Reset()
=> Throw.NotSupportedException();

public readonly void Dispose() { }
}

public int Count()
=> ArrayExtensions.Count<TSource>(source, predicate);

public bool Any()
=> ArrayExtensions.Any<TSource>(source, predicate);

public WhereEnumerable<TSource> Where(Predicate<TSource> predicate)
=> ArrayExtensions.Where<TSource>(source, Utils.Combine(this.predicate, predicate));
public WhereAtEnumerable<TSource> Where(PredicateAt<TSource> predicate)
=> ArrayExtensions.Where<TSource>(source, Utils.Combine(this.predicate, predicate));
var enumerator = GetEnumerator();
using var otherEnumerator = other.GetEnumerator();
while (true)
{
var thisEnded = !enumerator.MoveNext();
var otherEnded = !otherEnumerator.MoveNext();

public WhereRefEnumerable<TSource> WhereRef(Predicate<TSource> predicate)
=> ArrayExtensions.WhereRef<TSource>(source, Utils.Combine(this.predicate, predicate));
public WhereRefAtEnumerable<TSource> WhereRef(PredicateAt<TSource> predicate)
=> ArrayExtensions.WhereRef<TSource>(source, Utils.Combine(this.predicate, predicate));
if (thisEnded != otherEnded)
return false;

public WhereSelectEnumerable<TSource, TResult> Select<TResult>(NullableSelector<TSource, TResult> selector)
{
if (selector is null)
Throw.ArgumentNullException(nameof(selector));
if (thisEnded)
return true;

return ArrayExtensions.WhereSelect<TSource, TResult>(source, predicate, selector);
if (!comparer.Equals(enumerator.Current, otherEnumerator.Current))
return false;
}
}
}

public Option<TSource> ElementAt(int index)
=> ArrayExtensions.ElementAt<TSource>(source, index, predicate);

public Option<TSource> First()
=> ArrayExtensions.First<TSource>(source, predicate);

public Option<TSource> Single()
=> ArrayExtensions.Single<TSource>(source, predicate);

public TSource[] ToArray()
=> ArrayExtensions.ToArray<TSource>(source, predicate);

public List<TSource> ToList()
=> ArrayExtensions.ToList<TSource>(source, predicate);
}
}
}
Expand Down
132 changes: 32 additions & 100 deletions NetFabric.Hyperlinq/Filtering/WhereRef/WhereRef.Memory.cs
Original file line number Diff line number Diff line change
@@ -1,7 +1,5 @@
using System;
using System.Collections;
using System.Collections.Generic;
using System.Diagnostics.CodeAnalysis;
using System.Runtime.CompilerServices;

namespace NetFabric.Hyperlinq
Expand All @@ -18,8 +16,8 @@ public static MemoryWhereRefEnumerable<TSource> WhereRef<TSource>(this Memory<TS
return new MemoryWhereRefEnumerable<TSource>(source, predicate);
}

public readonly partial struct MemoryWhereRefEnumerable<TSource>
: IValueEnumerable<TSource, MemoryWhereRefEnumerable<TSource>.DisposableEnumerator>
[GeneratorIgnore]
public readonly struct MemoryWhereRefEnumerable<TSource>
{
internal readonly Memory<TSource> source;
internal readonly Predicate<TSource> predicate;
Expand All @@ -33,12 +31,6 @@ internal MemoryWhereRefEnumerable(in Memory<TSource> source, Predicate<TSource>

public readonly Enumerator GetEnumerator()
=> new Enumerator(in this);
readonly DisposableEnumerator IValueEnumerable<TSource, MemoryWhereRefEnumerable<TSource>.DisposableEnumerator>.GetEnumerator()
=> new DisposableEnumerator(in this);
readonly IEnumerator<TSource> IEnumerable<TSource>.GetEnumerator()
=> new DisposableEnumerator(in this);
readonly IEnumerator IEnumerable.GetEnumerator()
=> new DisposableEnumerator(in this);

public ref struct Enumerator
{
Expand Down Expand Up @@ -67,107 +59,47 @@ public bool MoveNext()
}
}

public struct DisposableEnumerator
: IEnumerator<TSource>
public bool SequenceEqual(IEnumerable<TSource> other, IEqualityComparer<TSource>? comparer = null)
{
readonly Memory<TSource> source;
readonly Predicate<TSource> predicate;
int index;

internal DisposableEnumerator(in MemoryWhereRefEnumerable<TSource> enumerable)
if (Utils.UseDefault(comparer))
{
source = enumerable.source;
predicate = enumerable.predicate;
index = -1;
}
var enumerator = GetEnumerator();
using var otherEnumerator = other.GetEnumerator();
while (true)
{
var thisEnded = !enumerator.MoveNext();
var otherEnded = !otherEnumerator.MoveNext();

public readonly ref TSource Current
=> ref source.Span[index];
readonly TSource IEnumerator<TSource>.Current
=> source.Span[index];
readonly object? IEnumerator.Current
=> source.Span[index];
if (thisEnded != otherEnded)
return false;

public bool MoveNext()
{
var span = source.Span;
while (++index < source.Length)
{
if (predicate(span[index]))
if (thisEnded)
return true;

if (!EqualityComparer<TSource>.Default.Equals(enumerator.Current, otherEnumerator.Current))
return false;
}
return false;
}

[ExcludeFromCodeCoverage]
public readonly void Reset()
=> throw new NotSupportedException();

public void Dispose() { }
}

public int Count()
=> ArrayExtensions.Count<TSource>(source.Span, predicate);

public bool Any()
=> ArrayExtensions.Any<TSource>(source.Span, predicate);

public MemoryWhereEnumerable<TSource> Where(Predicate<TSource> predicate)
=> ArrayExtensions.Where<TSource>(source, Utils.Combine(this.predicate, predicate));

public MemoryWhereAtEnumerable<TSource> Where(PredicateAt<TSource> predicate)
=> ArrayExtensions.Where<TSource>(source, Utils.Combine(this.predicate, predicate));

public MemoryWhereRefEnumerable<TSource> WhereRef(Predicate<TSource> predicate)
=> ArrayExtensions.WhereRef<TSource>(source, Utils.Combine(this.predicate, predicate));

public MemoryWhereRefAtEnumerable<TSource> WhereRef(PredicateAt<TSource> predicate)
=> ArrayExtensions.WhereRef<TSource>(source, Utils.Combine(this.predicate, predicate));

public MemoryWhereSelectEnumerable<TSource, TResult> Select<TResult>(NullableSelector<TSource, TResult> selector)
{
if (selector is null)
Throw.ArgumentNullException(nameof(selector));

return ArrayExtensions.WhereSelect<TSource, TResult>(source, predicate, selector);
}

public Option<TSource> ElementAt(int index)
=> ArrayExtensions.ElementAt(source.Span, index, predicate);

public Option<TSource> First()
=> ArrayExtensions.First(source.Span, predicate);

#pragma warning disable HLQ005 // Avoid Single() and SingleOrDefault()
public Option<TSource> Single()
=> ArrayExtensions.Single(source.Span, predicate);
#pragma warning restore HLQ005 // Avoid Single() and SingleOrDefault()

public TSource[] ToArray()
=> ArrayExtensions.ToArray<TSource>(source.Span, predicate);

public List<TSource> ToList()
=> ArrayExtensions.ToList<TSource>(source, predicate); // memory performs best

public bool SequenceEqual(IEnumerable<TSource> other, IEqualityComparer<TSource>? comparer = null)
{
comparer ??= EqualityComparer<TSource>.Default;

var enumerator = GetEnumerator();
using var otherEnumerator = other.GetEnumerator();
while (true)
else
{
var thisEnded = !enumerator.MoveNext();
var otherEnded = !otherEnumerator.MoveNext();
comparer ??= EqualityComparer<TSource>.Default;

if (thisEnded != otherEnded)
return false;
var enumerator = GetEnumerator();
using var otherEnumerator = other.GetEnumerator();
while (true)
{
var thisEnded = !enumerator.MoveNext();
var otherEnded = !otherEnumerator.MoveNext();

if (thisEnded)
return true;
if (thisEnded != otherEnded)
return false;

if (!comparer.Equals(enumerator.Current, otherEnumerator.Current))
return false;
if (thisEnded)
return true;

if (!comparer.Equals(enumerator.Current, otherEnumerator.Current))
return false;
}
}
}
}
Expand Down
Loading

0 comments on commit 43d48a2

Please sign in to comment.