Last active
November 27, 2019 12:44
-
-
Save sonnemaf/8853274ff83b4fe8b96a070200aa8b2a 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
using System; | |
using System.Runtime.InteropServices; | |
namespace Linq4Span { | |
// QUESTION: Does LINQ for ReadOnlySpan<T> make sense or is the extra Closure class a showstopper? | |
// QUESTION: Should it only support ReadOnlySpan<T> and not Span<T> | |
// QUESTION: What about Memory<T> and ReadonlyMemory<T> | |
class Program { | |
static void Main(string[] args) { | |
ReadOnlySpan<int> numbers = new int[] { 1, 2, 3, 4, 5, 6, 7 }; | |
var qry = numbers.Where((in int n) => n % 2 == 0); | |
foreach (var item in qry) { | |
Console.WriteLine(item); | |
} | |
// 2, 4, 6 | |
Console.WriteLine(numbers.Sum()); // 28 | |
Console.WriteLine(numbers.Where((in int n) => n % 2 == 0).Sum()); // 12 | |
Console.WriteLine(numbers.Where((in int n) => n % 2 == 0).Count()); // 3 | |
Console.WriteLine(numbers.Count((in int n) => n % 2 == 0)); // 3 | |
ReadOnlySpan<PointStruct> points = new PointStruct[] { | |
new PointStruct(1,1), | |
new PointStruct(2,2), | |
new PointStruct(3,3), | |
}; | |
Console.WriteLine(points.Where((in PointStruct p) => p.X > 1).Sum((in PointStruct p) => ref p.X)); // 5 (2 + 3) | |
} | |
} | |
static class SpanExtensions { | |
// QUESTION: Should we have seperate delegates with IN parameters and REF READONLY returns | |
public delegate bool Predicate<T>(T value); | |
public delegate bool PredicateWithIn<T>(in T value); | |
public delegate ref readonly TResult RefReadonlySelector<TValue, TResult>(in TValue value); | |
public delegate TResult Selector<TValue, TResult>(in TValue value); | |
public static FilterEnumerable<T> Where<T>(this ReadOnlySpan<T> source, PredicateWithIn<T> predicate) { | |
return new FilterEnumerable<T>(source, predicate); | |
} | |
// TODO: Overload without IN | |
//public static FilterEnumerable<T> Where<T>(this Span<T> source, Predicate<T> predicate) { | |
// return new FilterEnumerable<T>(source, predicate); | |
//} | |
// TODO: Overloads for double, decimal, long etc | |
public static int Sum(this ReadOnlySpan<int> source) { | |
int total = 0; | |
foreach (ref readonly var item in source) { | |
total += item; | |
} | |
return total; | |
} | |
// TODO: Overloads for double, decimal, long etc | |
public static int Sum(this FilterEnumerable<int> source) { | |
int total = 0; | |
foreach (ref readonly var item in source) { | |
total += item; | |
} | |
return total; | |
} | |
// TODO: Overloads for double, decimal, long etc | |
public static int Sum<T>(this FilterEnumerable<T> source, RefReadonlySelector<T, int> selector) { | |
int total = 0; | |
foreach (ref readonly var item in source) { | |
total += selector(item); | |
} | |
return total; | |
} | |
// TODO: Overloads for double, decimal, long etc | |
public static int Sum<T>(this FilterEnumerable<T> source, Selector<T, int> selector) { | |
int total = 0; | |
foreach (ref readonly var item in source) { | |
total += selector(item); | |
} | |
return total; | |
} | |
public static int Count<T>(this FilterEnumerable<T> source) { | |
int index = 0; | |
foreach (ref readonly var item in source) { | |
index += 1; | |
} | |
return index; | |
} | |
public static int Count<T>(this ReadOnlySpan<T> source, PredicateWithIn<T> predicate) { | |
int index = 0; | |
foreach (ref readonly var item in source.Where(predicate)) { | |
index += 1; | |
} | |
return index; | |
} | |
public ref struct FilterEnumerable<T> { | |
private readonly ReadOnlySpan<T> _source; | |
private readonly PredicateWithIn<T> _predicate; | |
public FilterEnumerable(ReadOnlySpan<T> source, PredicateWithIn<T> predicate) { | |
this._source = source; | |
this._predicate = predicate; | |
} | |
public FilterEnumerator<T> GetEnumerator() { | |
return new FilterEnumerator<T>(_source, _predicate); | |
} | |
} | |
public ref struct FilterEnumerator<T> { | |
private readonly ReadOnlySpan<T> _source; | |
private readonly PredicateWithIn<T> _predicate; | |
private int _index; | |
public FilterEnumerator(ReadOnlySpan<T> source, PredicateWithIn<T> predicate) : this() { | |
this._source = source; | |
this._predicate = predicate; | |
this._index = -1; | |
} | |
public ref readonly T Current => ref _source[_index]; | |
public bool MoveNext() { | |
while (_index++ < _source.Length - 1) { | |
if (_predicate(Current)) { | |
return true; | |
} | |
} | |
return false; | |
} | |
} | |
} | |
readonly struct PointStruct { | |
public readonly int X; // { get; set; } | |
public readonly int Y; // { get; set; } | |
public PointStruct(int x, int y) { | |
this.X = x; | |
this.Y = y; | |
} | |
public double Dist => Math.Sqrt((X * X) + (Y * Y)); | |
public override string ToString() => $"({X.ToString()},{Y.ToString()})"; | |
} | |
} |
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment